@haven_ai/sdk 0.8.0-alpha.0 → 0.9.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base64-BZDPJ8M1.d.ts +1344 -0
- package/dist/base64-Cyxhsvqd.d.cts +1344 -0
- package/dist/{chunk-UXULZ3ZY.js → chunk-424S4QMG.js} +10 -5
- package/dist/chunk-424S4QMG.js.map +1 -0
- package/dist/{chunk-HX34HOW4.cjs → chunk-4Z6ATE44.cjs} +2 -2
- package/dist/chunk-4Z6ATE44.cjs.map +1 -0
- package/dist/chunk-7UTWSJC5.cjs +106 -0
- package/dist/chunk-7UTWSJC5.cjs.map +1 -0
- package/dist/{chunk-H4APV67M.js → chunk-J7N4LUZZ.js} +2 -2
- package/dist/chunk-J7N4LUZZ.js.map +1 -0
- package/dist/chunk-VRKWNJ7H.js +103 -0
- package/dist/chunk-VRKWNJ7H.js.map +1 -0
- package/dist/{chunk-WJFDXCYP.cjs → chunk-ZDKNPNI3.cjs} +41 -35
- package/dist/chunk-ZDKNPNI3.cjs.map +1 -0
- package/dist/edge.cjs +97 -89
- package/dist/edge.d.cts +4 -2
- package/dist/edge.d.ts +4 -2
- package/dist/edge.js +4 -4
- package/dist/index.cjs +1033 -490
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +103 -147
- package/dist/index.d.ts +103 -147
- package/dist/index.js +705 -189
- package/dist/index.js.map +1 -1
- package/dist/receipt-D4Roey3D.d.cts +130 -0
- package/dist/receipt-WkXHZGbu.d.ts +130 -0
- package/dist/test-support.cjs +71 -18
- package/dist/test-support.cjs.map +1 -1
- package/dist/test-support.d.cts +21 -1
- package/dist/test-support.d.ts +21 -1
- package/dist/test-support.js +53 -3
- package/dist/test-support.js.map +1 -1
- package/dist/{base64-znjJJQqu.d.cts → types-CrszUJ7Z.d.cts} +208 -1306
- package/dist/{base64-znjJJQqu.d.ts → types-CrszUJ7Z.d.ts} +208 -1306
- package/package.json +1 -1
- package/dist/chunk-H4APV67M.js.map +0 -1
- package/dist/chunk-HX34HOW4.cjs.map +0 -1
- package/dist/chunk-UXULZ3ZY.js.map +0 -1
- package/dist/chunk-WJFDXCYP.cjs.map +0 -1
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { aV as RawPaymentParties } from './types-CrszUJ7Z.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verifiable payment receipts.
|
|
5
|
+
*
|
|
6
|
+
* A self-contained bundle for a settled Haven payment whose agent
|
|
7
|
+
* authorisation can be checked offline. What `verifyPaymentReceipt` proves is
|
|
8
|
+
* deliberately narrow: the `payment` block (amount, recipient) is
|
|
9
|
+
* Haven-asserted and is NOT bound by the signature, and `verified: true` never
|
|
10
|
+
* proves the payment settled on-chain — settlement stays an explorer check on
|
|
11
|
+
* `onChain.txHash` / `settlementTxHash`.
|
|
12
|
+
*
|
|
13
|
+
* What `verified: true` means, per scheme:
|
|
14
|
+
*
|
|
15
|
+
* - erc7710 (`authorization.signatureScheme: 'eip712_delegation'`): the bundle
|
|
16
|
+
* carries the settlement child's EIP-712 struct hash as `signHash`. The
|
|
17
|
+
* verifier rebuilds the digest the delegate actually signed —
|
|
18
|
+
* `keccak256(0x1901 ‖ domainSeparator(DelegationManager, chainId) ‖ signHash)`
|
|
19
|
+
* — from the DelegationManager address the SDK pins and the bundle's
|
|
20
|
+
* `onChain.chainId`, never from a value the receipt itself vouches for.
|
|
21
|
+
* `verified: true` means the delegate key signed that settlement delegation
|
|
22
|
+
* (`verifiedOver: 'delegation_digest'`).
|
|
23
|
+
* - direct payments and the eip3009 funding leg
|
|
24
|
+
* (`signatureScheme: 'eip712_userop'`) sign an ERC-4337 user operation the
|
|
25
|
+
* bundle does not carry: they return `not_verifiable_offline` rather than a
|
|
26
|
+
* false accusation.
|
|
27
|
+
* - retired-rail bundles (no scheme) carry a raw-signed `signHash`; the
|
|
28
|
+
* verifier recovers over it directly, then over the delegation digest when
|
|
29
|
+
* the chain allows rebuilding it.
|
|
30
|
+
*
|
|
31
|
+
* Anything that is not a signed bundle — including a `haven_list_receipts`
|
|
32
|
+
* history row, which carries no signature at all — returns
|
|
33
|
+
* `not_a_signed_receipt`. Verification never throws.
|
|
34
|
+
*
|
|
35
|
+
* #3723: the response `GET /payments/{id}/receipt` returns —
|
|
36
|
+
* `{ receipt, verification }` — is accepted AS-IS: when the top level carries
|
|
37
|
+
* no `authorization`, the `.receipt` object inside is verified instead (one
|
|
38
|
+
* level, no recursion). The wrapper's `verification` is never read — it is
|
|
39
|
+
* Haven's own self-check, and trusting it would defeat an offline verifier.
|
|
40
|
+
*
|
|
41
|
+
* This lives in the SDK so agents and users can verify receipts client-side.
|
|
42
|
+
*/
|
|
43
|
+
declare const RECEIPT_VERSION = "haven-receipt-1";
|
|
44
|
+
interface PaymentReceipt {
|
|
45
|
+
version: typeof RECEIPT_VERSION;
|
|
46
|
+
paymentId: string;
|
|
47
|
+
payment: {
|
|
48
|
+
token: string;
|
|
49
|
+
tokenAddress: string;
|
|
50
|
+
amount: string;
|
|
51
|
+
amountSek: string | null;
|
|
52
|
+
recipient: string;
|
|
53
|
+
/** The payer's smart-account address. */
|
|
54
|
+
account: string;
|
|
55
|
+
/**
|
|
56
|
+
* #2960: one party vocabulary for "who paid", additive alongside `account`
|
|
57
|
+
* above (which is `parties.treasury_account` only). Optional: a server
|
|
58
|
+
* from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,
|
|
59
|
+
* which reads only `authorization`.
|
|
60
|
+
*/
|
|
61
|
+
parties?: RawPaymentParties;
|
|
62
|
+
chainId: number;
|
|
63
|
+
settledAt: string | null;
|
|
64
|
+
resourceUrl: string | null;
|
|
65
|
+
/**
|
|
66
|
+
* #3770: the paying agent's own evidence-only verdict on what the
|
|
67
|
+
* merchant DELIVERED (`ok` / `unusable` / `partial`, plus a bounded
|
|
68
|
+
* note). Additive and OPTIONAL: a server from before #3770 emits
|
|
69
|
+
* neither, and `null` means the agent has not reported. Ignored by
|
|
70
|
+
* `verifyPaymentReceipt`, which reads only `authorization` — the same
|
|
71
|
+
* rule `parties` follows. Evidence only: it never changes what the
|
|
72
|
+
* payment itself is, and `settled`/amounts are untouched by a report.
|
|
73
|
+
*/
|
|
74
|
+
deliveryQuality?: {
|
|
75
|
+
quality: 'ok' | 'unusable' | 'partial';
|
|
76
|
+
note: string | null;
|
|
77
|
+
reportedAt: string | null;
|
|
78
|
+
} | null;
|
|
79
|
+
};
|
|
80
|
+
/** The agent's cryptographic authorisation — what makes the receipt verifiable. */
|
|
81
|
+
authorization: {
|
|
82
|
+
delegate: string;
|
|
83
|
+
signHash: string;
|
|
84
|
+
signature: string | null;
|
|
85
|
+
/**
|
|
86
|
+
* #3418: which digest the delegate signed — selects what offline
|
|
87
|
+
* verification rebuilds. `'eip712_delegation'`: the settlement
|
|
88
|
+
* delegation's EIP-712 digest (erc7710). `'eip712_userop'`: an ERC-4337
|
|
89
|
+
* user-operation digest the bundle does not carry (direct payments, the
|
|
90
|
+
* eip3009 funding leg) — not verifiable offline. Absent on retired-rail
|
|
91
|
+
* bundles and on backends older than #3418, whose `signHash` was signed
|
|
92
|
+
* raw. The value is only a selector: a lying one cannot make a forged
|
|
93
|
+
* signature verify, because recovery must still return `delegate`.
|
|
94
|
+
*/
|
|
95
|
+
signatureScheme?: 'eip712_delegation' | 'eip712_userop';
|
|
96
|
+
};
|
|
97
|
+
onChain: {
|
|
98
|
+
txHash: string | null;
|
|
99
|
+
chainId: number;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
type ReceiptVerification = {
|
|
103
|
+
verified: true;
|
|
104
|
+
recoveredSigner: string;
|
|
105
|
+
verifiedOver: 'sign_hash' | 'delegation_digest';
|
|
106
|
+
} | {
|
|
107
|
+
verified: false;
|
|
108
|
+
reason:
|
|
109
|
+
/** #3418: the input is not a haven-receipt-1 bundle (a haven_list_receipts row, null, undefined, a non-object). */
|
|
110
|
+
'not_a_signed_receipt'
|
|
111
|
+
/** #3418: eip712_userop bundle; or a delegation bundle on a chain the SDK pins no DelegationManager for. */
|
|
112
|
+
| 'not_verifiable_offline' | 'missing_signature' | 'bad_signature' | 'signer_mismatch';
|
|
113
|
+
recoveredSigner?: string;
|
|
114
|
+
};
|
|
115
|
+
type RecoverFn = (hash: string, signature: string) => string;
|
|
116
|
+
/**
|
|
117
|
+
* Verify a receipt's agent authorisation offline: recover the signer and
|
|
118
|
+
* confirm it is the agent delegate, over whichever digest the bundle's scheme
|
|
119
|
+
* names (see the module doc for what that proves — and what it does not).
|
|
120
|
+
* Never throws: anything that is not a signed receipt — a
|
|
121
|
+
* `haven_list_receipts` history row, null, undefined, a non-object — returns
|
|
122
|
+
* `not_a_signed_receipt`. The `{ receipt, verification }` wrapper the receipt
|
|
123
|
+
* endpoint returns is accepted as-is: `.receipt` is verified, and the
|
|
124
|
+
* wrapper's `verification` — Haven's own self-check — is never read. Pure —
|
|
125
|
+
* `recover` is injectable but defaults to
|
|
126
|
+
* standard ECDSA recovery, so this runs anywhere (no Haven backend).
|
|
127
|
+
*/
|
|
128
|
+
declare function verifyPaymentReceipt(receipt: unknown, recover?: RecoverFn): ReceiptVerification;
|
|
129
|
+
|
|
130
|
+
export { type PaymentReceipt as P, type ReceiptVerification as R, RECEIPT_VERSION as a, verifyPaymentReceipt as v };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { aV as RawPaymentParties } from './types-CrszUJ7Z.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verifiable payment receipts.
|
|
5
|
+
*
|
|
6
|
+
* A self-contained bundle for a settled Haven payment whose agent
|
|
7
|
+
* authorisation can be checked offline. What `verifyPaymentReceipt` proves is
|
|
8
|
+
* deliberately narrow: the `payment` block (amount, recipient) is
|
|
9
|
+
* Haven-asserted and is NOT bound by the signature, and `verified: true` never
|
|
10
|
+
* proves the payment settled on-chain — settlement stays an explorer check on
|
|
11
|
+
* `onChain.txHash` / `settlementTxHash`.
|
|
12
|
+
*
|
|
13
|
+
* What `verified: true` means, per scheme:
|
|
14
|
+
*
|
|
15
|
+
* - erc7710 (`authorization.signatureScheme: 'eip712_delegation'`): the bundle
|
|
16
|
+
* carries the settlement child's EIP-712 struct hash as `signHash`. The
|
|
17
|
+
* verifier rebuilds the digest the delegate actually signed —
|
|
18
|
+
* `keccak256(0x1901 ‖ domainSeparator(DelegationManager, chainId) ‖ signHash)`
|
|
19
|
+
* — from the DelegationManager address the SDK pins and the bundle's
|
|
20
|
+
* `onChain.chainId`, never from a value the receipt itself vouches for.
|
|
21
|
+
* `verified: true` means the delegate key signed that settlement delegation
|
|
22
|
+
* (`verifiedOver: 'delegation_digest'`).
|
|
23
|
+
* - direct payments and the eip3009 funding leg
|
|
24
|
+
* (`signatureScheme: 'eip712_userop'`) sign an ERC-4337 user operation the
|
|
25
|
+
* bundle does not carry: they return `not_verifiable_offline` rather than a
|
|
26
|
+
* false accusation.
|
|
27
|
+
* - retired-rail bundles (no scheme) carry a raw-signed `signHash`; the
|
|
28
|
+
* verifier recovers over it directly, then over the delegation digest when
|
|
29
|
+
* the chain allows rebuilding it.
|
|
30
|
+
*
|
|
31
|
+
* Anything that is not a signed bundle — including a `haven_list_receipts`
|
|
32
|
+
* history row, which carries no signature at all — returns
|
|
33
|
+
* `not_a_signed_receipt`. Verification never throws.
|
|
34
|
+
*
|
|
35
|
+
* #3723: the response `GET /payments/{id}/receipt` returns —
|
|
36
|
+
* `{ receipt, verification }` — is accepted AS-IS: when the top level carries
|
|
37
|
+
* no `authorization`, the `.receipt` object inside is verified instead (one
|
|
38
|
+
* level, no recursion). The wrapper's `verification` is never read — it is
|
|
39
|
+
* Haven's own self-check, and trusting it would defeat an offline verifier.
|
|
40
|
+
*
|
|
41
|
+
* This lives in the SDK so agents and users can verify receipts client-side.
|
|
42
|
+
*/
|
|
43
|
+
declare const RECEIPT_VERSION = "haven-receipt-1";
|
|
44
|
+
interface PaymentReceipt {
|
|
45
|
+
version: typeof RECEIPT_VERSION;
|
|
46
|
+
paymentId: string;
|
|
47
|
+
payment: {
|
|
48
|
+
token: string;
|
|
49
|
+
tokenAddress: string;
|
|
50
|
+
amount: string;
|
|
51
|
+
amountSek: string | null;
|
|
52
|
+
recipient: string;
|
|
53
|
+
/** The payer's smart-account address. */
|
|
54
|
+
account: string;
|
|
55
|
+
/**
|
|
56
|
+
* #2960: one party vocabulary for "who paid", additive alongside `account`
|
|
57
|
+
* above (which is `parties.treasury_account` only). Optional: a server
|
|
58
|
+
* from before #2960 emits neither. Ignored by `verifyPaymentReceipt`,
|
|
59
|
+
* which reads only `authorization`.
|
|
60
|
+
*/
|
|
61
|
+
parties?: RawPaymentParties;
|
|
62
|
+
chainId: number;
|
|
63
|
+
settledAt: string | null;
|
|
64
|
+
resourceUrl: string | null;
|
|
65
|
+
/**
|
|
66
|
+
* #3770: the paying agent's own evidence-only verdict on what the
|
|
67
|
+
* merchant DELIVERED (`ok` / `unusable` / `partial`, plus a bounded
|
|
68
|
+
* note). Additive and OPTIONAL: a server from before #3770 emits
|
|
69
|
+
* neither, and `null` means the agent has not reported. Ignored by
|
|
70
|
+
* `verifyPaymentReceipt`, which reads only `authorization` — the same
|
|
71
|
+
* rule `parties` follows. Evidence only: it never changes what the
|
|
72
|
+
* payment itself is, and `settled`/amounts are untouched by a report.
|
|
73
|
+
*/
|
|
74
|
+
deliveryQuality?: {
|
|
75
|
+
quality: 'ok' | 'unusable' | 'partial';
|
|
76
|
+
note: string | null;
|
|
77
|
+
reportedAt: string | null;
|
|
78
|
+
} | null;
|
|
79
|
+
};
|
|
80
|
+
/** The agent's cryptographic authorisation — what makes the receipt verifiable. */
|
|
81
|
+
authorization: {
|
|
82
|
+
delegate: string;
|
|
83
|
+
signHash: string;
|
|
84
|
+
signature: string | null;
|
|
85
|
+
/**
|
|
86
|
+
* #3418: which digest the delegate signed — selects what offline
|
|
87
|
+
* verification rebuilds. `'eip712_delegation'`: the settlement
|
|
88
|
+
* delegation's EIP-712 digest (erc7710). `'eip712_userop'`: an ERC-4337
|
|
89
|
+
* user-operation digest the bundle does not carry (direct payments, the
|
|
90
|
+
* eip3009 funding leg) — not verifiable offline. Absent on retired-rail
|
|
91
|
+
* bundles and on backends older than #3418, whose `signHash` was signed
|
|
92
|
+
* raw. The value is only a selector: a lying one cannot make a forged
|
|
93
|
+
* signature verify, because recovery must still return `delegate`.
|
|
94
|
+
*/
|
|
95
|
+
signatureScheme?: 'eip712_delegation' | 'eip712_userop';
|
|
96
|
+
};
|
|
97
|
+
onChain: {
|
|
98
|
+
txHash: string | null;
|
|
99
|
+
chainId: number;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
type ReceiptVerification = {
|
|
103
|
+
verified: true;
|
|
104
|
+
recoveredSigner: string;
|
|
105
|
+
verifiedOver: 'sign_hash' | 'delegation_digest';
|
|
106
|
+
} | {
|
|
107
|
+
verified: false;
|
|
108
|
+
reason:
|
|
109
|
+
/** #3418: the input is not a haven-receipt-1 bundle (a haven_list_receipts row, null, undefined, a non-object). */
|
|
110
|
+
'not_a_signed_receipt'
|
|
111
|
+
/** #3418: eip712_userop bundle; or a delegation bundle on a chain the SDK pins no DelegationManager for. */
|
|
112
|
+
| 'not_verifiable_offline' | 'missing_signature' | 'bad_signature' | 'signer_mismatch';
|
|
113
|
+
recoveredSigner?: string;
|
|
114
|
+
};
|
|
115
|
+
type RecoverFn = (hash: string, signature: string) => string;
|
|
116
|
+
/**
|
|
117
|
+
* Verify a receipt's agent authorisation offline: recover the signer and
|
|
118
|
+
* confirm it is the agent delegate, over whichever digest the bundle's scheme
|
|
119
|
+
* names (see the module doc for what that proves — and what it does not).
|
|
120
|
+
* Never throws: anything that is not a signed receipt — a
|
|
121
|
+
* `haven_list_receipts` history row, null, undefined, a non-object — returns
|
|
122
|
+
* `not_a_signed_receipt`. The `{ receipt, verification }` wrapper the receipt
|
|
123
|
+
* endpoint returns is accepted as-is: `.receipt` is verified, and the
|
|
124
|
+
* wrapper's `verification` — Haven's own self-check — is never read. Pure —
|
|
125
|
+
* `recover` is injectable but defaults to
|
|
126
|
+
* standard ECDSA recovery, so this runs anywhere (no Haven backend).
|
|
127
|
+
*/
|
|
128
|
+
declare function verifyPaymentReceipt(receipt: unknown, recover?: RecoverFn): ReceiptVerification;
|
|
129
|
+
|
|
130
|
+
export { type PaymentReceipt as P, type ReceiptVerification as R, RECEIPT_VERSION as a, verifyPaymentReceipt as v };
|
package/dist/test-support.cjs
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk7UTWSJC5_cjs = require('./chunk-7UTWSJC5.cjs');
|
|
4
|
+
var chunk4Z6ATE44_cjs = require('./chunk-4Z6ATE44.cjs');
|
|
4
5
|
var viem = require('viem');
|
|
6
|
+
var ethers = require('ethers');
|
|
5
7
|
|
|
6
8
|
var ZERO_BYTES32 = `0x${"00".repeat(32)}`;
|
|
7
9
|
var ROOT_AUTHORITY = `0x${"ff".repeat(32)}`;
|
|
8
10
|
var DEFAULT_DELEGATOR = "0x98989898989898989898989898989898989898De";
|
|
9
11
|
var DELEGATION_ARRAY_PARAM = [
|
|
10
|
-
{ type: "tuple[]", components:
|
|
12
|
+
{ type: "tuple[]", components: chunk4Z6ATE44_cjs.DELEGATION_TUPLE_COMPONENTS }
|
|
11
13
|
];
|
|
12
14
|
var EXECUTE_ABI = [
|
|
13
15
|
{
|
|
@@ -83,16 +85,16 @@ function buildBoundRedeemDelegationsCallData(options) {
|
|
|
83
85
|
10000n
|
|
84
86
|
);
|
|
85
87
|
return viem.encodeFunctionData({
|
|
86
|
-
abi:
|
|
88
|
+
abi: chunk4Z6ATE44_cjs.REDEEM_DELEGATIONS_ABI,
|
|
87
89
|
functionName: "redeemDelegations",
|
|
88
|
-
args: [[permissionContext], [
|
|
90
|
+
args: [[permissionContext], [chunk4Z6ATE44_cjs.SINGLE_DEFAULT_MODE], [executionCallData]]
|
|
89
91
|
});
|
|
90
92
|
}
|
|
91
93
|
function buildEmptyPermissionContextRedemption(selfCallCallData) {
|
|
92
94
|
return viem.encodeFunctionData({
|
|
93
|
-
abi:
|
|
95
|
+
abi: chunk4Z6ATE44_cjs.REDEEM_DELEGATIONS_ABI,
|
|
94
96
|
functionName: "redeemDelegations",
|
|
95
|
-
args: [[buildEmptyPermissionContext()], [
|
|
97
|
+
args: [[buildEmptyPermissionContext()], [chunk4Z6ATE44_cjs.SINGLE_DEFAULT_MODE], [selfCallCallData]]
|
|
96
98
|
});
|
|
97
99
|
}
|
|
98
100
|
function buildExecuteCallData(target, value, innerCallData) {
|
|
@@ -104,20 +106,20 @@ function buildExecuteCallData(target, value, innerCallData) {
|
|
|
104
106
|
}
|
|
105
107
|
function buildBoundDirectUserOp(options) {
|
|
106
108
|
const chainId = options.chainId ?? 84532;
|
|
107
|
-
const sender = options.sender ??
|
|
109
|
+
const sender = options.sender ?? chunk4Z6ATE44_cjs.deriveDelegateAccountAddress(options.delegate);
|
|
108
110
|
const callData = options.callData ?? buildExecuteCallData(
|
|
109
|
-
options.target ??
|
|
111
|
+
options.target ?? chunk4Z6ATE44_cjs.DELEGATION_MANAGER,
|
|
110
112
|
options.value ?? 0n,
|
|
111
113
|
buildBoundRedeemDelegationsCallData({ delegate: sender, delegator: options.delegator })
|
|
112
114
|
);
|
|
113
115
|
const typedData = {
|
|
114
116
|
domain: {
|
|
115
|
-
name:
|
|
116
|
-
version:
|
|
117
|
+
name: chunk4Z6ATE44_cjs.HYBRID_DELEGATOR_DOMAIN_NAME,
|
|
118
|
+
version: chunk4Z6ATE44_cjs.HYBRID_DELEGATOR_DOMAIN_VERSION,
|
|
117
119
|
chainId,
|
|
118
120
|
verifyingContract: sender
|
|
119
121
|
},
|
|
120
|
-
types: { PackedUserOperation:
|
|
122
|
+
types: { PackedUserOperation: chunk4Z6ATE44_cjs.PACKED_USER_OPERATION_FIELDS.map((field) => ({ ...field })) },
|
|
121
123
|
primaryType: "PackedUserOperation",
|
|
122
124
|
message: {
|
|
123
125
|
sender,
|
|
@@ -128,10 +130,10 @@ function buildBoundDirectUserOp(options) {
|
|
|
128
130
|
preVerificationGas: "0",
|
|
129
131
|
gasFees: ZERO_BYTES32,
|
|
130
132
|
paymasterAndData: "0x",
|
|
131
|
-
entryPoint:
|
|
133
|
+
entryPoint: chunk4Z6ATE44_cjs.ENTRY_POINT_V07
|
|
132
134
|
}
|
|
133
135
|
};
|
|
134
|
-
const payloadHash =
|
|
136
|
+
const payloadHash = chunk4Z6ATE44_cjs.packedUserOperationHash(typedData);
|
|
135
137
|
return { typedData, payloadHash, sender };
|
|
136
138
|
}
|
|
137
139
|
function buildSelfCallCallData(sender) {
|
|
@@ -149,7 +151,7 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
|
|
|
149
151
|
const originalCallData = fixtureTypedData.message.callData;
|
|
150
152
|
const { args: executeArgs } = viem.decodeFunctionData({ abi: EXECUTE_ABI, data: originalCallData });
|
|
151
153
|
const execution = executeArgs[0];
|
|
152
|
-
const { args: redeemArgs } = viem.decodeFunctionData({ abi:
|
|
154
|
+
const { args: redeemArgs } = viem.decodeFunctionData({ abi: chunk4Z6ATE44_cjs.REDEEM_DELEGATIONS_ABI, data: execution.callData });
|
|
153
155
|
const [permissionContexts, modes, executionCallDatas] = redeemArgs;
|
|
154
156
|
const [delegations] = viem.decodeAbiParameters(DELEGATION_ARRAY_PARAM, permissionContexts[0]);
|
|
155
157
|
const adjustedDelegations = delegations.map(
|
|
@@ -157,7 +159,7 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
|
|
|
157
159
|
);
|
|
158
160
|
const adjustedPermissionContext = viem.encodeAbiParameters(DELEGATION_ARRAY_PARAM, [adjustedDelegations]);
|
|
159
161
|
const adjustedRedeemCallData = viem.encodeFunctionData({
|
|
160
|
-
abi:
|
|
162
|
+
abi: chunk4Z6ATE44_cjs.REDEEM_DELEGATIONS_ABI,
|
|
161
163
|
functionName: "redeemDelegations",
|
|
162
164
|
args: [[adjustedPermissionContext], modes, executionCallDatas]
|
|
163
165
|
});
|
|
@@ -171,13 +173,13 @@ function rebuildDirectUserOpForSender(fixtureTypedData, newSender) {
|
|
|
171
173
|
domain: { ...fixtureTypedData.domain, verifyingContract: newSender },
|
|
172
174
|
message: { ...fixtureTypedData.message, sender: newSender, callData: adjustedCallData }
|
|
173
175
|
};
|
|
174
|
-
const payloadHash =
|
|
176
|
+
const payloadHash = chunk4Z6ATE44_cjs.packedUserOperationHash(typedData);
|
|
175
177
|
return { typedData, payloadHash };
|
|
176
178
|
}
|
|
177
179
|
function buildFundingLegUserOp(options) {
|
|
178
|
-
const sender =
|
|
180
|
+
const sender = chunk4Z6ATE44_cjs.deriveDelegateAccountAddress(options.delegate);
|
|
179
181
|
const callData = buildExecuteCallData(
|
|
180
|
-
|
|
182
|
+
chunk4Z6ATE44_cjs.DELEGATION_MANAGER,
|
|
181
183
|
0n,
|
|
182
184
|
buildBoundRedeemDelegationsCallData({
|
|
183
185
|
delegate: sender,
|
|
@@ -196,8 +198,58 @@ function buildFundingLegUserOp(options) {
|
|
|
196
198
|
});
|
|
197
199
|
return { typedData, payloadHash, digest: viem.hashTypedData(typedData) };
|
|
198
200
|
}
|
|
201
|
+
var RECEIPT_DELEGATE_KEY = `0x${"77".repeat(32)}`;
|
|
202
|
+
var OTHER_RECEIPT_KEY = `0x${"88".repeat(32)}`;
|
|
203
|
+
var EIP712_DOMAIN_TYPEHASH = viem.keccak256(
|
|
204
|
+
viem.toBytes("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")
|
|
205
|
+
);
|
|
206
|
+
function delegationDigest(signHash, chainId) {
|
|
207
|
+
const domainSeparator = viem.keccak256(
|
|
208
|
+
viem.encodeAbiParameters(
|
|
209
|
+
[{ type: "bytes32" }, { type: "bytes32" }, { type: "bytes32" }, { type: "uint256" }, { type: "address" }],
|
|
210
|
+
[
|
|
211
|
+
EIP712_DOMAIN_TYPEHASH,
|
|
212
|
+
viem.keccak256(viem.toBytes("DelegationManager")),
|
|
213
|
+
viem.keccak256(viem.toBytes("1")),
|
|
214
|
+
BigInt(chainId),
|
|
215
|
+
chunk4Z6ATE44_cjs.DELEGATION_MANAGER
|
|
216
|
+
]
|
|
217
|
+
)
|
|
218
|
+
);
|
|
219
|
+
return viem.keccak256(viem.concatHex(["0x1901", domainSeparator, signHash]));
|
|
220
|
+
}
|
|
221
|
+
function signedErc7710Receipt(options = {}) {
|
|
222
|
+
const chainId = options.chainId ?? 84532;
|
|
223
|
+
const signHash = options.signHash ?? `0x${"5e".repeat(32)}`;
|
|
224
|
+
const delegate = new ethers.Wallet(options.delegateKey ?? RECEIPT_DELEGATE_KEY);
|
|
225
|
+
const signature = delegate.signingKey.sign(delegationDigest(signHash, chainId)).serialized;
|
|
226
|
+
return {
|
|
227
|
+
version: chunk7UTWSJC5_cjs.RECEIPT_VERSION,
|
|
228
|
+
paymentId: options.paymentId ?? "pay_3723",
|
|
229
|
+
payment: {
|
|
230
|
+
token: "USDC",
|
|
231
|
+
tokenAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
232
|
+
amount: "0.50",
|
|
233
|
+
amountSek: "5.25",
|
|
234
|
+
recipient: "0x15179876c595922999C2d5DC7c23Cc7711fE799a",
|
|
235
|
+
account: "0x135a9215604711AC70d970e12Caa812c53537EF4",
|
|
236
|
+
chainId,
|
|
237
|
+
settledAt: "2026-10-07T10:00:00.000Z",
|
|
238
|
+
resourceUrl: "https://merchant.example/resource"
|
|
239
|
+
},
|
|
240
|
+
authorization: {
|
|
241
|
+
delegate: delegate.address,
|
|
242
|
+
signHash,
|
|
243
|
+
signature,
|
|
244
|
+
signatureScheme: "eip712_delegation"
|
|
245
|
+
},
|
|
246
|
+
onChain: { txHash: `0x${"cd".repeat(32)}`, chainId }
|
|
247
|
+
};
|
|
248
|
+
}
|
|
199
249
|
|
|
200
250
|
exports.DEFAULT_DELEGATOR = DEFAULT_DELEGATOR;
|
|
251
|
+
exports.OTHER_RECEIPT_KEY = OTHER_RECEIPT_KEY;
|
|
252
|
+
exports.RECEIPT_DELEGATE_KEY = RECEIPT_DELEGATE_KEY;
|
|
201
253
|
exports.buildBoundDirectUserOp = buildBoundDirectUserOp;
|
|
202
254
|
exports.buildBoundRedeemDelegationsCallData = buildBoundRedeemDelegationsCallData;
|
|
203
255
|
exports.buildChainPermissionContext = buildChainPermissionContext;
|
|
@@ -211,5 +263,6 @@ exports.buildSelfCallCallData = buildSelfCallCallData;
|
|
|
211
263
|
exports.buildSingleExecutionCallData = buildSingleExecutionCallData;
|
|
212
264
|
exports.buildTransferExecutionCallData = buildTransferExecutionCallData;
|
|
213
265
|
exports.rebuildDirectUserOpForSender = rebuildDirectUserOpForSender;
|
|
266
|
+
exports.signedErc7710Receipt = signedErc7710Receipt;
|
|
214
267
|
//# sourceMappingURL=test-support.cjs.map
|
|
215
268
|
//# sourceMappingURL=test-support.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/test-support/direct-userop.ts"],"names":["DELEGATION_TUPLE_COMPONENTS","encodeAbiParameters","encodePacked","encodeFunctionData","REDEEM_DELEGATIONS_ABI","SINGLE_DEFAULT_MODE","deriveDelegateAccountAddress","DELEGATION_MANAGER","HYBRID_DELEGATOR_DOMAIN_NAME","HYBRID_DELEGATOR_DOMAIN_VERSION","PACKED_USER_OPERATION_FIELDS","ENTRY_POINT_V07","packedUserOperationHash","decodeFunctionData","decodeAbiParameters","hashTypedData"],"mappings":"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","file":"test-support.cjs","sourcesContent":["/**\n * #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for\n * signer tests: `sender` is the counterfactual delegate account for a given\n * owner EOA, and `callData` is `execute(DelegationManager, 0,\n * redeemDelegations(...))` with a REAL redemption shape — one non-empty\n * `Delegation`, `delegate` = the signer's own account, `delegator` = a\n * distinct treasury address, `ExecutionMode.SingleDefault`, an\n * `encodePacked(target,value,callData)` execution — mirroring\n * `packages/backend/src/rails/delegation-rail.ts`'s `prepareRedemption`.\n * Replaces the toy 2-field / empty-callData / empty-arrays fixtures the\n * allowlist correctly refuses (including the B1 empty-permission-context\n * bypass, `buildEmptyPermissionContextRedemption` below, kept ONLY to\n * reproduce that exact refusal in a test).\n *\n * Moved here from `@haven_ai/signer` by #3283 so the SDK, the signer,\n * `@haven_ai/mcp` and `mcp-server` share ONE guard-valid builder. Published\n * as the `@haven_ai/sdk/test-support` subpath only because a sibling\n * package's tests cannot import this file by relative path (each package's\n * `tsc` `rootDir` is its own `src`). Test fixtures, not a signing API:\n * nothing here signs, and nothing the SDK or signer runs imports it.\n */\nimport {\n decodeAbiParameters,\n decodeFunctionData,\n encodeAbiParameters,\n encodeFunctionData,\n encodePacked,\n hashTypedData,\n type Address,\n type Hex,\n} from 'viem'\nimport {\n ENTRY_POINT_V07,\n HYBRID_DELEGATOR_DOMAIN_NAME,\n HYBRID_DELEGATOR_DOMAIN_VERSION,\n PACKED_USER_OPERATION_FIELDS,\n packedUserOperationHash,\n} from '../userop-binding.js'\nimport { DELEGATION_MANAGER } from '../settlement-child.js'\nimport { deriveDelegateAccountAddress } from '../delegate-account.js'\nimport { DELEGATION_TUPLE_COMPONENTS, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE } from '../redemption-guard.js'\n\nconst ZERO_BYTES32 = `0x${'00'.repeat(32)}` as const\n\n/** `Delegation.authority` sentinel for a root (unchained) delegation — `@metamask/delegation-core`'s `ROOT_AUTHORITY`. */\nconst ROOT_AUTHORITY: Hex = `0x${'ff'.repeat(32)}`\n\n/** Stand-in treasury address — distinct from any derived signer account, matching the real fixture's `delegator`. */\nexport const DEFAULT_DELEGATOR: Address = '0x98989898989898989898989898989898989898De' as Address\n\nconst DELEGATION_ARRAY_PARAM = [\n { type: 'tuple[]', components: DELEGATION_TUPLE_COMPONENTS },\n] as const\n\nconst EXECUTE_ABI = [\n {\n type: 'function',\n name: 'execute',\n inputs: [\n {\n name: '_execution',\n type: 'tuple',\n components: [\n { name: 'target', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'callData', type: 'bytes' },\n ],\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n] as const\n\nconst TRANSFER_ABI = [\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n] as const\n\nexport interface DelegationOverrides {\n /** The redeemer this delegation authorises — normally the signer's own derived account. */\n delegate: Address\n /** Who granted it — must differ from `delegate` for a real (non-self) delegation. */\n delegator?: Address\n authority?: Hex\n caveats?: Array<{ enforcer: Address; terms: Hex; args: Hex }>\n salt?: bigint\n signature?: Hex\n}\n\n/** A single, well-formed `Delegation` tuple — the ONE-link chain Haven's backend redeems (`delegations: [[delegation]]`). */\nexport function buildDelegation(overrides: DelegationOverrides) {\n return {\n delegate: overrides.delegate,\n delegator: overrides.delegator ?? DEFAULT_DELEGATOR,\n authority: overrides.authority ?? ROOT_AUTHORITY,\n caveats: overrides.caveats ?? [\n // A real-shaped (if inert for test purposes) TimestampEnforcer term —\n // real budget delegations always carry at least one caveat.\n { enforcer: '0x1046bb45C8d673d4ea75321280DB34899413c069' as Address, terms: `0x${'00'.repeat(32)}` as Hex, args: '0x' as Hex },\n ],\n salt: overrides.salt ?? 1n,\n signature: overrides.signature ?? (`0x${'ab'.repeat(65)}` as Hex),\n }\n}\n\n/** `abi.encode(Delegation[])` for a ONE-delegation chain — a Haven-shaped permission context. */\nexport function buildPermissionContext(delegation: ReturnType<typeof buildDelegation>): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [[delegation]])\n}\n\n/** `abi.encode(Delegation[])` for a MULTI-link chain (leaf first) — never emitted by Haven. */\nexport function buildChainPermissionContext(chain: ReturnType<typeof buildDelegation>[]): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [chain])\n}\n\n/** `abi.encode(Delegation[])` for an EMPTY chain — the exact B1 bypass shape MetaMask's DelegationManager treats as self-authorised. */\nexport function buildEmptyPermissionContext(): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [[]])\n}\n\n/** `encodePacked(address,uint256,bytes)` — the single-execution calldata `ExecutionMode.SingleDefault` expects. */\nexport function buildSingleExecutionCallData(target: Address, value: bigint, innerCallData: Hex): Hex {\n return encodePacked(['address', 'uint256', 'bytes'], [target, value, innerCallData])\n}\n\n/** A real-shaped ERC-20 `transfer(to, amount)` execution — what a budget redemption actually spends. */\nexport function buildTransferExecutionCallData(token: Address, to: Address, amount: bigint): Hex {\n return buildSingleExecutionCallData(\n token,\n 0n,\n encodeFunctionData({ abi: TRANSFER_ABI, functionName: 'transfer', args: [to, amount] }),\n )\n}\n\nexport interface BoundRedeemDelegationsOptions {\n /** The redeemer — normally the signer's own derived account (matches the UserOp's `sender`). */\n delegate: Address\n delegator?: Address\n caveats?: DelegationOverrides['caveats']\n /** Override the single execution's calldata entirely (default: a real-shaped ERC-20 transfer). */\n executionCallData?: Hex\n}\n\n/** `redeemDelegations([permissionContext], [SingleDefault], [executionCallData])` — the REAL, bound shape. */\nexport function buildBoundRedeemDelegationsCallData(options: BoundRedeemDelegationsOptions): Hex {\n const delegation = buildDelegation({ delegate: options.delegate, delegator: options.delegator, caveats: options.caveats })\n const permissionContext = buildPermissionContext(delegation)\n const executionCallData =\n options.executionCallData ??\n buildTransferExecutionCallData(\n '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as Address, // Base Sepolia USDC, matches the real captured fixture\n '0x98ffBf30459a98FD80fAce18f519967769641F76' as Address,\n 10000n,\n )\n return encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[permissionContext], [SINGLE_DEFAULT_MODE], [executionCallData]],\n })\n}\n\n/**\n * #3272 (B1 regression): `redeemDelegations([emptyPermissionContext],\n * [SingleDefault], [selfCallCallData])` — one permission context whose\n * `Delegation[]` decodes EMPTY, paired with a self-call execution. This is\n * the exact live bypass: MetaMask's DelegationManager treats an empty chain\n * as self-authorised and runs `selfCallCallData` AS the account. Exists only\n * so a test can assert this is refused, never to build a shape any code path\n * signs.\n */\nexport function buildEmptyPermissionContextRedemption(selfCallCallData: Hex): Hex {\n return encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[buildEmptyPermissionContext()], [SINGLE_DEFAULT_MODE], [selfCallCallData]],\n })\n}\n\n/** `execute((address,uint256,bytes))` — selector `0x5c1c6dcd`. */\nexport function buildExecuteCallData(target: Address, value: bigint, innerCallData: Hex): Hex {\n return encodeFunctionData({\n abi: EXECUTE_ABI,\n functionName: 'execute',\n args: [{ target, value, callData: innerCallData }],\n })\n}\n\nexport interface BoundDirectUserOpOptions {\n /** The delegate EOA (`signer.delegateAddress`) that owns the account `sender` derives from. */\n delegate: Address\n chainId?: number | bigint | string\n /** Override the execute() target — default DELEGATION_MANAGER (the bound shape). */\n target?: Address\n /** Override the execute() value — default 0n. */\n value?: bigint\n /** Override the full message.callData (bypasses target/value/redeemDelegations construction). */\n callData?: Hex\n /** Override sender/verifyingContract directly instead of deriving it from `delegate`. */\n sender?: Address\n /** Override the redemption's delegator (default: a distinct treasury address). */\n delegator?: Address\n}\n\nexport interface BoundDirectUserOp {\n typedData: {\n domain: { name: string; version: string; chainId: number | bigint | string; verifyingContract: Address }\n types: { PackedUserOperation: Array<{ name: string; type: string }> }\n primaryType: 'PackedUserOperation'\n message: Record<string, unknown>\n }\n payloadHash: Hex\n sender: Address\n}\n\n/**\n * A real-shaped, self-consistent (correct v0.7 hash) `PackedUserOperation`.\n * By default it is fully BOUND per #3272's allowlist: `sender` is the\n * counterfactual account for `delegate`, and `callData` redeems ONE real\n * delegation (delegate = `sender`, delegator = a distinct treasury address)\n * through the DelegationManager. Override `target` / `callData` / `sender` /\n * `delegator` to build the negative-test shapes the allowlist must refuse.\n */\nexport function buildBoundDirectUserOp(options: BoundDirectUserOpOptions): BoundDirectUserOp {\n const chainId = options.chainId ?? 84532\n const sender = options.sender ?? deriveDelegateAccountAddress(options.delegate)\n const callData =\n options.callData ??\n buildExecuteCallData(\n options.target ?? (DELEGATION_MANAGER as Address),\n options.value ?? 0n,\n buildBoundRedeemDelegationsCallData({ delegate: sender, delegator: options.delegator }),\n )\n const typedData = {\n domain: {\n name: HYBRID_DELEGATOR_DOMAIN_NAME,\n version: HYBRID_DELEGATOR_DOMAIN_VERSION,\n chainId,\n verifyingContract: sender,\n },\n types: { PackedUserOperation: PACKED_USER_OPERATION_FIELDS.map((field) => ({ ...field })) },\n primaryType: 'PackedUserOperation' as const,\n message: {\n sender,\n nonce: '0',\n initCode: '0x',\n callData,\n accountGasLimits: ZERO_BYTES32,\n preVerificationGas: '0',\n gasFees: ZERO_BYTES32,\n paymasterAndData: '0x',\n entryPoint: ENTRY_POINT_V07,\n },\n }\n const payloadHash = packedUserOperationHash(typedData)\n return { typedData, payloadHash, sender }\n}\n\n/** A well-formed `execute()` self-call — `target === sender` — for the (d)/self-call negative tests. */\nexport function buildSelfCallCallData(sender: Address): Hex {\n const TRANSFER_OWNERSHIP_ABI = [\n { type: 'function', name: 'transferOwnership', inputs: [{ name: 'newOwner', type: 'address' }], outputs: [], stateMutability: 'nonpayable' },\n ] as const\n const inner = encodeFunctionData({\n abi: TRANSFER_OWNERSHIP_ABI,\n functionName: 'transferOwnership',\n args: ['0x000000000000000000000000000000000000dEaD' as Address],\n })\n return buildExecuteCallData(sender, 0n, inner)\n}\n\n/**\n * Re-target a REAL captured direct-payment UserOp (for example\n * `__fixtures__/direct-payment-userop.json`) at `newSender`: the UserOp's\n * `sender` / `verifyingContract` and the redeemed delegation's `delegate`\n * become `newSender`; the delegator, caveats, mode and execution stay the\n * production bytes. The captured fixture is bound to a delegate whose key is\n * not in the repository, so a test signs this rebuilt copy with a test key\n * whose derived account is `newSender` — proving the guard accepts the actual\n * production shape, not only this file's synthetic one.\n */\nexport function rebuildDirectUserOpForSender(\n fixtureTypedData: {\n domain: Record<string, unknown>\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n },\n newSender: Address,\n) {\n const originalCallData = fixtureTypedData.message.callData as Hex\n const { args: executeArgs } = decodeFunctionData({ abi: EXECUTE_ABI, data: originalCallData })\n const execution = executeArgs[0] as { target: Address; value: bigint; callData: Hex }\n const { args: redeemArgs } = decodeFunctionData({ abi: REDEEM_DELEGATIONS_ABI, data: execution.callData })\n const [permissionContexts, modes, executionCallDatas] = redeemArgs as unknown as [\n readonly Hex[],\n readonly Hex[],\n readonly Hex[],\n ]\n const [delegations] = decodeAbiParameters(DELEGATION_ARRAY_PARAM, permissionContexts[0])\n const adjustedDelegations = (delegations as unknown as Array<Record<string, unknown>>).map((d, i) =>\n i === 0 ? { ...d, delegate: newSender } : d,\n )\n const adjustedPermissionContext = encodeAbiParameters(DELEGATION_ARRAY_PARAM, [adjustedDelegations as never])\n const adjustedRedeemCallData = encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[adjustedPermissionContext], modes as Hex[], executionCallDatas as Hex[]],\n })\n const adjustedCallData = encodeFunctionData({\n abi: EXECUTE_ABI,\n functionName: 'execute',\n args: [{ target: execution.target, value: execution.value, callData: adjustedRedeemCallData }],\n })\n const typedData = {\n ...fixtureTypedData,\n domain: { ...fixtureTypedData.domain, verifyingContract: newSender },\n message: { ...fixtureTypedData.message, sender: newSender, callData: adjustedCallData },\n }\n const payloadHash = packedUserOperationHash(typedData as never) as Hex\n return { typedData, payloadHash }\n}\n\nexport interface FundingLegUserOpOptions {\n /** The delegate EOA (`signer.delegateAddress`): the account is derived from it AND it is the transfer's recipient. */\n delegate: Address\n /** The quoted token (the expected context's `asset`). */\n asset: Address\n /** The quoted atomic amount (the expected context's `amount`). */\n amount: bigint | string\n chainId?: number\n /** Override the transfer recipient (default: `delegate`) — for the recipient-pin negative test. */\n recipient?: Address\n /** Override the budget delegation's caveats (e.g. a multi-KB term, for relay-size tests). */\n caveats?: DelegationOverrides['caveats']\n}\n\n/**\n * #3281: an x402 EIP-3009 bridge FUNDING LEG exactly as the backend builds it\n * (`delegation-authorize.ts` → `prepareDelegationPayment(agent, token,\n * payTo = the delegate EOA, amountRaw)` → `prepareRedemption`): the\n * direct-payment shape, whose single execution is\n * `transfer(<delegate EOA>, <amount>)` on the quoted token. Returns the typed\n * data, its v0.7 UserOp hash (the expected context's `payloadHash`) and its\n * EIP-712 digest (the expected context's `typedDataHash`).\n */\nexport function buildFundingLegUserOp(options: FundingLegUserOpOptions) {\n const sender = deriveDelegateAccountAddress(options.delegate)\n const callData = buildExecuteCallData(\n DELEGATION_MANAGER as Address,\n 0n,\n buildBoundRedeemDelegationsCallData({\n delegate: sender,\n caveats: options.caveats,\n executionCallData: buildTransferExecutionCallData(\n options.asset,\n options.recipient ?? options.delegate,\n BigInt(options.amount),\n ),\n }),\n )\n const { typedData, payloadHash } = buildBoundDirectUserOp({\n delegate: options.delegate,\n chainId: options.chainId ?? 84532,\n callData,\n })\n return { typedData, payloadHash, digest: hashTypedData(typedData as never) }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/test-support/direct-userop.ts","../src/test-support/signed-receipt.ts"],"names":["DELEGATION_TUPLE_COMPONENTS","encodeAbiParameters","encodePacked","encodeFunctionData","REDEEM_DELEGATIONS_ABI","SINGLE_DEFAULT_MODE","deriveDelegateAccountAddress","DELEGATION_MANAGER","HYBRID_DELEGATOR_DOMAIN_NAME","HYBRID_DELEGATOR_DOMAIN_VERSION","PACKED_USER_OPERATION_FIELDS","ENTRY_POINT_V07","packedUserOperationHash","decodeFunctionData","decodeAbiParameters","hashTypedData","keccak256","toBytes","concatHex","Wallet","RECEIPT_VERSION"],"mappings":"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","file":"test-support.cjs","sourcesContent":["/**\n * #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for\n * signer tests: `sender` is the counterfactual delegate account for a given\n * owner EOA, and `callData` is `execute(DelegationManager, 0,\n * redeemDelegations(...))` with a REAL redemption shape — one non-empty\n * `Delegation`, `delegate` = the signer's own account, `delegator` = a\n * distinct treasury address, `ExecutionMode.SingleDefault`, an\n * `encodePacked(target,value,callData)` execution — mirroring\n * `packages/backend/src/rails/delegation-rail.ts`'s `prepareRedemption`.\n * Replaces the toy 2-field / empty-callData / empty-arrays fixtures the\n * allowlist correctly refuses (including the B1 empty-permission-context\n * bypass, `buildEmptyPermissionContextRedemption` below, kept ONLY to\n * reproduce that exact refusal in a test).\n *\n * Moved here from `@haven_ai/signer` by #3283 so the SDK, the signer,\n * `@haven_ai/mcp` and `mcp-server` share ONE guard-valid builder. Published\n * as the `@haven_ai/sdk/test-support` subpath only because a sibling\n * package's tests cannot import this file by relative path (each package's\n * `tsc` `rootDir` is its own `src`). Test fixtures, not a signing API:\n * nothing here signs, and nothing the SDK or signer runs imports it.\n */\nimport {\n decodeAbiParameters,\n decodeFunctionData,\n encodeAbiParameters,\n encodeFunctionData,\n encodePacked,\n hashTypedData,\n type Address,\n type Hex,\n} from 'viem'\nimport {\n ENTRY_POINT_V07,\n HYBRID_DELEGATOR_DOMAIN_NAME,\n HYBRID_DELEGATOR_DOMAIN_VERSION,\n PACKED_USER_OPERATION_FIELDS,\n packedUserOperationHash,\n} from '../userop-binding.js'\nimport { DELEGATION_MANAGER } from '../settlement-child.js'\nimport { deriveDelegateAccountAddress } from '../delegate-account.js'\nimport { DELEGATION_TUPLE_COMPONENTS, REDEEM_DELEGATIONS_ABI, SINGLE_DEFAULT_MODE } from '../redemption-guard.js'\n\nconst ZERO_BYTES32 = `0x${'00'.repeat(32)}` as const\n\n/** `Delegation.authority` sentinel for a root (unchained) delegation — `@metamask/delegation-core`'s `ROOT_AUTHORITY`. */\nconst ROOT_AUTHORITY: Hex = `0x${'ff'.repeat(32)}`\n\n/** Stand-in treasury address — distinct from any derived signer account, matching the real fixture's `delegator`. */\nexport const DEFAULT_DELEGATOR: Address = '0x98989898989898989898989898989898989898De' as Address\n\nconst DELEGATION_ARRAY_PARAM = [\n { type: 'tuple[]', components: DELEGATION_TUPLE_COMPONENTS },\n] as const\n\nconst EXECUTE_ABI = [\n {\n type: 'function',\n name: 'execute',\n inputs: [\n {\n name: '_execution',\n type: 'tuple',\n components: [\n { name: 'target', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'callData', type: 'bytes' },\n ],\n },\n ],\n outputs: [],\n stateMutability: 'payable',\n },\n] as const\n\nconst TRANSFER_ABI = [\n {\n type: 'function',\n name: 'transfer',\n inputs: [\n { name: 'to', type: 'address' },\n { name: 'amount', type: 'uint256' },\n ],\n outputs: [{ type: 'bool' }],\n stateMutability: 'nonpayable',\n },\n] as const\n\nexport interface DelegationOverrides {\n /** The redeemer this delegation authorises — normally the signer's own derived account. */\n delegate: Address\n /** Who granted it — must differ from `delegate` for a real (non-self) delegation. */\n delegator?: Address\n authority?: Hex\n caveats?: Array<{ enforcer: Address; terms: Hex; args: Hex }>\n salt?: bigint\n signature?: Hex\n}\n\n/** A single, well-formed `Delegation` tuple — the ONE-link chain Haven's backend redeems (`delegations: [[delegation]]`). */\nexport function buildDelegation(overrides: DelegationOverrides) {\n return {\n delegate: overrides.delegate,\n delegator: overrides.delegator ?? DEFAULT_DELEGATOR,\n authority: overrides.authority ?? ROOT_AUTHORITY,\n caveats: overrides.caveats ?? [\n // A real-shaped (if inert for test purposes) TimestampEnforcer term —\n // real budget delegations always carry at least one caveat.\n { enforcer: '0x1046bb45C8d673d4ea75321280DB34899413c069' as Address, terms: `0x${'00'.repeat(32)}` as Hex, args: '0x' as Hex },\n ],\n salt: overrides.salt ?? 1n,\n signature: overrides.signature ?? (`0x${'ab'.repeat(65)}` as Hex),\n }\n}\n\n/** `abi.encode(Delegation[])` for a ONE-delegation chain — a Haven-shaped permission context. */\nexport function buildPermissionContext(delegation: ReturnType<typeof buildDelegation>): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [[delegation]])\n}\n\n/** `abi.encode(Delegation[])` for a MULTI-link chain (leaf first) — never emitted by Haven. */\nexport function buildChainPermissionContext(chain: ReturnType<typeof buildDelegation>[]): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [chain])\n}\n\n/** `abi.encode(Delegation[])` for an EMPTY chain — the exact B1 bypass shape MetaMask's DelegationManager treats as self-authorised. */\nexport function buildEmptyPermissionContext(): Hex {\n return encodeAbiParameters(DELEGATION_ARRAY_PARAM, [[]])\n}\n\n/** `encodePacked(address,uint256,bytes)` — the single-execution calldata `ExecutionMode.SingleDefault` expects. */\nexport function buildSingleExecutionCallData(target: Address, value: bigint, innerCallData: Hex): Hex {\n return encodePacked(['address', 'uint256', 'bytes'], [target, value, innerCallData])\n}\n\n/** A real-shaped ERC-20 `transfer(to, amount)` execution — what a budget redemption actually spends. */\nexport function buildTransferExecutionCallData(token: Address, to: Address, amount: bigint): Hex {\n return buildSingleExecutionCallData(\n token,\n 0n,\n encodeFunctionData({ abi: TRANSFER_ABI, functionName: 'transfer', args: [to, amount] }),\n )\n}\n\nexport interface BoundRedeemDelegationsOptions {\n /** The redeemer — normally the signer's own derived account (matches the UserOp's `sender`). */\n delegate: Address\n delegator?: Address\n caveats?: DelegationOverrides['caveats']\n /** Override the single execution's calldata entirely (default: a real-shaped ERC-20 transfer). */\n executionCallData?: Hex\n}\n\n/** `redeemDelegations([permissionContext], [SingleDefault], [executionCallData])` — the REAL, bound shape. */\nexport function buildBoundRedeemDelegationsCallData(options: BoundRedeemDelegationsOptions): Hex {\n const delegation = buildDelegation({ delegate: options.delegate, delegator: options.delegator, caveats: options.caveats })\n const permissionContext = buildPermissionContext(delegation)\n const executionCallData =\n options.executionCallData ??\n buildTransferExecutionCallData(\n '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as Address, // Base Sepolia USDC, matches the real captured fixture\n '0x98ffBf30459a98FD80fAce18f519967769641F76' as Address,\n 10000n,\n )\n return encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[permissionContext], [SINGLE_DEFAULT_MODE], [executionCallData]],\n })\n}\n\n/**\n * #3272 (B1 regression): `redeemDelegations([emptyPermissionContext],\n * [SingleDefault], [selfCallCallData])` — one permission context whose\n * `Delegation[]` decodes EMPTY, paired with a self-call execution. This is\n * the exact live bypass: MetaMask's DelegationManager treats an empty chain\n * as self-authorised and runs `selfCallCallData` AS the account. Exists only\n * so a test can assert this is refused, never to build a shape any code path\n * signs.\n */\nexport function buildEmptyPermissionContextRedemption(selfCallCallData: Hex): Hex {\n return encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[buildEmptyPermissionContext()], [SINGLE_DEFAULT_MODE], [selfCallCallData]],\n })\n}\n\n/** `execute((address,uint256,bytes))` — selector `0x5c1c6dcd`. */\nexport function buildExecuteCallData(target: Address, value: bigint, innerCallData: Hex): Hex {\n return encodeFunctionData({\n abi: EXECUTE_ABI,\n functionName: 'execute',\n args: [{ target, value, callData: innerCallData }],\n })\n}\n\nexport interface BoundDirectUserOpOptions {\n /** The delegate EOA (`signer.delegateAddress`) that owns the account `sender` derives from. */\n delegate: Address\n chainId?: number | bigint | string\n /** Override the execute() target — default DELEGATION_MANAGER (the bound shape). */\n target?: Address\n /** Override the execute() value — default 0n. */\n value?: bigint\n /** Override the full message.callData (bypasses target/value/redeemDelegations construction). */\n callData?: Hex\n /** Override sender/verifyingContract directly instead of deriving it from `delegate`. */\n sender?: Address\n /** Override the redemption's delegator (default: a distinct treasury address). */\n delegator?: Address\n}\n\nexport interface BoundDirectUserOp {\n typedData: {\n domain: { name: string; version: string; chainId: number | bigint | string; verifyingContract: Address }\n types: { PackedUserOperation: Array<{ name: string; type: string }> }\n primaryType: 'PackedUserOperation'\n message: Record<string, unknown>\n }\n payloadHash: Hex\n sender: Address\n}\n\n/**\n * A real-shaped, self-consistent (correct v0.7 hash) `PackedUserOperation`.\n * By default it is fully BOUND per #3272's allowlist: `sender` is the\n * counterfactual account for `delegate`, and `callData` redeems ONE real\n * delegation (delegate = `sender`, delegator = a distinct treasury address)\n * through the DelegationManager. Override `target` / `callData` / `sender` /\n * `delegator` to build the negative-test shapes the allowlist must refuse.\n */\nexport function buildBoundDirectUserOp(options: BoundDirectUserOpOptions): BoundDirectUserOp {\n const chainId = options.chainId ?? 84532\n const sender = options.sender ?? deriveDelegateAccountAddress(options.delegate)\n const callData =\n options.callData ??\n buildExecuteCallData(\n options.target ?? (DELEGATION_MANAGER as Address),\n options.value ?? 0n,\n buildBoundRedeemDelegationsCallData({ delegate: sender, delegator: options.delegator }),\n )\n const typedData = {\n domain: {\n name: HYBRID_DELEGATOR_DOMAIN_NAME,\n version: HYBRID_DELEGATOR_DOMAIN_VERSION,\n chainId,\n verifyingContract: sender,\n },\n types: { PackedUserOperation: PACKED_USER_OPERATION_FIELDS.map((field) => ({ ...field })) },\n primaryType: 'PackedUserOperation' as const,\n message: {\n sender,\n nonce: '0',\n initCode: '0x',\n callData,\n accountGasLimits: ZERO_BYTES32,\n preVerificationGas: '0',\n gasFees: ZERO_BYTES32,\n paymasterAndData: '0x',\n entryPoint: ENTRY_POINT_V07,\n },\n }\n const payloadHash = packedUserOperationHash(typedData)\n return { typedData, payloadHash, sender }\n}\n\n/** A well-formed `execute()` self-call — `target === sender` — for the (d)/self-call negative tests. */\nexport function buildSelfCallCallData(sender: Address): Hex {\n const TRANSFER_OWNERSHIP_ABI = [\n { type: 'function', name: 'transferOwnership', inputs: [{ name: 'newOwner', type: 'address' }], outputs: [], stateMutability: 'nonpayable' },\n ] as const\n const inner = encodeFunctionData({\n abi: TRANSFER_OWNERSHIP_ABI,\n functionName: 'transferOwnership',\n args: ['0x000000000000000000000000000000000000dEaD' as Address],\n })\n return buildExecuteCallData(sender, 0n, inner)\n}\n\n/**\n * Re-target a REAL captured direct-payment UserOp (for example\n * `__fixtures__/direct-payment-userop.json`) at `newSender`: the UserOp's\n * `sender` / `verifyingContract` and the redeemed delegation's `delegate`\n * become `newSender`; the delegator, caveats, mode and execution stay the\n * production bytes. The captured fixture is bound to a delegate whose key is\n * not in the repository, so a test signs this rebuilt copy with a test key\n * whose derived account is `newSender` — proving the guard accepts the actual\n * production shape, not only this file's synthetic one.\n */\nexport function rebuildDirectUserOpForSender(\n fixtureTypedData: {\n domain: Record<string, unknown>\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n },\n newSender: Address,\n) {\n const originalCallData = fixtureTypedData.message.callData as Hex\n const { args: executeArgs } = decodeFunctionData({ abi: EXECUTE_ABI, data: originalCallData })\n const execution = executeArgs[0] as { target: Address; value: bigint; callData: Hex }\n const { args: redeemArgs } = decodeFunctionData({ abi: REDEEM_DELEGATIONS_ABI, data: execution.callData })\n const [permissionContexts, modes, executionCallDatas] = redeemArgs as unknown as [\n readonly Hex[],\n readonly Hex[],\n readonly Hex[],\n ]\n const [delegations] = decodeAbiParameters(DELEGATION_ARRAY_PARAM, permissionContexts[0])\n const adjustedDelegations = (delegations as unknown as Array<Record<string, unknown>>).map((d, i) =>\n i === 0 ? { ...d, delegate: newSender } : d,\n )\n const adjustedPermissionContext = encodeAbiParameters(DELEGATION_ARRAY_PARAM, [adjustedDelegations as never])\n const adjustedRedeemCallData = encodeFunctionData({\n abi: REDEEM_DELEGATIONS_ABI,\n functionName: 'redeemDelegations',\n args: [[adjustedPermissionContext], modes as Hex[], executionCallDatas as Hex[]],\n })\n const adjustedCallData = encodeFunctionData({\n abi: EXECUTE_ABI,\n functionName: 'execute',\n args: [{ target: execution.target, value: execution.value, callData: adjustedRedeemCallData }],\n })\n const typedData = {\n ...fixtureTypedData,\n domain: { ...fixtureTypedData.domain, verifyingContract: newSender },\n message: { ...fixtureTypedData.message, sender: newSender, callData: adjustedCallData },\n }\n const payloadHash = packedUserOperationHash(typedData as never) as Hex\n return { typedData, payloadHash }\n}\n\nexport interface FundingLegUserOpOptions {\n /** The delegate EOA (`signer.delegateAddress`): the account is derived from it AND it is the transfer's recipient. */\n delegate: Address\n /** The quoted token (the expected context's `asset`). */\n asset: Address\n /** The quoted atomic amount (the expected context's `amount`). */\n amount: bigint | string\n chainId?: number\n /** Override the transfer recipient (default: `delegate`) — for the recipient-pin negative test. */\n recipient?: Address\n /** Override the budget delegation's caveats (e.g. a multi-KB term, for relay-size tests). */\n caveats?: DelegationOverrides['caveats']\n}\n\n/**\n * #3281: an x402 EIP-3009 bridge FUNDING LEG exactly as the backend builds it\n * (`delegation-authorize.ts` → `prepareDelegationPayment(agent, token,\n * payTo = the delegate EOA, amountRaw)` → `prepareRedemption`): the\n * direct-payment shape, whose single execution is\n * `transfer(<delegate EOA>, <amount>)` on the quoted token. Returns the typed\n * data, its v0.7 UserOp hash (the expected context's `payloadHash`) and its\n * EIP-712 digest (the expected context's `typedDataHash`).\n */\nexport function buildFundingLegUserOp(options: FundingLegUserOpOptions) {\n const sender = deriveDelegateAccountAddress(options.delegate)\n const callData = buildExecuteCallData(\n DELEGATION_MANAGER as Address,\n 0n,\n buildBoundRedeemDelegationsCallData({\n delegate: sender,\n caveats: options.caveats,\n executionCallData: buildTransferExecutionCallData(\n options.asset,\n options.recipient ?? options.delegate,\n BigInt(options.amount),\n ),\n }),\n )\n const { typedData, payloadHash } = buildBoundDirectUserOp({\n delegate: options.delegate,\n chainId: options.chainId ?? 84532,\n callData,\n })\n return { typedData, payloadHash, digest: hashTypedData(typedData as never) }\n}\n","/**\n * #3723 — a REAL signed erc7710 receipt bundle for handler-level tests: the\n * delegate key signs the DelegationManager EIP-712 digest rebuilt from the\n * bundle's own `signHash` + `onChain.chainId`, exactly the math\n * `verifyPaymentReceipt` performs. So `verifyPaymentReceipt(bundle)` returns\n * `{ verified: true, verifiedOver: 'delegation_digest' }` with the DEFAULT\n * ECDSA recovery — the first positive handler-level verify fixture on the\n * MCP runtimes (no stdio-originated payment is erc7710 live: `haven_send` is\n * direct and the stdio x402 path is the eip3009 bridge).\n *\n * Published on the `@haven_ai/sdk/test-support` subpath like the UserOp\n * builder: a sibling package's tests cannot import this file by relative\n * path. Test fixtures, not a signing API: nothing the SDK or signer runs\n * imports it.\n */\nimport { Wallet } from 'ethers'\nimport { concatHex, encodeAbiParameters, keccak256, toBytes, type Hex } from 'viem'\nimport { DELEGATION_MANAGER } from '../settlement-child.js'\nimport { RECEIPT_VERSION, type PaymentReceipt } from '../receipt.js'\n\n/** A fixed delegate key so fixtures are deterministic across runs. */\nexport const RECEIPT_DELEGATE_KEY = `0x${'77'.repeat(32)}` as const\n/** A distinct key, for signer_mismatch fixtures. */\nexport const OTHER_RECEIPT_KEY = `0x${'88'.repeat(32)}` as const\n\nconst EIP712_DOMAIN_TYPEHASH = keccak256(\n toBytes('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),\n)\n\n/** Same rebuild the verifier does — mirrored here so drift turns the positive test red. */\nfunction delegationDigest(signHash: string, chainId: number): Hex {\n const domainSeparator = keccak256(\n encodeAbiParameters(\n [{ type: 'bytes32' }, { type: 'bytes32' }, { type: 'bytes32' }, { type: 'uint256' }, { type: 'address' }],\n [\n EIP712_DOMAIN_TYPEHASH,\n keccak256(toBytes('DelegationManager')),\n keccak256(toBytes('1')),\n BigInt(chainId),\n DELEGATION_MANAGER as Hex,\n ],\n ),\n )\n return keccak256(concatHex(['0x1901', domainSeparator, signHash as Hex]))\n}\n\nexport interface SignedErc7710Options {\n /** Defaults to `RECEIPT_DELEGATE_KEY`; pass `OTHER_RECEIPT_KEY` for a forged bundle. */\n delegateKey?: string\n signHash?: string\n chainId?: number\n paymentId?: string\n}\n\n/**\n * A signed erc7710 bundle whose `authorization.signature` recovers to the\n * delegate over the delegation digest — `verifyPaymentReceipt` verifies it\n * offline with the default recovery.\n */\nexport function signedErc7710Receipt(options: SignedErc7710Options = {}): PaymentReceipt {\n const chainId = options.chainId ?? 84532 // Base Sepolia — a chain the SDK pins\n const signHash = options.signHash ?? (`0x${'5e'.repeat(32)}` as const)\n const delegate = new Wallet(options.delegateKey ?? RECEIPT_DELEGATE_KEY)\n const signature = delegate.signingKey.sign(delegationDigest(signHash, chainId)).serialized\n return {\n version: RECEIPT_VERSION,\n paymentId: options.paymentId ?? 'pay_3723',\n payment: {\n token: 'USDC',\n tokenAddress: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',\n amount: '0.50',\n amountSek: '5.25',\n recipient: '0x15179876c595922999C2d5DC7c23Cc7711fE799a',\n account: '0x135a9215604711AC70d970e12Caa812c53537EF4',\n chainId,\n settledAt: '2026-10-07T10:00:00.000Z',\n resourceUrl: 'https://merchant.example/resource',\n },\n authorization: {\n delegate: delegate.address,\n signHash,\n signature,\n signatureScheme: 'eip712_delegation',\n },\n onChain: { txHash: `0x${'cd'.repeat(32)}`, chainId },\n }\n}\n"]}
|
package/dist/test-support.d.cts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Address, Hex } from 'viem';
|
|
2
|
+
import { P as PaymentReceipt } from './receipt-D4Roey3D.cjs';
|
|
3
|
+
import './types-CrszUJ7Z.cjs';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for
|
|
@@ -201,4 +203,22 @@ declare function buildFundingLegUserOp(options: FundingLegUserOpOptions): {
|
|
|
201
203
|
digest: `0x${string}`;
|
|
202
204
|
};
|
|
203
205
|
|
|
204
|
-
|
|
206
|
+
/** A fixed delegate key so fixtures are deterministic across runs. */
|
|
207
|
+
declare const RECEIPT_DELEGATE_KEY: `0x${string}`;
|
|
208
|
+
/** A distinct key, for signer_mismatch fixtures. */
|
|
209
|
+
declare const OTHER_RECEIPT_KEY: `0x${string}`;
|
|
210
|
+
interface SignedErc7710Options {
|
|
211
|
+
/** Defaults to `RECEIPT_DELEGATE_KEY`; pass `OTHER_RECEIPT_KEY` for a forged bundle. */
|
|
212
|
+
delegateKey?: string;
|
|
213
|
+
signHash?: string;
|
|
214
|
+
chainId?: number;
|
|
215
|
+
paymentId?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* A signed erc7710 bundle whose `authorization.signature` recovers to the
|
|
219
|
+
* delegate over the delegation digest — `verifyPaymentReceipt` verifies it
|
|
220
|
+
* offline with the default recovery.
|
|
221
|
+
*/
|
|
222
|
+
declare function signedErc7710Receipt(options?: SignedErc7710Options): PaymentReceipt;
|
|
223
|
+
|
|
224
|
+
export { type BoundDirectUserOp, type BoundDirectUserOpOptions, type BoundRedeemDelegationsOptions, DEFAULT_DELEGATOR, type DelegationOverrides, type FundingLegUserOpOptions, OTHER_RECEIPT_KEY, RECEIPT_DELEGATE_KEY, type SignedErc7710Options, buildBoundDirectUserOp, buildBoundRedeemDelegationsCallData, buildChainPermissionContext, buildDelegation, buildEmptyPermissionContext, buildEmptyPermissionContextRedemption, buildExecuteCallData, buildFundingLegUserOp, buildPermissionContext, buildSelfCallCallData, buildSingleExecutionCallData, buildTransferExecutionCallData, rebuildDirectUserOpForSender, signedErc7710Receipt };
|
package/dist/test-support.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Address, Hex } from 'viem';
|
|
2
|
+
import { P as PaymentReceipt } from './receipt-WkXHZGbu.js';
|
|
3
|
+
import './types-CrszUJ7Z.js';
|
|
2
4
|
|
|
3
5
|
/**
|
|
4
6
|
* #3272 — a real-shaped, BOUND direct-payment `PackedUserOperation` for
|
|
@@ -201,4 +203,22 @@ declare function buildFundingLegUserOp(options: FundingLegUserOpOptions): {
|
|
|
201
203
|
digest: `0x${string}`;
|
|
202
204
|
};
|
|
203
205
|
|
|
204
|
-
|
|
206
|
+
/** A fixed delegate key so fixtures are deterministic across runs. */
|
|
207
|
+
declare const RECEIPT_DELEGATE_KEY: `0x${string}`;
|
|
208
|
+
/** A distinct key, for signer_mismatch fixtures. */
|
|
209
|
+
declare const OTHER_RECEIPT_KEY: `0x${string}`;
|
|
210
|
+
interface SignedErc7710Options {
|
|
211
|
+
/** Defaults to `RECEIPT_DELEGATE_KEY`; pass `OTHER_RECEIPT_KEY` for a forged bundle. */
|
|
212
|
+
delegateKey?: string;
|
|
213
|
+
signHash?: string;
|
|
214
|
+
chainId?: number;
|
|
215
|
+
paymentId?: string;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* A signed erc7710 bundle whose `authorization.signature` recovers to the
|
|
219
|
+
* delegate over the delegation digest — `verifyPaymentReceipt` verifies it
|
|
220
|
+
* offline with the default recovery.
|
|
221
|
+
*/
|
|
222
|
+
declare function signedErc7710Receipt(options?: SignedErc7710Options): PaymentReceipt;
|
|
223
|
+
|
|
224
|
+
export { type BoundDirectUserOp, type BoundDirectUserOpOptions, type BoundRedeemDelegationsOptions, DEFAULT_DELEGATOR, type DelegationOverrides, type FundingLegUserOpOptions, OTHER_RECEIPT_KEY, RECEIPT_DELEGATE_KEY, type SignedErc7710Options, buildBoundDirectUserOp, buildBoundRedeemDelegationsCallData, buildChainPermissionContext, buildDelegation, buildEmptyPermissionContext, buildEmptyPermissionContextRedemption, buildExecuteCallData, buildFundingLegUserOp, buildPermissionContext, buildSelfCallCallData, buildSingleExecutionCallData, buildTransferExecutionCallData, rebuildDirectUserOpForSender, signedErc7710Receipt };
|