@epoch-protocol/epoch-commons-sdk 0.1.19 → 0.1.21-mainnet.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.
@@ -97,10 +97,13 @@ export const ARBITER_ADDRESS = {
97
97
  10: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
98
98
  42161: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
99
99
  8453: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
100
+ // Robinhood placeholders — replace after deployment.
101
+ 4663: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
100
102
  // Testnets
101
103
  11155111: "0x2F5eA866716A04e91a55099620F2e1B423eC7011",
102
104
  84532: "0x2F5eA866716A04e91a55099620F2e1B423eC7011",
103
105
  11155420: "0x2F5eA866716A04e91a55099620F2e1B423eC7011",
106
+ 46630: "0x2F5eA866716A04e91a55099620F2e1B423eC7011",
104
107
  123456789: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
105
108
  999999999: "0x9f1de3ca45b09c61792a6f649ae68f420aa8a43b",
106
109
  };
@@ -111,10 +114,13 @@ export const ALLOCATOR_ADDRESS = {
111
114
  10: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
112
115
  42161: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
113
116
  8453: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
117
+ // Robinhood placeholders — replace after deployment.
118
+ 4663: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
114
119
  // Testnets
115
120
  11155111: "0xa46827635A7d329608085401a3b2Bf14a8a2bDF9",
116
121
  84532: "0xa46827635A7d329608085401a3b2Bf14a8a2bDF9",
117
122
  11155420: "0xa46827635A7d329608085401a3b2Bf14a8a2bDF9",
123
+ 46630: "0xa46827635A7d329608085401a3b2Bf14a8a2bDF9",
118
124
  123456789: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
119
125
  999999999: "0x444E8C0fC85BB47aBD3E97d00E2E2B0719034769",
120
126
  };
@@ -134,6 +140,32 @@ export function getArbiterAddress(chainId) {
134
140
  }
135
141
  return address;
136
142
  }
143
+ // The Robinhood Testnet deployment uses the same deterministic/testnet
144
+ // addresses as the existing Epoch testnet configuration. Populate every
145
+ // shared contract map together so any consumer consulting one of these maps
146
+ // cannot silently treat 46630 as unsupported.
147
+ const TESTNET_CONTRACT_ADDRESS_MAPS = [
148
+ INTENT_REGISTRY_ADDRESS,
149
+ EPOCH_MODULE_SAFE_ADDRESS,
150
+ EPOCH_SAFE_INIT_SETUP,
151
+ SAFE_INIT_SETUP_FORWARDER,
152
+ SAFE_WEBAUTHN_SHARED_SIGNER,
153
+ SAFE_WEBAUTHN_SIGNER_FACTORY,
154
+ FCLP256Verifier,
155
+ SAFE_PROXY_FACTORY_ADDRESS,
156
+ SAFE_SINGLETON_ADDRESS,
157
+ SAFE_7702_SINGLETON_ADDRESS,
158
+ SAFE_7579_MODULE_ADDRESS,
159
+ SAFE_7579_REGISTRY_ADDRESS,
160
+ EIP7702_SAFE_PROXY_ADDRESS,
161
+ METAMASK_EXEC_MANAGER,
162
+ EPOCH_ESCROW_ADDRESS,
163
+ SAFE_MULTISEND_ADDRESS,
164
+ SAFE_MULTISEND_CALL_ONLY_ADDRESS,
165
+ ];
166
+ for (const addresses of TESTNET_CONTRACT_ADDRESS_MAPS) {
167
+ addresses[46630] = addresses[11155420];
168
+ }
137
169
  const CONTRACT_ADDRESSES = {
138
170
  METAMASK_EXEC_MANAGER,
139
171
  SAFE_PROXY_FACTORY_ADDRESS,
@@ -7,7 +7,7 @@ export declare const DUMMY_LENDING_PROTOCOL: "dummy-lending";
7
7
  export declare const DUMMY_LENDING_MARKET_ADDRESS = "0xa73c1ae0e4e9116020dba0a419f91585d73459ee";
8
8
  /** CREATE2 staking contract — same on all dummy-staking testnets. */
9
9
  export declare const DUMMY_STAKING_CONTRACT_ADDRESS = "0xA25A981bc027E1f13aC70882a323B8B8EE880B9C";
10
- export declare const DUMMY_LENDING_CHAIN_IDS: readonly [84532, 11155111, 11155420];
10
+ export declare const DUMMY_LENDING_CHAIN_IDS: readonly [84532, 11155111, 11155420, 46630];
11
11
  export type DummyLendingChainId = (typeof DUMMY_LENDING_CHAIN_IDS)[number];
12
12
  /** Unified CREATE2 token addresses — same on every dummy-lending chain. */
13
13
  export declare const DUMMY_LENDING_TOKENS: {
@@ -11,6 +11,7 @@ export const DUMMY_LENDING_CHAIN_IDS = [
11
11
  84532, // Base Sepolia
12
12
  11155111, // Ethereum Sepolia
13
13
  11155420, // Optimism Sepolia
14
+ 46630, // Robinhood Testnet
14
15
  ];
15
16
  /** Unified CREATE2 token addresses — same on every dummy-lending chain. */
16
17
  export const DUMMY_LENDING_TOKENS = {
@@ -51,9 +51,41 @@
51
51
  "*": "*"
52
52
  },
53
53
  "type": ["swapandbridge"]
54
+ },
55
+ "MidenBridge": {
56
+ "contractAddress": {
57
+ "*": "*"
58
+ },
59
+ "type": ["swapandbridge", "bridge"]
60
+ }
61
+ },
62
+ "oracles": {
63
+ "PragmaMidenV1": {
64
+ "chain": "Miden",
65
+ "oracleAccount": "0x8f8d747477ca171144feadc60a1137",
66
+ "rpcUrl": "https://rpc.cedar.miden.io",
67
+ "method": "get_median",
68
+ "defaultMaxAgeSeconds": 120,
69
+ "minimumPublishers": 1,
70
+ "feeds": {
71
+ "USDC/USD": {
72
+ "key": "0x1dfbb6c4acb913805c4df6731bfe7bfb8b6acd999bb768feb24979170807ee51",
73
+ "expectedDecimals": 6
74
+ },
75
+ "ETH/USD": {
76
+ "key": "0x9a50f4137c634e0b384a87bea3a186e578e21274af6ae752230ead4631233e1d",
77
+ "expectedDecimals": 8
78
+ }
79
+ }
54
80
  }
55
81
  },
56
82
  "tokens": {
83
+ "USDCX": {
84
+ "contractAddress": {
85
+ "Miden": "mm1arnfum9xuwwlrvgvrefejwvlavn3vk24_qr7qqq9wr6w"
86
+ },
87
+ "decimals": 6
88
+ },
57
89
  "DAI": {
58
90
  "contractAddress": {
59
91
  "Ethereum": "0x6B175474E89094C44Da98b954EedeAC495271d0F",
@@ -80,7 +112,21 @@
80
112
  "Base": "0x4200000000000000000000000000000000000006",
81
113
  "Optimism": "0x4200000000000000000000000000000000000006",
82
114
  "Polygon": "0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619",
83
- "Arbitrum": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1"
115
+ "Arbitrum": "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
116
+ "Robinhood": "0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73",
117
+ "Miden": "mm1apqelr6tlaeftyfj4f7w59dycysmtawe_qr7qqq9wr6w"
118
+ },
119
+ "decimals": 18
120
+ },
121
+ "USDG": {
122
+ "contractAddress": {
123
+ "Robinhood": "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168"
124
+ },
125
+ "decimals": 6
126
+ },
127
+ "USDe": {
128
+ "contractAddress": {
129
+ "Robinhood": "0x5d3a1Ff2b6BAb83B63cd9AD0787074081a52ef34"
84
130
  },
85
131
  "decimals": 18
86
132
  },
@@ -114,6 +160,14 @@
114
160
  "Arbitrum": {
115
161
  "chainId": 42161,
116
162
  "explorer": "https://arbiscan.io"
163
+ },
164
+ "Robinhood": {
165
+ "chainId": 4663,
166
+ "explorer": "https://robinhoodchain.blockscout.com"
167
+ },
168
+ "Miden": {
169
+ "chainId": 999999999,
170
+ "explorer": "https://midenscan.com"
117
171
  }
118
172
  },
119
173
  "relationships": {
@@ -164,17 +218,32 @@
164
218
  "*": {
165
219
  "tokensInAndOut": ["*"]
166
220
  }
221
+ },
222
+ "MidenBridge": {
223
+ "*": {
224
+ "tokensInAndOut": ["*"]
225
+ }
167
226
  }
168
227
  },
169
228
  "tokenChains": {
170
229
  "DAI": ["Ethereum", "Base", "Optimism", "Polygon", "Arbitrum"],
171
230
  "USDC": ["Ethereum", "Base", "Optimism", "Polygon", "Arbitrum"],
172
- "WETH": ["Ethereum", "Base", "Optimism", "Polygon", "Arbitrum"],
231
+ "USDCX": ["Miden"],
232
+ "WETH": [
233
+ "Ethereum",
234
+ "Base",
235
+ "Optimism",
236
+ "Polygon",
237
+ "Arbitrum",
238
+ "Robinhood",
239
+ "Miden"
240
+ ],
241
+ "USDG": ["Robinhood"],
173
242
  "USDT": ["Ethereum", "Optimism", "Polygon", "Arbitrum"],
174
243
  "WBTC": ["Ethereum", "Optimism", "Polygon", "Arbitrum"],
175
244
  "wstETH": ["Ethereum", "Base", "Optimism", "Arbitrum"],
176
245
  "GHO": ["Ethereum", "Arbitrum", "Base"],
177
- "USDe": ["Ethereum", "Arbitrum"],
246
+ "USDe": ["Ethereum", "Arbitrum", "Robinhood"],
178
247
  "cbBTC": ["Ethereum", "Base"],
179
248
  "PYUSD": ["Ethereum"],
180
249
  "LINK": ["Ethereum", "Base", "Optimism", "Polygon", "Arbitrum"],
@@ -66,12 +66,19 @@
66
66
  }
67
67
  },
68
68
  "tokens": {
69
+ "USDCX": {
70
+ "contractAddress": {
71
+ "Miden": "0x4cbdcaffe75f0a317482224dae6436"
72
+ },
73
+ "decimals": 6
74
+ },
69
75
  "USDC": {
70
76
  "contractAddress": {
71
77
  "Base": "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69",
72
78
  "Mainnet": "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69",
73
- "Miden": "0xfc90f0f4da30e51168453b60eafed7",
74
- "Optimism": "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69"
79
+ "Miden": "0x5b043dcb48d5721106f7a1ceb2b804",
80
+ "Optimism": "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69",
81
+ "Robinhood": "0x2BB4FfD7E2c6D432b697554Efd77fA13bdbefd69"
75
82
  },
76
83
  "decimals": 18,
77
84
  "decimalsByChain": {
@@ -83,7 +90,8 @@
83
90
  "Base": "0xc30f1Ce05d1434d484E9A47283aA925fc8A8699a",
84
91
  "Mainnet": "0xc30f1Ce05d1434d484E9A47283aA925fc8A8699a",
85
92
  "Optimism": "0xc30f1Ce05d1434d484E9A47283aA925fc8A8699a",
86
- "Miden": "0x176275876f2fd41103257e341832b9"
93
+ "Robinhood": "0xc30f1Ce05d1434d484E9A47283aA925fc8A8699a",
94
+ "Miden": "0xd41499b8f142ad9119fd9da357a3b2"
87
95
  },
88
96
  "decimals": 18,
89
97
  "decimalsByChain": {
@@ -94,8 +102,9 @@
94
102
  "contractAddress": {
95
103
  "Base": "0xc04d2869665Be874881133943523723Be5782720",
96
104
  "Mainnet": "0xc04d2869665Be874881133943523723Be5782720",
97
- "Miden": "0x7725b0e9bb9406912d2ebeaeb05f4d",
98
- "Optimism": "0xc04d2869665Be874881133943523723Be5782720"
105
+ "Miden": "0x0ead4362a745e7d1790d75ea779611",
106
+ "Optimism": "0xc04d2869665Be874881133943523723Be5782720",
107
+ "Robinhood": "0xc04d2869665Be874881133943523723Be5782720"
99
108
  },
100
109
  "decimals": 18,
101
110
  "decimalsByChain": {
@@ -107,7 +116,8 @@
107
116
  "Base": "0x7946dd86eE310D0aC16804A37787289Fa5b88A8A",
108
117
  "Mainnet": "0x7946dd86eE310D0aC16804A37787289Fa5b88A8A",
109
118
  "Optimism": "0x7946dd86eE310D0aC16804A37787289Fa5b88A8A",
110
- "Miden": "0xa54717f6bd3210d128aeeaa8a2b7f3"
119
+ "Robinhood": "0x7946dd86eE310D0aC16804A37787289Fa5b88A8A",
120
+ "Miden": "0x9368815c611d5d517914a2c1f0bc8d"
111
121
  },
112
122
  "decimals": 18,
113
123
  "decimalsByChain": {
@@ -119,7 +129,8 @@
119
129
  "Base": "0x9b2a2754a9182fD65360E23afCDf3BeFF51796E9",
120
130
  "Mainnet": "0x9b2a2754a9182fD65360E23afCDf3BeFF51796E9",
121
131
  "Optimism": "0x9b2a2754a9182fD65360E23afCDf3BeFF51796E9",
122
- "Miden": "0x151823cde4b7bd91352617729d7614"
132
+ "Robinhood": "0x9b2a2754a9182fD65360E23afCDf3BeFF51796E9",
133
+ "Miden": "0x1b22d80328f58c5171f67a85f170a3"
123
134
  },
124
135
  "decimals": 18,
125
136
  "decimalsByChain": {
@@ -130,7 +141,8 @@
130
141
  "contractAddress": {
131
142
  "Base": "0xEA7dC9849206Ce73b11c465d37b85eC06B11Cf2C",
132
143
  "Mainnet": "0xEA7dC9849206Ce73b11c465d37b85eC06B11Cf2C",
133
- "Optimism": "0xEA7dC9849206Ce73b11c465d37b85eC06B11Cf2C"
144
+ "Optimism": "0xEA7dC9849206Ce73b11c465d37b85eC06B11Cf2C",
145
+ "Robinhood": "0xEA7dC9849206Ce73b11c465d37b85eC06B11Cf2C"
134
146
  },
135
147
  "decimals": 18
136
148
  },
@@ -138,7 +150,8 @@
138
150
  "contractAddress": {
139
151
  "Base": "0xB588418c0f90F07Bc9587d0050845a90C23C7502",
140
152
  "Mainnet": "0xB588418c0f90F07Bc9587d0050845a90C23C7502",
141
- "Optimism": "0xB588418c0f90F07Bc9587d0050845a90C23C7502"
153
+ "Optimism": "0xB588418c0f90F07Bc9587d0050845a90C23C7502",
154
+ "Robinhood": "0xB588418c0f90F07Bc9587d0050845a90C23C7502"
142
155
  },
143
156
  "decimals": 18
144
157
  },
@@ -146,7 +159,8 @@
146
159
  "contractAddress": {
147
160
  "Base": "0x512Ee6Bd7A4be5Ba4796F15Df080c4D0F89a38eD",
148
161
  "Mainnet": "0x512Ee6Bd7A4be5Ba4796F15Df080c4D0F89a38eD",
149
- "Optimism": "0x512Ee6Bd7A4be5Ba4796F15Df080c4D0F89a38eD"
162
+ "Optimism": "0x512Ee6Bd7A4be5Ba4796F15Df080c4D0F89a38eD",
163
+ "Robinhood": "0x512Ee6Bd7A4be5Ba4796F15Df080c4D0F89a38eD"
150
164
  },
151
165
  "decimals": 18
152
166
  },
@@ -154,7 +168,8 @@
154
168
  "contractAddress": {
155
169
  "Base": "0x145e03A80c19ad1b9d0429d06b6d52707de724A0",
156
170
  "Mainnet": "0x145e03A80c19ad1b9d0429d06b6d52707de724A0",
157
- "Optimism": "0x145e03A80c19ad1b9d0429d06b6d52707de724A0"
171
+ "Optimism": "0x145e03A80c19ad1b9d0429d06b6d52707de724A0",
172
+ "Robinhood": "0x145e03A80c19ad1b9d0429d06b6d52707de724A0"
158
173
  },
159
174
  "decimals": 18
160
175
  }
@@ -175,6 +190,10 @@
175
190
  "Optimism": {
176
191
  "chainId": 11155420,
177
192
  "explorer": "https://sepolia-optimistic.etherscan.io/"
193
+ },
194
+ "Robinhood": {
195
+ "chainId": 46630,
196
+ "explorer": "https://explorer.testnet.chain.robinhood.com"
178
197
  }
179
198
  },
180
199
  "relationships": {
@@ -338,15 +357,16 @@
338
357
  }
339
358
  },
340
359
  "tokenChains": {
341
- "DAI": ["Base", "Mainnet", "Optimism"],
342
- "USDT": ["Base", "Mainnet", "Optimism"],
343
- "USDC": ["Base", "Optimism", "Mainnet", "Miden"],
344
- "WETH": ["Base", "Mainnet", "Optimism"],
345
- "WBTC": ["Base", "Mainnet", "Optimism"],
346
- "PENGU": ["Base", "Mainnet", "Optimism"],
347
- "OSWALD": ["Base", "Mainnet", "Optimism"],
348
- "KICK": ["Base", "Mainnet", "Optimism"],
349
- "FERB": ["Base", "Mainnet", "Optimism"]
360
+ "USDCX": ["Miden"],
361
+ "DAI": ["Base", "Mainnet", "Optimism", "Robinhood"],
362
+ "USDT": ["Base", "Mainnet", "Optimism", "Robinhood"],
363
+ "USDC": ["Base", "Optimism", "Mainnet", "Miden", "Robinhood"],
364
+ "WETH": ["Base", "Mainnet", "Optimism", "Robinhood"],
365
+ "WBTC": ["Base", "Mainnet", "Optimism", "Robinhood"],
366
+ "PENGU": ["Base", "Mainnet", "Optimism", "Robinhood"],
367
+ "OSWALD": ["Base", "Mainnet", "Optimism", "Robinhood"],
368
+ "KICK": ["Base", "Mainnet", "Optimism", "Robinhood"],
369
+ "FERB": ["Base", "Mainnet", "Optimism", "Robinhood"]
350
370
  }
351
371
  }
352
372
  }
@@ -279,6 +279,11 @@ export type QueuedTransactionForIntent = {
279
279
  transactionHash: string | null;
280
280
  /** EIP-7702 authorization list for relay txs (enable delegation). */
281
281
  authorizationList?: Record<string, unknown>[];
282
+ /**
283
+ * Compact / Miden reservation keys so the queue worker can finalize those
284
+ * reservations on SUCCESS or FAILED.
285
+ */
286
+ processedCompactKeys?: string[];
282
287
  };
283
288
  export type CompactDataForQueue = {
284
289
  intentNonce: string;
@@ -0,0 +1,24 @@
1
+ import type { Hex } from "viem";
2
+ export declare const DEX_POOLS_EXTRA_TYPESTRING = "string dexPools";
3
+ export declare const MAX_DEX_POOL_PREFERENCES = 16;
4
+ export type UniswapV3PoolPreference = {
5
+ protocol: "uniswap-v3";
6
+ chainId: number;
7
+ address: Hex;
8
+ };
9
+ export type UniswapV4PoolKey = {
10
+ currency0: Hex;
11
+ currency1: Hex;
12
+ fee: number;
13
+ tickSpacing: number;
14
+ hooks: Hex;
15
+ };
16
+ export type UniswapV4PoolPreference = {
17
+ protocol: "uniswap-v4";
18
+ chainId: number;
19
+ poolKey: UniswapV4PoolKey;
20
+ hookData?: Hex;
21
+ };
22
+ export type DexPoolPreference = UniswapV3PoolPreference | UniswapV4PoolPreference;
23
+ export declare function decodeDexPools(value: unknown): DexPoolPreference[];
24
+ export declare function encodeDexPools(pools: readonly DexPoolPreference[]): string;
@@ -0,0 +1,94 @@
1
+ export const DEX_POOLS_EXTRA_TYPESTRING = "string dexPools";
2
+ export const MAX_DEX_POOL_PREFERENCES = 16;
3
+ const DYNAMIC_FEE_FLAG = 0x800000;
4
+ function invalid(message) {
5
+ throw new Error(`Invalid dexPools: ${message}`);
6
+ }
7
+ function isHex(value) {
8
+ return typeof value === "string" && /^0x(?:[0-9a-fA-F]{2})*$/.test(value);
9
+ }
10
+ function address(value, field, allowZero = false) {
11
+ if (typeof value !== "string" ||
12
+ !/^0x[0-9a-fA-F]{40}$/.test(value) ||
13
+ (!allowZero && /^0x0{40}$/i.test(value))) {
14
+ return invalid(`${field} must be a non-zero address`);
15
+ }
16
+ return value.toLowerCase();
17
+ }
18
+ function integer(value, field, minimum, maximum) {
19
+ if (typeof value !== "number" ||
20
+ !Number.isSafeInteger(value) ||
21
+ value < minimum ||
22
+ value > maximum) {
23
+ return invalid(`${field} must be an integer between ${minimum} and ${maximum}`);
24
+ }
25
+ return value;
26
+ }
27
+ function decodeEntry(value) {
28
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
29
+ return invalid("each entry must be an object");
30
+ }
31
+ const entry = value;
32
+ const chainId = integer(entry.chainId, "chainId", 1, Number.MAX_SAFE_INTEGER);
33
+ if (entry.protocol === "uniswap-v3") {
34
+ return {
35
+ protocol: "uniswap-v3",
36
+ chainId,
37
+ address: address(entry.address, "address"),
38
+ };
39
+ }
40
+ if (entry.protocol !== "uniswap-v4") {
41
+ return invalid("protocol must be uniswap-v3 or uniswap-v4");
42
+ }
43
+ if (!entry.poolKey ||
44
+ typeof entry.poolKey !== "object" ||
45
+ Array.isArray(entry.poolKey)) {
46
+ return invalid("poolKey must be an object");
47
+ }
48
+ const key = entry.poolKey;
49
+ const currency0 = address(key.currency0, "poolKey.currency0", true);
50
+ const currency1 = address(key.currency1, "poolKey.currency1");
51
+ if (currency0 >= currency1) {
52
+ return invalid("poolKey.currency0 must sort before poolKey.currency1");
53
+ }
54
+ const fee = integer(key.fee, "poolKey.fee", 0, 0xffffff);
55
+ if (fee > 1_000_000 && fee !== DYNAMIC_FEE_FLAG) {
56
+ return invalid("poolKey.fee is outside the v4 fee range");
57
+ }
58
+ const tickSpacing = integer(key.tickSpacing, "poolKey.tickSpacing", 1, 32767);
59
+ const hooks = address(key.hooks, "poolKey.hooks", true);
60
+ const hookData = entry.hookData === undefined ? "0x" : entry.hookData;
61
+ if (!isHex(hookData))
62
+ return invalid("hookData must be even-length hex");
63
+ return {
64
+ protocol: "uniswap-v4",
65
+ chainId,
66
+ poolKey: { currency0, currency1, fee, tickSpacing, hooks },
67
+ hookData: hookData.toLowerCase(),
68
+ };
69
+ }
70
+ export function decodeDexPools(value) {
71
+ if (value === undefined || value === null || value === "")
72
+ return [];
73
+ if (typeof value !== "string")
74
+ return invalid("must be a JSON string");
75
+ let decoded;
76
+ try {
77
+ decoded = JSON.parse(value);
78
+ }
79
+ catch {
80
+ return invalid("must contain valid JSON");
81
+ }
82
+ if (!Array.isArray(decoded))
83
+ return invalid("must contain an array");
84
+ if (decoded.length > MAX_DEX_POOL_PREFERENCES) {
85
+ return invalid(`must contain at most ${MAX_DEX_POOL_PREFERENCES} entries`);
86
+ }
87
+ return decoded.map(decodeEntry);
88
+ }
89
+ export function encodeDexPools(pools) {
90
+ if (!Array.isArray(pools))
91
+ return invalid("must be an array");
92
+ // Reuse the decoder so encoding and decoding accept precisely the same schema.
93
+ return JSON.stringify(decodeDexPools(JSON.stringify(pools)));
94
+ }
@@ -0,0 +1,9 @@
1
+ /** Compact witness declaration for selecting an external quote provider. */
2
+ export declare const EXTERNAL_PROVIDER_EXTRA_TYPESTRING = "string provider";
3
+ export declare const EXTERNAL_QUOTE_PROVIDERS: readonly ["khalani", "near", "lifi"];
4
+ export type ExternalQuoteProvider = (typeof EXTERNAL_QUOTE_PROVIDERS)[number];
5
+ /**
6
+ * Validates an optional signed provider field without normalizing its value.
7
+ * The exact string is part of the Compact witness and must remain unchanged.
8
+ */
9
+ export declare function decodeExternalQuoteProvider(value: unknown): ExternalQuoteProvider | undefined;
@@ -0,0 +1,16 @@
1
+ /** Compact witness declaration for selecting an external quote provider. */
2
+ export const EXTERNAL_PROVIDER_EXTRA_TYPESTRING = "string provider";
3
+ export const EXTERNAL_QUOTE_PROVIDERS = ["khalani", "near", "lifi"];
4
+ /**
5
+ * Validates an optional signed provider field without normalizing its value.
6
+ * The exact string is part of the Compact witness and must remain unchanged.
7
+ */
8
+ export function decodeExternalQuoteProvider(value) {
9
+ if (value === undefined)
10
+ return undefined;
11
+ if (typeof value !== "string" ||
12
+ !EXTERNAL_QUOTE_PROVIDERS.includes(value)) {
13
+ throw new Error(`Invalid external provider; expected one of ${EXTERNAL_QUOTE_PROVIDERS.join(", ")}`);
14
+ }
15
+ return value;
16
+ }
@@ -0,0 +1,20 @@
1
+ import type { Graph } from "../types/index.js";
2
+ /** Resolve the canonical graph name and metadata from an EVM chain id. */
3
+ export declare function getGraphChain(graph: Graph, chainId: number): {
4
+ chainId: number;
5
+ explorer: string;
6
+ nativeCurrency?: {
7
+ name: string;
8
+ symbol: string;
9
+ decimals: number;
10
+ };
11
+ name: string;
12
+ } | undefined;
13
+ /** Resolve an asset only when its address exists on the requested chain. */
14
+ export declare function getGraphToken(graph: Graph, chainId: number, symbol: string): {
15
+ symbol: string;
16
+ address: string;
17
+ decimals: number;
18
+ } | undefined;
19
+ /** Check graph path eligibility, including wildcard filler protocols. */
20
+ export declare function supportsGraphProtocol(graph: Graph, chainId: number, protocol: string, symbol: string): boolean;
@@ -0,0 +1,34 @@
1
+ /** Resolve the canonical graph name and metadata from an EVM chain id. */
2
+ export function getGraphChain(graph, chainId) {
3
+ const entry = Object.entries(graph.chains).find(([, chain]) => chain.chainId === chainId);
4
+ return entry ? { name: entry[0], ...entry[1] } : undefined;
5
+ }
6
+ /** Resolve an asset only when its address exists on the requested chain. */
7
+ export function getGraphToken(graph, chainId, symbol) {
8
+ const chain = getGraphChain(graph, chainId);
9
+ const token = graph.tokens[symbol];
10
+ const address = chain && token?.contractAddress[chain.name];
11
+ return address && chain && token
12
+ ? {
13
+ symbol,
14
+ address,
15
+ decimals: token.decimalsByChain?.[chain.name] ?? token.decimals,
16
+ }
17
+ : undefined;
18
+ }
19
+ /** Check graph path eligibility, including wildcard filler protocols. */
20
+ export function supportsGraphProtocol(graph, chainId, protocol, symbol) {
21
+ const chain = getGraphChain(graph, chainId);
22
+ if (!chain || !getGraphToken(graph, chainId, symbol))
23
+ return false;
24
+ const addresses = graph.protocols[protocol]?.contractAddress;
25
+ if (!addresses?.[chain.name] && !addresses?.["*"])
26
+ return false;
27
+ const relationships = graph.relationships.protocolTokensByChain[protocol];
28
+ const relation = relationships?.[chain.name] ?? relationships?.["*"];
29
+ return [
30
+ relation?.tokensIn,
31
+ relation?.tokensOut,
32
+ relation?.tokensInAndOut,
33
+ ].some((tokens) => tokens?.includes(symbol) || tokens?.includes("*"));
34
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./compact.js";
2
+ export * from "./miden-id.js";
2
3
  export * from "./miden-intent.js";
3
4
  export * from "./path.js";
4
5
  export * from "./witness-typestring.js";
@@ -1,4 +1,5 @@
1
1
  export * from "./compact.js";
2
+ export * from "./miden-id.js";
2
3
  export * from "./miden-intent.js";
3
4
  export * from "./path.js";
4
5
  export * from "./witness-typestring.js";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Convert a Miden account or faucet identifier to canonical 0x-prefixed hex.
3
+ *
4
+ * Hex identifiers pass through with their body case preserved. Valid Miden
5
+ * Bech32/Bech32m addresses (including an optional interface suffix) are decoded.
6
+ * Invalid non-hex input is returned trimmed so callers can apply their own
7
+ * validation and surface the original value in error messages.
8
+ */
9
+ export declare function normalizeMidenId(id: string): string;
@@ -0,0 +1,88 @@
1
+ const BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
2
+ const BECH32_CHECKSUM = 1;
3
+ const BECH32M_CHECKSUM = 0x2bc830a3;
4
+ const MIDEN_ACCOUNT_ID_BYTES = 15;
5
+ function bech32Polymod(values) {
6
+ const generator = [
7
+ 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3,
8
+ ];
9
+ let checksum = 1;
10
+ for (const value of values) {
11
+ const top = checksum >>> 25;
12
+ checksum = ((checksum & 0x1ffffff) << 5) ^ value;
13
+ for (let index = 0; index < generator.length; index += 1) {
14
+ if ((top >>> index) & 1)
15
+ checksum ^= generator[index];
16
+ }
17
+ }
18
+ return checksum >>> 0;
19
+ }
20
+ function bech32HrpExpand(hrp) {
21
+ const output = [];
22
+ for (let index = 0; index < hrp.length; index += 1) {
23
+ output.push(hrp.charCodeAt(index) >> 5);
24
+ }
25
+ output.push(0);
26
+ for (let index = 0; index < hrp.length; index += 1) {
27
+ output.push(hrp.charCodeAt(index) & 31);
28
+ }
29
+ return output;
30
+ }
31
+ function decodeMidenBech32(input) {
32
+ const address = input.split("_")[0].toLowerCase();
33
+ const separator = address.lastIndexOf("1");
34
+ if (separator < 1 || separator + 7 > address.length)
35
+ return null;
36
+ const words = [];
37
+ for (const character of address.slice(separator + 1)) {
38
+ const value = BECH32_CHARSET.indexOf(character);
39
+ if (value < 0)
40
+ return null;
41
+ words.push(value);
42
+ }
43
+ const checksum = bech32Polymod([
44
+ ...bech32HrpExpand(address.slice(0, separator)),
45
+ ...words,
46
+ ]);
47
+ if (checksum !== BECH32_CHECKSUM && checksum !== BECH32M_CHECKSUM) {
48
+ return null;
49
+ }
50
+ let accumulator = 0;
51
+ let bits = 0;
52
+ const bytes = [];
53
+ for (const word of words.slice(0, -6)) {
54
+ accumulator = (accumulator << 5) | word;
55
+ bits += 5;
56
+ while (bits >= 8) {
57
+ bits -= 8;
58
+ bytes.push((accumulator >> bits) & 0xff);
59
+ }
60
+ }
61
+ if (bytes.length < MIDEN_ACCOUNT_ID_BYTES + 1)
62
+ return null;
63
+ return ("0x" +
64
+ bytes
65
+ .slice(1, 1 + MIDEN_ACCOUNT_ID_BYTES)
66
+ .map((byte) => byte.toString(16).padStart(2, "0"))
67
+ .join(""));
68
+ }
69
+ /**
70
+ * Convert a Miden account or faucet identifier to canonical 0x-prefixed hex.
71
+ *
72
+ * Hex identifiers pass through with their body case preserved. Valid Miden
73
+ * Bech32/Bech32m addresses (including an optional interface suffix) are decoded.
74
+ * Invalid non-hex input is returned trimmed so callers can apply their own
75
+ * validation and surface the original value in error messages.
76
+ */
77
+ export function normalizeMidenId(id) {
78
+ const raw = (id ?? "").trim();
79
+ if (!raw)
80
+ return raw;
81
+ if (raw.startsWith("0x") || raw.startsWith("0X")) {
82
+ return "0x" + raw.slice(2);
83
+ }
84
+ if (/^[0-9a-fA-F]+$/.test(raw) && raw.length % 2 === 0) {
85
+ return "0x" + raw;
86
+ }
87
+ return decodeMidenBech32(raw) ?? raw;
88
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epoch-protocol/epoch-commons-sdk",
3
- "version": "0.1.19",
3
+ "version": "0.1.21-mainnet.0",
4
4
  "description": "SDK for interacting with Epoch Commons Protocol",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,18 +0,0 @@
1
- /** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
2
- export declare const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
3
- /** Miden → EVM cross-chain bridge witness suffix (canonical). */
4
- export declare const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
5
- /** EVM → Miden cross-chain bridge witness suffix (canonical). */
6
- export declare const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
7
- export declare const MIDEN_TO_EVM_WITNESS_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient,string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
8
- export declare const EVM_TO_MIDEN_WITNESS_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient,string midenRecipientAccount,string midenFaucetId";
9
- export declare const MIDEN_TO_EVM_FIELD_NAMES: string[];
10
- export declare const EVM_TO_MIDEN_FIELD_NAMES: string[];
11
- /** Union of all Miden bridge field names from the canonical extra typestrings. */
12
- export declare const MIDEN_MARKER_FIELD_NAMES: string[];
13
- /** Fields declared only on the Miden→EVM extra typestring. */
14
- export declare const MIDEN_TO_EVM_ONLY_FIELD_NAMES: string[];
15
- /** Fields declared only on the EVM→Miden extra typestring. */
16
- export declare const EVM_TO_MIDEN_ONLY_FIELD_NAMES: string[];
17
- export declare const MIDEN_SOURCE_ACCOUNT_FIELD_NAME: "midenSourceAccount";
18
- export declare const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME: "midenRecipientAccount";
@@ -1,31 +0,0 @@
1
- import { fieldNamesFromExtraTypestring } from "./witness-typestring-parse.js";
2
- function uniqueFieldNames(typestrings) {
3
- return [
4
- ...new Set(typestrings.flatMap((typestring) => fieldNamesFromExtraTypestring(typestring))),
5
- ];
6
- }
7
- function onlyInLeft(left, right) {
8
- const rightSet = new Set(right);
9
- return left.filter((name) => !rightSet.has(name));
10
- }
11
- /** Base Mandate fields shared by all Epoch intents (matches `getTaskData`). */
12
- export const BASE_MANDATE_TYPESTRING = "address tokenIn,uint256 tokenInAmount,address tokenOut,uint256 minTokenOut,uint256 destinationChainId,bytes4 taskType,bytes32 protocolHashIdentifier,address recipient";
13
- /** Miden → EVM cross-chain bridge witness suffix (canonical). */
14
- export const MIDEN_TO_EVM_EXTRA_TYPESTRING = "string midenSourceAccount,string midenFaucetId,string midenNoteType,string midenNoteId";
15
- /** EVM → Miden cross-chain bridge witness suffix (canonical). */
16
- export const EVM_TO_MIDEN_EXTRA_TYPESTRING = "string midenRecipientAccount,string midenFaucetId";
17
- export const MIDEN_TO_EVM_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${MIDEN_TO_EVM_EXTRA_TYPESTRING}`;
18
- export const EVM_TO_MIDEN_WITNESS_TYPESTRING = `${BASE_MANDATE_TYPESTRING},${EVM_TO_MIDEN_EXTRA_TYPESTRING}`;
19
- export const MIDEN_TO_EVM_FIELD_NAMES = fieldNamesFromExtraTypestring(MIDEN_TO_EVM_EXTRA_TYPESTRING);
20
- export const EVM_TO_MIDEN_FIELD_NAMES = fieldNamesFromExtraTypestring(EVM_TO_MIDEN_EXTRA_TYPESTRING);
21
- /** Union of all Miden bridge field names from the canonical extra typestrings. */
22
- export const MIDEN_MARKER_FIELD_NAMES = uniqueFieldNames([
23
- MIDEN_TO_EVM_EXTRA_TYPESTRING,
24
- EVM_TO_MIDEN_EXTRA_TYPESTRING,
25
- ]);
26
- /** Fields declared only on the Miden→EVM extra typestring. */
27
- export const MIDEN_TO_EVM_ONLY_FIELD_NAMES = onlyInLeft(MIDEN_TO_EVM_FIELD_NAMES, EVM_TO_MIDEN_FIELD_NAMES);
28
- /** Fields declared only on the EVM→Miden extra typestring. */
29
- export const EVM_TO_MIDEN_ONLY_FIELD_NAMES = onlyInLeft(EVM_TO_MIDEN_FIELD_NAMES, MIDEN_TO_EVM_FIELD_NAMES);
30
- export const MIDEN_SOURCE_ACCOUNT_FIELD_NAME = MIDEN_TO_EVM_ONLY_FIELD_NAMES.find((name) => name === "midenSourceAccount");
31
- export const MIDEN_RECIPIENT_ACCOUNT_FIELD_NAME = EVM_TO_MIDEN_ONLY_FIELD_NAMES.find((name) => name === "midenRecipientAccount");
@@ -1,5 +0,0 @@
1
- export declare function parseWitnessTypestringFields(witnessTypeString: string): Array<{
2
- type: string;
3
- name: string;
4
- }>;
5
- export declare function fieldNamesFromExtraTypestring(typestring: string): string[];
@@ -1,18 +0,0 @@
1
- export function parseWitnessTypestringFields(witnessTypeString) {
2
- return witnessTypeString
3
- .split(",")
4
- .map((field) => field.trim())
5
- .filter(Boolean)
6
- .map((field) => {
7
- const tokens = field.split(/\s+/).filter(Boolean);
8
- if (tokens.length < 2) {
9
- throw new Error(`Invalid witness field "${field}" (expected "type name" in witnessTypeString)`);
10
- }
11
- const name = tokens[tokens.length - 1];
12
- const type = tokens.slice(0, -1).join(" ");
13
- return { type, name };
14
- });
15
- }
16
- export function fieldNamesFromExtraTypestring(typestring) {
17
- return parseWitnessTypestringFields(typestring).map((field) => field.name);
18
- }