@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.
- package/README.md +171 -184
- package/dist/build.d.ts +27 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +47 -0
- package/dist/domain.d.ts +29 -0
- package/dist/domain.d.ts.map +1 -0
- package/dist/domain.js +57 -0
- package/dist/index.d.ts +8 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -31
- package/dist/registry.d.ts +44 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +166 -0
- package/dist/types/index.d.ts +44 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -3
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +19 -0
- package/dist/verify.d.ts +14 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +36 -0
- package/package.json +8 -7
- package/dist/api/index.d.ts +0 -2
- package/dist/api/index.d.ts.map +0 -1
- package/dist/api/index.js +0 -1
- package/dist/api/prepare.d.ts +0 -47
- package/dist/api/prepare.d.ts.map +0 -1
- package/dist/api/prepare.js +0 -57
- package/dist/core.d.ts +0 -14
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js +0 -13
- package/dist/domain/index.d.ts +0 -3
- package/dist/domain/index.d.ts.map +0 -1
- package/dist/domain/index.js +0 -2
- package/dist/domain/normalize.d.ts +0 -9
- package/dist/domain/normalize.d.ts.map +0 -1
- package/dist/domain/normalize.js +0 -25
- package/dist/domain/resolveDomain.d.ts +0 -15
- package/dist/domain/resolveDomain.d.ts.map +0 -1
- package/dist/domain/resolveDomain.js +0 -47
- package/dist/erc3009/buildTypes.d.ts +0 -6
- package/dist/erc3009/buildTypes.d.ts.map +0 -1
- package/dist/erc3009/buildTypes.js +0 -11
- package/dist/erc3009/constants.d.ts +0 -7
- package/dist/erc3009/constants.d.ts.map +0 -1
- package/dist/erc3009/constants.js +0 -6
- package/dist/erc3009/index.d.ts +0 -7
- package/dist/erc3009/index.d.ts.map +0 -1
- package/dist/erc3009/index.js +0 -6
- package/dist/erc3009/message.d.ts +0 -21
- package/dist/erc3009/message.d.ts.map +0 -1
- package/dist/erc3009/message.js +0 -29
- package/dist/erc3009/sign.d.ts +0 -7
- package/dist/erc3009/sign.d.ts.map +0 -1
- package/dist/erc3009/sign.js +0 -8
- package/dist/erc3009/typedData.d.ts +0 -15
- package/dist/erc3009/typedData.d.ts.map +0 -1
- package/dist/erc3009/typedData.js +0 -21
- package/dist/erc3009/verify.d.ts +0 -10
- package/dist/erc3009/verify.d.ts.map +0 -1
- package/dist/erc3009/verify.js +0 -17
- package/dist/registry/chains.d.ts +0 -22
- package/dist/registry/chains.d.ts.map +0 -1
- package/dist/registry/chains.js +0 -104
- package/dist/registry/index.d.ts +0 -4
- package/dist/registry/index.d.ts.map +0 -1
- package/dist/registry/index.js +0 -6
- package/dist/registry/registry.d.ts +0 -38
- package/dist/registry/registry.d.ts.map +0 -1
- package/dist/registry/registry.js +0 -73
- package/dist/registry/tokens/index.d.ts +0 -11
- package/dist/registry/tokens/index.d.ts.map +0 -1
- package/dist/registry/tokens/index.js +0 -14
- package/dist/registry/tokens/usdc.d.ts +0 -27
- package/dist/registry/tokens/usdc.d.ts.map +0 -1
- package/dist/registry/tokens/usdc.js +0 -104
- package/dist/types/domain.d.ts +0 -24
- package/dist/types/domain.d.ts.map +0 -1
- package/dist/types/domain.js +0 -1
- package/dist/types/erc3009.d.ts +0 -38
- package/dist/types/erc3009.d.ts.map +0 -1
- package/dist/types/erc3009.js +0 -15
- package/dist/types/registry.d.ts +0 -35
- package/dist/types/registry.d.ts.map +0 -1
- package/dist/types/registry.js +0 -1
- package/dist/utils/hex.d.ts +0 -13
- package/dist/utils/hex.d.ts.map +0 -1
- package/dist/utils/hex.js +0 -19
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js +0 -3
- package/dist/utils/nonce.d.ts +0 -5
- package/dist/utils/nonce.d.ts.map +0 -1
- package/dist/utils/nonce.js +0 -7
- package/dist/utils/time.d.ts +0 -13
- package/dist/utils/time.d.ts.map +0 -1
- package/dist/utils/time.js +0 -18
package/dist/index.js
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @seapay/erc3009
|
|
2
|
+
* @seapay-ai/erc3009
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Simplified ERC-3009 (TransferWithAuthorization) library
|
|
5
5
|
* for building, signing, and verifying EIP-712 typed data.
|
|
6
6
|
*/
|
|
7
|
-
// === Core ERC-3009 Namespace ===
|
|
8
|
-
export { erc3009 } from "./core.js";
|
|
9
|
-
// === Core Functions (individual exports) ===
|
|
10
|
-
export { buildTypes, buildMessage, buildMessageWithTTL, buildTypedData, signTransferWithAuthorization, recoverSigner, verifySignature, TRANSFER_WITH_AUTHORIZATION_TYPE, PRIMARY_TYPE, } from "./erc3009/index.js";
|
|
11
|
-
// === Domain Resolution ===
|
|
12
|
-
export { resolveDomain, resolveDomainFromToken, normalizeAddress, normalizeChainId, } from "./domain/index.js";
|
|
13
7
|
// === Registry ===
|
|
14
|
-
export {
|
|
15
|
-
//
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
8
|
+
export { registry, getTokenInfo } from "./registry.js";
|
|
9
|
+
// === Domain Resolution ===
|
|
10
|
+
export { resolveDomain } from "./domain.js";
|
|
11
|
+
// === Build Functions ===
|
|
12
|
+
export { buildTypedData, buildMessage } from "./build.js";
|
|
13
|
+
// === Verify Functions ===
|
|
14
|
+
export { verifySignature, recoverSigner } from "./verify.js";
|
|
21
15
|
// === Utils ===
|
|
22
|
-
export { randomNonce,
|
|
23
|
-
// === Ergonomic API ===
|
|
24
|
-
export { prepare } from "./api/index.js";
|
|
25
|
-
// === Registry object (for namespaced access) ===
|
|
26
|
-
import * as registryFunctions from "./registry/registry.js";
|
|
27
|
-
export const registry = {
|
|
28
|
-
getToken: registryFunctions.getToken,
|
|
29
|
-
getTokenByAddress: registryFunctions.getTokenByAddress,
|
|
30
|
-
getChain: registryFunctions.getChain,
|
|
31
|
-
listChains: registryFunctions.listChains,
|
|
32
|
-
listChainIds: registryFunctions.listChainIds,
|
|
33
|
-
listTokenSymbols: registryFunctions.listTokenSymbols,
|
|
34
|
-
listTokensOnChain: registryFunctions.listTokensOnChain,
|
|
35
|
-
isTokenSupported: registryFunctions.isTokenSupported,
|
|
36
|
-
isChainSupported: registryFunctions.isChainSupported,
|
|
37
|
-
};
|
|
16
|
+
export { randomNonce, nowPlusSeconds } from "./utils.js";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { TokenConfig, ChainConfig } from "./types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Chain registry - supported chains
|
|
4
|
+
*/
|
|
5
|
+
export declare const CHAINS: Record<number, ChainConfig>;
|
|
6
|
+
/**
|
|
7
|
+
* Token registry - USDC addresses and domain parameters per chain
|
|
8
|
+
* Note: Base mainnet uses "USD Coin" while Base Sepolia uses "USDC"
|
|
9
|
+
*/
|
|
10
|
+
export declare const TOKENS: Record<string, Record<number, TokenConfig>>;
|
|
11
|
+
/**
|
|
12
|
+
* Get token information for a given chain
|
|
13
|
+
*/
|
|
14
|
+
export declare function getTokenInfo(tokenSymbol: string, chainId: number): TokenConfig | null;
|
|
15
|
+
/**
|
|
16
|
+
* Registry utilities
|
|
17
|
+
*/
|
|
18
|
+
export declare const registry: {
|
|
19
|
+
/**
|
|
20
|
+
* Get token configuration
|
|
21
|
+
*/
|
|
22
|
+
readonly getToken: (symbol: string, chainId: number) => TokenConfig | null;
|
|
23
|
+
/**
|
|
24
|
+
* Get chain configuration
|
|
25
|
+
*/
|
|
26
|
+
readonly getChain: (chainId: number) => ChainConfig | null;
|
|
27
|
+
/**
|
|
28
|
+
* List all supported chains
|
|
29
|
+
*/
|
|
30
|
+
readonly listChains: () => ChainConfig[];
|
|
31
|
+
/**
|
|
32
|
+
* List all supported chain IDs
|
|
33
|
+
*/
|
|
34
|
+
readonly listChainIds: () => number[];
|
|
35
|
+
/**
|
|
36
|
+
* Check if a token is supported on a chain
|
|
37
|
+
*/
|
|
38
|
+
readonly isSupported: (symbol: string, chainId: number) => boolean;
|
|
39
|
+
/**
|
|
40
|
+
* List all tokens on a chain
|
|
41
|
+
*/
|
|
42
|
+
readonly listTokensOnChain: (chainId: number) => TokenConfig[];
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEjE;;GAEG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAW9C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAwF9D,CAAC;AAEF;;GAEG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,GACd,WAAW,GAAG,IAAI,CAMpB;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ;IACnB;;OAEG;gCACgB,MAAM,WAAW,MAAM,KAAG,WAAW,GAAG,IAAI;IAI/D;;OAEG;iCACiB,MAAM,KAAG,WAAW,GAAG,IAAI;IAI/C;;OAEG;+BACa,WAAW,EAAE;IAI7B;;OAEG;iCACe,MAAM,EAAE;IAI1B;;OAEG;mCACmB,MAAM,WAAW,MAAM,KAAG,OAAO;IAIvD;;OAEG;0CAC0B,MAAM,KAAG,WAAW,EAAE;CAU3C,CAAC"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain registry - supported chains
|
|
3
|
+
*/
|
|
4
|
+
export const CHAINS = {
|
|
5
|
+
1: { chainId: 1, name: "Ethereum", testnet: false },
|
|
6
|
+
11155111: { chainId: 11155111, name: "Sepolia", testnet: true },
|
|
7
|
+
8453: { chainId: 8453, name: "Base", testnet: false },
|
|
8
|
+
84532: { chainId: 84532, name: "Base Sepolia", testnet: true },
|
|
9
|
+
42161: { chainId: 42161, name: "Arbitrum One", testnet: false },
|
|
10
|
+
421614: { chainId: 421614, name: "Arbitrum Sepolia", testnet: true },
|
|
11
|
+
10: { chainId: 10, name: "Optimism", testnet: false },
|
|
12
|
+
11155420: { chainId: 11155420, name: "Optimism Sepolia", testnet: true },
|
|
13
|
+
137: { chainId: 137, name: "Polygon", testnet: false },
|
|
14
|
+
80002: { chainId: 80002, name: "Polygon Amoy", testnet: true },
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Token registry - USDC addresses and domain parameters per chain
|
|
18
|
+
* Note: Base mainnet uses "USD Coin" while Base Sepolia uses "USDC"
|
|
19
|
+
*/
|
|
20
|
+
export const TOKENS = {
|
|
21
|
+
USDC: {
|
|
22
|
+
// Ethereum
|
|
23
|
+
1: {
|
|
24
|
+
symbol: "USDC",
|
|
25
|
+
chainId: 1,
|
|
26
|
+
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
27
|
+
name: "USD Coin",
|
|
28
|
+
version: "2",
|
|
29
|
+
decimals: 6,
|
|
30
|
+
},
|
|
31
|
+
11155111: {
|
|
32
|
+
symbol: "USDC",
|
|
33
|
+
chainId: 11155111,
|
|
34
|
+
address: "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238",
|
|
35
|
+
name: "USD Coin",
|
|
36
|
+
version: "2",
|
|
37
|
+
decimals: 6,
|
|
38
|
+
},
|
|
39
|
+
// Base
|
|
40
|
+
8453: {
|
|
41
|
+
symbol: "USDC",
|
|
42
|
+
chainId: 8453,
|
|
43
|
+
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
44
|
+
name: "USD Coin", // Important: Base mainnet uses "USD Coin"
|
|
45
|
+
version: "2",
|
|
46
|
+
decimals: 6,
|
|
47
|
+
},
|
|
48
|
+
84532: {
|
|
49
|
+
symbol: "USDC",
|
|
50
|
+
chainId: 84532,
|
|
51
|
+
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
52
|
+
name: "USDC", // Important: Base Sepolia uses "USDC"
|
|
53
|
+
version: "2",
|
|
54
|
+
decimals: 6,
|
|
55
|
+
},
|
|
56
|
+
// Arbitrum
|
|
57
|
+
42161: {
|
|
58
|
+
symbol: "USDC",
|
|
59
|
+
chainId: 42161,
|
|
60
|
+
address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
|
|
61
|
+
name: "USD Coin",
|
|
62
|
+
version: "2",
|
|
63
|
+
decimals: 6,
|
|
64
|
+
},
|
|
65
|
+
421614: {
|
|
66
|
+
symbol: "USDC",
|
|
67
|
+
chainId: 421614,
|
|
68
|
+
address: "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
|
|
69
|
+
name: "USD Coin",
|
|
70
|
+
version: "2",
|
|
71
|
+
decimals: 6,
|
|
72
|
+
},
|
|
73
|
+
// Optimism
|
|
74
|
+
10: {
|
|
75
|
+
symbol: "USDC",
|
|
76
|
+
chainId: 10,
|
|
77
|
+
address: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
78
|
+
name: "USD Coin",
|
|
79
|
+
version: "2",
|
|
80
|
+
decimals: 6,
|
|
81
|
+
},
|
|
82
|
+
11155420: {
|
|
83
|
+
symbol: "USDC",
|
|
84
|
+
chainId: 11155420,
|
|
85
|
+
address: "0x5fd84259d66Cd46123540766Be93DFE6D43130D7",
|
|
86
|
+
name: "USD Coin",
|
|
87
|
+
version: "2",
|
|
88
|
+
decimals: 6,
|
|
89
|
+
},
|
|
90
|
+
// Polygon
|
|
91
|
+
137: {
|
|
92
|
+
symbol: "USDC",
|
|
93
|
+
chainId: 137,
|
|
94
|
+
address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
95
|
+
name: "USD Coin",
|
|
96
|
+
version: "2",
|
|
97
|
+
decimals: 6,
|
|
98
|
+
},
|
|
99
|
+
80002: {
|
|
100
|
+
symbol: "USDC",
|
|
101
|
+
chainId: 80002,
|
|
102
|
+
address: "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582",
|
|
103
|
+
name: "USD Coin",
|
|
104
|
+
version: "2",
|
|
105
|
+
decimals: 6,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Get token information for a given chain
|
|
111
|
+
*/
|
|
112
|
+
export function getTokenInfo(tokenSymbol, chainId) {
|
|
113
|
+
const token = TOKENS[tokenSymbol.toUpperCase()];
|
|
114
|
+
if (!token)
|
|
115
|
+
return null;
|
|
116
|
+
const config = token[chainId];
|
|
117
|
+
return config || null;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Registry utilities
|
|
121
|
+
*/
|
|
122
|
+
export const registry = {
|
|
123
|
+
/**
|
|
124
|
+
* Get token configuration
|
|
125
|
+
*/
|
|
126
|
+
getToken: (symbol, chainId) => {
|
|
127
|
+
return getTokenInfo(symbol, chainId);
|
|
128
|
+
},
|
|
129
|
+
/**
|
|
130
|
+
* Get chain configuration
|
|
131
|
+
*/
|
|
132
|
+
getChain: (chainId) => {
|
|
133
|
+
return CHAINS[chainId] || null;
|
|
134
|
+
},
|
|
135
|
+
/**
|
|
136
|
+
* List all supported chains
|
|
137
|
+
*/
|
|
138
|
+
listChains: () => {
|
|
139
|
+
return Object.values(CHAINS);
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* List all supported chain IDs
|
|
143
|
+
*/
|
|
144
|
+
listChainIds: () => {
|
|
145
|
+
return Object.keys(CHAINS).map(Number);
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* Check if a token is supported on a chain
|
|
149
|
+
*/
|
|
150
|
+
isSupported: (symbol, chainId) => {
|
|
151
|
+
return getTokenInfo(symbol, chainId) !== null;
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* List all tokens on a chain
|
|
155
|
+
*/
|
|
156
|
+
listTokensOnChain: (chainId) => {
|
|
157
|
+
const tokens = [];
|
|
158
|
+
for (const symbol of Object.keys(TOKENS)) {
|
|
159
|
+
const config = TOKENS[symbol][chainId];
|
|
160
|
+
if (config) {
|
|
161
|
+
tokens.push(config);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return tokens;
|
|
165
|
+
},
|
|
166
|
+
};
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { TypedDataDomain, TypedDataField } from "ethers";
|
|
2
|
+
/**
|
|
3
|
+
* ERC-3009 TransferWithAuthorization message
|
|
4
|
+
*/
|
|
5
|
+
export interface TransferWithAuthorization {
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
value: bigint;
|
|
9
|
+
validAfter: bigint;
|
|
10
|
+
validBefore: bigint;
|
|
11
|
+
nonce: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* EIP-712 Domain
|
|
15
|
+
*/
|
|
16
|
+
export type EIP712Domain = TypedDataDomain;
|
|
17
|
+
/**
|
|
18
|
+
* Token configuration
|
|
19
|
+
*/
|
|
20
|
+
export interface TokenConfig {
|
|
21
|
+
symbol: string;
|
|
22
|
+
chainId: number;
|
|
23
|
+
address: string;
|
|
24
|
+
name: string;
|
|
25
|
+
version: string;
|
|
26
|
+
decimals: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Chain configuration
|
|
30
|
+
*/
|
|
31
|
+
export interface ChainConfig {
|
|
32
|
+
chainId: number;
|
|
33
|
+
name: string;
|
|
34
|
+
testnet: boolean;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Complete EIP-712 typed data structure
|
|
38
|
+
*/
|
|
39
|
+
export interface TypedData {
|
|
40
|
+
domain: EIP712Domain;
|
|
41
|
+
types: Record<string, TypedDataField[]>;
|
|
42
|
+
message: TransferWithAuthorization;
|
|
43
|
+
primaryType: string;
|
|
44
|
+
}
|
|
4
45
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,eAAe,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;IACxC,OAAO,EAAE,yBAAyB,CAAC;IACnC,WAAW,EAAE,MAAM,CAAC;CACrB"}
|
package/dist/types/index.js
CHANGED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a random bytes32 nonce for TransferWithAuthorization
|
|
3
|
+
*/
|
|
4
|
+
export declare function randomNonce(): string;
|
|
5
|
+
/**
|
|
6
|
+
* Get current Unix timestamp + N seconds (for validBefore)
|
|
7
|
+
*/
|
|
8
|
+
export declare function nowPlusSeconds(seconds: number): bigint;
|
|
9
|
+
/**
|
|
10
|
+
* Get current Unix timestamp in seconds
|
|
11
|
+
*/
|
|
12
|
+
export declare function nowSeconds(): bigint;
|
|
13
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { randomBytes, hexlify } from "ethers";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a random bytes32 nonce for TransferWithAuthorization
|
|
4
|
+
*/
|
|
5
|
+
export function randomNonce() {
|
|
6
|
+
return hexlify(randomBytes(32));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get current Unix timestamp + N seconds (for validBefore)
|
|
10
|
+
*/
|
|
11
|
+
export function nowPlusSeconds(seconds) {
|
|
12
|
+
return BigInt(Math.floor(Date.now() / 1000) + seconds);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get current Unix timestamp in seconds
|
|
16
|
+
*/
|
|
17
|
+
export function nowSeconds() {
|
|
18
|
+
return BigInt(Math.floor(Date.now() / 1000));
|
|
19
|
+
}
|
package/dist/verify.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { TransferWithAuthorization, EIP712Domain } from "./types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Recover the signer address from a signature
|
|
4
|
+
*/
|
|
5
|
+
export declare function recoverSigner(domain: EIP712Domain, message: TransferWithAuthorization, signature: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Verify that a signature was created by the expected signer
|
|
8
|
+
*/
|
|
9
|
+
export declare function verifySignature(domain: EIP712Domain, message: TransferWithAuthorization, signature: string, expectedSigner: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Get the EIP-712 hash for a message (useful for debugging)
|
|
12
|
+
*/
|
|
13
|
+
export declare function getMessageHash(domain: EIP712Domain, message: TransferWithAuthorization): string;
|
|
14
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,yBAAyB,EACzB,YAAY,EACb,MAAM,kBAAkB,CAAC;AAc1B;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,yBAAyB,EAClC,SAAS,EAAE,MAAM,GAChB,MAAM,CAOR;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,yBAAyB,EAClC,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,GACrB,OAAO,CAOT;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,yBAAyB,GACjC,MAAM,CAMR"}
|
package/dist/verify.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { TypedDataEncoder, verifyTypedData } from "ethers";
|
|
2
|
+
/**
|
|
3
|
+
* ERC-3009 type definition for signature recovery
|
|
4
|
+
*/
|
|
5
|
+
const TRANSFER_WITH_AUTHORIZATION_TYPE = [
|
|
6
|
+
{ name: "from", type: "address" },
|
|
7
|
+
{ name: "to", type: "address" },
|
|
8
|
+
{ name: "value", type: "uint256" },
|
|
9
|
+
{ name: "validAfter", type: "uint256" },
|
|
10
|
+
{ name: "validBefore", type: "uint256" },
|
|
11
|
+
{ name: "nonce", type: "bytes32" },
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Recover the signer address from a signature
|
|
15
|
+
*/
|
|
16
|
+
export function recoverSigner(domain, message, signature) {
|
|
17
|
+
return verifyTypedData(domain, { TransferWithAuthorization: TRANSFER_WITH_AUTHORIZATION_TYPE }, message, signature);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Verify that a signature was created by the expected signer
|
|
21
|
+
*/
|
|
22
|
+
export function verifySignature(domain, message, signature, expectedSigner) {
|
|
23
|
+
try {
|
|
24
|
+
const recovered = recoverSigner(domain, message, signature);
|
|
25
|
+
return recovered.toLowerCase() === expectedSigner.toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get the EIP-712 hash for a message (useful for debugging)
|
|
33
|
+
*/
|
|
34
|
+
export function getMessageHash(domain, message) {
|
|
35
|
+
return TypedDataEncoder.hash(domain, { TransferWithAuthorization: TRANSFER_WITH_AUTHORIZATION_TYPE }, message);
|
|
36
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seapay-ai/erc3009",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "TypeScript utilities for ERC-3009 (Transfer With Authorization) EIP-712 signing",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"erc3009",
|
|
@@ -30,6 +30,12 @@
|
|
|
30
30
|
"README.md",
|
|
31
31
|
"LICENSE"
|
|
32
32
|
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -b",
|
|
35
|
+
"prepublishOnly": "pnpm build",
|
|
36
|
+
"lint": "echo \"no lint configured\"",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
},
|
|
33
39
|
"dependencies": {
|
|
34
40
|
"ethers": "^6.16.0"
|
|
35
41
|
},
|
|
@@ -43,10 +49,5 @@
|
|
|
43
49
|
},
|
|
44
50
|
"publishConfig": {
|
|
45
51
|
"access": "public"
|
|
46
|
-
},
|
|
47
|
-
"scripts": {
|
|
48
|
-
"build": "tsc -b",
|
|
49
|
-
"lint": "echo \"no lint configured\"",
|
|
50
|
-
"typecheck": "tsc --noEmit"
|
|
51
52
|
}
|
|
52
|
-
}
|
|
53
|
+
}
|
package/dist/api/index.d.ts
DELETED
package/dist/api/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC"}
|
package/dist/api/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./prepare.js";
|
package/dist/api/prepare.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import type { EIP712Domain, TransferWithAuthorization } from "../types/index.js";
|
|
2
|
-
import type { TypedData } from "../erc3009/typedData.js";
|
|
3
|
-
export type PrepareParams = {
|
|
4
|
-
chainId: number;
|
|
5
|
-
token: string;
|
|
6
|
-
name?: string;
|
|
7
|
-
version?: string;
|
|
8
|
-
verifyingContract?: string;
|
|
9
|
-
from: string;
|
|
10
|
-
to: string;
|
|
11
|
-
value: bigint | number | string;
|
|
12
|
-
ttlSeconds?: number;
|
|
13
|
-
nonce?: string;
|
|
14
|
-
validAfter?: bigint | number | string;
|
|
15
|
-
validBefore?: bigint | number | string;
|
|
16
|
-
};
|
|
17
|
-
export type PrepareResult = {
|
|
18
|
-
domain: EIP712Domain;
|
|
19
|
-
message: TransferWithAuthorization;
|
|
20
|
-
typedData: TypedData;
|
|
21
|
-
};
|
|
22
|
-
/**
|
|
23
|
-
* One-call convenience helper to prepare complete ERC-3009 typed data
|
|
24
|
-
*
|
|
25
|
-
* This resolves the domain from registry, builds the message with time window,
|
|
26
|
-
* and returns everything needed for signing.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* ```ts
|
|
30
|
-
* const { domain, message, typedData } = prepare({
|
|
31
|
-
* chainId: 8453,
|
|
32
|
-
* token: "USDC",
|
|
33
|
-
* from: "0x...",
|
|
34
|
-
* to: "0x...",
|
|
35
|
-
* value: 1000000n, // 1 USDC (6 decimals)
|
|
36
|
-
* ttlSeconds: 300, // 5 minutes
|
|
37
|
-
* });
|
|
38
|
-
*
|
|
39
|
-
* const signature = await wallet.signTypedData(
|
|
40
|
-
* typedData.domain,
|
|
41
|
-
* typedData.types,
|
|
42
|
-
* typedData.message
|
|
43
|
-
* );
|
|
44
|
-
* ```
|
|
45
|
-
*/
|
|
46
|
-
export declare function prepare(params: PrepareParams): PrepareResult;
|
|
47
|
-
//# sourceMappingURL=prepare.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.d.ts","sourceRoot":"","sources":["../../src/api/prepare.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,yBAAyB,EAE1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAMzD,MAAM,MAAM,aAAa,GAAG;IAE1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CACxC,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,yBAAyB,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAgC5D"}
|
package/dist/api/prepare.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { resolveDomain } from "../domain/resolveDomain.js";
|
|
2
|
-
import { buildMessageWithTTL } from "../erc3009/message.js";
|
|
3
|
-
import { buildTypedData } from "../erc3009/typedData.js";
|
|
4
|
-
import { randomNonce } from "../utils/nonce.js";
|
|
5
|
-
/**
|
|
6
|
-
* One-call convenience helper to prepare complete ERC-3009 typed data
|
|
7
|
-
*
|
|
8
|
-
* This resolves the domain from registry, builds the message with time window,
|
|
9
|
-
* and returns everything needed for signing.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```ts
|
|
13
|
-
* const { domain, message, typedData } = prepare({
|
|
14
|
-
* chainId: 8453,
|
|
15
|
-
* token: "USDC",
|
|
16
|
-
* from: "0x...",
|
|
17
|
-
* to: "0x...",
|
|
18
|
-
* value: 1000000n, // 1 USDC (6 decimals)
|
|
19
|
-
* ttlSeconds: 300, // 5 minutes
|
|
20
|
-
* });
|
|
21
|
-
*
|
|
22
|
-
* const signature = await wallet.signTypedData(
|
|
23
|
-
* typedData.domain,
|
|
24
|
-
* typedData.types,
|
|
25
|
-
* typedData.message
|
|
26
|
-
* );
|
|
27
|
-
* ```
|
|
28
|
-
*/
|
|
29
|
-
export function prepare(params) {
|
|
30
|
-
// Resolve domain
|
|
31
|
-
const domainParams = {
|
|
32
|
-
chainId: params.chainId,
|
|
33
|
-
token: params.token,
|
|
34
|
-
name: params.name,
|
|
35
|
-
version: params.version,
|
|
36
|
-
verifyingContract: params.verifyingContract,
|
|
37
|
-
};
|
|
38
|
-
const domain = resolveDomain(domainParams);
|
|
39
|
-
// Build message
|
|
40
|
-
const message = buildMessageWithTTL({
|
|
41
|
-
from: params.from,
|
|
42
|
-
to: params.to,
|
|
43
|
-
value: params.value,
|
|
44
|
-
ttlSeconds: params.ttlSeconds,
|
|
45
|
-
nonce: params.nonce ?? randomNonce(),
|
|
46
|
-
});
|
|
47
|
-
// Override time window if explicitly provided
|
|
48
|
-
if (params.validAfter !== undefined) {
|
|
49
|
-
message.validAfter = BigInt(params.validAfter);
|
|
50
|
-
}
|
|
51
|
-
if (params.validBefore !== undefined) {
|
|
52
|
-
message.validBefore = BigInt(params.validBefore);
|
|
53
|
-
}
|
|
54
|
-
// Build typed data
|
|
55
|
-
const typedData = buildTypedData({ domain, message });
|
|
56
|
-
return { domain, message, typedData };
|
|
57
|
-
}
|
package/dist/core.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core ERC-3009 namespace with all builder functions
|
|
3
|
-
*/
|
|
4
|
-
import { buildTypes, buildMessage, buildMessageWithTTL, buildTypedData, signTransferWithAuthorization, recoverSigner, verifySignature } from "./erc3009/index.js";
|
|
5
|
-
export declare const erc3009: {
|
|
6
|
-
readonly buildTypes: typeof buildTypes;
|
|
7
|
-
readonly buildMessage: typeof buildMessage;
|
|
8
|
-
readonly buildMessageWithTTL: typeof buildMessageWithTTL;
|
|
9
|
-
readonly buildTypedData: typeof buildTypedData;
|
|
10
|
-
readonly sign: typeof signTransferWithAuthorization;
|
|
11
|
-
readonly recoverSigner: typeof recoverSigner;
|
|
12
|
-
readonly verifySignature: typeof verifySignature;
|
|
13
|
-
};
|
|
14
|
-
//# sourceMappingURL=core.d.ts.map
|
package/dist/core.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,UAAU,EACV,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,6BAA6B,EAC7B,aAAa,EACb,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,OAAO;;;;;;;;CAQV,CAAC"}
|
package/dist/core.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core ERC-3009 namespace with all builder functions
|
|
3
|
-
*/
|
|
4
|
-
import { buildTypes, buildMessage, buildMessageWithTTL, buildTypedData, signTransferWithAuthorization, recoverSigner, verifySignature, } from "./erc3009/index.js";
|
|
5
|
-
export const erc3009 = {
|
|
6
|
-
buildTypes,
|
|
7
|
-
buildMessage,
|
|
8
|
-
buildMessageWithTTL,
|
|
9
|
-
buildTypedData,
|
|
10
|
-
sign: signTransferWithAuthorization,
|
|
11
|
-
recoverSigner,
|
|
12
|
-
verifySignature,
|
|
13
|
-
};
|
package/dist/domain/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/domain/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC"}
|
package/dist/domain/index.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Normalize address to checksum format
|
|
3
|
-
*/
|
|
4
|
-
export declare function normalizeAddress(address: string): string;
|
|
5
|
-
/**
|
|
6
|
-
* Normalize chainId to number
|
|
7
|
-
*/
|
|
8
|
-
export declare function normalizeChainId(chainId: number | bigint | string): number;
|
|
9
|
-
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/domain/normalize.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAI1E"}
|
package/dist/domain/normalize.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { getAddress } from "ethers";
|
|
2
|
-
/**
|
|
3
|
-
* Normalize address to checksum format
|
|
4
|
-
*/
|
|
5
|
-
export function normalizeAddress(address) {
|
|
6
|
-
try {
|
|
7
|
-
return getAddress(address);
|
|
8
|
-
}
|
|
9
|
-
catch {
|
|
10
|
-
// If invalid address, return lowercase with 0x
|
|
11
|
-
return address.toLowerCase().startsWith("0x")
|
|
12
|
-
? address.toLowerCase()
|
|
13
|
-
: `0x${address.toLowerCase()}`;
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Normalize chainId to number
|
|
18
|
-
*/
|
|
19
|
-
export function normalizeChainId(chainId) {
|
|
20
|
-
if (typeof chainId === "number")
|
|
21
|
-
return chainId;
|
|
22
|
-
if (typeof chainId === "bigint")
|
|
23
|
-
return Number(chainId);
|
|
24
|
-
return parseInt(String(chainId), 10);
|
|
25
|
-
}
|