@snapshot-labs/snapshot.js 0.13.0 → 0.14.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.
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  var fetch = require('cross-fetch');
4
- var abi = require('@ethersproject/abi');
5
4
  var contracts = require('@ethersproject/contracts');
6
5
  var address = require('@ethersproject/address');
7
6
  var units = require('@ethersproject/units');
@@ -10,12 +9,13 @@ var jsonToGraphqlQuery = require('json-to-graphql-query');
10
9
  var Ajv = require('ajv');
11
10
  var addFormats = require('ajv-formats');
12
11
  var addErrors = require('ajv-errors');
13
- var set = require('lodash.set');
14
- var providers$1 = require('@ethersproject/providers');
15
- var bytes = require('@ethersproject/bytes');
12
+ var providers = require('@ethersproject/providers');
16
13
  var starknet$1 = require('starknet');
14
+ var bytes = require('@ethersproject/bytes');
17
15
  var bignumber = require('@ethersproject/bignumber');
18
16
  var wallet = require('@ethersproject/wallet');
17
+ var abi = require('@ethersproject/abi');
18
+ var set = require('lodash.set');
19
19
 
20
20
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
21
21
 
@@ -283,33 +283,6 @@ var constants = {
283
283
  local: local
284
284
  };
285
285
 
286
- class Multicaller {
287
- constructor(network, provider, abi, options) {
288
- this.options = {};
289
- this.calls = [];
290
- this.paths = [];
291
- this.network = network;
292
- this.provider = provider;
293
- this.abi = abi;
294
- this.options = options || {};
295
- }
296
- call(path, address, fn, params) {
297
- this.calls.push([address, fn, params]);
298
- this.paths.push(path);
299
- return this;
300
- }
301
- execute(from) {
302
- return __awaiter(this, void 0, void 0, function* () {
303
- const obj = from || {};
304
- const result = yield multicall(this.network, this.provider, this.abi, this.calls, this.options);
305
- result.forEach((r, i) => set__default['default'](obj, this.paths[i], r.length > 1 ? r : r[0]));
306
- this.calls = [];
307
- this.paths = [];
308
- return obj;
309
- });
310
- }
311
- }
312
-
313
286
  let cache = {};
314
287
  let expirationTime = 0;
315
288
  function getSnapshots(network_1, snapshot_1, provider_1, networks_1) {
@@ -357,213 +330,6 @@ function getSnapshots(network_1, snapshot_1, provider_1, networks_1) {
357
330
  });
358
331
  }
359
332
 
360
- const providers = {};
361
- const DEFAULT_BROVIDER_URL = 'https://rpc.snapshot.org';
362
- const DEFAULT_TIMEOUT = 25000;
363
- function getProvider(network, { broviderUrl = DEFAULT_BROVIDER_URL, timeout = DEFAULT_TIMEOUT } = {}) {
364
- const url = `${broviderUrl}/${network}`;
365
- if (!providers[network])
366
- providers[network] = new providers$1.StaticJsonRpcProvider({
367
- url,
368
- timeout,
369
- allowGzip: true
370
- }, Number(network));
371
- return providers[network];
372
- }
373
-
374
- function signMessage(web3, msg, address) {
375
- return __awaiter(this, void 0, void 0, function* () {
376
- msg = bytes.hexlify(new Buffer(msg, 'utf8'));
377
- return yield web3.send('personal_sign', [msg, address]);
378
- });
379
- }
380
- function getBlockNumber(provider) {
381
- return __awaiter(this, void 0, void 0, function* () {
382
- try {
383
- const blockNumber = yield provider.getBlockNumber();
384
- return parseInt(blockNumber);
385
- }
386
- catch (e) {
387
- return Promise.reject();
388
- }
389
- });
390
- }
391
-
392
- const RPC_URLS = {
393
- SN_MAIN: 'https://starknet-mainnet.public.blastapi.io',
394
- SN_SEPOLIA: 'https://starknet-sepolia.public.blastapi.io'
395
- };
396
- const ABI = [
397
- {
398
- name: 'argent::common::account::IAccount',
399
- type: 'interface',
400
- items: [
401
- {
402
- name: 'is_valid_signature',
403
- type: 'function',
404
- inputs: [
405
- {
406
- name: 'hash',
407
- type: 'core::felt252'
408
- },
409
- {
410
- name: 'signature',
411
- type: 'core::array::Array::<core::felt252>'
412
- }
413
- ],
414
- outputs: [
415
- {
416
- type: 'core::felt252'
417
- }
418
- ],
419
- state_mutability: 'view'
420
- }
421
- ]
422
- }
423
- ];
424
- function getProvider$1(network, options) {
425
- var _a;
426
- if (!RPC_URLS[network])
427
- throw new Error('Invalid network');
428
- return new starknet$1.RpcProvider({
429
- nodeUrl: (_a = options === null || options === void 0 ? void 0 : options.broviderUrl) !== null && _a !== void 0 ? _a : RPC_URLS[network]
430
- });
431
- }
432
- function isStarknetMessage(data) {
433
- return !!data.primaryType && !!data.types.StarkNetDomain;
434
- }
435
- function getHash(data, address) {
436
- const { domain, types, primaryType, message } = data;
437
- return starknet$1.typedData.getMessageHash({ types, primaryType, domain, message }, address);
438
- }
439
- function verify(address_1, sig_1, data_1) {
440
- return __awaiter(this, arguments, void 0, function* (address, sig, data, network = 'SN_MAIN', options = {}) {
441
- try {
442
- const contractAccount = new starknet$1.Contract(ABI, address, getProvider$1(network, options));
443
- if (sig.length < 2) {
444
- throw new Error('Invalid signature format');
445
- }
446
- const result = yield contractAccount.is_valid_signature(getHash(data, address), sig.slice(-2));
447
- return bignumber.BigNumber.from(result).eq(bignumber.BigNumber.from('370462705988'));
448
- }
449
- catch (e) {
450
- if (e.message.includes('Contract not found')) {
451
- throw new Error('Contract not deployed');
452
- }
453
- throw e;
454
- }
455
- });
456
- }
457
-
458
- var starknet = /*#__PURE__*/Object.freeze({
459
- __proto__: null,
460
- isStarknetMessage: isStarknetMessage,
461
- getHash: getHash,
462
- 'default': verify
463
- });
464
-
465
- const ERC6492_DETECTION_SUFFIX = '6492649264926492649264926492649264926492649264926492649264926492';
466
- function isEqual(a, b) {
467
- return a.toLowerCase() === b.toLowerCase();
468
- }
469
- function getHash$1(data) {
470
- const { domain, types, message } = data;
471
- return hash._TypedDataEncoder.hash(domain, types, message);
472
- }
473
- function verify$1(address_1, sig_1, data_1) {
474
- return __awaiter(this, arguments, void 0, function* (address, sig, data, network = '1', options = {}) {
475
- const { domain, types, message } = data;
476
- try {
477
- const recoverAddress = wallet.verifyTypedData(domain, types, message, sig);
478
- if (isEqual(address, recoverAddress))
479
- return true;
480
- }
481
- catch (e) { }
482
- const provider = getProvider(network, options);
483
- const hash = getHash$1(data);
484
- // Handle EIP-6492
485
- // https://eips.ethereum.org/EIPS/eip-6492
486
- //
487
- // We can actually replace verifyTypedData and verifyDefault with the following code,
488
- // but https://github.com/AmbireTech/signature-validator/blob/main/contracts/DeploylessUniversalSigValidator.sol
489
- // also can send an extra network request to the provider. (with verifyTypedData we don't send any extra request)
490
- //
491
- if (sig.endsWith(ERC6492_DETECTION_SUFFIX)) {
492
- try {
493
- return ('0x01' ===
494
- (yield provider.call({
495
- data: bytes.concat([
496
- '0x60806040523480156200001157600080fd5b50604051620007003803806200070083398101604081905262000034916200056f565b6000620000438484846200004f565b9050806000526001601ff35b600080846001600160a01b0316803b806020016040519081016040528181526000908060200190933c90507f6492649264926492649264926492649264926492649264926492649264926492620000a68462000451565b036200021f57600060608085806020019051810190620000c79190620005ce565b8651929550909350915060000362000192576000836001600160a01b031683604051620000f5919062000643565b6000604051808303816000865af19150503d806000811462000134576040519150601f19603f3d011682016040523d82523d6000602084013e62000139565b606091505b5050905080620001905760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b505b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90620001c4908b90869060040162000661565b602060405180830381865afa158015620001e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020891906200069d565b6001600160e01b031916149450505050506200044a565b805115620002b157604051630b135d3f60e11b808252906001600160a01b03871690631626ba7e9062000259908890889060040162000661565b602060405180830381865afa15801562000277573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029d91906200069d565b6001600160e01b031916149150506200044a565b8251604114620003195760405162461bcd60e51b815260206004820152603a6024820152600080516020620006e083398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e677468000000000000606482015260840162000187565b620003236200046b565b506020830151604080850151855186939260009185919081106200034b576200034b620006c9565b016020015160f81c9050601b81148015906200036b57508060ff16601c14155b15620003cf5760405162461bcd60e51b815260206004820152603b6024820152600080516020620006e083398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c75650000000000606482015260840162000187565b6040805160008152602081018083528a905260ff83169181019190915260608101849052608081018390526001600160a01b038a169060019060a0016020604051602081039080840390855afa1580156200042e573d6000803e3d6000fd5b505050602060405103516001600160a01b031614955050505050505b9392505050565b60006020825110156200046357600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b03811681146200049f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620004d5578181015183820152602001620004bb565b50506000910152565b600082601f830112620004f057600080fd5b81516001600160401b03808211156200050d576200050d620004a2565b604051601f8301601f19908116603f01168101908282118183101715620005385762000538620004a2565b816040528381528660208588010111156200055257600080fd5b62000565846020830160208901620004b8565b9695505050505050565b6000806000606084860312156200058557600080fd5b8351620005928162000489565b6020850151604086015191945092506001600160401b03811115620005b657600080fd5b620005c486828701620004de565b9150509250925092565b600080600060608486031215620005e457600080fd5b8351620005f18162000489565b60208501519093506001600160401b03808211156200060f57600080fd5b6200061d87838801620004de565b935060408601519150808211156200063457600080fd5b50620005c486828701620004de565b6000825162000657818460208701620004b8565b9190910192915050565b828152604060208201526000825180604084015262000688816060850160208701620004b8565b601f01601f1916919091016060019392505050565b600060208284031215620006b057600080fd5b81516001600160e01b0319811681146200044a57600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572',
497
- new abi.AbiCoder().encode(['address', 'bytes32', 'bytes'], [address, bytes.arrayify(hash), sig])
498
- ])
499
- })));
500
- }
501
- catch (error) {
502
- return false;
503
- }
504
- }
505
- // Handle EIP-1271
506
- if (yield verifyDefault(address, sig, hash, provider))
507
- return true;
508
- return yield verifyOldVersion(address, sig, hash, provider);
509
- });
510
- }
511
- function verifyDefault(address, sig, hash, provider) {
512
- return __awaiter(this, void 0, void 0, function* () {
513
- let returnValue;
514
- const magicValue = '0x1626ba7e';
515
- const abi = 'function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue)';
516
- try {
517
- returnValue = yield call(provider, [abi], [address, 'isValidSignature', [bytes.arrayify(hash), sig]]);
518
- }
519
- catch (e) {
520
- if (e.message.startsWith('missing revert data in call exception')) {
521
- return false;
522
- }
523
- throw e;
524
- }
525
- return isEqual(returnValue, magicValue);
526
- });
527
- }
528
- function verifyOldVersion(address, sig, hash, provider) {
529
- return __awaiter(this, void 0, void 0, function* () {
530
- const magicValue = '0x20c13b0b';
531
- const abi = 'function isValidSignature(bytes _hash, bytes memory _signature) public view returns (bytes4 magicValue)';
532
- const returnValue = yield call(provider, [abi], [address, 'isValidSignature', [bytes.arrayify(hash), sig]]);
533
- return isEqual(returnValue, magicValue);
534
- });
535
- }
536
-
537
- var evm = /*#__PURE__*/Object.freeze({
538
- __proto__: null,
539
- getHash: getHash$1,
540
- 'default': verify$1
541
- });
542
-
543
- function getHash$2(data, address) {
544
- const networkType = isStarknetMessage(data) ? starknet : evm;
545
- return networkType.getHash(data, address);
546
- }
547
- function verify$2(address_1, sig_1, data_1) {
548
- return __awaiter(this, arguments, void 0, function* (address, sig, data, network = '1', options = {}) {
549
- if (!isStarknetAddress(address) && !isEvmAddress(address)) {
550
- throw new Error('Invalid address');
551
- }
552
- const networkType = isStarknetMessage(data) ? starknet : evm;
553
- return yield networkType.default(address, sig, data, network, options);
554
- });
555
- }
556
-
557
- var gateways = [
558
- "ipfs.snapshot.box",
559
- "snapshot.4everland.link",
560
- "ipfs.io",
561
- "ipfs.fleek.co",
562
- "gateway.pinata.cloud",
563
- "dweb.link",
564
- "ipfs.infura.io"
565
- ];
566
-
567
333
  var networks = {
568
334
  "1": {
569
335
  key: "1",
@@ -2593,18 +2359,298 @@ var networks = {
2593
2359
  },
2594
2360
  start: 7521509,
2595
2361
  logo: "ipfs://QmNnGPr1CNvj12SSGzKARtUHv9FyEfE5nES73U4vBWQSJL"
2362
+ },
2363
+ "0x534e5f4d41494e": {
2364
+ key: "sn",
2365
+ name: "Starknet",
2366
+ shortName: "Starknet",
2367
+ chainId: "0x534e5f4d41494e",
2368
+ network: "mainnet",
2369
+ multicall: "0x05754af3760f3356da99aea5c3ec39ccac7783d925a19666ebbeca58ff0087f4",
2370
+ explorer: {
2371
+ url: "https://starkscan.co"
2372
+ },
2373
+ rpc: [
2374
+ ],
2375
+ start: 8446,
2376
+ logo: "ipfs://bafkreihbjafyh7eud7r6e5743esaamifcttsvbspfwcrfoc5ykodjdi67m"
2377
+ },
2378
+ "0x534e5f5345504f4c4941": {
2379
+ key: "sn-sep",
2380
+ name: "Starknet Testnet",
2381
+ shortName: "testnet",
2382
+ chainId: "0x534e5f5345504f4c4941",
2383
+ network: "testnet",
2384
+ testnet: true,
2385
+ multicall: "0x05754af3760f3356da99aea5c3ec39ccac7783d925a19666ebbeca58ff0087f4",
2386
+ explorer: {
2387
+ url: "https://sepolia.starkscan.co"
2388
+ },
2389
+ rpc: [
2390
+ ],
2391
+ start: 7,
2392
+ logo: "ipfs://bafkreihbjafyh7eud7r6e5743esaamifcttsvbspfwcrfoc5ykodjdi67m"
2596
2393
  }
2597
2394
  };
2598
2395
 
2599
- class SingleChoiceVoting {
2600
- constructor(proposal, votes, strategies, selected) {
2601
- this.proposal = proposal;
2602
- this.votes = votes;
2603
- this.strategies = strategies;
2604
- this.selected = selected;
2396
+ const DEFAULT_BROVIDER_URL = 'https://rpc.snapshot.org';
2397
+ const DEFAULT_TIMEOUT = 25000;
2398
+ const STARKNET_BROVIDER_KEYS = ['sn', 'sn-sep'];
2399
+ const providerMemo = new Map();
2400
+ const providerFnMap = {
2401
+ evm: getEvmProvider,
2402
+ starknet: getStarknetProvider
2403
+ };
2404
+ function normalizeOptions(options = {}) {
2405
+ var _a;
2406
+ return {
2407
+ broviderUrl: options.broviderUrl || DEFAULT_BROVIDER_URL,
2408
+ timeout: (_a = options.timeout) !== null && _a !== void 0 ? _a : DEFAULT_TIMEOUT
2409
+ };
2410
+ }
2411
+ function getBroviderNetworkId(network) {
2412
+ const config = networks[network];
2413
+ if (!config) {
2414
+ throw new Error(`Network '${network}' is not supported`);
2605
2415
  }
2606
- static isValidChoice(voteChoice, proposalChoices) {
2607
- return (typeof voteChoice === 'number' &&
2416
+ return String(config.key);
2417
+ }
2418
+ function getProviderType(networkId) {
2419
+ const isStarknet = STARKNET_BROVIDER_KEYS.includes(networkId);
2420
+ return isStarknet ? 'starknet' : 'evm';
2421
+ }
2422
+ function createMemoKey(networkId, options) {
2423
+ return `${networkId}:${options.broviderUrl}:${options.timeout}`;
2424
+ }
2425
+ // return loose `any` type to avoid typecheck issues on package consumers
2426
+ function getProvider(network, options = {}) {
2427
+ const networkId = getBroviderNetworkId(network);
2428
+ const normalizedOptions = normalizeOptions(options);
2429
+ const memoKey = createMemoKey(networkId, normalizedOptions);
2430
+ const memoized = providerMemo.get(memoKey);
2431
+ if (memoized) {
2432
+ return memoized;
2433
+ }
2434
+ const providerType = getProviderType(networkId);
2435
+ const provider = providerFnMap[providerType](networkId, normalizedOptions);
2436
+ providerMemo.set(memoKey, provider);
2437
+ return provider;
2438
+ }
2439
+ function getEvmProvider(networkId, options) {
2440
+ return new providers.StaticJsonRpcProvider({
2441
+ url: `${options.broviderUrl}/${networkId}`,
2442
+ timeout: options.timeout,
2443
+ allowGzip: true
2444
+ }, Number(networkId));
2445
+ }
2446
+ function getStarknetProvider(networkKey, options) {
2447
+ return new starknet$1.RpcProvider({
2448
+ nodeUrl: `${options.broviderUrl}/${networkKey}`
2449
+ });
2450
+ }
2451
+
2452
+ function signMessage(web3, msg, address) {
2453
+ return __awaiter(this, void 0, void 0, function* () {
2454
+ msg = bytes.hexlify(new Buffer(msg, 'utf8'));
2455
+ return yield web3.send('personal_sign', [msg, address]);
2456
+ });
2457
+ }
2458
+ function getBlockNumber(provider) {
2459
+ return __awaiter(this, void 0, void 0, function* () {
2460
+ try {
2461
+ const blockNumber = yield provider.getBlockNumber();
2462
+ return parseInt(blockNumber);
2463
+ }
2464
+ catch (e) {
2465
+ return Promise.reject();
2466
+ }
2467
+ });
2468
+ }
2469
+
2470
+ const RPC_URLS = {
2471
+ SN_MAIN: 'https://starknet-mainnet.public.blastapi.io',
2472
+ SN_SEPOLIA: 'https://starknet-sepolia.public.blastapi.io'
2473
+ };
2474
+ const ABI = [
2475
+ {
2476
+ name: 'argent::common::account::IAccount',
2477
+ type: 'interface',
2478
+ items: [
2479
+ {
2480
+ name: 'is_valid_signature',
2481
+ type: 'function',
2482
+ inputs: [
2483
+ {
2484
+ name: 'hash',
2485
+ type: 'core::felt252'
2486
+ },
2487
+ {
2488
+ name: 'signature',
2489
+ type: 'core::array::Array::<core::felt252>'
2490
+ }
2491
+ ],
2492
+ outputs: [
2493
+ {
2494
+ type: 'core::felt252'
2495
+ }
2496
+ ],
2497
+ state_mutability: 'view'
2498
+ }
2499
+ ]
2500
+ }
2501
+ ];
2502
+ function getProvider$1(network, options) {
2503
+ var _a;
2504
+ if (!RPC_URLS[network])
2505
+ throw new Error('Invalid network');
2506
+ return new starknet$1.RpcProvider({
2507
+ nodeUrl: (_a = options === null || options === void 0 ? void 0 : options.broviderUrl) !== null && _a !== void 0 ? _a : RPC_URLS[network]
2508
+ });
2509
+ }
2510
+ function isStarknetMessage(data) {
2511
+ return !!data.primaryType && !!data.types.StarkNetDomain;
2512
+ }
2513
+ function getHash(data, address) {
2514
+ const { domain, types, primaryType, message } = data;
2515
+ return starknet$1.typedData.getMessageHash({ types, primaryType, domain, message }, address);
2516
+ }
2517
+ function verify(address_1, sig_1, data_1) {
2518
+ return __awaiter(this, arguments, void 0, function* (address, sig, data, network = 'SN_MAIN', options = {}) {
2519
+ try {
2520
+ const contractAccount = new starknet$1.Contract(ABI, address, getProvider$1(network, options));
2521
+ if (sig.length < 2) {
2522
+ throw new Error('Invalid signature format');
2523
+ }
2524
+ const result = yield contractAccount.is_valid_signature(getHash(data, address), sig.slice(-2));
2525
+ return bignumber.BigNumber.from(result).eq(bignumber.BigNumber.from('370462705988'));
2526
+ }
2527
+ catch (e) {
2528
+ if (e.message.includes('Contract not found')) {
2529
+ throw new Error('Contract not deployed');
2530
+ }
2531
+ throw e;
2532
+ }
2533
+ });
2534
+ }
2535
+
2536
+ var starknet = /*#__PURE__*/Object.freeze({
2537
+ __proto__: null,
2538
+ isStarknetMessage: isStarknetMessage,
2539
+ getHash: getHash,
2540
+ 'default': verify
2541
+ });
2542
+
2543
+ const ERC6492_DETECTION_SUFFIX = '6492649264926492649264926492649264926492649264926492649264926492';
2544
+ function isEqual(a, b) {
2545
+ return a.toLowerCase() === b.toLowerCase();
2546
+ }
2547
+ function getHash$1(data) {
2548
+ const { domain, types, message } = data;
2549
+ return hash._TypedDataEncoder.hash(domain, types, message);
2550
+ }
2551
+ function verify$1(address_1, sig_1, data_1) {
2552
+ return __awaiter(this, arguments, void 0, function* (address, sig, data, network = '1', options = {}) {
2553
+ const { domain, types, message } = data;
2554
+ try {
2555
+ const recoverAddress = wallet.verifyTypedData(domain, types, message, sig);
2556
+ if (isEqual(address, recoverAddress))
2557
+ return true;
2558
+ }
2559
+ catch (e) { }
2560
+ const provider = getProvider(network, options);
2561
+ const hash = getHash$1(data);
2562
+ // Handle EIP-6492
2563
+ // https://eips.ethereum.org/EIPS/eip-6492
2564
+ //
2565
+ // We can actually replace verifyTypedData and verifyDefault with the following code,
2566
+ // but https://github.com/AmbireTech/signature-validator/blob/main/contracts/DeploylessUniversalSigValidator.sol
2567
+ // also can send an extra network request to the provider. (with verifyTypedData we don't send any extra request)
2568
+ //
2569
+ if (sig.endsWith(ERC6492_DETECTION_SUFFIX)) {
2570
+ try {
2571
+ return ('0x01' ===
2572
+ (yield provider.call({
2573
+ data: bytes.concat([
2574
+ '0x60806040523480156200001157600080fd5b50604051620007003803806200070083398101604081905262000034916200056f565b6000620000438484846200004f565b9050806000526001601ff35b600080846001600160a01b0316803b806020016040519081016040528181526000908060200190933c90507f6492649264926492649264926492649264926492649264926492649264926492620000a68462000451565b036200021f57600060608085806020019051810190620000c79190620005ce565b8651929550909350915060000362000192576000836001600160a01b031683604051620000f5919062000643565b6000604051808303816000865af19150503d806000811462000134576040519150601f19603f3d011682016040523d82523d6000602084013e62000139565b606091505b5050905080620001905760405162461bcd60e51b815260206004820152601e60248201527f5369676e617475726556616c696461746f723a206465706c6f796d656e74000060448201526064015b60405180910390fd5b505b604051630b135d3f60e11b808252906001600160a01b038a1690631626ba7e90620001c4908b90869060040162000661565b602060405180830381865afa158015620001e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200020891906200069d565b6001600160e01b031916149450505050506200044a565b805115620002b157604051630b135d3f60e11b808252906001600160a01b03871690631626ba7e9062000259908890889060040162000661565b602060405180830381865afa15801562000277573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200029d91906200069d565b6001600160e01b031916149150506200044a565b8251604114620003195760405162461bcd60e51b815260206004820152603a6024820152600080516020620006e083398151915260448201527f3a20696e76616c6964207369676e6174757265206c656e677468000000000000606482015260840162000187565b620003236200046b565b506020830151604080850151855186939260009185919081106200034b576200034b620006c9565b016020015160f81c9050601b81148015906200036b57508060ff16601c14155b15620003cf5760405162461bcd60e51b815260206004820152603b6024820152600080516020620006e083398151915260448201527f3a20696e76616c6964207369676e617475726520762076616c75650000000000606482015260840162000187565b6040805160008152602081018083528a905260ff83169181019190915260608101849052608081018390526001600160a01b038a169060019060a0016020604051602081039080840390855afa1580156200042e573d6000803e3d6000fd5b505050602060405103516001600160a01b031614955050505050505b9392505050565b60006020825110156200046357600080fd5b508051015190565b60405180606001604052806003906020820280368337509192915050565b6001600160a01b03811681146200049f57600080fd5b50565b634e487b7160e01b600052604160045260246000fd5b60005b83811015620004d5578181015183820152602001620004bb565b50506000910152565b600082601f830112620004f057600080fd5b81516001600160401b03808211156200050d576200050d620004a2565b604051601f8301601f19908116603f01168101908282118183101715620005385762000538620004a2565b816040528381528660208588010111156200055257600080fd5b62000565846020830160208901620004b8565b9695505050505050565b6000806000606084860312156200058557600080fd5b8351620005928162000489565b6020850151604086015191945092506001600160401b03811115620005b657600080fd5b620005c486828701620004de565b9150509250925092565b600080600060608486031215620005e457600080fd5b8351620005f18162000489565b60208501519093506001600160401b03808211156200060f57600080fd5b6200061d87838801620004de565b935060408601519150808211156200063457600080fd5b50620005c486828701620004de565b6000825162000657818460208701620004b8565b9190910192915050565b828152604060208201526000825180604084015262000688816060850160208701620004b8565b601f01601f1916919091016060019392505050565b600060208284031215620006b057600080fd5b81516001600160e01b0319811681146200044a57600080fd5b634e487b7160e01b600052603260045260246000fdfe5369676e617475726556616c696461746f72237265636f7665725369676e6572',
2575
+ new abi.AbiCoder().encode(['address', 'bytes32', 'bytes'], [address, bytes.arrayify(hash), sig])
2576
+ ])
2577
+ })));
2578
+ }
2579
+ catch (error) {
2580
+ return false;
2581
+ }
2582
+ }
2583
+ // Handle EIP-1271
2584
+ if (yield verifyDefault(address, sig, hash, provider))
2585
+ return true;
2586
+ return yield verifyOldVersion(address, sig, hash, provider);
2587
+ });
2588
+ }
2589
+ function verifyDefault(address, sig, hash, provider) {
2590
+ return __awaiter(this, void 0, void 0, function* () {
2591
+ let returnValue;
2592
+ const magicValue = '0x1626ba7e';
2593
+ const abi = 'function isValidSignature(bytes32 _hash, bytes memory _signature) public view returns (bytes4 magicValue)';
2594
+ try {
2595
+ returnValue = yield call(provider, [abi], [address, 'isValidSignature', [bytes.arrayify(hash), sig]]);
2596
+ }
2597
+ catch (e) {
2598
+ if (e.message.startsWith('missing revert data in call exception')) {
2599
+ return false;
2600
+ }
2601
+ throw e;
2602
+ }
2603
+ return isEqual(returnValue, magicValue);
2604
+ });
2605
+ }
2606
+ function verifyOldVersion(address, sig, hash, provider) {
2607
+ return __awaiter(this, void 0, void 0, function* () {
2608
+ const magicValue = '0x20c13b0b';
2609
+ const abi = 'function isValidSignature(bytes _hash, bytes memory _signature) public view returns (bytes4 magicValue)';
2610
+ const returnValue = yield call(provider, [abi], [address, 'isValidSignature', [bytes.arrayify(hash), sig]]);
2611
+ return isEqual(returnValue, magicValue);
2612
+ });
2613
+ }
2614
+
2615
+ var evm = /*#__PURE__*/Object.freeze({
2616
+ __proto__: null,
2617
+ getHash: getHash$1,
2618
+ 'default': verify$1
2619
+ });
2620
+
2621
+ function getHash$2(data, address) {
2622
+ const networkType = isStarknetMessage(data) ? starknet : evm;
2623
+ return networkType.getHash(data, address);
2624
+ }
2625
+ function verify$2(address_1, sig_1, data_1) {
2626
+ return __awaiter(this, arguments, void 0, function* (address, sig, data, network = '1', options = {}) {
2627
+ if (!isStarknetAddress(address) && !isEvmAddress(address)) {
2628
+ throw new Error('Invalid address');
2629
+ }
2630
+ const networkType = isStarknetMessage(data) ? starknet : evm;
2631
+ return yield networkType.default(address, sig, data, network, options);
2632
+ });
2633
+ }
2634
+
2635
+ var gateways = [
2636
+ "ipfs.snapshot.box",
2637
+ "snapshot.4everland.link",
2638
+ "ipfs.io",
2639
+ "ipfs.fleek.co",
2640
+ "gateway.pinata.cloud",
2641
+ "dweb.link",
2642
+ "ipfs.infura.io"
2643
+ ];
2644
+
2645
+ class SingleChoiceVoting {
2646
+ constructor(proposal, votes, strategies, selected) {
2647
+ this.proposal = proposal;
2648
+ this.votes = votes;
2649
+ this.strategies = strategies;
2650
+ this.selected = selected;
2651
+ }
2652
+ static isValidChoice(voteChoice, proposalChoices) {
2653
+ return (typeof voteChoice === 'number' &&
2608
2654
  (proposalChoices === null || proposalChoices === void 0 ? void 0 : proposalChoices[voteChoice - 1]) !== undefined);
2609
2655
  }
2610
2656
  getValidVotes() {
@@ -3193,6 +3239,209 @@ function fetchData(_a) {
3193
3239
  });
3194
3240
  }
3195
3241
 
3242
+ const multicallAbi = [
3243
+ 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)'
3244
+ ];
3245
+ function multicall(address_1, provider_1, abi_1, calls_1, limit_1) {
3246
+ return __awaiter(this, arguments, void 0, function* (address, provider, abi$1, calls, limit, options = {}) {
3247
+ const multi = new contracts.Contract(address, multicallAbi, provider);
3248
+ const itf = new abi.Interface(abi$1);
3249
+ try {
3250
+ const pages = Math.ceil(calls.length / limit);
3251
+ const promises = [];
3252
+ Array.from(Array(pages)).forEach((x, i) => {
3253
+ const callsInPage = calls.slice(limit * i, limit * (i + 1));
3254
+ promises.push(multi.aggregate(callsInPage.map((call) => [
3255
+ call[0].toLowerCase(),
3256
+ itf.encodeFunctionData(call[1], call[2])
3257
+ ]), options));
3258
+ });
3259
+ let results = yield Promise.all(promises);
3260
+ results = results.reduce((prev, [, res]) => prev.concat(res), []);
3261
+ return results.map((call, i) => itf.decodeFunctionResult(calls[i][1], call));
3262
+ }
3263
+ catch (e) {
3264
+ return Promise.reject(e);
3265
+ }
3266
+ });
3267
+ }
3268
+
3269
+ /**
3270
+ * Parses the raw result from a Starknet function call based on its ABI.
3271
+ * It handles different types like felt252, u8, u256, etc., and decodes them accordingly.
3272
+ * @param rawResult - The raw result from the Starknet function call.
3273
+ * @param functionAbi - The ABI of the function that was called.
3274
+ * @returns The parsed result in a more usable format.
3275
+ */
3276
+ function parseStarknetResult(rawResult, functionAbi) {
3277
+ if (!functionAbi ||
3278
+ !functionAbi.outputs ||
3279
+ !Array.isArray(rawResult) ||
3280
+ rawResult.length === 0) {
3281
+ return rawResult;
3282
+ }
3283
+ const output = functionAbi.outputs[0];
3284
+ const rawValue = rawResult[0];
3285
+ try {
3286
+ switch (output.type) {
3287
+ case 'core::felt252':
3288
+ // Try to decode as shortString (for name, symbol)
3289
+ try {
3290
+ return starknet$1.shortString.decodeShortString(rawValue);
3291
+ }
3292
+ catch (_a) {
3293
+ // If shortString decode fails, return as hex
3294
+ return rawValue;
3295
+ }
3296
+ // Unsigned integers
3297
+ case 'core::integer::u8':
3298
+ case 'core::integer::u16':
3299
+ case 'core::integer::u32':
3300
+ case 'core::integer::u64':
3301
+ return parseInt(rawValue, 16);
3302
+ case 'core::integer::u128':
3303
+ case 'core::integer::usize':
3304
+ return BigInt(rawValue).toString();
3305
+ case 'core::integer::u256':
3306
+ return starknet$1.uint256.uint256ToBN({
3307
+ low: rawValue,
3308
+ high: rawResult[1] || '0x0'
3309
+ });
3310
+ // Signed integers
3311
+ case 'core::integer::i8':
3312
+ case 'core::integer::i16':
3313
+ case 'core::integer::i32':
3314
+ case 'core::integer::i64':
3315
+ return parseInt(rawValue, 16);
3316
+ case 'core::integer::i128':
3317
+ return BigInt(rawValue).toString();
3318
+ // Boolean type
3319
+ case 'core::bool':
3320
+ return rawValue === '0x1' || rawValue === '0x01';
3321
+ // Address types
3322
+ case 'core::starknet::contract_address::ContractAddress':
3323
+ case 'core::starknet::class_hash::ClassHash':
3324
+ case 'core::starknet::storage_access::StorageAddress':
3325
+ return rawValue;
3326
+ // Byte array
3327
+ case 'core::bytes_31::bytes31':
3328
+ return rawValue;
3329
+ default:
3330
+ // Return raw value for unknown types
3331
+ return rawValue;
3332
+ }
3333
+ }
3334
+ catch (_b) {
3335
+ // Fallback to raw result if parsing fails
3336
+ return rawResult;
3337
+ }
3338
+ }
3339
+ /**
3340
+ * Partitions the responses from a Starknet multicall into individual call results.
3341
+ * Each response starts with its length, followed by the actual response data.
3342
+ * @param responses - The array of responses from the Starknet multicall.
3343
+ * @returns An array of arrays, where each inner array contains the response data for a single call.
3344
+ */
3345
+ const partitionResponses = (responses) => {
3346
+ if (responses.length === 0) {
3347
+ return [];
3348
+ }
3349
+ const [responseLength, ...restResponses] = responses;
3350
+ const responseLengthInt = Number(starknet$1.num.toBigInt(responseLength));
3351
+ const response = restResponses.slice(0, responseLengthInt);
3352
+ const remainingResponses = restResponses.slice(responseLengthInt);
3353
+ return [response, ...partitionResponses(remainingResponses)];
3354
+ };
3355
+ function multicall$1(address_1, provider_1, abi_1, calls_1, limit_1) {
3356
+ return __awaiter(this, arguments, void 0, function* (address, provider, abi, calls, limit, options = {}) {
3357
+ const callData = calls.map((call) => {
3358
+ return {
3359
+ contractAddress: call[0],
3360
+ entrypoint: call[1],
3361
+ calldata: call[2] || []
3362
+ };
3363
+ });
3364
+ // Chunk calls into batches based on limit
3365
+ const chunks = [];
3366
+ for (let i = 0; i < callData.length; i += limit) {
3367
+ chunks.push(callData.slice(i, i + limit));
3368
+ }
3369
+ // Process each chunk
3370
+ const paginatedResults = yield Promise.all(chunks.map((chunk) => {
3371
+ var _a;
3372
+ return provider.callContract({
3373
+ contractAddress: address,
3374
+ entrypoint: 'aggregate',
3375
+ calldata: starknet$1.transaction.fromCallsToExecuteCalldata(chunk)
3376
+ }, (_a = options.blockTag) !== null && _a !== void 0 ? _a : 'latest');
3377
+ }));
3378
+ const callResults = paginatedResults
3379
+ .map((callContractResult) => {
3380
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3381
+ const [_blockNumber, _totalLength, ...results] = callContractResult;
3382
+ return partitionResponses(results);
3383
+ })
3384
+ .flat();
3385
+ return callResults.map((result, index) => {
3386
+ const [, functionName] = calls[index];
3387
+ const functionAbi = abi.find((item) => item.name === functionName);
3388
+ return [parseStarknetResult(result, functionAbi)];
3389
+ });
3390
+ });
3391
+ }
3392
+
3393
+ class Multicaller {
3394
+ constructor(network, provider, abi, options = {}) {
3395
+ this.options = {};
3396
+ this.calls = [];
3397
+ this.paths = [];
3398
+ this.network = network;
3399
+ this.provider = provider;
3400
+ this.abi = abi;
3401
+ this.options = options;
3402
+ }
3403
+ call(path, address, fn, params) {
3404
+ this.calls.push([address, fn, params]);
3405
+ this.paths.push(path);
3406
+ return this;
3407
+ }
3408
+ execute(from) {
3409
+ return __awaiter(this, void 0, void 0, function* () {
3410
+ const obj = from || {};
3411
+ const result = yield multicall$2(this.network, this.provider, this.abi, this.calls, this.options);
3412
+ result.forEach((r, i) => set__default['default'](obj, this.paths[i], r.length > 1 ? r : r[0]));
3413
+ this.calls = [];
3414
+ this.paths = [];
3415
+ return obj;
3416
+ });
3417
+ }
3418
+ }
3419
+
3420
+ const STARKNET_CHAIN_IDS = [
3421
+ starknet$1.constants.StarknetChainId.SN_MAIN,
3422
+ starknet$1.constants.StarknetChainId.SN_SEPOLIA
3423
+ ];
3424
+ const MULTICALLS_FN = {
3425
+ evm: multicall,
3426
+ starknet: multicall$1
3427
+ };
3428
+ function multicall$2(network_1, provider_1, abi_1, calls_1) {
3429
+ return __awaiter(this, arguments, void 0, function* (network, provider, abi, calls, options = {}) {
3430
+ const address = (options === null || options === void 0 ? void 0 : options.multicallAddress) || networks[network].multicall;
3431
+ if (!address) {
3432
+ throw new Error('missing multicall address');
3433
+ }
3434
+ const multicallOptions = Object.assign({}, options);
3435
+ const limit = (multicallOptions === null || multicallOptions === void 0 ? void 0 : multicallOptions.limit) || 500;
3436
+ delete multicallOptions.limit;
3437
+ delete multicallOptions.multicallAddress;
3438
+ const protocol = STARKNET_CHAIN_IDS.includes(network)
3439
+ ? 'starknet'
3440
+ : 'evm';
3441
+ return MULTICALLS_FN[protocol](address, provider, abi, calls, limit, multicallOptions);
3442
+ });
3443
+ }
3444
+
3196
3445
  const MUTED_ERRORS = [
3197
3446
  // mute error from coinbase, when the subdomain is not found
3198
3447
  // most other resolvers just return an empty address
@@ -3206,16 +3455,6 @@ const ENS_ABI = [
3206
3455
  'function resolver(bytes32 node) view returns (address)' // ENS registry ABI
3207
3456
  ];
3208
3457
  const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000';
3209
- const STARKNET_NETWORKS = {
3210
- '0x534e5f4d41494e': {
3211
- name: 'Starknet',
3212
- testnet: false
3213
- },
3214
- '0x534e5f5345504f4c4941': {
3215
- name: 'Starknet Sepolia',
3216
- testnet: true
3217
- }
3218
- };
3219
3458
  const scoreApiHeaders = {
3220
3459
  Accept: 'application/json',
3221
3460
  'Content-Type': 'application/json'
@@ -3339,22 +3578,6 @@ ajv.addKeyword({
3339
3578
  message: 'network not allowed'
3340
3579
  }
3341
3580
  });
3342
- ajv.addKeyword({
3343
- keyword: 'starknetNetwork',
3344
- validate: function (schema, data) {
3345
- // @ts-ignore
3346
- const snapshotEnv = this.snapshotEnv || 'default';
3347
- if (snapshotEnv === 'mainnet') {
3348
- return Object.keys(STARKNET_NETWORKS)
3349
- .filter((id) => !STARKNET_NETWORKS[id].testnet)
3350
- .includes(data);
3351
- }
3352
- return Object.keys(STARKNET_NETWORKS).includes(data);
3353
- },
3354
- error: {
3355
- message: 'network not allowed'
3356
- }
3357
- });
3358
3581
  // Custom URL format to allow empty string values
3359
3582
  // https://github.com/snapshot-labs/snapshot.js/pull/541/files
3360
3583
  ajv.addFormat('customUrl', {
@@ -3423,36 +3646,6 @@ function call(provider, abi, call, options) {
3423
3646
  }
3424
3647
  });
3425
3648
  }
3426
- function multicall(network, provider, abi$1, calls, options) {
3427
- return __awaiter(this, void 0, void 0, function* () {
3428
- const multicallAbi = [
3429
- 'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)'
3430
- ];
3431
- const multicallAddress = (options === null || options === void 0 ? void 0 : options.multicallAddress) || networks[network].multicall;
3432
- const multi = new contracts.Contract(multicallAddress, multicallAbi, provider);
3433
- const itf = new abi.Interface(abi$1);
3434
- try {
3435
- const max = (options === null || options === void 0 ? void 0 : options.limit) || 500;
3436
- if (options === null || options === void 0 ? void 0 : options.limit)
3437
- delete options.limit;
3438
- const pages = Math.ceil(calls.length / max);
3439
- const promises = [];
3440
- Array.from(Array(pages)).forEach((x, i) => {
3441
- const callsInPage = calls.slice(max * i, max * (i + 1));
3442
- promises.push(multi.aggregate(callsInPage.map((call) => [
3443
- call[0].toLowerCase(),
3444
- itf.encodeFunctionData(call[1], call[2])
3445
- ]), options || {}));
3446
- });
3447
- let results = yield Promise.all(promises);
3448
- results = results.reduce((prev, [, res]) => prev.concat(res), []);
3449
- return results.map((call, i) => itf.decodeFunctionResult(calls[i][1], call));
3450
- }
3451
- catch (e) {
3452
- return Promise.reject(e);
3453
- }
3454
- });
3455
- }
3456
3649
  function subgraphRequest(url_1, query_1) {
3457
3650
  return __awaiter(this, arguments, void 0, function* (url, query, options = {}) {
3458
3651
  const body = { query: jsonToGraphqlQuery.jsonToGraphQLQuery({ query }) };
@@ -3684,7 +3877,7 @@ function getEnsTextRecord(ens_1, record_1) {
3684
3877
  [ensHash, record]
3685
3878
  ]) // Query for text record from each resolver
3686
3879
  ];
3687
- const [[resolverAddress], ...textRecords] = yield multicall(network, provider, ENS_ABI, calls, multicallOptions);
3880
+ const [[resolverAddress], ...textRecords] = (yield multicall$2(network, provider, ENS_ABI, calls, multicallOptions));
3688
3881
  const resolverIndex = ensResolvers.indexOf(resolverAddress);
3689
3882
  return resolverIndex !== -1 ? (_b = textRecords[resolverIndex]) === null || _b === void 0 ? void 0 : _b[0] : null;
3690
3883
  });
@@ -3832,21 +4025,22 @@ function isEvmAddress(address$1) {
3832
4025
  return address.isAddress(address$1);
3833
4026
  }
3834
4027
  function getFormattedAddress(address$1, format) {
3835
- // Consider non-evm addresses as Starknet by default
3836
- // as there's no other way to differentiate them
3837
- const addressType = format !== null && format !== void 0 ? format : (isEvmAddress(address$1) ? 'evm' : 'starknet');
4028
+ if (typeof address$1 !== 'string' || !/^0[xX]/.test(address$1)) {
4029
+ throw new Error(`Invalid address: ${address$1}`);
4030
+ }
4031
+ const addressType = format !== null && format !== void 0 ? format : (address$1.length === 42 ? 'evm' : 'starknet');
3838
4032
  if (addressType === 'evm' && isEvmAddress(address$1))
3839
4033
  return address.getAddress(address$1);
3840
4034
  if (addressType === 'starknet' && isStarknetAddress(address$1))
3841
4035
  return starknet$1.validateAndParseAddress(address$1);
3842
- throw new Error(`Invalid address: ${address$1}`);
4036
+ throw new Error(`Invalid ${addressType} address: ${address$1}`);
3843
4037
  }
3844
4038
  function inputError(message) {
3845
4039
  return Promise.reject(new Error(message));
3846
4040
  }
3847
4041
  var utils = {
3848
4042
  call,
3849
- multicall,
4043
+ multicall: multicall$2,
3850
4044
  subgraphRequest,
3851
4045
  ipfsGet,
3852
4046
  getUrl,
@@ -4136,8 +4330,7 @@ var definitions = {
4136
4330
  type: "string",
4137
4331
  snapshotNetwork: true,
4138
4332
  title: "network",
4139
- minLength: 1,
4140
- maxLength: 32
4333
+ minLength: 1
4141
4334
  },
4142
4335
  symbol: {
4143
4336
  type: "string",
@@ -4180,7 +4373,6 @@ var definitions = {
4180
4373
  },
4181
4374
  network: {
4182
4375
  type: "string",
4183
- maxLength: 12,
4184
4376
  title: "network",
4185
4377
  snapshotNetwork: true
4186
4378
  },
@@ -4379,15 +4571,7 @@ var definitions = {
4379
4571
  type: "string",
4380
4572
  title: "Delegation network",
4381
4573
  description: "The network of your delegation contract",
4382
- anyOf: [
4383
- {
4384
- snapshotNetwork: true
4385
- },
4386
- {
4387
- starknetNetwork: true
4388
- }
4389
- ],
4390
- errorMessage: "Must be a valid network"
4574
+ snapshotNetwork: true
4391
4575
  },
4392
4576
  delegationApi: {
4393
4577
  type: "string",
@@ -4529,15 +4713,7 @@ var definitions = {
4529
4713
  network: {
4530
4714
  type: "string",
4531
4715
  title: "Network",
4532
- anyOf: [
4533
- {
4534
- snapshotNetwork: true
4535
- },
4536
- {
4537
- starknetNetwork: true
4538
- }
4539
- ],
4540
- errorMessage: "Must be a valid network"
4716
+ snapshotNetwork: true
4541
4717
  }
4542
4718
  },
4543
4719
  required: [