@agirails/sdk 4.4.8 → 4.5.2
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/builders/DeliveryProofBuilder.d.ts +224 -13
- package/dist/builders/DeliveryProofBuilder.d.ts.map +1 -1
- package/dist/builders/DeliveryProofBuilder.js +247 -13
- package/dist/builders/DeliveryProofBuilder.js.map +1 -1
- package/dist/cli/agirails.d.ts +85 -1
- package/dist/cli/agirails.d.ts.map +1 -1
- package/dist/cli/agirails.js +429 -154
- package/dist/cli/agirails.js.map +1 -1
- package/dist/cli/commands/init.d.ts +54 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +193 -1
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/receipt.d.ts +70 -2
- package/dist/cli/commands/receipt.d.ts.map +1 -1
- package/dist/cli/commands/receipt.js +218 -3
- package/dist/cli/commands/receipt.js.map +1 -1
- package/dist/cli/commands/test.d.ts +77 -1
- package/dist/cli/commands/test.d.ts.map +1 -1
- package/dist/cli/commands/test.js +264 -2
- package/dist/cli/commands/test.js.map +1 -1
- package/dist/cli/lib/runRequest.d.ts +90 -0
- package/dist/cli/lib/runRequest.d.ts.map +1 -1
- package/dist/cli/lib/runRequest.js +300 -9
- package/dist/cli/lib/runRequest.js.map +1 -1
- package/dist/cli/lib/sentinelReflections.d.ts +111 -0
- package/dist/cli/lib/sentinelReflections.d.ts.map +1 -0
- package/dist/cli/lib/sentinelReflections.js +193 -0
- package/dist/cli/lib/sentinelReflections.js.map +1 -0
- package/dist/delivery/MockDeliveryChannel.d.ts +208 -0
- package/dist/delivery/MockDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/MockDeliveryChannel.js +445 -0
- package/dist/delivery/MockDeliveryChannel.js.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts +176 -0
- package/dist/delivery/RelayDeliveryChannel.d.ts.map +1 -0
- package/dist/delivery/RelayDeliveryChannel.js +377 -0
- package/dist/delivery/RelayDeliveryChannel.js.map +1 -0
- package/dist/delivery/channel.d.ts +282 -0
- package/dist/delivery/channel.d.ts.map +1 -0
- package/dist/delivery/channel.js +76 -0
- package/dist/delivery/channel.js.map +1 -0
- package/dist/delivery/channelLog.d.ts +115 -0
- package/dist/delivery/channelLog.d.ts.map +1 -0
- package/dist/delivery/channelLog.js +94 -0
- package/dist/delivery/channelLog.js.map +1 -0
- package/dist/delivery/crypto.d.ts +312 -0
- package/dist/delivery/crypto.d.ts.map +1 -0
- package/dist/delivery/crypto.js +495 -0
- package/dist/delivery/crypto.js.map +1 -0
- package/dist/delivery/eip712.d.ts +248 -0
- package/dist/delivery/eip712.d.ts.map +1 -0
- package/dist/delivery/eip712.js +397 -0
- package/dist/delivery/eip712.js.map +1 -0
- package/dist/delivery/envelopeBuilder.d.ts +531 -0
- package/dist/delivery/envelopeBuilder.d.ts.map +1 -0
- package/dist/delivery/envelopeBuilder.js +832 -0
- package/dist/delivery/envelopeBuilder.js.map +1 -0
- package/dist/delivery/index.d.ts +53 -0
- package/dist/delivery/index.d.ts.map +1 -0
- package/dist/delivery/index.js +143 -0
- package/dist/delivery/index.js.map +1 -0
- package/dist/delivery/keys.d.ts +344 -0
- package/dist/delivery/keys.d.ts.map +1 -0
- package/dist/delivery/keys.js +513 -0
- package/dist/delivery/keys.js.map +1 -0
- package/dist/delivery/nonce-keys.d.ts +93 -0
- package/dist/delivery/nonce-keys.d.ts.map +1 -0
- package/dist/delivery/nonce-keys.js +88 -0
- package/dist/delivery/nonce-keys.js.map +1 -0
- package/dist/delivery/setupBuilder.d.ts +403 -0
- package/dist/delivery/setupBuilder.d.ts.map +1 -0
- package/dist/delivery/setupBuilder.js +554 -0
- package/dist/delivery/setupBuilder.js.map +1 -0
- package/dist/delivery/types.d.ts +722 -0
- package/dist/delivery/types.d.ts.map +1 -0
- package/dist/delivery/types.js +150 -0
- package/dist/delivery/types.js.map +1 -0
- package/dist/delivery/validate.d.ts +288 -0
- package/dist/delivery/validate.d.ts.map +1 -0
- package/dist/delivery/validate.js +648 -0
- package/dist/delivery/validate.js.map +1 -0
- package/dist/level1/Agent.d.ts +130 -0
- package/dist/level1/Agent.d.ts.map +1 -1
- package/dist/level1/Agent.js +248 -0
- package/dist/level1/Agent.js.map +1 -1
- package/dist/level1/types/Options.d.ts +62 -0
- package/dist/level1/types/Options.d.ts.map +1 -1
- package/dist/level1/types/Options.js +22 -0
- package/dist/level1/types/Options.js.map +1 -1
- package/dist/runtime/MockRuntime.d.ts +32 -0
- package/dist/runtime/MockRuntime.d.ts.map +1 -1
- package/dist/runtime/MockRuntime.js +44 -0
- package/dist/runtime/MockRuntime.js.map +1 -1
- package/dist/wallet/aa/BundlerClient.d.ts.map +1 -1
- package/dist/wallet/aa/BundlerClient.js +18 -3
- package/dist/wallet/aa/BundlerClient.js.map +1 -1
- package/dist/wallet/aa/PaymasterClient.d.ts.map +1 -1
- package/dist/wallet/aa/PaymasterClient.js +4 -1
- package/dist/wallet/aa/PaymasterClient.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AIP-16 Delivery Surface — Provider Envelope Builder + Verifier + Decryptor (Phase 2b)
|
|
3
|
+
* =======================================================================================
|
|
4
|
+
*
|
|
5
|
+
* Constructs and verifies the provider-signed `DeliveryEnvelopeV1` payload —
|
|
6
|
+
* the load-bearing artifact of the AIP-16 Rev 5 delivery surface. The
|
|
7
|
+
* provider posts this signed object to the delivery channel after the
|
|
8
|
+
* buyer's setup is received (and after the on-chain transaction reaches
|
|
9
|
+
* `COMMITTED`), carrying:
|
|
10
|
+
*
|
|
11
|
+
* - the EIP-712 binding to a specific kernel, chain, and `txId`,
|
|
12
|
+
* - the on-chain identity acting as the provider, plus the EOA that
|
|
13
|
+
* signed (smart-wallet two-step auth),
|
|
14
|
+
* - the cryptographic scheme used to protect the body (`public-v1` or
|
|
15
|
+
* `x25519-aes256gcm-v1`),
|
|
16
|
+
* - the provider's ephemeral X25519 pubkey (encrypted scheme) or
|
|
17
|
+
* canonical-empty bytes32 (public scheme),
|
|
18
|
+
* - the AES-256-GCM nonce + tag (encrypted) or canonical-empty
|
|
19
|
+
* bytes12 / bytes16 (public),
|
|
20
|
+
* - `payloadHash = keccak256(bodyBytes)` — the on-chain anchor for the
|
|
21
|
+
* exact bytes the buyer will receive,
|
|
22
|
+
* - the body bytes themselves (alongside the signed projection, in the
|
|
23
|
+
* wire envelope).
|
|
24
|
+
*
|
|
25
|
+
* ## Body encoding (SCHEME-AWARE — FIX-1, AIP-16 Phase 3.5)
|
|
26
|
+
*
|
|
27
|
+
* The wire encoding is scheme-dependent so the SDK and the Platform
|
|
28
|
+
* verifier (`Platform/agirails.app/web/lib/delivery/auth.ts`) hash the
|
|
29
|
+
* SAME bytes in BOTH locations:
|
|
30
|
+
*
|
|
31
|
+
* - `public-v1`: `wire.body = JSON.stringify(payload)` — plaintext
|
|
32
|
+
* UTF-8 JSON string, NOT hex. `payloadHash = keccak256(utf8Bytes(body))`.
|
|
33
|
+
* The Platform verifier computes `keccak256(toUtf8Bytes(body))`
|
|
34
|
+
* directly on the wire body. Hex-encoding the plaintext here would
|
|
35
|
+
* make the Platform recompute `keccak256(utf8Bytes("0x7b22…"))` —
|
|
36
|
+
* a different digest — and every public envelope would 400 with
|
|
37
|
+
* `payload_hash_mismatch`.
|
|
38
|
+
*
|
|
39
|
+
* - `x25519-aes256gcm-v1`: `wire.body = "0x" + hex(aesGcmCiphertext)`.
|
|
40
|
+
* `payloadHash = keccak256(rawCiphertextBytes)`. The Platform
|
|
41
|
+
* verifier hex-decodes `wire.body` and then keccak256s the bytes.
|
|
42
|
+
* Ciphertext is a byte string that does NOT round-trip through UTF-8
|
|
43
|
+
* (it contains arbitrary 0..255 bytes incl. 0x00 and high bits),
|
|
44
|
+
* so hex is the only safe text encoding — base64 would also work but
|
|
45
|
+
* AIP-16 standardizes on hex for cross-language SDK consistency.
|
|
46
|
+
*
|
|
47
|
+
* Rationale for the asymmetry:
|
|
48
|
+
* 1. **Public payloads are already text.** JSON serializes to valid
|
|
49
|
+
* UTF-8 — no encoding wrapper needed. The plaintext IS the wire.
|
|
50
|
+
* 2. **Ciphertext is binary.** Cannot travel naked in JSON; hex is the
|
|
51
|
+
* chosen text encoding (matches `nonce`, `tag`, `payloadHash`,
|
|
52
|
+
* `providerEphemeralPubkey`).
|
|
53
|
+
* 3. **Spec match.** AIP-16 §6.2 sign-side and the Platform verify-
|
|
54
|
+
* side both implement this exact rule.
|
|
55
|
+
*
|
|
56
|
+
* ## Builder shape (matches DeliverySetupBuilder)
|
|
57
|
+
*
|
|
58
|
+
* - `constructor(signer?)` — signer required for `build*()`, optional
|
|
59
|
+
* for `verify()` / `computeHash()` / `decryptPayload()`. The static
|
|
60
|
+
* helpers do not consult builder state.
|
|
61
|
+
* - `buildPublic(params)` / `buildEncrypted(params)` are `async`
|
|
62
|
+
* because EIP-712 signing on real wallets is async.
|
|
63
|
+
* - `verify`, `decryptPayload`, `verifyAndDecrypt`, `computeHash` are
|
|
64
|
+
* `static` — mirrors {@link DeliverySetupBuilder} and the existing
|
|
65
|
+
* delivery-proof / quote builders.
|
|
66
|
+
*
|
|
67
|
+
* ## Smart-wallet two-step auth (DEC-10 / V2 receipts)
|
|
68
|
+
*
|
|
69
|
+
* `providerAddress` (on-chain participant — possibly a Smart Wallet)
|
|
70
|
+
* and `signerAddress` (the EOA that actually signed) are accepted
|
|
71
|
+
* SEPARATELY. The SDK does NOT derive one from the other; the smart-
|
|
72
|
+
* wallet equality check
|
|
73
|
+
* computeSmartWalletFromSigner(signerAddress) === providerAddress
|
|
74
|
+
* is the SERVER'S responsibility (cross-vendor factory ABI agnostic).
|
|
75
|
+
*
|
|
76
|
+
* What the SDK enforces in `build*()` is the cheaper invariant:
|
|
77
|
+
* `signerAddress === await signer.getAddress()`.
|
|
78
|
+
*
|
|
79
|
+
* ## payloadHash defends against body-after-sign tamper
|
|
80
|
+
*
|
|
81
|
+
* Because `payloadHash = keccak256(bodyBytes)` is part of the SIGNED
|
|
82
|
+
* EIP-712 projection, any post-signature mutation of `wire.body`
|
|
83
|
+
* causes `bodyHash(wire.body)` to diverge from `signed.payloadHash`.
|
|
84
|
+
* The verifier short-circuits with `envelope_payload_hash_mismatch`
|
|
85
|
+
* before signature recovery, so a malicious relay cannot swap bodies
|
|
86
|
+
* even within an otherwise valid signed envelope.
|
|
87
|
+
*
|
|
88
|
+
* ## Verification order (first failure short-circuits)
|
|
89
|
+
*
|
|
90
|
+
* 1. `validateEnvelopeWire(wire)` — structural shape, types, lengths,
|
|
91
|
+
* and scheme/canonical-empty consistency in one pass.
|
|
92
|
+
* 2. `validateSchemeConsistency(signed)` — defense-in-depth re-check
|
|
93
|
+
* (already covered by step 1 but called explicitly so future
|
|
94
|
+
* refactors of the validator do not silently weaken the contract).
|
|
95
|
+
* 3. `signed.chainId === expectedChainId` → `envelope_chain_mismatch`.
|
|
96
|
+
* 4. `signed.kernelAddress` (lc) === `expectedKernelAddress` (lc)
|
|
97
|
+
* → `envelope_kernel_mismatch`.
|
|
98
|
+
* 5. `bodyHash(wire.body) === signed.payloadHash`
|
|
99
|
+
* → `envelope_payload_hash_mismatch`.
|
|
100
|
+
* 6. `recoverEnvelopeSigner(signed, providerSig, expectedKernel)`
|
|
101
|
+
* (lc) === `signed.signerAddress` (lc)
|
|
102
|
+
* → `envelope_signature_invalid`.
|
|
103
|
+
* 7. `|now - signed.createdAt| <= ENVELOPE_TIMESTAMP_SKEW_SEC`
|
|
104
|
+
* → `envelope_timestamp_skew`.
|
|
105
|
+
*
|
|
106
|
+
* Note that timestamp skew is checked LAST — a forged signature is a
|
|
107
|
+
* more severe error than a stale-but-genuine envelope and we want the
|
|
108
|
+
* caller to see the more severe failure first.
|
|
109
|
+
*
|
|
110
|
+
* @module delivery/envelopeBuilder
|
|
111
|
+
* @see ./types — signed/wire interfaces and {@link BuildEnvelopeResult}.
|
|
112
|
+
* @see ./eip712 — domain, types, and {@link recoverEnvelopeSigner}.
|
|
113
|
+
* @see ./validate — {@link validateEnvelopeWire},
|
|
114
|
+
* {@link validateSchemeConsistency}.
|
|
115
|
+
* @see ./keys — X25519 keygen + ECDH + HKDF.
|
|
116
|
+
* @see ./crypto — AES-256-GCM seal/open + {@link bodyHash}.
|
|
117
|
+
* @see ./setupBuilder — sibling builder; same shape conventions.
|
|
118
|
+
*/
|
|
119
|
+
import { type Signer } from 'ethers';
|
|
120
|
+
import { type EphemeralKeyPair } from './keys';
|
|
121
|
+
import { type BuildEnvelopeResult, type DeliveryEnvelopeSignedV1, type DeliveryEnvelopeWireV1 } from './types';
|
|
122
|
+
/**
|
|
123
|
+
* Maximum tolerated clock-skew, in seconds, between the signed
|
|
124
|
+
* `createdAt` and the verifier's wall clock. Symmetric (past + future).
|
|
125
|
+
*
|
|
126
|
+
* 900s (15 min) matches {@link DeliverySetupBuilder}'s
|
|
127
|
+
* `SETUP_TIMESTAMP_SKEW_SEC`, the receipts-V2 freshness window, and
|
|
128
|
+
* the AIP-3 anchor-receipt skew bound.
|
|
129
|
+
*/
|
|
130
|
+
export declare const ENVELOPE_TIMESTAMP_SKEW_SEC = 900;
|
|
131
|
+
/**
|
|
132
|
+
* Length (in bytes) of the AES-256-GCM AAD used by the encrypted
|
|
133
|
+
* scheme — `txId_bytes (32) || signerAddress_bytes (20) = 52`.
|
|
134
|
+
*
|
|
135
|
+
* H5 binding: GCM authenticates the AAD; a misrouted envelope (correct
|
|
136
|
+
* ciphertext + nonce + tag + sessionKey, but delivered as if for a
|
|
137
|
+
* different `txId` or `signerAddress`) fails the tag check on decrypt.
|
|
138
|
+
* The hash-input `payloadHash` in the EIP-712 signature already binds
|
|
139
|
+
* the body to a specific `txId` at the signature layer; this AAD adds
|
|
140
|
+
* the same binding INSIDE the GCM authentication, defense-in-depth.
|
|
141
|
+
*
|
|
142
|
+
* Bytes layout (network byte order, no padding):
|
|
143
|
+
* - [0..32): `txId` raw 32 bytes (from the 0x + 64 hex chars).
|
|
144
|
+
* - [32..52): `signerAddress` raw 20 bytes (from the 0x + 40 hex chars).
|
|
145
|
+
*/
|
|
146
|
+
export declare const ENVELOPE_AAD_LENGTH: 52;
|
|
147
|
+
/**
|
|
148
|
+
* Construct the AES-256-GCM AAD for the `x25519-aes256gcm-v1` scheme.
|
|
149
|
+
*
|
|
150
|
+
* Format: `txId (32 bytes) || signerAddress (20 bytes) = 52 bytes`.
|
|
151
|
+
*
|
|
152
|
+
* Both the build side (in {@link DeliveryEnvelopeBuilder.buildEncrypted})
|
|
153
|
+
* and the decrypt side (in {@link DeliveryEnvelopeBuilder.decryptPayload})
|
|
154
|
+
* call this helper with the SAME txId/signerAddress so the GCM tag
|
|
155
|
+
* commits to identical AAD bytes. Address case is normalized via
|
|
156
|
+
* `bytesFromHex` (which is case-insensitive on the hex characters), so
|
|
157
|
+
* checksum vs lowercase inputs round-trip to the same 20 raw bytes.
|
|
158
|
+
*
|
|
159
|
+
* @param txId - On-chain transaction id, `0x` + 64 hex chars.
|
|
160
|
+
* @param signerAddress - EOA address, `0x` + 40 hex chars.
|
|
161
|
+
* @returns 52-byte AAD buffer (`txId_bytes || signerAddress_bytes`).
|
|
162
|
+
* @throws {DeliveryCryptoError} `crypto_decrypt_failed` if either
|
|
163
|
+
* parameter has the wrong byte length (decoded via `bytesFromHex`
|
|
164
|
+
* from `./crypto`); the underlying helper raises this code.
|
|
165
|
+
*
|
|
166
|
+
* @internal Used by the envelope builder; exposed for cross-SDK
|
|
167
|
+
* fixtures and the H5 test suite.
|
|
168
|
+
*/
|
|
169
|
+
export declare function buildEnvelopeAad(txId: `0x${string}`, signerAddress: `0x${string}`): Uint8Array;
|
|
170
|
+
/**
|
|
171
|
+
* Replace the wall-clock implementation used inside this module.
|
|
172
|
+
*
|
|
173
|
+
* **TEST-ONLY.** Production code MUST NOT call this. Pass `null` (or
|
|
174
|
+
* call {@link resetSecondsNowForTests}) to restore the real-clock
|
|
175
|
+
* implementation.
|
|
176
|
+
*
|
|
177
|
+
* @param impl - Replacement function returning Unix seconds, or `null`
|
|
178
|
+
* to restore the default real-clock implementation.
|
|
179
|
+
*/
|
|
180
|
+
export declare function setSecondsNowForTests(impl: (() => number) | null): void;
|
|
181
|
+
/**
|
|
182
|
+
* Restore {@link secondsNow} to its default real-clock implementation.
|
|
183
|
+
*
|
|
184
|
+
* **TEST-ONLY.** Safe to call when no override is active.
|
|
185
|
+
*/
|
|
186
|
+
export declare function resetSecondsNowForTests(): void;
|
|
187
|
+
/**
|
|
188
|
+
* Parameters accepted by {@link DeliveryEnvelopeBuilder.buildPublic}.
|
|
189
|
+
*
|
|
190
|
+
* Every address is passed explicitly — no implicit derivation of one
|
|
191
|
+
* address from another. `providerAddress` and `signerAddress` are
|
|
192
|
+
* separate so the SDK is agnostic to which Smart Wallet factory the
|
|
193
|
+
* caller is using.
|
|
194
|
+
*/
|
|
195
|
+
export interface BuildPublicEnvelopeParams {
|
|
196
|
+
/**
|
|
197
|
+
* On-chain transaction id this envelope is bound to.
|
|
198
|
+
* 32-byte hex (`0x` + 64 hex chars). MUST equal the corresponding
|
|
199
|
+
* setup's `txId`.
|
|
200
|
+
*/
|
|
201
|
+
txId: `0x${string}`;
|
|
202
|
+
/**
|
|
203
|
+
* EVM chain id (e.g. `8453` for Base mainnet, `84532` for Base Sepolia).
|
|
204
|
+
* Encoded into BOTH the EIP-712 domain and the signed payload.
|
|
205
|
+
*/
|
|
206
|
+
chainId: number;
|
|
207
|
+
/**
|
|
208
|
+
* Address of the ACTP kernel contract on `chainId`. Becomes the
|
|
209
|
+
* EIP-712 `verifyingContract`.
|
|
210
|
+
*/
|
|
211
|
+
kernelAddress: `0x${string}`;
|
|
212
|
+
/**
|
|
213
|
+
* On-chain identity acting as the provider. Smart-wallet flows pass
|
|
214
|
+
* the Smart Wallet address here; non-smart-wallet flows pass the EOA.
|
|
215
|
+
* The SDK does NOT derive this from `signer`.
|
|
216
|
+
*/
|
|
217
|
+
providerAddress: `0x${string}`;
|
|
218
|
+
/**
|
|
219
|
+
* EOA address that will produce the signature. MUST equal
|
|
220
|
+
* `await signer.getAddress()` — `buildPublic()` enforces this and
|
|
221
|
+
* throws on mismatch.
|
|
222
|
+
*/
|
|
223
|
+
signerAddress: `0x${string}`;
|
|
224
|
+
/**
|
|
225
|
+
* The actual deliverable payload. Any JSON-serializable value.
|
|
226
|
+
* `buildPublic` will `JSON.stringify(payload)` and treat the UTF-8
|
|
227
|
+
* bytes of the resulting string as the body bytes.
|
|
228
|
+
*/
|
|
229
|
+
payload: unknown;
|
|
230
|
+
/**
|
|
231
|
+
* Override the `createdAt` timestamp. Defaults to {@link secondsNow}.
|
|
232
|
+
* Tests SHOULD pass an explicit value here for determinism rather
|
|
233
|
+
* than relying on {@link setSecondsNowForTests}.
|
|
234
|
+
*/
|
|
235
|
+
createdAt?: number;
|
|
236
|
+
/**
|
|
237
|
+
* CoinbaseSmartWallet factory nonce used to derive `providerAddress`
|
|
238
|
+
* from `signerAddress`. Defaults to `0` (the first wallet per owner).
|
|
239
|
+
*
|
|
240
|
+
* H4 fix (AIP-16 Phase 3 HIGH): providers whose Smart Wallet was
|
|
241
|
+
* deployed at a non-zero factory nonce MUST pass that nonce here so
|
|
242
|
+
* the server's smart-wallet derivation lands on the correct address.
|
|
243
|
+
*
|
|
244
|
+
* Must be a non-negative integer; `buildPublic()` rejects negatives
|
|
245
|
+
* with `BUILDER_INVALID_SMART_WALLET_NONCE`.
|
|
246
|
+
*/
|
|
247
|
+
smartWalletNonce?: number;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Parameters accepted by {@link DeliveryEnvelopeBuilder.buildEncrypted}.
|
|
251
|
+
*
|
|
252
|
+
* Extends {@link BuildPublicEnvelopeParams} with the buyer's ephemeral
|
|
253
|
+
* pubkey (from the corresponding setup) and an optional override for
|
|
254
|
+
* the provider's own ephemeral keypair (tests use this for determinism;
|
|
255
|
+
* production callers SHOULD omit it).
|
|
256
|
+
*/
|
|
257
|
+
export interface BuildEncryptedEnvelopeParams {
|
|
258
|
+
/** See {@link BuildPublicEnvelopeParams.txId}. */
|
|
259
|
+
txId: `0x${string}`;
|
|
260
|
+
/** See {@link BuildPublicEnvelopeParams.chainId}. */
|
|
261
|
+
chainId: number;
|
|
262
|
+
/** See {@link BuildPublicEnvelopeParams.kernelAddress}. */
|
|
263
|
+
kernelAddress: `0x${string}`;
|
|
264
|
+
/** See {@link BuildPublicEnvelopeParams.providerAddress}. */
|
|
265
|
+
providerAddress: `0x${string}`;
|
|
266
|
+
/** See {@link BuildPublicEnvelopeParams.signerAddress}. */
|
|
267
|
+
signerAddress: `0x${string}`;
|
|
268
|
+
/**
|
|
269
|
+
* The actual deliverable payload. Any JSON-serializable value.
|
|
270
|
+
* `buildEncrypted` will `JSON.stringify(payload)`, UTF-8 encode, then
|
|
271
|
+
* AES-256-GCM seal under the X25519+HKDF-derived session key.
|
|
272
|
+
*/
|
|
273
|
+
payload: unknown;
|
|
274
|
+
/**
|
|
275
|
+
* The buyer's ephemeral X25519 public key (32 bytes, hex), copied
|
|
276
|
+
* from the corresponding `DeliverySetupSignedV1.buyerEphemeralPubkey`.
|
|
277
|
+
* `buildEncrypted` runs ECDH with this and the provider's own
|
|
278
|
+
* ephemeral private key to derive the shared secret.
|
|
279
|
+
*
|
|
280
|
+
* MUST NOT be {@link CANONICAL_EMPTY_BYTES32} — the canonical-empty
|
|
281
|
+
* value is reserved for the public scheme.
|
|
282
|
+
*/
|
|
283
|
+
buyerEphemeralPubkey: `0x${string}`;
|
|
284
|
+
/**
|
|
285
|
+
* Override for the provider's ephemeral X25519 keypair. When omitted
|
|
286
|
+
* (the production path), a fresh keypair is generated via
|
|
287
|
+
* {@link generateEphemeralKeyPair}.
|
|
288
|
+
*
|
|
289
|
+
* **TEST-ONLY in practice.** Production callers SHOULD let the
|
|
290
|
+
* builder generate the keypair so the private key never crosses a
|
|
291
|
+
* call boundary; passing one in increases the risk of accidental
|
|
292
|
+
* persistence.
|
|
293
|
+
*/
|
|
294
|
+
providerEphemeralKeyPair?: EphemeralKeyPair;
|
|
295
|
+
/**
|
|
296
|
+
* Override the `createdAt` timestamp. Defaults to {@link secondsNow}.
|
|
297
|
+
*/
|
|
298
|
+
createdAt?: number;
|
|
299
|
+
/**
|
|
300
|
+
* CoinbaseSmartWallet factory nonce used to derive `providerAddress`
|
|
301
|
+
* from `signerAddress`. Defaults to `0` (the first wallet per owner).
|
|
302
|
+
*
|
|
303
|
+
* H4 fix (AIP-16 Phase 3 HIGH): symmetric to
|
|
304
|
+
* {@link BuildPublicEnvelopeParams.smartWalletNonce}. Allows providers
|
|
305
|
+
* with non-zero-nonce Smart Wallets to authenticate.
|
|
306
|
+
*/
|
|
307
|
+
smartWalletNonce?: number;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Builder + verifier + decryptor for AIP-16 delivery envelopes.
|
|
311
|
+
*
|
|
312
|
+
* Instances are cheap to construct and have no I/O side effects.
|
|
313
|
+
* `verify()`, `decryptPayload()`, `verifyAndDecrypt()`, and
|
|
314
|
+
* `computeHash()` are static — call them without constructing an
|
|
315
|
+
* instance.
|
|
316
|
+
*
|
|
317
|
+
* @example Provider build (public)
|
|
318
|
+
* ```typescript
|
|
319
|
+
* const builder = new DeliveryEnvelopeBuilder(wallet);
|
|
320
|
+
* const { wire } = await builder.buildPublic({
|
|
321
|
+
* txId, chainId: 84532, kernelAddress: KERNEL,
|
|
322
|
+
* providerAddress: SMART_WALLET, signerAddress: EOA,
|
|
323
|
+
* payload: { result: 'ok' },
|
|
324
|
+
* });
|
|
325
|
+
* await postToRelay(wire);
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* @example Provider build (encrypted)
|
|
329
|
+
* ```typescript
|
|
330
|
+
* const { wire, blobKey } = await builder.buildEncrypted({
|
|
331
|
+
* txId, chainId: 84532, kernelAddress: KERNEL,
|
|
332
|
+
* providerAddress: SMART_WALLET, signerAddress: EOA,
|
|
333
|
+
* payload: { secret: 'data' },
|
|
334
|
+
* buyerEphemeralPubkey: setupSigned.buyerEphemeralPubkey,
|
|
335
|
+
* });
|
|
336
|
+
* ```
|
|
337
|
+
*
|
|
338
|
+
* @example Buyer decrypt
|
|
339
|
+
* ```typescript
|
|
340
|
+
* const result = await DeliveryEnvelopeBuilder.verifyAndDecrypt(
|
|
341
|
+
* wire,
|
|
342
|
+
* buyerEphemeralPrivKey,
|
|
343
|
+
* { expectedKernelAddress: KERNEL, expectedChainId: 84532 },
|
|
344
|
+
* );
|
|
345
|
+
* if (!result.ok) throw new Error(result.code);
|
|
346
|
+
* const payload = result.payload;
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export declare class DeliveryEnvelopeBuilder {
|
|
350
|
+
private readonly signer?;
|
|
351
|
+
/**
|
|
352
|
+
* Construct a new builder.
|
|
353
|
+
*
|
|
354
|
+
* @param signer - EOA signer required for {@link buildPublic} and
|
|
355
|
+
* {@link buildEncrypted}. Pass `undefined` for a verify-/decrypt-only
|
|
356
|
+
* instance; all verification / decryption helpers are static and
|
|
357
|
+
* do not consult builder state.
|
|
358
|
+
*/
|
|
359
|
+
constructor(signer?: Signer);
|
|
360
|
+
/**
|
|
361
|
+
* Construct, sign, and return a {@link DeliveryEnvelopeWireV1} using
|
|
362
|
+
* the `public-v1` scheme.
|
|
363
|
+
*
|
|
364
|
+
* Encoding (FIX-1, AIP-16 Phase 3.5):
|
|
365
|
+
* - `bodyString = JSON.stringify(params.payload)`.
|
|
366
|
+
* - `wire.body = bodyString` (plaintext UTF-8 JSON, NOT hex).
|
|
367
|
+
* - `payloadHash = keccak256(utf8Bytes(bodyString))`.
|
|
368
|
+
* - The Platform verifier recomputes `keccak256(toUtf8Bytes(body))`
|
|
369
|
+
* on the wire body directly, so the SDK and verifier hash the
|
|
370
|
+
* same bytes byte-for-byte.
|
|
371
|
+
*
|
|
372
|
+
* Canonical-empty enforcement:
|
|
373
|
+
* - `providerEphemeralPubkey = CANONICAL_EMPTY_BYTES32`.
|
|
374
|
+
* - `nonce = CANONICAL_EMPTY_BYTES12`.
|
|
375
|
+
* - `tag = CANONICAL_EMPTY_BYTES16`.
|
|
376
|
+
*
|
|
377
|
+
* Pre-checks:
|
|
378
|
+
* - signer MUST be present.
|
|
379
|
+
* - `signerAddress` MUST equal `await signer.getAddress()`.
|
|
380
|
+
*
|
|
381
|
+
* @param params - {@link BuildPublicEnvelopeParams}.
|
|
382
|
+
* @returns A {@link BuildEnvelopeResult} carrying the signed wire
|
|
383
|
+
* envelope and the raw plaintext bytes (`bodyBytes`) that the
|
|
384
|
+
* `payloadHash` was computed over. `blobKey` is `undefined` for
|
|
385
|
+
* the public scheme.
|
|
386
|
+
* @throws {DeliveryEip712Error} on signer absence or signer/address
|
|
387
|
+
* mismatch.
|
|
388
|
+
*/
|
|
389
|
+
buildPublic(params: BuildPublicEnvelopeParams): Promise<BuildEnvelopeResult>;
|
|
390
|
+
/**
|
|
391
|
+
* Construct, sign, and return a {@link DeliveryEnvelopeWireV1} using
|
|
392
|
+
* the `x25519-aes256gcm-v1` scheme.
|
|
393
|
+
*
|
|
394
|
+
* Crypto flow:
|
|
395
|
+
* 1. Generate (or accept) a provider ephemeral X25519 keypair.
|
|
396
|
+
* 2. `shared = X25519(providerPriv, buyerPub)`.
|
|
397
|
+
* 3. `sessionKey = HKDF-SHA256(ikm=shared, salt=txId, info="agirails-delivery-v1", L=32)`.
|
|
398
|
+
* 4. `plaintextBytes = utf8Bytes(JSON.stringify(payload))`.
|
|
399
|
+
* 5. `{ciphertext, nonce, tag} = AES-256-GCM(plaintextBytes, sessionKey)`.
|
|
400
|
+
* 6. `wire.body = bytesToHex(ciphertext)`.
|
|
401
|
+
* 7. `payloadHash = keccak256(ciphertext)`.
|
|
402
|
+
* 8. Sign the EIP-712 projection containing `scheme = "x25519-aes256gcm-v1"`,
|
|
403
|
+
* the provider's ephemeral pubkey, the AES-GCM nonce + tag, and
|
|
404
|
+
* `payloadHash`.
|
|
405
|
+
*
|
|
406
|
+
* The provider's ephemeral PRIVATE key is dropped after step 5;
|
|
407
|
+
* forward secrecy w.r.t. provider long-term keys is provided by the
|
|
408
|
+
* fresh keypair per delivery.
|
|
409
|
+
*
|
|
410
|
+
* Pre-checks:
|
|
411
|
+
* - signer MUST be present.
|
|
412
|
+
* - `signerAddress` MUST equal `await signer.getAddress()`.
|
|
413
|
+
* - `buyerEphemeralPubkey` MUST NOT be {@link CANONICAL_EMPTY_BYTES32}.
|
|
414
|
+
*
|
|
415
|
+
* @param params - {@link BuildEncryptedEnvelopeParams}.
|
|
416
|
+
* @returns A {@link BuildEnvelopeResult} carrying the signed wire
|
|
417
|
+
* envelope, the ciphertext bytes (`bodyBytes`) the `payloadHash`
|
|
418
|
+
* was computed over, and the symmetric session `blobKey` (for
|
|
419
|
+
* provider-side observability / future reference-mode flows; the
|
|
420
|
+
* buyer derives the key independently).
|
|
421
|
+
* @throws {DeliveryEip712Error} on signer absence, signer/address
|
|
422
|
+
* mismatch, or canonical-empty buyer pubkey.
|
|
423
|
+
*/
|
|
424
|
+
buildEncrypted(params: BuildEncryptedEnvelopeParams): Promise<BuildEnvelopeResult>;
|
|
425
|
+
/**
|
|
426
|
+
* Verify a {@link DeliveryEnvelopeWireV1} received from the relay.
|
|
427
|
+
*
|
|
428
|
+
* See the module-level header for the full check ordering and rationale.
|
|
429
|
+
*
|
|
430
|
+
* @param wire - The wire envelope received from the relay.
|
|
431
|
+
* @param opts.expectedKernelAddress - Trusted kernel address for the
|
|
432
|
+
* target chain (from the verifier's allowlist).
|
|
433
|
+
* @param opts.expectedChainId - Trusted chainId for the target chain.
|
|
434
|
+
* @param opts.now - Override for the verifier's wall clock (Unix
|
|
435
|
+
* seconds). Tests use this for deterministic timestamp-skew paths;
|
|
436
|
+
* production callers SHOULD omit.
|
|
437
|
+
* @returns `{ ok: true, signed }` on success, `{ ok: false, code, error }`
|
|
438
|
+
* on failure.
|
|
439
|
+
*/
|
|
440
|
+
static verify(wire: DeliveryEnvelopeWireV1, opts: {
|
|
441
|
+
expectedKernelAddress: string;
|
|
442
|
+
expectedChainId: number;
|
|
443
|
+
now?: number;
|
|
444
|
+
}): {
|
|
445
|
+
ok: true;
|
|
446
|
+
signed: DeliveryEnvelopeSignedV1;
|
|
447
|
+
} | {
|
|
448
|
+
ok: false;
|
|
449
|
+
code: string;
|
|
450
|
+
error: string;
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Decrypt the payload of an `x25519-aes256gcm-v1` envelope using the
|
|
454
|
+
* buyer's ephemeral private key.
|
|
455
|
+
*
|
|
456
|
+
* Does NOT verify the EIP-712 signature, the chainId / kernel binding,
|
|
457
|
+
* or the payloadHash. Callers that have not already run {@link verify}
|
|
458
|
+
* SHOULD use {@link verifyAndDecrypt} instead.
|
|
459
|
+
*
|
|
460
|
+
* Throws on:
|
|
461
|
+
* - non-encrypted scheme (`public-v1` envelopes are not decrypted),
|
|
462
|
+
* - malformed buyerEphemeralPrivKey length,
|
|
463
|
+
* - ECDH failure (low-order peer pubkey, etc.),
|
|
464
|
+
* - HKDF failure,
|
|
465
|
+
* - AES-GCM authentication failure (tag mismatch).
|
|
466
|
+
*
|
|
467
|
+
* @param wire - The envelope to decrypt.
|
|
468
|
+
* @param buyerEphemeralPrivKey - The buyer's 32-byte X25519 private
|
|
469
|
+
* key (the one whose pubkey was embedded in the setup).
|
|
470
|
+
* @returns The JSON-parsed payload (`unknown`).
|
|
471
|
+
* @throws {DeliveryCryptoError} via the underlying crypto helpers.
|
|
472
|
+
* @throws {DeliveryEip712Error} `BUILDER_PUBLIC_DECRYPT_NOT_APPLICABLE`
|
|
473
|
+
* when called on a `public-v1` envelope.
|
|
474
|
+
*/
|
|
475
|
+
static decryptPayload(wire: DeliveryEnvelopeWireV1, buyerEphemeralPrivKey: Uint8Array): Promise<unknown>;
|
|
476
|
+
/**
|
|
477
|
+
* Combined {@link verify} + payload extraction.
|
|
478
|
+
*
|
|
479
|
+
* For `public-v1`: after a successful `verify`, the wire body (hex)
|
|
480
|
+
* is decoded to bytes, UTF-8 → string, JSON-parsed, and returned.
|
|
481
|
+
*
|
|
482
|
+
* For `x25519-aes256gcm-v1`: after a successful `verify`,
|
|
483
|
+
* {@link decryptPayload} is invoked with `buyerEphemeralPrivKey`.
|
|
484
|
+
*
|
|
485
|
+
* Verification failures are returned as `{ ok: false, code, error }`
|
|
486
|
+
* — the structured shape matches `verify`. Decryption failures are
|
|
487
|
+
* also returned as `{ ok: false, code: "envelope_decrypt_failed", ...}`
|
|
488
|
+
* (catching the underlying `DeliveryCryptoError`).
|
|
489
|
+
*
|
|
490
|
+
* @param wire - The envelope to verify + decrypt.
|
|
491
|
+
* @param buyerEphemeralPrivKey - 32-byte X25519 private key. Ignored
|
|
492
|
+
* for `public-v1` envelopes (pass `new Uint8Array(32)` if you do
|
|
493
|
+
* not have one — the value is never read in that branch).
|
|
494
|
+
* @param opts - Same as {@link verify}.
|
|
495
|
+
* @returns `{ ok: true, payload }` on success, `{ ok: false, code, error }`
|
|
496
|
+
* on any failure.
|
|
497
|
+
*/
|
|
498
|
+
static verifyAndDecrypt(wire: DeliveryEnvelopeWireV1, buyerEphemeralPrivKey: Uint8Array, opts: {
|
|
499
|
+
expectedKernelAddress: string;
|
|
500
|
+
expectedChainId: number;
|
|
501
|
+
now?: number;
|
|
502
|
+
}): Promise<{
|
|
503
|
+
ok: true;
|
|
504
|
+
payload: unknown;
|
|
505
|
+
} | {
|
|
506
|
+
ok: false;
|
|
507
|
+
code: string;
|
|
508
|
+
error: string;
|
|
509
|
+
}>;
|
|
510
|
+
/**
|
|
511
|
+
* Compute a stable, cross-SDK identifier for an envelope wire object.
|
|
512
|
+
*
|
|
513
|
+
* The hash is `keccak256(utf8Bytes(canonicalJsonStringify(wire.signed)))`:
|
|
514
|
+
*
|
|
515
|
+
* - canonical JSON (sorted keys, no whitespace) guarantees byte-for-
|
|
516
|
+
* byte identical input across SDK languages,
|
|
517
|
+
* - `keccak256` matches the on-chain hashing convention,
|
|
518
|
+
* - hashing the SIGNED projection (not the full wire) excludes the
|
|
519
|
+
* signature, body, and any `serverMeta` so the hash is stable
|
|
520
|
+
* across relay-side decoration and signature malleability.
|
|
521
|
+
*
|
|
522
|
+
* This is NOT the EIP-712 signing hash; it is a content-addressing
|
|
523
|
+
* helper for logs, dedup sets, and cross-SDK fixtures.
|
|
524
|
+
*
|
|
525
|
+
* @param wire - The wire envelope to hash.
|
|
526
|
+
* @returns 32-byte hex-encoded keccak256 hash (`0x` + 64 hex chars).
|
|
527
|
+
*/
|
|
528
|
+
static computeHash(wire: DeliveryEnvelopeWireV1): string;
|
|
529
|
+
}
|
|
530
|
+
export type { BuildEnvelopeResult } from './types';
|
|
531
|
+
//# sourceMappingURL=envelopeBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelopeBuilder.d.ts","sourceRoot":"","sources":["../../src/delivery/envelopeBuilder.ts"],"names":[],"mappings":"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"}
|