Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VIP] V6 saitama #908

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ dist
node_modules
npm-debug.log
package
yarn.lock
yarn.lock
__tests__/scripts
25 changes: 25 additions & 0 deletions __tests__/accountInstance.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Account, AccountInstance, LibraryError, RpcProvider } from '../src';

describe('Account instantiated from provider instance', () => {
const rpc = new RpcProvider();
const getNonceMock = jest.fn().mockResolvedValue('mock');
rpc.getNonceForAddress = getNonceMock;

test('Account to throw on extended custom methods for using re-instantiation on provider', () => {
const acc = new Account(rpc, '0x0', '0x1');

return expect(acc.getNonceForAddress('0x0')).rejects.toThrow(LibraryError);
});

test('AccountInstance to pass on extending', async () => {
const acc = new AccountInstance(rpc, '0x0', '0x1');
expect(await acc.getNonceForAddress('0x1')).toBe('mock');
expect(getNonceMock).toHaveBeenLastCalledWith('0x1');
});

test('Account to pass on extended custom methods for using instance on provider', async () => {
const acc = new Account(rpc, '0x0', '0x1', undefined, undefined, true);
expect(await acc.getNonceForAddress('0x2')).toBe('mock');
expect(getNonceMock).toHaveBeenLastCalledWith('0x2');
});
});
10 changes: 5 additions & 5 deletions __tests__/config/jestGlobalSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

import { BaseUrl } from '../../src/constants';
import { getDefaultNodeUrl } from '../../src/utils/provider';
import localDevnetDetector, { type DevnetStrategy } from './helpers/localDevnetDetector';
import { GS_DEFAULT_TEST_PROVIDER_URL } from './constants';
import { setIfNullish } from './helpers/env';
Expand Down Expand Up @@ -98,11 +99,10 @@ const verifySetup = (final?: boolean) => {
if (final) throw new Error('TEST_ACCOUNT_PRIVATE_KEY env is not provided');
else warnings.push('TEST_ACCOUNT_PRIVATE_KEY env is not provided!');
}
// TODO: revise after Sequencer removal
// if (!process.env.TEST_RPC_URL) {
// process.env.TEST_RPC_URL = getDefaultNodeUrl();
// console.warn('TEST_RPC_URL env is not provided');
// }

if (!process.env.TEST_RPC_URL && final) {
process.env.TEST_RPC_URL = getDefaultNodeUrl();
}

if (warnings.length > 0) {
console.log('\x1b[33m', warnings.join('\n'), '\x1b[0m');
Expand Down
9 changes: 5 additions & 4 deletions __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import {
Block,
CallData,
Contract,
ETransactionExecutionStatus,
ETransactionStatus,
FeeEstimate,
RPC,
RPC06,
RpcProvider,
TransactionExecutionStatus,
stark,
waitForTransactionOptions,
} from '../src';
Expand Down Expand Up @@ -142,8 +143,8 @@ describeIfRpc('RPCProvider', () => {

const generateOptions = (o: waitForTransactionOptions) => ({ retryInterval: 10, ...o });
const generateTransactionStatus = (
finality_status: RPC.SPEC.TXN_STATUS,
execution_status?: RPC.SPEC.TXN_EXECUTION_STATUS
finality_status: `${ETransactionStatus}`,
execution_status?: `${ETransactionExecutionStatus}`
): RPC.TransactionStatus => ({
finality_status,
execution_status,
Expand Down Expand Up @@ -183,7 +184,7 @@ describeIfRpc('RPCProvider', () => {

test('reverted - as error state', async () => {
transactionStatusSpy.mockResolvedValueOnce(response.reverted);
const options = generateOptions({ errorStates: [TransactionExecutionStatus.REVERTED] });
const options = generateOptions({ errorStates: [ETransactionExecutionStatus.REVERTED] });
await expect(rpcProvider.waitForTransaction(0, options)).rejects.toThrow(
`${RPC.ETransactionExecutionStatus.REVERTED}: ${RPC.ETransactionStatus.ACCEPTED_ON_L2}`
);
Expand Down
9 changes: 6 additions & 3 deletions src/account/default.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { UDC, ZERO } from '../constants';
import { DEFAULT_TRANSACTION_VERSION, UDC, ZERO } from '../constants';
import { Provider, ProviderInterface } from '../provider';
import { Signer, SignerInterface } from '../signer';
import {
Expand Down Expand Up @@ -72,9 +72,12 @@ export class Account extends Provider implements AccountInterface {
address: string,
pkOrSigner: Uint8Array | string | SignerInterface,
cairoVersion?: CairoVersion,
transactionVersion: ETransactionVersion.V2 | ETransactionVersion.V3 = ETransactionVersion.V2 // TODO: Discuss this, set to v2 for backward compatibility
transactionVersion:
| ETransactionVersion.V2
| ETransactionVersion.V3 = DEFAULT_TRANSACTION_VERSION,
instance?: boolean
) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This instance parameter and the new AccountInstance class feels like it could be confusing to users. I suggest evaluating if a different term might be a better fit, maybe something like inheritable or inheritableProvider.

Adding @ivpavici since he's had success with naming things.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that the user create Acc from the instance and not class.
Is there a better name to fit I'm fine with it, I am not supper happy with this name also, but it was only one logical to me.

super(providerOrOptions);
super(providerOrOptions, instance);
this.address = address.toLowerCase();
this.signer =
isString(pkOrSigner) || pkOrSigner instanceof Uint8Array
Expand Down
19 changes: 19 additions & 0 deletions src/account/instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { DEFAULT_TRANSACTION_VERSION } from '../constants';
import { ProviderInterface } from '../provider/interface';
import { SignerInterface } from '../signer/interface';
import { CairoVersion, ETransactionVersion, ProviderOptions } from '../types';
import { Account } from '.';

export class AccountInstance extends Account {
constructor(
providerOrOptions: ProviderOptions | ProviderInterface,
address: string,
pkOrSigner: Uint8Array | string | SignerInterface,
cairoVersion?: CairoVersion,
transactionVersion:
| ETransactionVersion.V2
| ETransactionVersion.V3 = DEFAULT_TRANSACTION_VERSION
) {
super(providerOrOptions, address, pkOrSigner, cairoVersion, transactionVersion, true);
}
}
26 changes: 17 additions & 9 deletions src/channel/rpc_0_6.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import {
AccountInvocations,
BigNumberish,
BlockIdentifier,
BlockTag,
Call,
DeclareContractTransaction,
DeployAccountContractTransaction,
EBlockTag,
Invocation,
InvocationsDetailsWithNonce,
RpcProviderOptions,
RpcChannelOptions,
TransactionType,
getEstimateFeeBulkOptions,
getSimulateTransactionOptions,
waitForTransactionOptions,
} from '../types';
import { JRPC, RPCSPEC06 as RPC } from '../types/api';
import { ERPCVersion, JRPC, RPCSPEC06 as RPC } from '../types/api';
import { CallData } from '../utils/calldata';
import { isSierra } from '../utils/contract';
import fetch from '../utils/fetchPonyfill';
Expand All @@ -30,7 +30,7 @@ import { getVersionsByType } from '../utils/transaction';

const defaultOptions = {
headers: { 'Content-Type': 'application/json' },
blockIdentifier: BlockTag.pending,
blockIdentifier: EBlockTag.PENDING,
retries: 200,
};

Expand All @@ -51,23 +51,31 @@ export class RpcChannel {

readonly waitMode: Boolean; // behave like web2 rpc and return when tx is processed

constructor(optionsOrProvider?: RpcProviderOptions) {
constructor(optionsOrProvider?: RpcChannelOptions) {
const { nodeUrl, retries, headers, blockIdentifier, chainId, specVersion, waitMode } =
optionsOrProvider || {};
if (Object.values(NetworkName).includes(nodeUrl as NetworkName)) {
this.nodeUrl = getDefaultNodeUrl(nodeUrl as NetworkName, optionsOrProvider?.default);
this.nodeUrl = getDefaultNodeUrl(
nodeUrl as NetworkName,
optionsOrProvider?.rpcVersion,
optionsOrProvider?.default
);
} else if (nodeUrl) {
this.nodeUrl = nodeUrl;
} else {
this.nodeUrl = getDefaultNodeUrl(undefined, optionsOrProvider?.default);
this.nodeUrl = getDefaultNodeUrl(
undefined,
optionsOrProvider?.rpcVersion,
optionsOrProvider?.default
);
}
this.retries = retries || defaultOptions.retries;
this.headers = { ...defaultOptions.headers, ...headers };
this.blockIdentifier = blockIdentifier || defaultOptions.blockIdentifier;
this.chainId = chainId;
this.specVersion = specVersion;
this.waitMode = waitMode || false;
this.requestId = 0;
this.specVersion = specVersion;
}

public setChainId(chainId: StarknetChainId) {
Expand Down Expand Up @@ -378,7 +386,7 @@ export class RpcChannel {
) {
const block_id = new Block(blockIdentifier).identifier;
let flags = {};
if (!isVersion('0.5', await this.getSpecVersion())) {
if (!isVersion(ERPCVersion.V0_5, await this.getSpecVersion())) {
flags = {
simulation_flags: skipValidate ? [RPC.ESimulationFlag.SKIP_VALIDATE] : [],
};
Expand Down
29 changes: 19 additions & 10 deletions src/channel/rpc_0_7.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
AccountInvocations,
BigNumberish,
BlockIdentifier,
BlockTag,
Call,
DeclareContractTransaction,
DeployAccountContractTransaction,
EBlockTag,
Invocation,
InvocationsDetailsWithNonce,
RpcProviderOptions,
RpcChannelOptions,
TransactionType,
getEstimateFeeBulkOptions,
getSimulateTransactionOptions,
Expand All @@ -30,7 +30,7 @@ import { getVersionsByType } from '../utils/transaction';

const defaultOptions = {
headers: { 'Content-Type': 'application/json' },
blockIdentifier: BlockTag.pending,
blockIdentifier: EBlockTag.PENDING,
retries: 200,
};

Expand All @@ -47,26 +47,35 @@ export class RpcChannel {

private chainId?: StarknetChainId;

private speckVersion?: string;
private specVersion?: string;

readonly waitMode: Boolean; // behave like web2 rpc and return when tx is processed

constructor(optionsOrProvider?: RpcProviderOptions) {
const { nodeUrl, retries, headers, blockIdentifier, chainId, waitMode } =
constructor(optionsOrProvider?: RpcChannelOptions) {
const { nodeUrl, retries, headers, blockIdentifier, chainId, specVersion, waitMode } =
optionsOrProvider || {};
if (Object.values(NetworkName).includes(nodeUrl as NetworkName)) {
this.nodeUrl = getDefaultNodeUrl(nodeUrl as NetworkName, optionsOrProvider?.default);
this.nodeUrl = getDefaultNodeUrl(
nodeUrl as NetworkName,
optionsOrProvider?.rpcVersion,
optionsOrProvider?.default
);
} else if (nodeUrl) {
this.nodeUrl = nodeUrl;
} else {
this.nodeUrl = getDefaultNodeUrl(undefined, optionsOrProvider?.default);
this.nodeUrl = getDefaultNodeUrl(
undefined,
optionsOrProvider?.rpcVersion,
optionsOrProvider?.default
);
}
this.retries = retries || defaultOptions.retries;
this.headers = { ...defaultOptions.headers, ...headers };
this.blockIdentifier = blockIdentifier || defaultOptions.blockIdentifier;
this.chainId = chainId;
this.waitMode = waitMode || false;
this.requestId = 0;
this.specVersion = specVersion;
}

public setChainId(chainId: StarknetChainId) {
Expand Down Expand Up @@ -124,8 +133,8 @@ export class RpcChannel {
}

public async getSpecVersion() {
this.speckVersion ??= (await this.fetchEndpoint('starknet_specVersion')) as StarknetChainId;
return this.speckVersion;
this.specVersion ??= (await this.fetchEndpoint('starknet_specVersion')) as StarknetChainId;
return this.specVersion;
}

public getNonceForAddress(
Expand Down
21 changes: 15 additions & 6 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,28 @@ export const UDC = {
ENTRYPOINT: 'deployContract',
};

export const DEFAULT_TRANSACTION_VERSION = ETransactionVersion.V2; // TODO: Discuss this, set to v2 for backward compatibility
export const RPC_DEFAULT_VERSION = 'v0_7';

export const DEFAULT_NETWORK_NAME = NetworkName.SN_GOERLI; // TODO: when goerli deprecated switch default to sepolia
export const RPC_DEFAULT_VERSION_TAG = 'v0_6';
export const RPC_NODES = {
SN_GOERLI: [
`https://starknet-testnet.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION}`,
`https://free-rpc.nethermind.io/goerli-juno/${RPC_DEFAULT_VERSION}`,
`https://starknet-testnet.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION_TAG}`,
`https://free-rpc.nethermind.io/goerli-juno/${RPC_DEFAULT_VERSION_TAG}`,
],
SN_MAIN: [
`https://starknet-mainnet.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION}`,
`https://free-rpc.nethermind.io/mainnet-juno/${RPC_DEFAULT_VERSION}`,
`https://starknet-mainnet.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION_TAG}`,
`https://free-rpc.nethermind.io/mainnet-juno/${RPC_DEFAULT_VERSION_TAG}`,
],
SN_SEPOLIA: [
`https://starknet-sepolia.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION}`,
`https://free-rpc.nethermind.io/sepolia-juno/${RPC_DEFAULT_VERSION}`,
`https://starknet-sepolia.public.blastapi.io/rpc/${RPC_DEFAULT_VERSION_TAG}`,
`https://free-rpc.nethermind.io/sepolia-juno/${RPC_DEFAULT_VERSION_TAG}`,
],
getNode(network: NetworkName, index: number, rpcVersion?: string) {
const defRpcUrl = this[network][index];
return rpcVersion
? `${defRpcUrl.substring(0, defRpcUrl.lastIndexOf('/') + 1)}v${rpcVersion.replace('.', '_')}`
: defRpcUrl;
},
};
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from './contract';
export * from './provider';
export * from './signer';
export * from './channel';
export * from './account/instance';

// TODO: decide on final export style
export * from './types';
Expand Down
Loading
Loading