@shroud-fi/payments 0.1.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/LICENSE +21 -0
- package/README.md +61 -0
- package/dist/cjs/amount-privacy.d.ts +30 -0
- package/dist/cjs/amount-privacy.d.ts.map +1 -0
- package/dist/cjs/amount-privacy.js +30 -0
- package/dist/cjs/amount-privacy.js.map +1 -0
- package/dist/cjs/constants.d.ts +7 -0
- package/dist/cjs/constants.d.ts.map +1 -0
- package/dist/cjs/constants.js +10 -0
- package/dist/cjs/constants.js.map +1 -0
- package/dist/cjs/errors.d.ts +57 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +91 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.d.ts +10 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +42 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/payments.d.ts +49 -0
- package/dist/cjs/payments.d.ts.map +1 -0
- package/dist/cjs/payments.js +266 -0
- package/dist/cjs/payments.js.map +1 -0
- package/dist/cjs/send-to-wallet.d.ts +57 -0
- package/dist/cjs/send-to-wallet.d.ts.map +1 -0
- package/dist/cjs/send-to-wallet.js +104 -0
- package/dist/cjs/send-to-wallet.js.map +1 -0
- package/dist/cjs/sweep.d.ts +47 -0
- package/dist/cjs/sweep.d.ts.map +1 -0
- package/dist/cjs/sweep.js +241 -0
- package/dist/cjs/sweep.js.map +1 -0
- package/dist/cjs/types.d.ts +27 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/amount-privacy.d.ts +30 -0
- package/dist/esm/amount-privacy.d.ts.map +1 -0
- package/dist/esm/amount-privacy.js +25 -0
- package/dist/esm/amount-privacy.js.map +1 -0
- package/dist/esm/constants.d.ts +7 -0
- package/dist/esm/constants.d.ts.map +1 -0
- package/dist/esm/constants.js +7 -0
- package/dist/esm/constants.js.map +1 -0
- package/dist/esm/errors.d.ts +57 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +78 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/payments.d.ts +49 -0
- package/dist/esm/payments.d.ts.map +1 -0
- package/dist/esm/payments.js +261 -0
- package/dist/esm/payments.js.map +1 -0
- package/dist/esm/send-to-wallet.d.ts +57 -0
- package/dist/esm/send-to-wallet.d.ts.map +1 -0
- package/dist/esm/send-to-wallet.js +100 -0
- package/dist/esm/send-to-wallet.js.map +1 -0
- package/dist/esm/sweep.d.ts +47 -0
- package/dist/esm/sweep.d.ts.map +1 -0
- package/dist/esm/sweep.js +237 -0
- package/dist/esm/sweep.js.map +1 -0
- package/dist/esm/types.d.ts +27 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ShroudFi Payments - Stealth Payment Construction
|
|
3
|
+
*
|
|
4
|
+
* Builds and submits stealth payments through the ShroudFiStealth contract.
|
|
5
|
+
* Uses generateStealthAddress from @shroud-fi/core for derivation.
|
|
6
|
+
*
|
|
7
|
+
* Privacy invariants enforced:
|
|
8
|
+
* - No private key material in any error message
|
|
9
|
+
* - No plaintext amounts in any error message
|
|
10
|
+
* - No console.log/warn/error anywhere
|
|
11
|
+
* - Non-custodial: only constructs transactions, never holds funds
|
|
12
|
+
*/
|
|
13
|
+
import { decodeEventLog } from 'viem';
|
|
14
|
+
import { generateStealthAddress } from '@shroud-fi/core';
|
|
15
|
+
import { ShroudFiStealthAbi } from '@shroud-fi/transport';
|
|
16
|
+
import { MissingWalletClientError, ZeroAmountError, InvalidRecipientError, PaymentError, } from './errors.js';
|
|
17
|
+
import { DEFAULT_GAS_MULTIPLIER } from './constants.js';
|
|
18
|
+
/**
|
|
19
|
+
* Encode the view tag (0-255) as a single byte (bytes1) for the contract call.
|
|
20
|
+
* Returns a `0x${string}` of exactly 4 chars (e.g. "0x07", "0xff").
|
|
21
|
+
*/
|
|
22
|
+
function viewTagToBytes1(viewTag) {
|
|
23
|
+
return `0x${viewTag.toString(16).padStart(2, '0')}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert a Uint8Array ephemeral pubkey to a 0x-prefixed hex string.
|
|
27
|
+
*/
|
|
28
|
+
function ephemeralPubKeyToHex(bytes) {
|
|
29
|
+
let hex = '0x';
|
|
30
|
+
for (const b of bytes) {
|
|
31
|
+
hex += b.toString(16).padStart(2, '0');
|
|
32
|
+
}
|
|
33
|
+
return hex;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Prepare stealth payment material from a recipient meta-address.
|
|
37
|
+
* Pure helper - does not submit any transaction.
|
|
38
|
+
*
|
|
39
|
+
* @throws InvalidRecipientError if the meta-address is malformed or invalid.
|
|
40
|
+
*/
|
|
41
|
+
export function prepareStealthPayment(metaAddress) {
|
|
42
|
+
let result;
|
|
43
|
+
try {
|
|
44
|
+
result = generateStealthAddress(metaAddress);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Wrap all core errors as InvalidRecipientError - never leak key bytes.
|
|
48
|
+
throw new InvalidRecipientError();
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
stealthAddress: result.stealthAddress,
|
|
52
|
+
ephemeralPubKey: ephemeralPubKeyToHex(result.ephemeralPubKey),
|
|
53
|
+
viewTag: result.viewTag,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Decode the StealthPayment event from a transaction receipt.
|
|
58
|
+
* Returns a PaymentReceipt with the on-chain stealth address + token + block.
|
|
59
|
+
*
|
|
60
|
+
* @throws PaymentError if the StealthPayment log cannot be found / decoded.
|
|
61
|
+
*/
|
|
62
|
+
async function parsePaymentReceipt(txHash, publicClient, ephemeralPubKey, viewTag, expectedToken) {
|
|
63
|
+
const receipt = await publicClient.getTransactionReceipt({ hash: txHash });
|
|
64
|
+
for (const log of receipt.logs) {
|
|
65
|
+
try {
|
|
66
|
+
const decoded = decodeEventLog({
|
|
67
|
+
abi: ShroudFiStealthAbi,
|
|
68
|
+
data: log.data,
|
|
69
|
+
topics: log.topics,
|
|
70
|
+
eventName: 'StealthPayment',
|
|
71
|
+
});
|
|
72
|
+
if (decoded.eventName === 'StealthPayment') {
|
|
73
|
+
const args = decoded.args;
|
|
74
|
+
// expectedToken is informational - we trust the event token.
|
|
75
|
+
void expectedToken;
|
|
76
|
+
void args.amount; // Never expose amount via this return - already in receipt.
|
|
77
|
+
return {
|
|
78
|
+
txHash,
|
|
79
|
+
stealthAddress: args.stealthAddress,
|
|
80
|
+
ephemeralPubKey,
|
|
81
|
+
viewTag,
|
|
82
|
+
blockNumber: receipt.blockNumber,
|
|
83
|
+
token: args.token,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Not a StealthPayment log - try next.
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
throw new PaymentError('StealthPayment event not found in receipt');
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Send native ETH to a stealth address derived from `metaAddress`.
|
|
96
|
+
*
|
|
97
|
+
* Privacy notes:
|
|
98
|
+
* - The contract emits a StealthPayment event with the stealth address.
|
|
99
|
+
* - The amount is on-chain by necessity (no native ETH amount privacy).
|
|
100
|
+
* - Caller pays gas - relayer abstraction is a separate concern.
|
|
101
|
+
*
|
|
102
|
+
* @throws MissingWalletClientError if transport has no walletClient configured.
|
|
103
|
+
* @throws ZeroAmountError if valueWei is 0n.
|
|
104
|
+
* @throws InvalidRecipientError if the meta-address is invalid.
|
|
105
|
+
*/
|
|
106
|
+
export async function sendETHPayment(transport, contractAddress, metaAddress, valueWei, options) {
|
|
107
|
+
if (valueWei === 0n) {
|
|
108
|
+
throw new ZeroAmountError();
|
|
109
|
+
}
|
|
110
|
+
const wallet = transport.walletClient;
|
|
111
|
+
if (!wallet) {
|
|
112
|
+
throw new MissingWalletClientError();
|
|
113
|
+
}
|
|
114
|
+
const account = wallet.account;
|
|
115
|
+
if (!account) {
|
|
116
|
+
throw new MissingWalletClientError();
|
|
117
|
+
}
|
|
118
|
+
const prepared = prepareStealthPayment(metaAddress);
|
|
119
|
+
const viewTagByte = viewTagToBytes1(prepared.viewTag);
|
|
120
|
+
const gasMultiplier = options?.gasMultiplier ?? DEFAULT_GAS_MULTIPLIER;
|
|
121
|
+
let gas;
|
|
122
|
+
try {
|
|
123
|
+
const estimated = await transport.publicClient.estimateContractGas({
|
|
124
|
+
address: contractAddress,
|
|
125
|
+
abi: ShroudFiStealthAbi,
|
|
126
|
+
functionName: 'sendETH',
|
|
127
|
+
args: [prepared.stealthAddress, prepared.ephemeralPubKey, viewTagByte],
|
|
128
|
+
value: valueWei,
|
|
129
|
+
account: account.address,
|
|
130
|
+
});
|
|
131
|
+
// Ceil-division — match sweep.ts so multiplier never under-shoots gas
|
|
132
|
+
gas = (estimated * gasMultiplier + 99n) / 100n;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Gas estimation can fail in tests / on mocks - fall through without gas
|
|
136
|
+
// override; walletClient will estimate on send.
|
|
137
|
+
gas = undefined;
|
|
138
|
+
}
|
|
139
|
+
const writeArgs = {
|
|
140
|
+
address: contractAddress,
|
|
141
|
+
abi: ShroudFiStealthAbi,
|
|
142
|
+
functionName: 'sendETH',
|
|
143
|
+
args: [prepared.stealthAddress, prepared.ephemeralPubKey, viewTagByte],
|
|
144
|
+
value: valueWei,
|
|
145
|
+
account,
|
|
146
|
+
chain: transport.chain,
|
|
147
|
+
};
|
|
148
|
+
if (gas !== undefined)
|
|
149
|
+
writeArgs['gas'] = gas;
|
|
150
|
+
if (options?.maxFeePerGas !== undefined)
|
|
151
|
+
writeArgs['maxFeePerGas'] = options.maxFeePerGas;
|
|
152
|
+
if (options?.maxPriorityFeePerGas !== undefined)
|
|
153
|
+
writeArgs['maxPriorityFeePerGas'] = options.maxPriorityFeePerGas;
|
|
154
|
+
if (options?.nonce !== undefined)
|
|
155
|
+
writeArgs['nonce'] = options.nonce;
|
|
156
|
+
let txHash;
|
|
157
|
+
try {
|
|
158
|
+
// viem's writeContract has a complex union signature - cast at the boundary.
|
|
159
|
+
txHash = (await wallet.writeContract(writeArgs));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
// Re-wrap without leaking amount or key material.
|
|
163
|
+
if (err instanceof PaymentError)
|
|
164
|
+
throw err;
|
|
165
|
+
throw new PaymentError('Failed to submit stealth ETH payment');
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
await transport.publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
throw new PaymentError('Failed to confirm stealth ETH payment');
|
|
172
|
+
}
|
|
173
|
+
return parsePaymentReceipt(txHash, transport.publicClient, prepared.ephemeralPubKey, prepared.viewTag, '0x0000000000000000000000000000000000000000');
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Send an ERC-20 token to a stealth address derived from `metaAddress`.
|
|
177
|
+
*
|
|
178
|
+
* **Pre-approval required:** the caller MUST have already approved
|
|
179
|
+
* `contractAddress` to spend at least `amount` of `token` from the sender's
|
|
180
|
+
* account. v1 does not include an approve flow.
|
|
181
|
+
*
|
|
182
|
+
* @throws MissingWalletClientError if transport has no walletClient configured.
|
|
183
|
+
* @throws ZeroAmountError if amount is 0n.
|
|
184
|
+
* @throws InvalidRecipientError if the meta-address is invalid.
|
|
185
|
+
*/
|
|
186
|
+
export async function sendERC20Payment(transport, contractAddress, metaAddress, token, amount, options) {
|
|
187
|
+
if (amount === 0n) {
|
|
188
|
+
throw new ZeroAmountError();
|
|
189
|
+
}
|
|
190
|
+
const wallet = transport.walletClient;
|
|
191
|
+
if (!wallet) {
|
|
192
|
+
throw new MissingWalletClientError();
|
|
193
|
+
}
|
|
194
|
+
const account = wallet.account;
|
|
195
|
+
if (!account) {
|
|
196
|
+
throw new MissingWalletClientError();
|
|
197
|
+
}
|
|
198
|
+
const prepared = prepareStealthPayment(metaAddress);
|
|
199
|
+
const viewTagByte = viewTagToBytes1(prepared.viewTag);
|
|
200
|
+
const gasMultiplier = options?.gasMultiplier ?? DEFAULT_GAS_MULTIPLIER;
|
|
201
|
+
let gas;
|
|
202
|
+
try {
|
|
203
|
+
const estimated = await transport.publicClient.estimateContractGas({
|
|
204
|
+
address: contractAddress,
|
|
205
|
+
abi: ShroudFiStealthAbi,
|
|
206
|
+
functionName: 'sendERC20',
|
|
207
|
+
args: [
|
|
208
|
+
prepared.stealthAddress,
|
|
209
|
+
token,
|
|
210
|
+
amount,
|
|
211
|
+
prepared.ephemeralPubKey,
|
|
212
|
+
viewTagByte,
|
|
213
|
+
],
|
|
214
|
+
account: account.address,
|
|
215
|
+
});
|
|
216
|
+
// Ceil-division — match sweep.ts so multiplier never under-shoots gas
|
|
217
|
+
gas = (estimated * gasMultiplier + 99n) / 100n;
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
gas = undefined;
|
|
221
|
+
}
|
|
222
|
+
const writeArgs = {
|
|
223
|
+
address: contractAddress,
|
|
224
|
+
abi: ShroudFiStealthAbi,
|
|
225
|
+
functionName: 'sendERC20',
|
|
226
|
+
args: [
|
|
227
|
+
prepared.stealthAddress,
|
|
228
|
+
token,
|
|
229
|
+
amount,
|
|
230
|
+
prepared.ephemeralPubKey,
|
|
231
|
+
viewTagByte,
|
|
232
|
+
],
|
|
233
|
+
account,
|
|
234
|
+
chain: transport.chain,
|
|
235
|
+
};
|
|
236
|
+
if (gas !== undefined)
|
|
237
|
+
writeArgs['gas'] = gas;
|
|
238
|
+
if (options?.maxFeePerGas !== undefined)
|
|
239
|
+
writeArgs['maxFeePerGas'] = options.maxFeePerGas;
|
|
240
|
+
if (options?.maxPriorityFeePerGas !== undefined)
|
|
241
|
+
writeArgs['maxPriorityFeePerGas'] = options.maxPriorityFeePerGas;
|
|
242
|
+
if (options?.nonce !== undefined)
|
|
243
|
+
writeArgs['nonce'] = options.nonce;
|
|
244
|
+
let txHash;
|
|
245
|
+
try {
|
|
246
|
+
txHash = (await wallet.writeContract(writeArgs));
|
|
247
|
+
}
|
|
248
|
+
catch (err) {
|
|
249
|
+
if (err instanceof PaymentError)
|
|
250
|
+
throw err;
|
|
251
|
+
throw new PaymentError('Failed to submit stealth ERC-20 payment');
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
await transport.publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
throw new PaymentError('Failed to confirm stealth ERC-20 payment');
|
|
258
|
+
}
|
|
259
|
+
return parsePaymentReceipt(txHash, transport.publicClient, prepared.ephemeralPubKey, prepared.viewTag, token);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=payments.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payments.js","sourceRoot":"","sources":["../../src/payments.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sendToWallet — ergonomic agent-facing helper.
|
|
3
|
+
*
|
|
4
|
+
* Pay an EVM wallet by its plain address. The helper:
|
|
5
|
+
* 1. Queries the canonical ERC-6538 Registry for the recipient's stealth
|
|
6
|
+
* meta-address (scheme 1, secp256k1 + view tag).
|
|
7
|
+
* 2. Throws `RecipientNotOnboardedError` if the recipient has not registered.
|
|
8
|
+
* 3. Decodes the 66-byte payload into a `StealthMetaAddress`.
|
|
9
|
+
* 4. Resolves the chain's `ShroudFiStealth` contract.
|
|
10
|
+
* 5. Dispatches to `sendETHPayment` or `sendERC20Payment`.
|
|
11
|
+
*
|
|
12
|
+
* Senders never have to know about meta-address formats, contract addresses,
|
|
13
|
+
* or scheme IDs — they pass `0xRecipient`, an asset, and an amount.
|
|
14
|
+
*
|
|
15
|
+
* Privacy invariants (see CLAUDE.md):
|
|
16
|
+
* - No console.* anywhere.
|
|
17
|
+
* - No plaintext amount in any error message.
|
|
18
|
+
* - The recipient wallet is NOT placed in `.message` strings; it lives on
|
|
19
|
+
* `RecipientNotOnboardedError.wallet` so log scrapers picking up `.message`
|
|
20
|
+
* do not capture it.
|
|
21
|
+
*/
|
|
22
|
+
import type { Address } from 'viem';
|
|
23
|
+
import type { StealthMetaAddress } from '@shroud-fi/core';
|
|
24
|
+
import type { ShroudFiTransport } from '@shroud-fi/transport';
|
|
25
|
+
import type { PaymentReceipt, SendOptions } from './types.js';
|
|
26
|
+
/**
|
|
27
|
+
* Asset selector. `'ETH'` sends native ETH; `{ token: 0x... }` sends an
|
|
28
|
+
* ERC-20 (caller must have pre-approved `ShroudFiStealth` to spend the
|
|
29
|
+
* amount from the sender's account — same constraint as `sendERC20Payment`).
|
|
30
|
+
*/
|
|
31
|
+
export type SendToWalletAsset = 'ETH' | {
|
|
32
|
+
readonly token: Address;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Look up a wallet's stealth meta-address in the canonical ERC-6538 registry.
|
|
36
|
+
* Public helper — useful for UIs that want to show "this wallet is onboarded"
|
|
37
|
+
* without dispatching a payment.
|
|
38
|
+
*
|
|
39
|
+
* @returns the decoded meta-address, or `null` if the wallet is not registered.
|
|
40
|
+
* @throws MalformedMetaAddressError if the registry bytes are not the expected
|
|
41
|
+
* 66-byte (33 + 33) compressed-key payload.
|
|
42
|
+
*/
|
|
43
|
+
export declare function lookupMetaAddress(transport: ShroudFiTransport, recipientWallet: Address): Promise<StealthMetaAddress | null>;
|
|
44
|
+
/**
|
|
45
|
+
* Send a payment to a plain EVM wallet address. The helper performs the
|
|
46
|
+
* Registry lookup → stealth derivation → on-chain dispatch in one call.
|
|
47
|
+
*
|
|
48
|
+
* @throws RecipientNotOnboardedError if the recipient has not registered.
|
|
49
|
+
* @throws MalformedMetaAddressError if the registry payload is corrupt.
|
|
50
|
+
* @throws InvalidRecipientError if `recipientWallet` is zero / not a valid address,
|
|
51
|
+
* or if the meta-address fails curve validation downstream.
|
|
52
|
+
* @throws ZeroAmountError if `amount` is 0n.
|
|
53
|
+
* @throws MissingWalletClientError if transport has no walletClient configured.
|
|
54
|
+
* @throws UnknownChainError if the transport's chain has no ShroudFiStealth deployment.
|
|
55
|
+
*/
|
|
56
|
+
export declare function sendToWallet(transport: ShroudFiTransport, recipientWallet: Address, asset: SendToWalletAsset, amount: bigint, options?: SendOptions): Promise<PaymentReceipt>;
|
|
57
|
+
//# sourceMappingURL=send-to-wallet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-to-wallet.d.ts","sourceRoot":"","sources":["../../src/send-to-wallet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAqB,MAAM,MAAM,CAAC;AAEvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAM1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAY9D;;;;GAIG;AACH,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAKpE;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,eAAe,EAAE,OAAO,GACvB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,SAAS,EAAE,iBAAiB,EAC5B,eAAe,EAAE,OAAO,EACxB,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,cAAc,CAAC,CAsBzB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sendToWallet — ergonomic agent-facing helper.
|
|
3
|
+
*
|
|
4
|
+
* Pay an EVM wallet by its plain address. The helper:
|
|
5
|
+
* 1. Queries the canonical ERC-6538 Registry for the recipient's stealth
|
|
6
|
+
* meta-address (scheme 1, secp256k1 + view tag).
|
|
7
|
+
* 2. Throws `RecipientNotOnboardedError` if the recipient has not registered.
|
|
8
|
+
* 3. Decodes the 66-byte payload into a `StealthMetaAddress`.
|
|
9
|
+
* 4. Resolves the chain's `ShroudFiStealth` contract.
|
|
10
|
+
* 5. Dispatches to `sendETHPayment` or `sendERC20Payment`.
|
|
11
|
+
*
|
|
12
|
+
* Senders never have to know about meta-address formats, contract addresses,
|
|
13
|
+
* or scheme IDs — they pass `0xRecipient`, an asset, and an amount.
|
|
14
|
+
*
|
|
15
|
+
* Privacy invariants (see CLAUDE.md):
|
|
16
|
+
* - No console.* anywhere.
|
|
17
|
+
* - No plaintext amount in any error message.
|
|
18
|
+
* - The recipient wallet is NOT placed in `.message` strings; it lives on
|
|
19
|
+
* `RecipientNotOnboardedError.wallet` so log scrapers picking up `.message`
|
|
20
|
+
* do not capture it.
|
|
21
|
+
*/
|
|
22
|
+
import { hexToBytes, isAddress } from 'viem';
|
|
23
|
+
import { ERC6538_REGISTRY, ERC6538RegistryAbi, getShroudFiStealth, } from '@shroud-fi/transport';
|
|
24
|
+
import { sendETHPayment, sendERC20Payment } from './payments.js';
|
|
25
|
+
import { InvalidRecipientError, MalformedMetaAddressError, RecipientNotOnboardedError, } from './errors.js';
|
|
26
|
+
import { SCHEME_ID, ZERO_ADDRESS } from './constants.js';
|
|
27
|
+
// Numeric form for the `StealthMetaAddress.schemeId` field (which is `number`).
|
|
28
|
+
// Keep in sync with payments' `SCHEME_ID` bigint (registry call arg).
|
|
29
|
+
const STEALTH_SCHEME_ID_NUM = 1;
|
|
30
|
+
const COMPRESSED_KEY_LENGTH = 33;
|
|
31
|
+
const META_ADDRESS_PAYLOAD_LENGTH = COMPRESSED_KEY_LENGTH * 2;
|
|
32
|
+
/**
|
|
33
|
+
* Look up a wallet's stealth meta-address in the canonical ERC-6538 registry.
|
|
34
|
+
* Public helper — useful for UIs that want to show "this wallet is onboarded"
|
|
35
|
+
* without dispatching a payment.
|
|
36
|
+
*
|
|
37
|
+
* @returns the decoded meta-address, or `null` if the wallet is not registered.
|
|
38
|
+
* @throws MalformedMetaAddressError if the registry bytes are not the expected
|
|
39
|
+
* 66-byte (33 + 33) compressed-key payload.
|
|
40
|
+
*/
|
|
41
|
+
export async function lookupMetaAddress(transport, recipientWallet) {
|
|
42
|
+
if (!isAddress(recipientWallet) || recipientWallet === ZERO_ADDRESS) {
|
|
43
|
+
throw new InvalidRecipientError();
|
|
44
|
+
}
|
|
45
|
+
const raw = (await transport.publicClient.readContract({
|
|
46
|
+
address: ERC6538_REGISTRY,
|
|
47
|
+
abi: ERC6538RegistryAbi,
|
|
48
|
+
functionName: 'stealthMetaAddressOf',
|
|
49
|
+
args: [recipientWallet, SCHEME_ID],
|
|
50
|
+
}));
|
|
51
|
+
// Empty bytes → not registered. viem returns '0x' for empty.
|
|
52
|
+
if (raw === '0x' || raw.length <= 2)
|
|
53
|
+
return null;
|
|
54
|
+
const bytes = hexToBytes(raw);
|
|
55
|
+
if (bytes.length !== META_ADDRESS_PAYLOAD_LENGTH) {
|
|
56
|
+
throw new MalformedMetaAddressError();
|
|
57
|
+
}
|
|
58
|
+
const spendingPubKey = bytes.slice(0, COMPRESSED_KEY_LENGTH);
|
|
59
|
+
const viewingPubKey = bytes.slice(COMPRESSED_KEY_LENGTH);
|
|
60
|
+
const sPrefix = spendingPubKey[0];
|
|
61
|
+
const vPrefix = viewingPubKey[0];
|
|
62
|
+
if (sPrefix !== 0x02 && sPrefix !== 0x03) {
|
|
63
|
+
throw new MalformedMetaAddressError();
|
|
64
|
+
}
|
|
65
|
+
if (vPrefix !== 0x02 && vPrefix !== 0x03) {
|
|
66
|
+
throw new MalformedMetaAddressError();
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
spendingPubKey,
|
|
70
|
+
viewingPubKey,
|
|
71
|
+
schemeId: STEALTH_SCHEME_ID_NUM,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Send a payment to a plain EVM wallet address. The helper performs the
|
|
76
|
+
* Registry lookup → stealth derivation → on-chain dispatch in one call.
|
|
77
|
+
*
|
|
78
|
+
* @throws RecipientNotOnboardedError if the recipient has not registered.
|
|
79
|
+
* @throws MalformedMetaAddressError if the registry payload is corrupt.
|
|
80
|
+
* @throws InvalidRecipientError if `recipientWallet` is zero / not a valid address,
|
|
81
|
+
* or if the meta-address fails curve validation downstream.
|
|
82
|
+
* @throws ZeroAmountError if `amount` is 0n.
|
|
83
|
+
* @throws MissingWalletClientError if transport has no walletClient configured.
|
|
84
|
+
* @throws UnknownChainError if the transport's chain has no ShroudFiStealth deployment.
|
|
85
|
+
*/
|
|
86
|
+
export async function sendToWallet(transport, recipientWallet, asset, amount, options) {
|
|
87
|
+
if (!isAddress(recipientWallet) || recipientWallet === ZERO_ADDRESS) {
|
|
88
|
+
throw new InvalidRecipientError();
|
|
89
|
+
}
|
|
90
|
+
const meta = await lookupMetaAddress(transport, recipientWallet);
|
|
91
|
+
if (meta === null) {
|
|
92
|
+
throw new RecipientNotOnboardedError(recipientWallet);
|
|
93
|
+
}
|
|
94
|
+
const stealthContract = getShroudFiStealth(transport.chain.id);
|
|
95
|
+
if (asset === 'ETH') {
|
|
96
|
+
return sendETHPayment(transport, stealthContract, meta, amount, options);
|
|
97
|
+
}
|
|
98
|
+
return sendERC20Payment(transport, stealthContract, meta, asset.token, amount, options);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=send-to-wallet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-to-wallet.js","sourceRoot":"","sources":["../../src/send-to-wallet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Address, Hex } from 'viem';
|
|
2
|
+
import type { ShroudFiTransport } from '@shroud-fi/transport';
|
|
3
|
+
import type { SweepReceipt, SendOptions } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Sweep the entire ETH balance from a stealth address to a destination.
|
|
6
|
+
*
|
|
7
|
+
* @param transport - ShroudFi transport (publicClient must reach the target chain)
|
|
8
|
+
* @param stealthPrivateKey - one-time stealth address private key. Treat as
|
|
9
|
+
* sensitive: caller MUST NOT log, persist, or transmit this value. The SDK
|
|
10
|
+
* does not retain it after the call returns.
|
|
11
|
+
* @param destination - final address that receives swept ETH
|
|
12
|
+
* @param options - optional fee/nonce overrides
|
|
13
|
+
*
|
|
14
|
+
* @remarks Phase 1: self-funded sweep. The stealth address pays its own gas in ETH,
|
|
15
|
+
* which creates a gas-funding correlation vector documented in research (Umbra deanonymization
|
|
16
|
+
* heuristic H2). This will be addressed in Phase 5 by a gasless relayer flow.
|
|
17
|
+
*
|
|
18
|
+
* @remarks Balance/nonce/gas-price are queried separately before signing. Callers running
|
|
19
|
+
* sweeps concurrently against the same stealth address should pass an explicit `nonce` in
|
|
20
|
+
* options to avoid races. Stack traces of thrown errors should NOT be logged by callers —
|
|
21
|
+
* they may contain RPC payload metadata.
|
|
22
|
+
*/
|
|
23
|
+
export declare function sweepETH(transport: ShroudFiTransport, stealthPrivateKey: Hex, destination: Address, options?: SendOptions): Promise<SweepReceipt>;
|
|
24
|
+
/**
|
|
25
|
+
* Sweep the entire ERC20 balance from a stealth address to a destination.
|
|
26
|
+
*
|
|
27
|
+
* The stealth address must already hold enough ETH to pay gas for the
|
|
28
|
+
* ERC20 transfer. Funding it from another account links the two — see
|
|
29
|
+
* privacy notes below.
|
|
30
|
+
*
|
|
31
|
+
* @param transport - ShroudFi transport
|
|
32
|
+
* @param stealthPrivateKey - one-time stealth private key (see sweepETH note)
|
|
33
|
+
* @param token - ERC20 contract address
|
|
34
|
+
* @param destination - final address that receives swept tokens
|
|
35
|
+
* @param options - optional fee/nonce overrides
|
|
36
|
+
*
|
|
37
|
+
* @remarks Phase 1: self-funded sweep. The stealth address pays its own gas in ETH,
|
|
38
|
+
* which creates a gas-funding correlation vector documented in research (Umbra deanonymization
|
|
39
|
+
* heuristic H2). This will be addressed in Phase 5 by a gasless relayer flow.
|
|
40
|
+
*
|
|
41
|
+
* @remarks Balance/nonce/gas-price are queried separately before signing. Callers running
|
|
42
|
+
* sweeps concurrently against the same stealth address should pass an explicit `nonce` in
|
|
43
|
+
* options to avoid races. Stack traces of thrown errors should NOT be logged by callers —
|
|
44
|
+
* they may contain RPC payload metadata.
|
|
45
|
+
*/
|
|
46
|
+
export declare function sweepERC20(transport: ShroudFiTransport, stealthPrivateKey: Hex, token: Address, destination: Address, options?: SendOptions): Promise<SweepReceipt>;
|
|
47
|
+
//# sourceMappingURL=sweep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sweep.d.ts","sourceRoot":"","sources":["../../src/sweep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAIzC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA4F5D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,iBAAiB,EAC5B,iBAAiB,EAAE,GAAG,EACtB,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,CAAC,CA2EvB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,UAAU,CAC9B,SAAS,EAAE,iBAAiB,EAC5B,iBAAiB,EAAE,GAAG,EACtB,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,OAAO,EACpB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,CAAC,CAsFvB"}
|