@snapshot-labs/snapshot.js 0.12.54 → 0.12.56
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 +85 -4
- package/dist/snapshot.esm.js +85 -4
- package/dist/snapshot.min.js +1 -1
- package/dist/src/utils.d.ts +2 -2
- package/package.json +1 -1
- package/src/networks.json +17 -2
- package/src/utils.spec.js +9 -1
- package/src/utils.ts +78 -4
package/dist/src/utils.d.ts
CHANGED
|
@@ -30,8 +30,8 @@ interface validateSchemaOptions {
|
|
|
30
30
|
export declare function validateSchema(schema: any, data: any, options?: validateSchemaOptions): true | import("ajv").ErrorObject<string, Record<string, any>, unknown>[] | null | undefined;
|
|
31
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
|
-
export declare function getEnsOwner(ens: string, network?: string, options?: any): Promise<string
|
|
34
|
-
export declare function getSpaceController(id: string, network?: string, options?: any): Promise<string
|
|
33
|
+
export declare function getEnsOwner(ens: string, network?: string, options?: any): Promise<string>;
|
|
34
|
+
export declare function getSpaceController(id: string, network?: string, options?: any): Promise<string>;
|
|
35
35
|
export declare function clone(item: any): any;
|
|
36
36
|
export declare function sleep(time: any): Promise<unknown>;
|
|
37
37
|
export declare function getNumberWithOrdinal(n: any): string;
|
package/package.json
CHANGED
package/src/networks.json
CHANGED
|
@@ -1414,7 +1414,7 @@
|
|
|
1414
1414
|
"multicall": "0xc454132B017b55b427f45078E335549A7124f5f7",
|
|
1415
1415
|
"rpc": [],
|
|
1416
1416
|
"explorer": {
|
|
1417
|
-
"url": "https://
|
|
1417
|
+
"url": "https://curtis.apescan.io"
|
|
1418
1418
|
},
|
|
1419
1419
|
"start": 6661339,
|
|
1420
1420
|
"logo": "ipfs://bafkreicljxttjq2xkgfwwpii5xegirgq2ctrnsjnzelxudjj33qzq65apu",
|
|
@@ -1429,7 +1429,7 @@
|
|
|
1429
1429
|
"multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
|
|
1430
1430
|
"rpc": [],
|
|
1431
1431
|
"explorer": {
|
|
1432
|
-
"url": "https://
|
|
1432
|
+
"url": "https://apescan.io"
|
|
1433
1433
|
},
|
|
1434
1434
|
"start": 20889,
|
|
1435
1435
|
"logo": "ipfs://bafkreielbgcox2jsw3g6pqulqb7pyjgx7czjt6ahnibihaij6lozoy53w4"
|
|
@@ -1671,6 +1671,21 @@
|
|
|
1671
1671
|
"logo": "ipfs://QmaxRoHpxZd8PqccAynherrMznMufG6sdmHZLihkECXmZv",
|
|
1672
1672
|
"testnet": true
|
|
1673
1673
|
},
|
|
1674
|
+
"314159": {
|
|
1675
|
+
"key": "314159",
|
|
1676
|
+
"name": "Filecoin Calibration Testnet",
|
|
1677
|
+
"shortName": "testnet",
|
|
1678
|
+
"chainId": 314159,
|
|
1679
|
+
"network": "testnet",
|
|
1680
|
+
"multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
|
|
1681
|
+
"rpc": [],
|
|
1682
|
+
"explorer": {
|
|
1683
|
+
"url": "https://calibration.filscan.io/en"
|
|
1684
|
+
},
|
|
1685
|
+
"start": 1446201,
|
|
1686
|
+
"logo": "ipfs://bafkreiffbopdjior7li3nlemzko7rjua6wd2hfh2vhdbenqbv4tfsbnzwu",
|
|
1687
|
+
"testnet": true
|
|
1688
|
+
},
|
|
1674
1689
|
"686868": {
|
|
1675
1690
|
"key": "686868",
|
|
1676
1691
|
"name": "Merlin Testnet",
|
package/src/utils.spec.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
getEnsTextRecord
|
|
11
11
|
} from './utils';
|
|
12
12
|
|
|
13
|
+
const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
14
|
+
|
|
13
15
|
vi.mock('cross-fetch', async () => {
|
|
14
16
|
const actual = await vi.importActual('cross-fetch');
|
|
15
17
|
|
|
@@ -617,7 +619,13 @@ describe('utils', () => {
|
|
|
617
619
|
describe('getEnsOwner', () => {
|
|
618
620
|
test('should return null when the ENS is not valid', () => {
|
|
619
621
|
// special hidden characters after the k
|
|
620
|
-
expect(getEnsOwner('elonmusk.eth')).resolves.toBe(
|
|
622
|
+
expect(getEnsOwner('elonmusk.eth')).resolves.toBe(EMPTY_ADDRESS);
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
test('throw an error when the network is not supported', () => {
|
|
626
|
+
expect(getEnsOwner('shot.eth', '100')).rejects.toThrow(
|
|
627
|
+
'Network not supported'
|
|
628
|
+
);
|
|
621
629
|
});
|
|
622
630
|
});
|
|
623
631
|
|
package/src/utils.ts
CHANGED
|
@@ -30,6 +30,15 @@ interface Strategy {
|
|
|
30
30
|
params: any;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
type DomainType = 'ens' | 'tld' | 'other-tld' | 'subdomain';
|
|
34
|
+
|
|
35
|
+
const MUTED_ERRORS = [
|
|
36
|
+
// mute error from coinbase, when the subdomain is not found
|
|
37
|
+
// most other resolvers just return an empty address
|
|
38
|
+
'response not found during CCIP fetch',
|
|
39
|
+
// mute error from missing offchain resolver (mostly for sepolia)
|
|
40
|
+
'UNSUPPORTED_OPERATION'
|
|
41
|
+
];
|
|
33
42
|
const ENS_REGISTRY = '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e';
|
|
34
43
|
const ENS_ABI = [
|
|
35
44
|
'function text(bytes32 node, string calldata key) external view returns (string memory)',
|
|
@@ -219,6 +228,45 @@ ajv.addFormat('domain', {
|
|
|
219
228
|
}
|
|
220
229
|
});
|
|
221
230
|
|
|
231
|
+
function getDomainType(domain: string): DomainType {
|
|
232
|
+
const isEns = domain.endsWith('.eth');
|
|
233
|
+
|
|
234
|
+
const tokens = domain.split('.');
|
|
235
|
+
|
|
236
|
+
if (tokens.length === 1) return 'tld';
|
|
237
|
+
else if (tokens.length === 2 && !isEns) return 'other-tld';
|
|
238
|
+
else if (tokens.length > 2) return 'subdomain';
|
|
239
|
+
else if (isEns) return 'ens';
|
|
240
|
+
else throw new Error('Invalid domain');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// see https://docs.ens.domains/registry/dns#gasless-import
|
|
244
|
+
async function getDNSOwner(domain: string): Promise<string> {
|
|
245
|
+
const response = await fetch(
|
|
246
|
+
`https://cloudflare-dns.com/dns-query?name=${domain}&type=TXT`,
|
|
247
|
+
{
|
|
248
|
+
headers: {
|
|
249
|
+
accept: 'application/dns-json'
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const data = await response.json();
|
|
255
|
+
// Error list: https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
|
|
256
|
+
if (data.Status === 3) return EMPTY_ADDRESS;
|
|
257
|
+
if (data.Status !== 0) throw new Error('Failed to fetch DNS Owner');
|
|
258
|
+
|
|
259
|
+
const ownerRecord = data.Answer?.find((record: any) =>
|
|
260
|
+
record.data.includes('ENS1')
|
|
261
|
+
);
|
|
262
|
+
|
|
263
|
+
if (!ownerRecord) return EMPTY_ADDRESS;
|
|
264
|
+
|
|
265
|
+
return getAddress(
|
|
266
|
+
ownerRecord.data.replace(new RegExp('"', 'g'), '').split(' ').pop()
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
222
270
|
export async function call(provider, abi: any[], call: any[], options?) {
|
|
223
271
|
const contract = new Contract(call[0], abi, provider);
|
|
224
272
|
try {
|
|
@@ -611,7 +659,12 @@ export async function getEnsOwner(
|
|
|
611
659
|
ens: string,
|
|
612
660
|
network = '1',
|
|
613
661
|
options: any = {}
|
|
614
|
-
): Promise<string
|
|
662
|
+
): Promise<string> {
|
|
663
|
+
if (!networks[network]?.ensResolvers?.length) {
|
|
664
|
+
throw new Error('Network not supported');
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const domainType = getDomainType(ens);
|
|
615
668
|
const provider = getProvider(network, options);
|
|
616
669
|
const ensRegistry = new Contract(
|
|
617
670
|
ENS_REGISTRY,
|
|
@@ -624,7 +677,7 @@ export async function getEnsOwner(
|
|
|
624
677
|
try {
|
|
625
678
|
ensHash = namehash(ensNormalize(ens));
|
|
626
679
|
} catch (e: any) {
|
|
627
|
-
return
|
|
680
|
+
return EMPTY_ADDRESS;
|
|
628
681
|
}
|
|
629
682
|
|
|
630
683
|
const ensNameWrapper =
|
|
@@ -639,14 +692,35 @@ export async function getEnsOwner(
|
|
|
639
692
|
);
|
|
640
693
|
owner = await ensNameWrapperContract.ownerOf(ensHash);
|
|
641
694
|
}
|
|
642
|
-
|
|
695
|
+
|
|
696
|
+
if (owner === EMPTY_ADDRESS && domainType === 'other-tld') {
|
|
697
|
+
const resolvedAddress = await provider.resolveName(ens);
|
|
698
|
+
|
|
699
|
+
// Filter out domains with valid TXT records, but not imported
|
|
700
|
+
if (resolvedAddress) {
|
|
701
|
+
owner = await getDNSOwner(ens);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (owner === EMPTY_ADDRESS && domainType === 'subdomain') {
|
|
706
|
+
try {
|
|
707
|
+
owner = await provider.resolveName(ens);
|
|
708
|
+
} catch (e: any) {
|
|
709
|
+
if (MUTED_ERRORS.every((error) => !e.message.includes(error))) {
|
|
710
|
+
throw e;
|
|
711
|
+
}
|
|
712
|
+
owner = EMPTY_ADDRESS;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
return owner || EMPTY_ADDRESS;
|
|
643
717
|
}
|
|
644
718
|
|
|
645
719
|
export async function getSpaceController(
|
|
646
720
|
id: string,
|
|
647
721
|
network = '1',
|
|
648
722
|
options: any = {}
|
|
649
|
-
): Promise<string
|
|
723
|
+
): Promise<string> {
|
|
650
724
|
const spaceUri = await getSpaceUri(id, network, options);
|
|
651
725
|
if (spaceUri) {
|
|
652
726
|
let isUriAddress = isAddress(spaceUri);
|