starknet 4.3.1 → 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.
- package/CHANGELOG.md +18 -0
- package/__mocks__/typedDataSessionExample.json +42 -0
- package/__tests__/utils/__snapshots__/ellipticalCurve.test.ts.snap +2 -0
- package/__tests__/utils/ellipticalCurve.test.ts +5 -0
- package/__tests__/utils/merkle.test.ts +146 -0
- package/__tests__/utils/typedData.test.ts +107 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/signer/default.d.ts +1 -1
- package/dist/signer/default.js +1 -0
- package/dist/utils/hash.js +8 -6
- package/dist/utils/merkle.d.ts +10 -0
- package/dist/utils/merkle.js +90 -0
- package/dist/utils/number.js +1 -1
- package/dist/utils/typedData/index.d.ts +23 -8
- package/dist/utils/typedData/index.js +70 -31
- package/dist/utils/typedData/types.d.ts +8 -3
- package/index.d.ts +1 -0
- package/index.js +2 -1
- package/package.json +1 -1
- package/signer/default.d.ts +1 -1
- package/signer/default.js +1 -0
- package/src/index.ts +1 -0
- package/src/signer/default.ts +2 -2
- package/src/utils/hash.ts +8 -6
- package/src/utils/merkle.ts +70 -0
- package/src/utils/number.ts +1 -1
- package/src/utils/typedData/index.ts +88 -34
- package/src/utils/typedData/types.ts +12 -4
- package/utils/hash.js +8 -6
- package/utils/merkle.d.ts +10 -0
- package/utils/merkle.js +90 -0
- package/utils/number.js +1 -1
- package/utils/typedData/index.d.ts +23 -8
- package/utils/typedData/index.js +70 -31
- package/utils/typedData/types.d.ts +8 -3
- package/www/guides/account.md +8 -8
- package/www/guides/erc20.md +4 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
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
|
+
|
|
1
19
|
## [4.3.1](https://github.com/0xs34n/starknet.js/compare/v4.3.0...v4.3.1) (2022-08-31)
|
|
2
20
|
|
|
3
21
|
### Bug Fixes
|
|
@@ -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
|
+
}
|
|
@@ -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 {
|
|
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(
|
|
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,6 +16,7 @@ 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';
|
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,6 +45,7 @@ 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"));
|
package/dist/signer/default.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { TypedData } from '../utils/typedData';
|
|
|
3
3
|
import { SignerInterface } from './interface';
|
|
4
4
|
export declare class Signer implements SignerInterface {
|
|
5
5
|
protected keyPair: KeyPair;
|
|
6
|
-
constructor(keyPair
|
|
6
|
+
constructor(keyPair?: KeyPair);
|
|
7
7
|
getPubKey(): Promise<string>;
|
|
8
8
|
signTransaction(transactions: Invocation[], transactionsDetail: InvocationsSignerDetails, abis?: Abi[]): Promise<Signature>;
|
|
9
9
|
signMessage(typedData: TypedData, accountAddress: string): Promise<Signature>;
|
package/dist/signer/default.js
CHANGED
|
@@ -43,6 +43,7 @@ var transaction_1 = require("../utils/transaction");
|
|
|
43
43
|
var typedData_1 = require("../utils/typedData");
|
|
44
44
|
var Signer = /** @class */ (function () {
|
|
45
45
|
function Signer(keyPair) {
|
|
46
|
+
if (keyPair === void 0) { keyPair = (0, ellipticCurve_1.genKeyPair)(); }
|
|
46
47
|
this.keyPair = keyPair;
|
|
47
48
|
}
|
|
48
49
|
Signer.prototype.getPubKey = function () {
|
package/dist/utils/hash.js
CHANGED
|
@@ -78,13 +78,15 @@ function pedersen(input) {
|
|
|
78
78
|
for (var i = 0; i < input.length; i += 1) {
|
|
79
79
|
var x = (0, number_1.toBN)(input[i]);
|
|
80
80
|
(0, minimalistic_assert_1.default)(x.gte(constants_1.ZERO) && x.lt((0, number_1.toBN)((0, encode_1.addHexPrefix)(constants_1.FIELD_PRIME))), "Invalid input: ".concat(input[i]));
|
|
81
|
-
|
|
82
|
-
var
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
if (!x.isZero()) {
|
|
82
|
+
for (var j = 0; j < 252; j += 1) {
|
|
83
|
+
var pt = constantPoints[2 + i * 252 + j];
|
|
84
|
+
(0, minimalistic_assert_1.default)(!point.getX().eq(pt.getX()));
|
|
85
|
+
if (x.and(constants_1.ONE).toNumber() !== 0) {
|
|
86
|
+
point = point.add(pt);
|
|
87
|
+
}
|
|
88
|
+
x = x.shrn(1);
|
|
86
89
|
}
|
|
87
|
-
x = x.shrn(1);
|
|
88
90
|
}
|
|
89
91
|
}
|
|
90
92
|
return (0, encode_1.addHexPrefix)(point.getX().toString(16));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare class MerkleTree {
|
|
2
|
+
leaves: string[];
|
|
3
|
+
branches: string[][];
|
|
4
|
+
root: string;
|
|
5
|
+
constructor(leafHashes: string[]);
|
|
6
|
+
private build;
|
|
7
|
+
static hash(a: string, b: string): string;
|
|
8
|
+
getProof(leaf: string, branch?: string[], hashPath?: string[]): string[];
|
|
9
|
+
}
|
|
10
|
+
export declare function proofMerklePath(root: string, leaf: string, path: string[]): boolean;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __read = (this && this.__read) || function (o, n) {
|
|
3
|
+
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
4
|
+
if (!m) return o;
|
|
5
|
+
var i = m.call(o), r, ar = [], e;
|
|
6
|
+
try {
|
|
7
|
+
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
8
|
+
}
|
|
9
|
+
catch (error) { e = { error: error }; }
|
|
10
|
+
finally {
|
|
11
|
+
try {
|
|
12
|
+
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
13
|
+
}
|
|
14
|
+
finally { if (e) throw e.error; }
|
|
15
|
+
}
|
|
16
|
+
return ar;
|
|
17
|
+
};
|
|
18
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
19
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
20
|
+
if (ar || !(i in from)) {
|
|
21
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
22
|
+
ar[i] = from[i];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
26
|
+
};
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.proofMerklePath = exports.MerkleTree = void 0;
|
|
29
|
+
var hash_1 = require("./hash");
|
|
30
|
+
var MerkleTree = /** @class */ (function () {
|
|
31
|
+
function MerkleTree(leafHashes) {
|
|
32
|
+
this.branches = [];
|
|
33
|
+
this.leaves = leafHashes;
|
|
34
|
+
this.root = this.build(leafHashes);
|
|
35
|
+
}
|
|
36
|
+
MerkleTree.prototype.build = function (leaves) {
|
|
37
|
+
if (leaves.length === 1) {
|
|
38
|
+
return leaves[0];
|
|
39
|
+
}
|
|
40
|
+
if (leaves.length !== this.leaves.length) {
|
|
41
|
+
this.branches.push(leaves);
|
|
42
|
+
}
|
|
43
|
+
var newLeaves = [];
|
|
44
|
+
for (var i = 0; i < leaves.length; i += 2) {
|
|
45
|
+
if (i + 1 === leaves.length) {
|
|
46
|
+
newLeaves.push(leaves[i]);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
newLeaves.push(MerkleTree.hash(leaves[i], leaves[i + 1]));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return this.build(newLeaves);
|
|
53
|
+
};
|
|
54
|
+
MerkleTree.hash = function (a, b) {
|
|
55
|
+
var _a = __read([a, b].sort(), 2), aSorted = _a[0], bSorted = _a[1];
|
|
56
|
+
return (0, hash_1.pedersen)([aSorted, bSorted]);
|
|
57
|
+
};
|
|
58
|
+
MerkleTree.prototype.getProof = function (leaf, branch, hashPath) {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
if (branch === void 0) { branch = this.leaves; }
|
|
61
|
+
if (hashPath === void 0) { hashPath = []; }
|
|
62
|
+
var index = branch.indexOf(leaf);
|
|
63
|
+
if (index === -1) {
|
|
64
|
+
throw new Error('leaf not found');
|
|
65
|
+
}
|
|
66
|
+
if (branch.length === 1) {
|
|
67
|
+
return hashPath;
|
|
68
|
+
}
|
|
69
|
+
var isLeft = index % 2 === 0;
|
|
70
|
+
var neededBranch = (_a = (isLeft ? branch[index + 1] : branch[index - 1])) !== null && _a !== void 0 ? _a : '0x0';
|
|
71
|
+
var newHashPath = __spreadArray(__spreadArray([], __read(hashPath), false), [neededBranch], false);
|
|
72
|
+
var currentBranchLevelIndex = this.leaves.length === branch.length
|
|
73
|
+
? -1
|
|
74
|
+
: this.branches.findIndex(function (b) { return b.length === branch.length; });
|
|
75
|
+
var nextBranch = (_b = this.branches[currentBranchLevelIndex + 1]) !== null && _b !== void 0 ? _b : [this.root];
|
|
76
|
+
return this.getProof(neededBranch === '0x0'
|
|
77
|
+
? leaf
|
|
78
|
+
: MerkleTree.hash(isLeft ? leaf : neededBranch, isLeft ? neededBranch : leaf), nextBranch, newHashPath);
|
|
79
|
+
};
|
|
80
|
+
return MerkleTree;
|
|
81
|
+
}());
|
|
82
|
+
exports.MerkleTree = MerkleTree;
|
|
83
|
+
function proofMerklePath(root, leaf, path) {
|
|
84
|
+
if (path.length === 0) {
|
|
85
|
+
return root === leaf;
|
|
86
|
+
}
|
|
87
|
+
var _a = __read(path), next = _a[0], rest = _a.slice(1);
|
|
88
|
+
return proofMerklePath(root, MerkleTree.hash(leaf, next), rest);
|
|
89
|
+
}
|
|
90
|
+
exports.proofMerklePath = proofMerklePath;
|
package/dist/utils/number.js
CHANGED
|
@@ -31,7 +31,7 @@ var bn_js_1 = __importStar(require("bn.js"));
|
|
|
31
31
|
var minimalistic_assert_1 = __importDefault(require("minimalistic-assert"));
|
|
32
32
|
var encode_1 = require("./encode");
|
|
33
33
|
function isHex(hex) {
|
|
34
|
-
return
|
|
34
|
+
return /^0x[0-9a-f]*$/i.test(hex);
|
|
35
35
|
}
|
|
36
36
|
exports.isHex = isHex;
|
|
37
37
|
function toBN(number, base) {
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BigNumberish } from '../number';
|
|
2
|
-
import { TypedData } from './types';
|
|
2
|
+
import { StarkNetMerkleType, StarkNetType, TypedData } from './types';
|
|
3
3
|
export * from './types';
|
|
4
|
+
export declare function prepareSelector(selector: string): string;
|
|
5
|
+
export declare function isMerkleTreeType(type: StarkNetType): type is StarkNetMerkleType;
|
|
6
|
+
interface Context {
|
|
7
|
+
parent?: string;
|
|
8
|
+
key?: string;
|
|
9
|
+
}
|
|
4
10
|
/**
|
|
5
11
|
* Get the dependencies of a struct type. If a struct has the same dependency multiple times, it's only included once
|
|
6
12
|
* in the resulting array.
|
|
@@ -10,7 +16,7 @@ export * from './types';
|
|
|
10
16
|
* @param {string[]} [dependencies]
|
|
11
17
|
* @return {string[]}
|
|
12
18
|
*/
|
|
13
|
-
export declare const getDependencies: (
|
|
19
|
+
export declare const getDependencies: (types: TypedData['types'], type: string, dependencies?: string[]) => string[];
|
|
14
20
|
/**
|
|
15
21
|
* Encode a type to a string. All dependant types are alphabetically sorted.
|
|
16
22
|
*
|
|
@@ -18,7 +24,7 @@ export declare const getDependencies: (typedData: TypedData, type: string, depen
|
|
|
18
24
|
* @param {string} type
|
|
19
25
|
* @return {string}
|
|
20
26
|
*/
|
|
21
|
-
export declare const encodeType: (
|
|
27
|
+
export declare const encodeType: (types: TypedData['types'], type: string) => string;
|
|
22
28
|
/**
|
|
23
29
|
* Get a type string as hash.
|
|
24
30
|
*
|
|
@@ -26,7 +32,17 @@ export declare const encodeType: (typedData: TypedData, type: string) => string;
|
|
|
26
32
|
* @param {string} type
|
|
27
33
|
* @return {string}
|
|
28
34
|
*/
|
|
29
|
-
export declare const getTypeHash: (
|
|
35
|
+
export declare const getTypeHash: (types: TypedData['types'], type: string) => string;
|
|
36
|
+
/**
|
|
37
|
+
* Encodes a single value to an ABI serialisable string, number or Buffer. Returns the data as tuple, which consists of
|
|
38
|
+
* an array of ABI compatible types, and an array of corresponding values.
|
|
39
|
+
*
|
|
40
|
+
* @param {TypedData} typedData
|
|
41
|
+
* @param {string} type
|
|
42
|
+
* @param {any} data
|
|
43
|
+
* @returns {[string, string]}
|
|
44
|
+
*/
|
|
45
|
+
export declare const encodeValue: (types: TypedData['types'], type: string, data: unknown, ctx?: Context) => [string, string];
|
|
30
46
|
/**
|
|
31
47
|
* Encode the data to an ABI encoded Buffer. The data should be a key -> value object with all the required values. All
|
|
32
48
|
* dependant types are automatically encoded.
|
|
@@ -35,7 +51,7 @@ export declare const getTypeHash: (typedData: TypedData, type: string) => string
|
|
|
35
51
|
* @param {string} type
|
|
36
52
|
* @param {Record<string, any>} data
|
|
37
53
|
*/
|
|
38
|
-
export declare const encodeData: <T extends TypedData>(
|
|
54
|
+
export declare const encodeData: <T extends TypedData>(types: T["types"], type: string, data: T["message"]) => string[][];
|
|
39
55
|
/**
|
|
40
56
|
* Get encoded data as a hash. The data should be a key -> value object with all the required values. All dependant
|
|
41
57
|
* types are automatically encoded.
|
|
@@ -45,10 +61,9 @@ export declare const encodeData: <T extends TypedData>(typedData: T, type: strin
|
|
|
45
61
|
* @param {Record<string, any>} data
|
|
46
62
|
* @return {Buffer}
|
|
47
63
|
*/
|
|
48
|
-
export declare const getStructHash: <T extends TypedData>(
|
|
64
|
+
export declare const getStructHash: <T extends TypedData>(types: T["types"], type: string, data: T["message"]) => string;
|
|
49
65
|
/**
|
|
50
|
-
* Get the EIP-191 encoded message to sign, from the typedData object.
|
|
51
|
-
* with Keccak256.
|
|
66
|
+
* Get the EIP-191 encoded message to sign, from the typedData object.
|
|
52
67
|
*
|
|
53
68
|
* @param {TypedData} typedData
|
|
54
69
|
* @param {BigNumberish} account
|