starknet 4.4.2 → 4.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +3 -1
  3. package/__tests__/defaultProvider.test.ts +7 -9
  4. package/__tests__/rpcProvider.test.ts +107 -12
  5. package/__tests__/utils/utils.test.ts +17 -0
  6. package/account/default.js +13 -7
  7. package/dist/account/default.js +13 -7
  8. package/dist/provider/default.d.ts +1 -0
  9. package/dist/provider/default.js +7 -0
  10. package/dist/provider/interface.d.ts +6 -0
  11. package/dist/provider/rpc.d.ts +12 -2
  12. package/dist/provider/rpc.js +126 -70
  13. package/dist/provider/sequencer.d.ts +1 -0
  14. package/dist/provider/sequencer.js +9 -1
  15. package/dist/provider/utils.d.ts +11 -35
  16. package/dist/provider/utils.js +52 -63
  17. package/dist/types/api/openrpc.d.ts +392 -32
  18. package/dist/types/api/openrpc.js +21 -3
  19. package/dist/types/api/rpc.d.ts +74 -107
  20. package/dist/utils/responseParser/rpc.d.ts +7 -4
  21. package/dist/utils/responseParser/rpc.js +1 -1
  22. package/package.json +4 -1
  23. package/provider/default.d.ts +1 -0
  24. package/provider/default.js +7 -0
  25. package/provider/interface.d.ts +6 -0
  26. package/provider/rpc.d.ts +12 -2
  27. package/provider/rpc.js +126 -70
  28. package/provider/sequencer.d.ts +1 -0
  29. package/provider/sequencer.js +9 -1
  30. package/provider/utils.d.ts +11 -35
  31. package/provider/utils.js +52 -63
  32. package/src/account/default.ts +4 -2
  33. package/src/provider/default.ts +4 -0
  34. package/src/provider/interface.ts +7 -0
  35. package/src/provider/rpc.ts +90 -54
  36. package/src/provider/sequencer.ts +7 -2
  37. package/src/provider/utils.ts +43 -56
  38. package/src/types/api/openrpc.ts +371 -41
  39. package/src/types/api/rpc.ts +71 -125
  40. package/src/utils/responseParser/rpc.ts +9 -5
  41. package/types/api/openrpc.d.ts +392 -32
  42. package/types/api/openrpc.js +21 -3
  43. package/types/api/rpc.d.ts +74 -107
  44. package/utils/responseParser/rpc.d.ts +7 -4
  45. package/utils/responseParser/rpc.js +1 -1
@@ -29,13 +29,14 @@ import { parseCalldata, parseContract, wait } from '../utils/provider';
29
29
  import { RPCResponseParser } from '../utils/responseParser/rpc';
30
30
  import { randomAddress } from '../utils/stark';
31
31
  import { ProviderInterface } from './interface';
32
- import { BlockIdentifier, BlockIdentifierClass } from './utils';
32
+ import { Block, BlockIdentifier } from './utils';
33
33
 
34
34
  export type RpcProviderOptions = { nodeUrl: string };
35
35
 
36
36
  export class RpcProvider implements ProviderInterface {
37
37
  public nodeUrl: string;
38
38
 
39
+ // from interface
39
40
  public chainId!: StarknetChainId;
40
41
 
41
42
  private responseParser = new RPCResponseParser();
@@ -49,87 +50,106 @@ export class RpcProvider implements ProviderInterface {
49
50
  });
50
51
  }
51
52
 
53
+ public fetch(method: any, params: any): Promise<any> {
54
+ return fetch(this.nodeUrl, {
55
+ method: 'POST',
56
+ body: stringify({ method, jsonrpc: '2.0', params, id: 0 }),
57
+ headers: { 'Content-Type': 'application/json' },
58
+ });
59
+ }
60
+
61
+ protected errorHandler(error: any) {
62
+ if (error) {
63
+ const { code, message } = error;
64
+ throw new Error(`${code}: ${message}`);
65
+ }
66
+ }
67
+
52
68
  protected async fetchEndpoint<T extends keyof RPC.Methods>(
53
69
  method: T,
54
70
  request?: RPC.Methods[T]['REQUEST']
55
71
  ): Promise<RPC.Methods[T]['RESPONSE']> {
56
- const requestData = {
57
- method,
58
- jsonrpc: '2.0',
59
- params: request,
60
- id: 0,
61
- };
62
-
63
72
  try {
64
- const rawResult = await fetch(this.nodeUrl, {
65
- method: 'POST',
66
- body: stringify(requestData),
67
- headers: {
68
- 'Content-Type': 'application/json',
69
- },
70
- });
73
+ const rawResult = await this.fetch(method, request);
71
74
  const { error, result } = await rawResult.json();
72
- if (error) {
73
- const { code, message } = error;
74
- throw new Error(`${code}: ${message}`);
75
- } else {
76
- return result as RPC.Methods[T]['RESPONSE'];
77
- }
75
+ this.errorHandler(error);
76
+ return result as RPC.Methods[T]['RESPONSE'];
78
77
  } catch (error: any) {
79
- const data = error?.response?.data;
80
- if (data?.message) {
81
- throw new Error(`${data.code}: ${data.message}`);
82
- }
78
+ this.errorHandler(error?.response?.data);
83
79
  throw error;
84
80
  }
85
81
  }
86
82
 
87
- public async getChainId(): Promise<StarknetChainId> {
83
+ // Methods from Interface
84
+ public async getChainId(): Promise<any> {
88
85
  return this.fetchEndpoint('starknet_chainId');
89
86
  }
90
87
 
91
- // Common Interface
88
+ // Methods from Interface
92
89
  public async getBlock(blockIdentifier: BlockIdentifier = 'pending'): Promise<GetBlockResponse> {
93
90
  return this.getBlockWithTxHashes(blockIdentifier).then(
94
91
  this.responseParser.parseGetBlockResponse
95
92
  );
96
93
  }
97
94
 
95
+ public async getBlockHashAndNumber(): Promise<RPC.BlockHashAndNumber> {
96
+ return this.fetchEndpoint('starknet_blockHashAndNumber');
97
+ }
98
+
98
99
  public async getBlockWithTxHashes(
99
100
  blockIdentifier: BlockIdentifier = 'pending'
100
101
  ): Promise<RPC.GetBlockWithTxHashesResponse> {
101
- const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
102
- return this.fetchEndpoint('starknet_getBlockWithTxHashes', [
103
- blockIdentifierGetter.getIdentifier(),
104
- ]);
102
+ const block = new Block(blockIdentifier);
103
+ return this.fetchEndpoint('starknet_getBlockWithTxHashes', [block.identifier]);
105
104
  }
106
105
 
107
106
  public async getBlockWithTxs(
108
107
  blockIdentifier: BlockIdentifier = 'pending'
109
108
  ): Promise<RPC.GetBlockWithTxs> {
110
- const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
111
- return this.fetchEndpoint('starknet_getBlockWithTxs', [blockIdentifierGetter.getIdentifier()]);
109
+ const block = new Block(blockIdentifier);
110
+ return this.fetchEndpoint('starknet_getBlockWithTxs', [block.identifier]);
111
+ }
112
+
113
+ public async getClassHashAt(
114
+ blockIdentifier: BlockIdentifier,
115
+ contractAddress: RPC.ContractAddress
116
+ ): Promise<RPC.Felt> {
117
+ const block = new Block(blockIdentifier);
118
+ return this.fetchEndpoint('starknet_getClassHashAt', [block.identifier, contractAddress]);
112
119
  }
113
120
 
114
121
  public async getNonce(contractAddress: string): Promise<any> {
115
122
  return this.fetchEndpoint('starknet_getNonce', [contractAddress]);
116
123
  }
117
124
 
125
+ public async getPendingTransactions(): Promise<RPC.PendingTransactions> {
126
+ return this.fetchEndpoint('starknet_pendingTransactions');
127
+ }
128
+
129
+ public async getProtocolVersion(): Promise<Error> {
130
+ throw new Error('Pathfinder does not implement this rpc 0.1.0 method');
131
+ }
132
+
133
+ public async getStateUpdate(blockIdentifier: BlockIdentifier): Promise<RPC.StateUpdate> {
134
+ const block = new Block(blockIdentifier);
135
+ return this.fetchEndpoint('starknet_getStateUpdate', [block.identifier]);
136
+ }
137
+
118
138
  public async getStorageAt(
119
139
  contractAddress: string,
120
140
  key: BigNumberish,
121
141
  blockIdentifier: BlockIdentifier = 'pending'
122
142
  ): Promise<BigNumberish> {
123
143
  const parsedKey = toHex(toBN(key));
124
- const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
144
+ const block = new Block(blockIdentifier);
125
145
  return this.fetchEndpoint('starknet_getStorageAt', [
126
146
  contractAddress,
127
147
  parsedKey,
128
- blockIdentifierGetter.getIdentifier(),
148
+ block.identifier,
129
149
  ]);
130
150
  }
131
151
 
132
- // common interface
152
+ // Methods from Interface
133
153
  public async getTransaction(txHash: BigNumberish): Promise<GetTransactionResponse> {
134
154
  return this.getTransactionByHash(txHash).then(this.responseParser.parseGetTransactionResponse);
135
155
  }
@@ -144,7 +164,11 @@ export class RpcProvider implements ProviderInterface {
144
164
  blockIdentifier: BlockIdentifier,
145
165
  index: number
146
166
  ): Promise<RPC.GetTransactionByBlockIdAndIndex> {
147
- return this.fetchEndpoint('starknet_getTransactionByHash', [blockIdentifier, index]);
167
+ const block = new Block(blockIdentifier);
168
+ return this.fetchEndpoint('starknet_getTransactionByBlockIdAndIndex', [
169
+ block.identifier,
170
+ index,
171
+ ]);
148
172
  }
149
173
 
150
174
  public async getTransactionReceipt(txHash: BigNumberish): Promise<GetTransactionReceiptResponse> {
@@ -153,12 +177,20 @@ export class RpcProvider implements ProviderInterface {
153
177
  );
154
178
  }
155
179
 
180
+ public async getClass(classHash: RPC.Felt): Promise<RPC.ContractClass> {
181
+ return this.fetchEndpoint('starknet_getClass', [classHash]);
182
+ }
183
+
156
184
  public async getClassAt(contractAddress: string, blockIdentifier: BlockIdentifier): Promise<any> {
157
- const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
158
- return this.fetchEndpoint('starknet_getClassAt', [
159
- blockIdentifierGetter.getIdentifier(),
160
- contractAddress,
161
- ]);
185
+ const block = new Block(blockIdentifier);
186
+ return this.fetchEndpoint('starknet_getClassAt', [block.identifier, contractAddress]);
187
+ }
188
+
189
+ public async getCode(
190
+ _contractAddress: string,
191
+ _blockIdentifier?: BlockIdentifier
192
+ ): Promise<GetCodeResponse> {
193
+ throw new Error('RPC 0.1.0 does not implement getCode function');
162
194
  }
163
195
 
164
196
  public async getEstimateFee(
@@ -166,6 +198,7 @@ export class RpcProvider implements ProviderInterface {
166
198
  blockIdentifier: BlockIdentifier = 'pending',
167
199
  invocationDetails: InvocationsDetails = {}
168
200
  ): Promise<EstimateFeeResponse> {
201
+ const block_id = new Block(blockIdentifier).identifier;
169
202
  return this.fetchEndpoint('starknet_estimateFee', [
170
203
  {
171
204
  contract_address: invocation.contractAddress,
@@ -174,7 +207,7 @@ export class RpcProvider implements ProviderInterface {
174
207
  signature: bigNumberishArrayToHexadecimalStringArray(invocation.signature || []),
175
208
  version: toHex(toBN(invocationDetails?.version || 0)),
176
209
  },
177
- blockIdentifier,
210
+ block_id,
178
211
  ]).then(this.responseParser.parseFeeEstimateResponse);
179
212
  }
180
213
 
@@ -188,6 +221,7 @@ export class RpcProvider implements ProviderInterface {
188
221
  {
189
222
  program: contractDefinition.program,
190
223
  entry_points_by_type: contractDefinition.entry_points_by_type,
224
+ abi: contractDefinition.abi, // rpc 2.0
191
225
  },
192
226
  toHex(toBN(version || 0)),
193
227
  ]).then(this.responseParser.parseDeclareContractResponse);
@@ -206,6 +240,7 @@ export class RpcProvider implements ProviderInterface {
206
240
  {
207
241
  program: contractDefinition.program,
208
242
  entry_points_by_type: contractDefinition.entry_points_by_type,
243
+ abi: contractDefinition.abi, // rpc 2.0
209
244
  },
210
245
  ]).then(this.responseParser.parseDeployContractResponse);
211
246
  }
@@ -226,32 +261,35 @@ export class RpcProvider implements ProviderInterface {
226
261
  ]).then(this.responseParser.parseInvokeFunctionResponse);
227
262
  }
228
263
 
264
+ // Methods from Interface
229
265
  public async callContract(
230
266
  call: Call,
231
267
  blockIdentifier: BlockIdentifier = 'pending'
232
268
  ): Promise<CallContractResponse> {
269
+ const block_id = new Block(blockIdentifier).identifier;
233
270
  const result = await this.fetchEndpoint('starknet_call', [
234
271
  {
235
272
  contract_address: call.contractAddress,
236
273
  entry_point_selector: getSelectorFromName(call.entrypoint),
237
274
  calldata: parseCalldata(call.calldata),
238
275
  },
239
- blockIdentifier,
276
+ block_id,
240
277
  ]);
241
278
 
242
279
  return this.responseParser.parseCallContractResponse(result);
243
280
  }
244
281
 
245
- public async getCode(
246
- _contractAddress: string,
247
- _blockIdentifier?: BlockIdentifier
248
- ): Promise<GetCodeResponse> {
249
- throw new Error('RPC 0.1.0 does not implement getCode function');
282
+ public async traceTransaction(transactionHash: RPC.TransactionHash): Promise<RPC.Trace> {
283
+ return this.fetchEndpoint('starknet_traceTransaction', [transactionHash]);
284
+ }
285
+
286
+ public async traceBlockTransactions(blockHash: RPC.BlockHash): Promise<RPC.Traces> {
287
+ return this.fetchEndpoint('starknet_traceBlockTransactions', [blockHash]);
250
288
  }
251
289
 
252
290
  public async waitForTransaction(txHash: BigNumberish, retryInterval: number = 8000) {
253
291
  let onchain = false;
254
- let retries = 100;
292
+ let retries = 200;
255
293
 
256
294
  while (!onchain) {
257
295
  const successStates = ['ACCEPTED_ON_L1', 'ACCEPTED_ON_L2', 'PENDING'];
@@ -297,10 +335,8 @@ export class RpcProvider implements ProviderInterface {
297
335
  public async getTransactionCount(
298
336
  blockIdentifier: BlockIdentifier
299
337
  ): Promise<RPC.GetTransactionCountResponse> {
300
- const blockIdentifierGetter = new BlockIdentifierClass(blockIdentifier);
301
- return this.fetchEndpoint('starknet_getBlockTransactionCount', [
302
- blockIdentifierGetter.getIdentifier(),
303
- ]);
338
+ const block = new Block(blockIdentifier);
339
+ return this.fetchEndpoint('starknet_getBlockTransactionCount', [block.identifier]);
304
340
  }
305
341
 
306
342
  /**
@@ -33,7 +33,7 @@ import { randomAddress } from '../utils/stark';
33
33
  import { buildUrl } from '../utils/url';
34
34
  import { GatewayError, HttpError } from './errors';
35
35
  import { ProviderInterface } from './interface';
36
- import { BlockIdentifier, getFormattedBlockIdentifier } from './utils';
36
+ import { Block, BlockIdentifier } from './utils';
37
37
 
38
38
  type NetworkName = 'mainnet-alpha' | 'goerli-alpha';
39
39
 
@@ -129,7 +129,8 @@ export class SequencerProvider implements ProviderInterface {
129
129
  const queryString = Object.entries(query)
130
130
  .map(([key, value]) => {
131
131
  if (key === 'blockIdentifier') {
132
- return `${getFormattedBlockIdentifier(value)}`;
132
+ const block = new Block(value);
133
+ return `${block.queryIdentifier}`;
133
134
  }
134
135
  return `${key}=${value}`;
135
136
  })
@@ -207,6 +208,10 @@ export class SequencerProvider implements ProviderInterface {
207
208
  }
208
209
  }
209
210
 
211
+ public async getChainId(): Promise<StarknetChainId> {
212
+ return Promise.resolve(this.chainId);
213
+ }
214
+
210
215
  public async callContract(
211
216
  { contractAddress, entrypoint: entryPointSelector, calldata = [] }: Call,
212
217
  blockIdentifier: BlockIdentifier = 'pending'
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-classes-per-file */
1
2
  import type { BlockNumber } from '../types';
2
3
  import { BigNumberish, isHex, toBN, toHex } from '../utils/number';
3
4
 
@@ -33,73 +34,59 @@ export function txIdentifier(txHash?: BigNumberish, txId?: BigNumberish): string
33
34
  // null appends nothing to the request url
34
35
 
35
36
  export type BlockIdentifier = BlockNumber | BigNumberish;
36
- type BlockIdentifierObject =
37
- | { type: 'BLOCK_NUMBER'; data: BlockNumber }
38
- | { type: 'BLOCK_HASH'; data: BigNumberish };
39
37
 
40
- export class BlockIdentifierClass {
41
- blockIdentifier: BlockIdentifier;
38
+ export class Block {
39
+ hash: BlockIdentifier = null;
42
40
 
43
- constructor(blockIdentifier: BlockIdentifier) {
44
- this.blockIdentifier = blockIdentifier;
41
+ number: BlockIdentifier = null;
42
+
43
+ tag: BlockIdentifier = null;
44
+
45
+ private setIdentifier: (_identifier: BlockIdentifier) => void;
46
+
47
+ constructor(_identifier: BlockIdentifier) {
48
+ this.setIdentifier = function (__identifier: BlockIdentifier) {
49
+ if (typeof __identifier === 'string' && isHex(__identifier)) {
50
+ this.hash = __identifier;
51
+ } else if (typeof __identifier === 'number') {
52
+ this.number = __identifier;
53
+ } else {
54
+ this.tag = __identifier;
55
+ }
56
+ };
57
+
58
+ this.setIdentifier(_identifier);
45
59
  }
46
60
 
47
- getIdentifier() {
48
- if (typeof this.blockIdentifier === 'string' && isHex(this.blockIdentifier)) {
49
- return { block_hash: this.blockIdentifier };
61
+ get queryIdentifier(): any {
62
+ if (this.number !== null) {
63
+ return `blockNumber=${this.number}`;
50
64
  }
51
65
 
52
- if (typeof this.blockIdentifier === 'number') {
53
- return { block_number: this.blockIdentifier };
66
+ if (this.hash !== null) {
67
+ return `blockHash=${this.hash}`;
54
68
  }
55
69
 
56
- return this.blockIdentifier;
70
+ return `blockNumber=${this.tag}`;
57
71
  }
58
- }
59
72
 
60
- /**
61
- * Identifies the block to be queried.
62
- *
63
- * @param blockIdentifier - block identifier
64
- * @returns block identifier object
65
- */
66
- export function getBlockIdentifier(blockIdentifier: BlockIdentifier): BlockIdentifierObject {
67
- if (blockIdentifier === null || blockIdentifier === 'latest') {
68
- return { type: 'BLOCK_NUMBER', data: 'latest' }; // default to latest block
69
- }
70
- if (blockIdentifier === 'pending') {
71
- return { type: 'BLOCK_NUMBER', data: 'pending' };
72
- }
73
- if (typeof blockIdentifier === 'number' || typeof blockIdentifier === 'bigint') {
74
- return { type: 'BLOCK_NUMBER', data: blockIdentifier };
75
- }
76
- if (typeof blockIdentifier === 'string' && blockIdentifier.startsWith('0x')) {
77
- return { type: 'BLOCK_HASH', data: blockIdentifier };
78
- }
79
- if (typeof blockIdentifier === 'string' && !Number.isNaN(parseInt(blockIdentifier, 10))) {
80
- return { type: 'BLOCK_NUMBER', data: parseInt(blockIdentifier, 10) };
81
- }
82
- if (typeof blockIdentifier === 'string') {
83
- throw new Error(`Invalid block identifier: ${blockIdentifier}`);
84
- }
85
- return { type: 'BLOCK_HASH', data: blockIdentifier };
86
- }
73
+ get identifier(): any {
74
+ if (this.number !== null) {
75
+ return { block_number: this.number };
76
+ }
87
77
 
88
- /**
89
- * Gets the block identifier for API request
90
- *
91
- * [Reference](https://github.com/starkware-libs/cairo-lang/blob/fc97bdd8322a7df043c87c371634b26c15ed6cee/src/starkware/starknet/services/api/feeder_gateway/feeder_gateway_client.py#L164-L173)
92
- *
93
- * @param blockIdentifier
94
- * @returns block identifier for API request
95
- */
96
- export function getFormattedBlockIdentifier(blockIdentifier: BlockIdentifier = null): string {
97
- const blockIdentifierObject = getBlockIdentifier(blockIdentifier);
98
- if (blockIdentifierObject.type === 'BLOCK_NUMBER' && blockIdentifierObject.data === null) {
99
- return '';
78
+ if (this.hash !== null) {
79
+ return { block_hash: this.hash };
80
+ }
81
+
82
+ return this.tag;
100
83
  }
101
- if (blockIdentifierObject.type === 'BLOCK_NUMBER') {
102
- return `blockNumber=${blockIdentifierObject.data}`;
84
+
85
+ set identifier(_identifier: BlockIdentifier) {
86
+ this.setIdentifier(_identifier);
103
87
  }
104
- return `blockHash=${toHex(toBN(blockIdentifierObject.data))}`;
88
+
89
+ valueOf = () => this.number;
90
+
91
+ toString = () => this.hash;
105
92
  }