@snapshot-labs/snapshot.js 0.12.1 → 0.12.2
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/dist/snapshot.cjs.js +18 -9
- package/dist/snapshot.esm.js +18 -9
- package/dist/snapshot.min.js +15 -15
- package/package.json +2 -1
- package/src/verify/starknet.spec.ts +57 -23
- package/src/verify/starknet.ts +26 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snapshot-labs/snapshot.js",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.2",
|
|
4
4
|
"repository": "snapshot-labs/snapshot.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/snapshot.cjs.js",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"@ensdomains/eth-ens-namehash": "^2.0.15",
|
|
12
12
|
"@ethersproject/abi": "^5.6.4",
|
|
13
13
|
"@ethersproject/address": "^5.6.1",
|
|
14
|
+
"@ethersproject/bignumber": "^5.7.0",
|
|
14
15
|
"@ethersproject/bytes": "^5.6.1",
|
|
15
16
|
"@ethersproject/contracts": "^5.6.2",
|
|
16
17
|
"@ethersproject/hash": "^5.7.0",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { test, expect, describe } from 'vitest';
|
|
2
2
|
import starknetMessage from '../../test/fixtures/starknet/message-alias.json';
|
|
3
|
+
import starknetMessageRsv from '../../test/fixtures/starknet/message-alias-rsv.json';
|
|
3
4
|
import verify, { getHash } from './starknet';
|
|
4
5
|
import { validateAndParseAddress } from 'starknet';
|
|
6
|
+
import { clone } from '../utils';
|
|
5
7
|
|
|
6
8
|
describe('verify/starknet', () => {
|
|
7
9
|
describe('getHash()', () => {
|
|
@@ -21,47 +23,79 @@ describe('verify/starknet', () => {
|
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
describe('verify()', () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
)
|
|
32
|
-
)
|
|
26
|
+
describe.each([
|
|
27
|
+
['2', starknetMessage],
|
|
28
|
+
['3', starknetMessageRsv]
|
|
29
|
+
])('with a %s items signature', (title, message) => {
|
|
30
|
+
test('should return true if the signature is valid', () => {
|
|
31
|
+
expect(
|
|
32
|
+
verify(message.address, message.sig, message.data, 'SN_MAIN')
|
|
33
|
+
).resolves.toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('should return true if the signature is valid with a padded address', () => {
|
|
37
|
+
expect(
|
|
38
|
+
verify(
|
|
39
|
+
validateAndParseAddress(message.address),
|
|
40
|
+
message.sig,
|
|
41
|
+
message.data,
|
|
42
|
+
'SN_MAIN'
|
|
43
|
+
)
|
|
44
|
+
).resolves.toBe(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should return true when verifying on a different network', () => {
|
|
48
|
+
expect(
|
|
49
|
+
verify(message.address, message.sig, message.data, 'SN_SEPOLIA')
|
|
50
|
+
).resolves.toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('should throw an error if the signature is invalid', () => {
|
|
54
|
+
expect(
|
|
55
|
+
verify(
|
|
56
|
+
'0x7667469b8e93faa642573078b6bf8c790d3a6184b2a1bb39c5c923a732862e1',
|
|
57
|
+
message.sig,
|
|
58
|
+
message.data
|
|
59
|
+
)
|
|
60
|
+
).rejects.toThrow();
|
|
61
|
+
});
|
|
33
62
|
});
|
|
34
63
|
|
|
35
|
-
test('should
|
|
64
|
+
test('should throw an error when the contract is not deployed', () => {
|
|
36
65
|
expect(
|
|
37
66
|
verify(
|
|
38
|
-
|
|
67
|
+
'0x07f71118e351c02f6EC7099C8CDf93AED66CEd8406E94631cC91637f7D7F203A',
|
|
39
68
|
starknetMessage.sig,
|
|
40
69
|
starknetMessage.data,
|
|
41
|
-
'
|
|
70
|
+
'SN_MAIN'
|
|
42
71
|
)
|
|
43
|
-
).
|
|
72
|
+
).rejects.toThrowError('Contract not deployed');
|
|
44
73
|
});
|
|
45
74
|
|
|
46
|
-
test('should
|
|
75
|
+
test('should return false when the signature is not valid', () => {
|
|
47
76
|
expect(
|
|
48
77
|
verify(
|
|
49
78
|
starknetMessage.address,
|
|
50
|
-
|
|
79
|
+
['1', '2'],
|
|
51
80
|
starknetMessage.data,
|
|
52
81
|
'SN_MAIN'
|
|
53
82
|
)
|
|
54
|
-
).
|
|
83
|
+
).resolves.toBe(false);
|
|
55
84
|
});
|
|
56
85
|
|
|
57
|
-
test('should
|
|
86
|
+
test('should return false when the signature is not valid', () => {
|
|
87
|
+
const data = clone(starknetMessage.data);
|
|
88
|
+
data.message.timestamp = 1234;
|
|
89
|
+
|
|
58
90
|
expect(
|
|
59
|
-
verify(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
91
|
+
verify(starknetMessage.address, starknetMessage.sig, data, 'SN_MAIN')
|
|
92
|
+
).resolves.toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('should throw an error on wrong signature length', () => {
|
|
96
|
+
expect(
|
|
97
|
+
verify(starknetMessage.address, ['1'], starknetMessage.data, 'SN_MAIN')
|
|
98
|
+
).rejects.toThrowError('Invalid signature format');
|
|
65
99
|
});
|
|
66
100
|
});
|
|
67
101
|
});
|
package/src/verify/starknet.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Contract, RpcProvider, typedData } from 'starknet';
|
|
2
|
+
import { BigNumber } from '@ethersproject/bignumber';
|
|
2
3
|
import type { SignaturePayload } from '.';
|
|
3
4
|
import type { ProviderOptions } from '../utils/provider';
|
|
4
5
|
|
|
@@ -11,11 +12,11 @@ const RPC_URLS: Record<NetworkType, string> = {
|
|
|
11
12
|
|
|
12
13
|
const ABI = [
|
|
13
14
|
{
|
|
14
|
-
name: 'argent::account::
|
|
15
|
+
name: 'argent::common::account::IAccount',
|
|
15
16
|
type: 'interface',
|
|
16
17
|
items: [
|
|
17
18
|
{
|
|
18
|
-
name: '
|
|
19
|
+
name: 'is_valid_signature',
|
|
19
20
|
type: 'function',
|
|
20
21
|
inputs: [
|
|
21
22
|
{
|
|
@@ -23,7 +24,7 @@ const ABI = [
|
|
|
23
24
|
type: 'core::felt252'
|
|
24
25
|
},
|
|
25
26
|
{
|
|
26
|
-
name: '
|
|
27
|
+
name: 'signature',
|
|
27
28
|
type: 'core::array::Array::<core::felt252>'
|
|
28
29
|
}
|
|
29
30
|
],
|
|
@@ -67,16 +68,28 @@ export default async function verify(
|
|
|
67
68
|
network: NetworkType = 'SN_MAIN',
|
|
68
69
|
options: ProviderOptions = {}
|
|
69
70
|
): Promise<boolean> {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
try {
|
|
72
|
+
const contractAccount = new Contract(
|
|
73
|
+
ABI,
|
|
74
|
+
address,
|
|
75
|
+
getProvider(network, options)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
if (sig.length < 2) {
|
|
79
|
+
throw new Error('Invalid signature format');
|
|
80
|
+
}
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
const result = await contractAccount.is_valid_signature(
|
|
83
|
+
getHash(data, address),
|
|
84
|
+
sig.slice(-2)
|
|
85
|
+
);
|
|
80
86
|
|
|
81
|
-
|
|
87
|
+
return BigNumber.from(result).eq(BigNumber.from('370462705988'));
|
|
88
|
+
} catch (e: any) {
|
|
89
|
+
if (e.message.includes('Contract not found')) {
|
|
90
|
+
throw new Error('Contract not deployed');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw e;
|
|
94
|
+
}
|
|
82
95
|
}
|