Skip to content
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
2 changes: 1 addition & 1 deletion packages/starknet-snap/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"async-mutex": "^0.3.2",
"ethereum-unit-converter": "^0.0.17",
"ethers": "^5.5.1",
"starknet": "7.6.3",
"starknet": "^9.4.2",
"starknet_v4.22.0": "npm:starknet@4.22.0",
"superstruct": "^2.0.2",
"uuid": "^10.0.0"
Expand Down
7 changes: 5 additions & 2 deletions 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": "gEwA/t7vMoY2xy8VkBaIVoyO3dpKu0G49R5IWH0vfmQ=",
"shasum": "Q4srgXGyGzep+2TDzZHXglfSbp+D7pq00/831biQDxI=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand All @@ -16,7 +16,10 @@
"registry": "https://registry.npmjs.org"
}
},
"locales": ["locales/en.json", "locales/fr.json"]
"locales": [
"locales/en.json",
"locales/fr.json"
]
},
"initialPermissions": {
"snap_getPreferences": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"transaction_status": "ACCEPTED_ON_L1",
"transaction_finality_status": "ACCEPTED_ON_L1",
"transaction_execution_status": "SUCCEEDED",
"transaction_type": "INVOKE_FUNCTION",
"transaction_type": "INVOKE",
"version": 1,
"signature": [
"0x555fe1b8e5183be2f6c81e5203ee3928aab894ab0b31279c89a3c7f016865fc",
Expand Down Expand Up @@ -70,7 +70,7 @@
"transaction_status": "ACCEPTED_ON_L1",
"transaction_finality_status": "ACCEPTED_ON_L1",
"transaction_execution_status": "SUCCEEDED",
"transaction_type": "INVOKE_FUNCTION",
"transaction_type": "INVOKE",
"version": 1,
"signature": [
"0x417671c63219250e0c80d53b1e1b3c0dd76ade552806a51fdfd8c06f7c47a12",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,18 @@
"transactionsDetail": {
"walletAddress": "0x00b28a089e7fb83debee4607b6334d687918644796b47d9e9e38ea8213833137",
"chainId": "0x534e5f4d41494e",
"cairoVersion": "0",
"cairoVersion": "1",
"nonce": "0x1",
"version": "0x0",
"maxFee": "0x64"
"version": "0x3",
"tip": "0x0",
"paymasterData": [],
"accountDeploymentData": [],
"nonceDataAvailabilityMode": "L1",
"feeDataAvailabilityMode": "L1",
"resourceBounds": {
"l1_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" },
"l2_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" },
"l1_data_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" }
}
}
}
40 changes: 13 additions & 27 deletions packages/starknet-snap/src/__tests__/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { UserInputEvent } from '@metamask/snaps-sdk';
import { UserInputEventType } from '@metamask/snaps-sdk';
import { generateMnemonic } from 'bip39';
import { getRandomValues } from 'crypto';
import type { EstimateFee } from 'starknet';
import type { EstimateFeeResponseOverhead } from 'starknet';
import {
constants,
ec,
Expand Down Expand Up @@ -275,7 +275,7 @@ export function generateTransactions({

const executionStatus = getRandomData(executionStatuses);
const finalityStatus =
executionStatus === TransactionExecutionStatus.REJECTED
executionStatus === TransactionExecutionStatus.REVERTED
? TransactionFinalityStatus.ACCEPTED_ON_L2
: getRandomData(finalityStatuses);
const txnType = getRandomData(_txnTypes);
Expand Down Expand Up @@ -569,54 +569,40 @@ export function generateStarkScanTransactions({
/**
* Method to generate a mock estimate fee response.
*
* @returns An array containing a mock EstimateFee object.
* @returns An array containing a mock EstimateFeeResponseOverhead object.
*/
export function generateEstimateFeesResponse(
chainId: constants.StarknetChainId = constants.StarknetChainId.SN_SEPOLIA,
): EstimateFee[] {
): EstimateFeeResponseOverhead[] {
const fees = [
{
// eslint-disable-next-line @typescript-eslint/naming-convention
overall_fee: BigInt(1500000000000000).toString(10),
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_gas_consumed: BigInt('0x0'),
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_gas_price: BigInt('0x0'),
// eslint-disable-next-line @typescript-eslint/naming-convention
l2_gas_consumed: BigInt('0x0'),
// eslint-disable-next-line @typescript-eslint/naming-convention
l2_gas_price: BigInt('0x0'),
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_data_gas_consumed: BigInt('0x0'),
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_data_gas_price: BigInt('0x0'),
suggestedMaxFee: BigInt(1500000000000000).toString(10),
// eslint-disable-next-line @typescript-eslint/naming-convention
gas_price: BigInt('0x0'),
overall_fee: BigInt(1500000000000000),
unit: 'WEI',
resourceBounds: {
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_gas: {
// eslint-disable-next-line @typescript-eslint/naming-convention
max_amount: '0',
max_amount: BigInt(0),
// eslint-disable-next-line @typescript-eslint/naming-convention
max_price_per_unit: '0',
max_price_per_unit: BigInt(0),
},
// eslint-disable-next-line @typescript-eslint/naming-convention
l2_gas: {
// eslint-disable-next-line @typescript-eslint/naming-convention
max_amount: '0',
max_amount: BigInt(0),
// eslint-disable-next-line @typescript-eslint/naming-convention
max_price_per_unit: '0',
max_price_per_unit: BigInt(0),
},
// eslint-disable-next-line @typescript-eslint/naming-convention
l1_data_gas: {
// eslint-disable-next-line @typescript-eslint/naming-convention
max_amount: '0',
max_amount: BigInt(0),
// eslint-disable-next-line @typescript-eslint/naming-convention
max_price_per_unit: '0',
max_price_per_unit: BigInt(0),
},
},
} as unknown as EstimateFee,
} as unknown as EstimateFeeResponseOverhead,
];
return fees;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ describe('TransactionService', () => {
expect(findTransactionsSpy).toHaveBeenCalledWith({
senderAddress: [address],
chainId: [network.chainId],
finalityStatus: [TransactionFinalityStatus.RECEIVED],
finalityStatus: [TransactionFinalityStatus.PRE_CONFIRMED],
dataVersion: [TransactionDataVersion.V2],
});
expect(transactions).toStrictEqual(filteredTransactions);
Expand Down
2 changes: 1 addition & 1 deletion packages/starknet-snap/src/chain/transaction-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class TransactionService {
const transactions = await this.txnStateMgr.findTransactions({
senderAddress: [address],
chainId: [this.network.chainId],
finalityStatus: [TransactionFinalityStatus.RECEIVED],
finalityStatus: [TransactionFinalityStatus.PRE_CONFIRMED],
// Exculde the transaction data that are not in the latest version,
// hence we dont have to migrate the data, as it can be retrieved from the chain eventually.
dataVersion: [TransactionDataVersion.V2],
Expand Down
8 changes: 0 additions & 8 deletions packages/starknet-snap/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,6 @@ export type SnapConfig = {
explorer: {
[key: string]: string;
};
enableRPCV8: {
[key: string]: boolean;
};
dataClient: {
[key: string]: {
apiKey: string | undefined;
Expand Down Expand Up @@ -79,11 +76,6 @@ export const Config: SnapConfig = {
'https://sepolia.voyager.online/contract/${address}',
},

enableRPCV8: {
[constants.StarknetChainId.SN_MAIN]: true,
[constants.StarknetChainId.SN_SEPOLIA]: true,
},

dataClient: {
[DataClient.STARKSCAN]: {
// eslint-disable-next-line no-restricted-globals
Expand Down
24 changes: 11 additions & 13 deletions packages/starknet-snap/src/createAccount.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { heading, panel, DialogType } from '@metamask/snaps-sdk';
import type { CairoVersion, EstimateFee } from 'starknet';
import { num as numUtils } from 'starknet';
import type { CairoVersion, EstimateFeeResponseOverhead } from 'starknet';

import type {
ApiParamsWithKeyDeriver,
Expand Down Expand Up @@ -74,22 +73,21 @@ export async function createAccount(
`estimateAccountDeployFee:\ncontractAddress = ${contractAddress}\npublicKey = ${publicKey}\naddressIndex = ${addressIndexInUsed}`,
);

const estimateDeployFee: EstimateFee = await estimateAccountDeployFee(
network,
contractAddress,
contractCallData,
publicKey,
privateKey,
cairoVersion,
);
const estimateDeployFee: EstimateFeeResponseOverhead =
await estimateAccountDeployFee(
network,
contractAddress,
contractCallData,
publicKey,
privateKey,
cairoVersion,
);
logger.log(
`estimateAccountDeployFee:\nestimateDeployFee: ${toJson(
estimateDeployFee,
)}`,
);
const maxFee = numUtils.toBigInt(
estimateDeployFee.suggestedMaxFee.toString(10) ?? '0',
);
const maxFee = estimateDeployFee.overall_fee;
const dialogComponents = getSendTxnText(
state,
contractAddress,
Expand Down
27 changes: 15 additions & 12 deletions packages/starknet-snap/src/estimateAccountDeployFee.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { EstimateFee } from 'starknet';
import type { EstimateFeeResponseOverhead } from 'starknet';

import type {
ApiParamsWithKeyDeriver,
Expand Down Expand Up @@ -42,25 +42,28 @@ export async function estimateAccDeployFee(params: ApiParamsWithKeyDeriver) {
`estimateAccountDeployFee:\ncontractAddress = ${contractAddress}\npublicKey = ${publicKey}\naddressIndex = ${addressIndexInUsed}`,
);

const estimateDeployFee: EstimateFee = await estimateAccountDeployFee(
network,
contractAddress,
contractCallData,
publicKey,
privateKey,
);
const estimateDeployFee: EstimateFeeResponseOverhead =
await estimateAccountDeployFee(
network,
contractAddress,
contractCallData,
publicKey,
privateKey,
);
logger.log(
`estimateAccountDeployFee:\nestimateDeployFee: ${toJson(
estimateDeployFee,
)}`,
);

const resp = {
suggestedMaxFee: estimateDeployFee.suggestedMaxFee.toString(10),
suggestedMaxFee: estimateDeployFee.overall_fee.toString(10),
overallFee: estimateDeployFee.overall_fee.toString(10),
gasConsumed: estimateDeployFee.l1_gas_consumed?.toString(10) ?? '0',
gasPrice: estimateDeployFee.l1_gas_price?.toString(10) ?? '0',
unit: 'wei',
gasConsumed:
estimateDeployFee.resourceBounds.l1_gas.max_amount.toString(10),
gasPrice:
estimateDeployFee.resourceBounds.l1_gas.max_price_per_unit.toString(10),
unit: estimateDeployFee.unit,
};
logger.log(`estimateAccountDeployFee:\nresp: ${toJson(resp)}`);

Expand Down
20 changes: 19 additions & 1 deletion packages/starknet-snap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ import {
import {
CAIRO_VERSION_LEGACY,
PRELOADED_TOKENS,
SnapEnv,
STARKNET_MAINNET_NETWORK,
STARKNET_SEPOLIA_TESTNET_NETWORK,
STARKNET_TESTNET_NETWORK,
Expand Down Expand Up @@ -326,8 +327,25 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
let snapError = error;

if (!isSnapRpcError(error)) {
// Always log the ORIGINAL error before discarding it. Wrapping in
// `UnknownError` replaces the message with a generic string, so without
// this the real cause is unrecoverable - the client only ever sees
// "Unable to execute the rpc request".
logger.error(
`onRpcRequest unexpected error in ${request.method}:`,
error?.stack ?? error?.message ?? String(error),
);

// To ensure the error meets both the SnapError format and WalletRpc format.
snapError = new UnknownError('Unable to execute the rpc request');
// Outside production, keep the original message so it reaches the dapp.
snapError =
Config.snapEnv === SnapEnv.Prod
? new UnknownError('Unable to execute the rpc request')
: new UnknownError(
`Unable to execute the rpc request: ${String(
error?.message ?? error,
)}`,
);
}
logger.error(
`onRpcRequest error: ${JSON.stringify(snapError.toJSON(), null, 2)}`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Json } from '@metamask/snaps-sdk';
import { Mutex } from 'async-mutex';

import { NetworkStateManager } from '../../state/network-state-manager';
import type { Network } from '../../types/snapState';
Expand All @@ -23,11 +24,31 @@ export abstract class ChainRpcController<

protected networkStateMgr: NetworkStateManager;

/**
* Serializes executions per controller instance.
*
* Every RPC controller is exported as a module-level singleton (e.g.
* `export const getCurrentAccount = new GetCurrentAccountRpc()` in
* `rpcs/get-current-account.ts`), while `preExecute` stores the resolved
* network on `this.network`. Without serialization, two concurrent requests
* for different chains (easily produced by switching networks quickly in
* the companion dapp) race on that field: request A can run
* `handleRequest` with request B's network, returning wrong-chain data or
* writing wrong-chain state.
*/
readonly #executionMutex = new Mutex();

constructor() {
super();
this.networkStateMgr = new NetworkStateManager();
}

async execute(params: Request): Promise<Response> {
return await this.#executionMutex.runExclusive(
async () => await super.execute(params),
);
}

protected async getNetwork(chainId: string): Promise<Network> {
const network = await this.networkStateMgr.getNetwork({ chainId });
// if the network is not in the list of networks that we support, we throw an error
Expand Down
Loading
Loading