@t402/wdk 2.4.0 → 2.6.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/cjs/adapters/index.d.ts +198 -1
- package/dist/cjs/adapters/index.js +255 -0
- package/dist/cjs/adapters/index.js.map +1 -1
- package/dist/cjs/adapters/svm-adapter.d.ts +146 -2
- package/dist/cjs/adapters/svm-adapter.js +255 -2
- package/dist/cjs/adapters/svm-adapter.js.map +1 -1
- package/dist/cjs/adapters/ton-adapter.d.ts +57 -2
- package/dist/cjs/adapters/ton-adapter.js +75 -2
- package/dist/cjs/adapters/ton-adapter.js.map +1 -1
- package/dist/cjs/adapters/tron-adapter.d.ts +57 -2
- package/dist/cjs/adapters/tron-adapter.js +101 -0
- package/dist/cjs/adapters/tron-adapter.js.map +1 -1
- package/dist/cjs/index-DnEI5M6d.d.ts +1798 -0
- package/dist/cjs/index.d.ts +702 -1118
- package/dist/cjs/index.js +3905 -246
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/integrations/index.d.ts +9 -0
- package/dist/cjs/integrations/index.js +249 -0
- package/dist/cjs/integrations/index.js.map +1 -0
- package/dist/cjs/testing/index.d.ts +62 -0
- package/dist/cjs/testing/index.js +129 -0
- package/dist/cjs/testing/index.js.map +1 -0
- package/dist/cjs/types-BwK8Xgvg.d.ts +967 -0
- package/dist/esm/adapters/index.d.mts +198 -1
- package/dist/esm/adapters/index.mjs +14 -3
- package/dist/esm/adapters/svm-adapter.d.mts +146 -2
- package/dist/esm/adapters/svm-adapter.mjs +18 -3
- package/dist/esm/adapters/ton-adapter.d.mts +57 -2
- package/dist/esm/adapters/ton-adapter.mjs +8 -3
- package/dist/esm/adapters/tron-adapter.d.mts +57 -2
- package/dist/esm/adapters/tron-adapter.mjs +2 -1
- package/dist/esm/chunk-2KWVW77U.mjs +353 -0
- package/dist/esm/chunk-2KWVW77U.mjs.map +1 -0
- package/dist/esm/chunk-7CG77QAN.mjs +153 -0
- package/dist/esm/chunk-7CG77QAN.mjs.map +1 -0
- package/dist/esm/chunk-BJTO5JO5.mjs +11 -0
- package/dist/esm/chunk-BJTO5JO5.mjs.map +1 -0
- package/dist/esm/{chunk-YWBJJV5M.mjs → chunk-KWX6CJIH.mjs} +72 -1
- package/dist/esm/chunk-KWX6CJIH.mjs.map +1 -0
- package/dist/esm/{chunk-HB2DGKQ3.mjs → chunk-QZKUU2O6.mjs} +102 -1
- package/dist/esm/chunk-QZKUU2O6.mjs.map +1 -0
- package/dist/esm/chunk-TVSNUSFZ.mjs +219 -0
- package/dist/esm/chunk-TVSNUSFZ.mjs.map +1 -0
- package/dist/esm/index-D5kvtDfm.d.mts +1798 -0
- package/dist/esm/index.d.mts +702 -1118
- package/dist/esm/index.mjs +2934 -70
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/integrations/index.d.mts +9 -0
- package/dist/esm/integrations/index.mjs +16 -0
- package/dist/esm/integrations/index.mjs.map +1 -0
- package/dist/esm/testing/index.d.mts +62 -0
- package/dist/esm/testing/index.mjs +101 -0
- package/dist/esm/testing/index.mjs.map +1 -0
- package/dist/esm/types-BwK8Xgvg.d.mts +967 -0
- package/package.json +69 -20
- package/dist/cjs/types-V7c-qhn6.d.ts +0 -489
- package/dist/esm/chunk-HB2DGKQ3.mjs.map +0 -1
- package/dist/esm/chunk-MCFHZSF7.mjs +0 -107
- package/dist/esm/chunk-MCFHZSF7.mjs.map +0 -1
- package/dist/esm/chunk-YWBJJV5M.mjs.map +0 -1
- package/dist/esm/types-V7c-qhn6.d.mts +0 -489
|
@@ -21,7 +21,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var svm_adapter_exports = {};
|
|
22
22
|
__export(svm_adapter_exports, {
|
|
23
23
|
WDKSvmSignerAdapter: () => WDKSvmSignerAdapter,
|
|
24
|
-
|
|
24
|
+
buildVersionedTransaction: () => buildVersionedTransaction,
|
|
25
|
+
createWDKSvmSigner: () => createWDKSvmSigner,
|
|
26
|
+
deriveATAAddress: () => deriveATAAddress,
|
|
27
|
+
getRecentPriorityFees: () => getRecentPriorityFees,
|
|
28
|
+
getTokenProgram: () => getTokenProgram,
|
|
29
|
+
getTransferFee: () => getTransferFee,
|
|
30
|
+
resolveATA: () => resolveATA,
|
|
31
|
+
transferWithPriorityFee: () => transferWithPriorityFee
|
|
25
32
|
});
|
|
26
33
|
module.exports = __toCommonJS(svm_adapter_exports);
|
|
27
34
|
var WDKSvmSignerAdapter = class {
|
|
@@ -119,6 +126,245 @@ var WDKSvmSignerAdapter = class {
|
|
|
119
126
|
return this._account.transfer(params);
|
|
120
127
|
}
|
|
121
128
|
};
|
|
129
|
+
var COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111";
|
|
130
|
+
var TOKEN_PROGRAM_ID = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
|
|
131
|
+
var TOKEN_2022_PROGRAM_ID = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
|
|
132
|
+
var ASSOCIATED_TOKEN_PROGRAM_ID = "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL";
|
|
133
|
+
function buildVersionedTransaction(adapter, params) {
|
|
134
|
+
if (!adapter.isInitialized) {
|
|
135
|
+
throw new Error("Adapter must be initialized before building transactions");
|
|
136
|
+
}
|
|
137
|
+
const allInstructions = [];
|
|
138
|
+
if (params.priorityFee) {
|
|
139
|
+
allInstructions.push(
|
|
140
|
+
createSetComputeUnitLimitInstruction(params.priorityFee.computeUnits ?? 2e5)
|
|
141
|
+
);
|
|
142
|
+
allInstructions.push(createSetComputeUnitPriceInstruction(params.priorityFee.microLamports));
|
|
143
|
+
}
|
|
144
|
+
allInstructions.push(...params.instructions);
|
|
145
|
+
const lookupTableCount = params.addressLookupTableAccounts?.length ?? 0;
|
|
146
|
+
const header = {
|
|
147
|
+
version: 0,
|
|
148
|
+
numSigners: 1,
|
|
149
|
+
numReadonlySignedAccounts: 0,
|
|
150
|
+
numReadonlyUnsignedAccounts: 0,
|
|
151
|
+
feePayer: adapter.address,
|
|
152
|
+
instructions: allInstructions,
|
|
153
|
+
lookupTableCount
|
|
154
|
+
};
|
|
155
|
+
return serializeVersionedMessage(header);
|
|
156
|
+
}
|
|
157
|
+
async function transferWithPriorityFee(adapter, params) {
|
|
158
|
+
if (!adapter.isInitialized) {
|
|
159
|
+
throw new Error("Adapter must be initialized before transferring");
|
|
160
|
+
}
|
|
161
|
+
return adapter.transfer({
|
|
162
|
+
token: params.token,
|
|
163
|
+
recipient: params.recipient,
|
|
164
|
+
amount: params.amount
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
async function getRecentPriorityFees(rpcUrl) {
|
|
168
|
+
const response = await fetch(rpcUrl, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: { "Content-Type": "application/json" },
|
|
171
|
+
body: JSON.stringify({
|
|
172
|
+
jsonrpc: "2.0",
|
|
173
|
+
id: 1,
|
|
174
|
+
method: "getRecentPrioritizationFees",
|
|
175
|
+
params: []
|
|
176
|
+
})
|
|
177
|
+
});
|
|
178
|
+
if (!response.ok) {
|
|
179
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
180
|
+
}
|
|
181
|
+
const result = await response.json();
|
|
182
|
+
if (result.error) {
|
|
183
|
+
throw new Error(`RPC error: ${result.error.message}`);
|
|
184
|
+
}
|
|
185
|
+
const fees = result.result ?? [];
|
|
186
|
+
if (fees.length === 0) {
|
|
187
|
+
return { low: 0, medium: 0, high: 0 };
|
|
188
|
+
}
|
|
189
|
+
const sorted = fees.map((f) => f.prioritizationFee).sort((a, b) => a - b);
|
|
190
|
+
const p25 = sorted[Math.floor(sorted.length * 0.25)] ?? 0;
|
|
191
|
+
const p50 = sorted[Math.floor(sorted.length * 0.5)] ?? 0;
|
|
192
|
+
const p75 = sorted[Math.floor(sorted.length * 0.75)] ?? 0;
|
|
193
|
+
return { low: p25, medium: p50, high: p75 };
|
|
194
|
+
}
|
|
195
|
+
async function resolveATA(rpcUrl, owner, mint) {
|
|
196
|
+
const ataAddress = deriveATAAddress(owner, mint);
|
|
197
|
+
const response = await fetch(rpcUrl, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: { "Content-Type": "application/json" },
|
|
200
|
+
body: JSON.stringify({
|
|
201
|
+
jsonrpc: "2.0",
|
|
202
|
+
id: 1,
|
|
203
|
+
method: "getAccountInfo",
|
|
204
|
+
params: [ataAddress, { encoding: "base64" }]
|
|
205
|
+
})
|
|
206
|
+
});
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
209
|
+
}
|
|
210
|
+
const result = await response.json();
|
|
211
|
+
if (result.error) {
|
|
212
|
+
throw new Error(`RPC error: ${result.error.message}`);
|
|
213
|
+
}
|
|
214
|
+
const exists = result.result?.value != null;
|
|
215
|
+
if (exists) {
|
|
216
|
+
return { address: ataAddress, exists: true };
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
address: ataAddress,
|
|
220
|
+
exists: false,
|
|
221
|
+
createInstruction: {
|
|
222
|
+
programId: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
223
|
+
keys: [
|
|
224
|
+
{ pubkey: owner, isSigner: true, isWritable: true },
|
|
225
|
+
{ pubkey: ataAddress, isSigner: false, isWritable: true },
|
|
226
|
+
{ pubkey: owner, isSigner: false, isWritable: false },
|
|
227
|
+
{ pubkey: mint, isSigner: false, isWritable: false },
|
|
228
|
+
{ pubkey: "11111111111111111111111111111111", isSigner: false, isWritable: false },
|
|
229
|
+
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }
|
|
230
|
+
],
|
|
231
|
+
data: new Uint8Array(0)
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
async function getTokenProgram(rpcUrl, mint) {
|
|
236
|
+
const response = await fetch(rpcUrl, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: { "Content-Type": "application/json" },
|
|
239
|
+
body: JSON.stringify({
|
|
240
|
+
jsonrpc: "2.0",
|
|
241
|
+
id: 1,
|
|
242
|
+
method: "getAccountInfo",
|
|
243
|
+
params: [mint, { encoding: "jsonParsed" }]
|
|
244
|
+
})
|
|
245
|
+
});
|
|
246
|
+
if (!response.ok) {
|
|
247
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
248
|
+
}
|
|
249
|
+
const result = await response.json();
|
|
250
|
+
if (result.error) {
|
|
251
|
+
throw new Error(`RPC error: ${result.error.message}`);
|
|
252
|
+
}
|
|
253
|
+
if (!result.result?.value) {
|
|
254
|
+
throw new Error(`Mint account not found: ${mint}`);
|
|
255
|
+
}
|
|
256
|
+
const owner = result.result.value.owner;
|
|
257
|
+
if (owner === TOKEN_2022_PROGRAM_ID) {
|
|
258
|
+
return "Token-2022";
|
|
259
|
+
}
|
|
260
|
+
return "Token";
|
|
261
|
+
}
|
|
262
|
+
async function getTransferFee(rpcUrl, mint, amount) {
|
|
263
|
+
const response = await fetch(rpcUrl, {
|
|
264
|
+
method: "POST",
|
|
265
|
+
headers: { "Content-Type": "application/json" },
|
|
266
|
+
body: JSON.stringify({
|
|
267
|
+
jsonrpc: "2.0",
|
|
268
|
+
id: 1,
|
|
269
|
+
method: "getAccountInfo",
|
|
270
|
+
params: [mint, { encoding: "jsonParsed" }]
|
|
271
|
+
})
|
|
272
|
+
});
|
|
273
|
+
if (!response.ok) {
|
|
274
|
+
throw new Error(`RPC request failed: ${response.status}`);
|
|
275
|
+
}
|
|
276
|
+
const result = await response.json();
|
|
277
|
+
if (result.error) {
|
|
278
|
+
throw new Error(`RPC error: ${result.error.message}`);
|
|
279
|
+
}
|
|
280
|
+
if (!result.result?.value) {
|
|
281
|
+
throw new Error(`Mint account not found: ${mint}`);
|
|
282
|
+
}
|
|
283
|
+
const extensions = result.result.value.data?.parsed?.info?.extensions ?? [];
|
|
284
|
+
const transferFeeExt = extensions.find((e) => e.extension === "transferFeeConfig");
|
|
285
|
+
if (!transferFeeExt?.state) {
|
|
286
|
+
return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n };
|
|
287
|
+
}
|
|
288
|
+
const feeConfig = transferFeeExt.state.newerTransferFee ?? transferFeeExt.state.olderTransferFee;
|
|
289
|
+
if (!feeConfig) {
|
|
290
|
+
return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n };
|
|
291
|
+
}
|
|
292
|
+
const basisPoints = feeConfig.transferFeeBasisPoints;
|
|
293
|
+
const maxFee = BigInt(feeConfig.maximumFee);
|
|
294
|
+
let fee = amount * BigInt(basisPoints) / 10000n;
|
|
295
|
+
if (fee > maxFee) fee = maxFee;
|
|
296
|
+
return {
|
|
297
|
+
fee,
|
|
298
|
+
netAmount: amount - fee,
|
|
299
|
+
transferFeeBasisPoints: basisPoints,
|
|
300
|
+
maximumFee: maxFee
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function createSetComputeUnitLimitInstruction(units) {
|
|
304
|
+
const data = new Uint8Array(5);
|
|
305
|
+
data[0] = 2;
|
|
306
|
+
const view = new DataView(data.buffer);
|
|
307
|
+
view.setUint32(1, units, true);
|
|
308
|
+
return {
|
|
309
|
+
programId: COMPUTE_BUDGET_PROGRAM_ID,
|
|
310
|
+
keys: [],
|
|
311
|
+
data
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function createSetComputeUnitPriceInstruction(microLamports) {
|
|
315
|
+
const data = new Uint8Array(9);
|
|
316
|
+
data[0] = 3;
|
|
317
|
+
const view = new DataView(data.buffer);
|
|
318
|
+
view.setUint32(1, microLamports & 4294967295, true);
|
|
319
|
+
view.setUint32(5, Math.floor(microLamports / 4294967296) & 4294967295, true);
|
|
320
|
+
return {
|
|
321
|
+
programId: COMPUTE_BUDGET_PROGRAM_ID,
|
|
322
|
+
keys: [],
|
|
323
|
+
data
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
function deriveATAAddress(owner, mint) {
|
|
327
|
+
return `ata:${owner}:${mint}`;
|
|
328
|
+
}
|
|
329
|
+
function serializeVersionedMessage(header) {
|
|
330
|
+
const encoder = new TextEncoder();
|
|
331
|
+
const parts = [];
|
|
332
|
+
parts.push(new Uint8Array([128]));
|
|
333
|
+
parts.push(
|
|
334
|
+
new Uint8Array([
|
|
335
|
+
header.numSigners,
|
|
336
|
+
header.numReadonlySignedAccounts,
|
|
337
|
+
header.numReadonlyUnsignedAccounts
|
|
338
|
+
])
|
|
339
|
+
);
|
|
340
|
+
const feePayerBytes = encoder.encode(header.feePayer);
|
|
341
|
+
parts.push(new Uint8Array([feePayerBytes.length]));
|
|
342
|
+
parts.push(feePayerBytes);
|
|
343
|
+
parts.push(new Uint8Array([header.instructions.length]));
|
|
344
|
+
for (const ix of header.instructions) {
|
|
345
|
+
const pidBytes = encoder.encode(ix.programId);
|
|
346
|
+
parts.push(new Uint8Array([pidBytes.length]));
|
|
347
|
+
parts.push(pidBytes);
|
|
348
|
+
parts.push(new Uint8Array([ix.keys.length]));
|
|
349
|
+
for (const key of ix.keys) {
|
|
350
|
+
const keyBytes = encoder.encode(key.pubkey);
|
|
351
|
+
parts.push(new Uint8Array([keyBytes.length]));
|
|
352
|
+
parts.push(keyBytes);
|
|
353
|
+
parts.push(new Uint8Array([key.isSigner ? 1 : 0, key.isWritable ? 1 : 0]));
|
|
354
|
+
}
|
|
355
|
+
parts.push(new Uint8Array([ix.data.length]));
|
|
356
|
+
parts.push(ix.data);
|
|
357
|
+
}
|
|
358
|
+
parts.push(new Uint8Array([header.lookupTableCount]));
|
|
359
|
+
const totalLength = parts.reduce((sum, p) => sum + p.length, 0);
|
|
360
|
+
const result = new Uint8Array(totalLength);
|
|
361
|
+
let offset = 0;
|
|
362
|
+
for (const part of parts) {
|
|
363
|
+
result.set(part, offset);
|
|
364
|
+
offset += part.length;
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
122
368
|
async function createWDKSvmSigner(account) {
|
|
123
369
|
const adapter = new WDKSvmSignerAdapter(account);
|
|
124
370
|
await adapter.initialize();
|
|
@@ -127,6 +373,13 @@ async function createWDKSvmSigner(account) {
|
|
|
127
373
|
// Annotate the CommonJS export names for ESM import in node:
|
|
128
374
|
0 && (module.exports = {
|
|
129
375
|
WDKSvmSignerAdapter,
|
|
130
|
-
|
|
376
|
+
buildVersionedTransaction,
|
|
377
|
+
createWDKSvmSigner,
|
|
378
|
+
deriveATAAddress,
|
|
379
|
+
getRecentPriorityFees,
|
|
380
|
+
getTokenProgram,
|
|
381
|
+
getTransferFee,
|
|
382
|
+
resolveATA,
|
|
383
|
+
transferWithPriorityFee
|
|
131
384
|
});
|
|
132
385
|
//# sourceMappingURL=svm-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/svm-adapter.ts"],"sourcesContent":["/**\n * Solana (SVM) Signer Adapter for WDK\n *\n * Wraps a Tether WDK Solana account to implement T402's ClientSvmSigner interface.\n * ClientSvmSigner is just TransactionSigner from @solana/kit.\n */\n\nimport type { WDKSolanaAccount } from '../types.js'\n\n/**\n * Address type from @solana/kit (base58 string)\n * We use a branded type for compatibility\n */\nexport type SolanaAddress = string & { readonly __brand?: unique symbol }\n\n/**\n * TransactionSigner interface matching @solana/kit\n * This is what T402's ClientSvmSigner expects\n */\nexport interface TransactionSigner {\n readonly address: SolanaAddress\n signTransactions<T extends { messageBytes: Uint8Array; signatures: Record<string, unknown> }>(\n transactions: readonly T[],\n ): Promise<readonly Record<string, Uint8Array>[]>\n}\n\n/**\n * WDKSvmSignerAdapter - Adapts a WDK Solana account to T402's ClientSvmSigner\n *\n * ClientSvmSigner is TransactionSigner from @solana/kit which requires:\n * - address: The public key as Address type\n * - signTransactions: Sign multiple transactions, returning signature dictionaries\n *\n * @example\n * ```typescript\n * const adapter = await createWDKSvmSigner(wdkSolanaAccount);\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'solana:mainnet', signer: adapter }]\n * });\n * ```\n */\nexport class WDKSvmSignerAdapter implements TransactionSigner {\n private _account: WDKSolanaAccount\n private _address: SolanaAddress | null = null\n private _initialized = false\n\n constructor(account: WDKSolanaAccount) {\n if (!account) {\n throw new Error('WDK Solana account is required')\n }\n this._account = account\n }\n\n /**\n * Get the wallet address (base58)\n * @throws Error if not initialized\n */\n get address(): SolanaAddress {\n if (!this._address) {\n throw new Error(\n 'Solana signer not initialized. Call initialize() first or use createWDKSvmSigner().',\n )\n }\n return this._address\n }\n\n /**\n * Check if the adapter is initialized\n */\n get isInitialized(): boolean {\n return this._initialized\n }\n\n /**\n * Initialize the adapter by fetching the address\n * Must be called before using the signer\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return\n }\n\n const addressStr = await this._account.getAddress()\n this._address = addressStr as SolanaAddress\n this._initialized = true\n }\n\n /**\n * Sign transactions with this signer\n *\n * This method signs the message bytes of each transaction and returns\n * signature dictionaries mapping address to signature.\n *\n * @param transactions - Array of transactions to sign\n * @returns Array of signature dictionaries\n */\n async signTransactions<\n T extends { messageBytes: Uint8Array; signatures: Record<string, unknown> },\n >(transactions: readonly T[]): Promise<readonly Record<string, Uint8Array>[]> {\n if (!transactions || transactions.length === 0) {\n return []\n }\n\n const results: Record<string, Uint8Array>[] = []\n\n for (const tx of transactions) {\n if (!tx.messageBytes || tx.messageBytes.length === 0) {\n throw new Error('Transaction messageBytes must not be empty')\n }\n\n // Sign the message bytes using WDK account\n const signature = await this._account.sign(tx.messageBytes)\n\n // Return as a dictionary mapping our address to the signature\n results.push({\n [this._address as string]: signature,\n })\n }\n\n return results\n }\n\n /**\n * Sign a single message (utility method)\n * @param message - Message bytes to sign\n * @returns Signature bytes\n */\n async sign(message: Uint8Array): Promise<Uint8Array> {\n return this._account.sign(message)\n }\n\n /**\n * Get SOL balance in lamports\n */\n async getBalance(): Promise<bigint> {\n return this._account.getBalance()\n }\n\n /**\n * Get SPL token balance\n * @param mint - Token mint address\n */\n async getTokenBalance(mint: string): Promise<bigint> {\n return this._account.getTokenBalance(mint)\n }\n\n /**\n * Transfer SPL tokens\n * @param params - Transfer parameters\n * @returns Transaction signature\n */\n async transfer(params: { token: string; recipient: string; amount: bigint }): Promise<string> {\n return this._account.transfer(params)\n }\n}\n\n/**\n * Create an initialized WDK Solana signer\n *\n * @param account - WDK Solana account from @tetherto/wdk-wallet-solana\n * @returns Initialized TransactionSigner (ClientSvmSigner)\n *\n * @example\n * ```typescript\n * import { T402WDK } from '@t402/wdk';\n *\n * const wallet = new T402WDK(seedPhrase, config);\n * const svmSigner = await wallet.getSvmSigner();\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'solana:mainnet', signer: svmSigner }]\n * });\n * ```\n */\nexport async function createWDKSvmSigner(account: WDKSolanaAccount): Promise<WDKSvmSignerAdapter> {\n const adapter = new WDKSvmSignerAdapter(account)\n await adapter.initialize()\n return adapter\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CO,IAAM,sBAAN,MAAuD;AAAA,EACpD;AAAA,EACA,WAAiC;AAAA,EACjC,eAAe;AAAA,EAEvB,YAAY,SAA2B;AACrC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAyB;AAC3B,QAAI,CAAC,KAAK,UAAU;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAA4B;AAChC,QAAI,KAAK,cAAc;AACrB;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,KAAK,SAAS,WAAW;AAClD,SAAK,WAAW;AAChB,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,iBAEJ,cAA4E;AAC5E,QAAI,CAAC,gBAAgB,aAAa,WAAW,GAAG;AAC9C,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAwC,CAAC;AAE/C,eAAW,MAAM,cAAc;AAC7B,UAAI,CAAC,GAAG,gBAAgB,GAAG,aAAa,WAAW,GAAG;AACpD,cAAM,IAAI,MAAM,4CAA4C;AAAA,MAC9D;AAGA,YAAM,YAAY,MAAM,KAAK,SAAS,KAAK,GAAG,YAAY;AAG1D,cAAQ,KAAK;AAAA,QACX,CAAC,KAAK,QAAkB,GAAG;AAAA,MAC7B,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,KAAK,SAA0C;AACnD,WAAO,KAAK,SAAS,KAAK,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA8B;AAClC,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,MAA+B;AACnD,WAAO,KAAK,SAAS,gBAAgB,IAAI;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,SAAS,QAA+E;AAC5F,WAAO,KAAK,SAAS,SAAS,MAAM;AAAA,EACtC;AACF;AAqBA,eAAsB,mBAAmB,SAAyD;AAChG,QAAM,UAAU,IAAI,oBAAoB,OAAO;AAC/C,QAAM,QAAQ,WAAW;AACzB,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/svm-adapter.ts"],"sourcesContent":["/**\n * Solana (SVM) Signer Adapter for WDK\n *\n * Wraps a Tether WDK Solana account to implement T402's ClientSvmSigner interface.\n * ClientSvmSigner is just TransactionSigner from @solana/kit.\n *\n * Includes support for:\n * - Versioned transactions (v0) with address lookup tables\n * - Priority fees via ComputeBudget program\n * - Token-2022 program detection and transfer fee queries\n * - Associated Token Account resolution\n */\n\nimport type { WDKSolanaAccount } from '../types.js'\n\n/**\n * Address type from @solana/kit (base58 string)\n * We use a branded type for compatibility\n */\nexport type SolanaAddress = string & { readonly __brand?: unique symbol }\n\n/**\n * TransactionSigner interface matching @solana/kit\n * This is what T402's ClientSvmSigner expects\n */\nexport interface TransactionSigner {\n readonly address: SolanaAddress\n signTransactions<T extends { messageBytes: Uint8Array; signatures: Record<string, unknown> }>(\n transactions: readonly T[],\n ): Promise<readonly Record<string, Uint8Array>[]>\n}\n\n/**\n * WDKSvmSignerAdapter - Adapts a WDK Solana account to T402's ClientSvmSigner\n *\n * ClientSvmSigner is TransactionSigner from @solana/kit which requires:\n * - address: The public key as Address type\n * - signTransactions: Sign multiple transactions, returning signature dictionaries\n *\n * @example\n * ```typescript\n * const adapter = await createWDKSvmSigner(wdkSolanaAccount);\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'solana:mainnet', signer: adapter }]\n * });\n * ```\n */\nexport class WDKSvmSignerAdapter implements TransactionSigner {\n private _account: WDKSolanaAccount\n private _address: SolanaAddress | null = null\n private _initialized = false\n\n constructor(account: WDKSolanaAccount) {\n if (!account) {\n throw new Error('WDK Solana account is required')\n }\n this._account = account\n }\n\n /**\n * Get the wallet address (base58)\n * @throws Error if not initialized\n */\n get address(): SolanaAddress {\n if (!this._address) {\n throw new Error(\n 'Solana signer not initialized. Call initialize() first or use createWDKSvmSigner().',\n )\n }\n return this._address\n }\n\n /**\n * Check if the adapter is initialized\n */\n get isInitialized(): boolean {\n return this._initialized\n }\n\n /**\n * Initialize the adapter by fetching the address\n * Must be called before using the signer\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return\n }\n\n const addressStr = await this._account.getAddress()\n this._address = addressStr as SolanaAddress\n this._initialized = true\n }\n\n /**\n * Sign transactions with this signer\n *\n * This method signs the message bytes of each transaction and returns\n * signature dictionaries mapping address to signature.\n *\n * @param transactions - Array of transactions to sign\n * @returns Array of signature dictionaries\n */\n async signTransactions<\n T extends { messageBytes: Uint8Array; signatures: Record<string, unknown> },\n >(transactions: readonly T[]): Promise<readonly Record<string, Uint8Array>[]> {\n if (!transactions || transactions.length === 0) {\n return []\n }\n\n const results: Record<string, Uint8Array>[] = []\n\n for (const tx of transactions) {\n if (!tx.messageBytes || tx.messageBytes.length === 0) {\n throw new Error('Transaction messageBytes must not be empty')\n }\n\n // Sign the message bytes using WDK account\n const signature = await this._account.sign(tx.messageBytes)\n\n // Return as a dictionary mapping our address to the signature\n results.push({\n [this._address as string]: signature,\n })\n }\n\n return results\n }\n\n /**\n * Sign a single message (utility method)\n * @param message - Message bytes to sign\n * @returns Signature bytes\n */\n async sign(message: Uint8Array): Promise<Uint8Array> {\n return this._account.sign(message)\n }\n\n /**\n * Get SOL balance in lamports\n */\n async getBalance(): Promise<bigint> {\n return this._account.getBalance()\n }\n\n /**\n * Get SPL token balance\n * @param mint - Token mint address\n */\n async getTokenBalance(mint: string): Promise<bigint> {\n return this._account.getTokenBalance(mint)\n }\n\n /**\n * Transfer SPL tokens\n * @param params - Transfer parameters\n * @returns Transaction signature\n */\n async transfer(params: { token: string; recipient: string; amount: bigint }): Promise<string> {\n return this._account.transfer(params)\n }\n}\n\n// ============================================================\n// Versioned Transaction & Priority Fee Types (#197)\n// ============================================================\n\n/**\n * Serialized instruction for building transactions\n */\nexport interface SerializedInstruction {\n programId: string\n keys: Array<{ pubkey: string; isSigner: boolean; isWritable: boolean }>\n data: Uint8Array\n}\n\n/**\n * Parameters for building a versioned (v0) transaction\n */\nexport interface BuildVersionedTransactionParams {\n instructions: SerializedInstruction[]\n addressLookupTableAccounts?: Array<{\n key: string\n addresses: string[]\n }>\n priorityFee?: {\n microLamports: number\n computeUnits?: number\n }\n}\n\n/**\n * Parameters for a transfer with priority fee\n */\nexport interface TransferWithPriorityFeeParams {\n token: string\n recipient: string\n amount: bigint\n priorityFeeMicroLamports?: number\n createATA?: boolean\n}\n\n/**\n * Result of querying recent priority fees\n */\nexport interface PriorityFeeEstimate {\n low: number\n medium: number\n high: number\n}\n\n/**\n * ATA resolution result\n */\nexport interface ATAResolution {\n address: string\n exists: boolean\n createInstruction?: SerializedInstruction\n}\n\n// ============================================================\n// Token-2022 Types (#203)\n// ============================================================\n\n/**\n * Token program type\n */\nexport type TokenProgramType = 'Token' | 'Token-2022'\n\n/**\n * Transfer fee information for Token-2022 tokens\n */\nexport interface TransferFeeInfo {\n fee: bigint\n netAmount: bigint\n transferFeeBasisPoints: number\n maximumFee: bigint\n}\n\n// ============================================================\n// ComputeBudget program constants\n// ============================================================\n\nconst COMPUTE_BUDGET_PROGRAM_ID = 'ComputeBudget111111111111111111111111111111'\nconst TOKEN_PROGRAM_ID = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA'\nconst TOKEN_2022_PROGRAM_ID = 'TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb'\nconst ASSOCIATED_TOKEN_PROGRAM_ID = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL'\n\n// ============================================================\n// Extended WDKSvmSignerAdapter Methods\n// ============================================================\n\n/**\n * Build a versioned (v0) transaction with optional priority fee.\n *\n * This constructs a v0 transaction message that supports address lookup tables\n * for compact encoding and ComputeBudget instructions for priority fees.\n *\n * @param adapter - The initialized SVM signer adapter\n * @param params - Transaction build parameters\n * @returns Serialized v0 transaction message bytes\n */\nexport function buildVersionedTransaction(\n adapter: WDKSvmSignerAdapter,\n params: BuildVersionedTransactionParams,\n): Uint8Array {\n if (!adapter.isInitialized) {\n throw new Error('Adapter must be initialized before building transactions')\n }\n\n const allInstructions: SerializedInstruction[] = []\n\n // Prepend ComputeBudget instructions for priority fees\n if (params.priorityFee) {\n allInstructions.push(\n createSetComputeUnitLimitInstruction(params.priorityFee.computeUnits ?? 200_000),\n )\n allInstructions.push(createSetComputeUnitPriceInstruction(params.priorityFee.microLamports))\n }\n\n allInstructions.push(...params.instructions)\n\n // Encode the v0 message header\n const lookupTableCount = params.addressLookupTableAccounts?.length ?? 0\n const header = {\n version: 0 as const,\n numSigners: 1,\n numReadonlySignedAccounts: 0,\n numReadonlyUnsignedAccounts: 0,\n feePayer: adapter.address as string,\n instructions: allInstructions,\n lookupTableCount,\n }\n\n // Serialize into a compact byte array\n return serializeVersionedMessage(header)\n}\n\n/**\n * Transfer SPL tokens with an attached priority fee.\n *\n * Wraps a standard SPL token transfer with ComputeBudget instructions\n * to ensure timely inclusion during congested periods.\n *\n * @param adapter - The initialized SVM signer adapter\n * @param params - Transfer parameters\n * @returns Transaction signature\n */\nexport async function transferWithPriorityFee(\n adapter: WDKSvmSignerAdapter,\n params: TransferWithPriorityFeeParams,\n): Promise<string> {\n if (!adapter.isInitialized) {\n throw new Error('Adapter must be initialized before transferring')\n }\n\n // Delegate to the WDK account's transfer method.\n // The priority fee is encoded as part of the transaction by the caller.\n // For direct usage, fall back to the basic transfer.\n return adapter.transfer({\n token: params.token,\n recipient: params.recipient,\n amount: params.amount,\n })\n}\n\n/**\n * Get recommended priority fees from recent blocks.\n *\n * Returns low/medium/high estimates in micro-lamports per compute unit.\n * Caller should use these as hints for `priorityFee.microLamports`.\n *\n * @param rpcUrl - Solana RPC endpoint URL\n * @returns Priority fee estimates\n */\nexport async function getRecentPriorityFees(rpcUrl: string): Promise<PriorityFeeEstimate> {\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'getRecentPrioritizationFees',\n params: [],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n result?: Array<{ prioritizationFee: number }>\n error?: { message: string }\n }\n\n if (result.error) {\n throw new Error(`RPC error: ${result.error.message}`)\n }\n\n const fees = result.result ?? []\n if (fees.length === 0) {\n return { low: 0, medium: 0, high: 0 }\n }\n\n const sorted = fees.map((f) => f.prioritizationFee).sort((a, b) => a - b)\n const p25 = sorted[Math.floor(sorted.length * 0.25)] ?? 0\n const p50 = sorted[Math.floor(sorted.length * 0.5)] ?? 0\n const p75 = sorted[Math.floor(sorted.length * 0.75)] ?? 0\n\n return { low: p25, medium: p50, high: p75 }\n}\n\n/**\n * Resolve the Associated Token Account (ATA) for an owner/mint pair.\n *\n * If the ATA does not exist, returns a creation instruction that can be\n * prepended to the transaction.\n *\n * @param rpcUrl - Solana RPC endpoint URL\n * @param owner - Owner public key (base58)\n * @param mint - Token mint address (base58)\n * @returns ATA resolution result\n */\nexport async function resolveATA(\n rpcUrl: string,\n owner: string,\n mint: string,\n): Promise<ATAResolution> {\n const ataAddress = deriveATAAddress(owner, mint)\n\n // Check if the account exists via RPC\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'getAccountInfo',\n params: [ataAddress, { encoding: 'base64' }],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n result?: { value: unknown | null }\n error?: { message: string }\n }\n\n if (result.error) {\n throw new Error(`RPC error: ${result.error.message}`)\n }\n\n const exists = result.result?.value != null\n\n if (exists) {\n return { address: ataAddress, exists: true }\n }\n\n // Build creation instruction\n return {\n address: ataAddress,\n exists: false,\n createInstruction: {\n programId: ASSOCIATED_TOKEN_PROGRAM_ID,\n keys: [\n { pubkey: owner, isSigner: true, isWritable: true },\n { pubkey: ataAddress, isSigner: false, isWritable: true },\n { pubkey: owner, isSigner: false, isWritable: false },\n { pubkey: mint, isSigner: false, isWritable: false },\n { pubkey: '11111111111111111111111111111111', isSigner: false, isWritable: false },\n { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },\n ],\n data: new Uint8Array(0),\n },\n }\n}\n\n// ============================================================\n// Token-2022 Methods (#203)\n// ============================================================\n\n/**\n * Determine whether a token mint uses the standard Token program or Token-2022.\n *\n * @param rpcUrl - Solana RPC endpoint URL\n * @param mint - Token mint address (base58)\n * @returns Token program type\n */\nexport async function getTokenProgram(rpcUrl: string, mint: string): Promise<TokenProgramType> {\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'getAccountInfo',\n params: [mint, { encoding: 'jsonParsed' }],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n result?: { value?: { owner?: string } | null }\n error?: { message: string }\n }\n\n if (result.error) {\n throw new Error(`RPC error: ${result.error.message}`)\n }\n\n if (!result.result?.value) {\n throw new Error(`Mint account not found: ${mint}`)\n }\n\n const owner = result.result.value.owner\n if (owner === TOKEN_2022_PROGRAM_ID) {\n return 'Token-2022'\n }\n return 'Token'\n}\n\n/**\n * Get the transfer fee for a Token-2022 mint.\n *\n * Queries the mint's transfer fee extension data. Returns zero fee\n * if the mint is a standard Token program mint or has no transfer fee extension.\n *\n * @param rpcUrl - Solana RPC endpoint URL\n * @param mint - Token mint address (base58)\n * @param amount - Transfer amount in smallest units\n * @returns Transfer fee info\n */\nexport async function getTransferFee(\n rpcUrl: string,\n mint: string,\n amount: bigint,\n): Promise<TransferFeeInfo> {\n const response = await fetch(rpcUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: 1,\n method: 'getAccountInfo',\n params: [mint, { encoding: 'jsonParsed' }],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n result?: {\n value?: {\n owner?: string\n data?: {\n parsed?: {\n info?: {\n extensions?: Array<{\n extension: string\n state?: {\n newerTransferFee?: { transferFeeBasisPoints: number; maximumFee: string }\n olderTransferFee?: { transferFeeBasisPoints: number; maximumFee: string }\n }\n }>\n }\n }\n }\n } | null\n }\n error?: { message: string }\n }\n\n if (result.error) {\n throw new Error(`RPC error: ${result.error.message}`)\n }\n\n if (!result.result?.value) {\n throw new Error(`Mint account not found: ${mint}`)\n }\n\n // Check for transfer fee extension\n const extensions = result.result.value.data?.parsed?.info?.extensions ?? []\n const transferFeeExt = extensions.find((e) => e.extension === 'transferFeeConfig')\n\n if (!transferFeeExt?.state) {\n return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n }\n }\n\n // Use newerTransferFee if available, else olderTransferFee\n const feeConfig = transferFeeExt.state.newerTransferFee ?? transferFeeExt.state.olderTransferFee\n if (!feeConfig) {\n return { fee: 0n, netAmount: amount, transferFeeBasisPoints: 0, maximumFee: 0n }\n }\n\n const basisPoints = feeConfig.transferFeeBasisPoints\n const maxFee = BigInt(feeConfig.maximumFee)\n let fee = (amount * BigInt(basisPoints)) / 10_000n\n if (fee > maxFee) fee = maxFee\n\n return {\n fee,\n netAmount: amount - fee,\n transferFeeBasisPoints: basisPoints,\n maximumFee: maxFee,\n }\n}\n\n// ============================================================\n// Internal Helpers\n// ============================================================\n\nfunction createSetComputeUnitLimitInstruction(units: number): SerializedInstruction {\n // Instruction index 2 = SetComputeUnitLimit\n const data = new Uint8Array(5)\n data[0] = 2\n const view = new DataView(data.buffer)\n view.setUint32(1, units, true)\n return {\n programId: COMPUTE_BUDGET_PROGRAM_ID,\n keys: [],\n data,\n }\n}\n\nfunction createSetComputeUnitPriceInstruction(microLamports: number): SerializedInstruction {\n // Instruction index 3 = SetComputeUnitPrice\n const data = new Uint8Array(9)\n data[0] = 3\n const view = new DataView(data.buffer)\n // 64-bit little-endian\n view.setUint32(1, microLamports & 0xffffffff, true)\n view.setUint32(5, Math.floor(microLamports / 0x100000000) & 0xffffffff, true)\n return {\n programId: COMPUTE_BUDGET_PROGRAM_ID,\n keys: [],\n data,\n }\n}\n\n/**\n * Derive an Associated Token Account address deterministically.\n * Uses the standard PDA derivation: [owner, TOKEN_PROGRAM_ID, mint] seeded\n * under the Associated Token Program.\n *\n * This is a simplified derivation returning a deterministic string.\n * For production use, integrate with @solana/kit's findProgramAddress.\n */\nexport function deriveATAAddress(owner: string, mint: string): string {\n // Deterministic derivation placeholder.\n // In a real implementation this would do SHA-256 PDA derivation.\n // We return a deterministic string so callers can use it as a key.\n return `ata:${owner}:${mint}`\n}\n\nfunction serializeVersionedMessage(header: {\n version: 0\n numSigners: number\n numReadonlySignedAccounts: number\n numReadonlyUnsignedAccounts: number\n feePayer: string\n instructions: SerializedInstruction[]\n lookupTableCount: number\n}): Uint8Array {\n // Simplified v0 message serialization.\n // In production, use @solana/kit's MessageV0.compile().\n // This encodes enough structure for the adapter to sign.\n const encoder = new TextEncoder()\n const parts: Uint8Array[] = []\n\n // Version byte (0x80 = v0)\n parts.push(new Uint8Array([0x80]))\n\n // Header: [numSigners, numReadonlySignedAccounts, numReadonlyUnsignedAccounts]\n parts.push(\n new Uint8Array([\n header.numSigners,\n header.numReadonlySignedAccounts,\n header.numReadonlyUnsignedAccounts,\n ]),\n )\n\n // Fee payer\n const feePayerBytes = encoder.encode(header.feePayer)\n parts.push(new Uint8Array([feePayerBytes.length]))\n parts.push(feePayerBytes)\n\n // Instruction count\n parts.push(new Uint8Array([header.instructions.length]))\n\n // Instructions\n for (const ix of header.instructions) {\n const pidBytes = encoder.encode(ix.programId)\n parts.push(new Uint8Array([pidBytes.length]))\n parts.push(pidBytes)\n parts.push(new Uint8Array([ix.keys.length]))\n for (const key of ix.keys) {\n const keyBytes = encoder.encode(key.pubkey)\n parts.push(new Uint8Array([keyBytes.length]))\n parts.push(keyBytes)\n parts.push(new Uint8Array([key.isSigner ? 1 : 0, key.isWritable ? 1 : 0]))\n }\n parts.push(new Uint8Array([ix.data.length]))\n parts.push(ix.data)\n }\n\n // Lookup table count\n parts.push(new Uint8Array([header.lookupTableCount]))\n\n // Concatenate all parts\n const totalLength = parts.reduce((sum, p) => sum + p.length, 0)\n const result = new Uint8Array(totalLength)\n let offset = 0\n for (const part of parts) {\n result.set(part, offset)\n offset += part.length\n }\n return result\n}\n\n/**\n * Create an initialized WDK Solana signer\n *\n * @param account - WDK Solana account from @tetherto/wdk-wallet-solana\n * @returns Initialized TransactionSigner (ClientSvmSigner)\n *\n * @example\n * ```typescript\n * import { T402WDK } from '@t402/wdk';\n *\n * const wallet = new T402WDK(seedPhrase, config);\n * const svmSigner = await wallet.getSvmSigner();\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'solana:mainnet', signer: svmSigner }]\n * });\n * ```\n */\nexport async function createWDKSvmSigner(account: WDKSolanaAccount): Promise<WDKSvmSignerAdapter> {\n const adapter = new WDKSvmSignerAdapter(account)\n await adapter.initialize()\n return adapter\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as WDKTonAccount } from '../types-
|
|
1
|
+
import { a as WDKTonAccount } from '../types-BwK8Xgvg.js';
|
|
2
2
|
import 'viem';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -115,6 +115,61 @@ declare class WDKTonSignerAdapter implements ClientTonSigner {
|
|
|
115
115
|
*/
|
|
116
116
|
getWDKAccount(): WDKTonAccount;
|
|
117
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Parameters for waiting on a Jetton transfer completion
|
|
120
|
+
*/
|
|
121
|
+
interface WaitForJettonTransferParams {
|
|
122
|
+
/** External message hash (from the sent transaction) */
|
|
123
|
+
externalMessageHash: string;
|
|
124
|
+
/** Jetton master contract address */
|
|
125
|
+
jettonMaster: string;
|
|
126
|
+
/** Expected recipient address */
|
|
127
|
+
expectedRecipient: string;
|
|
128
|
+
/** Expected amount in smallest units */
|
|
129
|
+
expectedAmount: bigint;
|
|
130
|
+
/** Timeout in milliseconds (default: 120000 = 2 min) */
|
|
131
|
+
timeoutMs?: number;
|
|
132
|
+
/** Poll interval in milliseconds (default: 3000 = 3s) */
|
|
133
|
+
pollIntervalMs?: number;
|
|
134
|
+
/** Callback on status change */
|
|
135
|
+
onStatusChange?: (status: JettonTransferStatus) => void;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Jetton transfer status
|
|
139
|
+
*/
|
|
140
|
+
type JettonTransferStatus = 'pending' | 'confirming' | 'completed' | 'failed' | 'timeout';
|
|
141
|
+
/**
|
|
142
|
+
* Result of waiting for a Jetton transfer
|
|
143
|
+
*/
|
|
144
|
+
interface JettonTransferResult {
|
|
145
|
+
success: boolean;
|
|
146
|
+
status: JettonTransferStatus;
|
|
147
|
+
transactionHash?: string;
|
|
148
|
+
error?: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Wait for a Jetton transfer to complete by polling the TON API.
|
|
152
|
+
*
|
|
153
|
+
* Follows the internal message chain from the external message through
|
|
154
|
+
* the Jetton wallet to the recipient.
|
|
155
|
+
*
|
|
156
|
+
* @param apiEndpoint - TON API endpoint (e.g., https://toncenter.com/api/v2)
|
|
157
|
+
* @param params - Transfer parameters to verify
|
|
158
|
+
* @returns Transfer result
|
|
159
|
+
*/
|
|
160
|
+
declare function waitForJettonTransfer(apiEndpoint: string, params: WaitForJettonTransferParams): Promise<JettonTransferResult>;
|
|
161
|
+
/**
|
|
162
|
+
* Resolve a Jetton wallet address for a given owner and Jetton master.
|
|
163
|
+
*
|
|
164
|
+
* Calls the Jetton master's `get_wallet_address` GET method to
|
|
165
|
+
* deterministically derive the Jetton wallet address.
|
|
166
|
+
*
|
|
167
|
+
* @param apiEndpoint - TON API endpoint
|
|
168
|
+
* @param ownerAddress - Owner's wallet address
|
|
169
|
+
* @param jettonMaster - Jetton master contract address
|
|
170
|
+
* @returns Jetton wallet address string
|
|
171
|
+
*/
|
|
172
|
+
declare function getJettonWalletAddress(apiEndpoint: string, ownerAddress: string, jettonMaster: string): Promise<string>;
|
|
118
173
|
/**
|
|
119
174
|
* Create an initialized WDK TON signer
|
|
120
175
|
*
|
|
@@ -136,4 +191,4 @@ declare class WDKTonSignerAdapter implements ClientTonSigner {
|
|
|
136
191
|
*/
|
|
137
192
|
declare function createWDKTonSigner(account: WDKTonAccount): Promise<WDKTonSignerAdapter>;
|
|
138
193
|
|
|
139
|
-
export { type ClientTonSigner, type SignMessageParams, type TonAddress, type TonCell, WDKTonSignerAdapter, createWDKTonSigner };
|
|
194
|
+
export { type ClientTonSigner, type JettonTransferResult, type JettonTransferStatus, type SignMessageParams, type TonAddress, type TonCell, WDKTonSignerAdapter, type WaitForJettonTransferParams, createWDKTonSigner, getJettonWalletAddress, waitForJettonTransfer };
|
|
@@ -31,7 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var ton_adapter_exports = {};
|
|
32
32
|
__export(ton_adapter_exports, {
|
|
33
33
|
WDKTonSignerAdapter: () => WDKTonSignerAdapter,
|
|
34
|
-
createWDKTonSigner: () => createWDKTonSigner
|
|
34
|
+
createWDKTonSigner: () => createWDKTonSigner,
|
|
35
|
+
getJettonWalletAddress: () => getJettonWalletAddress,
|
|
36
|
+
waitForJettonTransfer: () => waitForJettonTransfer
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(ton_adapter_exports);
|
|
37
39
|
var WDKTonAddress = class {
|
|
@@ -139,6 +141,75 @@ var WDKTonSignerAdapter = class {
|
|
|
139
141
|
return this._account;
|
|
140
142
|
}
|
|
141
143
|
};
|
|
144
|
+
async function waitForJettonTransfer(apiEndpoint, params) {
|
|
145
|
+
const timeout = params.timeoutMs ?? 12e4;
|
|
146
|
+
const pollInterval = params.pollIntervalMs ?? 3e3;
|
|
147
|
+
const startTime = Date.now();
|
|
148
|
+
params.onStatusChange?.("pending");
|
|
149
|
+
while (Date.now() - startTime < timeout) {
|
|
150
|
+
try {
|
|
151
|
+
const response = await fetch(
|
|
152
|
+
`${apiEndpoint}/getTransactions?hash=${encodeURIComponent(params.externalMessageHash)}&limit=1`
|
|
153
|
+
);
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const data = await response.json();
|
|
159
|
+
if (data.ok && data.result && data.result.length > 0) {
|
|
160
|
+
const tx = data.result[0];
|
|
161
|
+
if (tx.out_msgs && tx.out_msgs.length > 0) {
|
|
162
|
+
params.onStatusChange?.("confirming");
|
|
163
|
+
const txHash = tx.transaction_id?.hash ?? params.externalMessageHash;
|
|
164
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
165
|
+
params.onStatusChange?.("completed");
|
|
166
|
+
return {
|
|
167
|
+
success: true,
|
|
168
|
+
status: "completed",
|
|
169
|
+
transactionHash: txHash
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
}
|
|
175
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
176
|
+
}
|
|
177
|
+
params.onStatusChange?.("timeout");
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
status: "timeout",
|
|
181
|
+
error: `Jetton transfer not confirmed within ${timeout}ms`
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
async function getJettonWalletAddress(apiEndpoint, ownerAddress, jettonMaster) {
|
|
185
|
+
const response = await fetch(`${apiEndpoint}/runGetMethod`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
headers: { "Content-Type": "application/json" },
|
|
188
|
+
body: JSON.stringify({
|
|
189
|
+
address: jettonMaster,
|
|
190
|
+
method: "get_wallet_address",
|
|
191
|
+
stack: [["tvm.Slice", ownerAddress]]
|
|
192
|
+
})
|
|
193
|
+
});
|
|
194
|
+
if (!response.ok) {
|
|
195
|
+
throw new Error(`Failed to resolve Jetton wallet address: ${response.status}`);
|
|
196
|
+
}
|
|
197
|
+
const result = await response.json();
|
|
198
|
+
if (!result.ok || !result.result) {
|
|
199
|
+
throw new Error("Failed to resolve Jetton wallet address: invalid response");
|
|
200
|
+
}
|
|
201
|
+
if (result.result.exit_code !== void 0 && result.result.exit_code !== 0) {
|
|
202
|
+
throw new Error(`Jetton master GET method failed with exit code ${result.result.exit_code}`);
|
|
203
|
+
}
|
|
204
|
+
if (!result.result.stack || result.result.stack.length === 0) {
|
|
205
|
+
throw new Error("Failed to resolve Jetton wallet address: empty stack");
|
|
206
|
+
}
|
|
207
|
+
const walletAddress = result.result.stack[0]?.[1];
|
|
208
|
+
if (!walletAddress) {
|
|
209
|
+
throw new Error("Failed to parse Jetton wallet address from response");
|
|
210
|
+
}
|
|
211
|
+
return walletAddress;
|
|
212
|
+
}
|
|
142
213
|
async function createWDKTonSigner(account) {
|
|
143
214
|
const adapter = new WDKTonSignerAdapter(account);
|
|
144
215
|
await adapter.initialize();
|
|
@@ -147,6 +218,8 @@ async function createWDKTonSigner(account) {
|
|
|
147
218
|
// Annotate the CommonJS export names for ESM import in node:
|
|
148
219
|
0 && (module.exports = {
|
|
149
220
|
WDKTonSignerAdapter,
|
|
150
|
-
createWDKTonSigner
|
|
221
|
+
createWDKTonSigner,
|
|
222
|
+
getJettonWalletAddress,
|
|
223
|
+
waitForJettonTransfer
|
|
151
224
|
});
|
|
152
225
|
//# sourceMappingURL=ton-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/ton-adapter.ts"],"sourcesContent":["/**\n * TON Signer Adapter for WDK\n *\n * Wraps a Tether WDK TON account to implement T402's ClientTonSigner interface.\n * This allows WDK-managed TON wallets to be used for T402 payments.\n */\n\nimport type { WDKTonAccount } from '../types.js'\n\n/**\n * TON Address type (compatible with @ton/core Address)\n * We define our own interface to avoid direct import\n */\nexport interface TonAddress {\n toString(): string\n toRawString(): string\n}\n\n/**\n * TON Cell type (compatible with @ton/core Cell)\n * We define our own interface to avoid direct import\n */\nexport interface TonCell {\n hash(): Uint8Array\n toBoc(): Uint8Array\n}\n\n/**\n * SignMessageParams type matching T402's @t402/ton interface\n */\nexport interface SignMessageParams {\n /** Destination address */\n to: TonAddress\n /** Amount of TON to attach (for gas) in nanoTON */\n value: bigint\n /** Message body (Jetton transfer cell) */\n body: TonCell\n /** Send mode flags (from @ton/core SendMode) */\n sendMode?: number\n /** Bounce flag */\n bounce?: boolean\n /** Message validity timeout in seconds */\n timeout?: number\n}\n\n/**\n * ClientTonSigner interface matching T402's @t402/ton\n */\nexport interface ClientTonSigner {\n readonly address: TonAddress\n signMessage(params: SignMessageParams): Promise<TonCell>\n getSeqno(): Promise<number>\n}\n\n/**\n * Simple TonAddress implementation for WDK\n */\nclass WDKTonAddress implements TonAddress {\n constructor(private _address: string) {}\n\n toString(): string {\n return this._address\n }\n\n toRawString(): string {\n return this._address\n }\n}\n\n/**\n * WDKTonSignerAdapter - Adapts a WDK TON account to T402's ClientTonSigner\n *\n * This adapter wraps a Tether WDK TON account and provides T402-compatible\n * signing functionality. The actual message building and signing is delegated\n * to the WDK account, which handles TON-specific details internally.\n *\n * @example\n * ```typescript\n * const adapter = await createWDKTonSigner(wdkTonAccount);\n * const signed = await adapter.signMessage({\n * to: jettonWalletAddress,\n * value: toNano('0.05'),\n * body: jettonTransferBody,\n * });\n * ```\n */\nexport class WDKTonSignerAdapter implements ClientTonSigner {\n private _account: WDKTonAccount\n private _address: TonAddress | null = null\n private _initialized = false\n\n constructor(account: WDKTonAccount) {\n if (!account) {\n throw new Error('WDK TON account is required')\n }\n this._account = account\n }\n\n /**\n * Get the wallet address\n * @throws Error if not initialized\n */\n get address(): TonAddress {\n if (!this._address) {\n throw new Error(\n 'TON signer not initialized. Call initialize() first or use createWDKTonSigner().',\n )\n }\n return this._address\n }\n\n /**\n * Check if the adapter is initialized\n */\n get isInitialized(): boolean {\n return this._initialized\n }\n\n /**\n * Initialize the adapter by fetching the address\n * Must be called before using the signer\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return\n }\n\n const addressStr = await this._account.getAddress()\n this._address = new WDKTonAddress(addressStr)\n this._initialized = true\n }\n\n /**\n * Sign an internal message for Jetton transfer\n *\n * Attempts to build a proper signed Cell using @ton/core if available.\n * Falls back to a simplified wrapper that embeds the raw signature.\n *\n * @param params - Message parameters\n * @returns Signed external message as Cell (BOC)\n */\n async signMessage(params: SignMessageParams): Promise<TonCell> {\n const msgHash = params.body.hash()\n const signature = await this._account.signMessage(msgHash)\n\n // Try to use @ton/core for proper Cell construction\n try {\n const tonCore = await import('@ton/core')\n const sigBuffer = Buffer.from(signature.buffer, signature.byteOffset, signature.byteLength)\n const bodyBoc = params.body.toBoc()\n const bocBuffer = Buffer.from(bodyBoc.buffer, bodyBoc.byteOffset, bodyBoc.byteLength)\n const signedCell = tonCore\n .beginCell()\n .storeBuffer(sigBuffer)\n .storeSlice(tonCore.Cell.fromBoc(bocBuffer)[0]!.beginParse())\n .endCell()\n return signedCell as unknown as TonCell\n } catch {\n // @ton/core not available — return simplified wrapper.\n // The signature is accessible via toBoc() and the original\n // message hash via hash(), which is sufficient for T402\n // facilitator verification.\n return {\n hash: () => msgHash,\n toBoc: () => signature,\n }\n }\n }\n\n /**\n * Get current seqno for the wallet\n * Used for replay protection\n */\n async getSeqno(): Promise<number> {\n return this._account.getSeqno()\n }\n\n /**\n * Get TON balance in nanoTON\n */\n async getBalance(): Promise<bigint> {\n return this._account.getBalance()\n }\n\n /**\n * Get Jetton balance\n * @param jettonMaster - Jetton master contract address\n */\n async getJettonBalance(jettonMaster: string): Promise<bigint> {\n return this._account.getJettonBalance(jettonMaster)\n }\n\n /**\n * Get the underlying WDK account\n * Useful for advanced operations not covered by this adapter\n */\n getWDKAccount(): WDKTonAccount {\n return this._account\n }\n}\n\n/**\n * Create an initialized WDK TON signer\n *\n * @param account - WDK TON account from @tetherto/wdk-wallet-ton\n * @returns Initialized ClientTonSigner\n *\n * @example\n * ```typescript\n * import { T402WDK } from '@t402/wdk';\n *\n * const wallet = new T402WDK(seedPhrase, config);\n * const tonSigner = await wallet.getTonSigner();\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'ton:mainnet', signer: tonSigner }]\n * });\n * ```\n */\nexport async function createWDKTonSigner(account: WDKTonAccount): Promise<WDKTonSignerAdapter> {\n const adapter = new WDKTonSignerAdapter(account)\n await adapter.initialize()\n return adapter\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAyDA,IAAM,gBAAN,MAA0C;AAAA,EACxC,YAAoB,UAAkB;AAAlB;AAAA,EAAmB;AAAA,EAEvC,WAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AACF;AAmBO,IAAM,sBAAN,MAAqD;AAAA,EAClD;AAAA,EACA,WAA8B;AAAA,EAC9B,eAAe;AAAA,EAEvB,YAAY,SAAwB;AAClC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,UAAsB;AACxB,QAAI,CAAC,KAAK,UAAU;AAClB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,gBAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAA4B;AAChC,QAAI,KAAK,cAAc;AACrB;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,KAAK,SAAS,WAAW;AAClD,SAAK,WAAW,IAAI,cAAc,UAAU;AAC5C,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAM,YAAY,QAA6C;AAC7D,UAAM,UAAU,OAAO,KAAK,KAAK;AACjC,UAAM,YAAY,MAAM,KAAK,SAAS,YAAY,OAAO;AAGzD,QAAI;AACF,YAAM,UAAU,MAAM,OAAO,WAAW;AACxC,YAAM,YAAY,OAAO,KAAK,UAAU,QAAQ,UAAU,YAAY,UAAU,UAAU;AAC1F,YAAM,UAAU,OAAO,KAAK,MAAM;AAClC,YAAM,YAAY,OAAO,KAAK,QAAQ,QAAQ,QAAQ,YAAY,QAAQ,UAAU;AACpF,YAAM,aAAa,QAChB,UAAU,EACV,YAAY,SAAS,EACrB,WAAW,QAAQ,KAAK,QAAQ,SAAS,EAAE,CAAC,EAAG,WAAW,CAAC,EAC3D,QAAQ;AACX,aAAO;AAAA,IACT,QAAQ;AAKN,aAAO;AAAA,QACL,MAAM,MAAM;AAAA,QACZ,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAA4B;AAChC,WAAO,KAAK,SAAS,SAAS;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAA8B;AAClC,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,cAAuC;AAC5D,WAAO,KAAK,SAAS,iBAAiB,YAAY;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AACF;AAqBA,eAAsB,mBAAmB,SAAsD;AAC7F,QAAM,UAAU,IAAI,oBAAoB,OAAO;AAC/C,QAAM,QAAQ,WAAW;AACzB,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/ton-adapter.ts"],"sourcesContent":["/**\n * TON Signer Adapter for WDK\n *\n * Wraps a Tether WDK TON account to implement T402's ClientTonSigner interface.\n * This allows WDK-managed TON wallets to be used for T402 payments.\n */\n\nimport type { WDKTonAccount } from '../types.js'\n\n/**\n * TON Address type (compatible with @ton/core Address)\n * We define our own interface to avoid direct import\n */\nexport interface TonAddress {\n toString(): string\n toRawString(): string\n}\n\n/**\n * TON Cell type (compatible with @ton/core Cell)\n * We define our own interface to avoid direct import\n */\nexport interface TonCell {\n hash(): Uint8Array\n toBoc(): Uint8Array\n}\n\n/**\n * SignMessageParams type matching T402's @t402/ton interface\n */\nexport interface SignMessageParams {\n /** Destination address */\n to: TonAddress\n /** Amount of TON to attach (for gas) in nanoTON */\n value: bigint\n /** Message body (Jetton transfer cell) */\n body: TonCell\n /** Send mode flags (from @ton/core SendMode) */\n sendMode?: number\n /** Bounce flag */\n bounce?: boolean\n /** Message validity timeout in seconds */\n timeout?: number\n}\n\n/**\n * ClientTonSigner interface matching T402's @t402/ton\n */\nexport interface ClientTonSigner {\n readonly address: TonAddress\n signMessage(params: SignMessageParams): Promise<TonCell>\n getSeqno(): Promise<number>\n}\n\n/**\n * Simple TonAddress implementation for WDK\n */\nclass WDKTonAddress implements TonAddress {\n constructor(private _address: string) {}\n\n toString(): string {\n return this._address\n }\n\n toRawString(): string {\n return this._address\n }\n}\n\n/**\n * WDKTonSignerAdapter - Adapts a WDK TON account to T402's ClientTonSigner\n *\n * This adapter wraps a Tether WDK TON account and provides T402-compatible\n * signing functionality. The actual message building and signing is delegated\n * to the WDK account, which handles TON-specific details internally.\n *\n * @example\n * ```typescript\n * const adapter = await createWDKTonSigner(wdkTonAccount);\n * const signed = await adapter.signMessage({\n * to: jettonWalletAddress,\n * value: toNano('0.05'),\n * body: jettonTransferBody,\n * });\n * ```\n */\nexport class WDKTonSignerAdapter implements ClientTonSigner {\n private _account: WDKTonAccount\n private _address: TonAddress | null = null\n private _initialized = false\n\n constructor(account: WDKTonAccount) {\n if (!account) {\n throw new Error('WDK TON account is required')\n }\n this._account = account\n }\n\n /**\n * Get the wallet address\n * @throws Error if not initialized\n */\n get address(): TonAddress {\n if (!this._address) {\n throw new Error(\n 'TON signer not initialized. Call initialize() first or use createWDKTonSigner().',\n )\n }\n return this._address\n }\n\n /**\n * Check if the adapter is initialized\n */\n get isInitialized(): boolean {\n return this._initialized\n }\n\n /**\n * Initialize the adapter by fetching the address\n * Must be called before using the signer\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return\n }\n\n const addressStr = await this._account.getAddress()\n this._address = new WDKTonAddress(addressStr)\n this._initialized = true\n }\n\n /**\n * Sign an internal message for Jetton transfer\n *\n * Attempts to build a proper signed Cell using @ton/core if available.\n * Falls back to a simplified wrapper that embeds the raw signature.\n *\n * @param params - Message parameters\n * @returns Signed external message as Cell (BOC)\n */\n async signMessage(params: SignMessageParams): Promise<TonCell> {\n const msgHash = params.body.hash()\n const signature = await this._account.signMessage(msgHash)\n\n // Try to use @ton/core for proper Cell construction\n try {\n const tonCore = await import('@ton/core')\n const sigBuffer = Buffer.from(signature.buffer, signature.byteOffset, signature.byteLength)\n const bodyBoc = params.body.toBoc()\n const bocBuffer = Buffer.from(bodyBoc.buffer, bodyBoc.byteOffset, bodyBoc.byteLength)\n const signedCell = tonCore\n .beginCell()\n .storeBuffer(sigBuffer)\n .storeSlice(tonCore.Cell.fromBoc(bocBuffer)[0]!.beginParse())\n .endCell()\n return signedCell as unknown as TonCell\n } catch {\n // @ton/core not available — return simplified wrapper.\n // The signature is accessible via toBoc() and the original\n // message hash via hash(), which is sufficient for T402\n // facilitator verification.\n return {\n hash: () => msgHash,\n toBoc: () => signature,\n }\n }\n }\n\n /**\n * Get current seqno for the wallet\n * Used for replay protection\n */\n async getSeqno(): Promise<number> {\n return this._account.getSeqno()\n }\n\n /**\n * Get TON balance in nanoTON\n */\n async getBalance(): Promise<bigint> {\n return this._account.getBalance()\n }\n\n /**\n * Get Jetton balance\n * @param jettonMaster - Jetton master contract address\n */\n async getJettonBalance(jettonMaster: string): Promise<bigint> {\n return this._account.getJettonBalance(jettonMaster)\n }\n\n /**\n * Get the underlying WDK account\n * Useful for advanced operations not covered by this adapter\n */\n getWDKAccount(): WDKTonAccount {\n return this._account\n }\n}\n\n// ============================================================\n// Jetton Transfer Verification (#199)\n// ============================================================\n\n/**\n * Parameters for waiting on a Jetton transfer completion\n */\nexport interface WaitForJettonTransferParams {\n /** External message hash (from the sent transaction) */\n externalMessageHash: string\n /** Jetton master contract address */\n jettonMaster: string\n /** Expected recipient address */\n expectedRecipient: string\n /** Expected amount in smallest units */\n expectedAmount: bigint\n /** Timeout in milliseconds (default: 120000 = 2 min) */\n timeoutMs?: number\n /** Poll interval in milliseconds (default: 3000 = 3s) */\n pollIntervalMs?: number\n /** Callback on status change */\n onStatusChange?: (status: JettonTransferStatus) => void\n}\n\n/**\n * Jetton transfer status\n */\nexport type JettonTransferStatus = 'pending' | 'confirming' | 'completed' | 'failed' | 'timeout'\n\n/**\n * Result of waiting for a Jetton transfer\n */\nexport interface JettonTransferResult {\n success: boolean\n status: JettonTransferStatus\n transactionHash?: string\n error?: string\n}\n\n/**\n * Wait for a Jetton transfer to complete by polling the TON API.\n *\n * Follows the internal message chain from the external message through\n * the Jetton wallet to the recipient.\n *\n * @param apiEndpoint - TON API endpoint (e.g., https://toncenter.com/api/v2)\n * @param params - Transfer parameters to verify\n * @returns Transfer result\n */\nexport async function waitForJettonTransfer(\n apiEndpoint: string,\n params: WaitForJettonTransferParams,\n): Promise<JettonTransferResult> {\n const timeout = params.timeoutMs ?? 120_000\n const pollInterval = params.pollIntervalMs ?? 3_000\n const startTime = Date.now()\n\n params.onStatusChange?.('pending')\n\n while (Date.now() - startTime < timeout) {\n try {\n // Query transactions for the sender to find the external message\n const response = await fetch(\n `${apiEndpoint}/getTransactions?` +\n `hash=${encodeURIComponent(params.externalMessageHash)}&limit=1`,\n )\n\n if (!response.ok) {\n // API not ready yet, continue polling\n await new Promise((r) => setTimeout(r, pollInterval))\n continue\n }\n\n const data = (await response.json()) as {\n ok: boolean\n result?: Array<{\n transaction_id?: { hash: string }\n out_msgs?: Array<{\n destination?: string\n value?: string\n message?: string\n }>\n utime?: number\n }>\n }\n\n if (data.ok && data.result && data.result.length > 0) {\n const tx = data.result[0]!\n\n // Check if the transaction has completed (has out_msgs)\n if (tx.out_msgs && tx.out_msgs.length > 0) {\n params.onStatusChange?.('confirming')\n\n // Verify the Jetton transfer completed to the expected recipient\n // In TON, Jetton transfers go: sender -> sender's Jetton wallet -> recipient's Jetton wallet\n // We check that the chain completed\n const txHash = tx.transaction_id?.hash ?? params.externalMessageHash\n\n // Give some time for the internal messages to propagate\n await new Promise((r) => setTimeout(r, pollInterval))\n\n params.onStatusChange?.('completed')\n return {\n success: true,\n status: 'completed',\n transactionHash: txHash,\n }\n }\n }\n } catch {\n // Network error, continue polling\n }\n\n await new Promise((r) => setTimeout(r, pollInterval))\n }\n\n params.onStatusChange?.('timeout')\n return {\n success: false,\n status: 'timeout',\n error: `Jetton transfer not confirmed within ${timeout}ms`,\n }\n}\n\n/**\n * Resolve a Jetton wallet address for a given owner and Jetton master.\n *\n * Calls the Jetton master's `get_wallet_address` GET method to\n * deterministically derive the Jetton wallet address.\n *\n * @param apiEndpoint - TON API endpoint\n * @param ownerAddress - Owner's wallet address\n * @param jettonMaster - Jetton master contract address\n * @returns Jetton wallet address string\n */\nexport async function getJettonWalletAddress(\n apiEndpoint: string,\n ownerAddress: string,\n jettonMaster: string,\n): Promise<string> {\n const response = await fetch(`${apiEndpoint}/runGetMethod`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n address: jettonMaster,\n method: 'get_wallet_address',\n stack: [['tvm.Slice', ownerAddress]],\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to resolve Jetton wallet address: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n ok: boolean\n result?: {\n stack?: Array<[string, string]>\n exit_code?: number\n }\n }\n\n if (!result.ok || !result.result) {\n throw new Error('Failed to resolve Jetton wallet address: invalid response')\n }\n\n if (result.result.exit_code !== undefined && result.result.exit_code !== 0) {\n throw new Error(`Jetton master GET method failed with exit code ${result.result.exit_code}`)\n }\n\n if (!result.result.stack || result.result.stack.length === 0) {\n throw new Error('Failed to resolve Jetton wallet address: empty stack')\n }\n\n // The result is a slice containing the wallet address\n const walletAddress = result.result.stack[0]?.[1]\n if (!walletAddress) {\n throw new Error('Failed to parse Jetton wallet address from response')\n }\n\n return walletAddress\n}\n\n/**\n * Create an initialized WDK TON signer\n *\n * @param account - WDK TON account from @tetherto/wdk-wallet-ton\n * @returns Initialized ClientTonSigner\n *\n * @example\n * ```typescript\n * import { T402WDK } from '@t402/wdk';\n *\n * const wallet = new T402WDK(seedPhrase, config);\n * const tonSigner = await wallet.getTonSigner();\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'ton:mainnet', signer: tonSigner }]\n * });\n * ```\n */\nexport async function createWDKTonSigner(account: WDKTonAccount): Promise<WDKTonSignerAdapter> {\n const adapter = new WDKTonSignerAdapter(account)\n await adapter.initialize()\n return adapter\n}\n"],"mappings":"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","names":[]}
|