starknet 4.2.0 → 4.4.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 (102) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/__mocks__/typedDataSessionExample.json +42 -0
  3. package/__tests__/defaultProvider.test.ts +11 -24
  4. package/__tests__/rpcProvider.test.ts +3 -3
  5. package/__tests__/sequencerProvider.test.ts +40 -2
  6. package/__tests__/utils/__snapshots__/ellipticalCurve.test.ts.snap +2 -0
  7. package/__tests__/utils/ellipticalCurve.test.ts +5 -0
  8. package/__tests__/utils/merkle.test.ts +146 -0
  9. package/__tests__/utils/typedData.test.ts +107 -9
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.js +3 -1
  12. package/dist/provider/default.d.ts +2 -2
  13. package/dist/provider/default.js +3 -3
  14. package/dist/provider/interface.d.ts +6 -3
  15. package/dist/provider/rpc.d.ts +9 -4
  16. package/dist/provider/rpc.js +67 -25
  17. package/dist/provider/sequencer.d.ts +2 -2
  18. package/dist/provider/sequencer.js +9 -9
  19. package/dist/provider/utils.d.ts +12 -0
  20. package/dist/provider/utils.js +17 -1
  21. package/dist/signer/default.d.ts +1 -1
  22. package/dist/signer/default.js +1 -0
  23. package/dist/types/api/openrpc.d.ts +151 -0
  24. package/dist/types/api/openrpc.js +9 -0
  25. package/dist/types/api/rpc.d.ts +22 -43
  26. package/dist/types/provider.d.ts +5 -5
  27. package/dist/utils/ellipticCurve.d.ts +13 -0
  28. package/dist/utils/ellipticCurve.js +20 -16
  29. package/dist/utils/hash.js +8 -6
  30. package/dist/utils/merkle.d.ts +10 -0
  31. package/dist/utils/merkle.js +90 -0
  32. package/dist/utils/number.js +1 -1
  33. package/dist/utils/responseParser/rpc.d.ts +13 -3
  34. package/dist/utils/responseParser/rpc.js +2 -10
  35. package/dist/utils/responseParser/sequencer.d.ts +4 -1
  36. package/dist/utils/responseParser/sequencer.js +1 -7
  37. package/dist/utils/typedData/index.d.ts +23 -8
  38. package/dist/utils/typedData/index.js +70 -31
  39. package/dist/utils/typedData/types.d.ts +8 -3
  40. package/dist/utils/url.d.ts +7 -0
  41. package/dist/utils/url.js +49 -0
  42. package/index.d.ts +2 -0
  43. package/index.js +3 -1
  44. package/package.json +1 -1
  45. package/provider/default.d.ts +2 -2
  46. package/provider/default.js +3 -3
  47. package/provider/interface.d.ts +6 -3
  48. package/provider/rpc.d.ts +9 -4
  49. package/provider/rpc.js +67 -25
  50. package/provider/sequencer.d.ts +2 -2
  51. package/provider/sequencer.js +9 -9
  52. package/provider/utils.d.ts +12 -0
  53. package/provider/utils.js +17 -1
  54. package/signer/default.d.ts +1 -1
  55. package/signer/default.js +1 -0
  56. package/src/index.ts +2 -0
  57. package/src/provider/default.ts +2 -3
  58. package/src/provider/interface.ts +5 -3
  59. package/src/provider/rpc.ts +56 -34
  60. package/src/provider/sequencer.ts +11 -9
  61. package/src/provider/utils.ts +22 -1
  62. package/src/signer/default.ts +2 -2
  63. package/src/types/api/openrpc.ts +168 -0
  64. package/src/types/api/rpc.ts +22 -45
  65. package/src/types/provider.ts +5 -5
  66. package/src/utils/ellipticCurve.ts +20 -16
  67. package/src/utils/hash.ts +8 -6
  68. package/src/utils/merkle.ts +70 -0
  69. package/src/utils/number.ts +1 -1
  70. package/src/utils/responseParser/rpc.ts +16 -13
  71. package/src/utils/responseParser/sequencer.ts +5 -8
  72. package/src/utils/typedData/index.ts +88 -34
  73. package/src/utils/typedData/types.ts +12 -4
  74. package/src/utils/url.ts +53 -0
  75. package/types/api/openrpc.d.ts +151 -0
  76. package/types/api/openrpc.js +9 -0
  77. package/types/api/rpc.d.ts +22 -43
  78. package/types/provider.d.ts +5 -5
  79. package/utils/ellipticCurve.d.ts +13 -0
  80. package/utils/ellipticCurve.js +20 -16
  81. package/utils/hash.js +8 -6
  82. package/utils/merkle.d.ts +10 -0
  83. package/utils/merkle.js +90 -0
  84. package/utils/number.js +1 -1
  85. package/utils/responseParser/rpc.d.ts +13 -3
  86. package/utils/responseParser/rpc.js +2 -10
  87. package/utils/responseParser/sequencer.d.ts +4 -1
  88. package/utils/responseParser/sequencer.js +1 -7
  89. package/utils/typedData/index.d.ts +23 -8
  90. package/utils/typedData/index.js +70 -31
  91. package/utils/typedData/types.d.ts +8 -3
  92. package/utils/url.d.ts +7 -0
  93. package/utils/url.js +49 -0
  94. package/www/docs/API/account.md +20 -18
  95. package/www/docs/API/contract.md +10 -10
  96. package/www/docs/API/contractFactory.md +14 -11
  97. package/www/docs/API/provider.md +60 -37
  98. package/www/docs/API/signer.md +8 -10
  99. package/www/docs/API/utils.md +151 -74
  100. package/www/guides/account.md +12 -12
  101. package/www/guides/erc20.md +19 -4
  102. package/www/guides/intro.md +3 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,47 @@
1
+ # [4.4.0](https://github.com/0xs34n/starknet.js/compare/v4.3.1...v4.4.0) (2022-09-01)
2
+
3
+ ### Bug Fixes
4
+
5
+ - delete premature session account file ([ca3e70b](https://github.com/0xs34n/starknet.js/commit/ca3e70b06d21dba8b2074512251cf232ed8be46b))
6
+ - session ([00269bf](https://github.com/0xs34n/starknet.js/commit/00269bfd23ed647270a1efd699af7c36978965c7))
7
+ - session account prooving ([0b56833](https://github.com/0xs34n/starknet.js/commit/0b56833f6eb7557d55725a505a01185bbc9756db))
8
+ - tests ([4586e93](https://github.com/0xs34n/starknet.js/commit/4586e93f10a2a43c375a23d851a9778bab412fcc))
9
+ - typo ([1c60a4d](https://github.com/0xs34n/starknet.js/commit/1c60a4d4b306879422769a6c2afc4fd6c39c4c07))
10
+
11
+ ### Features
12
+
13
+ - add merkle trees ([e9b8674](https://github.com/0xs34n/starknet.js/commit/e9b8674f51c6d6fe57772a4c88b162c5132cfbdd))
14
+ - add visibility modifiers ([cd1a23d](https://github.com/0xs34n/starknet.js/commit/cd1a23d74b49407c27314a12d5bc149ed40209f3))
15
+ - allow merkle trees as native type in eip712 like messages ([65b7766](https://github.com/0xs34n/starknet.js/commit/65b7766c29eca4f4d0e89f6ad1368fedd5e0e18e))
16
+ - session ([9ac48cc](https://github.com/0xs34n/starknet.js/commit/9ac48cc15c1c7b0e504adfc79a7f382f5d0b55d0))
17
+ - session needs to be aware of the whole tree ([11e10bd](https://github.com/0xs34n/starknet.js/commit/11e10bda0f020a670854d941a54142d55936fc18))
18
+
19
+ ## [4.3.1](https://github.com/0xs34n/starknet.js/compare/v4.3.0...v4.3.1) (2022-08-31)
20
+
21
+ ### Bug Fixes
22
+
23
+ - getClassAt and Test Fixes ([548cf6e](https://github.com/0xs34n/starknet.js/commit/548cf6e69d16292b9c216493c77e1c7a14be2ae9))
24
+ - getCode removed from RPC 0.1.0 ([744a988](https://github.com/0xs34n/starknet.js/commit/744a9882c363331ff47f409971cacbfda977c4c2))
25
+ - merge ([67d87fc](https://github.com/0xs34n/starknet.js/commit/67d87fc834ea5b877029445f39782457584fb4ec))
26
+ - naming ([0c75f6f](https://github.com/0xs34n/starknet.js/commit/0c75f6f431c3828b1078d955123b2d13aef6b5d0))
27
+ - restore GetCode to common interface for backward compatibility ([52f8e61](https://github.com/0xs34n/starknet.js/commit/52f8e61797a3f2390577b3a6e977adae11346a23))
28
+ - rpc 0.1.0 getStorageAt ([c622913](https://github.com/0xs34n/starknet.js/commit/c6229138c57cd9a04b982c386c7278d63b931a1f))
29
+ - **RpcProvider:** update of RpcProvider getBlock method to work with v0.3.0 of pathfinder ([3b12421](https://github.com/0xs34n/starknet.js/commit/3b124219dd25ef5a0c81583fcfe67d6a3cc5a70e))
30
+ - test getBlock('latest') ([2c92f79](https://github.com/0xs34n/starknet.js/commit/2c92f79aefe3af68834aa9a9a16754c0ff4116cc))
31
+ - test getBlock(latest) ([0c5e31e](https://github.com/0xs34n/starknet.js/commit/0c5e31effb63bf7afb26c9f2049b66c93c6b1366))
32
+ - unoptimise getClassAt test to work with integration ([e98220b](https://github.com/0xs34n/starknet.js/commit/e98220bc6e6fff55bc439773bd1258844de312e2))
33
+
34
+ # [4.3.0](https://github.com/0xs34n/starknet.js/compare/v4.2.0...v4.3.0) (2022-08-09)
35
+
36
+ ### Bug Fixes
37
+
38
+ - indentations in provider.md ([4a310c6](https://github.com/0xs34n/starknet.js/commit/4a310c6c992c77f9f6729a70c1af14481cd891f7))
39
+ - **sequenceProvider:** feedergatewayUrl and gatewayUrl ([e236d23](https://github.com/0xs34n/starknet.js/commit/e236d2352e3fbb0f78965decac5893217347ceb7))
40
+
41
+ ### Features
42
+
43
+ - update docs ([28786ed](https://github.com/0xs34n/starknet.js/commit/28786ed550909f6a30b8cb145e93d072ed28a862))
44
+
1
45
  # [4.2.0](https://github.com/0xs34n/starknet.js/compare/v4.1.0...v4.2.0) (2022-08-09)
2
46
 
3
47
  ### Features
@@ -0,0 +1,42 @@
1
+ {
2
+ "primaryType": "Session",
3
+ "types": {
4
+ "Policy": [
5
+ { "name": "contractAddress", "type": "felt" },
6
+ { "name": "selector", "type": "selector" }
7
+ ],
8
+ "Session": [
9
+ { "name": "key", "type": "felt" },
10
+ { "name": "expires", "type": "felt" },
11
+ { "name": "root", "type": "merkletree", "contains": "Policy" }
12
+ ],
13
+ "StarkNetDomain": [
14
+ { "name": "name", "type": "felt" },
15
+ { "name": "version", "type": "felt" },
16
+ { "name": "chain_id", "type": "felt" }
17
+ ]
18
+ },
19
+ "domain": {
20
+ "name": "StarkNet Mail",
21
+ "version": "1",
22
+ "chain_id": 1
23
+ },
24
+ "message": {
25
+ "key": "0x0000000000000000000000000000000000000000000000000000000000000000",
26
+ "expires": "0x0000000000000000000000000000000000000000000000000000000000000000",
27
+ "root": [
28
+ {
29
+ "contractAddress": "0x1",
30
+ "selector": "transfer"
31
+ },
32
+ {
33
+ "contractAddress": "0x2",
34
+ "selector": "transfer"
35
+ },
36
+ {
37
+ "contractAddress": "0x3",
38
+ "selector": "transfer"
39
+ }
40
+ ]
41
+ }
42
+ }
@@ -50,11 +50,11 @@ describe('defaultProvider', () => {
50
50
  test('getBlock(blockIdentifier=latest)', async () => {
51
51
  expect(exampleBlock).not.toBeNull();
52
52
 
53
- const { block_number, accepted_time } = exampleBlock;
53
+ const { block_number, timestamp } = exampleBlock;
54
54
 
55
55
  expect(typeof block_number).toEqual('number');
56
56
 
57
- return expect(typeof accepted_time).toEqual('number');
57
+ return expect(typeof timestamp).toEqual('number');
58
58
  });
59
59
 
60
60
  test('getBlock() -> { blockNumber }', async () => {
@@ -62,11 +62,6 @@ describe('defaultProvider', () => {
62
62
  return expect(block).toHaveProperty('block_number');
63
63
  });
64
64
 
65
- test('getCode() -> { bytecode }', async () => {
66
- const code = await testProvider.getCode(exampleContractAddress);
67
- return expect(Array.isArray(code.bytecode)).toBe(true);
68
- });
69
-
70
65
  describe('getStorageAt', () => {
71
66
  test('with "key" type of number', () => {
72
67
  return expect(testProvider.getStorageAt(exampleContractAddress, 0)).resolves.not.toThrow();
@@ -144,7 +139,7 @@ describe('defaultProvider', () => {
144
139
 
145
140
  describeIfNotDevnet('Provider', () => {
146
141
  const provider = getTestProvider();
147
- describe(`Provider methods`, () => {
142
+ describe(`Provider methods if not devnet`, () => {
148
143
  describe('getBlock', () => {
149
144
  test('pending', async () => {
150
145
  const latestBlock = await provider.getBlock();
@@ -152,11 +147,8 @@ describe('defaultProvider', () => {
152
147
  expect(latestBlock).toHaveProperty('parent_hash');
153
148
  expect(latestBlock).toHaveProperty('block_number');
154
149
  expect(latestBlock).toHaveProperty('status');
155
- expect(latestBlock).toHaveProperty('sequencer');
156
150
  expect(latestBlock).toHaveProperty('new_root');
157
- expect(latestBlock).toHaveProperty('old_root');
158
- expect(latestBlock).toHaveProperty('accepted_time');
159
- expect(latestBlock).toHaveProperty('gas_price');
151
+ expect(latestBlock).toHaveProperty('timestamp');
160
152
  expect(latestBlock).toHaveProperty('transactions');
161
153
  expect(Array.isArray(latestBlock.transactions)).toBe(true);
162
154
  });
@@ -170,11 +162,8 @@ describe('defaultProvider', () => {
170
162
  expect(block).toHaveProperty('parent_hash');
171
163
  expect(block).toHaveProperty('block_number');
172
164
  expect(block).toHaveProperty('status');
173
- expect(block).toHaveProperty('sequencer');
174
165
  expect(block).toHaveProperty('new_root');
175
- expect(block).toHaveProperty('old_root');
176
- expect(block).toHaveProperty('accepted_time');
177
- expect(block).toHaveProperty('gas_price');
166
+ expect(block).toHaveProperty('timestamp');
178
167
  expect(block).toHaveProperty('transactions');
179
168
  expect(Array.isArray(block.transactions)).toBe(true);
180
169
  });
@@ -185,11 +174,8 @@ describe('defaultProvider', () => {
185
174
  expect(block).toHaveProperty('parent_hash');
186
175
  expect(block).toHaveProperty('block_number');
187
176
  expect(block).toHaveProperty('status');
188
- expect(block).toHaveProperty('sequencer');
189
177
  expect(block).toHaveProperty('new_root');
190
- expect(block).toHaveProperty('old_root');
191
- expect(block).toHaveProperty('accepted_time');
192
- expect(block).toHaveProperty('gas_price');
178
+ expect(block).toHaveProperty('timestamp');
193
179
  expect(block).toHaveProperty('transactions');
194
180
  expect(Array.isArray(block.transactions)).toBe(true);
195
181
  });
@@ -199,7 +185,7 @@ describe('defaultProvider', () => {
199
185
  test('pending', async () => {
200
186
  const storage = await provider.getStorageAt(
201
187
  '0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166',
202
- 0
188
+ '0'
203
189
  );
204
190
  expect(typeof storage).toBe('string');
205
191
  });
@@ -207,7 +193,7 @@ describe('defaultProvider', () => {
207
193
  test('Block Hash 0x7104702055c2a5773a870ceada9552ec659d69c18053b14078983f07527dea8', async () => {
208
194
  const storage = await provider.getStorageAt(
209
195
  '0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166',
210
- 0,
196
+ '0',
211
197
  '0x7225762c7ff5e7e5f0867f0a8e73594df4f44f05a65375339a76398e8ae3e64'
212
198
  );
213
199
  expect(typeof storage).toBe('string');
@@ -245,7 +231,6 @@ describe('defaultProvider', () => {
245
231
  expect(transaction.max_fee).toBeTruthy();
246
232
  expect(transaction.transaction_hash).toBeTruthy();
247
233
  expect(transaction).toHaveProperty('nonce');
248
- expect(transaction).toHaveProperty('sender_address');
249
234
  expect(transaction).toHaveProperty('version');
250
235
  });
251
236
  });
@@ -269,6 +254,7 @@ describe('defaultProvider', () => {
269
254
  let contractAddress: string;
270
255
  let deployResponse: DeployContractResponse;
271
256
  let declareResponse: DeclareContractResponse;
257
+ let blockNumber: BlockNumber;
272
258
 
273
259
  beforeAll(async () => {
274
260
  deployResponse = await provider.deployContract({ contract: compiledErc20 });
@@ -278,6 +264,7 @@ describe('defaultProvider', () => {
278
264
  provider.waitForTransaction(deployResponse.transaction_hash),
279
265
  provider.waitForTransaction(declareResponse.transaction_hash),
280
266
  ]);
267
+ ({ block_number: blockNumber } = await provider.getBlock('latest'));
281
268
  });
282
269
 
283
270
  describe('deployContract', () => {
@@ -296,7 +283,7 @@ describe('defaultProvider', () => {
296
283
 
297
284
  describe('getClassAt', () => {
298
285
  test('response', async () => {
299
- const classResponse = await provider.getClassAt(contractAddress);
286
+ const classResponse = await provider.getClassAt(contractAddress, blockNumber);
300
287
 
301
288
  expect(classResponse).toHaveProperty('program');
302
289
  expect(classResponse).toHaveProperty('entry_points_by_type');
@@ -2,15 +2,15 @@ import { RpcProvider } from '../src';
2
2
  import { describeIfRpc, getTestProvider } from './fixtures';
3
3
 
4
4
  describeIfRpc('RPCProvider', () => {
5
- let provider: RpcProvider;
5
+ let rpcProvider: RpcProvider;
6
6
 
7
7
  beforeAll(async () => {
8
- provider = getTestProvider() as RpcProvider;
8
+ rpcProvider = getTestProvider() as RpcProvider;
9
9
  });
10
10
 
11
11
  describe('RPC methods', () => {
12
12
  test('getChainId', async () => {
13
- const chainId = await provider.getChainId();
13
+ const chainId = await rpcProvider.getChainId();
14
14
  expect(chainId).toBe('0x534e5f474f45524c49');
15
15
  });
16
16
  });
@@ -1,4 +1,5 @@
1
- import { SequencerProvider } from '../src';
1
+ import { Contract, Provider, SequencerProvider, stark } from '../src';
2
+ import { toBN } from '../src/utils/number';
2
3
  import {
3
4
  compiledErc20,
4
5
  describeIfNotDevnet,
@@ -6,22 +7,33 @@ import {
6
7
  getTestProvider,
7
8
  } from './fixtures';
8
9
 
10
+ // Run only if Devnet Sequencer
9
11
  describeIfSequencer('SequencerProvider', () => {
10
12
  let provider: SequencerProvider;
13
+ let customSequencerProvider: Provider;
14
+ let exampleContractAddress: string;
11
15
 
12
16
  beforeAll(async () => {
13
17
  provider = getTestProvider() as SequencerProvider;
18
+ customSequencerProvider = new Provider({
19
+ sequencer: {
20
+ baseUrl: 'https://alpha4.starknet.io',
21
+ feederGatewayUrl: 'feeder_gateway',
22
+ gatewayUrl: 'gateway',
23
+ }, // Similar to arguements used in docs
24
+ });
14
25
  });
15
26
 
16
27
  describe('Gateway specific methods', () => {
17
28
  let exampleTransactionHash: string;
18
29
 
19
30
  beforeAll(async () => {
20
- const { transaction_hash } = await provider.deployContract({
31
+ const { transaction_hash, contract_address } = await provider.deployContract({
21
32
  contract: compiledErc20,
22
33
  });
23
34
  await provider.waitForTransaction(transaction_hash);
24
35
  exampleTransactionHash = transaction_hash;
36
+ exampleContractAddress = contract_address;
25
37
  });
26
38
 
27
39
  test('getTransactionStatus()', async () => {
@@ -34,6 +46,11 @@ describeIfSequencer('SequencerProvider', () => {
34
46
  expect(transactionTrace).toHaveProperty('signature');
35
47
  });
36
48
 
49
+ test('getCode() -> { bytecode }', async () => {
50
+ const code = await provider.getCode(exampleContractAddress);
51
+ return expect(Array.isArray(code.bytecode)).toBe(true);
52
+ });
53
+
37
54
  describeIfNotDevnet('which are not available on devnet', () => {
38
55
  test('getContractAddresses()', async () => {
39
56
  const { GpsStatementVerifier, Starknet } = await provider.getContractAddresses();
@@ -42,4 +59,25 @@ describeIfSequencer('SequencerProvider', () => {
42
59
  });
43
60
  });
44
61
  });
62
+
63
+ describe('Test calls with Custom Sequencer Provider', () => {
64
+ let erc20: Contract;
65
+ const wallet = stark.randomAddress();
66
+
67
+ beforeAll(async () => {
68
+ const { contract_address, transaction_hash } = await customSequencerProvider.deployContract({
69
+ contract: compiledErc20,
70
+ });
71
+
72
+ await customSequencerProvider.waitForTransaction(transaction_hash);
73
+ erc20 = new Contract(compiledErc20.abi, contract_address, customSequencerProvider);
74
+ });
75
+
76
+ test('Check ERC20 balance using Custom Sequencer Provider', async () => {
77
+ const result = await erc20.balance_of(wallet);
78
+ const [res] = result;
79
+ expect(res).toStrictEqual(toBN(0));
80
+ expect(res).toStrictEqual(result.res);
81
+ });
82
+ });
45
83
  });
@@ -1,3 +1,5 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`pedersen() 1`] = `"0x5ed2703dfdb505c587700ce2ebfcab5b3515cd7e6114817e6026ec9d4b364ca"`;
4
+
5
+ exports[`pedersen() with 0 1`] = `"0x1a5c561f97b52c17a19f34c4499a745cd4e8412e29e4ed5e91e4481c7d53935"`;
@@ -25,6 +25,11 @@ test('pedersen()', () => {
25
25
  expect(own).toMatchSnapshot();
26
26
  });
27
27
 
28
+ test('pedersen() with 0', () => {
29
+ const own = pedersen(['0x12773', '0x0']);
30
+ expect(own).toMatchSnapshot();
31
+ });
32
+
28
33
  test('computeHashOnElements()', () => {
29
34
  const array = ['1', '2', '3', '4'];
30
35
  expect(computeHashOnElements(array)).toBe(
@@ -0,0 +1,146 @@
1
+ import { MerkleTree, proofMerklePath } from '../../src/utils/merkle';
2
+
3
+ describe('MerkleTree class', () => {
4
+ describe('generate roots', () => {
5
+ test('should generate valid root for 1 elements', async () => {
6
+ const leaves = ['0x1'];
7
+ const tree = new MerkleTree(leaves);
8
+
9
+ const manualMerkle = leaves[0];
10
+
11
+ expect(tree.root).toBe(manualMerkle);
12
+ });
13
+ test('should generate valid root for 2 elements', async () => {
14
+ const leaves = ['0x1', '0x2'];
15
+ const tree = new MerkleTree(leaves);
16
+
17
+ const manualMerkle = MerkleTree.hash(leaves[0], leaves[1]);
18
+
19
+ expect(tree.root).toBe(manualMerkle);
20
+ });
21
+ test('should generate valid root for 4 elements', async () => {
22
+ const leaves = ['0x1', '0x2', '0x3', '0x4'];
23
+ const tree = new MerkleTree(leaves);
24
+
25
+ const manualMerkle = MerkleTree.hash(
26
+ MerkleTree.hash(leaves[0], leaves[1]),
27
+ MerkleTree.hash(leaves[2], leaves[3])
28
+ );
29
+
30
+ expect(tree.root).toBe(manualMerkle);
31
+ });
32
+ test('should generate valid root for 6 elements', async () => {
33
+ const leaves = ['0x1', '0x2', '0x3', '0x4', '0x5', '0x6'];
34
+ const tree = new MerkleTree(leaves);
35
+
36
+ const manualMerkle = MerkleTree.hash(
37
+ MerkleTree.hash(
38
+ MerkleTree.hash(leaves[0], leaves[1]),
39
+ MerkleTree.hash(leaves[2], leaves[3])
40
+ ),
41
+ MerkleTree.hash(leaves[4], leaves[5])
42
+ );
43
+
44
+ expect(tree.root).toBe(manualMerkle);
45
+ });
46
+ test('should generate valid root for 7 elements', async () => {
47
+ const leaves = ['0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7'];
48
+ const tree = new MerkleTree(leaves);
49
+
50
+ const manualMerkle = MerkleTree.hash(
51
+ MerkleTree.hash(
52
+ MerkleTree.hash(leaves[0], leaves[1]),
53
+ MerkleTree.hash(leaves[2], leaves[3])
54
+ ),
55
+ MerkleTree.hash(MerkleTree.hash(leaves[4], leaves[5]), leaves[6])
56
+ );
57
+
58
+ expect(tree.root).toBe(manualMerkle);
59
+ });
60
+ });
61
+ describe('generate proofs', () => {
62
+ let tree: MerkleTree;
63
+ beforeAll(() => {
64
+ const leaves = ['0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7'];
65
+ tree = new MerkleTree(leaves);
66
+ });
67
+ test('should return proof path for valid child', async () => {
68
+ const proof = tree.getProof('0x3');
69
+
70
+ const manualProof = [
71
+ '0x4',
72
+ MerkleTree.hash('0x1', '0x2'),
73
+ MerkleTree.hash(MerkleTree.hash('0x5', '0x6'), '0x7'),
74
+ ];
75
+
76
+ expect(proof).toEqual(manualProof);
77
+ });
78
+ test('should return proof path for valid child', async () => {
79
+ const proof = tree.getProof('0x7');
80
+
81
+ const manualProof = [
82
+ '0x0', // proofs should always be as long as the tree is deep
83
+ MerkleTree.hash('0x5', '0x6'),
84
+ MerkleTree.hash(MerkleTree.hash('0x1', '0x2'), MerkleTree.hash('0x3', '0x4')),
85
+ ];
86
+
87
+ expect(proof).toEqual(manualProof);
88
+ });
89
+ test('should throw for invalid child', () => {
90
+ expect(() => tree.getProof('0x8')).toThrow('leaf not found');
91
+ });
92
+ });
93
+ describe('verify proofs', () => {
94
+ let tree: MerkleTree;
95
+ beforeAll(() => {
96
+ const leaves = ['0x1', '0x2', '0x3', '0x4', '0x5', '0x6', '0x7'];
97
+ tree = new MerkleTree(leaves);
98
+ });
99
+
100
+ test('should return true for valid manual proof', async () => {
101
+ const manualProof = [
102
+ MerkleTree.hash('0x5', '0x6'),
103
+ MerkleTree.hash(MerkleTree.hash('0x1', '0x2'), MerkleTree.hash('0x3', '0x4')),
104
+ ];
105
+ const leaf = '0x7';
106
+ const { root } = tree;
107
+
108
+ expect(proofMerklePath(root, leaf, manualProof)).toBe(true);
109
+ });
110
+ test('should return true for valid proof', async () => {
111
+ const proof = tree.getProof('0x3');
112
+ const leaf = '0x3';
113
+ const { root } = tree;
114
+
115
+ expect(proofMerklePath(root, leaf, proof)).toBe(true);
116
+ });
117
+ test('should return false for invalid proof (root)', async () => {
118
+ const proof = tree.getProof('0x3');
119
+ const leaf = '0x3';
120
+ const root = '0x4';
121
+
122
+ expect(proofMerklePath(root, leaf, proof)).toBe(false);
123
+ });
124
+ test('should return false for invalid proof (proof[0])', async () => {
125
+ const proof = tree.getProof('0x3');
126
+ const leaf = '0x3';
127
+ const { root } = tree;
128
+ proof[0] = '0x7';
129
+ expect(proofMerklePath(root, leaf, proof)).toBe(false);
130
+ });
131
+ test('should return false for invalid proof (proof[1])', async () => {
132
+ const proof = tree.getProof('0x3');
133
+ const leaf = '0x3';
134
+ const { root } = tree;
135
+ proof[1] = '0x4';
136
+ expect(proofMerklePath(root, leaf, proof)).toBe(false);
137
+ });
138
+ test('should return false for invalid proof (proof[2])', async () => {
139
+ const proof = tree.getProof('0x3');
140
+ const leaf = '0x3';
141
+ const { root } = tree;
142
+ proof[2] = '0x4';
143
+ expect(proofMerklePath(root, leaf, proof)).toBe(false);
144
+ });
145
+ });
146
+ });
@@ -1,46 +1,134 @@
1
1
  import typedDataExample from '../../__mocks__/typedDataExample.json';
2
+ import typedDataSessionExample from '../../__mocks__/typedDataSessionExample.json';
2
3
  import typedDataStructArrayExample from '../../__mocks__/typedDataStructArrayExample.json';
3
4
  import { number } from '../../src';
5
+ import { getSelectorFromName } from '../../src/utils/hash';
6
+ import { MerkleTree } from '../../src/utils/merkle';
4
7
  import { BigNumberish } from '../../src/utils/number';
5
- import { encodeType, getMessageHash, getStructHash, getTypeHash } from '../../src/utils/typedData';
8
+ import {
9
+ StarkNetDomain,
10
+ encodeType,
11
+ encodeValue,
12
+ getMessageHash,
13
+ getStructHash,
14
+ getTypeHash,
15
+ } from '../../src/utils/typedData';
6
16
 
7
17
  describe('typedData', () => {
8
18
  test('should get right type encoding', () => {
9
- const typeEncoding = encodeType(typedDataExample, 'Mail');
19
+ const typeEncoding = encodeType(typedDataExample.types, 'Mail');
10
20
  expect(typeEncoding).toMatchInlineSnapshot(
11
21
  `"Mail(from:Person,to:Person,contents:felt)Person(name:felt,wallet:felt)"`
12
22
  );
13
- const typeEncodingStructArr = encodeType(typedDataStructArrayExample, 'Mail');
23
+ const typeEncodingStructArr = encodeType(typedDataStructArrayExample.types, 'Mail');
14
24
  expect(typeEncodingStructArr).toMatchInlineSnapshot(
15
25
  `"Mail(from:Person,to:Person,posts_len:felt,posts:Post*)Person(name:felt,wallet:felt)Post(title:felt,content:felt)"`
16
26
  );
17
27
  });
18
28
 
19
29
  test('should get right type hash', () => {
20
- const typeHashDomain = getTypeHash(typedDataExample, 'StarkNetDomain');
30
+ const typeHashDomain = getTypeHash(typedDataExample.types, 'StarkNetDomain');
21
31
  expect(typeHashDomain).toMatchInlineSnapshot(
22
32
  `"0x1bfc207425a47a5dfa1a50a4f5241203f50624ca5fdf5e18755765416b8e288"`
23
33
  );
24
- const typeHashPerson = getTypeHash(typedDataExample, 'Person');
34
+ const typeHashPerson = getTypeHash(typedDataExample.types, 'Person');
25
35
  expect(typeHashPerson).toMatchInlineSnapshot(
26
36
  `"0x2896dbe4b96a67110f454c01e5336edc5bbc3635537efd690f122f4809cc855"`
27
37
  );
28
- const typeHashMail = getTypeHash(typedDataExample, 'Mail');
38
+ const typeHashMail = getTypeHash(typedDataExample.types, 'Mail');
29
39
  expect(typeHashMail).toMatchInlineSnapshot(
30
40
  `"0x13d89452df9512bf750f539ba3001b945576243288137ddb6c788457d4b2f79"`
31
41
  );
32
- const typeHashPost = getTypeHash(typedDataStructArrayExample, 'Post');
42
+ const typeHashPost = getTypeHash(typedDataStructArrayExample.types, 'Post');
33
43
  expect(typeHashPost).toMatchInlineSnapshot(
34
44
  `"0x1d71e69bf476486b43cdcfaf5a85c00bb2d954c042b281040e513080388356d"`
35
45
  );
36
- const typeHashMailWithStructArray = getTypeHash(typedDataStructArrayExample, 'Mail');
46
+ const typeHashMailWithStructArray = getTypeHash(typedDataStructArrayExample.types, 'Mail');
37
47
  expect(typeHashMailWithStructArray).toMatchInlineSnapshot(
38
48
  `"0x873b878e35e258fc99e3085d5aaad3a81a0c821f189c08b30def2cde55ff27"`
39
49
  );
50
+ const selectorTypeHash = getTypeHash({}, 'selector');
51
+ expect(selectorTypeHash).toMatchInlineSnapshot(
52
+ `"0x1d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"`
53
+ );
54
+ });
55
+
56
+ test('should transform type selector', () => {
57
+ const selector = 'transfer';
58
+ const selectorHash = getSelectorFromName(selector);
59
+ const rawSelectorValueHash = encodeValue({}, 'felt', selectorHash);
60
+ const selectorValueHash = encodeValue({}, 'selector', selector);
61
+ expect(selectorValueHash).toEqual(rawSelectorValueHash);
62
+ expect(selectorValueHash).toMatchInlineSnapshot(`
63
+ Array [
64
+ "felt",
65
+ "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e",
66
+ ]
67
+ `);
68
+ });
69
+
70
+ test('should transform merkle tree', () => {
71
+ const tree = new MerkleTree(['0x1', '0x2', '0x3']);
72
+ const [, merkleTreeHash] = encodeValue({}, 'merkletree', tree.leaves);
73
+ expect(merkleTreeHash).toBe(tree.root);
74
+ expect(merkleTreeHash).toMatchInlineSnapshot(
75
+ `"0x551b4adb6c35d49c686a00b9192da9332b18c9b262507cad0ece37f3b6918d2"`
76
+ );
77
+ });
78
+
79
+ test('should transform merkle tree with custom types', () => {
80
+ const leaves = [
81
+ {
82
+ contractAddress: '0x1',
83
+ selector: 'transfer',
84
+ },
85
+ {
86
+ contractAddress: '0x2',
87
+ selector: 'transfer',
88
+ },
89
+ {
90
+ contractAddress: '0x3',
91
+ selector: 'transfer',
92
+ },
93
+ ];
94
+ const hashedLeaves = leaves.map(
95
+ (leaf) =>
96
+ encodeValue(
97
+ {
98
+ Policy: [
99
+ { name: 'contractAddress', type: 'felt' },
100
+ { name: 'selector', type: 'selector' },
101
+ ],
102
+ },
103
+ 'Policy',
104
+ leaf
105
+ )[1]
106
+ );
107
+ const tree = new MerkleTree(hashedLeaves);
108
+ const [, merkleTreeHash] = encodeValue(
109
+ {
110
+ Parent: [{ name: 'root', type: 'merkletree', contains: 'Policy' }],
111
+ Policy: [
112
+ { name: 'contractAddress', type: 'felt' },
113
+ { name: 'selector', type: 'selector' },
114
+ ],
115
+ },
116
+ 'merkletree',
117
+ leaves,
118
+ { key: 'root', parent: 'Parent' }
119
+ );
120
+ expect(merkleTreeHash).toBe(tree.root);
121
+ expect(merkleTreeHash).toMatchInlineSnapshot(
122
+ `"0x75c4f467f4527a5348f3e302007228a6b0057fc4c015f981ffb5b3ace475727"`
123
+ );
40
124
  });
41
125
 
42
126
  test('should get right hash for StarkNetDomain', () => {
43
- const hash = getStructHash(typedDataExample, 'StarkNetDomain', typedDataExample.domain as any);
127
+ const hash = getStructHash(
128
+ typedDataExample.types,
129
+ 'StarkNetDomain',
130
+ typedDataExample.domain as StarkNetDomain
131
+ );
44
132
  expect(hash).toMatchInlineSnapshot(
45
133
  `"0x54833b121883a3e3aebff48ec08a962f5742e5f7b973469c1f8f4f55d470b07"`
46
134
  );
@@ -122,4 +210,14 @@ describe('typedData', () => {
122
210
  `"0x70338fb11b8f70b68b261de8a322bcb004bd85e88ac47d9147982c7f5ac66fd"`
123
211
  );
124
212
  });
213
+
214
+ test('should transform session message correctly', () => {
215
+ const hash = getMessageHash(
216
+ typedDataSessionExample,
217
+ '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826'
218
+ );
219
+ expect(hash).toMatchInlineSnapshot(
220
+ `"0x1ad0330a62a4a94eae5ea1a7ad96388179d2e4d33e6f909d17421d315110653"`
221
+ );
222
+ });
125
223
  });
package/dist/index.d.ts CHANGED
@@ -16,8 +16,10 @@ export * as json from './utils/json';
16
16
  export * as number from './utils/number';
17
17
  export * as transaction from './utils/transaction';
18
18
  export * as stark from './utils/stark';
19
+ export * as merkle from './utils/merkle';
19
20
  export * as ec from './utils/ellipticCurve';
20
21
  export * as uint256 from './utils/uint256';
21
22
  export * as shortString from './utils/shortString';
22
23
  export * as typedData from './utils/typedData';
23
24
  export * from './utils/address';
25
+ export * from './utils/url';
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
26
26
  return result;
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.typedData = exports.shortString = exports.uint256 = exports.ec = exports.stark = exports.transaction = exports.number = exports.json = exports.hash = exports.encode = exports.constants = void 0;
29
+ exports.typedData = exports.shortString = exports.uint256 = exports.ec = exports.merkle = exports.stark = exports.transaction = exports.number = exports.json = exports.hash = exports.encode = exports.constants = void 0;
30
30
  /**
31
31
  * Main
32
32
  */
@@ -45,8 +45,10 @@ exports.json = __importStar(require("./utils/json"));
45
45
  exports.number = __importStar(require("./utils/number"));
46
46
  exports.transaction = __importStar(require("./utils/transaction"));
47
47
  exports.stark = __importStar(require("./utils/stark"));
48
+ exports.merkle = __importStar(require("./utils/merkle"));
48
49
  exports.ec = __importStar(require("./utils/ellipticCurve"));
49
50
  exports.uint256 = __importStar(require("./utils/uint256"));
50
51
  exports.shortString = __importStar(require("./utils/shortString"));
51
52
  exports.typedData = __importStar(require("./utils/typedData"));
52
53
  __exportStar(require("./utils/address"), exports);
54
+ __exportStar(require("./utils/url"), exports);