@rhinestone/shared-configs 2.0.0 → 2.1.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.
@@ -4,10 +4,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const bun_test_1 = require("bun:test");
7
+ const viem_1 = require("viem");
7
8
  const validation_1 = require("../validation");
8
9
  const index_1 = require("../../src/index");
9
10
  const oft_json_1 = __importDefault(require("../../configs/oft.json"));
10
11
  const nativeToken = { address: "0x0", symbol: "ETH", decimals: 18 };
12
+ const usdcAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
13
+ const validAuthorization = {
14
+ standards: ["erc3009", "erc2612"],
15
+ domain: {
16
+ name: "USD Coin",
17
+ version: "2",
18
+ chainId: 1,
19
+ verifyingContract: usdcAddress,
20
+ },
21
+ domainSeparator: "0x06c37168a7db5138defc7866392bb87a741f9b3d104deb5094588ce041cae335",
22
+ eoaOnly: false,
23
+ };
11
24
  /** A structurally complete entry, so semantic tests don't trip structural checks. */
12
25
  function validChain(overrides = {}) {
13
26
  return {
@@ -26,6 +39,8 @@ function validChain(overrides = {}) {
26
39
  tokens: [{ ...nativeToken, balanceSlot: null, approvalSlot: null }],
27
40
  settlementLayers: ["ACROSS", "ECO", "RELAY"],
28
41
  swapQuoters: ["0x"],
42
+ providerIds: { alchemy: "ETH_MAINNET", zerion: "ethereum" },
43
+ sessionCapable: true,
29
44
  ...overrides,
30
45
  };
31
46
  }
@@ -41,6 +56,62 @@ function errorsFor(chain) {
41
56
  (0, bun_test_1.expect)(errors).toEqual([]);
42
57
  (0, bun_test_1.expect)(result.hasErrors).toBe(false);
43
58
  });
59
+ (0, bun_test_1.it)("publishes exactly the authorization capabilities verified by the live audit", () => {
60
+ const both = { standards: ["erc3009", "erc2612"], eoaOnly: false };
61
+ const permitOnly = { standards: ["erc2612"], eoaOnly: true };
62
+ const transferOnly = { standards: ["erc3009"], eoaOnly: true };
63
+ const expected = new Map([
64
+ ["1:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", both],
65
+ ["10:0x0b2c639c533813f4aa9d7837caf62653d097ff85", both],
66
+ ["10:0x01bff41798a0bcf287b996046ca68b395dbc1071", both],
67
+ ["100:0x2a22f9c3b484c3629090feed35f17ff8f88f76f0", both],
68
+ ["130:0x078d782b760474a361dda0af3839290b0ef57ad6", both],
69
+ ["130:0x9151434b16b9763660705744891fa906f660ecc5", both],
70
+ ["137:0x3c499c542cef5e3811e1192ce70d8cc03d5c3359", both],
71
+ ["137:0xc2132d05d31c914a87c6611c10748aeb04b58e8f", permitOnly],
72
+ ["143:0x754704bc059f8c67012fed69bc8a327a5aafb603", both],
73
+ ["143:0xe7cd86e13ac4309349f30b3435a9d337750fc82d", both],
74
+ ["146:0x29219dd400f2bf60e5a23d13be72b486d4038894", both],
75
+ ["999:0xb88339cb7199b77e23db6e890353e22632ba630f", both],
76
+ ["999:0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb", both],
77
+ ["1868:0xba9986d2381edf1da03b0b9c1f8b00dc4aacc369", both],
78
+ ["4663:0x0bd7d308f8e1639fab988df18a8011f41eacad73", permitOnly],
79
+ ["4663:0x5fc5360d0400a0fd4f2af552add042d716f1d168", both],
80
+ ["8453:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", both],
81
+ ["9745:0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb", both],
82
+ ["9746:0x502012b361aebce43b26ec812b74d9a51db4d412", transferOnly],
83
+ ["42161:0x82af49447d8a07e3bd95bd0d56f35241523fbab1", permitOnly],
84
+ ["42161:0xaf88d065e77c8cc2239327c5edb3a432268e5831", both],
85
+ ["42161:0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9", both],
86
+ ["43114:0x9702230a8ea53601f5cd2dc00fdbc13d4df4a8c7", permitOnly],
87
+ ["43114:0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e", both],
88
+ ["84532:0x036cbd53842c5426634e7929541ec2318f3dcf7e", both],
89
+ ["421614:0x75faf114eafb1bdbe2f0316df893fd58ce46aa4d", both],
90
+ ["421614:0x980b62da83eff3d4576c647993b0c1d7faf17c73", permitOnly],
91
+ ["747474:0x203a662b0bd271a6ed5a60edfbd04bfce608fd36", permitOnly],
92
+ ["747474:0x2dca96907fde857dd3d816880a0df407eeb2d2f2", permitOnly],
93
+ ["747474:0xee7d8bcfb72bc1880d0cf19822eb0a2e6577ab62", permitOnly],
94
+ ["11155111:0x1c7d4b196cb0c7b01d743fbc6116a902379c7238", both],
95
+ ["11155111:0x768f42455a2d082e23ceef7d51e5787c82d67a39", permitOnly],
96
+ ["11155420:0x5fd84259d66cd46123540766be93dfe6d43130d7", both],
97
+ ]);
98
+ const configured = new Map(Object.entries(index_1.chainRegistry).flatMap(([chainId, entry]) => entry.tokens.flatMap((token) => {
99
+ if (!token.authorization)
100
+ return [];
101
+ const key = `${chainId}:${token.address.toLowerCase()}`;
102
+ (0, bun_test_1.expect)((0, viem_1.domainSeparator)({ domain: token.authorization.domain })).toBe(token.authorization.domainSeparator);
103
+ return [
104
+ [
105
+ key,
106
+ {
107
+ standards: token.authorization.standards,
108
+ eoaOnly: token.authorization.eoaOnly,
109
+ },
110
+ ],
111
+ ];
112
+ })));
113
+ (0, bun_test_1.expect)([...configured.entries()].sort()).toEqual([...expected.entries()].sort());
114
+ });
44
115
  (0, bun_test_1.it)("rejects a key that is not a canonical chain id", () => {
45
116
  const result = (0, validation_1.validateChainConfig)({ "01": validChain() });
46
117
  (0, bun_test_1.expect)(result.hasErrors).toBe(true);
@@ -83,12 +154,171 @@ function errorsFor(chain) {
83
154
  ["an iconSlug carrying its extension", { iconSlug: "base.svg" }],
84
155
  ["an iconSlug carrying a directory", { iconSlug: "chains/base" }],
85
156
  ["an iconSlug that is not a string", { iconSlug: 42 }],
157
+ // A missing vendor id and a null one mean opposite things — an artifact
158
+ // older than the field, versus a vendor that was checked and does not serve
159
+ // the chain. Only the second is an answer a consumer can act on.
160
+ ["missing providerIds", { providerIds: undefined }],
161
+ ["providerIds missing a vendor", { providerIds: { alchemy: "ETH_MAINNET" } }],
162
+ ["an empty vendor id", { providerIds: { alchemy: "", zerion: "ethereum" } }],
163
+ ["a missing sessionCapable", { sessionCapable: undefined }],
86
164
  ])("rejects %s", (_label, overrides) => {
87
165
  (0, bun_test_1.expect)(errorsFor(validChain(overrides)).length).toBeGreaterThan(0);
88
166
  });
89
167
  (0, bun_test_1.it)("accepts a null explorer, the answer for a chain that has none", () => {
90
168
  (0, bun_test_1.expect)(errorsFor(validChain({ explorer: null }))).toEqual([]);
91
169
  });
170
+ // Katana is exactly this: Alchemy serves it over RPC but Address Activity
171
+ // does not carry it, so ingestion is Zerion's alone.
172
+ (0, bun_test_1.it)("accepts a null vendor id, the answer for a vendor that does not serve the chain", () => {
173
+ (0, bun_test_1.expect)(errorsFor(validChain({ providerIds: { alchemy: null, zerion: "katana" } }))).toEqual([]);
174
+ (0, bun_test_1.expect)(errorsFor(validChain({ providerIds: { alchemy: null, zerion: null } }))).toEqual([]);
175
+ });
176
+ (0, bun_test_1.it)("accepts a complete token-native authorization declaration", () => {
177
+ (0, bun_test_1.expect)(errorsFor(validChain({
178
+ tokens: [
179
+ {
180
+ ...nativeToken,
181
+ balanceSlot: null,
182
+ approvalSlot: null,
183
+ authorization: validAuthorization,
184
+ address: usdcAddress,
185
+ },
186
+ ],
187
+ }))).toEqual([]);
188
+ });
189
+ bun_test_1.it.each([
190
+ ["a non-object declaration", "erc2612"],
191
+ [
192
+ "no standards",
193
+ {
194
+ ...validAuthorization,
195
+ standards: [],
196
+ },
197
+ ],
198
+ [
199
+ "an unknown standard",
200
+ {
201
+ ...validAuthorization,
202
+ standards: ["dai-permit"],
203
+ },
204
+ ],
205
+ [
206
+ "duplicate standards",
207
+ {
208
+ ...validAuthorization,
209
+ standards: ["erc2612", "erc2612"],
210
+ },
211
+ ],
212
+ [
213
+ "a missing domain",
214
+ {
215
+ ...validAuthorization,
216
+ standards: ["erc2612"],
217
+ domain: undefined,
218
+ },
219
+ ],
220
+ [
221
+ "an empty domain name",
222
+ {
223
+ ...validAuthorization,
224
+ domain: { ...validAuthorization.domain, name: "" },
225
+ },
226
+ ],
227
+ [
228
+ "a missing eoaOnly constraint",
229
+ {
230
+ ...validAuthorization,
231
+ eoaOnly: undefined,
232
+ },
233
+ ],
234
+ [
235
+ "a missing pinned separator",
236
+ {
237
+ ...validAuthorization,
238
+ domainSeparator: undefined,
239
+ },
240
+ ],
241
+ [
242
+ "a separator inconsistent with the domain",
243
+ {
244
+ ...validAuthorization,
245
+ domainSeparator: `0x${"00".repeat(32)}`,
246
+ },
247
+ ],
248
+ [
249
+ "a verifying contract different from the token",
250
+ {
251
+ ...validAuthorization,
252
+ domain: {
253
+ ...validAuthorization.domain,
254
+ verifyingContract: "0x0000000000000000000000000000000000000001",
255
+ },
256
+ },
257
+ ],
258
+ [
259
+ "a domain chain id different from the registry",
260
+ {
261
+ ...validAuthorization,
262
+ domain: { ...validAuthorization.domain, chainId: 10 },
263
+ },
264
+ ],
265
+ [
266
+ "both chainId and salt",
267
+ {
268
+ ...validAuthorization,
269
+ domain: {
270
+ ...validAuthorization.domain,
271
+ salt: `0x${"00".repeat(32)}`,
272
+ },
273
+ },
274
+ ],
275
+ [
276
+ "neither chainId nor salt",
277
+ {
278
+ ...validAuthorization,
279
+ domain: {
280
+ name: "USD Coin",
281
+ version: "2",
282
+ verifyingContract: usdcAddress,
283
+ },
284
+ },
285
+ ],
286
+ ])("rejects token authorization metadata with %s", (_label, authorization) => {
287
+ const tokens = [
288
+ {
289
+ ...nativeToken,
290
+ balanceSlot: null,
291
+ approvalSlot: null,
292
+ authorization,
293
+ address: usdcAddress,
294
+ },
295
+ ];
296
+ (0, bun_test_1.expect)(errorsFor(validChain({ tokens })).length).toBeGreaterThan(0);
297
+ });
298
+ (0, bun_test_1.it)("rejects token-native EIP-712 authorization metadata on non-EVM chains", () => {
299
+ const tokens = [
300
+ {
301
+ ...nativeToken,
302
+ balanceSlot: null,
303
+ approvalSlot: null,
304
+ authorization: validAuthorization,
305
+ address: usdcAddress,
306
+ },
307
+ ];
308
+ (0, bun_test_1.expect)(errorsFor(validChain({ vmType: "svm", tokens })).some((issue) => issue.message.includes("only valid for EVM tokens"))).toBe(true);
309
+ });
310
+ (0, bun_test_1.it)("rejects token authorization metadata on virtual EVM chains", () => {
311
+ const tokens = [
312
+ {
313
+ ...nativeToken,
314
+ address: usdcAddress,
315
+ balanceSlot: null,
316
+ approvalSlot: null,
317
+ authorization: validAuthorization,
318
+ },
319
+ ];
320
+ (0, bun_test_1.expect)(errorsFor(validChain({ virtual: true, tokens })).some((issue) => issue.message.includes("not valid on a virtual chain"))).toBe(true);
321
+ });
92
322
  (0, bun_test_1.it)("names the offending value so the build failure is actionable", () => {
93
323
  const [error] = errorsFor(validChain({ settlementLayers: ["TELEPORT"] }));
94
324
  (0, bun_test_1.expect)(error.message).toContain("TELEPORT");
@@ -0,0 +1 @@
1
+ export {};