@trustwallet/cli 0.18.0 → 0.19.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/automation-runner.d.ts +1 -1
- package/dist/automation-runner.d.ts.map +1 -1
- package/dist/commands/erc8183.d.ts.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/index.js +1141 -918
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -3237,10 +3237,10 @@ function getChainDomainId(chainKey) {
|
|
|
3237
3237
|
if (!entry) throw new Error(`Unsupported chain: ${chainKey}`);
|
|
3238
3238
|
return entry[1].id;
|
|
3239
3239
|
}
|
|
3240
|
-
function getExplorerTxUrl(chainKey,
|
|
3240
|
+
function getExplorerTxUrl(chainKey, hash) {
|
|
3241
3241
|
const chain2 = getChainById(chainKey);
|
|
3242
3242
|
if (!chain2) return "";
|
|
3243
|
-
return `${chain2.explorerUrl}/tx/${
|
|
3243
|
+
return `${chain2.explorerUrl}/tx/${hash}`;
|
|
3244
3244
|
}
|
|
3245
3245
|
function getSampleAccount(chainKey) {
|
|
3246
3246
|
return getChainById(chainKey)?.sampleAccount || "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
|
|
@@ -3344,6 +3344,9 @@ function classifyApiError(err) {
|
|
|
3344
3344
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3345
3345
|
}
|
|
3346
3346
|
if (err instanceof TwakNetworkError) {
|
|
3347
|
+
if (EXECUTION_REVERTED_RE.test(err.message)) {
|
|
3348
|
+
return { code: "TX_FAILED", message: err.message };
|
|
3349
|
+
}
|
|
3347
3350
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3348
3351
|
}
|
|
3349
3352
|
if (err instanceof TwakValidationError) {
|
|
@@ -3355,6 +3358,9 @@ function classifyApiError(err) {
|
|
|
3355
3358
|
}
|
|
3356
3359
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3357
3360
|
}
|
|
3361
|
+
if (err instanceof Error && EXECUTION_REVERTED_RE.test(err.message)) {
|
|
3362
|
+
return { code: "TX_FAILED", message: err.message };
|
|
3363
|
+
}
|
|
3358
3364
|
return null;
|
|
3359
3365
|
}
|
|
3360
3366
|
function classifyStorageError(err) {
|
|
@@ -3729,7 +3735,7 @@ async function fetchBalance(httpClient, assetId, address, currency = "USD") {
|
|
|
3729
3735
|
throw new BalanceError("NETWORK_ERROR", "Could not fetch balance. Please try again later.");
|
|
3730
3736
|
}
|
|
3731
3737
|
}
|
|
3732
|
-
var import_crypto, NATIVE_TOKEN_ADDRESS, SOLANA_NATIVE_ADDRESS, CHAINS, TESTNET_CHAINS, COMMON_TOKENS, NATIVE_SYMBOLS, CELO_NATIVE_ADDRESS, TwakError, TwakApiError, TwakNetworkError, TwakValidationError, CommandError, COMMON_ERROR_CODES, FS_ERRNO_CODES, SWAP_ERROR_CODES, SwapError, TRANSFER_ERROR_CODES, TransferError, WALLET_ERROR_CODES, WalletError, QUERY_ERROR_CODES, QueryError, BALANCE_ERROR_CODES, BalanceError, ALERT_ERROR_CODES, AlertError, ERC20_ERROR_CODES, Erc20Error, WATCH_ERROR_CODES, WatchError, AUTOMATION_ERROR_CODES, AutomationError, X402_ERROR_CODES, X402Error, RESOLVABLE_CHAINS, ALIASES, DECIMAL_AMOUNT_RE, UNSAFE_KEYS, NAMING_API, EVM_ADDRESS_RE, ERC20_TRANSFER_SIG, ZERO_ADDRESS, DEFAULT_GATEWAY_URL, DEFAULT_MARKET_URL, DEFAULT_TIMEOUT, DEFAULT_USER_AGENT, DEFAULT_X_ORIGIN, TwakHttpClient, ALLOWED_OFFRAMP_PROVIDERS, McpResponse;
|
|
3738
|
+
var import_crypto, NATIVE_TOKEN_ADDRESS, SOLANA_NATIVE_ADDRESS, CHAINS, TESTNET_CHAINS, COMMON_TOKENS, NATIVE_SYMBOLS, CELO_NATIVE_ADDRESS, TwakError, TwakApiError, TwakNetworkError, TwakValidationError, CommandError, COMMON_ERROR_CODES, EXECUTION_REVERTED_RE, FS_ERRNO_CODES, SWAP_ERROR_CODES, SwapError, TRANSFER_ERROR_CODES, TransferError, WALLET_ERROR_CODES, WalletError, QUERY_ERROR_CODES, QueryError, BALANCE_ERROR_CODES, BalanceError, ALERT_ERROR_CODES, AlertError, ERC20_ERROR_CODES, Erc20Error, WATCH_ERROR_CODES, WatchError, AUTOMATION_ERROR_CODES, AutomationError, X402_ERROR_CODES, X402Error, RESOLVABLE_CHAINS, ALIASES, DECIMAL_AMOUNT_RE, UNSAFE_KEYS, NAMING_API, EVM_ADDRESS_RE, ERC20_TRANSFER_SIG, ZERO_ADDRESS, DEFAULT_GATEWAY_URL, DEFAULT_MARKET_URL, DEFAULT_TIMEOUT, DEFAULT_USER_AGENT, DEFAULT_X_ORIGIN, TwakHttpClient, ALLOWED_OFFRAMP_PROVIDERS, McpResponse;
|
|
3733
3739
|
var init_dist = __esm({
|
|
3734
3740
|
"../core/dist/index.mjs"() {
|
|
3735
3741
|
"use strict";
|
|
@@ -4230,6 +4236,7 @@ var init_dist = __esm({
|
|
|
4230
4236
|
WALLET_AUTH_FAILED: "WALLET_AUTH_FAILED",
|
|
4231
4237
|
STORAGE_ERROR: "STORAGE_ERROR"
|
|
4232
4238
|
};
|
|
4239
|
+
EXECUTION_REVERTED_RE = /\bexecution reverted\b/i;
|
|
4233
4240
|
FS_ERRNO_CODES = /* @__PURE__ */ new Set([
|
|
4234
4241
|
"EACCES",
|
|
4235
4242
|
"EEXIST",
|
|
@@ -6772,13 +6779,47 @@ function patchNodeStubs() {
|
|
|
6772
6779
|
if (resolvedUrl.includes("gateway.us.trustwallet.com")) {
|
|
6773
6780
|
resolvedUrl = resolvedUrl.replace("gateway.us.trustwallet.com", "tws.trustwallet.com");
|
|
6774
6781
|
}
|
|
6782
|
+
let finalInput = input2;
|
|
6775
6783
|
if (resolvedUrl !== url) {
|
|
6776
|
-
|
|
6777
|
-
return originalFetch(finalInput, init3);
|
|
6784
|
+
finalInput = typeof input2 === "string" ? resolvedUrl : input2 instanceof URL ? new URL(resolvedUrl) : new Request(resolvedUrl, input2);
|
|
6778
6785
|
}
|
|
6779
|
-
|
|
6786
|
+
const bodyText = typeof init3?.body === "string" ? init3.body : init3?.body instanceof Uint8Array ? new TextDecoder().decode(init3.body) : void 0;
|
|
6787
|
+
if (bodyText && /"method":"eth_(call|estimateGas|sendRawTransaction)"/.test(bodyText)) {
|
|
6788
|
+
return originalFetch(finalInput, init3).then(appendRpcRevertData);
|
|
6789
|
+
}
|
|
6790
|
+
return originalFetch(finalInput, init3);
|
|
6780
6791
|
};
|
|
6781
6792
|
}
|
|
6793
|
+
function revertDataSuffix(message, data) {
|
|
6794
|
+
return typeof data === "string" && /^0x[0-9a-fA-F]+$/.test(data) && !message.includes(data) ? `: ${data}` : "";
|
|
6795
|
+
}
|
|
6796
|
+
async function appendRpcRevertData(response) {
|
|
6797
|
+
const text = await response.text();
|
|
6798
|
+
let body = text;
|
|
6799
|
+
if (text.includes('"error"') && text.includes('"data":"0x')) {
|
|
6800
|
+
try {
|
|
6801
|
+
const json = JSON.parse(text);
|
|
6802
|
+
const error2 = json.error;
|
|
6803
|
+
if (error2 && typeof error2.message === "string") {
|
|
6804
|
+
const suffix = revertDataSuffix(error2.message, error2.data);
|
|
6805
|
+
if (suffix) {
|
|
6806
|
+
error2.message = `${error2.message}${suffix}`;
|
|
6807
|
+
body = JSON.stringify(json);
|
|
6808
|
+
}
|
|
6809
|
+
}
|
|
6810
|
+
} catch {
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
const headers = new Headers(response.headers);
|
|
6814
|
+
if (body !== text) {
|
|
6815
|
+
headers.delete("content-length");
|
|
6816
|
+
}
|
|
6817
|
+
return new Response(body === "" ? null : body, {
|
|
6818
|
+
status: response.status,
|
|
6819
|
+
statusText: response.statusText,
|
|
6820
|
+
headers
|
|
6821
|
+
});
|
|
6822
|
+
}
|
|
6782
6823
|
function patchNaasSession(sessionId) {
|
|
6783
6824
|
if (naasSessionPatched) return;
|
|
6784
6825
|
naasSessionPatched = true;
|
|
@@ -7008,11 +7049,11 @@ function humanAmountToWei(amount, decimals = 18) {
|
|
|
7008
7049
|
const frac = parts[1].padEnd(decimals, "0").slice(0, decimals);
|
|
7009
7050
|
return whole * 10n ** BigInt(decimals) + BigInt(frac);
|
|
7010
7051
|
}
|
|
7011
|
-
function createPendingTransaction(client, chainKey,
|
|
7052
|
+
function createPendingTransaction(client, chainKey, hash) {
|
|
7012
7053
|
return {
|
|
7013
|
-
|
|
7054
|
+
hash,
|
|
7014
7055
|
chainKey,
|
|
7015
|
-
wait: (opts) => client.waitForReceipt(chainKey,
|
|
7056
|
+
wait: (opts) => client.waitForReceipt(chainKey, hash, opts)
|
|
7016
7057
|
};
|
|
7017
7058
|
}
|
|
7018
7059
|
function bscSponsoredBaseUrl() {
|
|
@@ -7433,7 +7474,7 @@ var init_dist3 = __esm({
|
|
|
7433
7474
|
* `receiptTimeoutMs` config when set, otherwise the global constants
|
|
7434
7475
|
* (1.5s poll, 60s timeout). Caller-supplied opts override both.
|
|
7435
7476
|
*/
|
|
7436
|
-
async waitForReceipt(chainKey,
|
|
7477
|
+
async waitForReceipt(chainKey, hash, opts) {
|
|
7437
7478
|
const { chain: chain2, chainConfig } = chainKeyToDefinedChain(chainKey);
|
|
7438
7479
|
if (chainConfig?.namespace && chainConfig.namespace !== "eip155") {
|
|
7439
7480
|
throw new TwakValidationError(
|
|
@@ -7459,15 +7500,15 @@ var init_dist3 = __esm({
|
|
|
7459
7500
|
const deadline = Date.now() + timeoutMs;
|
|
7460
7501
|
while (Date.now() < deadline) {
|
|
7461
7502
|
const remainingMs = Math.max(1, deadline - Date.now());
|
|
7462
|
-
const result = await this.postJsonRpc(rpcUrl, "eth_getTransactionReceipt", [
|
|
7503
|
+
const result = await this.postJsonRpc(rpcUrl, "eth_getTransactionReceipt", [hash], {
|
|
7463
7504
|
timeoutMs: Math.min(RPC_TIMEOUT_MS, remainingMs)
|
|
7464
7505
|
});
|
|
7465
7506
|
const receipt = result ?? null;
|
|
7466
7507
|
if (receipt) return receipt;
|
|
7467
7508
|
await new Promise((resolve2) => setTimeout(resolve2, pollMs));
|
|
7468
7509
|
}
|
|
7469
|
-
throw new TwakNetworkError(`Timed out waiting for receipt ${
|
|
7470
|
-
|
|
7510
|
+
throw new TwakNetworkError(`Timed out waiting for receipt ${hash} on ${chainKey}`, {
|
|
7511
|
+
hash,
|
|
7471
7512
|
chainKey
|
|
7472
7513
|
});
|
|
7473
7514
|
}
|
|
@@ -7558,13 +7599,13 @@ var init_dist3 = __esm({
|
|
|
7558
7599
|
currency: chainKey
|
|
7559
7600
|
};
|
|
7560
7601
|
}
|
|
7561
|
-
async findTransactionStatus(chainKey, address,
|
|
7602
|
+
async findTransactionStatus(chainKey, address, hash) {
|
|
7562
7603
|
const coinId = chainKeyToCoinType(chainKey);
|
|
7563
7604
|
if (coinId === void 0) throw new Error(`Unsupported chain: ${chainKey}`);
|
|
7564
7605
|
const account = this.createAccountForAddress(coinId, address);
|
|
7565
7606
|
let result;
|
|
7566
7607
|
try {
|
|
7567
|
-
result = await import_trust_sdk2.BlockchainService.findTransaction(account,
|
|
7608
|
+
result = await import_trust_sdk2.BlockchainService.findTransaction(account, hash);
|
|
7568
7609
|
} catch {
|
|
7569
7610
|
return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
|
|
7570
7611
|
}
|
|
@@ -7986,7 +8027,9 @@ var init_dist3 = __esm({
|
|
|
7986
8027
|
);
|
|
7987
8028
|
}
|
|
7988
8029
|
if (json.error) {
|
|
7989
|
-
|
|
8030
|
+
const { message, data } = json.error;
|
|
8031
|
+
const suffix = revertDataSuffix(message, data);
|
|
8032
|
+
throw new TwakNetworkError(`RPC error on ${method}: ${message}${suffix}`, {
|
|
7990
8033
|
method,
|
|
7991
8034
|
rpcUrl,
|
|
7992
8035
|
rpcError: json.error
|
|
@@ -8294,7 +8337,7 @@ var init_dist3 = __esm({
|
|
|
8294
8337
|
serializedMessage: params.data,
|
|
8295
8338
|
hdWallet
|
|
8296
8339
|
});
|
|
8297
|
-
return result2.
|
|
8340
|
+
return result2.hash;
|
|
8298
8341
|
}
|
|
8299
8342
|
if (hasCalldata || hasValue) {
|
|
8300
8343
|
const result2 = await this.blockchainClient.executeContract({
|
|
@@ -8305,7 +8348,7 @@ var init_dist3 = __esm({
|
|
|
8305
8348
|
hdWallet,
|
|
8306
8349
|
chainKey
|
|
8307
8350
|
});
|
|
8308
|
-
return result2.
|
|
8351
|
+
return result2.hash;
|
|
8309
8352
|
}
|
|
8310
8353
|
const result = await this.blockchainClient.transfer({
|
|
8311
8354
|
assetId,
|
|
@@ -8314,7 +8357,7 @@ var init_dist3 = __esm({
|
|
|
8314
8357
|
hdWallet,
|
|
8315
8358
|
chainKey
|
|
8316
8359
|
});
|
|
8317
|
-
return result.
|
|
8360
|
+
return result.hash;
|
|
8318
8361
|
}
|
|
8319
8362
|
supportsChain(chainId) {
|
|
8320
8363
|
return isChainSupported(chainId);
|
|
@@ -40603,762 +40646,139 @@ init_dist2();
|
|
|
40603
40646
|
var import_chalk6 = __toESM(require_source());
|
|
40604
40647
|
init_dist();
|
|
40605
40648
|
|
|
40606
|
-
//
|
|
40607
|
-
|
|
40608
|
-
|
|
40609
|
-
|
|
40610
|
-
|
|
40611
|
-
|
|
40612
|
-
|
|
40613
|
-
|
|
40614
|
-
|
|
40615
|
-
|
|
40616
|
-
|
|
40617
|
-
|
|
40618
|
-
" @@@@@@@@@@@@@@@@********++++++++ ",
|
|
40619
|
-
" @@@@@@@@@@@@@@@@**************++ ",
|
|
40620
|
-
" @@@@@@@@@@@@@@@@#####*********** ",
|
|
40621
|
-
" @@@@@@@@@@@@@@@###########**** ",
|
|
40622
|
-
" @@@@@@@@@@@@@@%############## ",
|
|
40623
|
-
" @@@@@@@@@@@@@@%%%%%%%####### ",
|
|
40624
|
-
" @@@@@@@@@@@@@%%%%%%%%%%%%% ",
|
|
40625
|
-
" @@@@@@@@@@@%%%%%%%%%%% ",
|
|
40626
|
-
" @@@@@@@@@@@@@%%%%% ",
|
|
40627
|
-
" @@@@@@@@@@@@@@ ",
|
|
40628
|
-
" @@@@@@@@@@ ",
|
|
40629
|
-
" @@ "
|
|
40630
|
-
];
|
|
40631
|
-
function printBanner(version3) {
|
|
40632
|
-
const logo = SHIELD.map((l4) => import_chalk5.default.green(l4)).join("\n");
|
|
40633
|
-
const title = import_chalk5.default.green.bold(" Trust Wallet Agent Kit");
|
|
40634
|
-
const ver = import_chalk5.default.dim(` v${version3}`);
|
|
40635
|
-
console.log(
|
|
40636
|
-
boxen(`${logo}
|
|
40637
|
-
|
|
40638
|
-
${title}
|
|
40639
|
-
${ver}`, {
|
|
40640
|
-
borderColor: "green",
|
|
40641
|
-
borderStyle: "round",
|
|
40642
|
-
padding: { top: 1, bottom: 1, left: 2, right: 2 }
|
|
40643
|
-
})
|
|
40644
|
-
);
|
|
40649
|
+
// ../contracts/dist/index.mjs
|
|
40650
|
+
init_dist();
|
|
40651
|
+
init_dist();
|
|
40652
|
+
init_dist();
|
|
40653
|
+
init_dist();
|
|
40654
|
+
init_dist3();
|
|
40655
|
+
init_dist();
|
|
40656
|
+
init_dist();
|
|
40657
|
+
init_dist();
|
|
40658
|
+
var HEX_PATTERN = /^0x[0-9a-fA-F]*$/;
|
|
40659
|
+
function isHex(value) {
|
|
40660
|
+
return HEX_PATTERN.test(value);
|
|
40645
40661
|
}
|
|
40646
|
-
function
|
|
40647
|
-
|
|
40648
|
-
|
|
40649
|
-
|
|
40650
|
-
|
|
40651
|
-
|
|
40662
|
+
function hexToBytes3(hex2) {
|
|
40663
|
+
if (!isHex(hex2)) {
|
|
40664
|
+
throw new TwakValidationError(`Invalid hex string: ${hex2}`, { kind: "invalidHex" });
|
|
40665
|
+
}
|
|
40666
|
+
const clean2 = hex2.slice(2);
|
|
40667
|
+
if (clean2.length % 2 !== 0) {
|
|
40668
|
+
throw new TwakValidationError(`Hex string has odd length: ${hex2}`, { kind: "invalidHex" });
|
|
40669
|
+
}
|
|
40670
|
+
const out = new Uint8Array(clean2.length / 2);
|
|
40671
|
+
for (let i2 = 0; i2 < out.length; i2++) {
|
|
40672
|
+
out[i2] = parseInt(clean2.slice(i2 * 2, i2 * 2 + 2), 16);
|
|
40673
|
+
}
|
|
40674
|
+
return out;
|
|
40652
40675
|
}
|
|
40653
|
-
|
|
40654
|
-
|
|
40655
|
-
|
|
40656
|
-
|
|
40657
|
-
const qrcode = require("qrcode-terminal");
|
|
40658
|
-
let result = "";
|
|
40659
|
-
qrcode.generate(address, { small: true }, (code2) => {
|
|
40660
|
-
result = code2;
|
|
40661
|
-
});
|
|
40662
|
-
return result;
|
|
40663
|
-
} catch {
|
|
40664
|
-
return "";
|
|
40676
|
+
function bytesToHex3(bytes) {
|
|
40677
|
+
let out = "0x";
|
|
40678
|
+
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
40679
|
+
out += bytes[i2].toString(16).padStart(2, "0");
|
|
40665
40680
|
}
|
|
40681
|
+
return out;
|
|
40666
40682
|
}
|
|
40667
|
-
function
|
|
40668
|
-
const
|
|
40669
|
-
|
|
40670
|
-
|
|
40671
|
-
|
|
40672
|
-
|
|
40673
|
-
|
|
40674
|
-
|
|
40675
|
-
|
|
40676
|
-
}
|
|
40677
|
-
await ensureTrustSDK();
|
|
40678
|
-
const store = new WalletConfigStore();
|
|
40679
|
-
if (await store.exists()) {
|
|
40680
|
-
throw new WalletError(
|
|
40681
|
-
"WALLET_EXISTS",
|
|
40682
|
-
"Wallet already exists. Back up ~/.twak/wallet.json, then delete it to create a new one."
|
|
40683
|
-
);
|
|
40684
|
-
}
|
|
40685
|
-
const provider = await AgentWalletProvider.create(opts.password);
|
|
40686
|
-
const addresses = await provider.getAddresses();
|
|
40687
|
-
if (opts.keychain !== false) {
|
|
40688
|
-
const kc2 = new KeychainManager();
|
|
40689
|
-
if (kc2.isAvailable()) {
|
|
40690
|
-
await kc2.saveWalletPassword(opts.password);
|
|
40691
|
-
if (!opts.json) info("Password saved to OS keychain (use --no-keychain to skip)");
|
|
40692
|
-
}
|
|
40693
|
-
}
|
|
40694
|
-
if (!opts.json) success("Agent wallet created successfully");
|
|
40695
|
-
try {
|
|
40696
|
-
const creds = await getCredentials();
|
|
40697
|
-
await registerWalletWithBackend(creds, provider);
|
|
40698
|
-
if (!opts.json) info("Wallet registered with backend");
|
|
40699
|
-
} catch {
|
|
40700
|
-
if (!opts.json) warn("Backend registration failed (holdings may be limited)");
|
|
40701
|
-
}
|
|
40702
|
-
if (opts.json) {
|
|
40703
|
-
output({ addresses }, true);
|
|
40704
|
-
} else {
|
|
40705
|
-
info(`Generated addresses for ${addresses.length} chains`);
|
|
40706
|
-
}
|
|
40707
|
-
} catch (err) {
|
|
40708
|
-
handleCommandError(err, opts.json, "Wallet creation failed");
|
|
40709
|
-
}
|
|
40710
|
-
safeExit();
|
|
40711
|
-
});
|
|
40712
|
-
wallet.command("address").description("Get wallet address for a chain").requiredOption("--chain <key>", "Chain key (e.g., ethereum, solana)").option(
|
|
40713
|
-
"--password <password>",
|
|
40714
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
40715
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
40716
|
-
try {
|
|
40717
|
-
if (!getChainById(opts.chain)) {
|
|
40718
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
40719
|
-
}
|
|
40720
|
-
await ensureTrustSDK();
|
|
40721
|
-
const password3 = await resolvePassword(opts);
|
|
40722
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
40723
|
-
const address = await provider.getAddress(opts.chain);
|
|
40724
|
-
if (opts.json) {
|
|
40725
|
-
output({ chain: opts.chain, address }, true);
|
|
40726
|
-
} else {
|
|
40727
|
-
const qr3 = getQRString(address);
|
|
40728
|
-
const content = `${import_chalk6.default.dim("Chain")} ${import_chalk6.default.bold(opts.chain)}
|
|
40729
|
-
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
40730
|
-
|
|
40731
|
-
${qr3}`;
|
|
40732
|
-
console.log(box(content));
|
|
40733
|
-
}
|
|
40734
|
-
} catch (err) {
|
|
40735
|
-
handleCommandError(err, opts.json, "Wallet address failed");
|
|
40736
|
-
}
|
|
40737
|
-
safeExit();
|
|
40738
|
-
});
|
|
40739
|
-
wallet.command("addresses").description("List all wallet addresses").option(
|
|
40740
|
-
"--password <password>",
|
|
40741
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
40742
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
40743
|
-
try {
|
|
40744
|
-
await ensureTrustSDK();
|
|
40745
|
-
const password3 = await resolvePassword(opts);
|
|
40746
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
40747
|
-
const addresses = await provider.getAddresses();
|
|
40748
|
-
if (opts.json) {
|
|
40749
|
-
output({ addresses }, true);
|
|
40750
|
-
} else {
|
|
40751
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
40752
|
-
for (const addr of addresses) {
|
|
40753
|
-
const chains = grouped.get(addr.address) ?? [];
|
|
40754
|
-
chains.push(addr.chainId);
|
|
40755
|
-
grouped.set(addr.address, chains);
|
|
40756
|
-
}
|
|
40757
|
-
for (const [address, chains] of grouped) {
|
|
40758
|
-
const qr3 = getQRString(address);
|
|
40759
|
-
const maxWidth = Math.max(address.length + 9, 50);
|
|
40760
|
-
const chainLabel = `${import_chalk6.default.dim("Chains")} `;
|
|
40761
|
-
const chainLabelLen = 9;
|
|
40762
|
-
const chainLines = [];
|
|
40763
|
-
let line = "";
|
|
40764
|
-
for (const c3 of chains) {
|
|
40765
|
-
const sep2 = line ? ", " : "";
|
|
40766
|
-
if (line && line.length + sep2.length + c3.length + chainLabelLen > maxWidth) {
|
|
40767
|
-
chainLines.push(line);
|
|
40768
|
-
line = c3;
|
|
40769
|
-
} else {
|
|
40770
|
-
line += sep2 + c3;
|
|
40771
|
-
}
|
|
40772
|
-
}
|
|
40773
|
-
if (line) chainLines.push(line);
|
|
40774
|
-
const chainsStr = chainLines.map((l4, i2) => (i2 === 0 ? chainLabel : " ".repeat(chainLabelLen)) + import_chalk6.default.bold(l4)).join("\n");
|
|
40775
|
-
const content = `${chainsStr}
|
|
40776
|
-
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
40777
|
-
|
|
40778
|
-
${qr3}`;
|
|
40779
|
-
console.log(box(content));
|
|
40780
|
-
}
|
|
40781
|
-
}
|
|
40782
|
-
} catch (err) {
|
|
40783
|
-
handleCommandError(err, opts.json, "Wallet addresses failed");
|
|
40683
|
+
function hexOrUtf8ToBytesHex(value) {
|
|
40684
|
+
const looksHex = value.length >= 2 && value[0] === "0" && (value[1] === "x" || value[1] === "X");
|
|
40685
|
+
if (looksHex) {
|
|
40686
|
+
const canonical = "0x" + value.slice(2);
|
|
40687
|
+
if (!isHex(canonical)) {
|
|
40688
|
+
throw new TwakValidationError(
|
|
40689
|
+
`Value starts with "0x" but is not valid hex: ${value}. Use only [0-9a-fA-F] characters, or drop the "0x" prefix to send a UTF-8 string.`,
|
|
40690
|
+
{ kind: "invalidHex" }
|
|
40691
|
+
);
|
|
40784
40692
|
}
|
|
40785
|
-
|
|
40786
|
-
|
|
40787
|
-
|
|
40788
|
-
|
|
40789
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
40790
|
-
).option("--no-tokens", "Skip token balance lookup").option("--json", "JSON output").action(async (opts) => {
|
|
40791
|
-
try {
|
|
40792
|
-
if (opts.all && opts.chain) {
|
|
40793
|
-
throw new WalletError("VALIDATION_ERROR", "--all and --chain are mutually exclusive");
|
|
40794
|
-
}
|
|
40795
|
-
if (!opts.all && !opts.chain) {
|
|
40796
|
-
throw new WalletError("VALIDATION_ERROR", "Provide --chain <key> or --all");
|
|
40797
|
-
}
|
|
40798
|
-
await ensureTrustSDK();
|
|
40799
|
-
const password3 = await resolvePassword(opts);
|
|
40800
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
40801
|
-
const httpClient = await getClient();
|
|
40802
|
-
if (!opts.all) {
|
|
40803
|
-
const chain2 = getChainById(opts.chain);
|
|
40804
|
-
if (!chain2) {
|
|
40805
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
40806
|
-
}
|
|
40807
|
-
}
|
|
40808
|
-
const allAddresses = await provider.getAddresses();
|
|
40809
|
-
const addressMap = /* @__PURE__ */ new Map();
|
|
40810
|
-
for (const a3 of allAddresses) addressMap.set(a3.chainId, a3.address);
|
|
40811
|
-
const requestedChains = opts.all ? Object.keys(CHAINS) : [opts.chain];
|
|
40812
|
-
const skipTokens = opts.tokens === false;
|
|
40813
|
-
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
40814
|
-
const chain2 = getChainById(chainKey);
|
|
40815
|
-
const address = addressMap.get(chainKey);
|
|
40816
|
-
if (!chain2 || !address) return [];
|
|
40817
|
-
return [{ chainKey, chain: chain2, address }];
|
|
40818
|
-
});
|
|
40819
|
-
if (!opts.all && chainEntries.length === 0) {
|
|
40820
|
-
throw new WalletError(
|
|
40821
|
-
"CHAIN_UNSUPPORTED",
|
|
40822
|
-
`Wallet does not have an address for chain: ${opts.chain}`
|
|
40823
|
-
);
|
|
40824
|
-
}
|
|
40825
|
-
const nativeAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
40826
|
-
chainKey,
|
|
40827
|
-
chain: chain2,
|
|
40828
|
-
token: void 0,
|
|
40829
|
-
assetId: `c${chain2.coinId}`,
|
|
40830
|
-
userAddress: address
|
|
40831
|
-
}));
|
|
40832
|
-
const tokenAssets = skipTokens ? [] : chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
40833
|
-
const knownTokens = COMMON_TOKENS[chainKey];
|
|
40834
|
-
if (!knownTokens) return [];
|
|
40835
|
-
return Object.keys(knownTokens).flatMap((sym) => {
|
|
40836
|
-
const resolved = resolveToken(sym, chainKey);
|
|
40837
|
-
if (!resolved) return [];
|
|
40838
|
-
return [
|
|
40839
|
-
{
|
|
40840
|
-
chainKey,
|
|
40841
|
-
chain: chain2,
|
|
40842
|
-
token: { ...resolved, symbol: sym },
|
|
40843
|
-
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
40844
|
-
userAddress: address
|
|
40845
|
-
}
|
|
40846
|
-
];
|
|
40847
|
-
});
|
|
40848
|
-
});
|
|
40849
|
-
const allAssets = [...nativeAssets, ...tokenAssets];
|
|
40850
|
-
const balances = await fetchBalances(
|
|
40851
|
-
httpClient,
|
|
40852
|
-
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
40693
|
+
if ((canonical.length - 2) % 2 !== 0) {
|
|
40694
|
+
throw new TwakValidationError(
|
|
40695
|
+
`Hex value has odd length: ${value}. Solidity bytes must be byte-aligned.`,
|
|
40696
|
+
{ kind: "invalidHex" }
|
|
40853
40697
|
);
|
|
40854
|
-
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
40855
|
-
const resultsByChain = /* @__PURE__ */ new Map();
|
|
40856
|
-
for (const { chainKey, chain: chain2, address } of chainEntries) {
|
|
40857
|
-
resultsByChain.set(chainKey, {
|
|
40858
|
-
chain: chainKey,
|
|
40859
|
-
address,
|
|
40860
|
-
symbol: chain2.symbol,
|
|
40861
|
-
available: "0",
|
|
40862
|
-
total: "0",
|
|
40863
|
-
totalUsd: null,
|
|
40864
|
-
tokens: []
|
|
40865
|
-
});
|
|
40866
|
-
}
|
|
40867
|
-
for (const balance of balances) {
|
|
40868
|
-
const assetInfo = assetsById.get(balance.assetId);
|
|
40869
|
-
if (!assetInfo) {
|
|
40870
|
-
throw new WalletError(
|
|
40871
|
-
"NETWORK_ERROR",
|
|
40872
|
-
"Could not fetch balances. Please try again later."
|
|
40873
|
-
);
|
|
40874
|
-
}
|
|
40875
|
-
const result = resultsByChain.get(assetInfo.chainKey);
|
|
40876
|
-
if (!result) continue;
|
|
40877
|
-
const { token, chain: chain2 } = assetInfo;
|
|
40878
|
-
const amts = balance.amounts;
|
|
40879
|
-
if (token) {
|
|
40880
|
-
const human = formatAmount(amts.total ?? "0", token.decimals);
|
|
40881
|
-
if (human !== "0") {
|
|
40882
|
-
result.tokens.push({
|
|
40883
|
-
symbol: token.symbol,
|
|
40884
|
-
contract: token.address,
|
|
40885
|
-
balance: human
|
|
40886
|
-
});
|
|
40887
|
-
}
|
|
40888
|
-
} else {
|
|
40889
|
-
result.available = formatAmount(amts.available ?? "0", chain2.decimals);
|
|
40890
|
-
result.total = formatAmount(amts.total ?? "0", chain2.decimals);
|
|
40891
|
-
const lockedHuman = formatAmount(amts.locked ?? "0", chain2.decimals);
|
|
40892
|
-
if (lockedHuman !== "0") result.staked = lockedHuman;
|
|
40893
|
-
const fiat = amts.totalInFiat;
|
|
40894
|
-
result.totalUsd = fiat && fiat !== "" ? parseFloat(fiat) : null;
|
|
40895
|
-
}
|
|
40896
|
-
}
|
|
40897
|
-
const orderedResults = chainEntries.map((e2) => resultsByChain.get(e2.chainKey)).filter((r3) => r3 !== void 0);
|
|
40898
|
-
const visible = opts.all ? orderedResults.filter((r3) => r3.total !== "0" || r3.tokens.length > 0) : orderedResults;
|
|
40899
|
-
const renderBlock = (r3, withSeparator) => {
|
|
40900
|
-
if (withSeparator) console.log("");
|
|
40901
|
-
console.log(import_chalk6.default.bold.underline(`${r3.chain} (${r3.symbol})`));
|
|
40902
|
-
console.log(` ${import_chalk6.default.dim("Address")} ${r3.address}`);
|
|
40903
|
-
console.log(` ${import_chalk6.default.dim("Available")} ${r3.available}`);
|
|
40904
|
-
if (r3.staked) console.log(` ${import_chalk6.default.dim("Staked")} ${r3.staked}`);
|
|
40905
|
-
const usdSuffix = r3.totalUsd !== null ? ` (\u2248 $${r3.totalUsd.toFixed(2)})` : "";
|
|
40906
|
-
console.log(` ${import_chalk6.default.dim("Total")} ${r3.total}${usdSuffix}`);
|
|
40907
|
-
if (r3.tokens.length > 0) {
|
|
40908
|
-
console.log(` ${import_chalk6.default.dim("Tokens:")}`);
|
|
40909
|
-
for (const t of r3.tokens) {
|
|
40910
|
-
console.log(` ${import_chalk6.default.bold(t.symbol.padEnd(10))} ${t.balance}`);
|
|
40911
|
-
}
|
|
40912
|
-
}
|
|
40913
|
-
};
|
|
40914
|
-
if (opts.all) {
|
|
40915
|
-
if (opts.json) {
|
|
40916
|
-
output(visible, true);
|
|
40917
|
-
} else if (visible.length === 0) {
|
|
40918
|
-
info("No chains with non-zero native balance found.");
|
|
40919
|
-
} else {
|
|
40920
|
-
visible.forEach((r3, i2) => renderBlock(r3, i2 > 0));
|
|
40921
|
-
}
|
|
40922
|
-
} else {
|
|
40923
|
-
const single = visible[0];
|
|
40924
|
-
if (opts.json) {
|
|
40925
|
-
output(single, true);
|
|
40926
|
-
} else {
|
|
40927
|
-
renderBlock(single, false);
|
|
40928
|
-
}
|
|
40929
|
-
}
|
|
40930
|
-
} catch (err) {
|
|
40931
|
-
handleCommandError(err, opts.json, "Balance check failed");
|
|
40932
40698
|
}
|
|
40933
|
-
|
|
40934
|
-
}
|
|
40935
|
-
|
|
40936
|
-
|
|
40937
|
-
|
|
40938
|
-
|
|
40939
|
-
|
|
40940
|
-
|
|
40941
|
-
|
|
40942
|
-
|
|
40943
|
-
|
|
40944
|
-
|
|
40945
|
-
handleCommandError(err, opts.json, "Keychain save failed");
|
|
40699
|
+
return canonical;
|
|
40700
|
+
}
|
|
40701
|
+
return bytesToHex3(new TextEncoder().encode(value));
|
|
40702
|
+
}
|
|
40703
|
+
function wc2() {
|
|
40704
|
+
return getWalletCore();
|
|
40705
|
+
}
|
|
40706
|
+
var BRIDGE = {
|
|
40707
|
+
createAbiFunction(name2) {
|
|
40708
|
+
const ctor = wc2().EthereumAbiFunction;
|
|
40709
|
+
if (typeof ctor?.createWithString === "function") {
|
|
40710
|
+
return ctor.createWithString(name2);
|
|
40946
40711
|
}
|
|
40947
|
-
|
|
40712
|
+
return new ctor(name2);
|
|
40713
|
+
},
|
|
40714
|
+
encode(fn2) {
|
|
40715
|
+
return wc2().EthereumAbi.encode(fn2);
|
|
40716
|
+
},
|
|
40717
|
+
decodeOutput(fn2, data) {
|
|
40718
|
+
return wc2().EthereumAbi.decodeOutput(fn2, data);
|
|
40719
|
+
},
|
|
40720
|
+
keccak256(data) {
|
|
40721
|
+
return wc2().Hash.keccak256(data);
|
|
40722
|
+
}
|
|
40723
|
+
};
|
|
40724
|
+
function getAbiBridge() {
|
|
40725
|
+
return BRIDGE;
|
|
40726
|
+
}
|
|
40727
|
+
function findAbiFunction(abi, methodName, argCount) {
|
|
40728
|
+
const matches = abi.filter(
|
|
40729
|
+
(e2) => e2.type === "function" && e2.name === methodName
|
|
40730
|
+
);
|
|
40731
|
+
if (matches.length === 0) {
|
|
40732
|
+
throw new TwakValidationError(`Unknown ABI method: ${methodName}`, {
|
|
40733
|
+
kind: "unknownMethod",
|
|
40734
|
+
methodName
|
|
40735
|
+
});
|
|
40736
|
+
}
|
|
40737
|
+
if (matches.length === 1 || argCount === void 0) {
|
|
40738
|
+
return matches[0];
|
|
40739
|
+
}
|
|
40740
|
+
const byArity = matches.filter((m2) => m2.inputs.length === argCount);
|
|
40741
|
+
if (byArity.length === 1) {
|
|
40742
|
+
return byArity[0];
|
|
40743
|
+
}
|
|
40744
|
+
throw new TwakValidationError(`No unique ${methodName} overload taking ${argCount} argument(s)`, {
|
|
40745
|
+
kind: "unknownMethod",
|
|
40746
|
+
methodName
|
|
40948
40747
|
});
|
|
40949
|
-
|
|
40950
|
-
|
|
40951
|
-
|
|
40952
|
-
|
|
40953
|
-
|
|
40748
|
+
}
|
|
40749
|
+
function encodeFunctionCall(abi, methodName, args) {
|
|
40750
|
+
const fnDef = findAbiFunction(abi, methodName, args.length);
|
|
40751
|
+
if (args.length !== fnDef.inputs.length) {
|
|
40752
|
+
throw new TwakValidationError(
|
|
40753
|
+
`Wrong arg count for ${methodName}: expected ${fnDef.inputs.length}, got ${args.length}`,
|
|
40754
|
+
{
|
|
40755
|
+
kind: "wrongArgCount",
|
|
40756
|
+
methodName,
|
|
40757
|
+
expected: fnDef.inputs.length,
|
|
40758
|
+
actual: args.length
|
|
40954
40759
|
}
|
|
40955
|
-
|
|
40956
|
-
|
|
40957
|
-
|
|
40958
|
-
|
|
40959
|
-
|
|
40960
|
-
|
|
40760
|
+
);
|
|
40761
|
+
}
|
|
40762
|
+
if (encoderRequiresHandRoll(fnDef.inputs)) {
|
|
40763
|
+
return encodeFunctionCallHandRoll(methodName, fnDef.inputs, args);
|
|
40764
|
+
}
|
|
40765
|
+
const bridge = getAbiBridge();
|
|
40766
|
+
const fn2 = bridge.createAbiFunction(methodName);
|
|
40767
|
+
fnDef.inputs.forEach((param, i2) => {
|
|
40768
|
+
pushParam(fn2, param, args[i2], methodName);
|
|
40961
40769
|
});
|
|
40962
|
-
|
|
40963
|
-
|
|
40964
|
-
|
|
40965
|
-
|
|
40966
|
-
|
|
40967
|
-
|
|
40968
|
-
|
|
40969
|
-
|
|
40970
|
-
|
|
40971
|
-
|
|
40972
|
-
|
|
40973
|
-
|
|
40974
|
-
const pw = await kc2.getWalletPassword();
|
|
40975
|
-
if (opts.json) {
|
|
40976
|
-
output({ available: true, stored: !!pw }, true);
|
|
40977
|
-
} else if (pw) {
|
|
40978
|
-
success("Wallet password is stored in OS keychain");
|
|
40979
|
-
} else {
|
|
40980
|
-
info("No wallet password found in OS keychain");
|
|
40981
|
-
}
|
|
40982
|
-
} catch (err) {
|
|
40983
|
-
handleCommandError(err, opts.json, "Keychain check failed");
|
|
40984
|
-
}
|
|
40985
|
-
safeExit();
|
|
40986
|
-
});
|
|
40987
|
-
wallet.command("connect").description("Connect external wallet via WalletConnect").option("--project-id <id>", "WalletConnect project ID (or set WALLETCONNECT_PROJECT_ID)").option(
|
|
40988
|
-
"--chains <list>",
|
|
40989
|
-
"Comma-separated CAIP-2 chain IDs",
|
|
40990
|
-
"eip155:1,eip155:56,eip155:137,eip155:8453,eip155:42161"
|
|
40991
|
-
).option("--timeout <seconds>", "Connection timeout in seconds", "300").option("--json", "JSON output").action(async (opts) => {
|
|
40992
|
-
try {
|
|
40993
|
-
const projectId = opts.projectId || process.env.WALLETCONNECT_PROJECT_ID;
|
|
40994
|
-
if (!projectId) {
|
|
40995
|
-
throw new WalletError(
|
|
40996
|
-
"VALIDATION_ERROR",
|
|
40997
|
-
"WalletConnect project ID required. Use --project-id or set WALLETCONNECT_PROJECT_ID"
|
|
40998
|
-
);
|
|
40999
|
-
}
|
|
41000
|
-
const provider = new WalletConnectProvider({ projectId });
|
|
41001
|
-
const chains = opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
41002
|
-
info("Connecting via WalletConnect...");
|
|
41003
|
-
const result = await provider.connect(chains);
|
|
41004
|
-
const qr3 = getQRString(result.uri);
|
|
41005
|
-
if (qr3) {
|
|
41006
|
-
console.log(qr3);
|
|
41007
|
-
}
|
|
41008
|
-
info(`Trust Wallet: ${result.deepLinks.native}`);
|
|
41009
|
-
info(`Universal: ${result.deepLinks.universal}`);
|
|
41010
|
-
info("\nWaiting for wallet approval...");
|
|
41011
|
-
const timeoutMs = parseInt(opts.timeout, 10) * 1e3;
|
|
41012
|
-
const session = await provider.waitForSession(timeoutMs);
|
|
41013
|
-
if (opts.json) {
|
|
41014
|
-
output(
|
|
41015
|
-
{
|
|
41016
|
-
connected: true,
|
|
41017
|
-
address: session.address,
|
|
41018
|
-
chainId: session.chainId,
|
|
41019
|
-
peer: session.peerName
|
|
41020
|
-
},
|
|
41021
|
-
true
|
|
41022
|
-
);
|
|
41023
|
-
} else {
|
|
41024
|
-
success(`Connected to ${session.peerName || "wallet"}`);
|
|
41025
|
-
info(` Address: ${session.address}`);
|
|
41026
|
-
info(` Chain: ${session.chainId}`);
|
|
41027
|
-
}
|
|
41028
|
-
} catch (err) {
|
|
41029
|
-
handleCommandError(err, opts.json, "WalletConnect failed");
|
|
41030
|
-
}
|
|
41031
|
-
safeExit();
|
|
41032
|
-
});
|
|
41033
|
-
wallet.command("status").description("Check wallet configuration status").option("--json", "JSON output").action(async (opts) => {
|
|
41034
|
-
try {
|
|
41035
|
-
const store = new WalletConfigStore();
|
|
41036
|
-
const exists = await store.exists();
|
|
41037
|
-
const kc2 = new KeychainManager();
|
|
41038
|
-
const keychainHasPassword = kc2.isAvailable() ? !!await kc2.getWalletPassword() : false;
|
|
41039
|
-
const totalChains = Object.keys(CHAINS).length;
|
|
41040
|
-
let createdAt;
|
|
41041
|
-
let addressCount;
|
|
41042
|
-
if (exists) {
|
|
41043
|
-
const config = await store.getConfig();
|
|
41044
|
-
createdAt = config?.createdAt;
|
|
41045
|
-
addressCount = config?.chains?.length ?? totalChains;
|
|
41046
|
-
}
|
|
41047
|
-
const result = {
|
|
41048
|
-
agentWallet: exists ? "configured" : "not configured",
|
|
41049
|
-
keychainPassword: keychainHasPassword ? "stored" : "not stored",
|
|
41050
|
-
chains: totalChains,
|
|
41051
|
-
supportedChains: totalChains,
|
|
41052
|
-
...createdAt ? { createdAt } : {},
|
|
41053
|
-
...addressCount !== void 0 ? { addressCount } : {}
|
|
41054
|
-
};
|
|
41055
|
-
if (opts.json) {
|
|
41056
|
-
output(result, true);
|
|
41057
|
-
} else {
|
|
41058
|
-
console.log(
|
|
41059
|
-
` ${import_chalk6.default.dim("Wallet")} ${exists ? import_chalk6.default.green("configured") : import_chalk6.default.yellow("not configured")}`
|
|
41060
|
-
);
|
|
41061
|
-
if (createdAt) console.log(` ${import_chalk6.default.dim("Created")} ${createdAt}`);
|
|
41062
|
-
console.log(
|
|
41063
|
-
` ${import_chalk6.default.dim("Keychain")} ${keychainHasPassword ? import_chalk6.default.green("password stored") : import_chalk6.default.yellow("no password")}`
|
|
41064
|
-
);
|
|
41065
|
-
console.log(` ${import_chalk6.default.dim("Chains")} ${totalChains} supported`);
|
|
41066
|
-
if (addressCount !== void 0)
|
|
41067
|
-
console.log(` ${import_chalk6.default.dim("Addresses")} ${addressCount}`);
|
|
41068
|
-
if (!exists) info("\nRun `twak wallet create --password <pw>` to create a wallet.");
|
|
41069
|
-
}
|
|
41070
|
-
} catch (err) {
|
|
41071
|
-
handleCommandError(err, opts.json, "Status failed");
|
|
41072
|
-
}
|
|
41073
|
-
safeExit();
|
|
41074
|
-
});
|
|
41075
|
-
wallet.command("portfolio").description("Show portfolio balances and USD values across chains, including token holdings").option("--chains <list>", "Comma-separated chain keys (default: all supported chains)").option(
|
|
41076
|
-
"--password <password>",
|
|
41077
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
41078
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
41079
|
-
try {
|
|
41080
|
-
await ensureTrustSDK();
|
|
41081
|
-
const password3 = await resolvePassword(opts);
|
|
41082
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41083
|
-
const httpClient = await getClient();
|
|
41084
|
-
const allAddresses = await provider.getAddresses();
|
|
41085
|
-
const chainsArg = opts.chains ?? Object.keys(CHAINS).join(",");
|
|
41086
|
-
const requestedChains = chainsArg.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
41087
|
-
if (requestedChains.length === 0) {
|
|
41088
|
-
throw new WalletError("VALIDATION_ERROR", "--chains must include at least one chain key");
|
|
41089
|
-
}
|
|
41090
|
-
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
41091
|
-
const chain2 = getChainById(chainKey);
|
|
41092
|
-
const addrEntry = allAddresses.find((a3) => a3.chainId === chainKey);
|
|
41093
|
-
if (!chain2 || !addrEntry) return [];
|
|
41094
|
-
return [{ chainKey, chain: chain2, address: addrEntry.address }];
|
|
41095
|
-
});
|
|
41096
|
-
if (chainEntries.length === 0) {
|
|
41097
|
-
throw new WalletError(
|
|
41098
|
-
"CHAIN_UNSUPPORTED",
|
|
41099
|
-
`No supported chains found in --chains "${opts.chains}"`
|
|
41100
|
-
);
|
|
41101
|
-
}
|
|
41102
|
-
const chainAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
41103
|
-
chainKey,
|
|
41104
|
-
chain: chain2,
|
|
41105
|
-
token: void 0,
|
|
41106
|
-
assetId: `c${chain2.coinId}`,
|
|
41107
|
-
userAddress: address
|
|
41108
|
-
}));
|
|
41109
|
-
const tokenAssets = chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
41110
|
-
const knownTokens = COMMON_TOKENS[chainKey];
|
|
41111
|
-
if (!knownTokens) return [];
|
|
41112
|
-
return Object.keys(knownTokens).flatMap((sym) => {
|
|
41113
|
-
const resolved = resolveToken(sym, chainKey);
|
|
41114
|
-
if (!resolved) return [];
|
|
41115
|
-
return [
|
|
41116
|
-
{
|
|
41117
|
-
chainKey,
|
|
41118
|
-
chain: chain2,
|
|
41119
|
-
token: { ...resolved, symbol: sym },
|
|
41120
|
-
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
41121
|
-
userAddress: address
|
|
41122
|
-
}
|
|
41123
|
-
];
|
|
41124
|
-
});
|
|
41125
|
-
});
|
|
41126
|
-
const allAssets = [...chainAssets, ...tokenAssets];
|
|
41127
|
-
const balances = await fetchBalances(
|
|
41128
|
-
httpClient,
|
|
41129
|
-
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
41130
|
-
);
|
|
41131
|
-
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
41132
|
-
const allRows = [];
|
|
41133
|
-
for (const balance of balances) {
|
|
41134
|
-
const assetInfo = assetsById.get(balance.assetId);
|
|
41135
|
-
if (!assetInfo) {
|
|
41136
|
-
throw new WalletError(
|
|
41137
|
-
"NETWORK_ERROR",
|
|
41138
|
-
"Could not fetch balances. Please try again later."
|
|
41139
|
-
);
|
|
41140
|
-
}
|
|
41141
|
-
const { token, chain: chain2, chainKey, userAddress } = assetInfo;
|
|
41142
|
-
const decimals = token ? token.decimals : chain2.decimals;
|
|
41143
|
-
const symbol = token ? token.symbol ?? token.address : chain2.symbol;
|
|
41144
|
-
const isToken = token !== void 0;
|
|
41145
|
-
const humanAmount = formatAmount(balance.amounts.total, decimals);
|
|
41146
|
-
const fiatRaw = balance.amounts.totalInFiat;
|
|
41147
|
-
const usdValue = fiatRaw && fiatRaw !== "" ? parseFloat(fiatRaw) : null;
|
|
41148
|
-
allRows.push({
|
|
41149
|
-
chain: chainKey,
|
|
41150
|
-
type: isToken ? "token" : "native",
|
|
41151
|
-
symbol,
|
|
41152
|
-
address: userAddress,
|
|
41153
|
-
...token ? { contract: token.address } : {},
|
|
41154
|
-
balance: humanAmount,
|
|
41155
|
-
usdValue
|
|
41156
|
-
});
|
|
41157
|
-
}
|
|
41158
|
-
const rows = allRows.filter((r3) => r3.type === "native" || r3.balance !== "0");
|
|
41159
|
-
rows.sort((a3, b3) => {
|
|
41160
|
-
const chainCmp = String(a3.chain).localeCompare(String(b3.chain));
|
|
41161
|
-
if (chainCmp !== 0) return chainCmp;
|
|
41162
|
-
return String(a3.type).localeCompare(String(b3.type));
|
|
41163
|
-
});
|
|
41164
|
-
if (opts.json) {
|
|
41165
|
-
output(rows, true);
|
|
41166
|
-
} else {
|
|
41167
|
-
const totalUsd = rows.reduce(
|
|
41168
|
-
(sum, r3) => sum + (typeof r3.usdValue === "number" ? r3.usdValue : 0),
|
|
41169
|
-
0
|
|
41170
|
-
);
|
|
41171
|
-
console.log("Chain Type Symbol Balance USD");
|
|
41172
|
-
console.log("\u2500".repeat(72));
|
|
41173
|
-
for (const r3 of rows) {
|
|
41174
|
-
const usd = r3.usdValue !== null ? `$${r3.usdValue.toFixed(2)}` : "";
|
|
41175
|
-
console.log(
|
|
41176
|
-
`${String(r3.chain).padEnd(12)} ${String(r3.type).padEnd(7)} ${String(r3.symbol).padEnd(17)} ${String(r3.balance).padEnd(20)} ${usd}`
|
|
41177
|
-
);
|
|
41178
|
-
}
|
|
41179
|
-
console.log("\u2500".repeat(72));
|
|
41180
|
-
console.log(`Total USD: $${totalUsd.toFixed(2)}`);
|
|
41181
|
-
}
|
|
41182
|
-
} catch (err) {
|
|
41183
|
-
handleCommandError(err, opts.json, "Portfolio failed");
|
|
41184
|
-
}
|
|
41185
|
-
safeExit();
|
|
41186
|
-
});
|
|
41187
|
-
wallet.command("sign-message").description("Sign a message with the agent wallet").requiredOption("--chain <key>", "Chain key (e.g., ethereum, solana)").requiredOption("--message <text>", "Message to sign").option(
|
|
41188
|
-
"--password <password>",
|
|
41189
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
41190
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
41191
|
-
try {
|
|
41192
|
-
if (!getChainById(opts.chain)) {
|
|
41193
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
41194
|
-
}
|
|
41195
|
-
await ensureTrustSDK();
|
|
41196
|
-
const password3 = await resolvePassword(opts);
|
|
41197
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41198
|
-
const address = await provider.getAddress(opts.chain);
|
|
41199
|
-
const signature = await provider.signMessage(opts.chain, opts.message);
|
|
41200
|
-
output({ chain: opts.chain, address, message: opts.message, signature }, opts.json);
|
|
41201
|
-
} catch (err) {
|
|
41202
|
-
handleCommandError(err, opts.json, "Sign failed");
|
|
41203
|
-
}
|
|
41204
|
-
safeExit();
|
|
41205
|
-
});
|
|
41206
|
-
wallet.command("register").description("Register wallet addresses with Trust Wallet backend (enables token holdings)").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (opts) => {
|
|
41207
|
-
try {
|
|
41208
|
-
const creds = await ensureTrustSDK();
|
|
41209
|
-
const password3 = await resolvePassword(opts);
|
|
41210
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41211
|
-
await registerWalletWithBackend(creds, provider);
|
|
41212
|
-
if (!opts.json) success("Wallet registered with backend");
|
|
41213
|
-
const addresses = await provider.getAddresses();
|
|
41214
|
-
output({ registered: true, chains: addresses.length }, opts.json);
|
|
41215
|
-
} catch (err) {
|
|
41216
|
-
handleCommandError(err, opts.json, "Registration failed");
|
|
41217
|
-
}
|
|
41218
|
-
safeExit();
|
|
41219
|
-
});
|
|
41220
|
-
}
|
|
41221
|
-
|
|
41222
|
-
// src/commands/transfer.ts
|
|
41223
|
-
init_dist();
|
|
41224
|
-
|
|
41225
|
-
// ../swap/dist/index.mjs
|
|
41226
|
-
init_dist();
|
|
41227
|
-
init_dist();
|
|
41228
|
-
|
|
41229
|
-
// ../contracts/dist/index.mjs
|
|
41230
|
-
init_dist();
|
|
41231
|
-
init_dist();
|
|
41232
|
-
init_dist();
|
|
41233
|
-
init_dist();
|
|
41234
|
-
init_dist3();
|
|
41235
|
-
init_dist();
|
|
41236
|
-
init_dist();
|
|
41237
|
-
init_dist();
|
|
41238
|
-
var HEX_PATTERN = /^0x[0-9a-fA-F]*$/;
|
|
41239
|
-
function isHex(value) {
|
|
41240
|
-
return HEX_PATTERN.test(value);
|
|
41241
|
-
}
|
|
41242
|
-
function hexToBytes3(hex2) {
|
|
41243
|
-
if (!isHex(hex2)) {
|
|
41244
|
-
throw new TwakValidationError(`Invalid hex string: ${hex2}`, { kind: "invalidHex" });
|
|
41245
|
-
}
|
|
41246
|
-
const clean2 = hex2.slice(2);
|
|
41247
|
-
if (clean2.length % 2 !== 0) {
|
|
41248
|
-
throw new TwakValidationError(`Hex string has odd length: ${hex2}`, { kind: "invalidHex" });
|
|
41249
|
-
}
|
|
41250
|
-
const out = new Uint8Array(clean2.length / 2);
|
|
41251
|
-
for (let i2 = 0; i2 < out.length; i2++) {
|
|
41252
|
-
out[i2] = parseInt(clean2.slice(i2 * 2, i2 * 2 + 2), 16);
|
|
41253
|
-
}
|
|
41254
|
-
return out;
|
|
41255
|
-
}
|
|
41256
|
-
function bytesToHex3(bytes) {
|
|
41257
|
-
let out = "0x";
|
|
41258
|
-
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
41259
|
-
out += bytes[i2].toString(16).padStart(2, "0");
|
|
41260
|
-
}
|
|
41261
|
-
return out;
|
|
41262
|
-
}
|
|
41263
|
-
function hexOrUtf8ToBytesHex(value) {
|
|
41264
|
-
const looksHex = value.length >= 2 && value[0] === "0" && (value[1] === "x" || value[1] === "X");
|
|
41265
|
-
if (looksHex) {
|
|
41266
|
-
const canonical = "0x" + value.slice(2);
|
|
41267
|
-
if (!isHex(canonical)) {
|
|
41268
|
-
throw new TwakValidationError(
|
|
41269
|
-
`Value starts with "0x" but is not valid hex: ${value}. Use only [0-9a-fA-F] characters, or drop the "0x" prefix to send a UTF-8 string.`,
|
|
41270
|
-
{ kind: "invalidHex" }
|
|
41271
|
-
);
|
|
41272
|
-
}
|
|
41273
|
-
if ((canonical.length - 2) % 2 !== 0) {
|
|
41274
|
-
throw new TwakValidationError(
|
|
41275
|
-
`Hex value has odd length: ${value}. Solidity bytes must be byte-aligned.`,
|
|
41276
|
-
{ kind: "invalidHex" }
|
|
41277
|
-
);
|
|
41278
|
-
}
|
|
41279
|
-
return canonical;
|
|
41280
|
-
}
|
|
41281
|
-
return bytesToHex3(new TextEncoder().encode(value));
|
|
41282
|
-
}
|
|
41283
|
-
function wc2() {
|
|
41284
|
-
return getWalletCore();
|
|
41285
|
-
}
|
|
41286
|
-
var BRIDGE = {
|
|
41287
|
-
createAbiFunction(name2) {
|
|
41288
|
-
const ctor = wc2().EthereumAbiFunction;
|
|
41289
|
-
if (typeof ctor?.createWithString === "function") {
|
|
41290
|
-
return ctor.createWithString(name2);
|
|
41291
|
-
}
|
|
41292
|
-
return new ctor(name2);
|
|
41293
|
-
},
|
|
41294
|
-
encode(fn2) {
|
|
41295
|
-
return wc2().EthereumAbi.encode(fn2);
|
|
41296
|
-
},
|
|
41297
|
-
decodeOutput(fn2, data) {
|
|
41298
|
-
return wc2().EthereumAbi.decodeOutput(fn2, data);
|
|
41299
|
-
},
|
|
41300
|
-
keccak256(data) {
|
|
41301
|
-
return wc2().Hash.keccak256(data);
|
|
41302
|
-
}
|
|
41303
|
-
};
|
|
41304
|
-
function getAbiBridge() {
|
|
41305
|
-
return BRIDGE;
|
|
41306
|
-
}
|
|
41307
|
-
function findAbiFunction(abi, methodName, argCount) {
|
|
41308
|
-
const matches = abi.filter(
|
|
41309
|
-
(e2) => e2.type === "function" && e2.name === methodName
|
|
41310
|
-
);
|
|
41311
|
-
if (matches.length === 0) {
|
|
41312
|
-
throw new TwakValidationError(`Unknown ABI method: ${methodName}`, {
|
|
41313
|
-
kind: "unknownMethod",
|
|
41314
|
-
methodName
|
|
41315
|
-
});
|
|
41316
|
-
}
|
|
41317
|
-
if (matches.length === 1 || argCount === void 0) {
|
|
41318
|
-
return matches[0];
|
|
41319
|
-
}
|
|
41320
|
-
const byArity = matches.filter((m2) => m2.inputs.length === argCount);
|
|
41321
|
-
if (byArity.length === 1) {
|
|
41322
|
-
return byArity[0];
|
|
41323
|
-
}
|
|
41324
|
-
throw new TwakValidationError(`No unique ${methodName} overload taking ${argCount} argument(s)`, {
|
|
41325
|
-
kind: "unknownMethod",
|
|
41326
|
-
methodName
|
|
41327
|
-
});
|
|
41328
|
-
}
|
|
41329
|
-
function encodeFunctionCall(abi, methodName, args) {
|
|
41330
|
-
const fnDef = findAbiFunction(abi, methodName, args.length);
|
|
41331
|
-
if (args.length !== fnDef.inputs.length) {
|
|
41332
|
-
throw new TwakValidationError(
|
|
41333
|
-
`Wrong arg count for ${methodName}: expected ${fnDef.inputs.length}, got ${args.length}`,
|
|
41334
|
-
{
|
|
41335
|
-
kind: "wrongArgCount",
|
|
41336
|
-
methodName,
|
|
41337
|
-
expected: fnDef.inputs.length,
|
|
41338
|
-
actual: args.length
|
|
41339
|
-
}
|
|
41340
|
-
);
|
|
41341
|
-
}
|
|
41342
|
-
if (encoderRequiresHandRoll(fnDef.inputs)) {
|
|
41343
|
-
return encodeFunctionCallHandRoll(methodName, fnDef.inputs, args);
|
|
41344
|
-
}
|
|
41345
|
-
const bridge = getAbiBridge();
|
|
41346
|
-
const fn2 = bridge.createAbiFunction(methodName);
|
|
41347
|
-
fnDef.inputs.forEach((param, i2) => {
|
|
41348
|
-
pushParam(fn2, param, args[i2], methodName);
|
|
41349
|
-
});
|
|
41350
|
-
return bytesToHex3(bridge.encode(fn2));
|
|
41351
|
-
}
|
|
41352
|
-
function pushParam(fn2, param, value, methodName) {
|
|
41353
|
-
const type = param.type;
|
|
41354
|
-
const isOutput = false;
|
|
41355
|
-
if (type === "address") {
|
|
41356
|
-
fn2.addParamAddress(toAddressBytes(value, param, methodName), isOutput);
|
|
41357
|
-
return;
|
|
41358
|
-
}
|
|
41359
|
-
if (type === "bool") {
|
|
41360
|
-
if (typeof value !== "boolean") {
|
|
41361
|
-
throw argTypeMismatch(methodName, param, value, "boolean");
|
|
40770
|
+
return bytesToHex3(bridge.encode(fn2));
|
|
40771
|
+
}
|
|
40772
|
+
function pushParam(fn2, param, value, methodName) {
|
|
40773
|
+
const type = param.type;
|
|
40774
|
+
const isOutput = false;
|
|
40775
|
+
if (type === "address") {
|
|
40776
|
+
fn2.addParamAddress(toAddressBytes(value, param, methodName), isOutput);
|
|
40777
|
+
return;
|
|
40778
|
+
}
|
|
40779
|
+
if (type === "bool") {
|
|
40780
|
+
if (typeof value !== "boolean") {
|
|
40781
|
+
throw argTypeMismatch(methodName, param, value, "boolean");
|
|
41362
40782
|
}
|
|
41363
40783
|
fn2.addParamBool(value, isOutput);
|
|
41364
40784
|
return;
|
|
@@ -42012,14 +41432,14 @@ function buildWriteProxy(abi, address, chainKey, client) {
|
|
|
42012
41432
|
});
|
|
42013
41433
|
}
|
|
42014
41434
|
const data = encodeFunctionCall(abi, prop, args);
|
|
42015
|
-
const
|
|
41435
|
+
const hash = await signer.sendTransaction({
|
|
42016
41436
|
chainId: chainKeyToCaip2(chainKey),
|
|
42017
41437
|
to: address,
|
|
42018
41438
|
data,
|
|
42019
41439
|
value: "0x0"
|
|
42020
41440
|
});
|
|
42021
41441
|
return makeContractPendingTransaction({
|
|
42022
|
-
|
|
41442
|
+
hash,
|
|
42023
41443
|
abi,
|
|
42024
41444
|
address,
|
|
42025
41445
|
chainKey,
|
|
@@ -42031,22 +41451,22 @@ function buildWriteProxy(abi, address, chainKey, client) {
|
|
|
42031
41451
|
});
|
|
42032
41452
|
}
|
|
42033
41453
|
function makeContractPendingTransaction(opts) {
|
|
42034
|
-
const {
|
|
41454
|
+
const { hash, abi, address, chainKey, client, methodName } = opts;
|
|
42035
41455
|
return {
|
|
42036
|
-
|
|
41456
|
+
hash,
|
|
42037
41457
|
async wait(waitOpts) {
|
|
42038
|
-
const receipt = await client.waitForReceipt(chainKey,
|
|
41458
|
+
const receipt = await client.waitForReceipt(chainKey, hash, {
|
|
42039
41459
|
timeoutMs: waitOpts?.timeoutMs
|
|
42040
41460
|
});
|
|
42041
41461
|
if (receipt.status === "0x0") {
|
|
42042
41462
|
throw new TwakError(
|
|
42043
41463
|
`Transaction reverted on-chain: ${receipt.transactionHash}`,
|
|
42044
41464
|
"TX_FAILED",
|
|
42045
|
-
{
|
|
41465
|
+
{ hash: receipt.transactionHash, methodName, receipt }
|
|
42046
41466
|
);
|
|
42047
41467
|
}
|
|
42048
41468
|
return {
|
|
42049
|
-
|
|
41469
|
+
hash: receipt.transactionHash,
|
|
42050
41470
|
blockNumber: hexToSafeNumber(receipt.blockNumber, "blockNumber"),
|
|
42051
41471
|
events: extractEvents(abi, receipt.logs, address)
|
|
42052
41472
|
};
|
|
@@ -42143,6 +41563,17 @@ function lookupAddress(id, addresses, chainKey) {
|
|
|
42143
41563
|
}
|
|
42144
41564
|
return address;
|
|
42145
41565
|
}
|
|
41566
|
+
function eip191Digest(message) {
|
|
41567
|
+
const messageBytes = new TextEncoder().encode(message);
|
|
41568
|
+
const prefixBytes = new TextEncoder().encode(
|
|
41569
|
+
`Ethereum Signed Message:
|
|
41570
|
+
${messageBytes.length}`
|
|
41571
|
+
);
|
|
41572
|
+
const data = new Uint8Array(prefixBytes.length + messageBytes.length);
|
|
41573
|
+
data.set(prefixBytes);
|
|
41574
|
+
data.set(messageBytes, prefixBytes.length);
|
|
41575
|
+
return bytesToHex3(getAbiBridge().keccak256(data));
|
|
41576
|
+
}
|
|
42146
41577
|
var ERC20_ABI = [
|
|
42147
41578
|
{
|
|
42148
41579
|
type: "function",
|
|
@@ -42722,6 +42153,29 @@ var ERC8183_POLICY_ABI = [
|
|
|
42722
42153
|
outputs: [],
|
|
42723
42154
|
stateMutability: "nonpayable"
|
|
42724
42155
|
},
|
|
42156
|
+
{
|
|
42157
|
+
type: "function",
|
|
42158
|
+
name: "disputeWindow",
|
|
42159
|
+
inputs: [],
|
|
42160
|
+
outputs: [{ name: "", type: "uint64" }],
|
|
42161
|
+
stateMutability: "view"
|
|
42162
|
+
},
|
|
42163
|
+
{
|
|
42164
|
+
// When the policy recorded the job's submission (0 if not submitted).
|
|
42165
|
+
type: "function",
|
|
42166
|
+
name: "submittedAt",
|
|
42167
|
+
inputs: [{ name: "jobId", type: "uint256" }],
|
|
42168
|
+
outputs: [{ name: "", type: "uint64" }],
|
|
42169
|
+
stateMutability: "view"
|
|
42170
|
+
},
|
|
42171
|
+
{
|
|
42172
|
+
// Vote quorum snapshotted for the job when its dispute was raised.
|
|
42173
|
+
type: "function",
|
|
42174
|
+
name: "disputeQuorumSnapshot",
|
|
42175
|
+
inputs: [{ name: "jobId", type: "uint256" }],
|
|
42176
|
+
outputs: [{ name: "", type: "uint16" }],
|
|
42177
|
+
stateMutability: "view"
|
|
42178
|
+
},
|
|
42725
42179
|
{
|
|
42726
42180
|
type: "function",
|
|
42727
42181
|
name: "disputed",
|
|
@@ -42833,8 +42287,640 @@ function resolveErc8183Contracts(client, chainInput) {
|
|
|
42833
42287
|
};
|
|
42834
42288
|
}
|
|
42835
42289
|
|
|
42290
|
+
// src/branding.ts
|
|
42291
|
+
var import_chalk5 = __toESM(require_source());
|
|
42292
|
+
var boxen = require_boxen();
|
|
42293
|
+
var SHIELD = [
|
|
42294
|
+
" @@=+ ",
|
|
42295
|
+
" @@@@@@@======= ",
|
|
42296
|
+
" @@@@@@@@@@@@@============+ ",
|
|
42297
|
+
" @@@@@@@@@@@@@@@@================ ",
|
|
42298
|
+
" @@@@@@@@@@@@@@@@+=============== ",
|
|
42299
|
+
" @@@@@@@@@@@@@@@@++++============ ",
|
|
42300
|
+
" @@@@@@@@@@@@@@@@++++++++++=====+ ",
|
|
42301
|
+
" @@@@@@@@@@@@@@@@**++++++++++++++ ",
|
|
42302
|
+
" @@@@@@@@@@@@@@@@********++++++++ ",
|
|
42303
|
+
" @@@@@@@@@@@@@@@@**************++ ",
|
|
42304
|
+
" @@@@@@@@@@@@@@@@#####*********** ",
|
|
42305
|
+
" @@@@@@@@@@@@@@@###########**** ",
|
|
42306
|
+
" @@@@@@@@@@@@@@%############## ",
|
|
42307
|
+
" @@@@@@@@@@@@@@%%%%%%%####### ",
|
|
42308
|
+
" @@@@@@@@@@@@@%%%%%%%%%%%%% ",
|
|
42309
|
+
" @@@@@@@@@@@%%%%%%%%%%% ",
|
|
42310
|
+
" @@@@@@@@@@@@@%%%%% ",
|
|
42311
|
+
" @@@@@@@@@@@@@@ ",
|
|
42312
|
+
" @@@@@@@@@@ ",
|
|
42313
|
+
" @@ "
|
|
42314
|
+
];
|
|
42315
|
+
function printBanner(version3) {
|
|
42316
|
+
const logo = SHIELD.map((l4) => import_chalk5.default.green(l4)).join("\n");
|
|
42317
|
+
const title = import_chalk5.default.green.bold(" Trust Wallet Agent Kit");
|
|
42318
|
+
const ver = import_chalk5.default.dim(` v${version3}`);
|
|
42319
|
+
console.log(
|
|
42320
|
+
boxen(`${logo}
|
|
42321
|
+
|
|
42322
|
+
${title}
|
|
42323
|
+
${ver}`, {
|
|
42324
|
+
borderColor: "green",
|
|
42325
|
+
borderStyle: "round",
|
|
42326
|
+
padding: { top: 1, bottom: 1, left: 2, right: 2 }
|
|
42327
|
+
})
|
|
42328
|
+
);
|
|
42329
|
+
}
|
|
42330
|
+
function box(content) {
|
|
42331
|
+
return boxen(content, {
|
|
42332
|
+
borderColor: "green",
|
|
42333
|
+
borderStyle: "round",
|
|
42334
|
+
padding: { top: 0, bottom: 0, left: 1, right: 1 }
|
|
42335
|
+
});
|
|
42336
|
+
}
|
|
42337
|
+
|
|
42338
|
+
// src/commands/wallet.ts
|
|
42339
|
+
function getQRString(address) {
|
|
42340
|
+
try {
|
|
42341
|
+
const qrcode = require("qrcode-terminal");
|
|
42342
|
+
let result = "";
|
|
42343
|
+
qrcode.generate(address, { small: true }, (code2) => {
|
|
42344
|
+
result = code2;
|
|
42345
|
+
});
|
|
42346
|
+
return result;
|
|
42347
|
+
} catch {
|
|
42348
|
+
return "";
|
|
42349
|
+
}
|
|
42350
|
+
}
|
|
42351
|
+
function registerWalletCommand(program3) {
|
|
42352
|
+
const wallet = program3.command("wallet").description("Manage agent wallet");
|
|
42353
|
+
wallet.command("create").description("Create a new agent wallet").requiredOption("--password <password>", "Password to encrypt the wallet").option("--no-keychain", "Do not save password to OS keychain").option("--skip-password-check", "Skip password strength validation").option("--json", "JSON output").action(async (opts) => {
|
|
42354
|
+
try {
|
|
42355
|
+
if (!opts.skipPasswordCheck) {
|
|
42356
|
+
const weakness = getPasswordWeaknesses(opts.password);
|
|
42357
|
+
if (weakness) {
|
|
42358
|
+
throw new WalletError("VALIDATION_ERROR", `Password too weak: must ${weakness}.`);
|
|
42359
|
+
}
|
|
42360
|
+
}
|
|
42361
|
+
await ensureTrustSDK();
|
|
42362
|
+
const store = new WalletConfigStore();
|
|
42363
|
+
if (await store.exists()) {
|
|
42364
|
+
throw new WalletError(
|
|
42365
|
+
"WALLET_EXISTS",
|
|
42366
|
+
"Wallet already exists. Back up ~/.twak/wallet.json, then delete it to create a new one."
|
|
42367
|
+
);
|
|
42368
|
+
}
|
|
42369
|
+
const provider = await AgentWalletProvider.create(opts.password);
|
|
42370
|
+
const addresses = await provider.getAddresses();
|
|
42371
|
+
if (opts.keychain !== false) {
|
|
42372
|
+
const kc2 = new KeychainManager();
|
|
42373
|
+
if (kc2.isAvailable()) {
|
|
42374
|
+
await kc2.saveWalletPassword(opts.password);
|
|
42375
|
+
if (!opts.json) info("Password saved to OS keychain (use --no-keychain to skip)");
|
|
42376
|
+
}
|
|
42377
|
+
}
|
|
42378
|
+
if (!opts.json) success("Agent wallet created successfully");
|
|
42379
|
+
try {
|
|
42380
|
+
const creds = await getCredentials();
|
|
42381
|
+
await registerWalletWithBackend(creds, provider);
|
|
42382
|
+
if (!opts.json) info("Wallet registered with backend");
|
|
42383
|
+
} catch {
|
|
42384
|
+
if (!opts.json) warn("Backend registration failed (holdings may be limited)");
|
|
42385
|
+
}
|
|
42386
|
+
if (opts.json) {
|
|
42387
|
+
output({ addresses }, true);
|
|
42388
|
+
} else {
|
|
42389
|
+
info(`Generated addresses for ${addresses.length} chains`);
|
|
42390
|
+
}
|
|
42391
|
+
} catch (err) {
|
|
42392
|
+
handleCommandError(err, opts.json, "Wallet creation failed");
|
|
42393
|
+
}
|
|
42394
|
+
safeExit();
|
|
42395
|
+
});
|
|
42396
|
+
wallet.command("address").description("Get wallet address for a chain").requiredOption("--chain <key>", "Chain key (e.g., ethereum, solana)").option(
|
|
42397
|
+
"--password <password>",
|
|
42398
|
+
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
42399
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
42400
|
+
try {
|
|
42401
|
+
if (!getChainById(opts.chain)) {
|
|
42402
|
+
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
42403
|
+
}
|
|
42404
|
+
await ensureTrustSDK();
|
|
42405
|
+
const password3 = await resolvePassword(opts);
|
|
42406
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42407
|
+
const address = await provider.getAddress(opts.chain);
|
|
42408
|
+
if (opts.json) {
|
|
42409
|
+
output({ chain: opts.chain, address }, true);
|
|
42410
|
+
} else {
|
|
42411
|
+
const qr3 = getQRString(address);
|
|
42412
|
+
const content = `${import_chalk6.default.dim("Chain")} ${import_chalk6.default.bold(opts.chain)}
|
|
42413
|
+
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
42414
|
+
|
|
42415
|
+
${qr3}`;
|
|
42416
|
+
console.log(box(content));
|
|
42417
|
+
}
|
|
42418
|
+
} catch (err) {
|
|
42419
|
+
handleCommandError(err, opts.json, "Wallet address failed");
|
|
42420
|
+
}
|
|
42421
|
+
safeExit();
|
|
42422
|
+
});
|
|
42423
|
+
wallet.command("addresses").description("List all wallet addresses").option(
|
|
42424
|
+
"--password <password>",
|
|
42425
|
+
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
42426
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
42427
|
+
try {
|
|
42428
|
+
await ensureTrustSDK();
|
|
42429
|
+
const password3 = await resolvePassword(opts);
|
|
42430
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42431
|
+
const addresses = await provider.getAddresses();
|
|
42432
|
+
if (opts.json) {
|
|
42433
|
+
output({ addresses }, true);
|
|
42434
|
+
} else {
|
|
42435
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
42436
|
+
for (const addr of addresses) {
|
|
42437
|
+
const chains = grouped.get(addr.address) ?? [];
|
|
42438
|
+
chains.push(addr.chainId);
|
|
42439
|
+
grouped.set(addr.address, chains);
|
|
42440
|
+
}
|
|
42441
|
+
for (const [address, chains] of grouped) {
|
|
42442
|
+
const qr3 = getQRString(address);
|
|
42443
|
+
const maxWidth = Math.max(address.length + 9, 50);
|
|
42444
|
+
const chainLabel = `${import_chalk6.default.dim("Chains")} `;
|
|
42445
|
+
const chainLabelLen = 9;
|
|
42446
|
+
const chainLines = [];
|
|
42447
|
+
let line = "";
|
|
42448
|
+
for (const c3 of chains) {
|
|
42449
|
+
const sep2 = line ? ", " : "";
|
|
42450
|
+
if (line && line.length + sep2.length + c3.length + chainLabelLen > maxWidth) {
|
|
42451
|
+
chainLines.push(line);
|
|
42452
|
+
line = c3;
|
|
42453
|
+
} else {
|
|
42454
|
+
line += sep2 + c3;
|
|
42455
|
+
}
|
|
42456
|
+
}
|
|
42457
|
+
if (line) chainLines.push(line);
|
|
42458
|
+
const chainsStr = chainLines.map((l4, i2) => (i2 === 0 ? chainLabel : " ".repeat(chainLabelLen)) + import_chalk6.default.bold(l4)).join("\n");
|
|
42459
|
+
const content = `${chainsStr}
|
|
42460
|
+
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
42461
|
+
|
|
42462
|
+
${qr3}`;
|
|
42463
|
+
console.log(box(content));
|
|
42464
|
+
}
|
|
42465
|
+
}
|
|
42466
|
+
} catch (err) {
|
|
42467
|
+
handleCommandError(err, opts.json, "Wallet addresses failed");
|
|
42468
|
+
}
|
|
42469
|
+
safeExit();
|
|
42470
|
+
});
|
|
42471
|
+
wallet.command("balance").description("Get wallet balance on a chain (native + token holdings)").option("--chain <key>", "Chain key").option("--all", "Show balances across all chains with funds").option(
|
|
42472
|
+
"--password <password>",
|
|
42473
|
+
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
42474
|
+
).option("--no-tokens", "Skip token balance lookup").option("--json", "JSON output").action(async (opts) => {
|
|
42475
|
+
try {
|
|
42476
|
+
if (opts.all && opts.chain) {
|
|
42477
|
+
throw new WalletError("VALIDATION_ERROR", "--all and --chain are mutually exclusive");
|
|
42478
|
+
}
|
|
42479
|
+
if (!opts.all && !opts.chain) {
|
|
42480
|
+
throw new WalletError("VALIDATION_ERROR", "Provide --chain <key> or --all");
|
|
42481
|
+
}
|
|
42482
|
+
await ensureTrustSDK();
|
|
42483
|
+
const password3 = await resolvePassword(opts);
|
|
42484
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42485
|
+
const httpClient = await getClient();
|
|
42486
|
+
if (!opts.all) {
|
|
42487
|
+
const chain2 = getChainById(opts.chain);
|
|
42488
|
+
if (!chain2) {
|
|
42489
|
+
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
42490
|
+
}
|
|
42491
|
+
}
|
|
42492
|
+
const allAddresses = await provider.getAddresses();
|
|
42493
|
+
const addressMap = /* @__PURE__ */ new Map();
|
|
42494
|
+
for (const a3 of allAddresses) addressMap.set(a3.chainId, a3.address);
|
|
42495
|
+
const requestedChains = opts.all ? Object.keys(CHAINS) : [opts.chain];
|
|
42496
|
+
const skipTokens = opts.tokens === false;
|
|
42497
|
+
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
42498
|
+
const chain2 = getChainById(chainKey);
|
|
42499
|
+
const address = addressMap.get(chainKey);
|
|
42500
|
+
if (!chain2 || !address) return [];
|
|
42501
|
+
return [{ chainKey, chain: chain2, address }];
|
|
42502
|
+
});
|
|
42503
|
+
if (!opts.all && chainEntries.length === 0) {
|
|
42504
|
+
throw new WalletError(
|
|
42505
|
+
"CHAIN_UNSUPPORTED",
|
|
42506
|
+
`Wallet does not have an address for chain: ${opts.chain}`
|
|
42507
|
+
);
|
|
42508
|
+
}
|
|
42509
|
+
const nativeAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
42510
|
+
chainKey,
|
|
42511
|
+
chain: chain2,
|
|
42512
|
+
token: void 0,
|
|
42513
|
+
assetId: `c${chain2.coinId}`,
|
|
42514
|
+
userAddress: address
|
|
42515
|
+
}));
|
|
42516
|
+
const tokenAssets = skipTokens ? [] : chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
42517
|
+
const knownTokens = COMMON_TOKENS[chainKey];
|
|
42518
|
+
if (!knownTokens) return [];
|
|
42519
|
+
return Object.keys(knownTokens).flatMap((sym) => {
|
|
42520
|
+
const resolved = resolveToken(sym, chainKey);
|
|
42521
|
+
if (!resolved) return [];
|
|
42522
|
+
return [
|
|
42523
|
+
{
|
|
42524
|
+
chainKey,
|
|
42525
|
+
chain: chain2,
|
|
42526
|
+
token: { ...resolved, symbol: sym },
|
|
42527
|
+
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
42528
|
+
userAddress: address
|
|
42529
|
+
}
|
|
42530
|
+
];
|
|
42531
|
+
});
|
|
42532
|
+
});
|
|
42533
|
+
const allAssets = [...nativeAssets, ...tokenAssets];
|
|
42534
|
+
const balances = await fetchBalances(
|
|
42535
|
+
httpClient,
|
|
42536
|
+
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
42537
|
+
);
|
|
42538
|
+
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
42539
|
+
const resultsByChain = /* @__PURE__ */ new Map();
|
|
42540
|
+
for (const { chainKey, chain: chain2, address } of chainEntries) {
|
|
42541
|
+
resultsByChain.set(chainKey, {
|
|
42542
|
+
chain: chainKey,
|
|
42543
|
+
address,
|
|
42544
|
+
symbol: chain2.symbol,
|
|
42545
|
+
available: "0",
|
|
42546
|
+
total: "0",
|
|
42547
|
+
totalUsd: null,
|
|
42548
|
+
tokens: []
|
|
42549
|
+
});
|
|
42550
|
+
}
|
|
42551
|
+
for (const balance of balances) {
|
|
42552
|
+
const assetInfo = assetsById.get(balance.assetId);
|
|
42553
|
+
if (!assetInfo) {
|
|
42554
|
+
throw new WalletError(
|
|
42555
|
+
"NETWORK_ERROR",
|
|
42556
|
+
"Could not fetch balances. Please try again later."
|
|
42557
|
+
);
|
|
42558
|
+
}
|
|
42559
|
+
const result = resultsByChain.get(assetInfo.chainKey);
|
|
42560
|
+
if (!result) continue;
|
|
42561
|
+
const { token, chain: chain2 } = assetInfo;
|
|
42562
|
+
const amts = balance.amounts;
|
|
42563
|
+
if (token) {
|
|
42564
|
+
const human = formatAmount(amts.total ?? "0", token.decimals);
|
|
42565
|
+
if (human !== "0") {
|
|
42566
|
+
result.tokens.push({
|
|
42567
|
+
symbol: token.symbol,
|
|
42568
|
+
contract: token.address,
|
|
42569
|
+
balance: human
|
|
42570
|
+
});
|
|
42571
|
+
}
|
|
42572
|
+
} else {
|
|
42573
|
+
result.available = formatAmount(amts.available ?? "0", chain2.decimals);
|
|
42574
|
+
result.total = formatAmount(amts.total ?? "0", chain2.decimals);
|
|
42575
|
+
const lockedHuman = formatAmount(amts.locked ?? "0", chain2.decimals);
|
|
42576
|
+
if (lockedHuman !== "0") result.staked = lockedHuman;
|
|
42577
|
+
const fiat = amts.totalInFiat;
|
|
42578
|
+
result.totalUsd = fiat && fiat !== "" ? parseFloat(fiat) : null;
|
|
42579
|
+
}
|
|
42580
|
+
}
|
|
42581
|
+
const orderedResults = chainEntries.map((e2) => resultsByChain.get(e2.chainKey)).filter((r3) => r3 !== void 0);
|
|
42582
|
+
const visible = opts.all ? orderedResults.filter((r3) => r3.total !== "0" || r3.tokens.length > 0) : orderedResults;
|
|
42583
|
+
const renderBlock = (r3, withSeparator) => {
|
|
42584
|
+
if (withSeparator) console.log("");
|
|
42585
|
+
console.log(import_chalk6.default.bold.underline(`${r3.chain} (${r3.symbol})`));
|
|
42586
|
+
console.log(` ${import_chalk6.default.dim("Address")} ${r3.address}`);
|
|
42587
|
+
console.log(` ${import_chalk6.default.dim("Available")} ${r3.available}`);
|
|
42588
|
+
if (r3.staked) console.log(` ${import_chalk6.default.dim("Staked")} ${r3.staked}`);
|
|
42589
|
+
const usdSuffix = r3.totalUsd !== null ? ` (\u2248 $${r3.totalUsd.toFixed(2)})` : "";
|
|
42590
|
+
console.log(` ${import_chalk6.default.dim("Total")} ${r3.total}${usdSuffix}`);
|
|
42591
|
+
if (r3.tokens.length > 0) {
|
|
42592
|
+
console.log(` ${import_chalk6.default.dim("Tokens:")}`);
|
|
42593
|
+
for (const t of r3.tokens) {
|
|
42594
|
+
console.log(` ${import_chalk6.default.bold(t.symbol.padEnd(10))} ${t.balance}`);
|
|
42595
|
+
}
|
|
42596
|
+
}
|
|
42597
|
+
};
|
|
42598
|
+
if (opts.all) {
|
|
42599
|
+
if (opts.json) {
|
|
42600
|
+
output(visible, true);
|
|
42601
|
+
} else if (visible.length === 0) {
|
|
42602
|
+
info("No chains with non-zero native balance found.");
|
|
42603
|
+
} else {
|
|
42604
|
+
visible.forEach((r3, i2) => renderBlock(r3, i2 > 0));
|
|
42605
|
+
}
|
|
42606
|
+
} else {
|
|
42607
|
+
const single = visible[0];
|
|
42608
|
+
if (opts.json) {
|
|
42609
|
+
output(single, true);
|
|
42610
|
+
} else {
|
|
42611
|
+
renderBlock(single, false);
|
|
42612
|
+
}
|
|
42613
|
+
}
|
|
42614
|
+
} catch (err) {
|
|
42615
|
+
handleCommandError(err, opts.json, "Balance check failed");
|
|
42616
|
+
}
|
|
42617
|
+
safeExit();
|
|
42618
|
+
});
|
|
42619
|
+
const keychain = wallet.command("keychain").description("Manage wallet password in OS keychain");
|
|
42620
|
+
keychain.command("save").description("Save wallet password to OS keychain").requiredOption("--password <password>", "Wallet password to store").option("--json", "JSON output").action(async (opts) => {
|
|
42621
|
+
try {
|
|
42622
|
+
const kc2 = new KeychainManager();
|
|
42623
|
+
if (!kc2.isAvailable()) {
|
|
42624
|
+
throw new WalletError("KEYCHAIN_UNAVAILABLE", "OS keychain not available on this system");
|
|
42625
|
+
}
|
|
42626
|
+
await kc2.saveWalletPassword(opts.password);
|
|
42627
|
+
success("Wallet password saved to OS keychain");
|
|
42628
|
+
} catch (err) {
|
|
42629
|
+
handleCommandError(err, opts.json, "Keychain save failed");
|
|
42630
|
+
}
|
|
42631
|
+
safeExit();
|
|
42632
|
+
});
|
|
42633
|
+
keychain.command("delete").description("Remove wallet password from OS keychain").option("--json", "JSON output").action(async (opts) => {
|
|
42634
|
+
try {
|
|
42635
|
+
const kc2 = new KeychainManager();
|
|
42636
|
+
if (!kc2.isAvailable()) {
|
|
42637
|
+
throw new WalletError("KEYCHAIN_UNAVAILABLE", "OS keychain not available on this system");
|
|
42638
|
+
}
|
|
42639
|
+
await kc2.deleteWalletPassword();
|
|
42640
|
+
success("Wallet password removed from OS keychain");
|
|
42641
|
+
} catch (err) {
|
|
42642
|
+
handleCommandError(err, opts.json, "Keychain delete failed");
|
|
42643
|
+
}
|
|
42644
|
+
safeExit();
|
|
42645
|
+
});
|
|
42646
|
+
keychain.command("check").description("Check if wallet password is stored in OS keychain").option("--json", "JSON output").action(async (opts) => {
|
|
42647
|
+
try {
|
|
42648
|
+
const kc2 = new KeychainManager();
|
|
42649
|
+
if (!kc2.isAvailable()) {
|
|
42650
|
+
if (opts.json) {
|
|
42651
|
+
output({ available: false, stored: false }, true);
|
|
42652
|
+
} else {
|
|
42653
|
+
warn("keytar not available on this system");
|
|
42654
|
+
}
|
|
42655
|
+
safeExit();
|
|
42656
|
+
return;
|
|
42657
|
+
}
|
|
42658
|
+
const pw = await kc2.getWalletPassword();
|
|
42659
|
+
if (opts.json) {
|
|
42660
|
+
output({ available: true, stored: !!pw }, true);
|
|
42661
|
+
} else if (pw) {
|
|
42662
|
+
success("Wallet password is stored in OS keychain");
|
|
42663
|
+
} else {
|
|
42664
|
+
info("No wallet password found in OS keychain");
|
|
42665
|
+
}
|
|
42666
|
+
} catch (err) {
|
|
42667
|
+
handleCommandError(err, opts.json, "Keychain check failed");
|
|
42668
|
+
}
|
|
42669
|
+
safeExit();
|
|
42670
|
+
});
|
|
42671
|
+
wallet.command("connect").description("Connect external wallet via WalletConnect").option("--project-id <id>", "WalletConnect project ID (or set WALLETCONNECT_PROJECT_ID)").option(
|
|
42672
|
+
"--chains <list>",
|
|
42673
|
+
"Comma-separated CAIP-2 chain IDs",
|
|
42674
|
+
"eip155:1,eip155:56,eip155:137,eip155:8453,eip155:42161"
|
|
42675
|
+
).option("--timeout <seconds>", "Connection timeout in seconds", "300").option("--json", "JSON output").action(async (opts) => {
|
|
42676
|
+
try {
|
|
42677
|
+
const projectId = opts.projectId || process.env.WALLETCONNECT_PROJECT_ID;
|
|
42678
|
+
if (!projectId) {
|
|
42679
|
+
throw new WalletError(
|
|
42680
|
+
"VALIDATION_ERROR",
|
|
42681
|
+
"WalletConnect project ID required. Use --project-id or set WALLETCONNECT_PROJECT_ID"
|
|
42682
|
+
);
|
|
42683
|
+
}
|
|
42684
|
+
const provider = new WalletConnectProvider({ projectId });
|
|
42685
|
+
const chains = opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
42686
|
+
info("Connecting via WalletConnect...");
|
|
42687
|
+
const result = await provider.connect(chains);
|
|
42688
|
+
const qr3 = getQRString(result.uri);
|
|
42689
|
+
if (qr3) {
|
|
42690
|
+
console.log(qr3);
|
|
42691
|
+
}
|
|
42692
|
+
info(`Trust Wallet: ${result.deepLinks.native}`);
|
|
42693
|
+
info(`Universal: ${result.deepLinks.universal}`);
|
|
42694
|
+
info("\nWaiting for wallet approval...");
|
|
42695
|
+
const timeoutMs = parseInt(opts.timeout, 10) * 1e3;
|
|
42696
|
+
const session = await provider.waitForSession(timeoutMs);
|
|
42697
|
+
if (opts.json) {
|
|
42698
|
+
output(
|
|
42699
|
+
{
|
|
42700
|
+
connected: true,
|
|
42701
|
+
address: session.address,
|
|
42702
|
+
chainId: session.chainId,
|
|
42703
|
+
peer: session.peerName
|
|
42704
|
+
},
|
|
42705
|
+
true
|
|
42706
|
+
);
|
|
42707
|
+
} else {
|
|
42708
|
+
success(`Connected to ${session.peerName || "wallet"}`);
|
|
42709
|
+
info(` Address: ${session.address}`);
|
|
42710
|
+
info(` Chain: ${session.chainId}`);
|
|
42711
|
+
}
|
|
42712
|
+
} catch (err) {
|
|
42713
|
+
handleCommandError(err, opts.json, "WalletConnect failed");
|
|
42714
|
+
}
|
|
42715
|
+
safeExit();
|
|
42716
|
+
});
|
|
42717
|
+
wallet.command("status").description("Check wallet configuration status").option("--json", "JSON output").action(async (opts) => {
|
|
42718
|
+
try {
|
|
42719
|
+
const store = new WalletConfigStore();
|
|
42720
|
+
const exists = await store.exists();
|
|
42721
|
+
const kc2 = new KeychainManager();
|
|
42722
|
+
const keychainHasPassword = kc2.isAvailable() ? !!await kc2.getWalletPassword() : false;
|
|
42723
|
+
const totalChains = Object.keys(CHAINS).length;
|
|
42724
|
+
let createdAt;
|
|
42725
|
+
let addressCount;
|
|
42726
|
+
if (exists) {
|
|
42727
|
+
const config = await store.getConfig();
|
|
42728
|
+
createdAt = config?.createdAt;
|
|
42729
|
+
addressCount = config?.chains?.length ?? totalChains;
|
|
42730
|
+
}
|
|
42731
|
+
const result = {
|
|
42732
|
+
agentWallet: exists ? "configured" : "not configured",
|
|
42733
|
+
keychainPassword: keychainHasPassword ? "stored" : "not stored",
|
|
42734
|
+
chains: totalChains,
|
|
42735
|
+
supportedChains: totalChains,
|
|
42736
|
+
...createdAt ? { createdAt } : {},
|
|
42737
|
+
...addressCount !== void 0 ? { addressCount } : {}
|
|
42738
|
+
};
|
|
42739
|
+
if (opts.json) {
|
|
42740
|
+
output(result, true);
|
|
42741
|
+
} else {
|
|
42742
|
+
console.log(
|
|
42743
|
+
` ${import_chalk6.default.dim("Wallet")} ${exists ? import_chalk6.default.green("configured") : import_chalk6.default.yellow("not configured")}`
|
|
42744
|
+
);
|
|
42745
|
+
if (createdAt) console.log(` ${import_chalk6.default.dim("Created")} ${createdAt}`);
|
|
42746
|
+
console.log(
|
|
42747
|
+
` ${import_chalk6.default.dim("Keychain")} ${keychainHasPassword ? import_chalk6.default.green("password stored") : import_chalk6.default.yellow("no password")}`
|
|
42748
|
+
);
|
|
42749
|
+
console.log(` ${import_chalk6.default.dim("Chains")} ${totalChains} supported`);
|
|
42750
|
+
if (addressCount !== void 0)
|
|
42751
|
+
console.log(` ${import_chalk6.default.dim("Addresses")} ${addressCount}`);
|
|
42752
|
+
if (!exists) info("\nRun `twak wallet create --password <pw>` to create a wallet.");
|
|
42753
|
+
}
|
|
42754
|
+
} catch (err) {
|
|
42755
|
+
handleCommandError(err, opts.json, "Status failed");
|
|
42756
|
+
}
|
|
42757
|
+
safeExit();
|
|
42758
|
+
});
|
|
42759
|
+
wallet.command("portfolio").description("Show portfolio balances and USD values across chains, including token holdings").option("--chains <list>", "Comma-separated chain keys (default: all supported chains)").option(
|
|
42760
|
+
"--password <password>",
|
|
42761
|
+
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
42762
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
42763
|
+
try {
|
|
42764
|
+
await ensureTrustSDK();
|
|
42765
|
+
const password3 = await resolvePassword(opts);
|
|
42766
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42767
|
+
const httpClient = await getClient();
|
|
42768
|
+
const allAddresses = await provider.getAddresses();
|
|
42769
|
+
const chainsArg = opts.chains ?? Object.keys(CHAINS).join(",");
|
|
42770
|
+
const requestedChains = chainsArg.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
42771
|
+
if (requestedChains.length === 0) {
|
|
42772
|
+
throw new WalletError("VALIDATION_ERROR", "--chains must include at least one chain key");
|
|
42773
|
+
}
|
|
42774
|
+
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
42775
|
+
const chain2 = getChainById(chainKey);
|
|
42776
|
+
const addrEntry = allAddresses.find((a3) => a3.chainId === chainKey);
|
|
42777
|
+
if (!chain2 || !addrEntry) return [];
|
|
42778
|
+
return [{ chainKey, chain: chain2, address: addrEntry.address }];
|
|
42779
|
+
});
|
|
42780
|
+
if (chainEntries.length === 0) {
|
|
42781
|
+
throw new WalletError(
|
|
42782
|
+
"CHAIN_UNSUPPORTED",
|
|
42783
|
+
`No supported chains found in --chains "${opts.chains}"`
|
|
42784
|
+
);
|
|
42785
|
+
}
|
|
42786
|
+
const chainAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
42787
|
+
chainKey,
|
|
42788
|
+
chain: chain2,
|
|
42789
|
+
token: void 0,
|
|
42790
|
+
assetId: `c${chain2.coinId}`,
|
|
42791
|
+
userAddress: address
|
|
42792
|
+
}));
|
|
42793
|
+
const tokenAssets = chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
42794
|
+
const knownTokens = COMMON_TOKENS[chainKey];
|
|
42795
|
+
if (!knownTokens) return [];
|
|
42796
|
+
return Object.keys(knownTokens).flatMap((sym) => {
|
|
42797
|
+
const resolved = resolveToken(sym, chainKey);
|
|
42798
|
+
if (!resolved) return [];
|
|
42799
|
+
return [
|
|
42800
|
+
{
|
|
42801
|
+
chainKey,
|
|
42802
|
+
chain: chain2,
|
|
42803
|
+
token: { ...resolved, symbol: sym },
|
|
42804
|
+
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
42805
|
+
userAddress: address
|
|
42806
|
+
}
|
|
42807
|
+
];
|
|
42808
|
+
});
|
|
42809
|
+
});
|
|
42810
|
+
const allAssets = [...chainAssets, ...tokenAssets];
|
|
42811
|
+
const balances = await fetchBalances(
|
|
42812
|
+
httpClient,
|
|
42813
|
+
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
42814
|
+
);
|
|
42815
|
+
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
42816
|
+
const allRows = [];
|
|
42817
|
+
for (const balance of balances) {
|
|
42818
|
+
const assetInfo = assetsById.get(balance.assetId);
|
|
42819
|
+
if (!assetInfo) {
|
|
42820
|
+
throw new WalletError(
|
|
42821
|
+
"NETWORK_ERROR",
|
|
42822
|
+
"Could not fetch balances. Please try again later."
|
|
42823
|
+
);
|
|
42824
|
+
}
|
|
42825
|
+
const { token, chain: chain2, chainKey, userAddress } = assetInfo;
|
|
42826
|
+
const decimals = token ? token.decimals : chain2.decimals;
|
|
42827
|
+
const symbol = token ? token.symbol ?? token.address : chain2.symbol;
|
|
42828
|
+
const isToken = token !== void 0;
|
|
42829
|
+
const humanAmount = formatAmount(balance.amounts.total, decimals);
|
|
42830
|
+
const fiatRaw = balance.amounts.totalInFiat;
|
|
42831
|
+
const usdValue = fiatRaw && fiatRaw !== "" ? parseFloat(fiatRaw) : null;
|
|
42832
|
+
allRows.push({
|
|
42833
|
+
chain: chainKey,
|
|
42834
|
+
type: isToken ? "token" : "native",
|
|
42835
|
+
symbol,
|
|
42836
|
+
address: userAddress,
|
|
42837
|
+
...token ? { contract: token.address } : {},
|
|
42838
|
+
balance: humanAmount,
|
|
42839
|
+
usdValue
|
|
42840
|
+
});
|
|
42841
|
+
}
|
|
42842
|
+
const rows = allRows.filter((r3) => r3.type === "native" || r3.balance !== "0");
|
|
42843
|
+
rows.sort((a3, b3) => {
|
|
42844
|
+
const chainCmp = String(a3.chain).localeCompare(String(b3.chain));
|
|
42845
|
+
if (chainCmp !== 0) return chainCmp;
|
|
42846
|
+
return String(a3.type).localeCompare(String(b3.type));
|
|
42847
|
+
});
|
|
42848
|
+
if (opts.json) {
|
|
42849
|
+
output(rows, true);
|
|
42850
|
+
} else {
|
|
42851
|
+
const totalUsd = rows.reduce(
|
|
42852
|
+
(sum, r3) => sum + (typeof r3.usdValue === "number" ? r3.usdValue : 0),
|
|
42853
|
+
0
|
|
42854
|
+
);
|
|
42855
|
+
console.log("Chain Type Symbol Balance USD");
|
|
42856
|
+
console.log("\u2500".repeat(72));
|
|
42857
|
+
for (const r3 of rows) {
|
|
42858
|
+
const usd = r3.usdValue !== null ? `$${r3.usdValue.toFixed(2)}` : "";
|
|
42859
|
+
console.log(
|
|
42860
|
+
`${String(r3.chain).padEnd(12)} ${String(r3.type).padEnd(7)} ${String(r3.symbol).padEnd(17)} ${String(r3.balance).padEnd(20)} ${usd}`
|
|
42861
|
+
);
|
|
42862
|
+
}
|
|
42863
|
+
console.log("\u2500".repeat(72));
|
|
42864
|
+
console.log(`Total USD: $${totalUsd.toFixed(2)}`);
|
|
42865
|
+
}
|
|
42866
|
+
} catch (err) {
|
|
42867
|
+
handleCommandError(err, opts.json, "Portfolio failed");
|
|
42868
|
+
}
|
|
42869
|
+
safeExit();
|
|
42870
|
+
});
|
|
42871
|
+
wallet.command("sign-message").description("Sign a message with the agent wallet").requiredOption("--chain <key>", "Chain key (e.g., ethereum, solana)").requiredOption("--message <text>", "Message to sign").option(
|
|
42872
|
+
"--password <password>",
|
|
42873
|
+
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
42874
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
42875
|
+
try {
|
|
42876
|
+
const chain2 = getChainById(opts.chain);
|
|
42877
|
+
if (!chain2) {
|
|
42878
|
+
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
42879
|
+
}
|
|
42880
|
+
await ensureTrustSDK();
|
|
42881
|
+
const password3 = await resolvePassword(opts);
|
|
42882
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42883
|
+
const address = await provider.getAddress(opts.chain);
|
|
42884
|
+
const rawSignature = await provider.signMessage(opts.chain, opts.message);
|
|
42885
|
+
const signature = chain2.isEVM && !rawSignature.startsWith("0x") ? `0x${rawSignature}` : rawSignature;
|
|
42886
|
+
output(
|
|
42887
|
+
{
|
|
42888
|
+
chain: opts.chain,
|
|
42889
|
+
address,
|
|
42890
|
+
message: opts.message,
|
|
42891
|
+
signature,
|
|
42892
|
+
...chain2.isEVM ? { digest: eip191Digest(opts.message) } : {}
|
|
42893
|
+
},
|
|
42894
|
+
opts.json
|
|
42895
|
+
);
|
|
42896
|
+
} catch (err) {
|
|
42897
|
+
handleCommandError(err, opts.json, "Sign failed");
|
|
42898
|
+
}
|
|
42899
|
+
safeExit();
|
|
42900
|
+
});
|
|
42901
|
+
wallet.command("register").description("Register wallet addresses with Trust Wallet backend (enables token holdings)").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (opts) => {
|
|
42902
|
+
try {
|
|
42903
|
+
const creds = await ensureTrustSDK();
|
|
42904
|
+
const password3 = await resolvePassword(opts);
|
|
42905
|
+
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
42906
|
+
await registerWalletWithBackend(creds, provider);
|
|
42907
|
+
if (!opts.json) success("Wallet registered with backend");
|
|
42908
|
+
const addresses = await provider.getAddresses();
|
|
42909
|
+
output({ registered: true, chains: addresses.length }, opts.json);
|
|
42910
|
+
} catch (err) {
|
|
42911
|
+
handleCommandError(err, opts.json, "Registration failed");
|
|
42912
|
+
}
|
|
42913
|
+
safeExit();
|
|
42914
|
+
});
|
|
42915
|
+
}
|
|
42916
|
+
|
|
42917
|
+
// src/commands/transfer.ts
|
|
42918
|
+
init_dist();
|
|
42919
|
+
|
|
42836
42920
|
// ../swap/dist/index.mjs
|
|
42837
42921
|
init_dist();
|
|
42922
|
+
init_dist();
|
|
42923
|
+
init_dist();
|
|
42838
42924
|
var SwapClient = class {
|
|
42839
42925
|
constructor(httpClient) {
|
|
42840
42926
|
this.httpClient = httpClient;
|
|
@@ -43116,9 +43202,9 @@ var SwapExecutor = class {
|
|
|
43116
43202
|
);
|
|
43117
43203
|
const chainConfig = getChainById(params.fromChain);
|
|
43118
43204
|
const transactions = await withRetry(() => this.swapClient.getSwapTransactions(route));
|
|
43119
|
-
let
|
|
43205
|
+
let approvalHash;
|
|
43120
43206
|
try {
|
|
43121
|
-
|
|
43207
|
+
approvalHash = await this.ensureStepApproval(
|
|
43122
43208
|
route,
|
|
43123
43209
|
transactions,
|
|
43124
43210
|
chainConfig,
|
|
@@ -43126,10 +43212,10 @@ var SwapExecutor = class {
|
|
|
43126
43212
|
address,
|
|
43127
43213
|
parsedAmount
|
|
43128
43214
|
);
|
|
43129
|
-
if (
|
|
43130
|
-
await this.pollForConfirmation(params.fromChain, address,
|
|
43215
|
+
if (approvalHash) {
|
|
43216
|
+
await this.pollForConfirmation(params.fromChain, address, approvalHash, 6e4);
|
|
43131
43217
|
}
|
|
43132
|
-
let
|
|
43218
|
+
let hash = "";
|
|
43133
43219
|
for (const txData of transactions) {
|
|
43134
43220
|
const txType = txData.transaction.type;
|
|
43135
43221
|
const isApproval = txType === "approval" || txType === "revokeApproval";
|
|
@@ -43138,30 +43224,30 @@ var SwapExecutor = class {
|
|
|
43138
43224
|
txType === "revokeApproval" ? "Revoking prior approval..." : "Sending token approval..."
|
|
43139
43225
|
);
|
|
43140
43226
|
}
|
|
43141
|
-
|
|
43142
|
-
if (isApproval)
|
|
43227
|
+
hash = await this.sendTransaction(txData, chainConfig, params.fromChain);
|
|
43228
|
+
if (isApproval) approvalHash = hash;
|
|
43143
43229
|
this.log(
|
|
43144
|
-
`${isApproval ? "Approval" : "Swap"} tx: ${getExplorerTxUrl(params.fromChain,
|
|
43230
|
+
`${isApproval ? "Approval" : "Swap"} tx: ${getExplorerTxUrl(params.fromChain, hash)}`
|
|
43145
43231
|
);
|
|
43146
43232
|
await this.pollForConfirmation(
|
|
43147
43233
|
params.fromChain,
|
|
43148
43234
|
address,
|
|
43149
|
-
|
|
43235
|
+
hash,
|
|
43150
43236
|
isApproval ? 6e4 : 12e4
|
|
43151
43237
|
);
|
|
43152
43238
|
}
|
|
43153
43239
|
return {
|
|
43154
43240
|
success: true,
|
|
43155
|
-
|
|
43241
|
+
hash,
|
|
43156
43242
|
route,
|
|
43157
|
-
explorerUrl: getExplorerTxUrl(params.fromChain,
|
|
43243
|
+
explorerUrl: getExplorerTxUrl(params.fromChain, hash)
|
|
43158
43244
|
};
|
|
43159
43245
|
} catch (err) {
|
|
43160
43246
|
let msg = err instanceof Error ? err.message : "Unknown error";
|
|
43161
43247
|
let code2 = classifySwapError(msg);
|
|
43162
|
-
if (
|
|
43248
|
+
if (approvalHash) {
|
|
43163
43249
|
code2 = "APPROVAL_SENT_SWAP_FAILED";
|
|
43164
|
-
msg += `. Approval was sent (tx: ${
|
|
43250
|
+
msg += `. Approval was sent (tx: ${approvalHash}). Check allowance before retrying.`;
|
|
43165
43251
|
}
|
|
43166
43252
|
return { success: false, route, error: msg, code: code2 };
|
|
43167
43253
|
}
|
|
@@ -43193,8 +43279,8 @@ var SwapExecutor = class {
|
|
|
43193
43279
|
if (allowance >= required) return void 0;
|
|
43194
43280
|
this.log("Sending token approval...");
|
|
43195
43281
|
const approveResult = await blockchainClient.contract(erc20).withAddress(fromAssetAddr, fromChain).write.approve([stepApproval.operatorAddress, required], this.walletProvider);
|
|
43196
|
-
this.log(`Approval tx: ${getExplorerTxUrl(fromChain, approveResult.
|
|
43197
|
-
return approveResult.
|
|
43282
|
+
this.log(`Approval tx: ${getExplorerTxUrl(fromChain, approveResult.hash)}`);
|
|
43283
|
+
return approveResult.hash;
|
|
43198
43284
|
}
|
|
43199
43285
|
getBlockchainClient() {
|
|
43200
43286
|
const blockchainClient = this.walletProvider.getBlockchainClient?.() ?? this.options.blockchainClient;
|
|
@@ -43419,11 +43505,11 @@ function registerTransferCommand(program3) {
|
|
|
43419
43505
|
} catch (err) {
|
|
43420
43506
|
mapBroadcastError(err);
|
|
43421
43507
|
}
|
|
43422
|
-
const explorerUrl = getExplorerTxUrl(result.chainKey, result.
|
|
43508
|
+
const explorerUrl = getExplorerTxUrl(result.chainKey, result.hash);
|
|
43423
43509
|
success("Transfer sent!");
|
|
43424
43510
|
output(
|
|
43425
43511
|
{
|
|
43426
|
-
hash: result.
|
|
43512
|
+
hash: result.hash,
|
|
43427
43513
|
chain: result.chainKey,
|
|
43428
43514
|
from: address,
|
|
43429
43515
|
to: resolvedTo,
|
|
@@ -43640,7 +43726,7 @@ function registerSwapCommand(program3) {
|
|
|
43640
43726
|
output(
|
|
43641
43727
|
{
|
|
43642
43728
|
...quoteData,
|
|
43643
|
-
hash: result.
|
|
43729
|
+
hash: result.hash,
|
|
43644
43730
|
fromChain,
|
|
43645
43731
|
toChain,
|
|
43646
43732
|
explorer: result.explorerUrl
|
|
@@ -43723,11 +43809,11 @@ function registerErc20Command(program3) {
|
|
|
43723
43809
|
info(`Approving ${opts.spender} to spend from ${address} on ${chainKey}...`);
|
|
43724
43810
|
const client = provider.getBlockchainClient();
|
|
43725
43811
|
const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, BigInt(amount)], provider);
|
|
43726
|
-
const explorerUrl = getExplorerTxUrl(chainKey, pending.
|
|
43812
|
+
const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
|
|
43727
43813
|
success("Approval sent!");
|
|
43728
43814
|
output(
|
|
43729
43815
|
{
|
|
43730
|
-
hash: pending.
|
|
43816
|
+
hash: pending.hash,
|
|
43731
43817
|
chain: chainKey,
|
|
43732
43818
|
owner: address,
|
|
43733
43819
|
spender: opts.spender,
|
|
@@ -43764,11 +43850,11 @@ function registerErc20Command(program3) {
|
|
|
43764
43850
|
info(`Revoking approval for ${opts.spender} on ${chainKey}...`);
|
|
43765
43851
|
const client = provider.getBlockchainClient();
|
|
43766
43852
|
const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, 0n], provider);
|
|
43767
|
-
const explorerUrl = getExplorerTxUrl(chainKey, pending.
|
|
43853
|
+
const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
|
|
43768
43854
|
success("Approval revoked!");
|
|
43769
43855
|
output(
|
|
43770
43856
|
{
|
|
43771
|
-
hash: pending.
|
|
43857
|
+
hash: pending.hash,
|
|
43772
43858
|
chain: chainKey,
|
|
43773
43859
|
owner: address,
|
|
43774
43860
|
spender: opts.spender,
|
|
@@ -43918,7 +44004,7 @@ function registerErc8004Command(program3) {
|
|
|
43918
44004
|
if (!registered) {
|
|
43919
44005
|
throw new WalletError(
|
|
43920
44006
|
"TX_FAILED",
|
|
43921
|
-
`No Registered event emitted (
|
|
44007
|
+
`No Registered event emitted (hash=${confirmed.hash})`
|
|
43922
44008
|
);
|
|
43923
44009
|
}
|
|
43924
44010
|
success("Agent registered!");
|
|
@@ -43928,9 +44014,9 @@ function registerErc8004Command(program3) {
|
|
|
43928
44014
|
owner: registered.owner,
|
|
43929
44015
|
agentURI: registered.agentURI,
|
|
43930
44016
|
...metadata.length > 0 ? { metadata: Object.fromEntries(metadata) } : {},
|
|
43931
|
-
hash: confirmed.
|
|
44017
|
+
hash: confirmed.hash,
|
|
43932
44018
|
chain: chainKey,
|
|
43933
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44019
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43934
44020
|
},
|
|
43935
44021
|
opts.json
|
|
43936
44022
|
);
|
|
@@ -43964,9 +44050,9 @@ function registerErc8004Command(program3) {
|
|
|
43964
44050
|
{
|
|
43965
44051
|
agentId,
|
|
43966
44052
|
agentURI: opts.uri,
|
|
43967
|
-
hash: confirmed.
|
|
44053
|
+
hash: confirmed.hash,
|
|
43968
44054
|
chain: chainKey,
|
|
43969
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44055
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43970
44056
|
},
|
|
43971
44057
|
opts.json
|
|
43972
44058
|
);
|
|
@@ -43999,9 +44085,9 @@ function registerErc8004Command(program3) {
|
|
|
43999
44085
|
agentId,
|
|
44000
44086
|
key: opts.key,
|
|
44001
44087
|
value: valueBytes,
|
|
44002
|
-
hash: confirmed.
|
|
44088
|
+
hash: confirmed.hash,
|
|
44003
44089
|
chain: chainKey,
|
|
44004
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44090
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44005
44091
|
},
|
|
44006
44092
|
opts.json
|
|
44007
44093
|
);
|
|
@@ -44061,6 +44147,8 @@ function registerErc8004Command(program3) {
|
|
|
44061
44147
|
init_dist();
|
|
44062
44148
|
init_dist3();
|
|
44063
44149
|
var CHAIN_OPT = "EVM chain key (`bsc` and `bsctestnet` have known deployments)";
|
|
44150
|
+
var OPT_PARAMS_OPT = "Optional opaque optParams bytes passed through raw, as 0x-prefixed hex (defaults to empty)";
|
|
44151
|
+
var SUBMIT_OPT_PARAMS_OPT = `${OPT_PARAMS_OPT}. Evaluators may expect deliverable metadata here, e.g. hex-encoded UTF-8 JSON like {"deliverable_url": "..."}`;
|
|
44064
44152
|
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
44065
44153
|
function parseUint(value, label) {
|
|
44066
44154
|
if (!/^\d+$/.test(value)) {
|
|
@@ -44071,6 +44159,16 @@ function parseUint(value, label) {
|
|
|
44071
44159
|
}
|
|
44072
44160
|
return BigInt(value);
|
|
44073
44161
|
}
|
|
44162
|
+
function parseOptParams(value) {
|
|
44163
|
+
if (value === void 0) return "0x";
|
|
44164
|
+
if (!/^0x([0-9a-fA-F]{2})*$/.test(value)) {
|
|
44165
|
+
throw new WalletError(
|
|
44166
|
+
"VALIDATION_ERROR",
|
|
44167
|
+
`--opt-params must be 0x-prefixed bytes (even-length hex): ${value}`
|
|
44168
|
+
);
|
|
44169
|
+
}
|
|
44170
|
+
return value;
|
|
44171
|
+
}
|
|
44074
44172
|
function registerErc8183Command(program3) {
|
|
44075
44173
|
const cmd = program3.command("erc8183").description("ERC-8183 Agentic Commerce \u2014 on-chain job escrows between AI agents");
|
|
44076
44174
|
cmd.command("create-job").description("Create a new job (caller becomes the client)").requiredOption("--provider <address>", "Provider (worker) address").requiredOption("--evaluator <address>", "Evaluator address").requiredOption("--expires-at <unix>", "Expiry as a unix timestamp (seconds)").requiredOption("--description <text>", "Human-readable job description").option("--hook <address>", "Optional hook contract (defaults to none)").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (opts) => {
|
|
@@ -44093,7 +44191,7 @@ function registerErc8183Command(program3) {
|
|
|
44093
44191
|
if (!created) {
|
|
44094
44192
|
throw new WalletError(
|
|
44095
44193
|
"TX_FAILED",
|
|
44096
|
-
`No JobCreated event emitted (
|
|
44194
|
+
`No JobCreated event emitted (hash=${confirmed.hash})`
|
|
44097
44195
|
);
|
|
44098
44196
|
}
|
|
44099
44197
|
success("Job created!");
|
|
@@ -44101,9 +44199,9 @@ function registerErc8183Command(program3) {
|
|
|
44101
44199
|
{
|
|
44102
44200
|
jobId: created.jobId.toString(),
|
|
44103
44201
|
status: "Open",
|
|
44104
|
-
hash: confirmed.
|
|
44202
|
+
hash: confirmed.hash,
|
|
44105
44203
|
chain: chainKey,
|
|
44106
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44204
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44107
44205
|
},
|
|
44108
44206
|
opts.json
|
|
44109
44207
|
);
|
|
@@ -44112,9 +44210,10 @@ function registerErc8183Command(program3) {
|
|
|
44112
44210
|
}
|
|
44113
44211
|
safeExit();
|
|
44114
44212
|
});
|
|
44115
|
-
cmd.command("set-provider <jobId>").description("Set or change the provider (client, while the job is Open)").requiredOption("--provider <address>", "New provider (worker) address").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44213
|
+
cmd.command("set-provider <jobId>").description("Set or change the provider (client, while the job is Open)").requiredOption("--provider <address>", "New provider (worker) address").option("--opt-params <hex>", OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44116
44214
|
try {
|
|
44117
44215
|
const id = parseUint(jobId, "jobId");
|
|
44216
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44118
44217
|
await ensureTrustSDK();
|
|
44119
44218
|
const password3 = await resolvePassword(opts);
|
|
44120
44219
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -44123,16 +44222,16 @@ function registerErc8183Command(program3) {
|
|
|
44123
44222
|
opts.chain
|
|
44124
44223
|
);
|
|
44125
44224
|
info(`Setting provider for job ${jobId} on ${chainKey}...`);
|
|
44126
|
-
const pending = await commerce.write.setProvider([id, opts.provider,
|
|
44225
|
+
const pending = await commerce.write.setProvider([id, opts.provider, optParams], provider);
|
|
44127
44226
|
const confirmed = await pending.wait();
|
|
44128
44227
|
success("Provider set!");
|
|
44129
44228
|
output(
|
|
44130
44229
|
{
|
|
44131
44230
|
jobId,
|
|
44132
44231
|
provider: opts.provider,
|
|
44133
|
-
hash: confirmed.
|
|
44232
|
+
hash: confirmed.hash,
|
|
44134
44233
|
chain: chainKey,
|
|
44135
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44234
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44136
44235
|
},
|
|
44137
44236
|
opts.json
|
|
44138
44237
|
);
|
|
@@ -44141,10 +44240,11 @@ function registerErc8183Command(program3) {
|
|
|
44141
44240
|
}
|
|
44142
44241
|
safeExit();
|
|
44143
44242
|
});
|
|
44144
|
-
cmd.command("set-budget <jobId>").description("Set the escrow budget (atomic units of the payment token)").requiredOption("--amount <atomic>", "Budget in atomic units").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44243
|
+
cmd.command("set-budget <jobId>").description("Set the escrow budget (atomic units of the payment token)").requiredOption("--amount <atomic>", "Budget in atomic units").option("--opt-params <hex>", OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44145
44244
|
try {
|
|
44146
44245
|
const id = parseUint(jobId, "jobId");
|
|
44147
44246
|
const amount = parseUint(opts.amount, "amount");
|
|
44247
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44148
44248
|
await ensureTrustSDK();
|
|
44149
44249
|
const password3 = await resolvePassword(opts);
|
|
44150
44250
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -44153,16 +44253,16 @@ function registerErc8183Command(program3) {
|
|
|
44153
44253
|
opts.chain
|
|
44154
44254
|
);
|
|
44155
44255
|
info(`Setting budget for job ${jobId} on ${chainKey}...`);
|
|
44156
|
-
const pending = await commerce.write.setBudget([id, amount,
|
|
44256
|
+
const pending = await commerce.write.setBudget([id, amount, optParams], provider);
|
|
44157
44257
|
const confirmed = await pending.wait();
|
|
44158
44258
|
success("Budget set!");
|
|
44159
44259
|
output(
|
|
44160
44260
|
{
|
|
44161
44261
|
jobId,
|
|
44162
44262
|
amount: opts.amount,
|
|
44163
|
-
hash: confirmed.
|
|
44263
|
+
hash: confirmed.hash,
|
|
44164
44264
|
chain: chainKey,
|
|
44165
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44265
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44166
44266
|
},
|
|
44167
44267
|
opts.json
|
|
44168
44268
|
);
|
|
@@ -44171,37 +44271,53 @@ function registerErc8183Command(program3) {
|
|
|
44171
44271
|
}
|
|
44172
44272
|
safeExit();
|
|
44173
44273
|
});
|
|
44174
|
-
cmd.command("fund <jobId>").description("Fund a job: approve the budget then deposit it into escrow (two txs)").option(
|
|
44274
|
+
cmd.command("fund <jobId>").description("Fund a job: approve the budget then deposit it into escrow (two txs)").option(
|
|
44275
|
+
"--expected-budget <atomic>",
|
|
44276
|
+
"Pin the budget (atomic units): approve and fund exactly this amount instead of reading it on-chain; the contract reverts with BudgetMismatch if the on-chain budget differs"
|
|
44277
|
+
).option("--opt-params <hex>", OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44175
44278
|
try {
|
|
44176
44279
|
const id = parseUint(jobId, "jobId");
|
|
44280
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44177
44281
|
await ensureTrustSDK();
|
|
44178
44282
|
const password3 = await resolvePassword(opts);
|
|
44179
44283
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
44180
44284
|
const client = provider.getBlockchainClient();
|
|
44181
44285
|
const { commerce, chainKey } = resolveErc8183Contracts(client, opts.chain);
|
|
44182
|
-
|
|
44183
|
-
if (
|
|
44184
|
-
|
|
44185
|
-
|
|
44186
|
-
|
|
44187
|
-
|
|
44286
|
+
let budget;
|
|
44287
|
+
if (opts.expectedBudget !== void 0) {
|
|
44288
|
+
budget = parseUint(opts.expectedBudget, "expected-budget");
|
|
44289
|
+
if (budget === 0n) {
|
|
44290
|
+
throw new WalletError(
|
|
44291
|
+
"VALIDATION_ERROR",
|
|
44292
|
+
"--expected-budget must be greater than zero."
|
|
44293
|
+
);
|
|
44294
|
+
}
|
|
44295
|
+
} else {
|
|
44296
|
+
const job = await commerce.read.getJob([id]);
|
|
44297
|
+
if (job.budget === 0n) {
|
|
44298
|
+
throw new WalletError(
|
|
44299
|
+
"VALIDATION_ERROR",
|
|
44300
|
+
`Job ${jobId} has no budget set \u2014 run \`twak erc8183 set-budget\` before funding.`
|
|
44301
|
+
);
|
|
44302
|
+
}
|
|
44303
|
+
budget = job.budget;
|
|
44188
44304
|
}
|
|
44189
44305
|
const token = await commerce.read.paymentToken([]);
|
|
44190
|
-
info(`Approving ${
|
|
44191
|
-
const approvePending = await erc20.using(client).withAddress(token, chainKey).write.approve([commerce.address,
|
|
44306
|
+
info(`Approving ${budget.toString()} for the escrow on ${chainKey}...`);
|
|
44307
|
+
const approvePending = await erc20.using(client).withAddress(token, chainKey).write.approve([commerce.address, budget], provider);
|
|
44192
44308
|
const approveConfirmed = await approvePending.wait();
|
|
44193
44309
|
info(`Funding job ${jobId}...`);
|
|
44194
|
-
const fundPending = await commerce.write.fund([id,
|
|
44310
|
+
const fundPending = await commerce.write.fund([id, budget, optParams], provider);
|
|
44195
44311
|
const fundConfirmed = await fundPending.wait();
|
|
44196
44312
|
success("Job funded!");
|
|
44197
44313
|
output(
|
|
44198
44314
|
{
|
|
44199
44315
|
jobId,
|
|
44200
44316
|
status: "Funded",
|
|
44201
|
-
approveHash: approveConfirmed.
|
|
44202
|
-
hash: fundConfirmed.
|
|
44317
|
+
approveHash: approveConfirmed.hash,
|
|
44318
|
+
hash: fundConfirmed.hash,
|
|
44203
44319
|
chain: chainKey,
|
|
44204
|
-
explorer: getExplorerTxUrl(chainKey, fundConfirmed.
|
|
44320
|
+
explorer: getExplorerTxUrl(chainKey, fundConfirmed.hash)
|
|
44205
44321
|
},
|
|
44206
44322
|
opts.json
|
|
44207
44323
|
);
|
|
@@ -44210,9 +44326,10 @@ function registerErc8183Command(program3) {
|
|
|
44210
44326
|
}
|
|
44211
44327
|
safeExit();
|
|
44212
44328
|
});
|
|
44213
|
-
cmd.command("submit <jobId>").description("Submit a deliverable (bytes32 commitment) for a funded job").requiredOption("--deliverable <bytes32>", "0x-prefixed 32-byte deliverable commitment").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44329
|
+
cmd.command("submit <jobId>").description("Submit a deliverable (bytes32 commitment) for a funded job").requiredOption("--deliverable <bytes32>", "0x-prefixed 32-byte deliverable commitment").option("--opt-params <hex>", SUBMIT_OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44214
44330
|
try {
|
|
44215
44331
|
const id = parseUint(jobId, "jobId");
|
|
44332
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44216
44333
|
await ensureTrustSDK();
|
|
44217
44334
|
const password3 = await resolvePassword(opts);
|
|
44218
44335
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -44221,16 +44338,16 @@ function registerErc8183Command(program3) {
|
|
|
44221
44338
|
opts.chain
|
|
44222
44339
|
);
|
|
44223
44340
|
info(`Submitting deliverable for job ${jobId} on ${chainKey}...`);
|
|
44224
|
-
const pending = await commerce.write.submit([id, opts.deliverable,
|
|
44341
|
+
const pending = await commerce.write.submit([id, opts.deliverable, optParams], provider);
|
|
44225
44342
|
const confirmed = await pending.wait();
|
|
44226
44343
|
success("Deliverable submitted!");
|
|
44227
44344
|
output(
|
|
44228
44345
|
{
|
|
44229
44346
|
jobId,
|
|
44230
44347
|
status: "Submitted",
|
|
44231
|
-
hash: confirmed.
|
|
44348
|
+
hash: confirmed.hash,
|
|
44232
44349
|
chain: chainKey,
|
|
44233
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44350
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44234
44351
|
},
|
|
44235
44352
|
opts.json
|
|
44236
44353
|
);
|
|
@@ -44239,9 +44356,10 @@ function registerErc8183Command(program3) {
|
|
|
44239
44356
|
}
|
|
44240
44357
|
safeExit();
|
|
44241
44358
|
});
|
|
44242
|
-
cmd.command("complete <jobId>").description("Mark a submitted job complete (evaluator) \u2014 releases escrow").option("--reason <bytes32>", "Optional bytes32 attestation (defaults to zero)").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44359
|
+
cmd.command("complete <jobId>").description("Mark a submitted job complete (evaluator) \u2014 releases escrow").option("--reason <bytes32>", "Optional bytes32 attestation (defaults to zero)").option("--opt-params <hex>", OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44243
44360
|
try {
|
|
44244
44361
|
const id = parseUint(jobId, "jobId");
|
|
44362
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44245
44363
|
await ensureTrustSDK();
|
|
44246
44364
|
const password3 = await resolvePassword(opts);
|
|
44247
44365
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -44251,7 +44369,7 @@ function registerErc8183Command(program3) {
|
|
|
44251
44369
|
);
|
|
44252
44370
|
info(`Completing job ${jobId} on ${chainKey}...`);
|
|
44253
44371
|
const pending = await commerce.write.complete(
|
|
44254
|
-
[id, opts.reason ?? ZERO_BYTES32,
|
|
44372
|
+
[id, opts.reason ?? ZERO_BYTES32, optParams],
|
|
44255
44373
|
provider
|
|
44256
44374
|
);
|
|
44257
44375
|
const confirmed = await pending.wait();
|
|
@@ -44262,9 +44380,9 @@ function registerErc8183Command(program3) {
|
|
|
44262
44380
|
jobId,
|
|
44263
44381
|
status: "Completed",
|
|
44264
44382
|
released: released ? released.amount.toString() : null,
|
|
44265
|
-
hash: confirmed.
|
|
44383
|
+
hash: confirmed.hash,
|
|
44266
44384
|
chain: chainKey,
|
|
44267
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44385
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44268
44386
|
},
|
|
44269
44387
|
opts.json
|
|
44270
44388
|
);
|
|
@@ -44273,9 +44391,10 @@ function registerErc8183Command(program3) {
|
|
|
44273
44391
|
}
|
|
44274
44392
|
safeExit();
|
|
44275
44393
|
});
|
|
44276
|
-
cmd.command("reject <jobId>").description("Reject a job \u2014 refunds the client if funded").option("--reason <bytes32>", "Optional bytes32 reason (defaults to zero)").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44394
|
+
cmd.command("reject <jobId>").description("Reject a job \u2014 refunds the client if funded").option("--reason <bytes32>", "Optional bytes32 reason (defaults to zero)").option("--opt-params <hex>", OPT_PARAMS_OPT).option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44277
44395
|
try {
|
|
44278
44396
|
const id = parseUint(jobId, "jobId");
|
|
44397
|
+
const optParams = parseOptParams(opts.optParams);
|
|
44279
44398
|
await ensureTrustSDK();
|
|
44280
44399
|
const password3 = await resolvePassword(opts);
|
|
44281
44400
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -44285,7 +44404,7 @@ function registerErc8183Command(program3) {
|
|
|
44285
44404
|
);
|
|
44286
44405
|
info(`Rejecting job ${jobId} on ${chainKey}...`);
|
|
44287
44406
|
const pending = await commerce.write.reject(
|
|
44288
|
-
[id, opts.reason ?? ZERO_BYTES32,
|
|
44407
|
+
[id, opts.reason ?? ZERO_BYTES32, optParams],
|
|
44289
44408
|
provider
|
|
44290
44409
|
);
|
|
44291
44410
|
const confirmed = await pending.wait();
|
|
@@ -44296,9 +44415,9 @@ function registerErc8183Command(program3) {
|
|
|
44296
44415
|
jobId,
|
|
44297
44416
|
status: "Rejected",
|
|
44298
44417
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
44299
|
-
hash: confirmed.
|
|
44418
|
+
hash: confirmed.hash,
|
|
44300
44419
|
chain: chainKey,
|
|
44301
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44420
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44302
44421
|
},
|
|
44303
44422
|
opts.json
|
|
44304
44423
|
);
|
|
@@ -44327,9 +44446,9 @@ function registerErc8183Command(program3) {
|
|
|
44327
44446
|
jobId,
|
|
44328
44447
|
status: "Expired",
|
|
44329
44448
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
44330
|
-
hash: confirmed.
|
|
44449
|
+
hash: confirmed.hash,
|
|
44331
44450
|
chain: chainKey,
|
|
44332
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44451
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44333
44452
|
},
|
|
44334
44453
|
opts.json
|
|
44335
44454
|
);
|
|
@@ -44389,9 +44508,9 @@ function registerErc8183Command(program3) {
|
|
|
44389
44508
|
{
|
|
44390
44509
|
jobId,
|
|
44391
44510
|
policy: policyAddr,
|
|
44392
|
-
hash: confirmed.
|
|
44511
|
+
hash: confirmed.hash,
|
|
44393
44512
|
chain: chainKey,
|
|
44394
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44513
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44395
44514
|
},
|
|
44396
44515
|
opts.json
|
|
44397
44516
|
);
|
|
@@ -44417,9 +44536,9 @@ function registerErc8183Command(program3) {
|
|
|
44417
44536
|
output(
|
|
44418
44537
|
{
|
|
44419
44538
|
jobId,
|
|
44420
|
-
hash: confirmed.
|
|
44539
|
+
hash: confirmed.hash,
|
|
44421
44540
|
chain: chainKey,
|
|
44422
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44541
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44423
44542
|
},
|
|
44424
44543
|
opts.json
|
|
44425
44544
|
);
|
|
@@ -44446,9 +44565,9 @@ function registerErc8183Command(program3) {
|
|
|
44446
44565
|
{
|
|
44447
44566
|
jobId,
|
|
44448
44567
|
status: "Expired",
|
|
44449
|
-
hash: confirmed.
|
|
44568
|
+
hash: confirmed.hash,
|
|
44450
44569
|
chain: chainKey,
|
|
44451
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44570
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44452
44571
|
},
|
|
44453
44572
|
opts.json
|
|
44454
44573
|
);
|
|
@@ -44457,6 +44576,45 @@ function registerErc8183Command(program3) {
|
|
|
44457
44576
|
}
|
|
44458
44577
|
safeExit();
|
|
44459
44578
|
});
|
|
44579
|
+
cmd.command("policy-info <jobId>").description("Show dispute-policy state for a job (read-only)").option("--chain <key>", CHAIN_OPT, "bsc").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44580
|
+
try {
|
|
44581
|
+
const id = parseUint(jobId, "jobId");
|
|
44582
|
+
await ensureTrustSDK();
|
|
44583
|
+
const client = new BlockchainClient();
|
|
44584
|
+
const { router, policy, chainKey } = resolveErc8183Contracts(client, opts.chain);
|
|
44585
|
+
const registeredPolicy = await router.read.jobPolicy([id]);
|
|
44586
|
+
const registered = !isZeroAddress(registeredPolicy);
|
|
44587
|
+
const policyContract = registered && registeredPolicy.toLowerCase() !== policy.address.toLowerCase() ? erc8183Policy.using(client).withAddress(registeredPolicy, chainKey) : policy;
|
|
44588
|
+
const [disputeWindow, submittedAt, disputed, rejectVotes, voteQuorum, quorumSnapshot] = await Promise.all([
|
|
44589
|
+
policyContract.read.disputeWindow([]),
|
|
44590
|
+
policyContract.read.submittedAt([id]),
|
|
44591
|
+
policyContract.read.disputed([id]),
|
|
44592
|
+
policyContract.read.rejectVotes([id]),
|
|
44593
|
+
policyContract.read.voteQuorum([]),
|
|
44594
|
+
policyContract.read.disputeQuorumSnapshot([id])
|
|
44595
|
+
]);
|
|
44596
|
+
const settleableAt = submittedAt > 0n ? submittedAt + disputeWindow : null;
|
|
44597
|
+
output(
|
|
44598
|
+
{
|
|
44599
|
+
jobId,
|
|
44600
|
+
policy: policyContract.address,
|
|
44601
|
+
registered,
|
|
44602
|
+
disputeWindow: disputeWindow.toString(),
|
|
44603
|
+
submittedAt: submittedAt.toString(),
|
|
44604
|
+
disputed,
|
|
44605
|
+
rejectVotes: rejectVotes.toString(),
|
|
44606
|
+
voteQuorum: voteQuorum.toString(),
|
|
44607
|
+
quorumSnapshot: quorumSnapshot.toString(),
|
|
44608
|
+
settleableAt: settleableAt?.toString() ?? null,
|
|
44609
|
+
chain: chainKey
|
|
44610
|
+
},
|
|
44611
|
+
opts.json
|
|
44612
|
+
);
|
|
44613
|
+
} catch (err) {
|
|
44614
|
+
handleCommandError(err, opts.json, "policy-info failed");
|
|
44615
|
+
}
|
|
44616
|
+
safeExit();
|
|
44617
|
+
});
|
|
44460
44618
|
cmd.command("dispute <jobId>").description("Raise a dispute on a job via the OptimisticPolicy (client)").option("--chain <key>", CHAIN_OPT, "bsc").option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (jobId, opts) => {
|
|
44461
44619
|
try {
|
|
44462
44620
|
const id = parseUint(jobId, "jobId");
|
|
@@ -44474,9 +44632,9 @@ function registerErc8183Command(program3) {
|
|
|
44474
44632
|
output(
|
|
44475
44633
|
{
|
|
44476
44634
|
jobId,
|
|
44477
|
-
hash: confirmed.
|
|
44635
|
+
hash: confirmed.hash,
|
|
44478
44636
|
chain: chainKey,
|
|
44479
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44637
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44480
44638
|
},
|
|
44481
44639
|
opts.json
|
|
44482
44640
|
);
|
|
@@ -44502,9 +44660,9 @@ function registerErc8183Command(program3) {
|
|
|
44502
44660
|
output(
|
|
44503
44661
|
{
|
|
44504
44662
|
jobId,
|
|
44505
|
-
hash: confirmed.
|
|
44663
|
+
hash: confirmed.hash,
|
|
44506
44664
|
chain: chainKey,
|
|
44507
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44665
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44508
44666
|
},
|
|
44509
44667
|
opts.json
|
|
44510
44668
|
);
|
|
@@ -44570,7 +44728,7 @@ function registerCompeteCommand(program3) {
|
|
|
44570
44728
|
if (!confirmed.events.Registered?.[0]) {
|
|
44571
44729
|
throw new WalletError(
|
|
44572
44730
|
"TX_FAILED",
|
|
44573
|
-
`no Registered event emitted (
|
|
44731
|
+
`no Registered event emitted (hash=${confirmed.hash})`
|
|
44574
44732
|
);
|
|
44575
44733
|
}
|
|
44576
44734
|
success("Registered for BNB HACK: AI TRADING AGENT EDITION!");
|
|
@@ -44579,9 +44737,9 @@ function registerCompeteCommand(program3) {
|
|
|
44579
44737
|
registered: true,
|
|
44580
44738
|
participant,
|
|
44581
44739
|
deadline: toIso(deadline),
|
|
44582
|
-
hash: confirmed.
|
|
44740
|
+
hash: confirmed.hash,
|
|
44583
44741
|
chain: chainKey,
|
|
44584
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44742
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44585
44743
|
},
|
|
44586
44744
|
opts.json
|
|
44587
44745
|
);
|
|
@@ -46259,15 +46417,15 @@ async function ensurePermit2Allowance(args) {
|
|
|
46259
46417
|
[PERMIT2_ADDRESS, BigInt(MAX_UINT256_DECIMAL)],
|
|
46260
46418
|
args.walletProvider
|
|
46261
46419
|
);
|
|
46262
|
-
await waitForTxConfirmation(args.blockchainClient, args.chainKey, args.owner, pending.
|
|
46263
|
-
return { token: args.tokenAddress, chain: args.chainKey,
|
|
46420
|
+
await waitForTxConfirmation(args.blockchainClient, args.chainKey, args.owner, pending.hash);
|
|
46421
|
+
return { token: args.tokenAddress, chain: args.chainKey, hash: pending.hash };
|
|
46264
46422
|
}
|
|
46265
46423
|
var APPROVE_TIMEOUT_MS = 6e4;
|
|
46266
46424
|
var APPROVE_POLL_MS = 2e3;
|
|
46267
|
-
async function waitForTxConfirmation(bc2, chainKey, address,
|
|
46425
|
+
async function waitForTxConfirmation(bc2, chainKey, address, hash) {
|
|
46268
46426
|
const start = Date.now();
|
|
46269
46427
|
while (Date.now() - start < APPROVE_TIMEOUT_MS) {
|
|
46270
|
-
const status = await bc2.findTransactionStatus(chainKey, address,
|
|
46428
|
+
const status = await bc2.findTransactionStatus(chainKey, address, hash);
|
|
46271
46429
|
if (status.confirmed) return;
|
|
46272
46430
|
if (status.failed) {
|
|
46273
46431
|
throw new X402Error(
|
|
@@ -46279,7 +46437,7 @@ async function waitForTxConfirmation(bc2, chainKey, address, txHash) {
|
|
|
46279
46437
|
}
|
|
46280
46438
|
throw new X402Error(
|
|
46281
46439
|
"TX_FAILED",
|
|
46282
|
-
`Permit2 approval ${
|
|
46440
|
+
`Permit2 approval ${hash} not confirmed within ${APPROVE_TIMEOUT_MS / 1e3}s`
|
|
46283
46441
|
);
|
|
46284
46442
|
}
|
|
46285
46443
|
function ipv4MappedToDotted(ip) {
|
|
@@ -46796,7 +46954,7 @@ var TransferActionProvider = class extends ActionProvider {
|
|
|
46796
46954
|
const resolvedTo = await resolveAddressOrName(input2.to);
|
|
46797
46955
|
const atomicAmount = parseAmount(input2.amount, decimals);
|
|
46798
46956
|
const isErc20 = Boolean(tokenAddress);
|
|
46799
|
-
let
|
|
46957
|
+
let hash;
|
|
46800
46958
|
if (isErc20) {
|
|
46801
46959
|
if (!this.blockchainClient) {
|
|
46802
46960
|
throw new TransferError(
|
|
@@ -46805,19 +46963,19 @@ var TransferActionProvider = class extends ActionProvider {
|
|
|
46805
46963
|
);
|
|
46806
46964
|
}
|
|
46807
46965
|
const pending = await this.blockchainClient.contract(erc20).withAddress(tokenAddress, chainKey).write.transfer([resolvedTo, BigInt(atomicAmount)], signer);
|
|
46808
|
-
|
|
46966
|
+
hash = pending.hash;
|
|
46809
46967
|
} else {
|
|
46810
|
-
|
|
46968
|
+
hash = await signer.sendTransaction({
|
|
46811
46969
|
chainId: caip2,
|
|
46812
46970
|
to: resolvedTo,
|
|
46813
46971
|
data: "0x",
|
|
46814
46972
|
value: "0x" + BigInt(atomicAmount).toString(16)
|
|
46815
46973
|
});
|
|
46816
46974
|
}
|
|
46817
|
-
const explorerUrl = getExplorerTxUrl(chainKey,
|
|
46975
|
+
const explorerUrl = getExplorerTxUrl(chainKey, hash);
|
|
46818
46976
|
return {
|
|
46819
46977
|
success: true,
|
|
46820
|
-
|
|
46978
|
+
hash,
|
|
46821
46979
|
to: resolvedTo,
|
|
46822
46980
|
resolvedFrom: input2.to !== resolvedTo ? input2.to : void 0,
|
|
46823
46981
|
explorer: explorerUrl || void 0
|
|
@@ -46902,7 +47060,7 @@ var SwapActionProvider = class extends ActionProvider {
|
|
|
46902
47060
|
const outputAmt = formatAmount(lastStep.to.amount, lastStep.to.asset.metadata.decimals);
|
|
46903
47061
|
return {
|
|
46904
47062
|
success: true,
|
|
46905
|
-
|
|
47063
|
+
hash: result.hash,
|
|
46906
47064
|
summary: `${inputAmt} ${firstStep.from.asset.metadata.symbol} -> ${outputAmt} ${lastStep.to.asset.metadata.symbol}`,
|
|
46907
47065
|
provider: result.route.steps.map((s2) => s2.provider.name).join(" -> "),
|
|
46908
47066
|
explorer: result.explorerUrl || void 0
|
|
@@ -47364,7 +47522,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47364
47522
|
hdWallet,
|
|
47365
47523
|
chainKey
|
|
47366
47524
|
});
|
|
47367
|
-
return { hash: result.
|
|
47525
|
+
return { hash: result.hash, chain: result.chainKey };
|
|
47368
47526
|
}
|
|
47369
47527
|
const chain2 = requireChain(chainKey);
|
|
47370
47528
|
if (chain2.namespace !== "eip155") {
|
|
@@ -47376,24 +47534,24 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47376
47534
|
if (input2.tokenAddress) assertEvmAddress(input2.tokenAddress, "tokenAddress");
|
|
47377
47535
|
const caipChainId = `${chain2.namespace}:${chain2.chainId}`;
|
|
47378
47536
|
const atomicAmount = parseAmount(input2.amount, decimals);
|
|
47379
|
-
let
|
|
47537
|
+
let hash;
|
|
47380
47538
|
if (input2.tokenAddress) {
|
|
47381
47539
|
if (!this.blockchainClient) {
|
|
47382
47540
|
throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
|
|
47383
47541
|
}
|
|
47384
47542
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.transfer([input2.to, BigInt(atomicAmount)], wallet);
|
|
47385
|
-
|
|
47543
|
+
hash = pending.hash;
|
|
47386
47544
|
} else {
|
|
47387
47545
|
assertEvmAddress(input2.to, "to");
|
|
47388
47546
|
const valueHex = "0x" + BigInt(atomicAmount).toString(16);
|
|
47389
|
-
|
|
47547
|
+
hash = await wallet.sendTransaction({
|
|
47390
47548
|
chainId: caipChainId,
|
|
47391
47549
|
to: input2.to,
|
|
47392
47550
|
data: "0x",
|
|
47393
47551
|
value: valueHex
|
|
47394
47552
|
});
|
|
47395
47553
|
}
|
|
47396
|
-
return { hash
|
|
47554
|
+
return { hash, chain: chainKey };
|
|
47397
47555
|
}
|
|
47398
47556
|
};
|
|
47399
47557
|
}
|
|
@@ -47424,7 +47582,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47424
47582
|
}
|
|
47425
47583
|
const amount = input2.amount === "unlimited" ? "115792089237316195423570985008687907853269984665640564039457584007913129639935" : input2.amount;
|
|
47426
47584
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, BigInt(amount)], wallet);
|
|
47427
|
-
return { hash: pending.
|
|
47585
|
+
return { hash: pending.hash, chain: chainKey };
|
|
47428
47586
|
}
|
|
47429
47587
|
};
|
|
47430
47588
|
}
|
|
@@ -47453,7 +47611,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47453
47611
|
throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
|
|
47454
47612
|
}
|
|
47455
47613
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, 0n], wallet);
|
|
47456
|
-
return { hash: pending.
|
|
47614
|
+
return { hash: pending.hash, chain: chainKey };
|
|
47457
47615
|
}
|
|
47458
47616
|
};
|
|
47459
47617
|
}
|
|
@@ -47923,7 +48081,7 @@ var OnrampActionProvider = class extends ActionProvider {
|
|
|
47923
48081
|
if (cap) return { success: false, ...cap };
|
|
47924
48082
|
}
|
|
47925
48083
|
const atomic = parseAmount(input2.cryptoAmount, decimals);
|
|
47926
|
-
let
|
|
48084
|
+
let hash;
|
|
47927
48085
|
if (input2.tokenAddress) {
|
|
47928
48086
|
if (!this.blockchainClient) {
|
|
47929
48087
|
throw new TransferError(
|
|
@@ -47932,19 +48090,19 @@ var OnrampActionProvider = class extends ActionProvider {
|
|
|
47932
48090
|
);
|
|
47933
48091
|
}
|
|
47934
48092
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.transfer([input2.depositAddress, BigInt(atomic)], signer);
|
|
47935
|
-
|
|
48093
|
+
hash = pending.hash;
|
|
47936
48094
|
} else {
|
|
47937
|
-
|
|
48095
|
+
hash = await signer.sendTransaction({
|
|
47938
48096
|
chainId: caip2,
|
|
47939
48097
|
to: input2.depositAddress,
|
|
47940
48098
|
data: "0x",
|
|
47941
48099
|
value: "0x" + BigInt(atomic).toString(16)
|
|
47942
48100
|
});
|
|
47943
48101
|
}
|
|
47944
|
-
const explorerUrl = getExplorerTxUrl(chainKey,
|
|
48102
|
+
const explorerUrl = getExplorerTxUrl(chainKey, hash) || void 0;
|
|
47945
48103
|
return {
|
|
47946
48104
|
success: true,
|
|
47947
|
-
|
|
48105
|
+
hash,
|
|
47948
48106
|
chain: chainKey,
|
|
47949
48107
|
tokenAddress: input2.tokenAddress,
|
|
47950
48108
|
to: input2.depositAddress,
|
|
@@ -48114,7 +48272,7 @@ var AutomateActionProvider = class extends ActionProvider {
|
|
|
48114
48272
|
await this.automationStore.update(record2.id, { lastRunAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
48115
48273
|
return {
|
|
48116
48274
|
success: true,
|
|
48117
|
-
|
|
48275
|
+
hash: result.hash,
|
|
48118
48276
|
automationId: record2.id,
|
|
48119
48277
|
swapped: `${record2.amount} ${record2.fromToken} \u2192 ${record2.toToken}`,
|
|
48120
48278
|
explorer: result.explorerUrl || void 0
|
|
@@ -48330,13 +48488,13 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48330
48488
|
if (!registered) {
|
|
48331
48489
|
throw new WalletError(
|
|
48332
48490
|
"TX_FAILED",
|
|
48333
|
-
`erc8004_register: no Registered event emitted (
|
|
48491
|
+
`erc8004_register: no Registered event emitted (hash=${confirmed.hash})`
|
|
48334
48492
|
);
|
|
48335
48493
|
}
|
|
48336
48494
|
return {
|
|
48337
48495
|
success: true,
|
|
48338
48496
|
agentId: registered.agentId.toString(),
|
|
48339
|
-
|
|
48497
|
+
hash: confirmed.hash,
|
|
48340
48498
|
owner: registered.owner,
|
|
48341
48499
|
agentURI: registered.agentURI,
|
|
48342
48500
|
...entries.length > 0 ? { metadata: Object.fromEntries(entries) } : {},
|
|
@@ -48363,7 +48521,7 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48363
48521
|
this.walletContext.activeWallet()
|
|
48364
48522
|
);
|
|
48365
48523
|
const confirmed = await pending.wait();
|
|
48366
|
-
return { success: true,
|
|
48524
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48367
48525
|
}
|
|
48368
48526
|
};
|
|
48369
48527
|
}
|
|
@@ -48387,7 +48545,7 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48387
48545
|
this.walletContext.activeWallet()
|
|
48388
48546
|
);
|
|
48389
48547
|
const confirmed = await pending.wait();
|
|
48390
|
-
return { success: true,
|
|
48548
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48391
48549
|
}
|
|
48392
48550
|
};
|
|
48393
48551
|
}
|
|
@@ -48453,6 +48611,7 @@ var jobIdSchema = import_zod17.z.string().regex(/^\d+$/, "jobId must be a decima
|
|
|
48453
48611
|
var amountSchema = import_zod17.z.string().regex(/^\d+$/, "amount must be an atomic (base-unit) integer string.");
|
|
48454
48612
|
var evmAddressSchema = import_zod17.z.string().refine(isEvmAddress, "must be a 0x-prefixed 40-hex EVM address.");
|
|
48455
48613
|
var bytes32Schema = import_zod17.z.string().regex(/^0x[0-9a-fA-F]{64}$/, "must be 0x-prefixed 32-byte hex.");
|
|
48614
|
+
var optParamsSchema = import_zod17.z.string().regex(/^0x([0-9a-fA-F]{2})*$/, "optParams must be 0x-prefixed bytes.").optional().describe("Optional opaque optParams bytes forwarded raw to the contract (defaults to empty).");
|
|
48456
48615
|
var ZERO_BYTES322 = `0x${"0".repeat(64)}`;
|
|
48457
48616
|
var Erc8183ActionProvider = class extends ActionProvider {
|
|
48458
48617
|
constructor(blockchainClient, walletContext) {
|
|
@@ -48473,6 +48632,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48473
48632
|
this.reject(),
|
|
48474
48633
|
this.claimRefund(),
|
|
48475
48634
|
this.status(),
|
|
48635
|
+
this.policyInfo(),
|
|
48476
48636
|
this.registerJob(),
|
|
48477
48637
|
this.settle(),
|
|
48478
48638
|
this.markExpired(),
|
|
@@ -48514,13 +48674,13 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48514
48674
|
if (!created) {
|
|
48515
48675
|
throw new WalletError(
|
|
48516
48676
|
"TX_FAILED",
|
|
48517
|
-
`erc8183_create_job: no JobCreated event emitted (
|
|
48677
|
+
`erc8183_create_job: no JobCreated event emitted (hash=${confirmed.hash})`
|
|
48518
48678
|
);
|
|
48519
48679
|
}
|
|
48520
48680
|
return {
|
|
48521
48681
|
success: true,
|
|
48522
48682
|
jobId: created.jobId.toString(),
|
|
48523
|
-
|
|
48683
|
+
hash: confirmed.hash,
|
|
48524
48684
|
status: "Open",
|
|
48525
48685
|
chain: chainKey
|
|
48526
48686
|
};
|
|
@@ -48534,16 +48694,17 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48534
48694
|
schema: import_zod17.z.object({
|
|
48535
48695
|
jobId: jobIdSchema,
|
|
48536
48696
|
provider: evmAddressSchema.describe("New provider (worker) address."),
|
|
48697
|
+
optParams: optParamsSchema,
|
|
48537
48698
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48538
48699
|
}),
|
|
48539
48700
|
invoke: async (_ctx, input2) => {
|
|
48540
48701
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48541
48702
|
const pending = await commerce.write.setProvider(
|
|
48542
|
-
[BigInt(input2.jobId), input2.provider, "0x"],
|
|
48703
|
+
[BigInt(input2.jobId), input2.provider, input2.optParams ?? "0x"],
|
|
48543
48704
|
this.walletContext.activeWallet()
|
|
48544
48705
|
);
|
|
48545
48706
|
const confirmed = await pending.wait();
|
|
48546
|
-
return { success: true,
|
|
48707
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48547
48708
|
}
|
|
48548
48709
|
};
|
|
48549
48710
|
}
|
|
@@ -48554,47 +48715,64 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48554
48715
|
schema: import_zod17.z.object({
|
|
48555
48716
|
jobId: jobIdSchema,
|
|
48556
48717
|
amount: amountSchema.describe("Budget in atomic units of the payment token."),
|
|
48718
|
+
optParams: optParamsSchema,
|
|
48557
48719
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48558
48720
|
}),
|
|
48559
48721
|
invoke: async (_ctx, input2) => {
|
|
48560
48722
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48561
48723
|
const pending = await commerce.write.setBudget(
|
|
48562
|
-
[BigInt(input2.jobId), BigInt(input2.amount), "0x"],
|
|
48724
|
+
[BigInt(input2.jobId), BigInt(input2.amount), input2.optParams ?? "0x"],
|
|
48563
48725
|
this.walletContext.activeWallet()
|
|
48564
48726
|
);
|
|
48565
48727
|
const confirmed = await pending.wait();
|
|
48566
|
-
return { success: true,
|
|
48728
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48567
48729
|
}
|
|
48568
48730
|
};
|
|
48569
48731
|
}
|
|
48570
48732
|
fund() {
|
|
48571
48733
|
return {
|
|
48572
48734
|
name: "erc8183_fund",
|
|
48573
|
-
description: "Fund a job: deposits the on-chain budget into escrow. The escrow pulls the payment token via transferFrom, so this first sends an ERC-20 approval for the exact budget, then calls fund \u2014 two transactions. Moves the job to `Funded`.",
|
|
48735
|
+
description: "Fund a job: deposits the on-chain budget into escrow. The escrow pulls the payment token via transferFrom, so this first sends an ERC-20 approval for the exact budget, then calls fund \u2014 two transactions. Moves the job to `Funded`. Pass `expectedBudget` to pin the amount instead of reading it on-chain.",
|
|
48574
48736
|
schema: import_zod17.z.object({
|
|
48575
48737
|
jobId: jobIdSchema,
|
|
48738
|
+
expectedBudget: amountSchema.optional().describe(
|
|
48739
|
+
"Pin the budget (atomic units): approve and fund exactly this amount instead of reading it on-chain. The contract reverts (BudgetMismatch) if the on-chain budget differs."
|
|
48740
|
+
),
|
|
48741
|
+
optParams: optParamsSchema,
|
|
48576
48742
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48577
48743
|
}),
|
|
48578
48744
|
invoke: async (_ctx, input2) => {
|
|
48579
48745
|
const { client, commerce, chainKey } = this.bind(input2.chain);
|
|
48580
48746
|
const jobId = BigInt(input2.jobId);
|
|
48581
|
-
|
|
48582
|
-
if (
|
|
48583
|
-
|
|
48584
|
-
|
|
48585
|
-
|
|
48586
|
-
|
|
48747
|
+
let budget;
|
|
48748
|
+
if (input2.expectedBudget !== void 0) {
|
|
48749
|
+
budget = BigInt(input2.expectedBudget);
|
|
48750
|
+
if (budget === 0n) {
|
|
48751
|
+
throw new WalletError("VALIDATION_ERROR", "expectedBudget must be greater than zero.");
|
|
48752
|
+
}
|
|
48753
|
+
} else {
|
|
48754
|
+
const job = await commerce.read.getJob([jobId]);
|
|
48755
|
+
if (job.budget === 0n) {
|
|
48756
|
+
throw new WalletError(
|
|
48757
|
+
"VALIDATION_ERROR",
|
|
48758
|
+
`Job ${input2.jobId} has no budget set \u2014 call erc8183_set_budget before funding.`
|
|
48759
|
+
);
|
|
48760
|
+
}
|
|
48761
|
+
budget = job.budget;
|
|
48587
48762
|
}
|
|
48588
48763
|
const token = await commerce.read.paymentToken([]);
|
|
48589
48764
|
const wallet = this.walletContext.activeWallet();
|
|
48590
|
-
const approvePending = await erc20.using(client).withAddress(token, chainKey).write.approve([commerce.address,
|
|
48765
|
+
const approvePending = await erc20.using(client).withAddress(token, chainKey).write.approve([commerce.address, budget], wallet);
|
|
48591
48766
|
const approveConfirmed = await approvePending.wait();
|
|
48592
|
-
const fundPending = await commerce.write.fund(
|
|
48767
|
+
const fundPending = await commerce.write.fund(
|
|
48768
|
+
[jobId, budget, input2.optParams ?? "0x"],
|
|
48769
|
+
wallet
|
|
48770
|
+
);
|
|
48593
48771
|
const fundConfirmed = await fundPending.wait();
|
|
48594
48772
|
return {
|
|
48595
48773
|
success: true,
|
|
48596
|
-
approveHash: approveConfirmed.
|
|
48597
|
-
|
|
48774
|
+
approveHash: approveConfirmed.hash,
|
|
48775
|
+
hash: fundConfirmed.hash,
|
|
48598
48776
|
status: "Funded",
|
|
48599
48777
|
chain: chainKey
|
|
48600
48778
|
};
|
|
@@ -48610,16 +48788,19 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48610
48788
|
deliverable: bytes32Schema.describe(
|
|
48611
48789
|
"bytes32 deliverable commitment (e.g. a content hash)."
|
|
48612
48790
|
),
|
|
48791
|
+
optParams: optParamsSchema.describe(
|
|
48792
|
+
'Optional opaque optParams bytes forwarded raw to the contract (defaults to empty). Evaluators may expect deliverable metadata here, e.g. hex-encoded UTF-8 JSON like {"deliverable_url": "..."}.'
|
|
48793
|
+
),
|
|
48613
48794
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48614
48795
|
}),
|
|
48615
48796
|
invoke: async (_ctx, input2) => {
|
|
48616
48797
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48617
48798
|
const pending = await commerce.write.submit(
|
|
48618
|
-
[BigInt(input2.jobId), input2.deliverable, "0x"],
|
|
48799
|
+
[BigInt(input2.jobId), input2.deliverable, input2.optParams ?? "0x"],
|
|
48619
48800
|
this.walletContext.activeWallet()
|
|
48620
48801
|
);
|
|
48621
48802
|
const confirmed = await pending.wait();
|
|
48622
|
-
return { success: true,
|
|
48803
|
+
return { success: true, hash: confirmed.hash, status: "Submitted", chain: chainKey };
|
|
48623
48804
|
}
|
|
48624
48805
|
};
|
|
48625
48806
|
}
|
|
@@ -48630,19 +48811,20 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48630
48811
|
schema: import_zod17.z.object({
|
|
48631
48812
|
jobId: jobIdSchema,
|
|
48632
48813
|
reason: bytes32Schema.optional().describe("Optional bytes32 reason/attestation (defaults to zero)."),
|
|
48814
|
+
optParams: optParamsSchema,
|
|
48633
48815
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48634
48816
|
}),
|
|
48635
48817
|
invoke: async (_ctx, input2) => {
|
|
48636
48818
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48637
48819
|
const pending = await commerce.write.complete(
|
|
48638
|
-
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, "0x"],
|
|
48820
|
+
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, input2.optParams ?? "0x"],
|
|
48639
48821
|
this.walletContext.activeWallet()
|
|
48640
48822
|
);
|
|
48641
48823
|
const confirmed = await pending.wait();
|
|
48642
48824
|
const released = confirmed.events.PaymentReleased?.[0];
|
|
48643
48825
|
return {
|
|
48644
48826
|
success: true,
|
|
48645
|
-
|
|
48827
|
+
hash: confirmed.hash,
|
|
48646
48828
|
status: "Completed",
|
|
48647
48829
|
released: released ? released.amount.toString() : null,
|
|
48648
48830
|
chain: chainKey
|
|
@@ -48657,19 +48839,20 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48657
48839
|
schema: import_zod17.z.object({
|
|
48658
48840
|
jobId: jobIdSchema,
|
|
48659
48841
|
reason: bytes32Schema.optional().describe("Optional bytes32 reason (defaults to zero)."),
|
|
48842
|
+
optParams: optParamsSchema,
|
|
48660
48843
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48661
48844
|
}),
|
|
48662
48845
|
invoke: async (_ctx, input2) => {
|
|
48663
48846
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48664
48847
|
const pending = await commerce.write.reject(
|
|
48665
|
-
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, "0x"],
|
|
48848
|
+
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, input2.optParams ?? "0x"],
|
|
48666
48849
|
this.walletContext.activeWallet()
|
|
48667
48850
|
);
|
|
48668
48851
|
const confirmed = await pending.wait();
|
|
48669
48852
|
const refunded = confirmed.events.Refunded?.[0];
|
|
48670
48853
|
return {
|
|
48671
48854
|
success: true,
|
|
48672
|
-
|
|
48855
|
+
hash: confirmed.hash,
|
|
48673
48856
|
status: "Rejected",
|
|
48674
48857
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
48675
48858
|
chain: chainKey
|
|
@@ -48695,7 +48878,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48695
48878
|
const refunded = confirmed.events.Refunded?.[0];
|
|
48696
48879
|
return {
|
|
48697
48880
|
success: true,
|
|
48698
|
-
|
|
48881
|
+
hash: confirmed.hash,
|
|
48699
48882
|
status: "Expired",
|
|
48700
48883
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
48701
48884
|
chain: chainKey
|
|
@@ -48737,6 +48920,46 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48737
48920
|
}
|
|
48738
48921
|
};
|
|
48739
48922
|
}
|
|
48923
|
+
policyInfo() {
|
|
48924
|
+
return {
|
|
48925
|
+
name: "erc8183_policy_info",
|
|
48926
|
+
description: "Read the dispute-policy state of a job: the registered policy address, dispute window, submission time, dispute/vote tallies, and when the job becomes settleable (submittedAt + disputeWindow). Use before `erc8183_settle` to check timing, and before `erc8183_dispute`/`erc8183_vote_reject` to avoid opaque reverts.",
|
|
48927
|
+
schema: import_zod17.z.object({
|
|
48928
|
+
jobId: jobIdSchema,
|
|
48929
|
+
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48930
|
+
}),
|
|
48931
|
+
invoke: async (_ctx, input2) => {
|
|
48932
|
+
const { client, router, policy, chainKey } = this.bind(input2.chain);
|
|
48933
|
+
const jobId = BigInt(input2.jobId);
|
|
48934
|
+
const registeredPolicy = await router.read.jobPolicy([jobId]);
|
|
48935
|
+
const registered = !isZeroAddress(registeredPolicy);
|
|
48936
|
+
const policyContract = registered && registeredPolicy.toLowerCase() !== policy.address.toLowerCase() ? erc8183Policy.using(client).withAddress(registeredPolicy, chainKey) : policy;
|
|
48937
|
+
const [disputeWindow, submittedAt, disputed, rejectVotes, voteQuorum, quorumSnapshot] = await Promise.all([
|
|
48938
|
+
policyContract.read.disputeWindow([]),
|
|
48939
|
+
policyContract.read.submittedAt([jobId]),
|
|
48940
|
+
policyContract.read.disputed([jobId]),
|
|
48941
|
+
policyContract.read.rejectVotes([jobId]),
|
|
48942
|
+
policyContract.read.voteQuorum([]),
|
|
48943
|
+
policyContract.read.disputeQuorumSnapshot([jobId])
|
|
48944
|
+
]);
|
|
48945
|
+
const settleableAt = submittedAt > 0n ? submittedAt + disputeWindow : null;
|
|
48946
|
+
return {
|
|
48947
|
+
success: true,
|
|
48948
|
+
jobId: input2.jobId,
|
|
48949
|
+
policy: policyContract.address,
|
|
48950
|
+
registered,
|
|
48951
|
+
disputeWindow: disputeWindow.toString(),
|
|
48952
|
+
submittedAt: submittedAt.toString(),
|
|
48953
|
+
disputed,
|
|
48954
|
+
rejectVotes: rejectVotes.toString(),
|
|
48955
|
+
voteQuorum: voteQuorum.toString(),
|
|
48956
|
+
quorumSnapshot: quorumSnapshot.toString(),
|
|
48957
|
+
settleableAt: settleableAt?.toString() ?? null,
|
|
48958
|
+
chain: chainKey
|
|
48959
|
+
};
|
|
48960
|
+
}
|
|
48961
|
+
};
|
|
48962
|
+
}
|
|
48740
48963
|
// ----- Router -------------------------------------------------------------
|
|
48741
48964
|
registerJob() {
|
|
48742
48965
|
return {
|
|
@@ -48754,7 +48977,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48754
48977
|
this.walletContext.activeWallet()
|
|
48755
48978
|
);
|
|
48756
48979
|
const confirmed = await pending.wait();
|
|
48757
|
-
return { success: true,
|
|
48980
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48758
48981
|
}
|
|
48759
48982
|
};
|
|
48760
48983
|
}
|
|
@@ -48774,7 +48997,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48774
48997
|
this.walletContext.activeWallet()
|
|
48775
48998
|
);
|
|
48776
48999
|
const confirmed = await pending.wait();
|
|
48777
|
-
return { success: true,
|
|
49000
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48778
49001
|
}
|
|
48779
49002
|
};
|
|
48780
49003
|
}
|
|
@@ -48793,7 +49016,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48793
49016
|
this.walletContext.activeWallet()
|
|
48794
49017
|
);
|
|
48795
49018
|
const confirmed = await pending.wait();
|
|
48796
|
-
return { success: true,
|
|
49019
|
+
return { success: true, hash: confirmed.hash, status: "Expired", chain: chainKey };
|
|
48797
49020
|
}
|
|
48798
49021
|
};
|
|
48799
49022
|
}
|
|
@@ -48813,7 +49036,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48813
49036
|
this.walletContext.activeWallet()
|
|
48814
49037
|
);
|
|
48815
49038
|
const confirmed = await pending.wait();
|
|
48816
|
-
return { success: true,
|
|
49039
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48817
49040
|
}
|
|
48818
49041
|
};
|
|
48819
49042
|
}
|
|
@@ -48832,7 +49055,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48832
49055
|
this.walletContext.activeWallet()
|
|
48833
49056
|
);
|
|
48834
49057
|
const confirmed = await pending.wait();
|
|
48835
|
-
return { success: true,
|
|
49058
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48836
49059
|
}
|
|
48837
49060
|
};
|
|
48838
49061
|
}
|
|
@@ -48903,14 +49126,14 @@ var CompetitionActionProvider = class extends ActionProvider {
|
|
|
48903
49126
|
if (!confirmed.events.Registered?.[0]) {
|
|
48904
49127
|
throw new WalletError(
|
|
48905
49128
|
"TX_FAILED",
|
|
48906
|
-
`competition_register: no Registered event emitted (
|
|
49129
|
+
`competition_register: no Registered event emitted (hash=${confirmed.hash})`
|
|
48907
49130
|
);
|
|
48908
49131
|
}
|
|
48909
49132
|
return {
|
|
48910
49133
|
success: true,
|
|
48911
49134
|
registered: true,
|
|
48912
49135
|
participant,
|
|
48913
|
-
|
|
49136
|
+
hash: confirmed.hash,
|
|
48914
49137
|
deadline: toIso2(deadline),
|
|
48915
49138
|
chain: CHAIN
|
|
48916
49139
|
};
|
|
@@ -53915,7 +54138,7 @@ async function runAutomationsTick(deps) {
|
|
|
53915
54138
|
runCount: (auto.runCount ?? 0) + 1
|
|
53916
54139
|
});
|
|
53917
54140
|
log("info", `DCA executed: ${res.explorerUrl}`);
|
|
53918
|
-
result.executed.push({ id: auto.id, type: "dca",
|
|
54141
|
+
result.executed.push({ id: auto.id, type: "dca", hash: res.hash });
|
|
53919
54142
|
} else {
|
|
53920
54143
|
log("warn", `DCA ${auto.id} failed: ${res.error}`);
|
|
53921
54144
|
result.errors++;
|
|
@@ -53963,7 +54186,7 @@ async function runAutomationsTick(deps) {
|
|
|
53963
54186
|
lastRunAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53964
54187
|
});
|
|
53965
54188
|
log("info", `Limit order executed: ${res.explorerUrl}`);
|
|
53966
|
-
result.executed.push({ id: auto.id, type: "limit",
|
|
54189
|
+
result.executed.push({ id: auto.id, type: "limit", hash: res.hash });
|
|
53967
54190
|
} else {
|
|
53968
54191
|
log("warn", `Limit order ${auto.id} failed: ${res.error}`);
|
|
53969
54192
|
result.errors++;
|
|
@@ -54519,7 +54742,7 @@ ${url}`);
|
|
|
54519
54742
|
} catch (err) {
|
|
54520
54743
|
mapBroadcastError(err);
|
|
54521
54744
|
}
|
|
54522
|
-
const explorerUrl = getExplorerTxUrl(result.chainKey, result.
|
|
54745
|
+
const explorerUrl = getExplorerTxUrl(result.chainKey, result.hash);
|
|
54523
54746
|
success("Off-ramp payout broadcast!");
|
|
54524
54747
|
if (!opts.json) {
|
|
54525
54748
|
info(
|
|
@@ -54528,7 +54751,7 @@ ${url}`);
|
|
|
54528
54751
|
}
|
|
54529
54752
|
output(
|
|
54530
54753
|
{
|
|
54531
|
-
hash: result.
|
|
54754
|
+
hash: result.hash,
|
|
54532
54755
|
chain: result.chainKey,
|
|
54533
54756
|
from: address,
|
|
54534
54757
|
to: opts.to,
|
|
@@ -54913,7 +55136,7 @@ function registerX402Command(program3) {
|
|
|
54913
55136
|
confirmApproval: opts.autoApprove ? autoApproveConfirm : makeReadlineApprovalConfirm()
|
|
54914
55137
|
});
|
|
54915
55138
|
if (approval) {
|
|
54916
|
-
info(`x402: Permit2 approved (one-time): tx ${approval.
|
|
55139
|
+
info(`x402: Permit2 approved (one-time): tx ${approval.hash}`);
|
|
54917
55140
|
}
|
|
54918
55141
|
if (payment) {
|
|
54919
55142
|
info(
|
|
@@ -55028,7 +55251,7 @@ var crypto7 = __toESM(require("crypto"));
|
|
|
55028
55251
|
// package.json
|
|
55029
55252
|
var package_default = {
|
|
55030
55253
|
name: "@trustwallet/cli",
|
|
55031
|
-
version: "0.
|
|
55254
|
+
version: "0.19.0",
|
|
55032
55255
|
description: "TWAK CLI \u2014 command-line interface for Trust Wallet Agent Kit",
|
|
55033
55256
|
main: "dist/index.js",
|
|
55034
55257
|
types: "dist/index.d.ts",
|
|
@@ -55404,7 +55627,7 @@ function registerWatchCommand(program3) {
|
|
|
55404
55627
|
tickResults.automations.executed.push({
|
|
55405
55628
|
id: auto.id,
|
|
55406
55629
|
type: "dca",
|
|
55407
|
-
|
|
55630
|
+
hash: result.hash,
|
|
55408
55631
|
explorer: result.explorerUrl
|
|
55409
55632
|
});
|
|
55410
55633
|
} else {
|
|
@@ -55472,7 +55695,7 @@ function registerWatchCommand(program3) {
|
|
|
55472
55695
|
tickResults.automations.executed.push({
|
|
55473
55696
|
id: auto.id,
|
|
55474
55697
|
type: "limit",
|
|
55475
|
-
|
|
55698
|
+
hash: result.hash,
|
|
55476
55699
|
explorer: result.explorerUrl
|
|
55477
55700
|
});
|
|
55478
55701
|
} else {
|