@snapshot-labs/snapshot.js 0.12.0-beta.5 → 0.12.0-beta.6

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.
@@ -28,7 +28,7 @@ interface validateSchemaOptions {
28
28
  spaceType?: string;
29
29
  }
30
30
  export declare function validateSchema(schema: any, data: any, options?: validateSchemaOptions): true | import("ajv").ErrorObject<string, Record<string, any>, unknown>[] | null | undefined;
31
- export declare function getEnsTextRecord(ens: string, record: string, network?: string, options?: any): Promise<any>;
31
+ export declare function getEnsTextRecord(ens: string, record: string, network?: string, options?: any): Promise<string | null>;
32
32
  export declare function getSpaceUri(id: string, network?: string, options?: any): Promise<string | null>;
33
33
  export declare function getEnsOwner(ens: string, network?: string, options?: any): Promise<string | null>;
34
34
  export declare function getSpaceController(id: string, network?: string, options?: any): Promise<string | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snapshot-labs/snapshot.js",
3
- "version": "0.12.0-beta.5",
3
+ "version": "0.12.0-beta.6",
4
4
  "repository": "snapshot-labs/snapshot.js",
5
5
  "license": "MIT",
6
6
  "main": "dist/snapshot.cjs.js",
@@ -46,7 +46,7 @@
46
46
  "rollup-plugin-terser": "^7.0.0",
47
47
  "rollup-plugin-typescript2": "^0.27.0",
48
48
  "ts-node": "^10.9.2",
49
- "typescript": "^5",
49
+ "typescript": "^5.0.0",
50
50
  "vitest": "^0.33.0"
51
51
  },
52
52
  "scripts": {
@@ -55,7 +55,8 @@
55
55
  "test": "vitest",
56
56
  "test:once": "vitest run",
57
57
  "dev": "rollup -c -w",
58
- "lint": "eslint . --ext .ts --fix",
58
+ "lint": "eslint . --ext .ts",
59
+ "lint:fix": "yarn lint --fix",
59
60
  "typecheck": "tsc --noEmit",
60
61
  "prepublishOnly": "yarn build"
61
62
  },
package/src/networks.json CHANGED
@@ -151,7 +151,7 @@
151
151
  },
152
152
  "56": {
153
153
  "key": "56",
154
- "name": "Binance Smart Chain",
154
+ "name": "BNB Smart Chain",
155
155
  "shortName": "BSC",
156
156
  "chainId": 56,
157
157
  "network": "mainnet",
@@ -168,7 +168,7 @@
168
168
  "url": "https://bscscan.com"
169
169
  },
170
170
  "start": 461230,
171
- "logo": "ipfs://QmWQaQ4Tv28DwA4DRKjSDJFWY9mZboGvuu77J8nh7kucxv"
171
+ "logo": "ipfs://bafkreibll4la7wqerzs7zwxjne2j7ayynbg2wlenemssoahxxj5rbt6c64"
172
172
  },
173
173
  "61": {
174
174
  "key": "61",
@@ -254,7 +254,7 @@
254
254
  },
255
255
  "97": {
256
256
  "key": "97",
257
- "name": "Binance Smart Chain Testnet",
257
+ "name": "BNB Smart Chain Testnet",
258
258
  "shortName": "BSC Testnet",
259
259
  "chainId": 97,
260
260
  "network": "testnet",
@@ -268,7 +268,7 @@
268
268
  "url": "https://testnet.bscscan.com"
269
269
  },
270
270
  "start": 3599656,
271
- "logo": "ipfs://QmWQaQ4Tv28DwA4DRKjSDJFWY9mZboGvuu77J8nh7kucxv"
271
+ "logo": "ipfs://bafkreibll4la7wqerzs7zwxjne2j7ayynbg2wlenemssoahxxj5rbt6c64"
272
272
  },
273
273
  "100": {
274
274
  "key": "100",
@@ -1408,7 +1408,7 @@
1408
1408
  "url": "https://blastscan.io"
1409
1409
  },
1410
1410
  "start": 88189,
1411
- "logo": "ipfs://bafkreibfmkjg22cozxppzcoxswj45clvh2rqhxzax57cmmgudbtkf4dkce"
1411
+ "logo": "ipfs://bafkreicqhrimt2zyp2kvhmbpvffxlmxovkg5vw6zkissyzibcfy45kbvrm"
1412
1412
  },
1413
1413
  "84532": {
1414
1414
  "key": "84532",
@@ -1622,4 +1622,4 @@
1622
1622
  "start": 7521509,
1623
1623
  "logo": "ipfs://QmNnGPr1CNvj12SSGzKARtUHv9FyEfE5nES73U4vBWQSJL"
1624
1624
  }
1625
- }
1625
+ }
@@ -59,5 +59,6 @@
59
59
  "8ea9074bff3a30cb61f4f0f0f142c9335c6be828feba0571a45de3f1fd0319c0": "alias",
60
60
  "42f8858a21d4aa232721cb97074851e729829ea362b88bb21f3879899663b586": "follow",
61
61
  "2bb75450e28b06f259ea764cd669de6bde0ba70ce729b0ff05ab9df56e0ff21d": "unfollow",
62
- "2ffbebcbd22ef48fd2f4a1182ff1feda7795b57689bd6f0dd73c89e925e7fefb": "profile"
62
+ "2ffbebcbd22ef48fd2f4a1182ff1feda7795b57689bd6f0dd73c89e925e7fefb": "profile",
63
+ "4288d50b713081aae77d60d596d75864bff7acf7791a00183401e58658ee9da5": "statement"
63
64
  }
package/src/sign/index.ts CHANGED
@@ -75,7 +75,9 @@ export default class Client {
75
75
  // @ts-ignore
76
76
  const signer = web3?.getSigner ? web3.getSigner() : web3;
77
77
  const checksumAddress = getAddress(address);
78
- message.from = message.from ? getAddress(message.from) : checksumAddress;
78
+ message.from = message.from
79
+ ? getAddress(message.from).toLowerCase()
80
+ : checksumAddress.toLowerCase();
79
81
  if (!message.timestamp)
80
82
  message.timestamp = parseInt((Date.now() / 1e3).toFixed());
81
83
 
@@ -88,7 +90,11 @@ export default class Client {
88
90
  }
89
91
  const data: any = { domain: domainData, types, message };
90
92
  const sig = await signer._signTypedData(domainData, data.types, message);
91
- return await this.send({ address: checksumAddress, sig, data });
93
+ return await this.send({
94
+ address: checksumAddress.toLowerCase(),
95
+ sig,
96
+ data
97
+ });
92
98
  }
93
99
 
94
100
  async send(envelop) {
package/src/sign/types.ts CHANGED
@@ -272,6 +272,7 @@ export const voteString2Types = {
272
272
  };
273
273
 
274
274
  export const followTypes = {
275
+
275
276
  Follow: [
276
277
  { name: 'from', type: 'address' },
277
278
  { name: 'network', type: 'string' },
package/src/utils.spec.js CHANGED
@@ -1,6 +1,12 @@
1
1
  import { describe, test, expect, vi, afterEach } from 'vitest';
2
2
  import * as crossFetch from 'cross-fetch';
3
- import { validate, getScores, getVp, getFormattedAddress } from './utils';
3
+ import {
4
+ validate,
5
+ validateSchema,
6
+ getScores,
7
+ getVp,
8
+ getFormattedAddress
9
+ } from './utils';
4
10
 
5
11
  vi.mock('cross-fetch', async () => {
6
12
  const actual = await vi.importActual('cross-fetch');
@@ -527,4 +533,82 @@ describe('utils', () => {
527
533
  expect(() => getFormattedAddress(address, 'evm')).toThrow();
528
534
  });
529
535
  });
536
+
537
+ describe('address validation', () => {
538
+ const evmSchema = {
539
+ $schema: 'http://json-schema.org/draft-07/schema#',
540
+ $ref: '#/definitions/Envelope',
541
+ definitions: {
542
+ Envelope: {
543
+ type: 'object',
544
+ properties: {
545
+ address: {
546
+ type: 'string',
547
+ format: 'address'
548
+ }
549
+ }
550
+ }
551
+ }
552
+ };
553
+
554
+ const starknetSchema = {
555
+ $schema: 'http://json-schema.org/draft-07/schema#',
556
+ $ref: '#/definitions/Envelope',
557
+ definitions: {
558
+ Envelope: {
559
+ type: 'object',
560
+ properties: {
561
+ address: {
562
+ type: 'string',
563
+ format: 'starknetAddress'
564
+ }
565
+ }
566
+ }
567
+ }
568
+ };
569
+
570
+ test('should return true on checksummed EVM address', async () => {
571
+ const result = validateSchema(evmSchema, {
572
+ address: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'
573
+ });
574
+ expect(result).toBe(true);
575
+ });
576
+
577
+ test('should return an error on lowercase EVM address', async () => {
578
+ const result = validateSchema(evmSchema, {
579
+ address: '0x91FD2c8d24767db4Ece7069AA27832ffaf8590f3'.toLowerCase()
580
+ });
581
+ expect(result).not.toBe(true);
582
+ });
583
+
584
+ test('should return an error on empty address', async () => {
585
+ const result = validateSchema(evmSchema, {
586
+ address: ''
587
+ });
588
+ expect(result).not.toBe(true);
589
+ });
590
+
591
+ test('should return true on lowercase padded starknet address', async () => {
592
+ const result = validateSchema(starknetSchema, {
593
+ address:
594
+ '0x02a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
595
+ });
596
+ expect(result).toBe(true);
597
+ });
598
+
599
+ test('should return an error on non-padded starknet address', async () => {
600
+ const result = validateSchema(starknetSchema, {
601
+ address:
602
+ '0x2a0a8f3b6097e7a6bd7649deb30715323072a159c0e6b71b689bd245c146cc0'
603
+ });
604
+ expect(result).not.toBe(true);
605
+ });
606
+
607
+ test('should return an error on empty starknet address', async () => {
608
+ const result = validateSchema(starknetSchema, {
609
+ address: ''
610
+ });
611
+ expect(result).not.toBe(true);
612
+ });
613
+ });
530
614
  });
package/src/utils.ts CHANGED
@@ -30,8 +30,10 @@ interface Strategy {
30
30
  params: any;
31
31
  }
32
32
 
33
- const ENS_RESOLVER_ABI = [
34
- 'function text(bytes32 node, string calldata key) external view returns (string memory)'
33
+ const ENS_REGISTRY = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
34
+ const ENS_ABI = [
35
+ 'function text(bytes32 node, string calldata key) external view returns (string memory)',
36
+ 'function resolver(bytes32 node) view returns (address)' // ENS registry ABI
35
37
  ];
36
38
  const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000';
37
39
 
@@ -90,7 +92,7 @@ addErrors(ajv);
90
92
  ajv.addFormat('address', {
91
93
  validate: (value: string) => {
92
94
  try {
93
- return isAddress(value);
95
+ return value === getAddress(value);
94
96
  } catch (e: any) {
95
97
  return false;
96
98
  }
@@ -100,7 +102,7 @@ ajv.addFormat('address', {
100
102
  ajv.addFormat('starknetAddress', {
101
103
  validate: (value: string) => {
102
104
  try {
103
- return isStarknetAddress(value);
105
+ return validateAndParseAddress(value) === value;
104
106
  } catch (e: any) {
105
107
  return false;
106
108
  }
@@ -536,25 +538,34 @@ export async function getEnsTextRecord(
536
538
  options: any = {}
537
539
  ) {
538
540
  const {
539
- ensResolvers: ensResolversOpt,
541
+ ensResolvers = networks[network]?.ensResolvers ||
542
+ networks['1'].ensResolvers,
540
543
  broviderUrl,
541
544
  ...multicallOptions
542
545
  } = options;
543
- const ensResolvers =
544
- ensResolversOpt ||
545
- networks[network].ensResolvers ||
546
- networks['1'].ensResolvers;
546
+
547
547
  const ensHash = namehash(ensNormalize(ens));
548
548
  const provider = getProvider(network, { broviderUrl });
549
549
 
550
- const result = await multicall(
550
+ const calls = [
551
+ [ENS_REGISTRY, 'resolver', [ensHash]], // Query for resolver from registry
552
+ ...ensResolvers.map((address: string) => [
553
+ address,
554
+ 'text',
555
+ [ensHash, record]
556
+ ]) // Query for text record from each resolver
557
+ ];
558
+
559
+ const [[resolverAddress], ...textRecords]: string[][] = await multicall(
551
560
  network,
552
561
  provider,
553
- ENS_RESOLVER_ABI,
554
- ensResolvers.map((address: any) => [address, 'text', [ensHash, record]]),
562
+ ENS_ABI,
563
+ calls,
555
564
  multicallOptions
556
565
  );
557
- return result.flat().find((r: string) => r) || '';
566
+
567
+ const resolverIndex = ensResolvers.indexOf(resolverAddress);
568
+ return resolverIndex !== -1 ? textRecords[resolverIndex]?.[0] : null;
558
569
  }
559
570
 
560
571
  export async function getSpaceUri(
@@ -575,10 +586,9 @@ export async function getEnsOwner(
575
586
  network = '1',
576
587
  options: any = {}
577
588
  ): Promise<string | null> {
578
- const registryAddress = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
579
589
  const provider = getProvider(network, options);
580
590
  const ensRegistry = new Contract(
581
- registryAddress,
591
+ ENS_REGISTRY,
582
592
  ['function owner(bytes32) view returns (address)'],
583
593
  provider
584
594
  );
@@ -1,6 +1,7 @@
1
1
  import { test, expect, describe } from 'vitest';
2
2
  import starknetMessage from '../../test/fixtures/starknet/message-alias.json';
3
3
  import verify, { getHash } from './starknet';
4
+ import { validateAndParseAddress } from 'starknet';
4
5
 
5
6
  describe('verify/starknet', () => {
6
7
  describe('getHash()', () => {
@@ -31,6 +32,17 @@ describe('verify/starknet', () => {
31
32
  ).resolves.toBe(true);
32
33
  });
33
34
 
35
+ test('should return true if the signature is valid with a padded address', () => {
36
+ expect(
37
+ verify(
38
+ validateAndParseAddress(starknetMessage.address),
39
+ starknetMessage.sig,
40
+ starknetMessage.data,
41
+ 'SN_SEPOLIA'
42
+ )
43
+ ).resolves.toBe(true);
44
+ });
45
+
34
46
  test('should throw an error if message is on wrong network', () => {
35
47
  expect(
36
48
  verify(