@sparkdotfi/abi-cli 0.2.0-20251031.00360a84 → 0.2.0-20260317.e49bd3f1

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.
@@ -26,12 +26,22 @@ export class AbiFetcherClient {
26
26
  return result.abi;
27
27
  }
28
28
  }
29
- async function loadAbiUsingWhatsAbi(args) {
30
- const { address, domain, client, etherscanApiKey } = args;
31
- const loader = new whatsabi.loaders.EtherscanV2ABILoader({
29
+ function createAbiLoader(domain, etherscanApiKey) {
30
+ // Etherscan v2 API's contract/getabi module is broken for Gnosis (returns "Unknown Exception"),
31
+ // so we use Blockscout directly for Gnosis.
32
+ if (domain === 'gnosis') {
33
+ return new whatsabi.loaders.BlockscoutABILoader({
34
+ baseURL: 'https://gnosis.blockscout.com/api',
35
+ });
36
+ }
37
+ return new whatsabi.loaders.EtherscanV2ABILoader({
32
38
  apiKey: etherscanApiKey,
33
39
  chainId: domainToChainId[domain],
34
40
  });
41
+ }
42
+ async function loadAbiUsingWhatsAbi(args) {
43
+ const { address, domain, client, etherscanApiKey } = args;
44
+ const loader = createAbiLoader(domain, etherscanApiKey);
35
45
  const data = await lazyPipe(() => whatsabi.autoload(address, {
36
46
  provider: client,
37
47
  followProxies: true,
@@ -44,7 +54,8 @@ async function loadAbiUsingWhatsAbi(args) {
44
54
  if (data.abi.length === 0) {
45
55
  throw new Error(`Abi not found for ${domain}:${address}`);
46
56
  }
47
- if (!data.abiLoadedFrom || !data.abiLoadedFrom.name.toLowerCase().includes('etherscan')) {
57
+ const loaderName = data.abiLoadedFrom?.name.toLowerCase() ?? '';
58
+ if (!data.abiLoadedFrom || !(loaderName.includes('etherscan') || loaderName.includes('blockscout'))) {
48
59
  throw new Error(`Abi not found for ${domain}:${address}`);
49
60
  }
50
61
  return data;
@@ -12,10 +12,49 @@ export function getAbiForContract(abiRegistry, config, name) {
12
12
  }));
13
13
  assert(instances.length > 0);
14
14
  const rootAbi = instances[0].abi;
15
- const rootAbiStringified = JSON.stringify(rootAbi);
15
+ const rootNormalized = normalizeAbiForComparison(rootAbi);
16
16
  const notMatchingAbi = instances.find(({ abi }) => {
17
- return JSON.stringify(abi) !== rootAbiStringified;
17
+ return normalizeAbiForComparison(abi) !== rootNormalized;
18
18
  });
19
19
  assert(!notMatchingAbi, `Found not matching abis: ${notMatchingAbi?.name}`);
20
20
  return rootAbi;
21
21
  }
22
+ /**
23
+ * Normalizes an ABI for comparison by removing source-specific differences:
24
+ * - Strips `internalType` fields (compiler metadata, not part of ABI spec)
25
+ * - Sorts entries by type + name for consistent ordering
26
+ * Different ABI sources (Etherscan, Blockscout) may return the same ABI with cosmetic differences.
27
+ */
28
+ function normalizeAbiForComparison(abi) {
29
+ const normalized = abi.map((entry) => {
30
+ const clone = structuredClone(entry);
31
+ // Constructors and fallback/receive without stateMutability are implicitly "nonpayable"
32
+ if ((clone.type === 'constructor' || clone.type === 'fallback' || clone.type === 'receive') &&
33
+ !clone.stateMutability) {
34
+ clone.stateMutability = 'nonpayable';
35
+ }
36
+ return normalizeAbiEntry(clone);
37
+ });
38
+ normalized.sort((a, b) => {
39
+ const typeCmp = (a.type ?? '').localeCompare(b.type ?? '');
40
+ if (typeCmp !== 0)
41
+ return typeCmp;
42
+ return (a.name ?? '').localeCompare(b.name ?? '');
43
+ });
44
+ return JSON.stringify(normalized);
45
+ }
46
+ function normalizeAbiEntry(obj) {
47
+ if (Array.isArray(obj)) {
48
+ return obj.map(normalizeAbiEntry);
49
+ }
50
+ if (obj !== null && typeof obj === 'object') {
51
+ const result = {};
52
+ for (const key of Object.keys(obj).sort()) {
53
+ if (key === 'internalType')
54
+ continue;
55
+ result[key] = normalizeAbiEntry(obj[key]);
56
+ }
57
+ return result;
58
+ }
59
+ return obj;
60
+ }
@@ -1,13 +1,12 @@
1
- import { CheckedAddress, getUnsafeChainIdToDomain } from '@sparkdotfi/common-universal';
1
+ import { checkedAddressSchema, getUnsafeChainIdToDomain, } from '@sparkdotfi/common-universal';
2
2
  import { entries, mapKeys } from 'remeda';
3
3
  import { z } from 'zod';
4
- export const CheckedAddressSchema = z.string().transform(CheckedAddress);
5
4
  export const FullAddressSchema = z.object({
6
- address: CheckedAddressSchema,
5
+ address: checkedAddressSchema,
7
6
  skipAbiVerification: z.boolean().default(false),
8
7
  });
9
8
  export const NakedOrFullAddressSchema = z
10
- .union([CheckedAddressSchema, FullAddressSchema])
9
+ .union([checkedAddressSchema, FullAddressSchema])
11
10
  .transform((union) => {
12
11
  if (typeof union === 'string') {
13
12
  return { address: union, skipAbiVerification: false };
@@ -1,8 +1,5 @@
1
1
  import { CheckedAddress, SparkDomain } from '@sparkdotfi/common-universal';
2
2
  import { z } from 'zod';
3
- export declare const CheckedAddressSchema: z.ZodEffects<z.ZodString, `0x${string}` & {
4
- readonly __TAG__: "CheckedAddress";
5
- }, string>;
6
3
  export declare const FullAddressSchema: z.ZodObject<{
7
4
  address: z.ZodEffects<z.ZodString, `0x${string}` & {
8
5
  readonly __TAG__: "CheckedAddress";
@@ -873,10 +870,6 @@ export declare const ManifestSchema: z.ZodObject<{
873
870
  };
874
871
  useCheckedAddress?: boolean | undefined;
875
872
  };
876
- eoa?: Record<string, Record<string, string | {
877
- address: string;
878
- skipAbiVerification?: boolean | undefined;
879
- }>> | undefined;
880
873
  contracts?: Record<string, Record<string, string | {
881
874
  address: string;
882
875
  skipAbiVerification?: boolean | undefined;
@@ -884,6 +877,10 @@ export declare const ManifestSchema: z.ZodObject<{
884
877
  address: string;
885
878
  skipAbiVerification?: boolean | undefined;
886
879
  }>>> | undefined;
880
+ eoa?: Record<string, Record<string, string | {
881
+ address: string;
882
+ skipAbiVerification?: boolean | undefined;
883
+ }>> | undefined;
887
884
  interfaces?: Record<string, {
888
885
  addresses: Record<string, string | {
889
886
  address: string;
@@ -1 +1 @@
1
- {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../src/manifest/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAA4B,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAEpG,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,oBAAoB;;UAAuC,CAAA;AACxE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;EAG5B,CAAA;AACF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;EAQjC,CAAA;AAEJ,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAO9C,CAAA;AAEJ,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAK5C,CAAA;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKxC,CAAA;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAuD,CAAA;AAE9E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAA2D,CAAA;AAEvF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIpC,CAAA;AACF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAkD,CAAA;AAE/E,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYzB,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAA;AACtD,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACvC,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAC5E,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kCAAkC,CAAC,CAAA;AAC/F,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAA;AACzE,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qCAAqC,CAAC,CAAA;AAE5F,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../../src/manifest/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAGd,WAAW,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;EAG5B,CAAA;AACF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;EAQjC,CAAA;AAEJ,eAAO,MAAM,qCAAqC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAO9C,CAAA;AAEJ,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAK5C,CAAA;AAEH,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAKxC,CAAA;AAEH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAuD,CAAA;AAE9E,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAA2D,CAAA;AAEvF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAIpC,CAAA;AACF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAAkD,CAAA;AAE/E,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYzB,CAAA;AAEF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AACxD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAA;AACtD,MAAM,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;AACvC,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,yBAAyB,CAAC,CAAA;AAC5E,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kCAAkC,CAAC,CAAA;AAC/F,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAA;AACzE,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qCAAqC,CAAC,CAAA;AAE5F,MAAM,MAAM,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sparkdotfi/abi-cli",
3
- "version": "0.2.0-20251031.00360a84",
3
+ "version": "0.2.0-20260317.e49bd3f1",
4
4
  "engines": {
5
5
  "node": ">=22.0.0"
6
6
  },
@@ -45,6 +45,6 @@
45
45
  "prettier": "^3.6.2",
46
46
  "remeda": "^2.30.0",
47
47
  "viem": "^2.0.0",
48
- "zod": "^3.0.0"
48
+ "zod": "^3.24.0"
49
49
  }
50
50
  }