@seapay-ai/erc3009 0.1.1 → 0.2.1

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.
Files changed (98) hide show
  1. package/README.md +171 -184
  2. package/dist/build.d.ts +27 -0
  3. package/dist/build.d.ts.map +1 -0
  4. package/dist/build.js +47 -0
  5. package/dist/domain.d.ts +29 -0
  6. package/dist/domain.d.ts.map +1 -0
  7. package/dist/domain.js +57 -0
  8. package/dist/index.d.ts +8 -22
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +10 -31
  11. package/dist/registry.d.ts +44 -0
  12. package/dist/registry.d.ts.map +1 -0
  13. package/dist/registry.js +166 -0
  14. package/dist/types/index.d.ts +44 -3
  15. package/dist/types/index.d.ts.map +1 -1
  16. package/dist/types/index.js +1 -3
  17. package/dist/utils.d.ts +13 -0
  18. package/dist/utils.d.ts.map +1 -0
  19. package/dist/utils.js +19 -0
  20. package/dist/verify.d.ts +14 -0
  21. package/dist/verify.d.ts.map +1 -0
  22. package/dist/verify.js +36 -0
  23. package/package.json +8 -7
  24. package/dist/api/index.d.ts +0 -2
  25. package/dist/api/index.d.ts.map +0 -1
  26. package/dist/api/index.js +0 -1
  27. package/dist/api/prepare.d.ts +0 -47
  28. package/dist/api/prepare.d.ts.map +0 -1
  29. package/dist/api/prepare.js +0 -57
  30. package/dist/core.d.ts +0 -14
  31. package/dist/core.d.ts.map +0 -1
  32. package/dist/core.js +0 -13
  33. package/dist/domain/index.d.ts +0 -3
  34. package/dist/domain/index.d.ts.map +0 -1
  35. package/dist/domain/index.js +0 -2
  36. package/dist/domain/normalize.d.ts +0 -9
  37. package/dist/domain/normalize.d.ts.map +0 -1
  38. package/dist/domain/normalize.js +0 -25
  39. package/dist/domain/resolveDomain.d.ts +0 -15
  40. package/dist/domain/resolveDomain.d.ts.map +0 -1
  41. package/dist/domain/resolveDomain.js +0 -47
  42. package/dist/erc3009/buildTypes.d.ts +0 -6
  43. package/dist/erc3009/buildTypes.d.ts.map +0 -1
  44. package/dist/erc3009/buildTypes.js +0 -11
  45. package/dist/erc3009/constants.d.ts +0 -7
  46. package/dist/erc3009/constants.d.ts.map +0 -1
  47. package/dist/erc3009/constants.js +0 -6
  48. package/dist/erc3009/index.d.ts +0 -7
  49. package/dist/erc3009/index.d.ts.map +0 -1
  50. package/dist/erc3009/index.js +0 -6
  51. package/dist/erc3009/message.d.ts +0 -21
  52. package/dist/erc3009/message.d.ts.map +0 -1
  53. package/dist/erc3009/message.js +0 -29
  54. package/dist/erc3009/sign.d.ts +0 -7
  55. package/dist/erc3009/sign.d.ts.map +0 -1
  56. package/dist/erc3009/sign.js +0 -8
  57. package/dist/erc3009/typedData.d.ts +0 -15
  58. package/dist/erc3009/typedData.d.ts.map +0 -1
  59. package/dist/erc3009/typedData.js +0 -21
  60. package/dist/erc3009/verify.d.ts +0 -10
  61. package/dist/erc3009/verify.d.ts.map +0 -1
  62. package/dist/erc3009/verify.js +0 -17
  63. package/dist/registry/chains.d.ts +0 -22
  64. package/dist/registry/chains.d.ts.map +0 -1
  65. package/dist/registry/chains.js +0 -104
  66. package/dist/registry/index.d.ts +0 -4
  67. package/dist/registry/index.d.ts.map +0 -1
  68. package/dist/registry/index.js +0 -6
  69. package/dist/registry/registry.d.ts +0 -38
  70. package/dist/registry/registry.d.ts.map +0 -1
  71. package/dist/registry/registry.js +0 -73
  72. package/dist/registry/tokens/index.d.ts +0 -11
  73. package/dist/registry/tokens/index.d.ts.map +0 -1
  74. package/dist/registry/tokens/index.js +0 -14
  75. package/dist/registry/tokens/usdc.d.ts +0 -27
  76. package/dist/registry/tokens/usdc.d.ts.map +0 -1
  77. package/dist/registry/tokens/usdc.js +0 -104
  78. package/dist/types/domain.d.ts +0 -24
  79. package/dist/types/domain.d.ts.map +0 -1
  80. package/dist/types/domain.js +0 -1
  81. package/dist/types/erc3009.d.ts +0 -38
  82. package/dist/types/erc3009.d.ts.map +0 -1
  83. package/dist/types/erc3009.js +0 -15
  84. package/dist/types/registry.d.ts +0 -35
  85. package/dist/types/registry.d.ts.map +0 -1
  86. package/dist/types/registry.js +0 -1
  87. package/dist/utils/hex.d.ts +0 -13
  88. package/dist/utils/hex.d.ts.map +0 -1
  89. package/dist/utils/hex.js +0 -19
  90. package/dist/utils/index.d.ts +0 -4
  91. package/dist/utils/index.d.ts.map +0 -1
  92. package/dist/utils/index.js +0 -3
  93. package/dist/utils/nonce.d.ts +0 -5
  94. package/dist/utils/nonce.d.ts.map +0 -1
  95. package/dist/utils/nonce.js +0 -7
  96. package/dist/utils/time.d.ts +0 -13
  97. package/dist/utils/time.d.ts.map +0 -1
  98. package/dist/utils/time.js +0 -18
package/README.md CHANGED
@@ -1,15 +1,6 @@
1
1
  # @seapay-ai/erc3009
2
2
 
3
- Multi-chain ERC-3009 (TransferWithAuthorization) helper library for building, signing, and verifying EIP-712 typed data.
4
-
5
- ## Features
6
-
7
- - ✅ **Multi-chain support**: Base, Ethereum, Arbitrum, Optimism, Polygon (mainnet + testnets)
8
- - ✅ **Token registry**: Pre-configured USDC addresses and domain parameters for all chains
9
- - ✅ **Type-safe**: Full TypeScript support with strict types
10
- - ✅ **Ergonomic API**: One-liner `prepare()` for common use cases
11
- - ✅ **Override support**: Customize domain parameters for custom tokens
12
- - ✅ **ethers.js v6**: Built on ethers v6 for signing and verification
3
+ Simplified TypeScript library for ERC-3009 (TransferWithAuthorization) EIP-712 signing and verification.
13
4
 
14
5
  ## Installation
15
6
 
@@ -22,145 +13,161 @@ npm install @seapay-ai/erc3009
22
13
  ## Quick Start
23
14
 
24
15
  ```typescript
25
- import { prepare } from "@seapay-ai/erc3009";
16
+ import {
17
+ buildTypedData,
18
+ buildMessage,
19
+ resolveDomain,
20
+ nowPlusSeconds,
21
+ } from "@seapay-ai/erc3009";
26
22
  import { Wallet } from "ethers";
27
23
 
28
- // One-call convenience API
29
- const { typedData } = prepare({
30
- chainId: 8453, // Base
31
- token: "USDC",
24
+ // 1. Build the message
25
+ const message = buildMessage({
32
26
  from: wallet.address,
33
27
  to: "0xRecipient...",
34
28
  value: 1000000n, // 1 USDC (6 decimals)
35
- ttlSeconds: 300, // 5 minutes
29
+ validBefore: nowPlusSeconds(300), // Valid for 5 minutes
36
30
  });
37
31
 
38
- // Sign with ethers wallet
39
- const signature = await wallet.signTypedData(
40
- typedData.domain,
41
- typedData.types,
42
- typedData.message
43
- );
44
- ```
45
-
46
- ## Usage Examples
47
-
48
- ### 1. Ergonomic API (Recommended)
49
-
50
- The `prepare()` function resolves the domain, builds the message, and returns everything needed:
51
-
52
- ```typescript
53
- import { prepare } from "@seapay-ai/erc3009";
54
-
55
- const { domain, message, typedData } = prepare({
32
+ // 2. Build typed data (includes domain resolution from registry)
33
+ const {
34
+ domain,
35
+ types,
36
+ message: msg,
37
+ } = buildTypedData({
56
38
  chainId: 8453, // Base mainnet
57
39
  token: "USDC",
58
- from: "0xSender...",
59
- to: "0xRecipient...",
60
- value: 1000000n, // 1 USDC
61
- ttlSeconds: 300, // optional, default: 300
40
+ message,
62
41
  });
63
42
 
64
- // Sign it
65
- const sig = await wallet.signTypedData(
66
- typedData.domain,
67
- typedData.types,
68
- typedData.message
69
- );
43
+ // 3. Sign with ethers wallet
44
+ const signature = await wallet.signTypedData(domain, types, msg);
70
45
  ```
71
46
 
72
- ### 2. Core Builders (Manual)
47
+ ## Core Functions
73
48
 
74
- For more control, use the core builders:
49
+ ### 1. Build Message
75
50
 
76
51
  ```typescript
77
- import {
78
- resolveDomain,
79
- buildMessage,
80
- buildTypedData,
81
- erc3009,
82
- } from "@seapay-ai/erc3009";
83
-
84
- // 1. Resolve domain from registry
85
- const domain = resolveDomain({
86
- chainId: 8453,
87
- token: "USDC",
88
- });
52
+ import { buildMessage, nowPlusSeconds, randomNonce } from "@seapay-ai/erc3009";
89
53
 
90
- // 2. Build message
91
54
  const message = buildMessage({
92
55
  from: "0xSender...",
93
56
  to: "0xRecipient...",
94
- value: 1000000n,
95
- validAfter: 0n,
96
- validBefore: 1234567890n,
97
- nonce: "0x...", // or use randomNonce()
57
+ value: 1000000n, // Amount in token's smallest unit
58
+ validAfter: 0n, // Optional, defaults to 0
59
+ validBefore: nowPlusSeconds(300), // Unix timestamp
60
+ nonce: randomNonce(), // Optional, auto-generated if not provided
98
61
  });
99
-
100
- // 3. Build typed data
101
- const typedData = buildTypedData({ domain, message });
102
-
103
- // 4. Sign
104
- const signature = await erc3009.sign(wallet, domain, message);
105
62
  ```
106
63
 
107
- ### 3. Using the Registry
64
+ ### 2. Build Typed Data
108
65
 
109
- Query supported chains and tokens:
66
+ Automatically resolves token info from the registry:
110
67
 
111
68
  ```typescript
112
- import { registry, getToken, CHAINS } from "@seapay-ai/erc3009";
113
-
114
- // Get token config
115
- const usdcBase = getToken("USDC", 8453);
116
- // => { symbol: "USDC", chainId: 8453, verifyingContract: "0x...", ... }
117
-
118
- // List all chains
119
- const chains = registry.listChains();
69
+ import { buildTypedData } from "@seapay-ai/erc3009";
120
70
 
121
- // Check support
122
- if (registry.isTokenSupported("USDC", 8453)) {
123
- console.log("USDC is supported on Base");
124
- }
71
+ const typedData = buildTypedData({
72
+ chainId: 8453, // Base mainnet
73
+ token: "USDC", // Symbol from registry
74
+ message,
75
+ });
125
76
 
126
- // List tokens on a chain
127
- const tokens = registry.listTokensOnChain(8453);
77
+ // Returns:
78
+ // {
79
+ // domain: { name, version, chainId, verifyingContract },
80
+ // types: { TransferWithAuthorization: [...] },
81
+ // message: { from, to, value, ... },
82
+ // primaryType: "TransferWithAuthorization"
83
+ // }
128
84
  ```
129
85
 
130
- ### 4. Custom Tokens / Domain Overrides
131
-
132
86
  For custom tokens not in the registry:
133
87
 
134
88
  ```typescript
135
- import { prepare } from "@seapay-ai/erc3009";
136
-
137
- const { typedData } = prepare({
89
+ const typedData = buildTypedData({
138
90
  chainId: 8453,
139
91
  token: "0xCustomTokenAddress",
140
- // Override domain fields
141
- name: "My Custom Token",
92
+ message,
93
+ domainOverrides: {
94
+ name: "My Token",
95
+ version: "1",
96
+ verifyingContract: "0xCustomTokenAddress",
97
+ },
98
+ });
99
+ ```
100
+
101
+ ### 3. Resolve Domain
102
+
103
+ Resolve EIP-712 domain from chain ID and token:
104
+
105
+ ```typescript
106
+ import { resolveDomain } from "@seapay-ai/erc3009";
107
+
108
+ // Resolve USDC domain on Base
109
+ const domain = resolveDomain(8453, "USDC");
110
+ // Returns:
111
+ // {
112
+ // name: "USD Coin",
113
+ // version: "2",
114
+ // chainId: 8453,
115
+ // verifyingContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
116
+ // }
117
+
118
+ // For custom tokens
119
+ const customDomain = resolveDomain(8453, "0xCustomTokenAddress", {
120
+ name: "My Token",
142
121
  version: "1",
143
122
  verifyingContract: "0xCustomTokenAddress",
144
- from: "0xSender...",
145
- to: "0xRecipient...",
146
- value: 1000000n,
147
123
  });
148
124
  ```
149
125
 
150
- ### 5. Signature Verification
126
+ This function is useful when you need just the domain object without building the complete typed data structure. It's used internally by `buildTypedData`.
127
+
128
+ ### 4. Verify Signature
151
129
 
152
130
  ```typescript
153
131
  import { verifySignature, recoverSigner } from "@seapay-ai/erc3009";
154
132
 
155
- // Recover signer
156
- const recovered = recoverSigner(domain, message, signature);
157
- console.log("Signed by:", recovered);
158
-
159
- // Verify signature
133
+ // Verify signature matches expected signer
160
134
  const isValid = verifySignature(domain, message, signature, expectedSigner);
135
+
136
+ // Or recover the signer address
137
+ const signer = recoverSigner(domain, message, signature);
138
+ console.log("Signed by:", signer);
161
139
  ```
162
140
 
163
- ## Supported Chains
141
+ ## Registry
142
+
143
+ The package includes a built-in registry of USDC deployments across multiple chains.
144
+
145
+ ### Query the Registry
146
+
147
+ ```typescript
148
+ import { registry, getTokenInfo } from "@seapay-ai/erc3009";
149
+
150
+ // Get token config
151
+ const usdcBase = registry.getToken("USDC", 8453);
152
+ // => { symbol: "USDC", chainId: 8453, address: "0x...", name: "USD Coin", version: "2", decimals: 6 }
153
+
154
+ // Check if token is supported
155
+ if (registry.isSupported("USDC", 8453)) {
156
+ console.log("USDC supported on Base");
157
+ }
158
+
159
+ // List all chains
160
+ const chains = registry.listChains();
161
+
162
+ // List tokens on a chain
163
+ const tokens = registry.listTokensOnChain(8453);
164
+
165
+ // Get chain info
166
+ const baseChain = registry.getChain(8453);
167
+ // => { chainId: 8453, name: "Base", testnet: false }
168
+ ```
169
+
170
+ ### Supported Chains
164
171
 
165
172
  | Chain | Chain ID | Testnet |
166
173
  | ---------------- | -------- | ------- |
@@ -175,81 +182,93 @@ const isValid = verifySignature(domain, message, signature, expectedSigner);
175
182
  | Polygon | 137 | - |
176
183
  | Polygon Amoy | 80002 | ✅ |
177
184
 
178
- ## Supported Tokens
179
-
180
- Currently supports **USDC** on all chains above. The registry includes:
185
+ ### Supported Tokens
181
186
 
182
- - Proxy contract addresses
183
- - EIP-712 domain parameters (name, version)
184
- - Token decimals
187
+ Currently includes **USDC** on all chains above.
185
188
 
186
189
  ### ⚠️ Important: Base Network Domain Names
187
190
 
188
- USDC has **different domain names** on Base networks:
191
+ USDC has **different EIP-712 domain names** on Base networks:
189
192
 
190
193
  | Network | Chain ID | Domain Name |
191
194
  | ------------ | -------- | ------------ |
192
195
  | Base Mainnet | 8453 | `"USD Coin"` |
193
196
  | Base Sepolia | 84532 | `"USDC"` |
194
197
 
195
- **This is critical for signature verification!** Always use the correct domain name:
198
+ The registry handles this automatically. Always use the registry to ensure correct domain parameters.
199
+
200
+ ## Complete Example
196
201
 
197
202
  ```typescript
198
- // ✅ Correct - Base Mainnet
199
- const { typedData } = prepare({
200
- chainId: 8453,
201
- token: "USDC", // Resolves to name: "USD Coin"
202
- from: "0x...",
203
- to: "0x...",
204
- value: 1000000n,
205
- });
203
+ import {
204
+ buildTypedData,
205
+ buildMessage,
206
+ nowPlusSeconds,
207
+ verifySignature,
208
+ } from "@seapay-ai/erc3009";
209
+ import { Wallet } from "ethers";
210
+
211
+ // Create wallet
212
+ const wallet = new Wallet("0x...");
206
213
 
207
- // Correct - Base Sepolia
208
- const { typedData } = prepare({
209
- chainId: 84532,
210
- token: "USDC", // Resolves to name: "USDC"
211
- from: "0x...",
212
- to: "0x...",
213
- value: 1000000n,
214
+ // Build message
215
+ const message = buildMessage({
216
+ from: wallet.address,
217
+ to: "0xRecipient...",
218
+ value: 1000000n, // 1 USDC
219
+ validBefore: nowPlusSeconds(300), // 5 minutes
214
220
  });
215
221
 
216
- // Wrong - Signature will fail!
217
- const { typedData } = prepare({
218
- chainId: 84532,
222
+ // Build typed data
223
+ const {
224
+ domain,
225
+ types,
226
+ message: msg,
227
+ } = buildTypedData({
228
+ chainId: 84532, // Base Sepolia
219
229
  token: "USDC",
220
- name: "USD Coin", // Override with wrong name
221
- // ...
230
+ message,
222
231
  });
223
- ```
224
232
 
225
- The `prepare()` function automatically uses the correct domain name from the registry.
233
+ // Sign
234
+ const signature = await wallet.signTypedData(domain, types, msg);
235
+
236
+ // Verify
237
+ const isValid = verifySignature(domain, message, signature, wallet.address);
238
+ console.log("Signature valid:", isValid);
239
+ ```
226
240
 
227
241
  ## API Reference
228
242
 
229
- ### Core Functions
243
+ ### Build Functions
244
+
245
+ - **`buildMessage(params)`** - Create TransferWithAuthorization message
246
+ - **`buildTypedData(params)`** - Create complete EIP-712 typed data with domain resolution
247
+
248
+ ### Domain Resolution
249
+
250
+ - **`resolveDomain(chainId, token, domainOverrides?)`** - Resolve EIP-712 domain from chain and token
251
+
252
+ ### Verification Functions
230
253
 
231
- - `prepare(params)` - One-call API to build everything
232
- - `buildMessage(params)` - Build TransferWithAuthorization message
233
- - `buildTypedData({ domain, message })` - Build EIP-712 typed data
234
- - `resolveDomain({ chainId, token, ...overrides })` - Resolve EIP-712 domain
235
- - `erc3009.sign(wallet, domain, message)` - Sign with ethers wallet
236
- - `verifySignature(domain, message, sig, signer)` - Verify signature
237
- - `recoverSigner(domain, message, sig)` - Recover signer address
254
+ - **`verifySignature(domain, message, signature, expectedSigner)`** - Verify signature
255
+ - **`recoverSigner(domain, message, signature)`** - Recover signer address
238
256
 
239
- ### Registry
257
+ ### Registry Functions
240
258
 
241
- - `registry.getToken(symbol, chainId)` - Get token config
242
- - `registry.getChain(chainId)` - Get chain config
243
- - `registry.listChains()` - List all supported chains
244
- - `registry.listTokensOnChain(chainId)` - List tokens on a chain
245
- - `registry.isTokenSupported(symbol, chainId)` - Check support
259
+ - **`getTokenInfo(symbol, chainId)`** - Get token configuration
260
+ - **`registry.getToken(symbol, chainId)`** - Get token config
261
+ - **`registry.getChain(chainId)`** - Get chain config
262
+ - **`registry.listChains()`** - List all chains
263
+ - **`registry.listChainIds()`** - List all chain IDs
264
+ - **`registry.isSupported(symbol, chainId)`** - Check if token is supported
265
+ - **`registry.listTokensOnChain(chainId)`** - List tokens on a chain
246
266
 
247
- ### Utils
267
+ ### Utility Functions
248
268
 
249
- - `randomNonce()` - Generate random bytes32 nonce
250
- - `nowSeconds()` - Current Unix timestamp
251
- - `nowPlusSeconds(n)` - Unix timestamp N seconds from now
252
- - `normalizeAddress(addr)` - Normalize to checksum address
269
+ - **`randomNonce()`** - Generate random bytes32 nonce
270
+ - **`nowPlusSeconds(seconds)`** - Get Unix timestamp N seconds from now
271
+ - **`nowSeconds()`** - Get current Unix timestamp
253
272
 
254
273
  ## TypeScript Types
255
274
 
@@ -257,44 +276,12 @@ The `prepare()` function automatically uses the correct domain name from the reg
257
276
  import type {
258
277
  TransferWithAuthorization,
259
278
  EIP712Domain,
279
+ TypedData,
260
280
  TokenConfig,
261
281
  ChainConfig,
262
- PrepareParams,
263
282
  } from "@seapay-ai/erc3009";
264
283
  ```
265
284
 
266
- ## Advanced: Custom Registry
267
-
268
- You can extend the registry by directly importing and modifying `TOKENS`:
269
-
270
- ```typescript
271
- import { TOKENS } from "@seapay-ai/erc3009";
272
-
273
- // Add your custom token
274
- TOKENS["MYTOKEN"] = {
275
- 8453: {
276
- symbol: "MYTOKEN",
277
- chainId: 8453,
278
- verifyingContract: "0x...",
279
- name: "My Token",
280
- version: "1",
281
- decimals: 18,
282
- },
283
- };
284
- ```
285
-
286
- ## Examples
287
-
288
- See the `/apps/erc3009-relay/src/signer-test.ts` in the monorepo for a complete working example.
289
-
290
- ## Contributing
291
-
292
- Contributions welcome! To add support for a new token:
293
-
294
- 1. Add token config to `src/registry/tokens/{token}.ts`
295
- 2. Export from `src/registry/tokens/index.ts`
296
- 3. Add to `TOKENS` registry
297
-
298
285
  ## License
299
286
 
300
287
  Apache-2.0
@@ -0,0 +1,27 @@
1
+ import type { TransferWithAuthorization, EIP712Domain, TypedData } from "./types/index.js";
2
+ /**
3
+ * Build TransferWithAuthorization message
4
+ */
5
+ export declare function buildMessage(params: {
6
+ from: string;
7
+ to: string;
8
+ value: bigint;
9
+ validAfter?: bigint;
10
+ validBefore: bigint;
11
+ nonce?: string;
12
+ }): TransferWithAuthorization;
13
+ /**
14
+ * Build complete EIP-712 typed data for signing
15
+ *
16
+ * @param chainId - Chain ID (e.g. 8453 for Base)
17
+ * @param token - Token symbol (e.g. "USDC") or contract address
18
+ * @param message - TransferWithAuthorization message
19
+ * @param domainOverrides - Optional domain parameter overrides for custom tokens
20
+ */
21
+ export declare function buildTypedData(params: {
22
+ chainId: number;
23
+ token: string;
24
+ message: TransferWithAuthorization;
25
+ domainOverrides?: Partial<EIP712Domain>;
26
+ }): TypedData;
27
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../src/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,YAAY,EACZ,SAAS,EACV,MAAM,kBAAkB,CAAC;AAgB1B;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,yBAAyB,CAS5B;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,yBAAyB,CAAC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;CACzC,GAAG,SAAS,CAcZ"}
package/dist/build.js ADDED
@@ -0,0 +1,47 @@
1
+ import { randomNonce } from "./utils.js";
2
+ import { resolveDomain } from "./domain.js";
3
+ /**
4
+ * ERC-3009 TransferWithAuthorization type definition
5
+ */
6
+ const TRANSFER_WITH_AUTHORIZATION_TYPE = [
7
+ { name: "from", type: "address" },
8
+ { name: "to", type: "address" },
9
+ { name: "value", type: "uint256" },
10
+ { name: "validAfter", type: "uint256" },
11
+ { name: "validBefore", type: "uint256" },
12
+ { name: "nonce", type: "bytes32" },
13
+ ];
14
+ /**
15
+ * Build TransferWithAuthorization message
16
+ */
17
+ export function buildMessage(params) {
18
+ return {
19
+ from: params.from,
20
+ to: params.to,
21
+ value: params.value,
22
+ validAfter: params.validAfter ?? 0n,
23
+ validBefore: params.validBefore,
24
+ nonce: params.nonce ?? randomNonce(),
25
+ };
26
+ }
27
+ /**
28
+ * Build complete EIP-712 typed data for signing
29
+ *
30
+ * @param chainId - Chain ID (e.g. 8453 for Base)
31
+ * @param token - Token symbol (e.g. "USDC") or contract address
32
+ * @param message - TransferWithAuthorization message
33
+ * @param domainOverrides - Optional domain parameter overrides for custom tokens
34
+ */
35
+ export function buildTypedData(params) {
36
+ const { chainId, token, message, domainOverrides } = params;
37
+ // Resolve domain using the resolveDomain function
38
+ const domain = resolveDomain(chainId, token, domainOverrides);
39
+ return {
40
+ domain,
41
+ types: {
42
+ TransferWithAuthorization: TRANSFER_WITH_AUTHORIZATION_TYPE,
43
+ },
44
+ message,
45
+ primaryType: "TransferWithAuthorization",
46
+ };
47
+ }
@@ -0,0 +1,29 @@
1
+ import type { EIP712Domain } from "./types/index.js";
2
+ /**
3
+ * Resolve EIP-712 domain from chain ID and token
4
+ *
5
+ * @param chainId - Chain ID (e.g. 8453 for Base)
6
+ * @param token - Token symbol (e.g. "USDC") or contract address (0x...)
7
+ * @param domainOverrides - Optional domain parameter overrides for custom tokens
8
+ * @returns EIP-712 Domain object
9
+ *
10
+ * @example
11
+ * // Resolve USDC on Base
12
+ * const domain = resolveDomain(8453, "USDC");
13
+ * // Returns:
14
+ * // {
15
+ * // name: "USD Coin",
16
+ * // version: "2",
17
+ * // chainId: 8453,
18
+ * // verifyingContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
19
+ * // }
20
+ *
21
+ * @example
22
+ * // Resolve custom token with overrides
23
+ * const domain = resolveDomain(8453, "0x123...", {
24
+ * name: "My Token",
25
+ * version: "1"
26
+ * });
27
+ */
28
+ export declare function resolveDomain(chainId: number, token: string, domainOverrides?: Partial<EIP712Domain>): EIP712Domain;
29
+ //# sourceMappingURL=domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.ts","sourceRoot":"","sources":["../src/domain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,eAAe,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GACtC,YAAY,CAmCd"}
package/dist/domain.js ADDED
@@ -0,0 +1,57 @@
1
+ import { getTokenInfo } from "./registry.js";
2
+ /**
3
+ * Resolve EIP-712 domain from chain ID and token
4
+ *
5
+ * @param chainId - Chain ID (e.g. 8453 for Base)
6
+ * @param token - Token symbol (e.g. "USDC") or contract address (0x...)
7
+ * @param domainOverrides - Optional domain parameter overrides for custom tokens
8
+ * @returns EIP-712 Domain object
9
+ *
10
+ * @example
11
+ * // Resolve USDC on Base
12
+ * const domain = resolveDomain(8453, "USDC");
13
+ * // Returns:
14
+ * // {
15
+ * // name: "USD Coin",
16
+ * // version: "2",
17
+ * // chainId: 8453,
18
+ * // verifyingContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
19
+ * // }
20
+ *
21
+ * @example
22
+ * // Resolve custom token with overrides
23
+ * const domain = resolveDomain(8453, "0x123...", {
24
+ * name: "My Token",
25
+ * version: "1"
26
+ * });
27
+ */
28
+ export function resolveDomain(chainId, token, domainOverrides) {
29
+ let domain;
30
+ if (token.startsWith("0x")) {
31
+ // Custom token address - use overrides or fail
32
+ if (!domainOverrides?.name || !domainOverrides?.verifyingContract) {
33
+ throw new Error("Custom token address requires domain overrides (name, verifyingContract)");
34
+ }
35
+ domain = {
36
+ name: domainOverrides.name,
37
+ version: domainOverrides.version ?? "1",
38
+ chainId,
39
+ verifyingContract: domainOverrides.verifyingContract,
40
+ };
41
+ }
42
+ else {
43
+ // Try registry lookup
44
+ const tokenInfo = getTokenInfo(token, chainId);
45
+ if (!tokenInfo) {
46
+ throw new Error(`Token ${token} not found in registry for chain ${chainId}. Use domainOverrides for custom tokens.`);
47
+ }
48
+ domain = {
49
+ name: tokenInfo.name,
50
+ version: tokenInfo.version,
51
+ chainId: tokenInfo.chainId,
52
+ verifyingContract: tokenInfo.address,
53
+ ...domainOverrides, // Allow overriding registry values
54
+ };
55
+ }
56
+ return domain;
57
+ }
package/dist/index.d.ts CHANGED
@@ -1,27 +1,13 @@
1
1
  /**
2
- * @seapay/erc3009
2
+ * @seapay-ai/erc3009
3
3
  *
4
- * Multi-chain ERC-3009 (TransferWithAuthorization) helper library
4
+ * Simplified ERC-3009 (TransferWithAuthorization) library
5
5
  * for building, signing, and verifying EIP-712 typed data.
6
6
  */
7
- export type { TransferWithAuthorization, EIP712Domain, DomainOverrides, ResolveDomainParams, ChainConfig, TokenConfig, TokenRegistry, } from "./types/index.js";
8
- export { erc3009 } from "./core.js";
9
- export { buildTypes, buildMessage, buildMessageWithTTL, buildTypedData, signTransferWithAuthorization, recoverSigner, verifySignature, TRANSFER_WITH_AUTHORIZATION_TYPE, PRIMARY_TYPE, } from "./erc3009/index.js";
10
- export { resolveDomain, resolveDomainFromToken, normalizeAddress, normalizeChainId, } from "./domain/index.js";
11
- export { CHAINS, getChain, listChains, listChainIds, isChainSupported, TOKENS, USDC, getUSDC, isUSDCSupported, listUSDCChains, listTokenSymbols, getToken, getTokenByAddress, listTokensOnChain, isTokenSupported, } from "./registry/index.js";
12
- export { randomNonce, nowSeconds, nowPlusSeconds, toBigInt, ensureHex, isBytes32Hex, } from "./utils/index.js";
13
- export { prepare } from "./api/index.js";
14
- export type { PrepareParams, PrepareResult } from "./api/prepare.js";
15
- import * as registryFunctions from "./registry/registry.js";
16
- export declare const registry: {
17
- readonly getToken: typeof registryFunctions.getToken;
18
- readonly getTokenByAddress: typeof registryFunctions.getTokenByAddress;
19
- readonly getChain: typeof registryFunctions.getChain;
20
- readonly listChains: typeof registryFunctions.listChains;
21
- readonly listChainIds: typeof registryFunctions.listChainIds;
22
- readonly listTokenSymbols: typeof registryFunctions.listTokenSymbols;
23
- readonly listTokensOnChain: typeof registryFunctions.listTokensOnChain;
24
- readonly isTokenSupported: typeof registryFunctions.isTokenSupported;
25
- readonly isChainSupported: typeof registryFunctions.isChainSupported;
26
- };
7
+ export type { TransferWithAuthorization, EIP712Domain, TypedData, TokenConfig, ChainConfig, } from "./types/index.js";
8
+ export { registry, getTokenInfo } from "./registry.js";
9
+ export { resolveDomain } from "./domain.js";
10
+ export { buildTypedData, buildMessage } from "./build.js";
11
+ export { verifySignature, recoverSigner } from "./verify.js";
12
+ export { randomNonce, nowPlusSeconds } from "./utils.js";
27
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,yBAAyB,EACzB,YAAY,EACZ,eAAe,EACf,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,aAAa,GACd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,OAAO,EACL,UAAU,EACV,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,6BAA6B,EAC7B,aAAa,EACb,eAAe,EACf,gCAAgC,EAChC,YAAY,GACb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,aAAa,EACb,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAEL,MAAM,EACN,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,gBAAgB,EAEhB,MAAM,EACN,IAAI,EACJ,OAAO,EACP,eAAe,EACf,cAAc,EACd,gBAAgB,EAEhB,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,WAAW,EACX,UAAU,EACV,cAAc,EACd,QAAQ,EACR,SAAS,EACT,YAAY,GACb,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGrE,OAAO,KAAK,iBAAiB,MAAM,wBAAwB,CAAC;AAC5D,eAAO,MAAM,QAAQ;;;;;;;;;;CAUX,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,yBAAyB,EACzB,YAAY,EACZ,SAAS,EACT,WAAW,EACX,WAAW,GACZ,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1D,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG7D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}