From 4aab970a7ac78d8c381698163ebd5febc31dd08a Mon Sep 17 00:00:00 2001 From: Toni Tabak Date: Fri, 19 Apr 2024 11:58:17 +0200 Subject: [PATCH] feat: specification implementation * chore: wip, revision typed Data * fix: resolved spec * chore: format and exports --- .github/workflows/publish.yml | 20 +- README.md | 19 +- package.json | 2 +- src/api/components.ts | 681 ++++++++++++++++++ src/common/constants.ts | 9 - src/common/miscellaneous.ts | 13 - src/index.ts | 16 +- .../StarknetWindowObject.ts | 0 src/wallet-api/components.ts | 147 ++++ src/wallet-api/constants.ts | 3 + src/wallet-api/errors.ts | 24 + src/{wallet-json-rpc => wallet-api}/events.ts | 6 +- .../methods.ts | 65 +- src/{common => wallet-api}/typedData.ts | 10 +- src/wallet-json-rpc/components.ts | 151 ---- tsconfig.base.json | 2 +- tsconfig.build.json | 2 +- tsconfig.json | 2 +- tsconfig.node.json | 2 +- 19 files changed, 940 insertions(+), 234 deletions(-) create mode 100644 src/api/components.ts delete mode 100644 src/common/constants.ts delete mode 100644 src/common/miscellaneous.ts rename src/{wallet-json-rpc => wallet-api}/StarknetWindowObject.ts (100%) create mode 100644 src/wallet-api/components.ts create mode 100644 src/wallet-api/constants.ts create mode 100644 src/wallet-api/errors.ts rename src/{wallet-json-rpc => wallet-api}/events.ts (78%) rename src/{wallet-json-rpc => wallet-api}/methods.ts (68%) rename src/{common => wallet-api}/typedData.ts (79%) delete mode 100644 src/wallet-json-rpc/components.ts diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index aa24dfc..770ff9a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -15,7 +15,7 @@ on: type: boolean default: true push: - branches: [ "main" ] + branches: ['main'] pull_request: branches: '*' @@ -25,15 +25,15 @@ jobs: name: Quality test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - name: Run tests on Node lts/* - uses: actions/setup-node@v4 - with: - node-version: lts/* - cache: 'npm' - - run: npm ci - - run: npm run pretest - + - uses: actions/checkout@v4 + - name: Run tests on Node lts/* + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: 'npm' + - run: npm ci + - run: npm run pretest + publish: runs-on: ubuntu-latest if: ${{ github.ref == 'refs/heads/main' }} diff --git a/README.md b/README.md index cc9b25c..b9e8572 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,30 @@ - - # starknet-types 🐺 Starknet TypeScript types 🚀 -[![GitHub Workflow Status](https://github.com/starknet-io/types-js/actions/workflows/test.yml/badge.svg)](https://github.com/starknet-io/types-js/actions/workflows/test.yml) +[![GitHub Workflow Status](https://github.com/starknet-io/types-js/actions/workflows/publish.yml/badge.svg)](https://github.com/starknet-io/types-js/actions/workflows/publish.yml) [![Project license](https://img.shields.io/github/license/starknet-io/types-js.svg?style=flat-square)](LICENSE) [![Pull Requests welcome](https://img.shields.io/badge/PRs-welcome-ff69b4.svg?style=flat-square)](https://github.com/starknet-io/types-js/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) Shared TypeScript type definitions for Starknet projects ## Types -- common enums -- Wallet JSON RPC Specification + +- (WIP) api [Starknet JSON RPC Specification](https://github.com/starkware-libs/starknet-specs/tree/master/api) +- wallet-api [Wallet JSON RPC Specification](https://github.com/starkware-libs/starknet-specs/tree/48e77bf4aaf687388b40b8198e3105401941517a/wallet-api) +- SNIP-12 [Hashing and signing typed structured data](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-12.md) + +## Versioning (wip - pending PR merge will be the first version in sync) + +(MAJOR.MINOR) Version of this package should follow [starknet-spec](https://github.com/starkware-libs/starknet-specs) semantic versioning. +PATCH version can diverge based on bug-fixes + +Starknet types v0.7.x <-> Starknet Spec v0.7.x ## Usage + As a package + ```bash npm i starknet-types ``` diff --git a/package.json b/package.json index 5de3ca7..4db83a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "starknet-types", - "version": "0.0.5", + "version": "0.7.1", "description": "Shared TypeScript definitions for Starknet projects", "homepage": "https://github.com/starknet-io/types-js", "keywords": [ diff --git a/src/api/components.ts b/src/api/components.ts new file mode 100644 index 0000000..29320d3 --- /dev/null +++ b/src/api/components.ts @@ -0,0 +1,681 @@ +// TODO: To be completed in future revisions +// This is in API SPEC extracted from starknetjs RPC 0.7 components.ts + +/** + * PRIMITIVES + */ + +/** + * A field element. represented by at most 63 hex digits + * @pattern ^0x(0|[a-fA-F1-9]{1}[a-fA-F0-9]{0,62})$ + */ +export type FELT = string; +/** + * an ethereum address represented as 40 hex digits + * @pattern ^0x[a-fA-F0-9]{40}$ + */ +export type ETH_ADDRESS = string; +/** + * A storage key. Represented as up to 62 hex digits, 3 bits, and 5 leading zeroes. + * @pattern ^0x(0|[0-7]{1}[a-fA-F0-9]{0,62}$) + */ +export type STORAGE_KEY = string; +export type ADDRESS = FELT; +export type NUM_AS_HEX = string; +/** + * 64 bit integers, represented by hex string of length at most 16 + * "pattern": "^0x(0|[a-fA-F1-9]{1}[a-fA-F0-9]{0,15})$" + */ +export type u64 = string; +/** + * 64 bit integers, represented by hex string of length at most 32 + * "pattern": "^0x(0|[a-fA-F1-9]{1}[a-fA-F0-9]{0,31})$" + */ +export type u128 = string; +export type SIGNATURE = Array; +export type BLOCK_NUMBER = number; +export type BLOCK_HASH = FELT; +export type TXN_HASH = FELT; +export type CHAIN_ID = NUM_AS_HEX; +export type STRUCT_ABI_TYPE = 'struct'; +export type EVENT_ABI_TYPE = 'event'; +export type FUNCTION_ABI_TYPE = 'function' | 'l1_handler' | 'constructor'; +// Represents the type of an entry point. +export type ENTRY_POINT_TYPE = 'EXTERNAL' | 'L1_HANDLER' | 'CONSTRUCTOR'; +// Represents the type of a function call. +export type CALL_TYPE = 'DELEGATE' | 'LIBRARY_CALL' | 'CALL'; +// Represents the status of the transaction +export type TXN_STATUS = 'RECEIVED' | 'REJECTED' | 'ACCEPTED_ON_L2' | 'ACCEPTED_ON_L1'; +// Flags that indicate how to simulate a given transaction. By default, the sequencer behavior is replicated locally (enough funds are expected to be in the account, and the fee will be deducted from the balance before the simulation of the next transaction). To skip the fee charge, use the SKIP_FEE_CHARGE flag. +export type SIMULATION_FLAG = 'SKIP_VALIDATE' | 'SKIP_FEE_CHARGE'; +// Data availability mode +export type DA_MODE = 'L1' | 'L2'; +export type TXN_TYPE = 'DECLARE' | 'DEPLOY' | 'DEPLOY_ACCOUNT' | 'INVOKE' | 'L1_HANDLER'; +export type TXN_FINALITY_STATUS = 'ACCEPTED_ON_L2' | 'ACCEPTED_ON_L1'; +export type TXN_EXECUTION_STATUS = 'SUCCEEDED' | 'REVERTED'; +export type BLOCK_STATUS = 'PENDING' | 'ACCEPTED_ON_L2' | 'ACCEPTED_ON_L1' | 'REJECTED'; +export type BLOCK_TAG = 'latest' | 'pending'; + +/** + * READ API + */ + +export type EVENTS_CHUNK = { + // Returns matching events + events: EMITTED_EVENT[]; + // Use this token in a subsequent query to obtain the next page. Should not appear if there are no more pages. + continuation_token?: string; +}; + +export type RESULT_PAGE_REQUEST = { + // The token returned from the previous query. If no token is provided the first page is returned. + continuation_token?: string; + // Chunk size + chunk_size: number; +}; + +export type EMITTED_EVENT = EVENT & { + block_hash: BLOCK_HASH; + block_number: BLOCK_NUMBER; + transaction_hash: TXN_HASH; +}; + +export type EVENT = { + from_address: ADDRESS; +} & EVENT_CONTENT; + +export type EVENT_CONTENT = { + keys: FELT[]; + data: FELT[]; +}; + +export type EVENT_FILTER = { + from_block?: BLOCK_ID; + to_block?: BLOCK_ID; + address?: ADDRESS; + keys?: FELT[][]; +}; + +export type BLOCK_ID = + | { + block_hash?: BLOCK_HASH; + block_number?: BLOCK_NUMBER; + } + | BLOCK_TAG; + +export type SYNC_STATUS = { + starting_block_hash: BLOCK_HASH; + starting_block_num: BLOCK_NUMBER; + current_block_hash: BLOCK_HASH; + current_block_num: BLOCK_NUMBER; + highest_block_hash: BLOCK_HASH; + highest_block_num: BLOCK_NUMBER; +}; + +export type NEW_CLASSES = { + class_hash: FELT; + compiled_class_hash: FELT; +}; + +export type REPLACED_CLASS = { + class_hash: FELT; + contract_address: FELT; +}; + +export type NONCE_UPDATE = { + contract_address: ADDRESS; + nonce: FELT; +}; + +export type STATE_DIFF = { + storage_diffs: CONTRACT_STORAGE_DIFF_ITEM[]; + deprecated_declared_classes: FELT[]; + declared_classes: NEW_CLASSES[]; + deployed_contracts: DEPLOYED_CONTRACT_ITEM[]; + replaced_classes: REPLACED_CLASS[]; + nonces: NONCE_UPDATE[]; +}; + +export type PENDING_STATE_UPDATE = { + old_root: FELT; + state_diff: STATE_DIFF; + block_hash: never; // diverge: this makes it distinct +}; + +export type STATE_UPDATE = { + block_hash: BLOCK_HASH; + old_root: FELT; + new_root: FELT; + state_diff: STATE_DIFF; +}; + +export type BLOCK_BODY_WITH_TX_HASHES = { + transactions: TXN_HASH[]; +}; + +export type BLOCK_BODY_WITH_TXS = { + transactions: (TXN & { + transaction_hash: TXN_HASH; + })[]; +}; + +export type BLOCK_BODY_WITH_RECEIPTS = { + transactions: { + transaction: TXN; + receipt: TXN_RECEIPT; + }[]; +}; + +export type BLOCK_HEADER = { + block_hash: BLOCK_HASH; + parent_hash: BLOCK_HASH; + block_number: BLOCK_NUMBER; + new_root: FELT; + timestamp: number; + sequencer_address: FELT; + l1_gas_price: RESOURCE_PRICE; + l1_data_gas_price: RESOURCE_PRICE; + l1_da_mode: 'BLOB' | 'CALLDATA'; + starknet_version: string; +}; + +export type PENDING_BLOCK_HEADER = { + parent_hash: BLOCK_HASH; + timestamp: number; + sequencer_address: FELT; + l1_gas_price: RESOURCE_PRICE; + l1_data_gas_price: RESOURCE_PRICE; + l1_da_mode: 'BLOB' | 'CALLDATA'; + starknet_version: string; +}; + +export type BLOCK_WITH_TX_HASHES = { status: BLOCK_STATUS } & BLOCK_HEADER & + BLOCK_BODY_WITH_TX_HASHES; + +export type BLOCK_WITH_TXS = { status: BLOCK_STATUS } & BLOCK_HEADER & BLOCK_BODY_WITH_TXS; + +export type BLOCK_WITH_RECEIPTS = { + status: BLOCK_STATUS; +} & BLOCK_HEADER & + BLOCK_BODY_WITH_RECEIPTS; + +export type PENDING_BLOCK_WITH_TX_HASHES = BLOCK_BODY_WITH_TX_HASHES & PENDING_BLOCK_HEADER; + +export type PENDING_BLOCK_WITH_TXS = BLOCK_BODY_WITH_TXS & PENDING_BLOCK_HEADER; + +export type PENDING_BLOCK_WITH_RECEIPTS = BLOCK_BODY_WITH_RECEIPTS & PENDING_BLOCK_HEADER; + +export type DEPLOYED_CONTRACT_ITEM = { + address: FELT; + class_hash: FELT; +}; + +export type CONTRACT_STORAGE_DIFF_ITEM = { + // The contract address for which the storage changed (in FELT format) + address: string; + // The changes in the storage of the contract + storage_entries: StorageDiffItem[]; +}; + +export type StorageDiffItem = { + // The key of the changed value (in FELT format) + key: string; + // The new value applied to the given address (in FELT format) + value: string; +}; + +export type TXN = INVOKE_TXN | L1_HANDLER_TXN | DECLARE_TXN | DEPLOY_TXN | DEPLOY_ACCOUNT_TXN; + +export type DECLARE_TXN = DECLARE_TXN_V0 | DECLARE_TXN_V1 | DECLARE_TXN_V2 | DECLARE_TXN_V3; + +export type DECLARE_TXN_V0 = { + type: 'DECLARE'; + sender_address: ADDRESS; + max_fee: FELT; + version: '0x0' | '0x100000000000000000000000000000000'; + signature: SIGNATURE; + class_hash: FELT; +}; + +export type DECLARE_TXN_V1 = { + type: 'DECLARE'; + sender_address: ADDRESS; + max_fee: FELT; + version: '0x1' | '0x100000000000000000000000000000001'; + signature: SIGNATURE; + nonce: FELT; + class_hash: FELT; +}; + +export type DECLARE_TXN_V2 = { + type: 'DECLARE'; + sender_address: ADDRESS; + compiled_class_hash: FELT; + max_fee: FELT; + version: '0x2' | '0x100000000000000000000000000000002'; + signature: SIGNATURE; + nonce: FELT; + class_hash: FELT; +}; + +export type DECLARE_TXN_V3 = { + type: 'DECLARE'; + sender_address: ADDRESS; + compiled_class_hash: FELT; + version: '0x3' | '0x100000000000000000000000000000003'; + signature: SIGNATURE; + nonce: FELT; + class_hash: FELT; + // new... + resource_bounds: RESOURCE_BOUNDS_MAPPING; + tip: u64; + paymaster_data: FELT[]; + account_deployment_data: FELT[]; + nonce_data_availability_mode: DA_MODE; + fee_data_availability_mode: DA_MODE; +}; + +export type BROADCASTED_TXN = + | BROADCASTED_INVOKE_TXN + | BROADCASTED_DECLARE_TXN + | BROADCASTED_DEPLOY_ACCOUNT_TXN; + +export type BROADCASTED_INVOKE_TXN = INVOKE_TXN; + +export type BROADCASTED_DEPLOY_ACCOUNT_TXN = DEPLOY_ACCOUNT_TXN; + +export type BROADCASTED_DECLARE_TXN = + | BROADCASTED_DECLARE_TXN_V1 + | BROADCASTED_DECLARE_TXN_V2 + | BROADCASTED_DECLARE_TXN_V3; + +export type BROADCASTED_DECLARE_TXN_V1 = { + type: 'DECLARE'; + sender_address: ADDRESS; + max_fee: FELT; + // todo: check if working, prev i fixed it with NUM_AS_HEX + version: '0x1' | '0x100000000000000000000000000000001'; + signature: SIGNATURE; + nonce: FELT; + contract_class: DEPRECATED_CONTRACT_CLASS; +}; + +export type BROADCASTED_DECLARE_TXN_V2 = { + type: 'DECLARE'; + sender_address: ADDRESS; + compiled_class_hash: FELT; + max_fee: FELT; + version: '0x2' | '0x100000000000000000000000000000002'; + signature: SIGNATURE; + nonce: FELT; + contract_class: CONTRACT_CLASS; +}; + +export type BROADCASTED_DECLARE_TXN_V3 = { + type: 'DECLARE'; + sender_address: ADDRESS; + compiled_class_hash: FELT; + version: '0x3' | '0x100000000000000000000000000000003'; + signature: SIGNATURE; + nonce: FELT; + contract_class: CONTRACT_CLASS; + // new... + resource_bounds: RESOURCE_BOUNDS_MAPPING; + tip: u64; + paymaster_data: FELT[]; + account_deployment_data: FELT[]; + nonce_data_availability_mode: DA_MODE; + fee_data_availability_mode: DA_MODE; +}; + +export type DEPLOY_ACCOUNT_TXN = DEPLOY_ACCOUNT_TXN_V1 | DEPLOY_ACCOUNT_TXN_V3; + +export type DEPLOY_ACCOUNT_TXN_V1 = { + type: 'DEPLOY_ACCOUNT'; + max_fee: FELT; + version: '0x1' | '0x100000000000000000000000000000001'; + signature: SIGNATURE; + nonce: FELT; + contract_address_salt: FELT; + constructor_calldata: FELT[]; + class_hash: FELT; +}; + +export type DEPLOY_ACCOUNT_TXN_V3 = { + type: 'DEPLOY_ACCOUNT'; + version: '0x3' | '0x100000000000000000000000000000003'; + signature: SIGNATURE; + nonce: FELT; + contract_address_salt: FELT; + constructor_calldata: FELT[]; + class_hash: FELT; + resource_bounds: RESOURCE_BOUNDS_MAPPING; + tip: u64; + paymaster_data: FELT[]; + nonce_data_availability_mode: DA_MODE; + fee_data_availability_mode: DA_MODE; +}; + +export type DEPLOY_TXN = { + type: 'DEPLOY'; + version: FELT; + contract_address_salt: FELT; + constructor_calldata: FELT[]; + class_hash: FELT; +}; + +export type INVOKE_TXN = INVOKE_TXN_V0 | INVOKE_TXN_V1 | INVOKE_TXN_V3; + +export type INVOKE_TXN_V0 = { + type: 'INVOKE'; + max_fee: FELT; + version: '0x0' | '0x100000000000000000000000000000000'; + signature: SIGNATURE; + contract_address: ADDRESS; + entry_point_selector: FELT; + calldata: FELT[]; +}; + +export type INVOKE_TXN_V1 = { + type: 'INVOKE'; + sender_address: ADDRESS; + calldata: FELT[]; + max_fee: FELT; + version: '0x1' | '0x100000000000000000000000000000001'; + signature: SIGNATURE; + nonce: FELT; +}; + +export type INVOKE_TXN_V3 = { + type: 'INVOKE'; + sender_address: ADDRESS; + calldata: FELT[]; + version: '0x3' | '0x100000000000000000000000000000003'; + signature: SIGNATURE; + nonce: FELT; + resource_bounds: RESOURCE_BOUNDS_MAPPING; + tip: u64; + paymaster_data: FELT[]; + account_deployment_data: FELT[]; + nonce_data_availability_mode: DA_MODE; + fee_data_availability_mode: DA_MODE; +}; + +export type L1_HANDLER_TXN = { + version: '0x0'; + type: 'L1_HANDLER'; + nonce: NUM_AS_HEX; +} & FUNCTION_CALL; + +export type COMMON_RECEIPT_PROPERTIES = { + transaction_hash: TXN_HASH; + actual_fee: FEE_PAYMENT; + finality_status: TXN_FINALITY_STATUS; + messages_sent: MSG_TO_L1[]; + events: EVENT[]; + execution_resources: EXECUTION_RESOURCES; +} & (SUCCESSFUL_COMMON_RECEIPT_PROPERTIES | REVERTED_COMMON_RECEIPT_PROPERTIES); + +type SUCCESSFUL_COMMON_RECEIPT_PROPERTIES = { + execution_status: 'SUCCEEDED'; +}; + +type REVERTED_COMMON_RECEIPT_PROPERTIES = { + execution_status: 'REVERTED'; + revert_reason: string; +}; + +export type INVOKE_TXN_RECEIPT = { + type: 'INVOKE'; +} & COMMON_RECEIPT_PROPERTIES; + +export type DECLARE_TXN_RECEIPT = { + type: 'DECLARE'; +} & COMMON_RECEIPT_PROPERTIES; + +export type DEPLOY_ACCOUNT_TXN_RECEIPT = { + type: 'DEPLOY_ACCOUNT'; + contract_address: FELT; +} & COMMON_RECEIPT_PROPERTIES; + +export type DEPLOY_TXN_RECEIPT = { + type: 'DEPLOY'; + contract_address: FELT; +} & COMMON_RECEIPT_PROPERTIES; + +export type L1_HANDLER_TXN_RECEIPT = { + type: 'L1_HANDLER'; + message_hash: NUM_AS_HEX; +} & COMMON_RECEIPT_PROPERTIES; + +export type TXN_RECEIPT = + | INVOKE_TXN_RECEIPT + | L1_HANDLER_TXN_RECEIPT + | DECLARE_TXN_RECEIPT + | DEPLOY_TXN_RECEIPT + | DEPLOY_ACCOUNT_TXN_RECEIPT; + +export type TXN_RECEIPT_WITH_BLOCK_INFO = TXN_RECEIPT & { + block_hash?: BLOCK_HASH; + block_number?: BLOCK_NUMBER; +}; + +export type MSG_TO_L1 = { + from_address: FELT; + to_address: FELT; + payload: FELT[]; +}; + +export type MSG_FROM_L1 = { + from_address: ETH_ADDRESS; + to_address: ADDRESS; + entry_point_selector: FELT; + payload: FELT[]; +}; + +export type FUNCTION_CALL = { + contract_address: ADDRESS; + entry_point_selector: FELT; + calldata: FELT[]; +}; + +export type CONTRACT_CLASS = { + sierra_program: FELT[]; + contract_class_version: string; + entry_points_by_type: { + CONSTRUCTOR: SIERRA_ENTRY_POINT[]; + EXTERNAL: SIERRA_ENTRY_POINT[]; + L1_HANDLER: SIERRA_ENTRY_POINT[]; + }; + abi: string; +}; + +export type DEPRECATED_CONTRACT_CLASS = { + program: string; + entry_points_by_type: { + CONSTRUCTOR: DEPRECATED_CAIRO_ENTRY_POINT[]; + EXTERNAL: DEPRECATED_CAIRO_ENTRY_POINT[]; + L1_HANDLER: DEPRECATED_CAIRO_ENTRY_POINT[]; + }; + abi: CONTRACT_ABI; +}; + +export type DEPRECATED_CAIRO_ENTRY_POINT = { + offset: NUM_AS_HEX | number; + selector: FELT; +}; + +export type SIERRA_ENTRY_POINT = { + selector: FELT; + function_idx: number; +}; + +export type CONTRACT_ABI = readonly CONTRACT_ABI_ENTRY[]; + +export type CONTRACT_ABI_ENTRY = { + selector: FELT; + input: string; + output: string; +}; + +export type STRUCT_ABI_ENTRY = { + type: STRUCT_ABI_TYPE; + name: string; + size: number; + members: STRUCT_MEMBER[]; +}; + +export type STRUCT_MEMBER = TYPED_PARAMETER & { + offset: number; +}; + +export type EVENT_ABI_ENTRY = { + type: EVENT_ABI_TYPE; + name: string; + keys: TYPED_PARAMETER[]; + data: TYPED_PARAMETER[]; +}; + +export type FUNCTION_STATE_MUTABILITY = 'view'; + +export type FUNCTION_ABI_ENTRY = { + type: FUNCTION_ABI_TYPE; + name: string; + inputs: TYPED_PARAMETER[]; + outputs: TYPED_PARAMETER[]; + stateMutability: FUNCTION_STATE_MUTABILITY; +}; + +export type TYPED_PARAMETER = { + name: string; + type: string; +}; + +export type SIMULATION_FLAG_FOR_ESTIMATE_FEE = 'SKIP_VALIDATE'; +export type PRICE_UNIT = 'WEI' | 'FRI'; + +export type FEE_ESTIMATE = { + gas_consumed: FELT; + gas_price: FELT; + data_gas_consumed: FELT; + data_gas_price: FELT; + overall_fee: FELT; + unit: PRICE_UNIT; +}; + +export type FEE_PAYMENT = { + amount: FELT; + unit: PRICE_UNIT; +}; + +export type RESOURCE_BOUNDS_MAPPING = { + l1_gas: RESOURCE_BOUNDS; + l2_gas: RESOURCE_BOUNDS; +}; + +export type RESOURCE_BOUNDS = { + max_amount: u64; + max_price_per_unit: u128; +}; + +export type RESOURCE_PRICE = { + price_in_fri: FELT; + price_in_wei: FELT; +}; + +export type COMPUTATION_RESOURCES = { + steps: number; + memory_holes?: number; + range_check_builtin_applications?: number; + pedersen_builtin_applications?: number; + poseidon_builtin_applications?: number; + ec_op_builtin_applications?: number; + ecdsa_builtin_applications?: number; + bitwise_builtin_applications?: number; + keccak_builtin_applications?: number; + segment_arena_builtin?: number; +}; + +export type EXECUTION_RESOURCES = COMPUTATION_RESOURCES & { + data_availability: { + l1_gas: number; + l1_data_gas: number; + }; +}; + +/** + * TRACE API + */ + +// Represents a transaction trace including the execution details. +export type TRANSACTION_TRACE = { + invoke_tx_trace?: INVOKE_TXN_TRACE; + declare_tx_trace?: DECLARE_TXN_TRACE; + deploy_account_tx_trace?: DEPLOY_ACCOUNT_TXN_TRACE; + l1_handler_tx_trace?: L1_HANDLER_TXN_TRACE; +}; + +// Represents a transaction trace for an invoke transaction. +export type INVOKE_TXN_TRACE = { + type: 'INVOKE'; + execute_invocation: FUNCTION_INVOCATION | { revert_reason: string }; + validate_invocation?: FUNCTION_INVOCATION; + fee_transfer_invocation?: FUNCTION_INVOCATION; + state_diff?: STATE_DIFF; + execution_resources: EXECUTION_RESOURCES; +}; + +// Represents a transaction trace for a declare transaction. +export type DECLARE_TXN_TRACE = { + type: 'DECLARE'; + validate_invocation?: FUNCTION_INVOCATION; + fee_transfer_invocation?: FUNCTION_INVOCATION; + state_diff?: STATE_DIFF; + execution_resources: EXECUTION_RESOURCES; +}; + +// Represents a transaction trace for a deploy account transaction. +export type DEPLOY_ACCOUNT_TXN_TRACE = { + type: 'DEPLOY_ACCOUNT'; + constructor_invocation: FUNCTION_INVOCATION; + validate_invocation?: FUNCTION_INVOCATION; + fee_transfer_invocation?: FUNCTION_INVOCATION; + state_diff?: STATE_DIFF; + execution_resources: EXECUTION_RESOURCES; +}; + +// Represents a transaction trace for an L1 handler transaction. +export type L1_HANDLER_TXN_TRACE = { + type: 'L1_HANDLER'; + function_invocation: FUNCTION_INVOCATION; + state_diff?: STATE_DIFF; + execution_resources: EXECUTION_RESOURCES; +}; + +// Represents a nested function call. +export type NESTED_CALL = FUNCTION_INVOCATION; + +// Represents a function invocation along with its execution details. +export type FUNCTION_INVOCATION = FUNCTION_CALL & { + caller_address: string; + class_hash: string; + entry_point_type: ENTRY_POINT_TYPE; + call_type: CALL_TYPE; + result: string[]; + calls: NESTED_CALL[]; + events: ORDERED_EVENT[]; + messages: ORDERED_MESSAGE[]; + execution_resources: COMPUTATION_RESOURCES; +}; + +// Represents an ordered event alongside its order within the transaction. +export type ORDERED_EVENT = { + order: number; + event: EVENT; +}; + +// Represents an ordered message alongside its order within the transaction. +export type ORDERED_MESSAGE = { + order: number; + message: MSG_TO_L1; +}; diff --git a/src/common/constants.ts b/src/common/constants.ts deleted file mode 100644 index b9df159..0000000 --- a/src/common/constants.ts +++ /dev/null @@ -1,9 +0,0 @@ -export enum StarknetChainId { - SN_MAIN = '0x534e5f4d41494e', - SN_GOERLI = '0x534e5f474f45524c49', - SN_SEPOLIA = '0x534e5f5345504f4c4941', -} - -export enum Permission { - Accounts = 'accounts', -} diff --git a/src/common/miscellaneous.ts b/src/common/miscellaneous.ts deleted file mode 100644 index 5ff225a..0000000 --- a/src/common/miscellaneous.ts +++ /dev/null @@ -1,13 +0,0 @@ -// TODO: To be resolved in future revisions -export type FELT = string; - -export type Call = { - contract_address: FELT; - entrypoint: string; - calldata?: FELT[]; -}; - -export type SIERRA_ENTRY_POINT = { - selector: FELT; - function_idx: number; -}; diff --git a/src/index.ts b/src/index.ts index d13cee2..4ef7345 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,8 @@ -export * from './common/constants.js'; -export * from './common/miscellaneous.js'; -export * from './common/typedData.js'; - -export * from './wallet-json-rpc/StarknetWindowObject.js'; -export * from './wallet-json-rpc/components.js'; -export * from './wallet-json-rpc/methods.js'; -export * from './wallet-json-rpc/events.js'; +export * from './api/components.js'; +export * from './wallet-api/constants.js'; +export * from './wallet-api/typedData.js'; +export * from './wallet-api/StarknetWindowObject.js'; +export * from './wallet-api/components.js'; +export * from './wallet-api/methods.js'; +export * from './wallet-api/events.js'; +export * from './wallet-api/errors.js'; diff --git a/src/wallet-json-rpc/StarknetWindowObject.ts b/src/wallet-api/StarknetWindowObject.ts similarity index 100% rename from src/wallet-json-rpc/StarknetWindowObject.ts rename to src/wallet-api/StarknetWindowObject.ts diff --git a/src/wallet-api/components.ts b/src/wallet-api/components.ts new file mode 100644 index 0000000..abbb816 --- /dev/null +++ b/src/wallet-api/components.ts @@ -0,0 +1,147 @@ +import type { CONTRACT_CLASS, FELT, ADDRESS, SIGNATURE } from '../api/components.js'; + +/** + * Account Address + */ +export type Address = ADDRESS; + +export type Signature = SIGNATURE; + +/** + * The transaction hash, as assigned in Starknet + */ +export type PADDED_TXN_HASH = PADDED_FELT; // TODO: Should be like TXN_HASH_PADDED to avoid collision with api TXN_HASH + +/** + * A padded felt represent 0x0 + (0-7) + (62 hex digits) + * @pattern ^0x(0[0-7]{1}[a-fA-F0-9]{62}$) + */ +export type PADDED_FELT = string; // TODO: STORAGE_KEY should also be PADDED_FELT to remove duplication, and padded felt added to api spec ? + +/** + * A Starknet RPC spec version, only two numbers are provided + * @pattern ^[0-9]+\\.[0-9]+$ + */ +export type SpecVersion = string; + +/** + * ERC20 Token Symbol (min:1 char - max:6 chars) + * @pattern ^[A-Za-z0-9]{1,6}$ + */ +export type TokenSymbol = string; // TODO: I would recommend rename to TOKEN_SYMBOL to avoid collision with js Symbol (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) + +/** + * chain id, given in hex representation. + * @pattern "^0x[a-fA-F0-9]+$" + */ +export type ChainId = string; + +/** + * Starknet Token + * Details of an onchain Starknet ERC20 token + */ +export type Asset = { + type: 'ERC20'; // The asset's interface, e.g. 'ERC20' + options: { + address: Address; // The hexadecimal Starknet address of the token contract + symbol?: TokenSymbol; // A ticker symbol or shorthand, up to 5 alphanumerical characters + decimals?: number; // The number of asset decimals + image?: string; // A string url of the token logo + name?: string; // The name of the token - not in spec + }; +}; + +// SPEC: STARKNET_CHAIN +export type StarknetChain = { + id: string; + chain_id: ChainId; + chain_name: string; + rpc_urls?: string[]; + block_explorer_url?: string[]; + native_currency?: Asset; + icon_urls?: string[]; // Currently ignored. +}; + +// SPEC: INVOKE_CALL +export type Call = { + contract_address: Address; + entry_point: string; + calldata?: FELT[]; +}; + +/** + * INVOKE_TXN_V1 + * @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json + */ +export interface AddInvokeTransactionParameters { + /** + * Calls to invoke by the account + */ + calls: Call[]; +} +export interface AddInvokeTransactionResult { + /** + * The hash of the invoke transaction + */ + transaction_hash: PADDED_TXN_HASH; +} + +/** + * SPEC: DECLARE_TXN + */ +export interface AddDeclareTransactionParameters { + compiled_class_hash: FELT; + class_hash?: FELT; + contract_class: CONTRACT_CLASS; +} + +export interface AddDeclareTransactionResult { + /** + * The hash of the declare transaction + */ + transaction_hash: PADDED_TXN_HASH; + /** + * The hash of the declared class + */ + class_hash: PADDED_FELT; +} + +/** + * EIP-1102: + * @see https://eips.ethereum.org/EIPS/eip-1102 + */ +export interface RequestAccountsParameters { + /** + * If true, the wallet will not show the wallet-unlock UI in case of a locked wallet, + * nor the dApp-approve UI in case of a non-allowed dApp. + */ + silent_mode?: boolean; +} + +/** + * EIP-747: + * @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-747.md + */ +export interface WatchAssetParameters extends Asset {} + +/** + * EIP-3085: + * @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3085.md + */ +export interface AddStarknetChainParameters extends StarknetChain {} + +export interface SwitchStarknetChainParameters { + chainId: ChainId; +} + +/** + * SPEC: ACCOUNT_DEPLOYMENT_DATA + */ +export interface AccountDeploymentData { + address: Address; // the expected address, used to double-check the returned data + class_hash: FELT; // The class hash of the contract to deploy + salt: FELT; // The salt used for the computation of the account address + calldata: FELT[]; // An array of felts + sigdata?: FELT[]; // An optional array of felts to be added in the signature + version: 0 | 1; // Cairo version (an integer) +} diff --git a/src/wallet-api/constants.ts b/src/wallet-api/constants.ts new file mode 100644 index 0000000..13611eb --- /dev/null +++ b/src/wallet-api/constants.ts @@ -0,0 +1,3 @@ +export enum Permission { + Accounts = 'accounts', +} diff --git a/src/wallet-api/errors.ts b/src/wallet-api/errors.ts new file mode 100644 index 0000000..7d90373 --- /dev/null +++ b/src/wallet-api/errors.ts @@ -0,0 +1,24 @@ +export interface NOT_ERC20 { + code: 111; + message: 'An error occurred (NOT_ERC20)'; +} + +export interface UNLISTED_NETWORK { + code: 112; + message: 'An error occurred (UNLISTED_NETWORK)'; +} + +export interface USER_REFUSED_OP { + code: 113; + message: 'An error occurred (USER_REFUSED_OP)'; +} + +export interface INVALID_REQUEST_PAYLOAD { + code: 114; + message: 'An error occurred (INVALID_REQUEST_PAYLOAD)'; +} + +export interface UNKNOWN_ERROR { + code: 163; + message: 'An error occurred (UNKNOWN_ERROR)'; +} diff --git a/src/wallet-json-rpc/events.ts b/src/wallet-api/events.ts similarity index 78% rename from src/wallet-json-rpc/events.ts rename to src/wallet-api/events.ts index 941f6ab..036d447 100644 --- a/src/wallet-json-rpc/events.ts +++ b/src/wallet-api/events.ts @@ -1,8 +1,8 @@ -// Optimization on events -import { StarknetChainId } from '../common/constants.js'; +import type { ChainId } from './components.js'; +// Optimization on events export type AccountChangeEventHandler = (accounts?: string[]) => void; -export type NetworkChangeEventHandler = (chainId?: StarknetChainId, accounts?: string[]) => void; +export type NetworkChangeEventHandler = (chainId?: ChainId, accounts?: string[]) => void; export interface WalletEventHandlers { accountsChanged: AccountChangeEventHandler; diff --git a/src/wallet-json-rpc/methods.ts b/src/wallet-api/methods.ts similarity index 68% rename from src/wallet-json-rpc/methods.ts rename to src/wallet-api/methods.ts index 09b4d26..af25581 100644 --- a/src/wallet-json-rpc/methods.ts +++ b/src/wallet-api/methods.ts @@ -1,15 +1,18 @@ -import { Permission, StarknetChainId } from '../common/constants.js'; -import type { TypedData } from '../common/typedData.js'; +import { Permission } from './constants.js'; +import type { TypedData } from './typedData.js'; +import * as Errors from './errors.js'; import type { + AccountDeploymentData, AddDeclareTransactionParameters, AddDeclareTransactionResult, - AddDeployAccountTransactionParameters, - AddDeployAccountTransactionResult, AddInvokeTransactionParameters, AddInvokeTransactionResult, AddStarknetChainParameters, - GetDeploymentDataResult, + Address, + ChainId, RequestAccountsParameters, + Signature, + SpecVersion, SwitchStarknetChainParameters, WatchAssetParameters, } from './components.js'; @@ -22,16 +25,16 @@ export interface RpcTypeToMessageMap { * Get permissions from the wallet. * @returns An array of permissions. */ - wallet_getPermissions: { params?: never; result: Permission[] }; + wallet_getPermissions: { params?: never; result: Permission[] | [] }; /** - * Request accounts from the wallet. + * Request active accounts from the wallet. * @param params Optional parameters for requesting accounts. * @returns An array of account addresses as strings. */ wallet_requestAccounts: { params?: RequestAccountsParameters; - result: string[]; + result: Address[]; }; /** @@ -39,7 +42,15 @@ export interface RpcTypeToMessageMap { * @param params The parameters required to watch an asset. * @returns A boolean indicating if the operation was successful. */ - wallet_watchAsset: { params: WatchAssetParameters; result: boolean }; + wallet_watchAsset: { + params: WatchAssetParameters; + result: boolean; + errors: + | Errors.NOT_ERC20 + | Errors.INVALID_REQUEST_PAYLOAD + | Errors.USER_REFUSED_OP + | Errors.UNKNOWN_ERROR; + }; /** * Add a new Starknet chain to the wallet. @@ -49,6 +60,7 @@ export interface RpcTypeToMessageMap { wallet_addStarknetChain: { params: AddStarknetChainParameters; result: boolean; + errors: Errors.INVALID_REQUEST_PAYLOAD | Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; }; /** @@ -59,28 +71,34 @@ export interface RpcTypeToMessageMap { wallet_switchStarknetChain: { params: SwitchStarknetChainParameters; result: boolean; + errors: Errors.UNLISTED_NETWORK | Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; }; /** * Request the current chain ID from the wallet. * @returns The current Starknet chain ID. */ - wallet_requestChainId: { params?: never; result: StarknetChainId }; + wallet_requestChainId: { params?: never; result: ChainId }; /** * Get deployment data for a contract. * @returns The deployment data result. */ - wallet_deploymentData: { params?: never; result: GetDeploymentDataResult }; + wallet_deploymentData: { + params?: never; + result: AccountDeploymentData; + errors: Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; + }; /** * Add an invoke transaction to the wallet. * @param params The parameters required for the invoke transaction. * @returns The result of adding the invoke transaction. */ - starknet_addInvokeTransaction: { + wallet_addInvokeTransaction: { params: AddInvokeTransactionParameters; result: AddInvokeTransactionResult; + errors: Errors.INVALID_REQUEST_PAYLOAD | Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; }; /** @@ -88,19 +106,10 @@ export interface RpcTypeToMessageMap { * @param params The parameters required for the declare transaction. * @returns The result of adding the declare transaction. */ - starknet_addDeclareTransaction: { + wallet_addDeclareTransaction: { params: AddDeclareTransactionParameters; result: AddDeclareTransactionResult; - }; - - /** - * Add a deploy account transaction to the wallet. - * @param params The parameters required for the deploy account transaction. - * @returns The result of adding the deploy account transaction. - */ - starknet_addDeployAccountTransaction: { - params: AddDeployAccountTransactionParameters; - result: AddDeployAccountTransactionResult; + errors: Errors.INVALID_REQUEST_PAYLOAD | Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; }; /** @@ -108,13 +117,17 @@ export interface RpcTypeToMessageMap { * @param params The typed data to sign. * @returns An array of signatures as strings. */ - starknet_signTypedData: { params: TypedData; result: string[] }; + wallet_signTypedData: { + params: TypedData; + result: Signature; + errors: Errors.INVALID_REQUEST_PAYLOAD | Errors.USER_REFUSED_OP | Errors.UNKNOWN_ERROR; + }; /** - * Get the list of supported specifications. + * Get the list of supported RPC specification versions. * @returns An array of supported specification strings. */ - starknet_supportedSpecs: { params?: never; result: string[] }; + wallet_supportedSpecs: { params?: never; result: SpecVersion[] }; } export type RpcMessage = { diff --git a/src/common/typedData.ts b/src/wallet-api/typedData.ts similarity index 79% rename from src/common/typedData.ts rename to src/wallet-api/typedData.ts index 1753389..273e578 100644 --- a/src/common/typedData.ts +++ b/src/wallet-api/typedData.ts @@ -9,6 +9,7 @@ export type StarknetEnumType = { contains: string; }; +// SPEC: STARKNET_MERKLE_TYPE export type StarknetMerkleType = { name: string; type: 'merkletree'; @@ -16,8 +17,8 @@ export type StarknetMerkleType = { }; /** + * SPEC: STARKNET_TYPE * A single type, as part of a struct. The `type` field can be any of the EIP-712 supported types. - * * Note that the `uint` and `int` aliases like in Solidity, and fixed point numbers are not supported by the EIP-712 * standard. */ @@ -35,16 +36,17 @@ export type StarknetType = export interface StarknetDomain extends Record { name?: string; version?: string; - chainId?: string | number; + chainId?: string | number; // TODO: check resolution, diverge from SPEC and follow SNIP-12 revision?: string; } /** + * SPEC: TYPED_DATA * The complete typed data, with all the structs, domain data, primary type of the message, and the message itself. */ export interface TypedData { types: Record; - primaryType: string; + primaryType: string; // TODO: check resolution, diverge from SPEC and follow SNIP-12 domain: StarknetDomain; - message: Record; + message: object; } diff --git a/src/wallet-json-rpc/components.ts b/src/wallet-json-rpc/components.ts deleted file mode 100644 index 7a59104..0000000 --- a/src/wallet-json-rpc/components.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { Call, FELT, SIERRA_ENTRY_POINT } from '../common/miscellaneous.js'; - -/** - * INVOKE_TXN_V1 - * @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json - */ -export interface AddInvokeTransactionParameters { - /** - * Calls to invoke by the account - */ - calls: Call[]; -} -export interface AddInvokeTransactionResult { - /** - * The hash of the invoke transaction - */ - transaction_hash: FELT; -} - -/** - * BROADCASTED_DECLARE_TXN_V2 - * @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json - */ -export interface AddDeclareTransactionParameters { - /** - * The hash of the Cairo assembly resulting from the Sierra compilation - */ - compiled_class_hash: FELT; - contract_class: { - /** - * The list of Sierra instructions of which the program consists - */ - sierra_program: FELT[]; - /** - * The version of the contract class object. Currently, the Starknet OS supports version 0.1.0 - */ - contract_class_version: string; - /** - * Entry points by type - */ - entry_points_by_type: { - CONSTRUCTOR: SIERRA_ENTRY_POINT[]; - EXTERNAL: SIERRA_ENTRY_POINT[]; - L1_HANDLER: SIERRA_ENTRY_POINT[]; - }; - /** - * The class ABI, as supplied by the user declaring the class - */ - abi?: string; - }; -} -export interface AddDeclareTransactionResult { - /** - * The hash of the declare transaction - */ - transaction_hash: FELT; - /** - * The hash of the declared class - */ - class_hash: FELT; -} - -/** - * DEPLOY_ACCOUNT_TXN_V1 - * @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json - */ -export interface AddDeployAccountTransactionParameters { - /** - * The salt for the address of the deployed contract - */ - contract_address_salt: FELT; - /** - * The parameters passed to the constructor - */ - constructor_calldata: FELT[]; - /** - * The hash of the deployed contract's class - */ - class_hash: FELT; -} -export interface AddDeployAccountTransactionResult { - /** - * The hash of the deploy transaction - */ - transaction_hash: FELT; - /** - * The address of the new contract - */ - contract_address: FELT; -} - -/** - * EIP-1102: - * @see https://eips.ethereum.org/EIPS/eip-1102 - */ -export interface RequestAccountsParameters { - /** - * If true, the wallet will not show the wallet-unlock UI in case of a locked wallet, - * nor the dApp-approve UI in case of a non-allowed dApp. - */ - silentMode?: boolean; -} - -/** - * EIP-747: - * @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-747.md - */ -export interface WatchAssetParameters { - type: 'ERC20'; // The asset's interface, e.g. 'ERC20' - options: { - address: string; // The hexadecimal Starknet address of the token contract - symbol?: string; // A ticker symbol or shorthand, up to 5 alphanumerical characters - decimals?: number; // The number of asset decimals - image?: string; // A string url of the token logo - name?: string; // The name of the token - not in spec - }; -} - -/** - * EIP-3085: - * @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3085.md - */ -export interface AddStarknetChainParameters { - id: string; - chainId: string; // A 0x-prefixed hexadecimal string - chainName: string; - rpcUrls?: string[]; - blockExplorerUrls?: string[]; - - nativeCurrency?: { - address: string; // Not part of the standard, but required by Starknet as it can work with any ERC20 token as the fee token - name: string; - symbol: string; // 2-6 characters long - decimals: number; - }; // Currently ignored. - iconUrls?: string[]; // Currently ignored. -} - -export interface SwitchStarknetChainParameters { - chainId: string; // A 0x-prefixed hexadecimal string -} - -// see https://community.starknet.io/t/snip-deployment-interface-between-dapps-and-wallets/101923 -export interface GetDeploymentDataResult { - address: FELT; // the expected address, used to double-check the returned data - class_hash: FELT; // The class hash of the contract to deploy - salt: FELT; // The salt used for the computation of the account address - calldata: FELT[]; // An array of felts - sigdata?: FELT[]; // An optional array of felts to be added in the signature - version: 0 | 1; // Cairo version (an integer) -} diff --git a/tsconfig.base.json b/tsconfig.base.json index adcd5d7..001b59b 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -42,4 +42,4 @@ // Skip type checking for node modules "skipLibCheck": true } -} \ No newline at end of file +} diff --git a/tsconfig.build.json b/tsconfig.build.json index ce4f3a8..713b654 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -8,4 +8,4 @@ "sourceMap": true, "rootDir": "./src" } -} \ No newline at end of file +} diff --git a/tsconfig.json b/tsconfig.json index d176f03..7a64997 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,4 +7,4 @@ "compilerOptions": { "baseUrl": "." } -} \ No newline at end of file +} diff --git a/tsconfig.node.json b/tsconfig.node.json index 65b7b00..75b173b 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -7,4 +7,4 @@ "moduleResolution": "Node", "allowSyntheticDefaultImports": true } -} \ No newline at end of file +}