@x402r/evm 0.0.2 → 0.0.3
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 +20 -16
- package/dist/cjs/escrow/client/index.cjs +227 -0
- package/dist/cjs/escrow/client/index.cjs.map +1 -0
- package/dist/cjs/escrow/client/index.d.cts +23 -0
- package/dist/cjs/escrow/client/index.d.ts +23 -0
- package/dist/cjs/escrow/client/index.js +223 -0
- package/dist/cjs/escrow/client/index.js.map +1 -0
- package/dist/cjs/escrow/facilitator/index.cjs +359 -0
- package/dist/cjs/escrow/facilitator/index.cjs.map +1 -0
- package/dist/cjs/escrow/facilitator/index.d.cts +53 -0
- package/dist/{escrow → cjs/escrow}/facilitator/index.d.ts +17 -13
- package/dist/cjs/escrow/facilitator/index.js +358 -0
- package/dist/cjs/escrow/facilitator/index.js.map +1 -0
- package/dist/cjs/escrow/server/index.cjs +222 -0
- package/dist/cjs/escrow/server/index.cjs.map +1 -0
- package/dist/cjs/escrow/server/index.d.cts +78 -0
- package/dist/{escrow → cjs/escrow}/server/index.d.ts +15 -9
- package/dist/cjs/escrow/server/index.js +217 -0
- package/dist/cjs/escrow/server/index.js.map +1 -0
- package/dist/{shared/types.d.ts → cjs/escrow/types/index.d.ts} +7 -6
- package/dist/cjs/escrow/types/index.js +40 -0
- package/dist/cjs/escrow/types/index.js.map +1 -0
- package/dist/cjs/index.cjs +215 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +22 -0
- package/dist/cjs/index.d.ts +54 -0
- package/dist/cjs/index.js +223 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/scheme-CNrmuyp3.d.ts +22 -0
- package/dist/esm/chunk-DLIBGHEY.mjs +85 -0
- package/dist/esm/chunk-DLIBGHEY.mjs.map +1 -0
- package/dist/esm/chunk-IYUU7AJZ.mjs +187 -0
- package/dist/esm/chunk-IYUU7AJZ.mjs.map +1 -0
- package/dist/esm/chunk-JBHVAJN3.mjs +13 -0
- package/dist/esm/chunk-JBHVAJN3.mjs.map +1 -0
- package/dist/esm/chunk-NSSMTXJJ.mjs +8 -0
- package/dist/esm/chunk-NSSMTXJJ.mjs.map +1 -0
- package/dist/esm/escrow/client/index.d.mts +23 -0
- package/dist/esm/escrow/client/index.mjs +20 -0
- package/dist/esm/escrow/client/index.mjs.map +1 -0
- package/dist/esm/escrow/facilitator/index.d.mts +53 -0
- package/dist/esm/escrow/facilitator/index.mjs +230 -0
- package/dist/esm/escrow/facilitator/index.mjs.map +1 -0
- package/dist/esm/escrow/server/index.d.mts +78 -0
- package/dist/esm/escrow/server/index.mjs +191 -0
- package/dist/esm/escrow/server/index.mjs.map +1 -0
- package/dist/esm/index.d.mts +54 -0
- package/dist/esm/index.mjs +15 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/scheme-CNrmuyp3.d.mts +22 -0
- package/package.json +42 -16
- package/src/escrow/client/index.ts +3 -161
- package/src/escrow/client/register.ts +33 -0
- package/src/escrow/client/scheme.ts +107 -0
- package/src/escrow/facilitator/index.ts +3 -388
- package/src/escrow/facilitator/register.ts +33 -0
- package/src/escrow/facilitator/scheme.ts +289 -0
- package/src/escrow/index.ts +3 -0
- package/src/escrow/server/index.ts +3 -261
- package/src/escrow/server/register.ts +34 -0
- package/src/escrow/server/scheme.ts +226 -0
- package/src/escrow/shared/constants.ts +65 -0
- package/src/escrow/shared/nonce.ts +175 -0
- package/src/escrow/shared/types.ts +69 -0
- package/src/escrow/shared/utils.ts +16 -0
- package/dist/escrow/client/index.d.ts +0 -40
- package/dist/escrow/client/index.d.ts.map +0 -1
- package/dist/escrow/client/index.js +0 -104
- package/dist/escrow/client/index.js.map +0 -1
- package/dist/escrow/facilitator/index.d.ts.map +0 -1
- package/dist/escrow/facilitator/index.js +0 -300
- package/dist/escrow/facilitator/index.js.map +0 -1
- package/dist/escrow/server/index.d.ts.map +0 -1
- package/dist/escrow/server/index.js +0 -214
- package/dist/escrow/server/index.js.map +0 -1
- package/dist/shared/constants.d.ts +0 -112
- package/dist/shared/constants.d.ts.map +0 -1
- package/dist/shared/constants.js +0 -51
- package/dist/shared/constants.js.map +0 -1
- package/dist/shared/nonce.d.ts +0 -41
- package/dist/shared/nonce.d.ts.map +0 -1
- package/dist/shared/nonce.js +0 -154
- package/dist/shared/nonce.js.map +0 -1
- package/dist/shared/types.d.ts.map +0 -1
- package/dist/shared/types.js +0 -21
- package/dist/shared/types.js.map +0 -1
- package/src/shared/constants.ts +0 -58
- package/src/shared/nonce.ts +0 -203
- package/src/shared/types.ts +0 -69
package/dist/shared/constants.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
2
|
-
export const MAX_UINT48 = 281474976710655;
|
|
3
|
-
export const MAX_UINT32 = 4294967295;
|
|
4
|
-
// PaymentInfo struct for AuthCaptureEscrow (matches commerce-payments contract)
|
|
5
|
-
export const PAYMENT_INFO_COMPONENTS = [
|
|
6
|
-
{ name: "operator", type: "address" },
|
|
7
|
-
{ name: "payer", type: "address" },
|
|
8
|
-
{ name: "receiver", type: "address" },
|
|
9
|
-
{ name: "token", type: "address" },
|
|
10
|
-
{ name: "maxAmount", type: "uint120" },
|
|
11
|
-
{ name: "preApprovalExpiry", type: "uint48" },
|
|
12
|
-
{ name: "authorizationExpiry", type: "uint48" },
|
|
13
|
-
{ name: "refundExpiry", type: "uint48" },
|
|
14
|
-
{ name: "minFeeBps", type: "uint16" },
|
|
15
|
-
{ name: "maxFeeBps", type: "uint16" },
|
|
16
|
-
{ name: "feeReceiver", type: "address" },
|
|
17
|
-
{ name: "salt", type: "uint256" },
|
|
18
|
-
];
|
|
19
|
-
export const OPERATOR_ABI = [
|
|
20
|
-
{
|
|
21
|
-
name: "authorize",
|
|
22
|
-
type: "function",
|
|
23
|
-
stateMutability: "nonpayable",
|
|
24
|
-
inputs: [
|
|
25
|
-
{
|
|
26
|
-
name: "paymentInfo",
|
|
27
|
-
type: "tuple",
|
|
28
|
-
components: PAYMENT_INFO_COMPONENTS,
|
|
29
|
-
},
|
|
30
|
-
{ name: "amount", type: "uint256" },
|
|
31
|
-
{ name: "tokenCollector", type: "address" },
|
|
32
|
-
{ name: "collectorData", type: "bytes" },
|
|
33
|
-
],
|
|
34
|
-
outputs: [],
|
|
35
|
-
},
|
|
36
|
-
];
|
|
37
|
-
// ERC-3009 TransferWithAuthorization type hash
|
|
38
|
-
export const TRANSFER_WITH_AUTHORIZATION_TYPEHASH = "0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267";
|
|
39
|
-
// EIP-6492 magic suffix (32 bytes) — appended to signatures from counterfactual smart wallets
|
|
40
|
-
export const ERC6492_MAGIC_VALUE = "0x6492649264926492649264926492649264926492649264926492649264926492";
|
|
41
|
-
// ERC-20 balanceOf ABI for balance checks
|
|
42
|
-
export const ERC20_BALANCE_OF_ABI = [
|
|
43
|
-
{
|
|
44
|
-
name: "balanceOf",
|
|
45
|
-
type: "function",
|
|
46
|
-
stateMutability: "view",
|
|
47
|
-
inputs: [{ name: "account", type: "address" }],
|
|
48
|
-
outputs: [{ name: "balance", type: "uint256" }],
|
|
49
|
-
},
|
|
50
|
-
];
|
|
51
|
-
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,YAAY,GACvB,4CAAqD,CAAC;AACxD,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC;AAC1C,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAC;AAErC,gFAAgF;AAChF,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;IACrC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;IACrC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE;IAClC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IACtC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC7C,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,QAAQ,EAAE;IAC/C,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,EAAE;IACxC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;IACrC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE;IACrC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE;IACxC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE;CACzB,CAAC;AAEX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;QACE,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,YAAY;QAC7B,MAAM,EAAE;YACN;gBACE,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,OAAO;gBACb,UAAU,EAAE,uBAAuB;aACpC;YACD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE;YACnC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,EAAE;YAC3C,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE;SACzC;QACD,OAAO,EAAE,EAAE;KACZ;CACO,CAAC;AAEX,+CAA+C;AAC/C,MAAM,CAAC,MAAM,oCAAoC,GAC/C,oEAA6E,CAAC;AAEhF,8FAA8F;AAC9F,MAAM,CAAC,MAAM,mBAAmB,GAC9B,oEAA6E,CAAC;AAEhF,0CAA0C;AAC1C,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC;QACE,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,MAAM;QACvB,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC9C,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAChD;CACO,CAAC"}
|
package/dist/shared/nonce.d.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nonce computation and ERC-3009 signing utilities
|
|
3
|
-
* Adapted from @agentokratia/x402-escrow (MIT)
|
|
4
|
-
*/
|
|
5
|
-
import type { ClientEvmSigner } from "@x402/evm";
|
|
6
|
-
import type { EscrowExtra, EscrowPayload } from "./types.js";
|
|
7
|
-
/**
|
|
8
|
-
* Compute escrow nonce for ERC-3009 authorization
|
|
9
|
-
* Must match AuthCaptureEscrow.getHash() with payer=address(0)
|
|
10
|
-
*/
|
|
11
|
-
export declare function computeEscrowNonce(chainId: number, escrowAddress: `0x${string}`, paymentInfo: EscrowPayload["paymentInfo"]): `0x${string}`;
|
|
12
|
-
/**
|
|
13
|
-
* Sign ERC-3009 ReceiveWithAuthorization
|
|
14
|
-
* Note: receiveWithAuthorization uses a different primary type than transferWithAuthorization
|
|
15
|
-
*/
|
|
16
|
-
export declare function signERC3009(signer: ClientEvmSigner, authorization: EscrowPayload["authorization"], extra: EscrowExtra, tokenAddress: `0x${string}`, chainId: number): Promise<`0x${string}`>;
|
|
17
|
-
/**
|
|
18
|
-
* Verify ERC-3009 signature (facilitator-side)
|
|
19
|
-
* @param signer - The signer with verifyTypedData method
|
|
20
|
-
* @param authorization - ERC-3009 authorization data
|
|
21
|
-
* @param signature - The signature to verify
|
|
22
|
-
* @param extra - Extra configuration including chainId
|
|
23
|
-
* @param tokenAddress - The token contract address (verifyingContract for EIP-712)
|
|
24
|
-
*/
|
|
25
|
-
export declare function verifyERC3009Signature(signer: {
|
|
26
|
-
verifyTypedData: (args: {
|
|
27
|
-
address: `0x${string}`;
|
|
28
|
-
domain: Record<string, unknown>;
|
|
29
|
-
types: Record<string, unknown>;
|
|
30
|
-
primaryType: string;
|
|
31
|
-
message: Record<string, unknown>;
|
|
32
|
-
signature: `0x${string}`;
|
|
33
|
-
}) => Promise<boolean>;
|
|
34
|
-
}, authorization: EscrowPayload["authorization"], signature: `0x${string}`, extra: EscrowExtra & {
|
|
35
|
-
chainId: number;
|
|
36
|
-
}, tokenAddress: `0x${string}`): Promise<boolean>;
|
|
37
|
-
/**
|
|
38
|
-
* Generate random salt for paymentInfo
|
|
39
|
-
*/
|
|
40
|
-
export declare function generateSalt(): `0x${string}`;
|
|
41
|
-
//# sourceMappingURL=nonce.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nonce.d.ts","sourceRoot":"","sources":["../../src/shared/nonce.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAW7D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,KAAK,MAAM,EAAE,EAC5B,WAAW,EAAE,aAAa,CAAC,aAAa,CAAC,GACxC,KAAK,MAAM,EAAE,CA+Cf;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,eAAe,EACvB,aAAa,EAAE,aAAa,CAAC,eAAe,CAAC,EAC7C,KAAK,EAAE,WAAW,EAClB,YAAY,EAAE,KAAK,MAAM,EAAE,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,KAAK,MAAM,EAAE,CAAC,CAqCxB;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE;IACN,eAAe,EAAE,CAAC,IAAI,EAAE;QACtB,OAAO,EAAE,KAAK,MAAM,EAAE,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,SAAS,EAAE,KAAK,MAAM,EAAE,CAAC;KAC1B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB,EACD,aAAa,EAAE,aAAa,CAAC,eAAe,CAAC,EAC7C,SAAS,EAAE,KAAK,MAAM,EAAE,EACxB,KAAK,EAAE,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EACxC,YAAY,EAAE,KAAK,MAAM,EAAE,GAC1B,OAAO,CAAC,OAAO,CAAC,CA2ClB;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,KAAK,MAAM,EAAE,CAM5C"}
|
package/dist/shared/nonce.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nonce computation and ERC-3009 signing utilities
|
|
3
|
-
* Adapted from @agentokratia/x402-escrow (MIT)
|
|
4
|
-
*/
|
|
5
|
-
import { encodeAbiParameters, keccak256 } from "viem";
|
|
6
|
-
import { ZERO_ADDRESS } from "./constants.js";
|
|
7
|
-
/**
|
|
8
|
-
* PaymentInfo typehash - must match AuthCaptureEscrow.PAYMENT_INFO_TYPEHASH
|
|
9
|
-
*/
|
|
10
|
-
const PAYMENT_INFO_TYPEHASH = keccak256(new TextEncoder().encode("PaymentInfo(address operator,address payer,address receiver,address token,uint120 maxAmount,uint48 preApprovalExpiry,uint48 authorizationExpiry,uint48 refundExpiry,uint16 minFeeBps,uint16 maxFeeBps,address feeReceiver,uint256 salt)"));
|
|
11
|
-
/**
|
|
12
|
-
* Compute escrow nonce for ERC-3009 authorization
|
|
13
|
-
* Must match AuthCaptureEscrow.getHash() with payer=address(0)
|
|
14
|
-
*/
|
|
15
|
-
export function computeEscrowNonce(chainId, escrowAddress, paymentInfo) {
|
|
16
|
-
// Step 1: Encode paymentInfo with payer=0 (payer-agnostic)
|
|
17
|
-
const paymentInfoEncoded = encodeAbiParameters([
|
|
18
|
-
{ name: "typehash", type: "bytes32" },
|
|
19
|
-
{ name: "operator", type: "address" },
|
|
20
|
-
{ name: "payer", type: "address" },
|
|
21
|
-
{ name: "receiver", type: "address" },
|
|
22
|
-
{ name: "token", type: "address" },
|
|
23
|
-
{ name: "maxAmount", type: "uint120" },
|
|
24
|
-
{ name: "preApprovalExpiry", type: "uint48" },
|
|
25
|
-
{ name: "authorizationExpiry", type: "uint48" },
|
|
26
|
-
{ name: "refundExpiry", type: "uint48" },
|
|
27
|
-
{ name: "minFeeBps", type: "uint16" },
|
|
28
|
-
{ name: "maxFeeBps", type: "uint16" },
|
|
29
|
-
{ name: "feeReceiver", type: "address" },
|
|
30
|
-
{ name: "salt", type: "uint256" },
|
|
31
|
-
], [
|
|
32
|
-
PAYMENT_INFO_TYPEHASH,
|
|
33
|
-
paymentInfo.operator,
|
|
34
|
-
ZERO_ADDRESS, // payer-agnostic
|
|
35
|
-
paymentInfo.receiver,
|
|
36
|
-
paymentInfo.token,
|
|
37
|
-
BigInt(paymentInfo.maxAmount),
|
|
38
|
-
paymentInfo.preApprovalExpiry,
|
|
39
|
-
paymentInfo.authorizationExpiry,
|
|
40
|
-
paymentInfo.refundExpiry,
|
|
41
|
-
paymentInfo.minFeeBps,
|
|
42
|
-
paymentInfo.maxFeeBps,
|
|
43
|
-
paymentInfo.feeReceiver,
|
|
44
|
-
BigInt(paymentInfo.salt),
|
|
45
|
-
]);
|
|
46
|
-
const paymentInfoHash = keccak256(paymentInfoEncoded);
|
|
47
|
-
// Step 2: Encode (chainId, escrow, paymentInfoHash) and hash
|
|
48
|
-
const outerEncoded = encodeAbiParameters([
|
|
49
|
-
{ name: "chainId", type: "uint256" },
|
|
50
|
-
{ name: "escrow", type: "address" },
|
|
51
|
-
{ name: "paymentInfoHash", type: "bytes32" },
|
|
52
|
-
], [BigInt(chainId), escrowAddress, paymentInfoHash]);
|
|
53
|
-
return keccak256(outerEncoded);
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Sign ERC-3009 ReceiveWithAuthorization
|
|
57
|
-
* Note: receiveWithAuthorization uses a different primary type than transferWithAuthorization
|
|
58
|
-
*/
|
|
59
|
-
export async function signERC3009(signer, authorization, extra, tokenAddress, chainId) {
|
|
60
|
-
// EIP-712 domain - name must match the token's EIP-712 domain
|
|
61
|
-
// (e.g., "USDC" for Base USDC, not "USD Coin")
|
|
62
|
-
const domain = {
|
|
63
|
-
name: extra.name,
|
|
64
|
-
version: extra.version ?? "2",
|
|
65
|
-
chainId,
|
|
66
|
-
verifyingContract: tokenAddress,
|
|
67
|
-
};
|
|
68
|
-
// ERC-3009 uses ReceiveWithAuthorization for receiveWithAuthorization()
|
|
69
|
-
const types = {
|
|
70
|
-
ReceiveWithAuthorization: [
|
|
71
|
-
{ name: "from", type: "address" },
|
|
72
|
-
{ name: "to", type: "address" },
|
|
73
|
-
{ name: "value", type: "uint256" },
|
|
74
|
-
{ name: "validAfter", type: "uint256" },
|
|
75
|
-
{ name: "validBefore", type: "uint256" },
|
|
76
|
-
{ name: "nonce", type: "bytes32" },
|
|
77
|
-
],
|
|
78
|
-
};
|
|
79
|
-
const message = {
|
|
80
|
-
from: authorization.from,
|
|
81
|
-
to: authorization.to,
|
|
82
|
-
value: BigInt(authorization.value),
|
|
83
|
-
validAfter: BigInt(authorization.validAfter),
|
|
84
|
-
validBefore: BigInt(authorization.validBefore),
|
|
85
|
-
nonce: authorization.nonce,
|
|
86
|
-
};
|
|
87
|
-
return signer.signTypedData({
|
|
88
|
-
domain,
|
|
89
|
-
types,
|
|
90
|
-
primaryType: "ReceiveWithAuthorization",
|
|
91
|
-
message,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Verify ERC-3009 signature (facilitator-side)
|
|
96
|
-
* @param signer - The signer with verifyTypedData method
|
|
97
|
-
* @param authorization - ERC-3009 authorization data
|
|
98
|
-
* @param signature - The signature to verify
|
|
99
|
-
* @param extra - Extra configuration including chainId
|
|
100
|
-
* @param tokenAddress - The token contract address (verifyingContract for EIP-712)
|
|
101
|
-
*/
|
|
102
|
-
export async function verifyERC3009Signature(signer, authorization, signature, extra, tokenAddress) {
|
|
103
|
-
// EIP-712 domain - name must match the token's EIP-712 domain
|
|
104
|
-
// (e.g., "USDC" for Base USDC, not "USD Coin")
|
|
105
|
-
const domain = {
|
|
106
|
-
name: extra.name,
|
|
107
|
-
version: extra.version ?? "2",
|
|
108
|
-
chainId: extra.chainId,
|
|
109
|
-
verifyingContract: tokenAddress,
|
|
110
|
-
};
|
|
111
|
-
// Must use ReceiveWithAuthorization to match what was signed
|
|
112
|
-
const types = {
|
|
113
|
-
ReceiveWithAuthorization: [
|
|
114
|
-
{ name: "from", type: "address" },
|
|
115
|
-
{ name: "to", type: "address" },
|
|
116
|
-
{ name: "value", type: "uint256" },
|
|
117
|
-
{ name: "validAfter", type: "uint256" },
|
|
118
|
-
{ name: "validBefore", type: "uint256" },
|
|
119
|
-
{ name: "nonce", type: "bytes32" },
|
|
120
|
-
],
|
|
121
|
-
};
|
|
122
|
-
const message = {
|
|
123
|
-
from: authorization.from,
|
|
124
|
-
to: authorization.to,
|
|
125
|
-
value: BigInt(authorization.value),
|
|
126
|
-
validAfter: BigInt(authorization.validAfter),
|
|
127
|
-
validBefore: BigInt(authorization.validBefore),
|
|
128
|
-
nonce: authorization.nonce,
|
|
129
|
-
};
|
|
130
|
-
try {
|
|
131
|
-
return await signer.verifyTypedData({
|
|
132
|
-
address: authorization.from,
|
|
133
|
-
domain,
|
|
134
|
-
types,
|
|
135
|
-
primaryType: "ReceiveWithAuthorization",
|
|
136
|
-
message,
|
|
137
|
-
signature,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Generate random salt for paymentInfo
|
|
146
|
-
*/
|
|
147
|
-
export function generateSalt() {
|
|
148
|
-
const bytes = new Uint8Array(32);
|
|
149
|
-
crypto.getRandomValues(bytes);
|
|
150
|
-
return `0x${Array.from(bytes)
|
|
151
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
152
|
-
.join("")}`;
|
|
153
|
-
}
|
|
154
|
-
//# sourceMappingURL=nonce.js.map
|
package/dist/shared/nonce.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"nonce.js","sourceRoot":"","sources":["../../src/shared/nonce.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAQtE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAQlE;AAGD,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,KAAK,MAAM,EAAE,CAAC;IAC7B,eAAe,EAAE,KAAK,MAAM,EAAE,CAAC;IAC/B,cAAc,EAAE,KAAK,MAAM,EAAE,CAAC;IAC9B,gBAAgB,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,0BAA0B,CAAC,EAAE,MAAM,CAAC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE;QACb,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;QACpB,EAAE,EAAE,KAAK,MAAM,EAAE,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;KACtB,CAAC;IACF,SAAS,EAAE,KAAK,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE;QACX,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;QACxB,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;QACxB,KAAK,EAAE,KAAK,MAAM,EAAE,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,mBAAmB,EAAE,MAAM,CAAC;QAC5B,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QAC3B,IAAI,EAAE,KAAK,MAAM,EAAE,CAAC;KACrB,CAAC;CACH"}
|
package/dist/shared/types.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type guard for EscrowPayload
|
|
3
|
-
*/
|
|
4
|
-
export function isEscrowPayload(value) {
|
|
5
|
-
return (typeof value === "object" &&
|
|
6
|
-
value !== null &&
|
|
7
|
-
"authorization" in value &&
|
|
8
|
-
"signature" in value &&
|
|
9
|
-
"paymentInfo" in value);
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Type guard for EscrowExtra
|
|
13
|
-
*/
|
|
14
|
-
export function isEscrowExtra(value) {
|
|
15
|
-
return (typeof value === "object" &&
|
|
16
|
-
value !== null &&
|
|
17
|
-
"escrowAddress" in value &&
|
|
18
|
-
"operatorAddress" in value &&
|
|
19
|
-
"tokenCollector" in value);
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=types.js.map
|
package/dist/shared/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/shared/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,eAAe,IAAI,KAAK;QACxB,WAAW,IAAI,KAAK;QACpB,aAAa,IAAI,KAAK,CACvB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,eAAe,IAAI,KAAK;QACxB,iBAAiB,IAAI,KAAK;QAC1B,gBAAgB,IAAI,KAAK,CAC1B,CAAC;AACJ,CAAC"}
|
package/src/shared/constants.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
export const ZERO_ADDRESS =
|
|
2
|
-
"0x0000000000000000000000000000000000000000" as const;
|
|
3
|
-
export const MAX_UINT48 = 281474976710655;
|
|
4
|
-
export const MAX_UINT32 = 4294967295;
|
|
5
|
-
|
|
6
|
-
// PaymentInfo struct for AuthCaptureEscrow (matches commerce-payments contract)
|
|
7
|
-
export const PAYMENT_INFO_COMPONENTS = [
|
|
8
|
-
{ name: "operator", type: "address" },
|
|
9
|
-
{ name: "payer", type: "address" },
|
|
10
|
-
{ name: "receiver", type: "address" },
|
|
11
|
-
{ name: "token", type: "address" },
|
|
12
|
-
{ name: "maxAmount", type: "uint120" },
|
|
13
|
-
{ name: "preApprovalExpiry", type: "uint48" },
|
|
14
|
-
{ name: "authorizationExpiry", type: "uint48" },
|
|
15
|
-
{ name: "refundExpiry", type: "uint48" },
|
|
16
|
-
{ name: "minFeeBps", type: "uint16" },
|
|
17
|
-
{ name: "maxFeeBps", type: "uint16" },
|
|
18
|
-
{ name: "feeReceiver", type: "address" },
|
|
19
|
-
{ name: "salt", type: "uint256" },
|
|
20
|
-
] as const;
|
|
21
|
-
|
|
22
|
-
export const OPERATOR_ABI = [
|
|
23
|
-
{
|
|
24
|
-
name: "authorize",
|
|
25
|
-
type: "function",
|
|
26
|
-
stateMutability: "nonpayable",
|
|
27
|
-
inputs: [
|
|
28
|
-
{
|
|
29
|
-
name: "paymentInfo",
|
|
30
|
-
type: "tuple",
|
|
31
|
-
components: PAYMENT_INFO_COMPONENTS,
|
|
32
|
-
},
|
|
33
|
-
{ name: "amount", type: "uint256" },
|
|
34
|
-
{ name: "tokenCollector", type: "address" },
|
|
35
|
-
{ name: "collectorData", type: "bytes" },
|
|
36
|
-
],
|
|
37
|
-
outputs: [],
|
|
38
|
-
},
|
|
39
|
-
] as const;
|
|
40
|
-
|
|
41
|
-
// ERC-3009 TransferWithAuthorization type hash
|
|
42
|
-
export const TRANSFER_WITH_AUTHORIZATION_TYPEHASH =
|
|
43
|
-
"0x7c7c6cdb67a18743f49ec6fa9b35f50d52ed05cbed4cc592e13b44501c1a2267" as const;
|
|
44
|
-
|
|
45
|
-
// EIP-6492 magic suffix (32 bytes) — appended to signatures from counterfactual smart wallets
|
|
46
|
-
export const ERC6492_MAGIC_VALUE =
|
|
47
|
-
"0x6492649264926492649264926492649264926492649264926492649264926492" as const;
|
|
48
|
-
|
|
49
|
-
// ERC-20 balanceOf ABI for balance checks
|
|
50
|
-
export const ERC20_BALANCE_OF_ABI = [
|
|
51
|
-
{
|
|
52
|
-
name: "balanceOf",
|
|
53
|
-
type: "function",
|
|
54
|
-
stateMutability: "view",
|
|
55
|
-
inputs: [{ name: "account", type: "address" }],
|
|
56
|
-
outputs: [{ name: "balance", type: "uint256" }],
|
|
57
|
-
},
|
|
58
|
-
] as const;
|
package/src/shared/nonce.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Nonce computation and ERC-3009 signing utilities
|
|
3
|
-
* Adapted from @agentokratia/x402-escrow (MIT)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { encodeAbiParameters, keccak256 } from "viem";
|
|
7
|
-
import type { ClientEvmSigner } from "@x402/evm";
|
|
8
|
-
import { ZERO_ADDRESS, PAYMENT_INFO_COMPONENTS } from "./constants.js";
|
|
9
|
-
import type { EscrowExtra, EscrowPayload } from "./types.js";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* PaymentInfo typehash - must match AuthCaptureEscrow.PAYMENT_INFO_TYPEHASH
|
|
13
|
-
*/
|
|
14
|
-
const PAYMENT_INFO_TYPEHASH = keccak256(
|
|
15
|
-
new TextEncoder().encode(
|
|
16
|
-
"PaymentInfo(address operator,address payer,address receiver,address token,uint120 maxAmount,uint48 preApprovalExpiry,uint48 authorizationExpiry,uint48 refundExpiry,uint16 minFeeBps,uint16 maxFeeBps,address feeReceiver,uint256 salt)",
|
|
17
|
-
),
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Compute escrow nonce for ERC-3009 authorization
|
|
22
|
-
* Must match AuthCaptureEscrow.getHash() with payer=address(0)
|
|
23
|
-
*/
|
|
24
|
-
export function computeEscrowNonce(
|
|
25
|
-
chainId: number,
|
|
26
|
-
escrowAddress: `0x${string}`,
|
|
27
|
-
paymentInfo: EscrowPayload["paymentInfo"],
|
|
28
|
-
): `0x${string}` {
|
|
29
|
-
// Step 1: Encode paymentInfo with payer=0 (payer-agnostic)
|
|
30
|
-
const paymentInfoEncoded = encodeAbiParameters(
|
|
31
|
-
[
|
|
32
|
-
{ name: "typehash", type: "bytes32" },
|
|
33
|
-
{ name: "operator", type: "address" },
|
|
34
|
-
{ name: "payer", type: "address" },
|
|
35
|
-
{ name: "receiver", type: "address" },
|
|
36
|
-
{ name: "token", type: "address" },
|
|
37
|
-
{ name: "maxAmount", type: "uint120" },
|
|
38
|
-
{ name: "preApprovalExpiry", type: "uint48" },
|
|
39
|
-
{ name: "authorizationExpiry", type: "uint48" },
|
|
40
|
-
{ name: "refundExpiry", type: "uint48" },
|
|
41
|
-
{ name: "minFeeBps", type: "uint16" },
|
|
42
|
-
{ name: "maxFeeBps", type: "uint16" },
|
|
43
|
-
{ name: "feeReceiver", type: "address" },
|
|
44
|
-
{ name: "salt", type: "uint256" },
|
|
45
|
-
],
|
|
46
|
-
[
|
|
47
|
-
PAYMENT_INFO_TYPEHASH,
|
|
48
|
-
paymentInfo.operator,
|
|
49
|
-
ZERO_ADDRESS, // payer-agnostic
|
|
50
|
-
paymentInfo.receiver,
|
|
51
|
-
paymentInfo.token,
|
|
52
|
-
BigInt(paymentInfo.maxAmount),
|
|
53
|
-
paymentInfo.preApprovalExpiry,
|
|
54
|
-
paymentInfo.authorizationExpiry,
|
|
55
|
-
paymentInfo.refundExpiry,
|
|
56
|
-
paymentInfo.minFeeBps,
|
|
57
|
-
paymentInfo.maxFeeBps,
|
|
58
|
-
paymentInfo.feeReceiver,
|
|
59
|
-
BigInt(paymentInfo.salt),
|
|
60
|
-
],
|
|
61
|
-
);
|
|
62
|
-
const paymentInfoHash = keccak256(paymentInfoEncoded);
|
|
63
|
-
|
|
64
|
-
// Step 2: Encode (chainId, escrow, paymentInfoHash) and hash
|
|
65
|
-
const outerEncoded = encodeAbiParameters(
|
|
66
|
-
[
|
|
67
|
-
{ name: "chainId", type: "uint256" },
|
|
68
|
-
{ name: "escrow", type: "address" },
|
|
69
|
-
{ name: "paymentInfoHash", type: "bytes32" },
|
|
70
|
-
],
|
|
71
|
-
[BigInt(chainId), escrowAddress, paymentInfoHash],
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
return keccak256(outerEncoded);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Sign ERC-3009 ReceiveWithAuthorization
|
|
79
|
-
* Note: receiveWithAuthorization uses a different primary type than transferWithAuthorization
|
|
80
|
-
*/
|
|
81
|
-
export async function signERC3009(
|
|
82
|
-
signer: ClientEvmSigner,
|
|
83
|
-
authorization: EscrowPayload["authorization"],
|
|
84
|
-
extra: EscrowExtra,
|
|
85
|
-
tokenAddress: `0x${string}`,
|
|
86
|
-
chainId: number,
|
|
87
|
-
): Promise<`0x${string}`> {
|
|
88
|
-
// EIP-712 domain - name must match the token's EIP-712 domain
|
|
89
|
-
// (e.g., "USDC" for Base USDC, not "USD Coin")
|
|
90
|
-
const domain = {
|
|
91
|
-
name: extra.name,
|
|
92
|
-
version: extra.version ?? "2",
|
|
93
|
-
chainId,
|
|
94
|
-
verifyingContract: tokenAddress,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// ERC-3009 uses ReceiveWithAuthorization for receiveWithAuthorization()
|
|
98
|
-
const types = {
|
|
99
|
-
ReceiveWithAuthorization: [
|
|
100
|
-
{ name: "from", type: "address" },
|
|
101
|
-
{ name: "to", type: "address" },
|
|
102
|
-
{ name: "value", type: "uint256" },
|
|
103
|
-
{ name: "validAfter", type: "uint256" },
|
|
104
|
-
{ name: "validBefore", type: "uint256" },
|
|
105
|
-
{ name: "nonce", type: "bytes32" },
|
|
106
|
-
],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const message = {
|
|
110
|
-
from: authorization.from,
|
|
111
|
-
to: authorization.to,
|
|
112
|
-
value: BigInt(authorization.value),
|
|
113
|
-
validAfter: BigInt(authorization.validAfter),
|
|
114
|
-
validBefore: BigInt(authorization.validBefore),
|
|
115
|
-
nonce: authorization.nonce,
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
return signer.signTypedData({
|
|
119
|
-
domain,
|
|
120
|
-
types,
|
|
121
|
-
primaryType: "ReceiveWithAuthorization",
|
|
122
|
-
message,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Verify ERC-3009 signature (facilitator-side)
|
|
128
|
-
* @param signer - The signer with verifyTypedData method
|
|
129
|
-
* @param authorization - ERC-3009 authorization data
|
|
130
|
-
* @param signature - The signature to verify
|
|
131
|
-
* @param extra - Extra configuration including chainId
|
|
132
|
-
* @param tokenAddress - The token contract address (verifyingContract for EIP-712)
|
|
133
|
-
*/
|
|
134
|
-
export async function verifyERC3009Signature(
|
|
135
|
-
signer: {
|
|
136
|
-
verifyTypedData: (args: {
|
|
137
|
-
address: `0x${string}`;
|
|
138
|
-
domain: Record<string, unknown>;
|
|
139
|
-
types: Record<string, unknown>;
|
|
140
|
-
primaryType: string;
|
|
141
|
-
message: Record<string, unknown>;
|
|
142
|
-
signature: `0x${string}`;
|
|
143
|
-
}) => Promise<boolean>;
|
|
144
|
-
},
|
|
145
|
-
authorization: EscrowPayload["authorization"],
|
|
146
|
-
signature: `0x${string}`,
|
|
147
|
-
extra: EscrowExtra & { chainId: number },
|
|
148
|
-
tokenAddress: `0x${string}`,
|
|
149
|
-
): Promise<boolean> {
|
|
150
|
-
// EIP-712 domain - name must match the token's EIP-712 domain
|
|
151
|
-
// (e.g., "USDC" for Base USDC, not "USD Coin")
|
|
152
|
-
const domain = {
|
|
153
|
-
name: extra.name,
|
|
154
|
-
version: extra.version ?? "2",
|
|
155
|
-
chainId: extra.chainId,
|
|
156
|
-
verifyingContract: tokenAddress,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Must use ReceiveWithAuthorization to match what was signed
|
|
160
|
-
const types = {
|
|
161
|
-
ReceiveWithAuthorization: [
|
|
162
|
-
{ name: "from", type: "address" },
|
|
163
|
-
{ name: "to", type: "address" },
|
|
164
|
-
{ name: "value", type: "uint256" },
|
|
165
|
-
{ name: "validAfter", type: "uint256" },
|
|
166
|
-
{ name: "validBefore", type: "uint256" },
|
|
167
|
-
{ name: "nonce", type: "bytes32" },
|
|
168
|
-
],
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const message = {
|
|
172
|
-
from: authorization.from,
|
|
173
|
-
to: authorization.to,
|
|
174
|
-
value: BigInt(authorization.value),
|
|
175
|
-
validAfter: BigInt(authorization.validAfter),
|
|
176
|
-
validBefore: BigInt(authorization.validBefore),
|
|
177
|
-
nonce: authorization.nonce,
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
try {
|
|
181
|
-
return await signer.verifyTypedData({
|
|
182
|
-
address: authorization.from,
|
|
183
|
-
domain,
|
|
184
|
-
types,
|
|
185
|
-
primaryType: "ReceiveWithAuthorization",
|
|
186
|
-
message,
|
|
187
|
-
signature,
|
|
188
|
-
});
|
|
189
|
-
} catch {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Generate random salt for paymentInfo
|
|
196
|
-
*/
|
|
197
|
-
export function generateSalt(): `0x${string}` {
|
|
198
|
-
const bytes = new Uint8Array(32);
|
|
199
|
-
crypto.getRandomValues(bytes);
|
|
200
|
-
return `0x${Array.from(bytes)
|
|
201
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
202
|
-
.join("")}` as `0x${string}`;
|
|
203
|
-
}
|
package/src/shared/types.ts
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Type guard for EscrowPayload
|
|
3
|
-
*/
|
|
4
|
-
export function isEscrowPayload(value: unknown): value is EscrowPayload {
|
|
5
|
-
return (
|
|
6
|
-
typeof value === "object" &&
|
|
7
|
-
value !== null &&
|
|
8
|
-
"authorization" in value &&
|
|
9
|
-
"signature" in value &&
|
|
10
|
-
"paymentInfo" in value
|
|
11
|
-
);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Type guard for EscrowExtra
|
|
16
|
-
*/
|
|
17
|
-
export function isEscrowExtra(value: unknown): value is EscrowExtra {
|
|
18
|
-
return (
|
|
19
|
-
typeof value === "object" &&
|
|
20
|
-
value !== null &&
|
|
21
|
-
"escrowAddress" in value &&
|
|
22
|
-
"operatorAddress" in value &&
|
|
23
|
-
"tokenCollector" in value
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// EscrowExtra - fields in PaymentRequirements.extra
|
|
28
|
-
export interface EscrowExtra {
|
|
29
|
-
escrowAddress: `0x${string}`;
|
|
30
|
-
operatorAddress: `0x${string}`;
|
|
31
|
-
tokenCollector: `0x${string}`;
|
|
32
|
-
authorizeAddress?: `0x${string}`;
|
|
33
|
-
minDeposit?: string;
|
|
34
|
-
maxDeposit?: string;
|
|
35
|
-
preApprovalExpirySeconds?: number;
|
|
36
|
-
authorizationExpirySeconds?: number;
|
|
37
|
-
refundExpirySeconds?: number;
|
|
38
|
-
minFeeBps?: number;
|
|
39
|
-
maxFeeBps?: number;
|
|
40
|
-
feeReceiver?: `0x${string}`;
|
|
41
|
-
name: string; // EIP-712 domain name (e.g., "USDC" for Base USDC)
|
|
42
|
-
version?: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// EscrowPayload - the payload field in PaymentPayload
|
|
46
|
-
export interface EscrowPayload {
|
|
47
|
-
authorization: {
|
|
48
|
-
from: `0x${string}`;
|
|
49
|
-
to: `0x${string}`;
|
|
50
|
-
value: string;
|
|
51
|
-
validAfter: string;
|
|
52
|
-
validBefore: string;
|
|
53
|
-
nonce: `0x${string}`;
|
|
54
|
-
};
|
|
55
|
-
signature: `0x${string}`;
|
|
56
|
-
paymentInfo: {
|
|
57
|
-
operator: `0x${string}`;
|
|
58
|
-
receiver: `0x${string}`;
|
|
59
|
-
token: `0x${string}`;
|
|
60
|
-
maxAmount: string;
|
|
61
|
-
preApprovalExpiry: number;
|
|
62
|
-
authorizationExpiry: number;
|
|
63
|
-
refundExpiry: number;
|
|
64
|
-
minFeeBps: number;
|
|
65
|
-
maxFeeBps: number;
|
|
66
|
-
feeReceiver: `0x${string}`;
|
|
67
|
-
salt: `0x${string}`;
|
|
68
|
-
};
|
|
69
|
-
}
|