@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
|
@@ -104,6 +104,75 @@ var WDKTonSignerAdapter = class {
|
|
|
104
104
|
return this._account;
|
|
105
105
|
}
|
|
106
106
|
};
|
|
107
|
+
async function waitForJettonTransfer(apiEndpoint, params) {
|
|
108
|
+
const timeout = params.timeoutMs ?? 12e4;
|
|
109
|
+
const pollInterval = params.pollIntervalMs ?? 3e3;
|
|
110
|
+
const startTime = Date.now();
|
|
111
|
+
params.onStatusChange?.("pending");
|
|
112
|
+
while (Date.now() - startTime < timeout) {
|
|
113
|
+
try {
|
|
114
|
+
const response = await fetch(
|
|
115
|
+
`${apiEndpoint}/getTransactions?hash=${encodeURIComponent(params.externalMessageHash)}&limit=1`
|
|
116
|
+
);
|
|
117
|
+
if (!response.ok) {
|
|
118
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const data = await response.json();
|
|
122
|
+
if (data.ok && data.result && data.result.length > 0) {
|
|
123
|
+
const tx = data.result[0];
|
|
124
|
+
if (tx.out_msgs && tx.out_msgs.length > 0) {
|
|
125
|
+
params.onStatusChange?.("confirming");
|
|
126
|
+
const txHash = tx.transaction_id?.hash ?? params.externalMessageHash;
|
|
127
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
128
|
+
params.onStatusChange?.("completed");
|
|
129
|
+
return {
|
|
130
|
+
success: true,
|
|
131
|
+
status: "completed",
|
|
132
|
+
transactionHash: txHash
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
await new Promise((r) => setTimeout(r, pollInterval));
|
|
139
|
+
}
|
|
140
|
+
params.onStatusChange?.("timeout");
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
status: "timeout",
|
|
144
|
+
error: `Jetton transfer not confirmed within ${timeout}ms`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function getJettonWalletAddress(apiEndpoint, ownerAddress, jettonMaster) {
|
|
148
|
+
const response = await fetch(`${apiEndpoint}/runGetMethod`, {
|
|
149
|
+
method: "POST",
|
|
150
|
+
headers: { "Content-Type": "application/json" },
|
|
151
|
+
body: JSON.stringify({
|
|
152
|
+
address: jettonMaster,
|
|
153
|
+
method: "get_wallet_address",
|
|
154
|
+
stack: [["tvm.Slice", ownerAddress]]
|
|
155
|
+
})
|
|
156
|
+
});
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
throw new Error(`Failed to resolve Jetton wallet address: ${response.status}`);
|
|
159
|
+
}
|
|
160
|
+
const result = await response.json();
|
|
161
|
+
if (!result.ok || !result.result) {
|
|
162
|
+
throw new Error("Failed to resolve Jetton wallet address: invalid response");
|
|
163
|
+
}
|
|
164
|
+
if (result.result.exit_code !== void 0 && result.result.exit_code !== 0) {
|
|
165
|
+
throw new Error(`Jetton master GET method failed with exit code ${result.result.exit_code}`);
|
|
166
|
+
}
|
|
167
|
+
if (!result.result.stack || result.result.stack.length === 0) {
|
|
168
|
+
throw new Error("Failed to resolve Jetton wallet address: empty stack");
|
|
169
|
+
}
|
|
170
|
+
const walletAddress = result.result.stack[0]?.[1];
|
|
171
|
+
if (!walletAddress) {
|
|
172
|
+
throw new Error("Failed to parse Jetton wallet address from response");
|
|
173
|
+
}
|
|
174
|
+
return walletAddress;
|
|
175
|
+
}
|
|
107
176
|
async function createWDKTonSigner(account) {
|
|
108
177
|
const adapter = new WDKTonSignerAdapter(account);
|
|
109
178
|
await adapter.initialize();
|
|
@@ -112,6 +181,8 @@ async function createWDKTonSigner(account) {
|
|
|
112
181
|
|
|
113
182
|
export {
|
|
114
183
|
WDKTonSignerAdapter,
|
|
184
|
+
waitForJettonTransfer,
|
|
185
|
+
getJettonWalletAddress,
|
|
115
186
|
createWDKTonSigner
|
|
116
187
|
};
|
|
117
|
-
//# sourceMappingURL=chunk-
|
|
188
|
+
//# sourceMappingURL=chunk-KWX6CJIH.mjs.map
|
|
@@ -0,0 +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// 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":[]}
|
|
@@ -4,6 +4,7 @@ var WDKTronSignerAdapter = class {
|
|
|
4
4
|
_address = null;
|
|
5
5
|
_initialized = false;
|
|
6
6
|
_rpcUrl;
|
|
7
|
+
_energyProvider = null;
|
|
7
8
|
constructor(account, rpcUrl = "https://api.trongrid.io") {
|
|
8
9
|
if (!account) {
|
|
9
10
|
throw new Error("WDK TRON account is required");
|
|
@@ -105,6 +106,106 @@ var WDKTronSignerAdapter = class {
|
|
|
105
106
|
);
|
|
106
107
|
}
|
|
107
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Estimate the energy required for a TRC20 transfer.
|
|
111
|
+
*
|
|
112
|
+
* Uses the `wallet/triggerconstantcontract` API to simulate the transfer
|
|
113
|
+
* and return the energy/bandwidth requirements.
|
|
114
|
+
*
|
|
115
|
+
* @param params - Transaction parameters to simulate
|
|
116
|
+
* @returns Energy estimation result
|
|
117
|
+
*/
|
|
118
|
+
async estimateEnergy(params) {
|
|
119
|
+
if (!this._address) {
|
|
120
|
+
throw new Error("TRON signer not initialized. Call initialize() first.");
|
|
121
|
+
}
|
|
122
|
+
const functionSelector = "transfer(address,uint256)";
|
|
123
|
+
const toAddressHex = this.addressToHex(params.to).slice(2).padStart(64, "0");
|
|
124
|
+
const amountHex = BigInt(params.amount).toString(16).padStart(64, "0");
|
|
125
|
+
const parameter = toAddressHex + amountHex;
|
|
126
|
+
try {
|
|
127
|
+
const response = await fetch(`${this._rpcUrl}/wallet/triggerconstantcontract`, {
|
|
128
|
+
method: "POST",
|
|
129
|
+
headers: { "Content-Type": "application/json" },
|
|
130
|
+
body: JSON.stringify({
|
|
131
|
+
owner_address: this.addressToHex(this._address),
|
|
132
|
+
contract_address: this.addressToHex(params.contractAddress),
|
|
133
|
+
function_selector: functionSelector,
|
|
134
|
+
parameter
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
throw new Error(`Energy estimation failed: ${response.status}`);
|
|
139
|
+
}
|
|
140
|
+
const result = await response.json();
|
|
141
|
+
if (result.result?.code && result.result.code !== "SUCCESS") {
|
|
142
|
+
throw new Error(`Energy estimation failed: ${result.result.message ?? result.result.code}`);
|
|
143
|
+
}
|
|
144
|
+
const energyRequired = (result.energy_used ?? 0) + (result.energy_penalty ?? 0);
|
|
145
|
+
const resourceResponse = await fetch(`${this._rpcUrl}/wallet/getaccountresource`, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers: { "Content-Type": "application/json" },
|
|
148
|
+
body: JSON.stringify({
|
|
149
|
+
address: this.addressToHex(this._address)
|
|
150
|
+
})
|
|
151
|
+
});
|
|
152
|
+
let energyAvailable = 0;
|
|
153
|
+
if (resourceResponse.ok) {
|
|
154
|
+
const resources = await resourceResponse.json();
|
|
155
|
+
energyAvailable = (resources.EnergyLimit ?? 0) - (resources.EnergyUsed ?? 0);
|
|
156
|
+
}
|
|
157
|
+
const bandwidthRequired = 350;
|
|
158
|
+
const trxCostIfNoEnergy = BigInt(Math.max(0, energyRequired - energyAvailable)) * 420n;
|
|
159
|
+
return {
|
|
160
|
+
energyRequired,
|
|
161
|
+
energyAvailable,
|
|
162
|
+
trxCostIfNoEnergy,
|
|
163
|
+
bandwidthRequired
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Failed to estimate energy: ${error instanceof Error ? error.message : String(error)}`
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Sign a TRC20 transfer with dynamic fee limit estimation.
|
|
173
|
+
*
|
|
174
|
+
* Instead of using a hardcoded 100 TRX fee limit, estimates the actual
|
|
175
|
+
* energy cost and adds a 20% margin.
|
|
176
|
+
*
|
|
177
|
+
* @param params - Transaction parameters
|
|
178
|
+
* @returns Hex-encoded signed transaction
|
|
179
|
+
*/
|
|
180
|
+
async signTransactionWithEstimation(params) {
|
|
181
|
+
if (!params.feeLimit) {
|
|
182
|
+
const estimate = await this.estimateEnergy(params);
|
|
183
|
+
const estimatedFee = estimate.trxCostIfNoEnergy;
|
|
184
|
+
const feeWithMargin = estimatedFee + estimatedFee * 20n / 100n;
|
|
185
|
+
const feeLimitSun = Number(
|
|
186
|
+
feeWithMargin < 10000000n ? 10000000n : feeWithMargin > 150000000n ? 150000000n : feeWithMargin
|
|
187
|
+
);
|
|
188
|
+
return this.signTransaction({ ...params, feeLimit: feeLimitSun });
|
|
189
|
+
}
|
|
190
|
+
return this.signTransaction(params);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Register an external energy delegation provider.
|
|
194
|
+
*
|
|
195
|
+
* Energy providers can delegate bandwidth and energy to this account
|
|
196
|
+
* to reduce TRX costs for TRC20 transfers.
|
|
197
|
+
*
|
|
198
|
+
* @param provider - Energy delegation provider
|
|
199
|
+
*/
|
|
200
|
+
registerEnergyProvider(provider) {
|
|
201
|
+
this._energyProvider = provider;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Get the registered energy provider, if any
|
|
205
|
+
*/
|
|
206
|
+
getEnergyProvider() {
|
|
207
|
+
return this._energyProvider;
|
|
208
|
+
}
|
|
108
209
|
/**
|
|
109
210
|
* Build a TRC20 transfer transaction
|
|
110
211
|
*/
|
|
@@ -193,4 +294,4 @@ export {
|
|
|
193
294
|
WDKTronSignerAdapter,
|
|
194
295
|
createWDKTronSigner
|
|
195
296
|
};
|
|
196
|
-
//# sourceMappingURL=chunk-
|
|
297
|
+
//# sourceMappingURL=chunk-QZKUU2O6.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/tron-adapter.ts"],"sourcesContent":["/**\n * TRON Signer Adapter for WDK\n *\n * Wraps a Tether WDK TRON account to implement T402's ClientTronSigner interface.\n * This allows WDK-managed TRON wallets to be used for T402 payments.\n *\n * Includes support for:\n * - Energy estimation for dynamic fee limits\n * - External energy delegation providers\n * - Dynamic fee limit calculation with 20% margin\n */\n\nimport type { WDKTronAccount } from '../types.js'\n\n/**\n * SignTransactionParams matching T402's @t402/tron interface\n */\nexport interface SignTransactionParams {\n /** TRC20 contract address */\n contractAddress: string\n /** Recipient address (T-prefix base58check) */\n to: string\n /** Amount to transfer (in smallest units) */\n amount: string\n /** Fee limit in SUN (optional, defaults to 100 TRX) */\n feeLimit?: number\n /** Transaction expiration time in milliseconds (optional) */\n expiration?: number\n}\n\n/**\n * Block info for transaction building\n */\nexport interface BlockInfo {\n /** Reference block bytes (hex) */\n refBlockBytes: string\n /** Reference block hash (hex) */\n refBlockHash: string\n /** Expiration timestamp in milliseconds */\n expiration: number\n}\n\n/**\n * ClientTronSigner interface matching T402's @t402/tron\n */\nexport interface ClientTronSigner {\n readonly address: string\n signTransaction(params: SignTransactionParams): Promise<string>\n getBlockInfo(): Promise<BlockInfo>\n}\n\n/**\n * Energy estimation result\n */\nexport interface EnergyEstimate {\n energyRequired: number\n energyAvailable: number\n trxCostIfNoEnergy: bigint\n bandwidthRequired: number\n}\n\n/**\n * Energy provider interface for external delegation services\n */\nexport interface EnergyProvider {\n delegateEnergy(to: string, amount: number): Promise<string>\n getPrice(amount: number): Promise<bigint>\n}\n\n// TronWeb-compatible types\ninterface TronWebTransaction {\n txID: string\n raw_data: {\n contract: unknown[]\n ref_block_bytes: string\n ref_block_hash: string\n expiration: number\n timestamp: number\n }\n raw_data_hex: string\n signature?: string[]\n}\n\ninterface TronWebBlock {\n block_header: {\n raw_data: {\n number: number\n txTrieRoot: string\n witness_address: string\n parentHash: string\n version: number\n timestamp: number\n }\n witness_signature: string\n }\n blockID: string\n}\n\n/**\n * WDKTronSignerAdapter - Adapts a WDK TRON account to T402's ClientTronSigner\n *\n * @example\n * ```typescript\n * const adapter = await createWDKTronSigner(wdkTronAccount);\n * const signedTx = await adapter.signTransaction({\n * contractAddress: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',\n * to: 'TRecipientAddress...',\n * amount: '1000000', // 1 USDT\n * });\n * ```\n */\nexport class WDKTronSignerAdapter implements ClientTronSigner {\n private _account: WDKTronAccount\n private _address: string | null = null\n private _initialized = false\n private _rpcUrl: string\n private _energyProvider: EnergyProvider | null = null\n\n constructor(account: WDKTronAccount, rpcUrl = 'https://api.trongrid.io') {\n if (!account) {\n throw new Error('WDK TRON account is required')\n }\n this._account = account\n this._rpcUrl = rpcUrl\n }\n\n /**\n * Get the wallet address (T-prefix base58check)\n * @throws Error if not initialized\n */\n get address(): string {\n if (!this._address) {\n throw new Error(\n 'TRON signer not initialized. Call initialize() first or use createWDKTronSigner().',\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 this._address = await this._account.getAddress()\n this._initialized = true\n }\n\n /**\n * Sign a TRC20 transfer transaction\n *\n * This method:\n * 1. Builds a TRC20 transfer transaction\n * 2. Signs it using the WDK account\n * 3. Returns the hex-encoded signed transaction\n *\n * @param params - Transaction parameters\n * @returns Hex-encoded signed transaction\n */\n async signTransaction(params: SignTransactionParams): Promise<string> {\n if (!params.contractAddress) {\n throw new Error('contractAddress is required')\n }\n if (!params.to) {\n throw new Error('recipient address (to) is required')\n }\n if (!params.amount || BigInt(params.amount) <= 0n) {\n throw new Error('amount must be a positive value')\n }\n\n // Get block info for transaction\n const blockInfo = await this.getBlockInfo()\n\n // Default fee limit: 100 TRX = 100_000_000 SUN\n const feeLimit = params.feeLimit ?? 100_000_000\n\n // Build the TRC20 transfer transaction\n const transaction = await this.buildTrc20Transaction({\n contractAddress: params.contractAddress,\n to: params.to,\n amount: params.amount,\n feeLimit,\n refBlockBytes: blockInfo.refBlockBytes,\n refBlockHash: blockInfo.refBlockHash,\n expiration: params.expiration ?? blockInfo.expiration,\n })\n\n // Sign the transaction using WDK account\n const signedTx = await this._account.signTransaction(transaction)\n\n // Serialize to hex format\n return this.serializeTransaction(signedTx as TronWebTransaction)\n }\n\n /**\n * Get the current reference block info for transaction building\n * This is required for TRON's replay protection mechanism\n */\n async getBlockInfo(): Promise<BlockInfo> {\n try {\n const response = await fetch(`${this._rpcUrl}/wallet/getnowblock`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({}),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to get block info: ${response.status}`)\n }\n\n const block = (await response.json()) as TronWebBlock\n\n // Extract reference block bytes (last 4 bytes of block number)\n const blockNum = block.block_header.raw_data.number\n const refBlockBytes = blockNum.toString(16).padStart(8, '0').slice(-4)\n\n // Reference block hash (first 8 bytes of block ID)\n const refBlockHash = block.blockID.slice(16, 32)\n\n // Expiration: block timestamp + 60 seconds\n const expiration = block.block_header.raw_data.timestamp + 60000\n\n return {\n refBlockBytes,\n refBlockHash,\n expiration,\n }\n } catch (error) {\n throw new Error(\n `Failed to get TRON block info: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n /**\n * Estimate the energy required for a TRC20 transfer.\n *\n * Uses the `wallet/triggerconstantcontract` API to simulate the transfer\n * and return the energy/bandwidth requirements.\n *\n * @param params - Transaction parameters to simulate\n * @returns Energy estimation result\n */\n async estimateEnergy(params: SignTransactionParams): Promise<EnergyEstimate> {\n if (!this._address) {\n throw new Error('TRON signer not initialized. Call initialize() first.')\n }\n\n const functionSelector = 'transfer(address,uint256)'\n const toAddressHex = this.addressToHex(params.to).slice(2).padStart(64, '0')\n const amountHex = BigInt(params.amount).toString(16).padStart(64, '0')\n const parameter = toAddressHex + amountHex\n\n try {\n const response = await fetch(`${this._rpcUrl}/wallet/triggerconstantcontract`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n owner_address: this.addressToHex(this._address),\n contract_address: this.addressToHex(params.contractAddress),\n function_selector: functionSelector,\n parameter,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Energy estimation failed: ${response.status}`)\n }\n\n const result = (await response.json()) as {\n energy_used?: number\n energy_penalty?: number\n result?: { code?: string; message?: string }\n }\n\n if (result.result?.code && result.result.code !== 'SUCCESS') {\n throw new Error(`Energy estimation failed: ${result.result.message ?? result.result.code}`)\n }\n\n const energyRequired = (result.energy_used ?? 0) + (result.energy_penalty ?? 0)\n\n // Get account resources to check available energy\n const resourceResponse = await fetch(`${this._rpcUrl}/wallet/getaccountresource`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n address: this.addressToHex(this._address),\n }),\n })\n\n let energyAvailable = 0\n if (resourceResponse.ok) {\n const resources = (await resourceResponse.json()) as {\n EnergyLimit?: number\n EnergyUsed?: number\n freeNetLimit?: number\n freeNetUsed?: number\n NetLimit?: number\n NetUsed?: number\n }\n energyAvailable = (resources.EnergyLimit ?? 0) - (resources.EnergyUsed ?? 0)\n }\n\n // TRC20 transfer typically requires ~350 bytes of bandwidth\n const bandwidthRequired = 350\n\n // Energy costs 420 SUN each (approximate, varies with market)\n const trxCostIfNoEnergy = BigInt(Math.max(0, energyRequired - energyAvailable)) * 420n\n\n return {\n energyRequired,\n energyAvailable,\n trxCostIfNoEnergy,\n bandwidthRequired,\n }\n } catch (error) {\n throw new Error(\n `Failed to estimate energy: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n /**\n * Sign a TRC20 transfer with dynamic fee limit estimation.\n *\n * Instead of using a hardcoded 100 TRX fee limit, estimates the actual\n * energy cost and adds a 20% margin.\n *\n * @param params - Transaction parameters\n * @returns Hex-encoded signed transaction\n */\n async signTransactionWithEstimation(params: SignTransactionParams): Promise<string> {\n if (!params.feeLimit) {\n const estimate = await this.estimateEnergy(params)\n // Convert energy cost to SUN with 20% margin\n const estimatedFee = estimate.trxCostIfNoEnergy\n const feeWithMargin = estimatedFee + (estimatedFee * 20n) / 100n\n // Minimum 10 TRX fee limit, max 150 TRX\n const feeLimitSun = Number(\n feeWithMargin < 10_000_000n\n ? 10_000_000n\n : feeWithMargin > 150_000_000n\n ? 150_000_000n\n : feeWithMargin,\n )\n return this.signTransaction({ ...params, feeLimit: feeLimitSun })\n }\n return this.signTransaction(params)\n }\n\n /**\n * Register an external energy delegation provider.\n *\n * Energy providers can delegate bandwidth and energy to this account\n * to reduce TRX costs for TRC20 transfers.\n *\n * @param provider - Energy delegation provider\n */\n registerEnergyProvider(provider: EnergyProvider): void {\n this._energyProvider = provider\n }\n\n /**\n * Get the registered energy provider, if any\n */\n getEnergyProvider(): EnergyProvider | null {\n return this._energyProvider\n }\n\n /**\n * Build a TRC20 transfer transaction\n */\n private async buildTrc20Transaction(params: {\n contractAddress: string\n to: string\n amount: string\n feeLimit: number\n refBlockBytes: string\n refBlockHash: string\n expiration: number\n }): Promise<TronWebTransaction> {\n // Build TRC20 transfer function call\n // transfer(address,uint256) = 0xa9059cbb\n const functionSelector = 'transfer(address,uint256)'\n\n // Encode parameters\n const toAddressHex = this.addressToHex(params.to).slice(2).padStart(64, '0')\n const amountHex = BigInt(params.amount).toString(16).padStart(64, '0')\n const parameter = toAddressHex + amountHex\n\n try {\n const response = await fetch(`${this._rpcUrl}/wallet/triggersmartcontract`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n owner_address: this.addressToHex(this._address!),\n contract_address: this.addressToHex(params.contractAddress),\n function_selector: functionSelector,\n parameter,\n fee_limit: params.feeLimit,\n }),\n })\n\n if (!response.ok) {\n throw new Error(`Failed to build transaction: ${response.status}`)\n }\n\n const result = await response.json()\n\n if (result.result?.code) {\n throw new Error(`Transaction build failed: ${result.result.message}`)\n }\n\n return result.transaction as TronWebTransaction\n } catch (error) {\n throw new Error(\n `Failed to build TRC20 transaction: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n }\n\n /**\n * Serialize a signed transaction to hex format\n */\n private serializeTransaction(signedTx: TronWebTransaction): string {\n // Return the raw_data_hex with signature appended\n if (signedTx.signature && signedTx.signature.length > 0) {\n return JSON.stringify(signedTx)\n }\n return signedTx.raw_data_hex\n }\n\n /**\n * Convert TRON base58 address to hex format\n */\n private addressToHex(address: string): string {\n // If already hex, return as-is\n if (address.startsWith('41') || address.startsWith('0x')) {\n return address.startsWith('0x') ? '41' + address.slice(2) : address\n }\n\n // Convert base58 to hex using simple algorithm\n const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'\n let num = BigInt(0)\n for (const char of address) {\n num = num * BigInt(58) + BigInt(ALPHABET.indexOf(char))\n }\n\n // Convert to hex and take first 42 chars (21 bytes)\n let hex = num.toString(16)\n // Handle leading zeros\n let leadingZeros = 0\n for (const char of address) {\n if (char === '1') leadingZeros++\n else break\n }\n hex = '00'.repeat(leadingZeros) + hex\n\n // TRON address is 21 bytes = 42 hex chars\n return hex.slice(0, 42)\n }\n\n /**\n * Get TRX balance in SUN\n */\n async getBalance(): Promise<bigint> {\n return this._account.getBalance()\n }\n\n /**\n * Get TRC20 token balance\n * @param contractAddress - TRC20 contract address\n */\n async getTrc20Balance(contractAddress: string): Promise<bigint> {\n return this._account.getTrc20Balance(contractAddress)\n }\n}\n\n/**\n * Create an initialized WDK TRON signer\n *\n * @param account - WDK TRON account from @tetherto/wdk-wallet-tron\n * @param rpcUrl - Optional custom RPC URL (default: https://api.trongrid.io)\n * @returns Initialized ClientTronSigner\n *\n * @example\n * ```typescript\n * import { T402WDK } from '@t402/wdk';\n *\n * const wallet = new T402WDK(seedPhrase, config);\n * const tronSigner = await wallet.getTronSigner();\n *\n * // Use with T402 client\n * const client = createT402HTTPClient({\n * signers: [{ scheme: 'exact', network: 'tron:mainnet', signer: tronSigner }]\n * });\n * ```\n */\nexport async function createWDKTronSigner(\n account: WDKTronAccount,\n rpcUrl?: string,\n): Promise<WDKTronSignerAdapter> {\n const adapter = new WDKTronSignerAdapter(account, rpcUrl)\n await adapter.initialize()\n return adapter\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
// src/integrations/a2a-adapter.ts
|
|
2
|
+
function findBestOption(accepts, signers, preferredScheme) {
|
|
3
|
+
const signerNetworks = new Set(signers.map((s) => s.network));
|
|
4
|
+
const exactMatch = accepts.find(
|
|
5
|
+
(a) => a.scheme === preferredScheme && signerNetworks.has(a.network)
|
|
6
|
+
);
|
|
7
|
+
if (exactMatch) return exactMatch;
|
|
8
|
+
const networkMatch = accepts.find((a) => signerNetworks.has(a.network));
|
|
9
|
+
if (networkMatch) return networkMatch;
|
|
10
|
+
const schemeMatch = accepts.find((a) => a.scheme === preferredScheme);
|
|
11
|
+
if (schemeMatch) return schemeMatch;
|
|
12
|
+
return accepts[0];
|
|
13
|
+
}
|
|
14
|
+
async function createWdkA2APaymentClient(wdk, options) {
|
|
15
|
+
const preferredScheme = options?.preferredScheme ?? "exact";
|
|
16
|
+
const signers = await wdk.getAllSigners({ schemes: [preferredScheme] });
|
|
17
|
+
const paymentHandler = async (req) => {
|
|
18
|
+
if (!req.accepts || req.accepts.length === 0) {
|
|
19
|
+
throw new Error("No payment options in requirements");
|
|
20
|
+
}
|
|
21
|
+
const selected = findBestOption(req.accepts, signers, preferredScheme);
|
|
22
|
+
if (!selected) {
|
|
23
|
+
throw new Error("No compatible payment option found for available signers");
|
|
24
|
+
}
|
|
25
|
+
if (options?.spendingLimit !== void 0) {
|
|
26
|
+
const amount = BigInt(selected.amount);
|
|
27
|
+
if (amount > options.spendingLimit) {
|
|
28
|
+
throw new Error(`Payment amount ${amount} exceeds spending limit ${options.spendingLimit}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (options?.onApprovalRequired) {
|
|
32
|
+
const approved = await options.onApprovalRequired({
|
|
33
|
+
amount: BigInt(selected.amount),
|
|
34
|
+
network: selected.network
|
|
35
|
+
});
|
|
36
|
+
if (!approved) {
|
|
37
|
+
throw new Error("Payment rejected by approval callback");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const signerEntry = signers.find((s) => s.network === selected.network && s.scheme === selected.scheme) ?? signers.find((s) => s.network === selected.network);
|
|
41
|
+
if (!signerEntry) {
|
|
42
|
+
throw new Error(`No signer available for network ${selected.network}`);
|
|
43
|
+
}
|
|
44
|
+
if (options?.autoBalance) {
|
|
45
|
+
const chainName = getChainNameFromNetwork(wdk, selected.network);
|
|
46
|
+
if (chainName) {
|
|
47
|
+
const balance = await wdk.getUsdt0Balance(chainName);
|
|
48
|
+
const requiredAmount = BigInt(selected.amount);
|
|
49
|
+
if (balance < requiredAmount && options.autoBridge) {
|
|
50
|
+
const best = await wdk.findBestChainForPayment(requiredAmount);
|
|
51
|
+
if (best && best.chain !== chainName) {
|
|
52
|
+
await wdk.bridgeUsdt0({
|
|
53
|
+
fromChain: best.chain,
|
|
54
|
+
toChain: chainName,
|
|
55
|
+
amount: requiredAmount
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const signer = signerEntry.signer;
|
|
62
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
63
|
+
const deadline = now + selected.maxTimeoutSeconds;
|
|
64
|
+
const nonce = "0x" + Array.from(globalThis.crypto.getRandomValues(new Uint8Array(32))).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
65
|
+
const chainId = parseInt(selected.network.split(":")[1] || "0");
|
|
66
|
+
const signature = await signer.signTypedData({
|
|
67
|
+
domain: {
|
|
68
|
+
name: "USD\u20AE0",
|
|
69
|
+
version: "1",
|
|
70
|
+
chainId,
|
|
71
|
+
verifyingContract: selected.asset
|
|
72
|
+
},
|
|
73
|
+
types: {
|
|
74
|
+
TransferWithAuthorization: [
|
|
75
|
+
{ name: "from", type: "address" },
|
|
76
|
+
{ name: "to", type: "address" },
|
|
77
|
+
{ name: "value", type: "uint256" },
|
|
78
|
+
{ name: "validAfter", type: "uint256" },
|
|
79
|
+
{ name: "validBefore", type: "uint256" },
|
|
80
|
+
{ name: "nonce", type: "bytes32" }
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
primaryType: "TransferWithAuthorization",
|
|
84
|
+
message: {
|
|
85
|
+
from: signer.address,
|
|
86
|
+
to: selected.payTo,
|
|
87
|
+
value: BigInt(selected.amount),
|
|
88
|
+
validAfter: 0n,
|
|
89
|
+
validBefore: BigInt(deadline),
|
|
90
|
+
nonce
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
t402Version: req.t402Version,
|
|
95
|
+
resource: req.resource,
|
|
96
|
+
accepted: selected,
|
|
97
|
+
payload: {
|
|
98
|
+
signature,
|
|
99
|
+
from: signer.address,
|
|
100
|
+
validAfter: "0",
|
|
101
|
+
validBefore: deadline.toString(),
|
|
102
|
+
nonce
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
return { signers, paymentHandler };
|
|
107
|
+
}
|
|
108
|
+
function getChainNameFromNetwork(wdk, network) {
|
|
109
|
+
for (const chain of wdk.getConfiguredChains()) {
|
|
110
|
+
const config = wdk.getChainConfig(chain);
|
|
111
|
+
if (config && config.network === network) {
|
|
112
|
+
return chain;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/integrations/facilitator-adapter.ts
|
|
119
|
+
async function toFacilitatorWdkSigner(wdk, chain, options) {
|
|
120
|
+
const wdkSigner = await wdk.getSigner(chain);
|
|
121
|
+
const address = wdkSigner.address;
|
|
122
|
+
return {
|
|
123
|
+
address,
|
|
124
|
+
async signTransaction(tx) {
|
|
125
|
+
if (tx && typeof tx === "object" && "domain" in tx) {
|
|
126
|
+
const typedData = tx;
|
|
127
|
+
return wdkSigner.signTypedData(typedData);
|
|
128
|
+
}
|
|
129
|
+
if (typeof tx === "string") {
|
|
130
|
+
return wdkSigner.signMessage(tx);
|
|
131
|
+
}
|
|
132
|
+
throw new Error("Unsupported transaction format for WDK facilitator signer");
|
|
133
|
+
},
|
|
134
|
+
async signTypedData(data) {
|
|
135
|
+
return wdkSigner.signTypedData(data);
|
|
136
|
+
},
|
|
137
|
+
async sendTransaction(params) {
|
|
138
|
+
const result = await wdkSigner.sendTransaction({
|
|
139
|
+
to: params.to,
|
|
140
|
+
value: params.value,
|
|
141
|
+
data: params.data
|
|
142
|
+
});
|
|
143
|
+
if (options?.bridgeToMainChain && options.bridgeToMainChain !== chain) {
|
|
144
|
+
const balance = await wdk.getUsdt0Balance(chain);
|
|
145
|
+
if (balance > 0n) {
|
|
146
|
+
try {
|
|
147
|
+
await wdk.bridgeUsdt0({
|
|
148
|
+
fromChain: chain,
|
|
149
|
+
toChain: options.bridgeToMainChain,
|
|
150
|
+
amount: balance
|
|
151
|
+
});
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return result.hash;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
async function createFacilitatorSigners(wdk, options) {
|
|
161
|
+
const chains = wdk.getConfiguredChains();
|
|
162
|
+
const signers = /* @__PURE__ */ new Map();
|
|
163
|
+
const results = await Promise.allSettled(
|
|
164
|
+
chains.map(async (chain) => {
|
|
165
|
+
const signer = await toFacilitatorWdkSigner(wdk, chain, options);
|
|
166
|
+
return { chain, signer };
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
for (const result of results) {
|
|
170
|
+
if (result.status === "fulfilled") {
|
|
171
|
+
signers.set(result.value.chain, result.value.signer);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return signers;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// src/integrations/siwx-adapter.ts
|
|
178
|
+
async function toSIWxSigner(wdk, chain) {
|
|
179
|
+
const wdkSigner = await wdk.getSigner(chain);
|
|
180
|
+
return {
|
|
181
|
+
address: wdkSigner.address,
|
|
182
|
+
async signMessage(message) {
|
|
183
|
+
return wdkSigner.signMessage(message);
|
|
184
|
+
},
|
|
185
|
+
async signTypedData(data) {
|
|
186
|
+
return wdkSigner.signTypedData({
|
|
187
|
+
domain: data.domain,
|
|
188
|
+
types: data.types,
|
|
189
|
+
primaryType: data.primaryType,
|
|
190
|
+
message: data.message
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
async function createSIWxSigners(wdk) {
|
|
196
|
+
const chains = wdk.getConfiguredChains();
|
|
197
|
+
const signers = /* @__PURE__ */ new Map();
|
|
198
|
+
const results = await Promise.allSettled(
|
|
199
|
+
chains.map(async (chain) => {
|
|
200
|
+
const signer = await toSIWxSigner(wdk, chain);
|
|
201
|
+
return { chain, signer };
|
|
202
|
+
})
|
|
203
|
+
);
|
|
204
|
+
for (const result of results) {
|
|
205
|
+
if (result.status === "fulfilled") {
|
|
206
|
+
signers.set(result.value.chain, result.value.signer);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return signers;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export {
|
|
213
|
+
createWdkA2APaymentClient,
|
|
214
|
+
toFacilitatorWdkSigner,
|
|
215
|
+
createFacilitatorSigners,
|
|
216
|
+
toSIWxSigner,
|
|
217
|
+
createSIWxSigners
|
|
218
|
+
};
|
|
219
|
+
//# sourceMappingURL=chunk-TVSNUSFZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/integrations/a2a-adapter.ts","../../src/integrations/facilitator-adapter.ts","../../src/integrations/siwx-adapter.ts"],"sourcesContent":["/**\n * A2A + WDK Adapter\n *\n * Bridges T402WDK wallets with the A2A (Agent-to-Agent) payment transport,\n * enabling AI agents to make payments using WDK-managed wallets.\n */\n\nimport type { T402WDK } from '../t402wdk.js'\nimport type { SignerEntry } from '../types.js'\n\n/**\n * Payment requirements received from an A2A server (402 response).\n * Matches the core PaymentRequired type shape.\n */\nexport interface A2APaymentRequired {\n t402Version: number\n resource: { url: string; description?: string; mimeType?: string }\n accepts: Array<{\n scheme: string\n network: string\n asset: string\n amount: string\n payTo: string\n maxTimeoutSeconds: number\n extra: Record<string, unknown>\n }>\n extensions?: Record<string, unknown>\n}\n\n/**\n * Payment payload to submit to an A2A server.\n * Matches the core PaymentPayload type shape.\n */\nexport interface A2APaymentPayload {\n t402Version: number\n resource?: { url: string; description?: string; mimeType?: string }\n accepted: A2APaymentRequired['accepts'][0]\n payload: Record<string, unknown>\n extensions?: Record<string, unknown>\n}\n\n/**\n * Options for the WDK A2A payment client adapter.\n */\nexport interface WdkA2AOptions {\n /** Maximum spending limit per payment (in atomic units) */\n spendingLimit?: bigint\n /** Callback when manual approval is required */\n onApprovalRequired?: (payment: { amount: bigint; network: string }) => Promise<boolean>\n /** Auto-check balance before payment */\n autoBalance?: boolean\n /** Auto-bridge if insufficient balance on target chain */\n autoBridge?: boolean\n /** Preferred payment scheme (default: \"exact\") */\n preferredScheme?: string\n}\n\n/**\n * Result of createWdkA2APaymentClient.\n */\nexport interface WdkA2APaymentClient {\n /** Signer entries from WDK for all configured chains */\n signers: SignerEntry[]\n /** Handle a 402 payment required response */\n paymentHandler: (req: A2APaymentRequired) => Promise<A2APaymentPayload>\n}\n\n/**\n * Find the best matching payment option for the available signers.\n */\nfunction findBestOption(\n accepts: A2APaymentRequired['accepts'],\n signers: SignerEntry[],\n preferredScheme: string,\n): A2APaymentRequired['accepts'][0] | undefined {\n const signerNetworks = new Set(signers.map((s) => s.network))\n\n // Prefer matching both scheme and network\n const exactMatch = accepts.find(\n (a) => a.scheme === preferredScheme && signerNetworks.has(a.network),\n )\n if (exactMatch) return exactMatch\n\n // Match by network only\n const networkMatch = accepts.find((a) => signerNetworks.has(a.network))\n if (networkMatch) return networkMatch\n\n // Match by scheme only\n const schemeMatch = accepts.find((a) => a.scheme === preferredScheme)\n if (schemeMatch) return schemeMatch\n\n return accepts[0]\n}\n\n/**\n * Create a WDK-backed A2A payment client.\n *\n * Extracts all configured chain signers from WDK and wraps them for A2A use.\n * The returned `paymentHandler` selects the best signer for the payment\n * requirements, optionally checks balance, and creates a signed payment payload.\n *\n * @param wdk - An initialized T402WDK instance\n * @param options - Configuration options\n * @returns Object with signers and a paymentHandler function\n *\n * @example\n * ```typescript\n * const { signers, paymentHandler } = await createWdkA2APaymentClient(wdk, {\n * spendingLimit: 10_000_000n, // 10 USDT0\n * autoBalance: true,\n * });\n *\n * // When the A2A agent receives a 402 response:\n * const payload = await paymentHandler(paymentRequired);\n * // Submit payload back to the A2A server\n * ```\n */\nexport async function createWdkA2APaymentClient(\n wdk: T402WDK,\n options?: WdkA2AOptions,\n): Promise<WdkA2APaymentClient> {\n const preferredScheme = options?.preferredScheme ?? 'exact'\n\n // Get all signers from WDK\n const signers = await wdk.getAllSigners({ schemes: [preferredScheme] })\n\n const paymentHandler = async (req: A2APaymentRequired): Promise<A2APaymentPayload> => {\n if (!req.accepts || req.accepts.length === 0) {\n throw new Error('No payment options in requirements')\n }\n\n // Find the best option\n const selected = findBestOption(req.accepts, signers, preferredScheme)\n if (!selected) {\n throw new Error('No compatible payment option found for available signers')\n }\n\n // Check spending limit\n if (options?.spendingLimit !== undefined) {\n const amount = BigInt(selected.amount)\n if (amount > options.spendingLimit) {\n throw new Error(`Payment amount ${amount} exceeds spending limit ${options.spendingLimit}`)\n }\n }\n\n // Request approval if callback provided\n if (options?.onApprovalRequired) {\n const approved = await options.onApprovalRequired({\n amount: BigInt(selected.amount),\n network: selected.network,\n })\n if (!approved) {\n throw new Error('Payment rejected by approval callback')\n }\n }\n\n // Find the matching signer\n const signerEntry =\n signers.find((s) => s.network === selected.network && s.scheme === selected.scheme) ??\n signers.find((s) => s.network === selected.network)\n\n if (!signerEntry) {\n throw new Error(`No signer available for network ${selected.network}`)\n }\n\n // Auto-balance check\n if (options?.autoBalance) {\n const chainName = getChainNameFromNetwork(wdk, selected.network)\n if (chainName) {\n const balance = await wdk.getUsdt0Balance(chainName)\n const requiredAmount = BigInt(selected.amount)\n if (balance < requiredAmount && options.autoBridge) {\n // Try to find a chain with enough balance and bridge\n const best = await wdk.findBestChainForPayment(requiredAmount)\n if (best && best.chain !== chainName) {\n await wdk.bridgeUsdt0({\n fromChain: best.chain,\n toChain: chainName,\n amount: requiredAmount,\n })\n }\n }\n }\n }\n\n // Sign the payment using the WDK signer\n const signer = signerEntry.signer as {\n signTypedData: (params: Record<string, unknown>) => Promise<string>\n address: string\n }\n\n // Create EIP-3009 transferWithAuthorization typed data\n const now = Math.floor(Date.now() / 1000)\n const deadline = now + selected.maxTimeoutSeconds\n const nonce =\n '0x' +\n Array.from(globalThis.crypto.getRandomValues(new Uint8Array(32)))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n\n const chainId = parseInt(selected.network.split(':')[1] || '0')\n\n const signature = await signer.signTypedData({\n domain: {\n name: 'USD₮0',\n version: '1',\n chainId,\n verifyingContract: selected.asset,\n },\n types: {\n TransferWithAuthorization: [\n { name: 'from', type: 'address' },\n { name: 'to', type: 'address' },\n { name: 'value', type: 'uint256' },\n { name: 'validAfter', type: 'uint256' },\n { name: 'validBefore', type: 'uint256' },\n { name: 'nonce', type: 'bytes32' },\n ],\n },\n primaryType: 'TransferWithAuthorization',\n message: {\n from: signer.address,\n to: selected.payTo,\n value: BigInt(selected.amount),\n validAfter: 0n,\n validBefore: BigInt(deadline),\n nonce,\n },\n })\n\n return {\n t402Version: req.t402Version,\n resource: req.resource,\n accepted: selected,\n payload: {\n signature,\n from: signer.address,\n validAfter: '0',\n validBefore: deadline.toString(),\n nonce,\n },\n }\n }\n\n return { signers, paymentHandler }\n}\n\n/**\n * Get chain name from CAIP-2 network identifier.\n */\nfunction getChainNameFromNetwork(wdk: T402WDK, network: string): string | undefined {\n for (const chain of wdk.getConfiguredChains()) {\n const config = wdk.getChainConfig(chain)\n if (config && config.network === network) {\n return chain\n }\n }\n return undefined\n}\n","/**\n * Facilitator + WDK Adapter\n *\n * Wraps a T402WDK wallet as a facilitator-compatible signer, enabling WDK\n * wallets to be used for on-chain settlement (verify + settle operations).\n */\n\nimport type { T402WDK } from '../t402wdk.js'\nimport type { WDKSigner } from '../signer.js'\n\n/**\n * Options for the facilitator WDK signer adapter.\n */\nexport interface FacilitatorWdkSignerOptions {\n /** Automatically settle payments after verification */\n autoSettle?: boolean\n /** Auto-bridge received payments to this chain (CAIP-2 network or chain name) */\n bridgeToMainChain?: string\n}\n\n/**\n * Facilitator-compatible signer backed by WDK.\n */\nexport interface FacilitatorWdkSigner {\n /** Wallet address on the target chain */\n address: string\n /** Sign a transaction for on-chain settlement */\n signTransaction: (tx: unknown) => Promise<string>\n /** Sign typed data (EIP-712) */\n signTypedData: (data: {\n domain: Record<string, unknown>\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n }) => Promise<string>\n /** Send a signed transaction */\n sendTransaction: (params: { to: string; value?: bigint; data?: string }) => Promise<string>\n}\n\n/**\n * Convert a T402WDK instance into a facilitator-compatible signer for a given chain.\n *\n * The returned signer can be used with `toFacilitatorEvmSigner()` or directly\n * with a `t402Facilitator` instance for on-chain payment verification and settlement.\n *\n * @param wdk - An initialized T402WDK instance\n * @param chain - Chain name (e.g., \"arbitrum\", \"base\")\n * @param options - Optional configuration\n * @returns A facilitator-compatible signer object\n *\n * @example\n * ```typescript\n * const signer = await toFacilitatorWdkSigner(wdk, 'arbitrum', {\n * autoSettle: true,\n * bridgeToMainChain: 'arbitrum',\n * });\n *\n * // Use the signer with the facilitator\n * console.log('Facilitator address:', signer.address);\n * ```\n */\nexport async function toFacilitatorWdkSigner(\n wdk: T402WDK,\n chain: string,\n options?: FacilitatorWdkSignerOptions,\n): Promise<FacilitatorWdkSigner> {\n // Get the WDK signer for the specified chain\n const wdkSigner: WDKSigner = await wdk.getSigner(chain)\n const address = wdkSigner.address\n\n return {\n address,\n\n async signTransaction(tx: unknown): Promise<string> {\n // For EVM chains, sign typed data if the tx is structured as EIP-712\n if (tx && typeof tx === 'object' && 'domain' in tx) {\n const typedData = tx as {\n domain: Record<string, unknown>\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n }\n return wdkSigner.signTypedData(typedData)\n }\n\n // For raw message signing, convert to string\n if (typeof tx === 'string') {\n return wdkSigner.signMessage(tx)\n }\n\n throw new Error('Unsupported transaction format for WDK facilitator signer')\n },\n\n async signTypedData(data: {\n domain: Record<string, unknown>\n types: Record<string, unknown>\n primaryType: string\n message: Record<string, unknown>\n }): Promise<string> {\n return wdkSigner.signTypedData(data)\n },\n\n async sendTransaction(params: { to: string; value?: bigint; data?: string }): Promise<string> {\n const result = await wdkSigner.sendTransaction({\n to: params.to as `0x${string}`,\n value: params.value,\n data: params.data,\n })\n\n // Auto-bridge if configured\n if (options?.bridgeToMainChain && options.bridgeToMainChain !== chain) {\n // Check balance on source chain\n const balance = await wdk.getUsdt0Balance(chain)\n if (balance > 0n) {\n try {\n await wdk.bridgeUsdt0({\n fromChain: chain,\n toChain: options.bridgeToMainChain,\n amount: balance,\n })\n } catch {\n // Bridge failure is non-fatal for the facilitator\n }\n }\n }\n\n return result.hash\n },\n }\n}\n\n/**\n * Create facilitator signers for all configured WDK chains.\n *\n * @param wdk - An initialized T402WDK instance\n * @param options - Optional configuration applied to all signers\n * @returns Map of chain name to facilitator signer\n *\n * @example\n * ```typescript\n * const signers = await createFacilitatorSigners(wdk, {\n * bridgeToMainChain: 'arbitrum',\n * });\n *\n * for (const [chain, signer] of signers) {\n * console.log(`${chain}: ${signer.address}`);\n * }\n * ```\n */\nexport async function createFacilitatorSigners(\n wdk: T402WDK,\n options?: FacilitatorWdkSignerOptions,\n): Promise<Map<string, FacilitatorWdkSigner>> {\n const chains = wdk.getConfiguredChains()\n const signers = new Map<string, FacilitatorWdkSigner>()\n\n const results = await Promise.allSettled(\n chains.map(async (chain) => {\n const signer = await toFacilitatorWdkSigner(wdk, chain, options)\n return { chain, signer }\n }),\n )\n\n for (const result of results) {\n if (result.status === 'fulfilled') {\n signers.set(result.value.chain, result.value.signer)\n }\n }\n\n return signers\n}\n","/**\n * SIWx + WDK Adapter\n *\n * Wraps a T402WDK wallet as a SIWx (Sign-In-With-X) signer, enabling\n * WDK wallets to sign CAIP-122 authentication messages.\n */\n\nimport type { T402WDK } from '../t402wdk.js'\n\n/**\n * SIWx signer interface, compatible with the SIWxSigner from @t402/extensions.\n */\nexport interface SIWxSigner {\n /** Wallet address */\n address: string\n /** Sign a personal message (EIP-191) */\n signMessage(message: string): Promise<string>\n /** Sign EIP-712 typed data */\n signTypedData(data: {\n domain: unknown\n types: unknown\n primaryType: string\n message: unknown\n }): Promise<string>\n}\n\n/**\n * Convert a T402WDK instance into a SIWx-compatible signer for a given chain.\n *\n * The returned signer implements the `SIWxSigner` interface used by\n * `@t402/extensions` for CAIP-122 Sign-In-With-X authentication flows.\n *\n * @param wdk - An initialized T402WDK instance\n * @param chain - Chain name (e.g., \"arbitrum\", \"base\")\n * @returns A SIWx-compatible signer\n *\n * @example\n * ```typescript\n * import { toSIWxSigner } from '@t402/wdk';\n * import { createSIWxPayload, encodeSIWxHeader } from '@t402/extensions';\n *\n * const siwxSigner = await toSIWxSigner(wdk, 'arbitrum');\n *\n * // Create and sign SIWx payload\n * const payload = await createSIWxPayload(serverExtension, siwxSigner);\n * const header = encodeSIWxHeader(payload);\n *\n * // Include in request\n * fetch(url, { headers: { 'X-T402-SIWx': header } });\n * ```\n */\nexport async function toSIWxSigner(wdk: T402WDK, chain: string): Promise<SIWxSigner> {\n const wdkSigner = await wdk.getSigner(chain)\n\n return {\n address: wdkSigner.address,\n\n async signMessage(message: string): Promise<string> {\n return wdkSigner.signMessage(message)\n },\n\n async signTypedData(data: {\n domain: unknown\n types: unknown\n primaryType: string\n message: unknown\n }): Promise<string> {\n return wdkSigner.signTypedData({\n domain: data.domain as Record<string, unknown>,\n types: data.types as Record<string, unknown>,\n primaryType: data.primaryType,\n message: data.message as Record<string, unknown>,\n })\n },\n }\n}\n\n/**\n * Create SIWx signers for all configured WDK chains.\n *\n * @param wdk - An initialized T402WDK instance\n * @returns Map of chain name to SIWx signer\n *\n * @example\n * ```typescript\n * const signers = await createSIWxSigners(wdk);\n * const arbSigner = signers.get('arbitrum');\n * ```\n */\nexport async function createSIWxSigners(wdk: T402WDK): Promise<Map<string, SIWxSigner>> {\n const chains = wdk.getConfiguredChains()\n const signers = new Map<string, SIWxSigner>()\n\n const results = await Promise.allSettled(\n chains.map(async (chain) => {\n const signer = await toSIWxSigner(wdk, chain)\n return { chain, signer }\n }),\n )\n\n for (const result of results) {\n if (result.status === 'fulfilled') {\n signers.set(result.value.chain, result.value.signer)\n }\n }\n\n return signers\n}\n"],"mappings":"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","names":[]}
|