Skip to content

Commit

Permalink
feat: add waiting mode for create account (#251)
Browse files Browse the repository at this point in the history
* feat: add waiting mode for create account

* chore: add read me for waitmode
  • Loading branch information
stanleyyconsensys authored Jun 11, 2024
1 parent 634152d commit 0c91142
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 11 deletions.
2 changes: 1 addition & 1 deletion packages/starknet-snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/ConsenSys/starknet-snap.git"
},
"source": {
"shasum": "trDDU4ANftSs6SE0RJK3uXaxRnCBq7fvgptzA280SPA=",
"shasum": "vVFyA2r3PuADhGuwrnvREDPCLnSidbQzT3lxf9uzvOA=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
14 changes: 13 additions & 1 deletion packages/starknet-snap/src/createAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
callContract,
estimateAccountDeployFee,
getSigner,
waitForTransaction,
} from './utils/starknetUtils';
import {
getEtherErc20Token,
Expand All @@ -23,7 +24,14 @@ import { DialogType } from '@metamask/rpc-methods';
import { heading, panel, text } from '@metamask/snaps-sdk';
import { logger } from './utils/logger';

export async function createAccount(params: ApiParams, silentMode = false) {
/**
* Create an starknet account.
*
* @template Params - The ApiParams of the request.
* @param silentMode - The flag to disable the confirmation dialog from snap.
* @param waitMode - The flag to enable an determination by doing an recursive fetch to check if the deploy account status is on L2 or not. The wait mode is only useful when it compose with other txn together, it can make sure the deploy txn execute complete, avoiding the latter txn failed.
*/
export async function createAccount(params: ApiParams, silentMode = false, waitMode = false) {
try {
const { state, wallet, saveMutex, keyDeriver, requestParams } = params;
const requestParamsObj = requestParams as CreateAccountRequestParams;
Expand Down Expand Up @@ -148,6 +156,10 @@ export async function createAccount(params: ApiParams, silentMode = false) {

logger.log(`createAccount:\ndeployResp: ${toJson(deployResp)}`);

if (waitMode) {
await waitForTransaction(network, deployResp.contract_address, privateKey, deployResp.transaction_hash);
}

return {
address: deployResp.contract_address,
transaction_hash: deployResp.transaction_hash,
Expand Down
2 changes: 1 addition & 1 deletion packages/starknet-snap/src/sendTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export async function sendTransaction(params: ApiParams) {
chainId: requestParamsObj.chainId,
},
};
await createAccount(createAccountApiParams, true);
await createAccount(createAccountApiParams, true, true);
}

//In case this is the first transaction we assign a nonce of 1 to make sure it does after the deploy transaction
Expand Down
2 changes: 1 addition & 1 deletion packages/starknet-snap/src/utils/snapUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ export function getRPCUrl(chainId: string) {
}

export function getRPCCredentials(): string {
return process.env.ALCHEMY_API_KEY ?? ''
return process.env.ALCHEMY_API_KEY ?? '';
}

export function getVoyagerUrl(chainId: string) {
Expand Down
14 changes: 14 additions & 0 deletions packages/starknet-snap/src/utils/starknetUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import {
DeployAccountSignerDetails,
InvocationsSignerDetails,
ProviderInterface,
CairoVersion,
GetTransactionReceiptResponse,
} from 'starknet';
import { Network, SnapState, Transaction, TransactionType } from '../types/snapState';
import { ACCOUNT_CLASS_HASH_V0, PROXY_CONTRACT_HASH, TRANSFER_SELECTOR_HEX } from './constants';
Expand Down Expand Up @@ -108,6 +110,18 @@ export const estimateFee = async (
});
};

export const waitForTransaction = async (
network: Network,
senderAddress: string,
privateKey: string | Uint8Array,
txnHash: num.BigNumberish,
cairoVersion?: CairoVersion,
): Promise<GetTransactionReceiptResponse> => {
const provider = getProvider(network);
const account = new Account(provider, senderAddress, privateKey, cairoVersion ?? '0');
return account.waitForTransaction(txnHash);
};

export const estimateFeeBulk = async (
network: Network,
senderAddress: string,
Expand Down
26 changes: 25 additions & 1 deletion packages/starknet-snap/test/src/createAccount.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ import {
import { getAddressKeyDeriver } from '../../src/utils/keyPair';
import { Mutex } from 'async-mutex';
import { ApiParams, CreateAccountRequestParams } from '../../src/types/snapApi';
import { GetTransactionReceiptResponse } from 'starknet';

chai.use(sinonChai);
const sandbox = sinon.createSandbox();

describe('Test function: createAccount', function () {
this.timeout(10000);
const walletStub = new WalletMock();
let waitForTransactionStub;
const state: SnapState = {
accContracts: [],
erc20Tokens: [],
Expand All @@ -50,6 +52,8 @@ describe('Test function: createAccount', function () {
sandbox.useFakeTimers(createAccountProxyTxn.timestamp);
walletStub.rpcStubs.snap_dialog.resolves(true);
walletStub.rpcStubs.snap_manageState.resolves(state);
waitForTransactionStub = sandbox.stub(utils, 'waitForTransaction');
waitForTransactionStub.resolves({} as unknown as GetTransactionReceiptResponse);
});

afterEach(function () {
Expand Down Expand Up @@ -77,6 +81,27 @@ describe('Test function: createAccount', function () {
expect(state.transactions.length).to.be.eq(0);
});

it('waits for tansaction after an account has deployed', async function () {
sandbox.stub(utils, 'deployAccount').callsFake(async () => {
return createAccountProxyMainnetResp;
});
sandbox.stub(utils, 'getSigner').throws(new Error());
sandbox.stub(utils, 'callContract').callsFake(async () => {
return getBalanceResp;
});
sandbox.stub(utils, 'estimateAccountDeployFee').callsFake(async () => {
return estimateDeployFeeResp;
});
const requestObject: CreateAccountRequestParams = {
chainId: STARKNET_MAINNET_NETWORK.chainId,
deploy: true,
};
apiParams.requestParams = requestObject;
await createAccount(apiParams, false, true);

expect(waitForTransactionStub).to.have.been.callCount(1);
});

it('should create and store an user account with proxy in state correctly in mainnet', async function () {
sandbox.stub(utils, 'deployAccount').callsFake(async () => {
return createAccountProxyMainnetResp;
Expand All @@ -100,7 +125,6 @@ describe('Test function: createAccount', function () {
state,
createAccountProxyMainnetResp.contract_address,
);
expect(walletStub.rpcStubs.snap_manageState).to.have.been.callCount(4);
expect(result.address).to.be.eq(createAccountProxyMainnetResp.contract_address);
expect(result.transaction_hash).to.be.eq(createAccountProxyMainnetResp.transaction_hash);
expect(state.accContracts.length).to.be.eq(1);
Expand Down
2 changes: 2 additions & 0 deletions packages/starknet-snap/test/src/sendTransaction.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { getAddressKeyDeriver } from '../../src/utils/keyPair';
import { Mutex } from 'async-mutex';
import { ApiParams, SendTransactionRequestParams } from '../../src/types/snapApi';
import { GetTransactionReceiptResponse } from 'starknet';

chai.use(sinonChai);
chai.use(chaiAsPromised);
Expand Down Expand Up @@ -62,6 +63,7 @@ describe('Test function: sendTransaction', function () {
});
walletStub.rpcStubs.snap_dialog.resolves(true);
walletStub.rpcStubs.snap_manageState.resolves(state);
sandbox.stub(utils, 'waitForTransaction').resolves({} as unknown as GetTransactionReceiptResponse);
});

afterEach(function () {
Expand Down
10 changes: 7 additions & 3 deletions packages/starknet-snap/test/utils/snapUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,20 @@ describe('getVoyagerCredentials', () => {

describe('getRPCUrl', () => {
it('returns Mainnet RPC URL if chain id is Mainnet', () => {
expect(getRPCUrl(constants.StarknetChainId.SN_MAIN)).to.be.equal('https://starknet-mainnet.g.alchemy.com/starknet/version/rpc/v0_7/');
expect(getRPCUrl(constants.StarknetChainId.SN_MAIN)).to.be.equal(
'https://starknet-mainnet.g.alchemy.com/starknet/version/rpc/v0_7/',
);
});

it('returns Sepolia RPC URL if chain id is not either Mainnet or Sepolia', () => {
expect(getRPCUrl('0x534e5f474f45524c49')).to.be.equal('https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/');
expect(getRPCUrl('0x534e5f474f45524c49')).to.be.equal(
'https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/',
);
});

it('returns Sepolia RPC URL if chain id is Sepolia', () => {
expect(getRPCUrl(STARKNET_SEPOLIA_TESTNET_NETWORK.chainId)).to.be.equal(
'https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_7/',
);
});
});
});
19 changes: 18 additions & 1 deletion packages/starknet-snap/test/utils/starknetUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
account2,
} from '../constants.test';
import { SnapState } from '../../src/types/snapState';
import { Calldata } from 'starknet';
import { Calldata, GetTransactionReceiptResponse } from 'starknet';

chai.use(sinonChai);
const sandbox = sinon.createSandbox();
Expand Down Expand Up @@ -129,3 +129,20 @@ describe('Test function: validateAndParseAddress', function () {
);
});
});

describe('Test function: waitForTransaction', function () {
const walletStub = new WalletMock();
const userAddress = '0x27f204588cadd08a7914f6a9808b34de0cbfc4cb53aa053663e7fd3a34dbc26';

afterEach(function () {
walletStub.reset();
sandbox.restore();
});

it('pass parameter to waitForTransaction correctly', async function () {
const stub = sandbox.stub(utils, 'waitForTransaction');
stub.resolves({} as unknown as GetTransactionReceiptResponse);
await utils.waitForTransaction(STARKNET_SEPOLIA_TESTNET_NETWORK, userAddress, 'pk', 'txHash');
expect(stub).to.have.been.calledWith(STARKNET_SEPOLIA_TESTNET_NETWORK, userAddress, 'pk', 'txHash');
});
});
4 changes: 2 additions & 2 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3246,7 +3246,7 @@ __metadata:

"@consensys/starknet-snap@file:../starknet-snap::locator=wallet-ui%40workspace%3Apackages%2Fwallet-ui":
version: 2.7.0
resolution: "@consensys/starknet-snap@file:../starknet-snap#../starknet-snap::hash=660e3f&locator=wallet-ui%40workspace%3Apackages%2Fwallet-ui"
resolution: "@consensys/starknet-snap@file:../starknet-snap#../starknet-snap::hash=099522&locator=wallet-ui%40workspace%3Apackages%2Fwallet-ui"
dependencies:
"@metamask/snaps-sdk": 3.0.1
async-mutex: ^0.3.2
Expand All @@ -3255,7 +3255,7 @@ __metadata:
ethers: ^5.5.1
starknet: 6.7.0
starknet_v4.22.0: "npm:[email protected]"
checksum: bc84f37ad403ec57113becf7b6bd0be167fe2ceb0a2ca9359eff062b277c2f1b863ac4255b28ba43a0f455e8165633a84c5178beefd9ea9e23e4e954a0ea750e
checksum: a53e3b5b9b53448473b4b362ebdda3d1ecb97321baa7db52393c0b43e9454ccb81d641bd2a86956896a591c23f237566d4c131034806c2609de79f9f1a12ba41
languageName: node
linkType: hard

Expand Down

0 comments on commit 0c91142

Please sign in to comment.