@trustwallet/cli 0.17.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/erc20.d.ts.map +1 -1
- package/dist/commands/erc8004.d.ts.map +1 -1
- package/dist/commands/erc8183.d.ts.map +1 -1
- package/dist/commands/onramp.d.ts.map +1 -1
- package/dist/commands/transfer.d.ts.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/index.js +1653 -1103
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -3134,6 +3134,7 @@ __export(dist_exports, {
|
|
|
3134
3134
|
SOLANA_NATIVE_ADDRESS: () => SOLANA_NATIVE_ADDRESS,
|
|
3135
3135
|
SWAP_ERROR_CODES: () => SWAP_ERROR_CODES,
|
|
3136
3136
|
SwapError: () => SwapError,
|
|
3137
|
+
TESTNET_CHAINS: () => TESTNET_CHAINS,
|
|
3137
3138
|
TRANSFER_ERROR_CODES: () => TRANSFER_ERROR_CODES,
|
|
3138
3139
|
TransferError: () => TransferError,
|
|
3139
3140
|
TwakApiError: () => TwakApiError,
|
|
@@ -3178,6 +3179,7 @@ __export(dist_exports, {
|
|
|
3178
3179
|
isEvmAddress: () => isEvmAddress,
|
|
3179
3180
|
isNativeTokenId: () => isNativeTokenId,
|
|
3180
3181
|
isRateLimited: () => isRateLimited,
|
|
3182
|
+
isTestnetChain: () => isTestnetChain,
|
|
3181
3183
|
isZeroAddress: () => isZeroAddress,
|
|
3182
3184
|
lookupKnownTokenDecimals: () => lookupKnownTokenDecimals,
|
|
3183
3185
|
parseAmount: () => parseAmount,
|
|
@@ -3200,13 +3202,17 @@ __export(dist_exports, {
|
|
|
3200
3202
|
});
|
|
3201
3203
|
function getChainById(chainKey) {
|
|
3202
3204
|
const lower = chainKey.toLowerCase();
|
|
3203
|
-
return CHAINS[lower] ?? Object.values(CHAINS).find((c3) => c3.id === lower);
|
|
3205
|
+
return CHAINS[lower] ?? TESTNET_CHAINS[lower] ?? Object.values(CHAINS).find((c3) => c3.id === lower) ?? Object.values(TESTNET_CHAINS).find((c3) => c3.id === lower);
|
|
3204
3206
|
}
|
|
3205
3207
|
function getChainByCoinId(coinId) {
|
|
3206
3208
|
return Object.values(CHAINS).find((chain2) => chain2.coinId === coinId);
|
|
3207
3209
|
}
|
|
3208
3210
|
function getChainByEvmId(evmChainId) {
|
|
3209
|
-
return Object.values(CHAINS).find((chain2) => chain2.chainId === evmChainId);
|
|
3211
|
+
return Object.values(CHAINS).find((chain2) => chain2.chainId === evmChainId) ?? Object.values(TESTNET_CHAINS).find((chain2) => chain2.chainId === evmChainId);
|
|
3212
|
+
}
|
|
3213
|
+
function isTestnetChain(chainKey) {
|
|
3214
|
+
if (!chainKey) return false;
|
|
3215
|
+
return Object.hasOwn(TESTNET_CHAINS, chainKey.toLowerCase());
|
|
3210
3216
|
}
|
|
3211
3217
|
function getSupportedChains() {
|
|
3212
3218
|
return Object.values(CHAINS);
|
|
@@ -3231,10 +3237,10 @@ function getChainDomainId(chainKey) {
|
|
|
3231
3237
|
if (!entry) throw new Error(`Unsupported chain: ${chainKey}`);
|
|
3232
3238
|
return entry[1].id;
|
|
3233
3239
|
}
|
|
3234
|
-
function getExplorerTxUrl(chainKey,
|
|
3240
|
+
function getExplorerTxUrl(chainKey, hash) {
|
|
3235
3241
|
const chain2 = getChainById(chainKey);
|
|
3236
3242
|
if (!chain2) return "";
|
|
3237
|
-
return `${chain2.explorerUrl}/tx/${
|
|
3243
|
+
return `${chain2.explorerUrl}/tx/${hash}`;
|
|
3238
3244
|
}
|
|
3239
3245
|
function getSampleAccount(chainKey) {
|
|
3240
3246
|
return getChainById(chainKey)?.sampleAccount || "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045";
|
|
@@ -3338,6 +3344,9 @@ function classifyApiError(err) {
|
|
|
3338
3344
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3339
3345
|
}
|
|
3340
3346
|
if (err instanceof TwakNetworkError) {
|
|
3347
|
+
if (EXECUTION_REVERTED_RE.test(err.message)) {
|
|
3348
|
+
return { code: "TX_FAILED", message: err.message };
|
|
3349
|
+
}
|
|
3341
3350
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3342
3351
|
}
|
|
3343
3352
|
if (err instanceof TwakValidationError) {
|
|
@@ -3349,6 +3358,9 @@ function classifyApiError(err) {
|
|
|
3349
3358
|
}
|
|
3350
3359
|
return { code: "NETWORK_ERROR", message: err.message };
|
|
3351
3360
|
}
|
|
3361
|
+
if (err instanceof Error && EXECUTION_REVERTED_RE.test(err.message)) {
|
|
3362
|
+
return { code: "TX_FAILED", message: err.message };
|
|
3363
|
+
}
|
|
3352
3364
|
return null;
|
|
3353
3365
|
}
|
|
3354
3366
|
function classifyStorageError(err) {
|
|
@@ -3431,7 +3443,7 @@ function resolveChain(input2) {
|
|
|
3431
3443
|
if (colonIdx > 0 && colonIdx < lower.length - 1) {
|
|
3432
3444
|
const namespace = lower.slice(0, colonIdx);
|
|
3433
3445
|
const reference = lower.slice(colonIdx + 1);
|
|
3434
|
-
for (const [key, chain2] of Object.entries(
|
|
3446
|
+
for (const [key, chain2] of Object.entries(RESOLVABLE_CHAINS)) {
|
|
3435
3447
|
if (chain2.namespace === namespace && chain2.chainId.toLowerCase() === reference) {
|
|
3436
3448
|
return key;
|
|
3437
3449
|
}
|
|
@@ -3448,10 +3460,10 @@ function resolveChain(input2) {
|
|
|
3448
3460
|
throw chainUnsupported(input2);
|
|
3449
3461
|
}
|
|
3450
3462
|
}
|
|
3451
|
-
if (
|
|
3463
|
+
if (RESOLVABLE_CHAINS[lower]) return lower;
|
|
3452
3464
|
const aliased = ALIASES[lower];
|
|
3453
3465
|
if (aliased) return aliased;
|
|
3454
|
-
for (const [key, chain2] of Object.entries(
|
|
3466
|
+
for (const [key, chain2] of Object.entries(RESOLVABLE_CHAINS)) {
|
|
3455
3467
|
if (chain2.id === lower) return key;
|
|
3456
3468
|
}
|
|
3457
3469
|
if (/^0x[0-9a-f]+$/.test(lower)) {
|
|
@@ -3464,14 +3476,14 @@ function resolveChain(input2) {
|
|
|
3464
3476
|
throw chainUnsupported(input2);
|
|
3465
3477
|
}
|
|
3466
3478
|
function lookupEvm(chainId) {
|
|
3467
|
-
for (const [key, chain2] of Object.entries(
|
|
3479
|
+
for (const [key, chain2] of Object.entries(RESOLVABLE_CHAINS)) {
|
|
3468
3480
|
if (chain2.namespace === "eip155" && chain2.chainId === chainId) return key;
|
|
3469
3481
|
}
|
|
3470
3482
|
return void 0;
|
|
3471
3483
|
}
|
|
3472
3484
|
function resolveAsset(chain2, tokenAddress) {
|
|
3473
3485
|
const chainKey = resolveChain(chain2);
|
|
3474
|
-
const coinId =
|
|
3486
|
+
const coinId = RESOLVABLE_CHAINS[chainKey].coinId;
|
|
3475
3487
|
return { chainKey, coinId, assetId: formatTokenId(coinId, tokenAddress) };
|
|
3476
3488
|
}
|
|
3477
3489
|
function chainUnsupported(input2) {
|
|
@@ -3723,7 +3735,7 @@ async function fetchBalance(httpClient, assetId, address, currency = "USD") {
|
|
|
3723
3735
|
throw new BalanceError("NETWORK_ERROR", "Could not fetch balance. Please try again later.");
|
|
3724
3736
|
}
|
|
3725
3737
|
}
|
|
3726
|
-
var import_crypto, NATIVE_TOKEN_ADDRESS, SOLANA_NATIVE_ADDRESS, 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, 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;
|
|
3727
3739
|
var init_dist = __esm({
|
|
3728
3740
|
"../core/dist/index.mjs"() {
|
|
3729
3741
|
"use strict";
|
|
@@ -4064,6 +4076,21 @@ var init_dist = __esm({
|
|
|
4064
4076
|
sampleAccount: "0x8d1f3c7b5e9a2047c6b3d80f1e4a9258c7d6b3e5f8a0c2d4e6f8a0b2c4d6e8f"
|
|
4065
4077
|
}
|
|
4066
4078
|
};
|
|
4079
|
+
TESTNET_CHAINS = {
|
|
4080
|
+
bsctestnet: {
|
|
4081
|
+
id: "smartchain-testnet",
|
|
4082
|
+
name: "BNB Smart Chain Testnet",
|
|
4083
|
+
coinId: 20000714,
|
|
4084
|
+
namespace: "eip155",
|
|
4085
|
+
chainId: "97",
|
|
4086
|
+
symbol: "tBNB",
|
|
4087
|
+
decimals: 18,
|
|
4088
|
+
explorerUrl: "https://testnet.bscscan.com",
|
|
4089
|
+
rpcUrl: "https://bsc-testnet.twnodes.com",
|
|
4090
|
+
isEVM: true,
|
|
4091
|
+
sampleAccount: "0x8894E0a0c962CB723c1976a4421c95949bE2D4E3"
|
|
4092
|
+
}
|
|
4093
|
+
};
|
|
4067
4094
|
COMMON_TOKENS = {
|
|
4068
4095
|
ethereum: {
|
|
4069
4096
|
USDT: { address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6 },
|
|
@@ -4209,6 +4236,7 @@ var init_dist = __esm({
|
|
|
4209
4236
|
WALLET_AUTH_FAILED: "WALLET_AUTH_FAILED",
|
|
4210
4237
|
STORAGE_ERROR: "STORAGE_ERROR"
|
|
4211
4238
|
};
|
|
4239
|
+
EXECUTION_REVERTED_RE = /\bexecution reverted\b/i;
|
|
4212
4240
|
FS_ERRNO_CODES = /* @__PURE__ */ new Set([
|
|
4213
4241
|
"EACCES",
|
|
4214
4242
|
"EEXIST",
|
|
@@ -4347,6 +4375,7 @@ var init_dist = __esm({
|
|
|
4347
4375
|
this.name = "X402Error";
|
|
4348
4376
|
}
|
|
4349
4377
|
};
|
|
4378
|
+
RESOLVABLE_CHAINS = { ...CHAINS, ...TESTNET_CHAINS };
|
|
4350
4379
|
ALIASES = {
|
|
4351
4380
|
"binance-smart-chain": "bsc",
|
|
4352
4381
|
matic: "polygon",
|
|
@@ -6750,13 +6779,47 @@ function patchNodeStubs() {
|
|
|
6750
6779
|
if (resolvedUrl.includes("gateway.us.trustwallet.com")) {
|
|
6751
6780
|
resolvedUrl = resolvedUrl.replace("gateway.us.trustwallet.com", "tws.trustwallet.com");
|
|
6752
6781
|
}
|
|
6782
|
+
let finalInput = input2;
|
|
6753
6783
|
if (resolvedUrl !== url) {
|
|
6754
|
-
|
|
6755
|
-
|
|
6784
|
+
finalInput = typeof input2 === "string" ? resolvedUrl : input2 instanceof URL ? new URL(resolvedUrl) : new Request(resolvedUrl, input2);
|
|
6785
|
+
}
|
|
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);
|
|
6756
6789
|
}
|
|
6757
|
-
return originalFetch(
|
|
6790
|
+
return originalFetch(finalInput, init3);
|
|
6758
6791
|
};
|
|
6759
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
|
+
}
|
|
6760
6823
|
function patchNaasSession(sessionId) {
|
|
6761
6824
|
if (naasSessionPatched) return;
|
|
6762
6825
|
naasSessionPatched = true;
|
|
@@ -6810,19 +6873,40 @@ async function initTrustSDK(config) {
|
|
|
6810
6873
|
"com.trustwallet.agent",
|
|
6811
6874
|
""
|
|
6812
6875
|
);
|
|
6813
|
-
new import_trust_sdk.TrustSDKConfig.Builder().setContext(
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6876
|
+
new import_trust_sdk.TrustSDKConfig.Builder().setContext(
|
|
6877
|
+
new import_trust_sdk.TrustSDKContext(
|
|
6878
|
+
clientPlatform,
|
|
6879
|
+
authCredentials,
|
|
6880
|
+
config.logEnabled ? import_trust_sdk.LogMode.Debug : import_trust_sdk.LogMode.None,
|
|
6881
|
+
config.logEnabled ? import_trust_sdk.LogSeverity.Debug : import_trust_sdk.LogSeverity.Error
|
|
6882
|
+
)
|
|
6883
|
+
).addFeatureModule().addTrustSDKModule().init();
|
|
6819
6884
|
const nodeSyncMode = naasSessionId ? new import_trust_sdk.NodeSyncMode(import_trust_sdk.NodeSyncMode.NodeSyncModeType.NaaS) : new import_trust_sdk.NodeSyncMode(import_trust_sdk.NodeSyncMode.NodeSyncModeType.Default);
|
|
6820
|
-
new import_trust_sdk.WalletKitConfig.Builder().setContext(
|
|
6885
|
+
new import_trust_sdk.WalletKitConfig.Builder().setContext(
|
|
6886
|
+
new import_trust_sdk.WalletKitContext(
|
|
6887
|
+
clientPlatform,
|
|
6888
|
+
nodeSyncMode,
|
|
6889
|
+
void 0,
|
|
6890
|
+
authCredentials,
|
|
6891
|
+
config.logEnabled ? import_trust_sdk.LoggerMode.Debug : import_trust_sdk.LoggerMode.None
|
|
6892
|
+
)
|
|
6893
|
+
).addWalletKitModule().addSwapModule().init();
|
|
6821
6894
|
walletCore = await import_trust_sdk.WalletCoreKotlin.init();
|
|
6822
6895
|
import_trust_sdk.FeatureModule.setEnvironment(import_trust_sdk.TwEnvironmentProduction);
|
|
6823
6896
|
await import_trust_sdk.AmberService.setEnvironment(import_trust_sdk.TwEnvironmentProduction);
|
|
6824
6897
|
await import_trust_sdk.BlockchainService.useBitcoinV2();
|
|
6825
6898
|
buildCoinTypeMap();
|
|
6899
|
+
for (const cfg of Object.values(TESTNET_CHAINS)) {
|
|
6900
|
+
try {
|
|
6901
|
+
await import_trust_sdk.BlockchainService.setNode(
|
|
6902
|
+
new import_trust_sdk.CustomChain(getCoinType(cfg.coinId), cfg.chainId),
|
|
6903
|
+
new import_trust_sdk.Node(cfg.rpcUrl)
|
|
6904
|
+
);
|
|
6905
|
+
} catch (err) {
|
|
6906
|
+
process.stderr.write(`twak: could not register testnet node for ${cfg.id}: ${String(err)}
|
|
6907
|
+
`);
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6826
6910
|
initialized = true;
|
|
6827
6911
|
}
|
|
6828
6912
|
function getWalletCore() {
|
|
@@ -6951,7 +7035,12 @@ function chainKeyToDefinedChain(chainKey) {
|
|
|
6951
7035
|
if (!ct5) {
|
|
6952
7036
|
throw new TwakValidationError(`No CoinType mapping for coinId ${coinId}`, { chainKey, coinId });
|
|
6953
7037
|
}
|
|
6954
|
-
|
|
7038
|
+
const chainConfig = getChainById(canonicalKey);
|
|
7039
|
+
if (!chainConfig) {
|
|
7040
|
+
throw new TwakValidationError(`No chain config for ${canonicalKey}`, { chainKey });
|
|
7041
|
+
}
|
|
7042
|
+
const chain2 = isTestnetChain(canonicalKey) ? new import_trust_sdk3.CustomChain(ct5, chainConfig.chainId) : new import_trust_sdk3.DefinedChain(ct5);
|
|
7043
|
+
return { chain: chain2, chainConfig };
|
|
6955
7044
|
}
|
|
6956
7045
|
function humanAmountToWei(amount, decimals = 18) {
|
|
6957
7046
|
const parts = amount.split(".");
|
|
@@ -6960,11 +7049,11 @@ function humanAmountToWei(amount, decimals = 18) {
|
|
|
6960
7049
|
const frac = parts[1].padEnd(decimals, "0").slice(0, decimals);
|
|
6961
7050
|
return whole * 10n ** BigInt(decimals) + BigInt(frac);
|
|
6962
7051
|
}
|
|
6963
|
-
function createPendingTransaction(client, chainKey,
|
|
7052
|
+
function createPendingTransaction(client, chainKey, hash) {
|
|
6964
7053
|
return {
|
|
6965
|
-
|
|
7054
|
+
hash,
|
|
6966
7055
|
chainKey,
|
|
6967
|
-
wait: (opts) => client.waitForReceipt(chainKey,
|
|
7056
|
+
wait: (opts) => client.waitForReceipt(chainKey, hash, opts)
|
|
6968
7057
|
};
|
|
6969
7058
|
}
|
|
6970
7059
|
function bscSponsoredBaseUrl() {
|
|
@@ -7188,6 +7277,7 @@ var init_dist3 = __esm({
|
|
|
7188
7277
|
fs2 = __toESM(require("fs"), 1);
|
|
7189
7278
|
path2 = __toESM(require("path"), 1);
|
|
7190
7279
|
import_trust_sdk = require("@trustwallet-trust-sdk/trust-sdk");
|
|
7280
|
+
init_dist();
|
|
7191
7281
|
import_trust_sdk2 = require("@trustwallet-trust-sdk/trust-sdk");
|
|
7192
7282
|
init_dist();
|
|
7193
7283
|
import_trust_sdk3 = require("@trustwallet-trust-sdk/trust-sdk");
|
|
@@ -7230,10 +7320,10 @@ var init_dist3 = __esm({
|
|
|
7230
7320
|
setSigner(signer) {
|
|
7231
7321
|
this.signer = signer;
|
|
7232
7322
|
}
|
|
7233
|
-
async getBalance(assetId, address) {
|
|
7323
|
+
async getBalance(assetId, address, chainKey) {
|
|
7234
7324
|
const { coinId, contractAddress } = parseTokenId(assetId);
|
|
7235
7325
|
const ct5 = requireCoinType(coinId);
|
|
7236
|
-
const account = this.createAccountForAddress(coinId, address);
|
|
7326
|
+
const account = this.createAccountForAddress(coinId, address, chainKey);
|
|
7237
7327
|
const asset = contractAddress ? new import_trust_sdk2.Asset.Token(account, contractAddress, tokenTypeForCoinId(coinId)) : new import_trust_sdk2.Asset.Coin(account);
|
|
7238
7328
|
let results;
|
|
7239
7329
|
try {
|
|
@@ -7268,8 +7358,8 @@ var init_dist3 = __esm({
|
|
|
7268
7358
|
total: total.toString()
|
|
7269
7359
|
};
|
|
7270
7360
|
}
|
|
7271
|
-
async getTokenBalance(assetId, ownerAddress) {
|
|
7272
|
-
return this.getBalance(assetId, ownerAddress);
|
|
7361
|
+
async getTokenBalance(assetId, ownerAddress, chainKey) {
|
|
7362
|
+
return this.getBalance(assetId, ownerAddress, chainKey);
|
|
7273
7363
|
}
|
|
7274
7364
|
async getBalancesBatch(assetIds, address) {
|
|
7275
7365
|
if (assetIds.length === 0) return /* @__PURE__ */ new Map();
|
|
@@ -7329,10 +7419,7 @@ var init_dist3 = __esm({
|
|
|
7329
7419
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7330
7420
|
async transfer(params) {
|
|
7331
7421
|
const { coinId, contractAddress } = parseTokenId(params.assetId);
|
|
7332
|
-
const chainKey =
|
|
7333
|
-
if (!chainKey) {
|
|
7334
|
-
throw new Error(`Unsupported coin type: ${coinId}`);
|
|
7335
|
-
}
|
|
7422
|
+
const chainKey = params.chainKey;
|
|
7336
7423
|
const ct5 = requireCoinType(coinId);
|
|
7337
7424
|
const account = this.getAccountFromSigner(chainKey);
|
|
7338
7425
|
const asset = contractAddress ? new import_trust_sdk2.Asset.Token(account, contractAddress, tokenTypeForCoinId(coinId)) : new import_trust_sdk2.Asset.Coin(account);
|
|
@@ -7362,10 +7449,7 @@ var init_dist3 = __esm({
|
|
|
7362
7449
|
}
|
|
7363
7450
|
async executeContract(params) {
|
|
7364
7451
|
const { coinId } = parseTokenId(params.assetId);
|
|
7365
|
-
const chainKey =
|
|
7366
|
-
if (!chainKey) {
|
|
7367
|
-
throw new Error(`Unsupported coin type: ${coinId}`);
|
|
7368
|
-
}
|
|
7452
|
+
const chainKey = params.chainKey;
|
|
7369
7453
|
const ct5 = requireCoinType(coinId);
|
|
7370
7454
|
const account = this.getAccountFromSigner(chainKey);
|
|
7371
7455
|
const asset = new import_trust_sdk2.Asset.Coin(account);
|
|
@@ -7390,7 +7474,7 @@ var init_dist3 = __esm({
|
|
|
7390
7474
|
* `receiptTimeoutMs` config when set, otherwise the global constants
|
|
7391
7475
|
* (1.5s poll, 60s timeout). Caller-supplied opts override both.
|
|
7392
7476
|
*/
|
|
7393
|
-
async waitForReceipt(chainKey,
|
|
7477
|
+
async waitForReceipt(chainKey, hash, opts) {
|
|
7394
7478
|
const { chain: chain2, chainConfig } = chainKeyToDefinedChain(chainKey);
|
|
7395
7479
|
if (chainConfig?.namespace && chainConfig.namespace !== "eip155") {
|
|
7396
7480
|
throw new TwakValidationError(
|
|
@@ -7416,15 +7500,15 @@ var init_dist3 = __esm({
|
|
|
7416
7500
|
const deadline = Date.now() + timeoutMs;
|
|
7417
7501
|
while (Date.now() < deadline) {
|
|
7418
7502
|
const remainingMs = Math.max(1, deadline - Date.now());
|
|
7419
|
-
const result = await this.postJsonRpc(rpcUrl, "eth_getTransactionReceipt", [
|
|
7503
|
+
const result = await this.postJsonRpc(rpcUrl, "eth_getTransactionReceipt", [hash], {
|
|
7420
7504
|
timeoutMs: Math.min(RPC_TIMEOUT_MS, remainingMs)
|
|
7421
7505
|
});
|
|
7422
7506
|
const receipt = result ?? null;
|
|
7423
7507
|
if (receipt) return receipt;
|
|
7424
7508
|
await new Promise((resolve2) => setTimeout(resolve2, pollMs));
|
|
7425
7509
|
}
|
|
7426
|
-
throw new TwakNetworkError(`Timed out waiting for receipt ${
|
|
7427
|
-
|
|
7510
|
+
throw new TwakNetworkError(`Timed out waiting for receipt ${hash} on ${chainKey}`, {
|
|
7511
|
+
hash,
|
|
7428
7512
|
chainKey
|
|
7429
7513
|
});
|
|
7430
7514
|
}
|
|
@@ -7515,13 +7599,13 @@ var init_dist3 = __esm({
|
|
|
7515
7599
|
currency: chainKey
|
|
7516
7600
|
};
|
|
7517
7601
|
}
|
|
7518
|
-
async findTransactionStatus(chainKey, address,
|
|
7602
|
+
async findTransactionStatus(chainKey, address, hash) {
|
|
7519
7603
|
const coinId = chainKeyToCoinType(chainKey);
|
|
7520
7604
|
if (coinId === void 0) throw new Error(`Unsupported chain: ${chainKey}`);
|
|
7521
7605
|
const account = this.createAccountForAddress(coinId, address);
|
|
7522
7606
|
let result;
|
|
7523
7607
|
try {
|
|
7524
|
-
result = await import_trust_sdk2.BlockchainService.findTransaction(account,
|
|
7608
|
+
result = await import_trust_sdk2.BlockchainService.findTransaction(account, hash);
|
|
7525
7609
|
} catch {
|
|
7526
7610
|
return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
|
|
7527
7611
|
}
|
|
@@ -7629,8 +7713,9 @@ var init_dist3 = __esm({
|
|
|
7629
7713
|
* EIP-7702 token-as-gas sponsorship.
|
|
7630
7714
|
*/
|
|
7631
7715
|
async signAndBroadcast(transaction, account, coinId, chainKey, ct5, hdWallet) {
|
|
7632
|
-
const
|
|
7633
|
-
const
|
|
7716
|
+
const testnet = isTestnetChain(chainKey);
|
|
7717
|
+
const chain2 = testnet ? chainKeyToDefinedChain(chainKey).chain : new import_trust_sdk2.DefinedChain(ct5);
|
|
7718
|
+
const sponsoredUrl = testnet ? void 0 : this.getSponsoredRpcUrl(coinId);
|
|
7634
7719
|
if (sponsoredUrl) {
|
|
7635
7720
|
try {
|
|
7636
7721
|
const zeroFee = zeroGasFee(await import_trust_sdk2.BlockchainService.calculateFee(transaction));
|
|
@@ -7659,7 +7744,8 @@ var init_dist3 = __esm({
|
|
|
7659
7744
|
const { fee, transaction7702 } = await this.calculateFeeWithSponsorship(
|
|
7660
7745
|
transaction,
|
|
7661
7746
|
account,
|
|
7662
|
-
coinId
|
|
7747
|
+
coinId,
|
|
7748
|
+
chainKey
|
|
7663
7749
|
);
|
|
7664
7750
|
const tx = transaction7702 ?? transaction;
|
|
7665
7751
|
const nonce = await import_trust_sdk2.BlockchainService.fetchNonce(account);
|
|
@@ -7729,8 +7815,8 @@ var init_dist3 = __esm({
|
|
|
7729
7815
|
* Sets is7702=true and energy=tokenAsset on the transaction so the
|
|
7730
7816
|
* Trust SDK routes through the Smart Wallet fee service internally.
|
|
7731
7817
|
*/
|
|
7732
|
-
async calculateFeeWithSponsorship(transaction, account, coinId) {
|
|
7733
|
-
if (!_BlockchainClient.SPONSORABLE_COINS.includes(coinId)) {
|
|
7818
|
+
async calculateFeeWithSponsorship(transaction, account, coinId, chainKey) {
|
|
7819
|
+
if (!_BlockchainClient.SPONSORABLE_COINS.includes(coinId) || chainKey !== void 0 && isTestnetChain(chainKey)) {
|
|
7734
7820
|
return { fee: await import_trust_sdk2.BlockchainService.calculateFee(transaction) };
|
|
7735
7821
|
}
|
|
7736
7822
|
let supports7702 = false;
|
|
@@ -7866,18 +7952,18 @@ var init_dist3 = __esm({
|
|
|
7866
7952
|
}
|
|
7867
7953
|
return this.signer.getAccount(chainKey);
|
|
7868
7954
|
}
|
|
7869
|
-
createAccountForAddress(coinId, address) {
|
|
7955
|
+
createAccountForAddress(coinId, address, chainKey) {
|
|
7870
7956
|
if (this.signer) {
|
|
7871
|
-
const
|
|
7872
|
-
if (
|
|
7957
|
+
const key = chainKey ?? coinTypeToChainKey(coinId);
|
|
7958
|
+
if (key) {
|
|
7873
7959
|
try {
|
|
7874
|
-
return this.signer.getAccount(
|
|
7960
|
+
return this.signer.getAccount(key);
|
|
7875
7961
|
} catch {
|
|
7876
7962
|
}
|
|
7877
7963
|
}
|
|
7878
7964
|
}
|
|
7879
7965
|
const ct5 = requireCoinType(coinId);
|
|
7880
|
-
const chain2 = new import_trust_sdk2.DefinedChain(ct5);
|
|
7966
|
+
const chain2 = chainKey !== void 0 && isTestnetChain(chainKey) ? chainKeyToDefinedChain(chainKey).chain : new import_trust_sdk2.DefinedChain(ct5);
|
|
7881
7967
|
const wc3 = getWalletCore();
|
|
7882
7968
|
const derivation = coinId === 0 && address.startsWith("bc1p") ? wc3.Derivation.bitcoinTaproot : coinId === 0 && address.startsWith("bc1") ? wc3.Derivation.bitcoinSegwit : wc3.Derivation.default;
|
|
7883
7969
|
return new import_trust_sdk2.Account(address, derivation, "", "", "", chain2);
|
|
@@ -7941,7 +8027,9 @@ var init_dist3 = __esm({
|
|
|
7941
8027
|
);
|
|
7942
8028
|
}
|
|
7943
8029
|
if (json.error) {
|
|
7944
|
-
|
|
8030
|
+
const { message, data } = json.error;
|
|
8031
|
+
const suffix = revertDataSuffix(message, data);
|
|
8032
|
+
throw new TwakNetworkError(`RPC error on ${method}: ${message}${suffix}`, {
|
|
7945
8033
|
method,
|
|
7946
8034
|
rpcUrl,
|
|
7947
8035
|
rpcError: json.error
|
|
@@ -7974,7 +8062,7 @@ var init_dist3 = __esm({
|
|
|
7974
8062
|
getAddress(chainKey) {
|
|
7975
8063
|
const cached = this.addressCache.get(chainKey);
|
|
7976
8064
|
if (cached) return cached;
|
|
7977
|
-
const coinId = chainKeyToCoinType(chainKey);
|
|
8065
|
+
const coinId = chainKeyToCoinType(chainKey) ?? getChainById(chainKey)?.coinId;
|
|
7978
8066
|
if (coinId === void 0) {
|
|
7979
8067
|
throw new Error(`Unsupported chain: ${chainKey}`);
|
|
7980
8068
|
}
|
|
@@ -7994,7 +8082,8 @@ var init_dist3 = __esm({
|
|
|
7994
8082
|
}
|
|
7995
8083
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7996
8084
|
getAccount(chainKey) {
|
|
7997
|
-
const
|
|
8085
|
+
const testnet = isTestnetChain(chainKey);
|
|
8086
|
+
const coinId = chainKeyToCoinType(chainKey) ?? getChainById(chainKey)?.coinId;
|
|
7998
8087
|
if (coinId === void 0) {
|
|
7999
8088
|
throw new Error(`Unsupported chain: ${chainKey}`);
|
|
8000
8089
|
}
|
|
@@ -8002,12 +8091,21 @@ var init_dist3 = __esm({
|
|
|
8002
8091
|
if (!ct5) {
|
|
8003
8092
|
throw new Error(`No CoinType mapping for chain: ${chainKey} (coinId: ${coinId})`);
|
|
8004
8093
|
}
|
|
8005
|
-
const chain2 = new import_trust_sdk4.DefinedChain(ct5);
|
|
8094
|
+
const chain2 = testnet ? new import_trust_sdk4.CustomChain(ct5, getChainById(chainKey).chainId) : new import_trust_sdk4.DefinedChain(ct5);
|
|
8006
8095
|
const accounts = import_trust_sdk4.AccountManagementService.createDefaultAccountsHdWallet(chain2, this.hdWallet);
|
|
8007
8096
|
if (accounts.length === 0) {
|
|
8008
8097
|
throw new Error(`No accounts for chain: ${chainKey}`);
|
|
8009
8098
|
}
|
|
8010
|
-
|
|
8099
|
+
const account = coinId === 0 && accounts.length > 1 ? accounts[1] : accounts[0];
|
|
8100
|
+
if (!testnet) return account;
|
|
8101
|
+
return new import_trust_sdk4.Account(
|
|
8102
|
+
account.address,
|
|
8103
|
+
account.derivation,
|
|
8104
|
+
account.publicKey,
|
|
8105
|
+
account.extendedPublicKey,
|
|
8106
|
+
account.derivationPath,
|
|
8107
|
+
chain2
|
|
8108
|
+
);
|
|
8011
8109
|
}
|
|
8012
8110
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8013
8111
|
getPrivateKey(chainKey) {
|
|
@@ -8217,7 +8315,7 @@ var init_dist3 = __esm({
|
|
|
8217
8315
|
async sendTransaction(params) {
|
|
8218
8316
|
await this.ensureConnected();
|
|
8219
8317
|
this.resetAutoLockTimer();
|
|
8220
|
-
const { getChainByEvmId: getChainByEvmId2, chainKeyToCoinType: chainKeyToCoinType3 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
8318
|
+
const { getChainByEvmId: getChainByEvmId2, chainKeyToCoinType: chainKeyToCoinType3, resolveChain: resolveChain2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
8221
8319
|
let assetId;
|
|
8222
8320
|
if (params.chainId.startsWith("eip155:")) {
|
|
8223
8321
|
const chain2 = getChainByEvmId2(params.chainId.replace("eip155:", ""));
|
|
@@ -8230,6 +8328,7 @@ var init_dist3 = __esm({
|
|
|
8230
8328
|
if (coinId === void 0) throw new Error(`Unsupported chain: ${params.chainId}`);
|
|
8231
8329
|
assetId = `c${coinId}`;
|
|
8232
8330
|
}
|
|
8331
|
+
const chainKey = resolveChain2(params.chainId);
|
|
8233
8332
|
const hdWallet = this.signer.getHDWallet();
|
|
8234
8333
|
const hasCalldata = params.data && params.data !== "0x" && params.data !== "0x0";
|
|
8235
8334
|
const hasValue = params.value && params.value !== "0x0" && params.value !== "0x" && params.value !== "0";
|
|
@@ -8238,7 +8337,7 @@ var init_dist3 = __esm({
|
|
|
8238
8337
|
serializedMessage: params.data,
|
|
8239
8338
|
hdWallet
|
|
8240
8339
|
});
|
|
8241
|
-
return result2.
|
|
8340
|
+
return result2.hash;
|
|
8242
8341
|
}
|
|
8243
8342
|
if (hasCalldata || hasValue) {
|
|
8244
8343
|
const result2 = await this.blockchainClient.executeContract({
|
|
@@ -8246,17 +8345,19 @@ var init_dist3 = __esm({
|
|
|
8246
8345
|
to: params.to,
|
|
8247
8346
|
value: params.value || "0x0",
|
|
8248
8347
|
data: params.data || "0x",
|
|
8249
|
-
hdWallet
|
|
8348
|
+
hdWallet,
|
|
8349
|
+
chainKey
|
|
8250
8350
|
});
|
|
8251
|
-
return result2.
|
|
8351
|
+
return result2.hash;
|
|
8252
8352
|
}
|
|
8253
8353
|
const result = await this.blockchainClient.transfer({
|
|
8254
8354
|
assetId,
|
|
8255
8355
|
to: params.to,
|
|
8256
8356
|
amount: params.value || "0",
|
|
8257
|
-
hdWallet
|
|
8357
|
+
hdWallet,
|
|
8358
|
+
chainKey
|
|
8258
8359
|
});
|
|
8259
|
-
return result.
|
|
8360
|
+
return result.hash;
|
|
8260
8361
|
}
|
|
8261
8362
|
supportsChain(chainId) {
|
|
8262
8363
|
return isChainSupported(chainId);
|
|
@@ -14355,7 +14456,7 @@ var require_codegen = __commonJS({
|
|
|
14355
14456
|
AND: new code_1._Code("&&"),
|
|
14356
14457
|
ADD: new code_1._Code("+")
|
|
14357
14458
|
};
|
|
14358
|
-
var
|
|
14459
|
+
var Node2 = class {
|
|
14359
14460
|
optimizeNodes() {
|
|
14360
14461
|
return this;
|
|
14361
14462
|
}
|
|
@@ -14363,7 +14464,7 @@ var require_codegen = __commonJS({
|
|
|
14363
14464
|
return this;
|
|
14364
14465
|
}
|
|
14365
14466
|
};
|
|
14366
|
-
var Def = class extends
|
|
14467
|
+
var Def = class extends Node2 {
|
|
14367
14468
|
constructor(varKind, name2, rhs) {
|
|
14368
14469
|
super();
|
|
14369
14470
|
this.varKind = varKind;
|
|
@@ -14386,7 +14487,7 @@ var require_codegen = __commonJS({
|
|
|
14386
14487
|
return this.rhs instanceof code_1._CodeOrName ? this.rhs.names : {};
|
|
14387
14488
|
}
|
|
14388
14489
|
};
|
|
14389
|
-
var Assign = class extends
|
|
14490
|
+
var Assign = class extends Node2 {
|
|
14390
14491
|
constructor(lhs, rhs, sideEffects) {
|
|
14391
14492
|
super();
|
|
14392
14493
|
this.lhs = lhs;
|
|
@@ -14416,7 +14517,7 @@ var require_codegen = __commonJS({
|
|
|
14416
14517
|
return `${this.lhs} ${this.op}= ${this.rhs};` + _n3;
|
|
14417
14518
|
}
|
|
14418
14519
|
};
|
|
14419
|
-
var Label = class extends
|
|
14520
|
+
var Label = class extends Node2 {
|
|
14420
14521
|
constructor(label) {
|
|
14421
14522
|
super();
|
|
14422
14523
|
this.label = label;
|
|
@@ -14426,7 +14527,7 @@ var require_codegen = __commonJS({
|
|
|
14426
14527
|
return `${this.label}:` + _n3;
|
|
14427
14528
|
}
|
|
14428
14529
|
};
|
|
14429
|
-
var Break = class extends
|
|
14530
|
+
var Break = class extends Node2 {
|
|
14430
14531
|
constructor(label) {
|
|
14431
14532
|
super();
|
|
14432
14533
|
this.label = label;
|
|
@@ -14437,7 +14538,7 @@ var require_codegen = __commonJS({
|
|
|
14437
14538
|
return `break${label};` + _n3;
|
|
14438
14539
|
}
|
|
14439
14540
|
};
|
|
14440
|
-
var Throw = class extends
|
|
14541
|
+
var Throw = class extends Node2 {
|
|
14441
14542
|
constructor(error2) {
|
|
14442
14543
|
super();
|
|
14443
14544
|
this.error = error2;
|
|
@@ -14449,7 +14550,7 @@ var require_codegen = __commonJS({
|
|
|
14449
14550
|
return this.error.names;
|
|
14450
14551
|
}
|
|
14451
14552
|
};
|
|
14452
|
-
var AnyCode = class extends
|
|
14553
|
+
var AnyCode = class extends Node2 {
|
|
14453
14554
|
constructor(code2) {
|
|
14454
14555
|
super();
|
|
14455
14556
|
this.code = code2;
|
|
@@ -14468,7 +14569,7 @@ var require_codegen = __commonJS({
|
|
|
14468
14569
|
return this.code instanceof code_1._CodeOrName ? this.code.names : {};
|
|
14469
14570
|
}
|
|
14470
14571
|
};
|
|
14471
|
-
var ParentNode = class extends
|
|
14572
|
+
var ParentNode = class extends Node2 {
|
|
14472
14573
|
constructor(nodes = []) {
|
|
14473
14574
|
super();
|
|
14474
14575
|
this.nodes = nodes;
|
|
@@ -40545,756 +40646,146 @@ init_dist2();
|
|
|
40545
40646
|
var import_chalk6 = __toESM(require_source());
|
|
40546
40647
|
init_dist();
|
|
40547
40648
|
|
|
40548
|
-
//
|
|
40549
|
-
|
|
40550
|
-
|
|
40551
|
-
|
|
40552
|
-
|
|
40553
|
-
|
|
40554
|
-
|
|
40555
|
-
|
|
40556
|
-
|
|
40557
|
-
|
|
40558
|
-
|
|
40559
|
-
|
|
40560
|
-
" @@@@@@@@@@@@@@@@********++++++++ ",
|
|
40561
|
-
" @@@@@@@@@@@@@@@@**************++ ",
|
|
40562
|
-
" @@@@@@@@@@@@@@@@#####*********** ",
|
|
40563
|
-
" @@@@@@@@@@@@@@@###########**** ",
|
|
40564
|
-
" @@@@@@@@@@@@@@%############## ",
|
|
40565
|
-
" @@@@@@@@@@@@@@%%%%%%%####### ",
|
|
40566
|
-
" @@@@@@@@@@@@@%%%%%%%%%%%%% ",
|
|
40567
|
-
" @@@@@@@@@@@%%%%%%%%%%% ",
|
|
40568
|
-
" @@@@@@@@@@@@@%%%%% ",
|
|
40569
|
-
" @@@@@@@@@@@@@@ ",
|
|
40570
|
-
" @@@@@@@@@@ ",
|
|
40571
|
-
" @@ "
|
|
40572
|
-
];
|
|
40573
|
-
function printBanner(version3) {
|
|
40574
|
-
const logo = SHIELD.map((l4) => import_chalk5.default.green(l4)).join("\n");
|
|
40575
|
-
const title = import_chalk5.default.green.bold(" Trust Wallet Agent Kit");
|
|
40576
|
-
const ver = import_chalk5.default.dim(` v${version3}`);
|
|
40577
|
-
console.log(
|
|
40578
|
-
boxen(`${logo}
|
|
40579
|
-
|
|
40580
|
-
${title}
|
|
40581
|
-
${ver}`, {
|
|
40582
|
-
borderColor: "green",
|
|
40583
|
-
borderStyle: "round",
|
|
40584
|
-
padding: { top: 1, bottom: 1, left: 2, right: 2 }
|
|
40585
|
-
})
|
|
40586
|
-
);
|
|
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);
|
|
40587
40661
|
}
|
|
40588
|
-
function
|
|
40589
|
-
|
|
40590
|
-
|
|
40591
|
-
|
|
40592
|
-
|
|
40593
|
-
|
|
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;
|
|
40594
40675
|
}
|
|
40595
|
-
|
|
40596
|
-
|
|
40597
|
-
|
|
40598
|
-
|
|
40599
|
-
const qrcode = require("qrcode-terminal");
|
|
40600
|
-
let result = "";
|
|
40601
|
-
qrcode.generate(address, { small: true }, (code2) => {
|
|
40602
|
-
result = code2;
|
|
40603
|
-
});
|
|
40604
|
-
return result;
|
|
40605
|
-
} catch {
|
|
40606
|
-
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");
|
|
40607
40680
|
}
|
|
40681
|
+
return out;
|
|
40608
40682
|
}
|
|
40609
|
-
function
|
|
40610
|
-
const
|
|
40611
|
-
|
|
40612
|
-
|
|
40613
|
-
|
|
40614
|
-
|
|
40615
|
-
|
|
40616
|
-
|
|
40617
|
-
|
|
40618
|
-
}
|
|
40619
|
-
await ensureTrustSDK();
|
|
40620
|
-
const store = new WalletConfigStore();
|
|
40621
|
-
if (await store.exists()) {
|
|
40622
|
-
throw new WalletError(
|
|
40623
|
-
"WALLET_EXISTS",
|
|
40624
|
-
"Wallet already exists. Back up ~/.twak/wallet.json, then delete it to create a new one."
|
|
40625
|
-
);
|
|
40626
|
-
}
|
|
40627
|
-
const provider = await AgentWalletProvider.create(opts.password);
|
|
40628
|
-
const addresses = await provider.getAddresses();
|
|
40629
|
-
if (opts.keychain !== false) {
|
|
40630
|
-
const kc2 = new KeychainManager();
|
|
40631
|
-
if (kc2.isAvailable()) {
|
|
40632
|
-
await kc2.saveWalletPassword(opts.password);
|
|
40633
|
-
if (!opts.json) info("Password saved to OS keychain (use --no-keychain to skip)");
|
|
40634
|
-
}
|
|
40635
|
-
}
|
|
40636
|
-
if (!opts.json) success("Agent wallet created successfully");
|
|
40637
|
-
try {
|
|
40638
|
-
const creds = await getCredentials();
|
|
40639
|
-
await registerWalletWithBackend(creds, provider);
|
|
40640
|
-
if (!opts.json) info("Wallet registered with backend");
|
|
40641
|
-
} catch {
|
|
40642
|
-
if (!opts.json) warn("Backend registration failed (holdings may be limited)");
|
|
40643
|
-
}
|
|
40644
|
-
if (opts.json) {
|
|
40645
|
-
output({ addresses }, true);
|
|
40646
|
-
} else {
|
|
40647
|
-
info(`Generated addresses for ${addresses.length} chains`);
|
|
40648
|
-
}
|
|
40649
|
-
} catch (err) {
|
|
40650
|
-
handleCommandError(err, opts.json, "Wallet creation 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
|
+
);
|
|
40651
40692
|
}
|
|
40652
|
-
|
|
40653
|
-
|
|
40654
|
-
|
|
40655
|
-
|
|
40656
|
-
|
|
40657
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
40658
|
-
try {
|
|
40659
|
-
if (!getChainById(opts.chain)) {
|
|
40660
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
40661
|
-
}
|
|
40662
|
-
await ensureTrustSDK();
|
|
40663
|
-
const password3 = await resolvePassword(opts);
|
|
40664
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
40665
|
-
const address = await provider.getAddress(opts.chain);
|
|
40666
|
-
if (opts.json) {
|
|
40667
|
-
output({ chain: opts.chain, address }, true);
|
|
40668
|
-
} else {
|
|
40669
|
-
const qr3 = getQRString(address);
|
|
40670
|
-
const content = `${import_chalk6.default.dim("Chain")} ${import_chalk6.default.bold(opts.chain)}
|
|
40671
|
-
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
40672
|
-
|
|
40673
|
-
${qr3}`;
|
|
40674
|
-
console.log(box(content));
|
|
40675
|
-
}
|
|
40676
|
-
} catch (err) {
|
|
40677
|
-
handleCommandError(err, opts.json, "Wallet address failed");
|
|
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" }
|
|
40697
|
+
);
|
|
40678
40698
|
}
|
|
40679
|
-
|
|
40680
|
-
}
|
|
40681
|
-
|
|
40682
|
-
|
|
40683
|
-
|
|
40684
|
-
|
|
40685
|
-
|
|
40686
|
-
|
|
40687
|
-
|
|
40688
|
-
|
|
40689
|
-
|
|
40690
|
-
|
|
40691
|
-
output({ addresses }, true);
|
|
40692
|
-
} else {
|
|
40693
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
40694
|
-
for (const addr of addresses) {
|
|
40695
|
-
const chains = grouped.get(addr.address) ?? [];
|
|
40696
|
-
chains.push(addr.chainId);
|
|
40697
|
-
grouped.set(addr.address, chains);
|
|
40698
|
-
}
|
|
40699
|
-
for (const [address, chains] of grouped) {
|
|
40700
|
-
const qr3 = getQRString(address);
|
|
40701
|
-
const maxWidth = Math.max(address.length + 9, 50);
|
|
40702
|
-
const chainLabel = `${import_chalk6.default.dim("Chains")} `;
|
|
40703
|
-
const chainLabelLen = 9;
|
|
40704
|
-
const chainLines = [];
|
|
40705
|
-
let line = "";
|
|
40706
|
-
for (const c3 of chains) {
|
|
40707
|
-
const sep2 = line ? ", " : "";
|
|
40708
|
-
if (line && line.length + sep2.length + c3.length + chainLabelLen > maxWidth) {
|
|
40709
|
-
chainLines.push(line);
|
|
40710
|
-
line = c3;
|
|
40711
|
-
} else {
|
|
40712
|
-
line += sep2 + c3;
|
|
40713
|
-
}
|
|
40714
|
-
}
|
|
40715
|
-
if (line) chainLines.push(line);
|
|
40716
|
-
const chainsStr = chainLines.map((l4, i2) => (i2 === 0 ? chainLabel : " ".repeat(chainLabelLen)) + import_chalk6.default.bold(l4)).join("\n");
|
|
40717
|
-
const content = `${chainsStr}
|
|
40718
|
-
${import_chalk6.default.dim("Address")} ${import_chalk6.default.green(address)}
|
|
40719
|
-
|
|
40720
|
-
${qr3}`;
|
|
40721
|
-
console.log(box(content));
|
|
40722
|
-
}
|
|
40723
|
-
}
|
|
40724
|
-
} catch (err) {
|
|
40725
|
-
handleCommandError(err, opts.json, "Wallet addresses 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);
|
|
40726
40711
|
}
|
|
40727
|
-
|
|
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
|
|
40728
40747
|
});
|
|
40729
|
-
|
|
40730
|
-
|
|
40731
|
-
|
|
40732
|
-
|
|
40733
|
-
|
|
40734
|
-
|
|
40735
|
-
|
|
40736
|
-
|
|
40737
|
-
|
|
40738
|
-
|
|
40739
|
-
|
|
40740
|
-
await ensureTrustSDK();
|
|
40741
|
-
const password3 = await resolvePassword(opts);
|
|
40742
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
40743
|
-
const httpClient = await getClient();
|
|
40744
|
-
if (!opts.all) {
|
|
40745
|
-
const chain2 = getChainById(opts.chain);
|
|
40746
|
-
if (!chain2) {
|
|
40747
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
40748
|
-
}
|
|
40749
|
-
}
|
|
40750
|
-
const allAddresses = await provider.getAddresses();
|
|
40751
|
-
const addressMap = /* @__PURE__ */ new Map();
|
|
40752
|
-
for (const a3 of allAddresses) addressMap.set(a3.chainId, a3.address);
|
|
40753
|
-
const requestedChains = opts.all ? Object.keys(CHAINS) : [opts.chain];
|
|
40754
|
-
const skipTokens = opts.tokens === false;
|
|
40755
|
-
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
40756
|
-
const chain2 = getChainById(chainKey);
|
|
40757
|
-
const address = addressMap.get(chainKey);
|
|
40758
|
-
if (!chain2 || !address) return [];
|
|
40759
|
-
return [{ chainKey, chain: chain2, address }];
|
|
40760
|
-
});
|
|
40761
|
-
if (!opts.all && chainEntries.length === 0) {
|
|
40762
|
-
throw new WalletError(
|
|
40763
|
-
"CHAIN_UNSUPPORTED",
|
|
40764
|
-
`Wallet does not have an address for chain: ${opts.chain}`
|
|
40765
|
-
);
|
|
40766
|
-
}
|
|
40767
|
-
const nativeAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
40768
|
-
chainKey,
|
|
40769
|
-
chain: chain2,
|
|
40770
|
-
token: void 0,
|
|
40771
|
-
assetId: `c${chain2.coinId}`,
|
|
40772
|
-
userAddress: address
|
|
40773
|
-
}));
|
|
40774
|
-
const tokenAssets = skipTokens ? [] : chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
40775
|
-
const knownTokens = COMMON_TOKENS[chainKey];
|
|
40776
|
-
if (!knownTokens) return [];
|
|
40777
|
-
return Object.keys(knownTokens).flatMap((sym) => {
|
|
40778
|
-
const resolved = resolveToken(sym, chainKey);
|
|
40779
|
-
if (!resolved) return [];
|
|
40780
|
-
return [
|
|
40781
|
-
{
|
|
40782
|
-
chainKey,
|
|
40783
|
-
chain: chain2,
|
|
40784
|
-
token: { ...resolved, symbol: sym },
|
|
40785
|
-
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
40786
|
-
userAddress: address
|
|
40787
|
-
}
|
|
40788
|
-
];
|
|
40789
|
-
});
|
|
40790
|
-
});
|
|
40791
|
-
const allAssets = [...nativeAssets, ...tokenAssets];
|
|
40792
|
-
const balances = await fetchBalances(
|
|
40793
|
-
httpClient,
|
|
40794
|
-
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
40795
|
-
);
|
|
40796
|
-
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
40797
|
-
const resultsByChain = /* @__PURE__ */ new Map();
|
|
40798
|
-
for (const { chainKey, chain: chain2, address } of chainEntries) {
|
|
40799
|
-
resultsByChain.set(chainKey, {
|
|
40800
|
-
chain: chainKey,
|
|
40801
|
-
address,
|
|
40802
|
-
symbol: chain2.symbol,
|
|
40803
|
-
available: "0",
|
|
40804
|
-
total: "0",
|
|
40805
|
-
totalUsd: null,
|
|
40806
|
-
tokens: []
|
|
40807
|
-
});
|
|
40808
|
-
}
|
|
40809
|
-
for (const balance of balances) {
|
|
40810
|
-
const assetInfo = assetsById.get(balance.assetId);
|
|
40811
|
-
if (!assetInfo) {
|
|
40812
|
-
throw new WalletError(
|
|
40813
|
-
"NETWORK_ERROR",
|
|
40814
|
-
"Could not fetch balances. Please try again later."
|
|
40815
|
-
);
|
|
40816
|
-
}
|
|
40817
|
-
const result = resultsByChain.get(assetInfo.chainKey);
|
|
40818
|
-
if (!result) continue;
|
|
40819
|
-
const { token, chain: chain2 } = assetInfo;
|
|
40820
|
-
const amts = balance.amounts;
|
|
40821
|
-
if (token) {
|
|
40822
|
-
const human = formatAmount(amts.total ?? "0", token.decimals);
|
|
40823
|
-
if (human !== "0") {
|
|
40824
|
-
result.tokens.push({
|
|
40825
|
-
symbol: token.symbol,
|
|
40826
|
-
contract: token.address,
|
|
40827
|
-
balance: human
|
|
40828
|
-
});
|
|
40829
|
-
}
|
|
40830
|
-
} else {
|
|
40831
|
-
result.available = formatAmount(amts.available ?? "0", chain2.decimals);
|
|
40832
|
-
result.total = formatAmount(amts.total ?? "0", chain2.decimals);
|
|
40833
|
-
const lockedHuman = formatAmount(amts.locked ?? "0", chain2.decimals);
|
|
40834
|
-
if (lockedHuman !== "0") result.staked = lockedHuman;
|
|
40835
|
-
const fiat = amts.totalInFiat;
|
|
40836
|
-
result.totalUsd = fiat && fiat !== "" ? parseFloat(fiat) : null;
|
|
40837
|
-
}
|
|
40838
|
-
}
|
|
40839
|
-
const orderedResults = chainEntries.map((e2) => resultsByChain.get(e2.chainKey)).filter((r3) => r3 !== void 0);
|
|
40840
|
-
const visible = opts.all ? orderedResults.filter((r3) => r3.total !== "0" || r3.tokens.length > 0) : orderedResults;
|
|
40841
|
-
const renderBlock = (r3, withSeparator) => {
|
|
40842
|
-
if (withSeparator) console.log("");
|
|
40843
|
-
console.log(import_chalk6.default.bold.underline(`${r3.chain} (${r3.symbol})`));
|
|
40844
|
-
console.log(` ${import_chalk6.default.dim("Address")} ${r3.address}`);
|
|
40845
|
-
console.log(` ${import_chalk6.default.dim("Available")} ${r3.available}`);
|
|
40846
|
-
if (r3.staked) console.log(` ${import_chalk6.default.dim("Staked")} ${r3.staked}`);
|
|
40847
|
-
const usdSuffix = r3.totalUsd !== null ? ` (\u2248 $${r3.totalUsd.toFixed(2)})` : "";
|
|
40848
|
-
console.log(` ${import_chalk6.default.dim("Total")} ${r3.total}${usdSuffix}`);
|
|
40849
|
-
if (r3.tokens.length > 0) {
|
|
40850
|
-
console.log(` ${import_chalk6.default.dim("Tokens:")}`);
|
|
40851
|
-
for (const t of r3.tokens) {
|
|
40852
|
-
console.log(` ${import_chalk6.default.bold(t.symbol.padEnd(10))} ${t.balance}`);
|
|
40853
|
-
}
|
|
40854
|
-
}
|
|
40855
|
-
};
|
|
40856
|
-
if (opts.all) {
|
|
40857
|
-
if (opts.json) {
|
|
40858
|
-
output(visible, true);
|
|
40859
|
-
} else if (visible.length === 0) {
|
|
40860
|
-
info("No chains with non-zero native balance found.");
|
|
40861
|
-
} else {
|
|
40862
|
-
visible.forEach((r3, i2) => renderBlock(r3, i2 > 0));
|
|
40863
|
-
}
|
|
40864
|
-
} else {
|
|
40865
|
-
const single = visible[0];
|
|
40866
|
-
if (opts.json) {
|
|
40867
|
-
output(single, true);
|
|
40868
|
-
} else {
|
|
40869
|
-
renderBlock(single, false);
|
|
40870
|
-
}
|
|
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
|
|
40871
40759
|
}
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
|
|
40875
|
-
|
|
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);
|
|
40876
40769
|
});
|
|
40877
|
-
|
|
40878
|
-
|
|
40879
|
-
|
|
40880
|
-
|
|
40881
|
-
|
|
40882
|
-
|
|
40883
|
-
|
|
40884
|
-
|
|
40885
|
-
|
|
40886
|
-
|
|
40887
|
-
|
|
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");
|
|
40888
40782
|
}
|
|
40889
|
-
|
|
40890
|
-
|
|
40891
|
-
|
|
40892
|
-
|
|
40893
|
-
|
|
40894
|
-
|
|
40895
|
-
throw new WalletError("KEYCHAIN_UNAVAILABLE", "OS keychain not available on this system");
|
|
40896
|
-
}
|
|
40897
|
-
await kc2.deleteWalletPassword();
|
|
40898
|
-
success("Wallet password removed from OS keychain");
|
|
40899
|
-
} catch (err) {
|
|
40900
|
-
handleCommandError(err, opts.json, "Keychain delete failed");
|
|
40901
|
-
}
|
|
40902
|
-
safeExit();
|
|
40903
|
-
});
|
|
40904
|
-
keychain.command("check").description("Check if wallet password is stored in OS keychain").option("--json", "JSON output").action(async (opts) => {
|
|
40905
|
-
try {
|
|
40906
|
-
const kc2 = new KeychainManager();
|
|
40907
|
-
if (!kc2.isAvailable()) {
|
|
40908
|
-
if (opts.json) {
|
|
40909
|
-
output({ available: false, stored: false }, true);
|
|
40910
|
-
} else {
|
|
40911
|
-
warn("keytar not available on this system");
|
|
40912
|
-
}
|
|
40913
|
-
safeExit();
|
|
40914
|
-
return;
|
|
40915
|
-
}
|
|
40916
|
-
const pw = await kc2.getWalletPassword();
|
|
40917
|
-
if (opts.json) {
|
|
40918
|
-
output({ available: true, stored: !!pw }, true);
|
|
40919
|
-
} else if (pw) {
|
|
40920
|
-
success("Wallet password is stored in OS keychain");
|
|
40921
|
-
} else {
|
|
40922
|
-
info("No wallet password found in OS keychain");
|
|
40923
|
-
}
|
|
40924
|
-
} catch (err) {
|
|
40925
|
-
handleCommandError(err, opts.json, "Keychain check failed");
|
|
40926
|
-
}
|
|
40927
|
-
safeExit();
|
|
40928
|
-
});
|
|
40929
|
-
wallet.command("connect").description("Connect external wallet via WalletConnect").option("--project-id <id>", "WalletConnect project ID (or set WALLETCONNECT_PROJECT_ID)").option(
|
|
40930
|
-
"--chains <list>",
|
|
40931
|
-
"Comma-separated CAIP-2 chain IDs",
|
|
40932
|
-
"eip155:1,eip155:56,eip155:137,eip155:8453,eip155:42161"
|
|
40933
|
-
).option("--timeout <seconds>", "Connection timeout in seconds", "300").option("--json", "JSON output").action(async (opts) => {
|
|
40934
|
-
try {
|
|
40935
|
-
const projectId = opts.projectId || process.env.WALLETCONNECT_PROJECT_ID;
|
|
40936
|
-
if (!projectId) {
|
|
40937
|
-
throw new WalletError(
|
|
40938
|
-
"VALIDATION_ERROR",
|
|
40939
|
-
"WalletConnect project ID required. Use --project-id or set WALLETCONNECT_PROJECT_ID"
|
|
40940
|
-
);
|
|
40941
|
-
}
|
|
40942
|
-
const provider = new WalletConnectProvider({ projectId });
|
|
40943
|
-
const chains = opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
40944
|
-
info("Connecting via WalletConnect...");
|
|
40945
|
-
const result = await provider.connect(chains);
|
|
40946
|
-
const qr3 = getQRString(result.uri);
|
|
40947
|
-
if (qr3) {
|
|
40948
|
-
console.log(qr3);
|
|
40949
|
-
}
|
|
40950
|
-
info(`Trust Wallet: ${result.deepLinks.native}`);
|
|
40951
|
-
info(`Universal: ${result.deepLinks.universal}`);
|
|
40952
|
-
info("\nWaiting for wallet approval...");
|
|
40953
|
-
const timeoutMs = parseInt(opts.timeout, 10) * 1e3;
|
|
40954
|
-
const session = await provider.waitForSession(timeoutMs);
|
|
40955
|
-
if (opts.json) {
|
|
40956
|
-
output(
|
|
40957
|
-
{
|
|
40958
|
-
connected: true,
|
|
40959
|
-
address: session.address,
|
|
40960
|
-
chainId: session.chainId,
|
|
40961
|
-
peer: session.peerName
|
|
40962
|
-
},
|
|
40963
|
-
true
|
|
40964
|
-
);
|
|
40965
|
-
} else {
|
|
40966
|
-
success(`Connected to ${session.peerName || "wallet"}`);
|
|
40967
|
-
info(` Address: ${session.address}`);
|
|
40968
|
-
info(` Chain: ${session.chainId}`);
|
|
40969
|
-
}
|
|
40970
|
-
} catch (err) {
|
|
40971
|
-
handleCommandError(err, opts.json, "WalletConnect failed");
|
|
40972
|
-
}
|
|
40973
|
-
safeExit();
|
|
40974
|
-
});
|
|
40975
|
-
wallet.command("status").description("Check wallet configuration status").option("--json", "JSON output").action(async (opts) => {
|
|
40976
|
-
try {
|
|
40977
|
-
const store = new WalletConfigStore();
|
|
40978
|
-
const exists = await store.exists();
|
|
40979
|
-
const kc2 = new KeychainManager();
|
|
40980
|
-
const keychainHasPassword = kc2.isAvailable() ? !!await kc2.getWalletPassword() : false;
|
|
40981
|
-
const totalChains = Object.keys(CHAINS).length;
|
|
40982
|
-
let createdAt;
|
|
40983
|
-
let addressCount;
|
|
40984
|
-
if (exists) {
|
|
40985
|
-
const config = await store.getConfig();
|
|
40986
|
-
createdAt = config?.createdAt;
|
|
40987
|
-
addressCount = config?.chains?.length ?? totalChains;
|
|
40988
|
-
}
|
|
40989
|
-
const result = {
|
|
40990
|
-
agentWallet: exists ? "configured" : "not configured",
|
|
40991
|
-
keychainPassword: keychainHasPassword ? "stored" : "not stored",
|
|
40992
|
-
chains: totalChains,
|
|
40993
|
-
supportedChains: totalChains,
|
|
40994
|
-
...createdAt ? { createdAt } : {},
|
|
40995
|
-
...addressCount !== void 0 ? { addressCount } : {}
|
|
40996
|
-
};
|
|
40997
|
-
if (opts.json) {
|
|
40998
|
-
output(result, true);
|
|
40999
|
-
} else {
|
|
41000
|
-
console.log(
|
|
41001
|
-
` ${import_chalk6.default.dim("Wallet")} ${exists ? import_chalk6.default.green("configured") : import_chalk6.default.yellow("not configured")}`
|
|
41002
|
-
);
|
|
41003
|
-
if (createdAt) console.log(` ${import_chalk6.default.dim("Created")} ${createdAt}`);
|
|
41004
|
-
console.log(
|
|
41005
|
-
` ${import_chalk6.default.dim("Keychain")} ${keychainHasPassword ? import_chalk6.default.green("password stored") : import_chalk6.default.yellow("no password")}`
|
|
41006
|
-
);
|
|
41007
|
-
console.log(` ${import_chalk6.default.dim("Chains")} ${totalChains} supported`);
|
|
41008
|
-
if (addressCount !== void 0)
|
|
41009
|
-
console.log(` ${import_chalk6.default.dim("Addresses")} ${addressCount}`);
|
|
41010
|
-
if (!exists) info("\nRun `twak wallet create --password <pw>` to create a wallet.");
|
|
41011
|
-
}
|
|
41012
|
-
} catch (err) {
|
|
41013
|
-
handleCommandError(err, opts.json, "Status failed");
|
|
41014
|
-
}
|
|
41015
|
-
safeExit();
|
|
41016
|
-
});
|
|
41017
|
-
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(
|
|
41018
|
-
"--password <password>",
|
|
41019
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
41020
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
41021
|
-
try {
|
|
41022
|
-
await ensureTrustSDK();
|
|
41023
|
-
const password3 = await resolvePassword(opts);
|
|
41024
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41025
|
-
const httpClient = await getClient();
|
|
41026
|
-
const allAddresses = await provider.getAddresses();
|
|
41027
|
-
const chainsArg = opts.chains ?? Object.keys(CHAINS).join(",");
|
|
41028
|
-
const requestedChains = chainsArg.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
41029
|
-
if (requestedChains.length === 0) {
|
|
41030
|
-
throw new WalletError("VALIDATION_ERROR", "--chains must include at least one chain key");
|
|
41031
|
-
}
|
|
41032
|
-
const chainEntries = requestedChains.flatMap((chainKey) => {
|
|
41033
|
-
const chain2 = getChainById(chainKey);
|
|
41034
|
-
const addrEntry = allAddresses.find((a3) => a3.chainId === chainKey);
|
|
41035
|
-
if (!chain2 || !addrEntry) return [];
|
|
41036
|
-
return [{ chainKey, chain: chain2, address: addrEntry.address }];
|
|
41037
|
-
});
|
|
41038
|
-
if (chainEntries.length === 0) {
|
|
41039
|
-
throw new WalletError(
|
|
41040
|
-
"CHAIN_UNSUPPORTED",
|
|
41041
|
-
`No supported chains found in --chains "${opts.chains}"`
|
|
41042
|
-
);
|
|
41043
|
-
}
|
|
41044
|
-
const chainAssets = chainEntries.map(({ chainKey, chain: chain2, address }) => ({
|
|
41045
|
-
chainKey,
|
|
41046
|
-
chain: chain2,
|
|
41047
|
-
token: void 0,
|
|
41048
|
-
assetId: `c${chain2.coinId}`,
|
|
41049
|
-
userAddress: address
|
|
41050
|
-
}));
|
|
41051
|
-
const tokenAssets = chainEntries.flatMap(({ chainKey, chain: chain2, address }) => {
|
|
41052
|
-
const knownTokens = COMMON_TOKENS[chainKey];
|
|
41053
|
-
if (!knownTokens) return [];
|
|
41054
|
-
return Object.keys(knownTokens).flatMap((sym) => {
|
|
41055
|
-
const resolved = resolveToken(sym, chainKey);
|
|
41056
|
-
if (!resolved) return [];
|
|
41057
|
-
return [
|
|
41058
|
-
{
|
|
41059
|
-
chainKey,
|
|
41060
|
-
chain: chain2,
|
|
41061
|
-
token: { ...resolved, symbol: sym },
|
|
41062
|
-
assetId: `c${chain2.coinId}_t${resolved.address}`,
|
|
41063
|
-
userAddress: address
|
|
41064
|
-
}
|
|
41065
|
-
];
|
|
41066
|
-
});
|
|
41067
|
-
});
|
|
41068
|
-
const allAssets = [...chainAssets, ...tokenAssets];
|
|
41069
|
-
const balances = await fetchBalances(
|
|
41070
|
-
httpClient,
|
|
41071
|
-
allAssets.map(({ assetId, userAddress }) => ({ assetId, address: userAddress }))
|
|
41072
|
-
);
|
|
41073
|
-
const assetsById = new Map(allAssets.map((a3) => [a3.assetId, a3]));
|
|
41074
|
-
const allRows = [];
|
|
41075
|
-
for (const balance of balances) {
|
|
41076
|
-
const assetInfo = assetsById.get(balance.assetId);
|
|
41077
|
-
if (!assetInfo) {
|
|
41078
|
-
throw new WalletError(
|
|
41079
|
-
"NETWORK_ERROR",
|
|
41080
|
-
"Could not fetch balances. Please try again later."
|
|
41081
|
-
);
|
|
41082
|
-
}
|
|
41083
|
-
const { token, chain: chain2, chainKey, userAddress } = assetInfo;
|
|
41084
|
-
const decimals = token ? token.decimals : chain2.decimals;
|
|
41085
|
-
const symbol = token ? token.symbol ?? token.address : chain2.symbol;
|
|
41086
|
-
const isToken = token !== void 0;
|
|
41087
|
-
const humanAmount = formatAmount(balance.amounts.total, decimals);
|
|
41088
|
-
const fiatRaw = balance.amounts.totalInFiat;
|
|
41089
|
-
const usdValue = fiatRaw && fiatRaw !== "" ? parseFloat(fiatRaw) : null;
|
|
41090
|
-
allRows.push({
|
|
41091
|
-
chain: chainKey,
|
|
41092
|
-
type: isToken ? "token" : "native",
|
|
41093
|
-
symbol,
|
|
41094
|
-
address: userAddress,
|
|
41095
|
-
...token ? { contract: token.address } : {},
|
|
41096
|
-
balance: humanAmount,
|
|
41097
|
-
usdValue
|
|
41098
|
-
});
|
|
41099
|
-
}
|
|
41100
|
-
const rows = allRows.filter((r3) => r3.type === "native" || r3.balance !== "0");
|
|
41101
|
-
rows.sort((a3, b3) => {
|
|
41102
|
-
const chainCmp = String(a3.chain).localeCompare(String(b3.chain));
|
|
41103
|
-
if (chainCmp !== 0) return chainCmp;
|
|
41104
|
-
return String(a3.type).localeCompare(String(b3.type));
|
|
41105
|
-
});
|
|
41106
|
-
if (opts.json) {
|
|
41107
|
-
output(rows, true);
|
|
41108
|
-
} else {
|
|
41109
|
-
const totalUsd = rows.reduce(
|
|
41110
|
-
(sum, r3) => sum + (typeof r3.usdValue === "number" ? r3.usdValue : 0),
|
|
41111
|
-
0
|
|
41112
|
-
);
|
|
41113
|
-
console.log("Chain Type Symbol Balance USD");
|
|
41114
|
-
console.log("\u2500".repeat(72));
|
|
41115
|
-
for (const r3 of rows) {
|
|
41116
|
-
const usd = r3.usdValue !== null ? `$${r3.usdValue.toFixed(2)}` : "";
|
|
41117
|
-
console.log(
|
|
41118
|
-
`${String(r3.chain).padEnd(12)} ${String(r3.type).padEnd(7)} ${String(r3.symbol).padEnd(17)} ${String(r3.balance).padEnd(20)} ${usd}`
|
|
41119
|
-
);
|
|
41120
|
-
}
|
|
41121
|
-
console.log("\u2500".repeat(72));
|
|
41122
|
-
console.log(`Total USD: $${totalUsd.toFixed(2)}`);
|
|
41123
|
-
}
|
|
41124
|
-
} catch (err) {
|
|
41125
|
-
handleCommandError(err, opts.json, "Portfolio failed");
|
|
41126
|
-
}
|
|
41127
|
-
safeExit();
|
|
41128
|
-
});
|
|
41129
|
-
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(
|
|
41130
|
-
"--password <password>",
|
|
41131
|
-
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
41132
|
-
).option("--json", "JSON output").action(async (opts) => {
|
|
41133
|
-
try {
|
|
41134
|
-
if (!getChainById(opts.chain)) {
|
|
41135
|
-
throw new WalletError("CHAIN_UNSUPPORTED", `Unknown chain: ${opts.chain}`);
|
|
41136
|
-
}
|
|
41137
|
-
await ensureTrustSDK();
|
|
41138
|
-
const password3 = await resolvePassword(opts);
|
|
41139
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41140
|
-
const address = await provider.getAddress(opts.chain);
|
|
41141
|
-
const signature = await provider.signMessage(opts.chain, opts.message);
|
|
41142
|
-
output({ chain: opts.chain, address, message: opts.message, signature }, opts.json);
|
|
41143
|
-
} catch (err) {
|
|
41144
|
-
handleCommandError(err, opts.json, "Sign failed");
|
|
41145
|
-
}
|
|
41146
|
-
safeExit();
|
|
41147
|
-
});
|
|
41148
|
-
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) => {
|
|
41149
|
-
try {
|
|
41150
|
-
const creds = await ensureTrustSDK();
|
|
41151
|
-
const password3 = await resolvePassword(opts);
|
|
41152
|
-
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
41153
|
-
await registerWalletWithBackend(creds, provider);
|
|
41154
|
-
if (!opts.json) success("Wallet registered with backend");
|
|
41155
|
-
const addresses = await provider.getAddresses();
|
|
41156
|
-
output({ registered: true, chains: addresses.length }, opts.json);
|
|
41157
|
-
} catch (err) {
|
|
41158
|
-
handleCommandError(err, opts.json, "Registration failed");
|
|
41159
|
-
}
|
|
41160
|
-
safeExit();
|
|
41161
|
-
});
|
|
41162
|
-
}
|
|
41163
|
-
|
|
41164
|
-
// src/commands/transfer.ts
|
|
41165
|
-
init_dist();
|
|
41166
|
-
|
|
41167
|
-
// ../swap/dist/index.mjs
|
|
41168
|
-
init_dist();
|
|
41169
|
-
init_dist();
|
|
41170
|
-
|
|
41171
|
-
// ../contracts/dist/index.mjs
|
|
41172
|
-
init_dist();
|
|
41173
|
-
init_dist();
|
|
41174
|
-
init_dist();
|
|
41175
|
-
init_dist();
|
|
41176
|
-
init_dist3();
|
|
41177
|
-
init_dist();
|
|
41178
|
-
init_dist();
|
|
41179
|
-
init_dist();
|
|
41180
|
-
var HEX_PATTERN = /^0x[0-9a-fA-F]*$/;
|
|
41181
|
-
function isHex(value) {
|
|
41182
|
-
return HEX_PATTERN.test(value);
|
|
41183
|
-
}
|
|
41184
|
-
function hexToBytes3(hex2) {
|
|
41185
|
-
if (!isHex(hex2)) {
|
|
41186
|
-
throw new TwakValidationError(`Invalid hex string: ${hex2}`, { kind: "invalidHex" });
|
|
41187
|
-
}
|
|
41188
|
-
const clean2 = hex2.slice(2);
|
|
41189
|
-
if (clean2.length % 2 !== 0) {
|
|
41190
|
-
throw new TwakValidationError(`Hex string has odd length: ${hex2}`, { kind: "invalidHex" });
|
|
41191
|
-
}
|
|
41192
|
-
const out = new Uint8Array(clean2.length / 2);
|
|
41193
|
-
for (let i2 = 0; i2 < out.length; i2++) {
|
|
41194
|
-
out[i2] = parseInt(clean2.slice(i2 * 2, i2 * 2 + 2), 16);
|
|
41195
|
-
}
|
|
41196
|
-
return out;
|
|
41197
|
-
}
|
|
41198
|
-
function bytesToHex3(bytes) {
|
|
41199
|
-
let out = "0x";
|
|
41200
|
-
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
41201
|
-
out += bytes[i2].toString(16).padStart(2, "0");
|
|
41202
|
-
}
|
|
41203
|
-
return out;
|
|
41204
|
-
}
|
|
41205
|
-
function hexOrUtf8ToBytesHex(value) {
|
|
41206
|
-
const looksHex = value.length >= 2 && value[0] === "0" && (value[1] === "x" || value[1] === "X");
|
|
41207
|
-
if (looksHex) {
|
|
41208
|
-
const canonical = "0x" + value.slice(2);
|
|
41209
|
-
if (!isHex(canonical)) {
|
|
41210
|
-
throw new TwakValidationError(
|
|
41211
|
-
`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.`,
|
|
41212
|
-
{ kind: "invalidHex" }
|
|
41213
|
-
);
|
|
41214
|
-
}
|
|
41215
|
-
if ((canonical.length - 2) % 2 !== 0) {
|
|
41216
|
-
throw new TwakValidationError(
|
|
41217
|
-
`Hex value has odd length: ${value}. Solidity bytes must be byte-aligned.`,
|
|
41218
|
-
{ kind: "invalidHex" }
|
|
41219
|
-
);
|
|
41220
|
-
}
|
|
41221
|
-
return canonical;
|
|
41222
|
-
}
|
|
41223
|
-
return bytesToHex3(new TextEncoder().encode(value));
|
|
41224
|
-
}
|
|
41225
|
-
function wc2() {
|
|
41226
|
-
return getWalletCore();
|
|
41227
|
-
}
|
|
41228
|
-
var BRIDGE = {
|
|
41229
|
-
createAbiFunction(name2) {
|
|
41230
|
-
const ctor = wc2().EthereumAbiFunction;
|
|
41231
|
-
if (typeof ctor?.createWithString === "function") {
|
|
41232
|
-
return ctor.createWithString(name2);
|
|
41233
|
-
}
|
|
41234
|
-
return new ctor(name2);
|
|
41235
|
-
},
|
|
41236
|
-
encode(fn2) {
|
|
41237
|
-
return wc2().EthereumAbi.encode(fn2);
|
|
41238
|
-
},
|
|
41239
|
-
decodeOutput(fn2, data) {
|
|
41240
|
-
return wc2().EthereumAbi.decodeOutput(fn2, data);
|
|
41241
|
-
},
|
|
41242
|
-
keccak256(data) {
|
|
41243
|
-
return wc2().Hash.keccak256(data);
|
|
41244
|
-
}
|
|
41245
|
-
};
|
|
41246
|
-
function getAbiBridge() {
|
|
41247
|
-
return BRIDGE;
|
|
41248
|
-
}
|
|
41249
|
-
function findAbiFunction(abi, methodName) {
|
|
41250
|
-
const entry = abi.find(
|
|
41251
|
-
(e2) => e2.type === "function" && e2.name === methodName
|
|
41252
|
-
);
|
|
41253
|
-
if (!entry) {
|
|
41254
|
-
throw new TwakValidationError(`Unknown ABI method: ${methodName}`, {
|
|
41255
|
-
kind: "unknownMethod",
|
|
41256
|
-
methodName
|
|
41257
|
-
});
|
|
41258
|
-
}
|
|
41259
|
-
return entry;
|
|
41260
|
-
}
|
|
41261
|
-
function encodeFunctionCall(abi, methodName, args) {
|
|
41262
|
-
const fnDef = findAbiFunction(abi, methodName);
|
|
41263
|
-
if (args.length !== fnDef.inputs.length) {
|
|
41264
|
-
throw new TwakValidationError(
|
|
41265
|
-
`Wrong arg count for ${methodName}: expected ${fnDef.inputs.length}, got ${args.length}`,
|
|
41266
|
-
{
|
|
41267
|
-
kind: "wrongArgCount",
|
|
41268
|
-
methodName,
|
|
41269
|
-
expected: fnDef.inputs.length,
|
|
41270
|
-
actual: args.length
|
|
41271
|
-
}
|
|
41272
|
-
);
|
|
41273
|
-
}
|
|
41274
|
-
const bridge = getAbiBridge();
|
|
41275
|
-
const fn2 = bridge.createAbiFunction(methodName);
|
|
41276
|
-
fnDef.inputs.forEach((param, i2) => {
|
|
41277
|
-
pushParam(fn2, param, args[i2], methodName);
|
|
41278
|
-
});
|
|
41279
|
-
return bytesToHex3(bridge.encode(fn2));
|
|
41280
|
-
}
|
|
41281
|
-
function pushParam(fn2, param, value, methodName) {
|
|
41282
|
-
const type = param.type;
|
|
41283
|
-
const isOutput = false;
|
|
41284
|
-
if (type === "address") {
|
|
41285
|
-
fn2.addParamAddress(toAddressBytes(value, param, methodName), isOutput);
|
|
41286
|
-
return;
|
|
41287
|
-
}
|
|
41288
|
-
if (type === "bool") {
|
|
41289
|
-
if (typeof value !== "boolean") {
|
|
41290
|
-
throw argTypeMismatch(methodName, param, value, "boolean");
|
|
41291
|
-
}
|
|
41292
|
-
fn2.addParamBool(value, isOutput);
|
|
41293
|
-
return;
|
|
41294
|
-
}
|
|
41295
|
-
if (type === "string") {
|
|
41296
|
-
if (typeof value !== "string") {
|
|
41297
|
-
throw argTypeMismatch(methodName, param, value, "string");
|
|
40783
|
+
fn2.addParamBool(value, isOutput);
|
|
40784
|
+
return;
|
|
40785
|
+
}
|
|
40786
|
+
if (type === "string") {
|
|
40787
|
+
if (typeof value !== "string") {
|
|
40788
|
+
throw argTypeMismatch(methodName, param, value, "string");
|
|
41298
40789
|
}
|
|
41299
40790
|
fn2.addParamString(value, isOutput);
|
|
41300
40791
|
return;
|
|
@@ -41311,32 +40802,8 @@ function pushParam(fn2, param, value, methodName) {
|
|
|
41311
40802
|
}
|
|
41312
40803
|
const intMatch = /^(u?)int(\d*)$/.exec(type);
|
|
41313
40804
|
if (intMatch) {
|
|
41314
|
-
const
|
|
41315
|
-
|
|
41316
|
-
if (bits < 8 || bits > 256 || bits % 8 !== 0) {
|
|
41317
|
-
throw new TwakValidationError(
|
|
41318
|
-
`Unsupported integer width ${type} for ${methodName}.${param.name} (expected 8..256, multiple of 8)`,
|
|
41319
|
-
{ kind: "argTypeMismatch", methodName, paramName: param.name, type }
|
|
41320
|
-
);
|
|
41321
|
-
}
|
|
41322
|
-
const bigValue = toBigInt2(value, param, methodName);
|
|
41323
|
-
if (isUnsigned) {
|
|
41324
|
-
if (bigValue < 0n || bigValue >= 1n << BigInt(bits)) {
|
|
41325
|
-
throw argTypeMismatch(methodName, param, value, `uint${bits} (0 <= x < 2^${bits})`);
|
|
41326
|
-
}
|
|
41327
|
-
} else {
|
|
41328
|
-
const limit = 1n << BigInt(bits - 1);
|
|
41329
|
-
if (bigValue < -limit || bigValue >= limit) {
|
|
41330
|
-
throw argTypeMismatch(
|
|
41331
|
-
methodName,
|
|
41332
|
-
param,
|
|
41333
|
-
value,
|
|
41334
|
-
`int${bits} (-2^${bits - 1} <= x < 2^${bits - 1})`
|
|
41335
|
-
);
|
|
41336
|
-
}
|
|
41337
|
-
}
|
|
41338
|
-
const bytes = bigIntToBytes32(bigValue, isUnsigned);
|
|
41339
|
-
if (isUnsigned) {
|
|
40805
|
+
const bytes = encodeIntWord(type, value, param, methodName);
|
|
40806
|
+
if (intMatch[1] === "u") {
|
|
41340
40807
|
fn2.addParamUInt256(bytes, isOutput);
|
|
41341
40808
|
} else {
|
|
41342
40809
|
fn2.addParamInt256(bytes, isOutput);
|
|
@@ -41423,6 +40890,165 @@ function argTypeMismatch(methodName, param, value, expected) {
|
|
|
41423
40890
|
}
|
|
41424
40891
|
);
|
|
41425
40892
|
}
|
|
40893
|
+
function encodeIntWord(type, value, param, methodName) {
|
|
40894
|
+
const intMatch = /^(u?)int(\d*)$/.exec(type);
|
|
40895
|
+
const isUnsigned = intMatch[1] === "u";
|
|
40896
|
+
const bits = intMatch[2] ? Number(intMatch[2]) : 256;
|
|
40897
|
+
if (bits < 8 || bits > 256 || bits % 8 !== 0) {
|
|
40898
|
+
throw new TwakValidationError(
|
|
40899
|
+
`Unsupported integer width ${type} for ${methodName}.${param.name} (expected 8..256, multiple of 8)`,
|
|
40900
|
+
{ kind: "argTypeMismatch", methodName, paramName: param.name, type }
|
|
40901
|
+
);
|
|
40902
|
+
}
|
|
40903
|
+
const bigValue = toBigInt2(value, param, methodName);
|
|
40904
|
+
if (isUnsigned) {
|
|
40905
|
+
if (bigValue < 0n || bigValue >= 1n << BigInt(bits)) {
|
|
40906
|
+
throw argTypeMismatch(methodName, param, value, `uint${bits} (0 <= x < 2^${bits})`);
|
|
40907
|
+
}
|
|
40908
|
+
} else {
|
|
40909
|
+
const limit = 1n << BigInt(bits - 1);
|
|
40910
|
+
if (bigValue < -limit || bigValue >= limit) {
|
|
40911
|
+
throw argTypeMismatch(
|
|
40912
|
+
methodName,
|
|
40913
|
+
param,
|
|
40914
|
+
value,
|
|
40915
|
+
`int${bits} (-2^${bits - 1} <= x < 2^${bits - 1})`
|
|
40916
|
+
);
|
|
40917
|
+
}
|
|
40918
|
+
}
|
|
40919
|
+
return bigIntToBytes32(bigValue, isUnsigned);
|
|
40920
|
+
}
|
|
40921
|
+
function encoderRequiresHandRoll(params) {
|
|
40922
|
+
return params.some((p3) => p3.type === "tuple" || p3.type.endsWith("[]"));
|
|
40923
|
+
}
|
|
40924
|
+
function isDynamicType(param) {
|
|
40925
|
+
const t = param.type;
|
|
40926
|
+
if (t === "string" || t === "bytes") return true;
|
|
40927
|
+
if (t.endsWith("[]")) return true;
|
|
40928
|
+
if (t === "tuple") return (param.components ?? []).some(isDynamicType);
|
|
40929
|
+
return false;
|
|
40930
|
+
}
|
|
40931
|
+
function canonicalType(param) {
|
|
40932
|
+
const t = param.type;
|
|
40933
|
+
if (t === "tuple") return `(${(param.components ?? []).map(canonicalType).join(",")})`;
|
|
40934
|
+
if (t === "tuple[]") return `(${(param.components ?? []).map(canonicalType).join(",")})[]`;
|
|
40935
|
+
if (t.startsWith("tuple")) {
|
|
40936
|
+
throw new TwakValidationError(`Unsupported tuple array shape "${t}" for ${param.name}`, {
|
|
40937
|
+
kind: "argTypeMismatch",
|
|
40938
|
+
paramName: param.name,
|
|
40939
|
+
type: t
|
|
40940
|
+
});
|
|
40941
|
+
}
|
|
40942
|
+
return t;
|
|
40943
|
+
}
|
|
40944
|
+
function numberToWord(n4) {
|
|
40945
|
+
const out = new Uint8Array(32);
|
|
40946
|
+
let v5 = BigInt(n4);
|
|
40947
|
+
for (let i2 = 31; i2 >= 0; i2--) {
|
|
40948
|
+
out[i2] = Number(v5 & 0xffn);
|
|
40949
|
+
v5 >>= 8n;
|
|
40950
|
+
}
|
|
40951
|
+
return out;
|
|
40952
|
+
}
|
|
40953
|
+
function padRight32(bytes) {
|
|
40954
|
+
const out = new Uint8Array(Math.ceil(bytes.length / 32) * 32);
|
|
40955
|
+
out.set(bytes);
|
|
40956
|
+
return out;
|
|
40957
|
+
}
|
|
40958
|
+
function concatBytes3(parts) {
|
|
40959
|
+
const total = parts.reduce((acc, p3) => acc + p3.length, 0);
|
|
40960
|
+
const out = new Uint8Array(total);
|
|
40961
|
+
let offset = 0;
|
|
40962
|
+
for (const p3 of parts) {
|
|
40963
|
+
out.set(p3, offset);
|
|
40964
|
+
offset += p3.length;
|
|
40965
|
+
}
|
|
40966
|
+
return out;
|
|
40967
|
+
}
|
|
40968
|
+
function encodeHeadTail(items) {
|
|
40969
|
+
let headLen = 0;
|
|
40970
|
+
for (const it4 of items) headLen += it4.dynamic ? 32 : it4.bytes.length;
|
|
40971
|
+
const head = [];
|
|
40972
|
+
const tail = [];
|
|
40973
|
+
let offset = headLen;
|
|
40974
|
+
for (const it4 of items) {
|
|
40975
|
+
if (it4.dynamic) {
|
|
40976
|
+
head.push(numberToWord(offset));
|
|
40977
|
+
tail.push(it4.bytes);
|
|
40978
|
+
offset += it4.bytes.length;
|
|
40979
|
+
} else {
|
|
40980
|
+
head.push(it4.bytes);
|
|
40981
|
+
}
|
|
40982
|
+
}
|
|
40983
|
+
return concatBytes3([...head, ...tail]);
|
|
40984
|
+
}
|
|
40985
|
+
function encodeAbiValue(param, value, methodName) {
|
|
40986
|
+
const t = param.type;
|
|
40987
|
+
if (t.endsWith("[]")) {
|
|
40988
|
+
if (!Array.isArray(value)) {
|
|
40989
|
+
throw argTypeMismatch(methodName, param, value, `${t} (array)`);
|
|
40990
|
+
}
|
|
40991
|
+
const base3 = { ...param, type: t.slice(0, -2) };
|
|
40992
|
+
const items = value.map((v5) => encodeAbiValue(base3, v5, methodName));
|
|
40993
|
+
return {
|
|
40994
|
+
dynamic: true,
|
|
40995
|
+
bytes: concatBytes3([numberToWord(value.length), encodeHeadTail(items)])
|
|
40996
|
+
};
|
|
40997
|
+
}
|
|
40998
|
+
if (t === "tuple") {
|
|
40999
|
+
const components = param.components ?? [];
|
|
41000
|
+
if (!Array.isArray(value) || value.length !== components.length) {
|
|
41001
|
+
throw argTypeMismatch(methodName, param, value, `tuple of ${components.length} components`);
|
|
41002
|
+
}
|
|
41003
|
+
const items = components.map((c3, i2) => encodeAbiValue(c3, value[i2], methodName));
|
|
41004
|
+
return { dynamic: isDynamicType(param), bytes: encodeHeadTail(items) };
|
|
41005
|
+
}
|
|
41006
|
+
if (t === "string") {
|
|
41007
|
+
if (typeof value !== "string") {
|
|
41008
|
+
throw argTypeMismatch(methodName, param, value, "string");
|
|
41009
|
+
}
|
|
41010
|
+
const b3 = new TextEncoder().encode(value);
|
|
41011
|
+
return { dynamic: true, bytes: concatBytes3([numberToWord(b3.length), padRight32(b3)]) };
|
|
41012
|
+
}
|
|
41013
|
+
if (t === "bytes") {
|
|
41014
|
+
const b3 = toBytes4(value, param, methodName);
|
|
41015
|
+
return { dynamic: true, bytes: concatBytes3([numberToWord(b3.length), padRight32(b3)]) };
|
|
41016
|
+
}
|
|
41017
|
+
if (t === "address") {
|
|
41018
|
+
const word = new Uint8Array(32);
|
|
41019
|
+
word.set(toAddressBytes(value, param, methodName), 12);
|
|
41020
|
+
return { dynamic: false, bytes: word };
|
|
41021
|
+
}
|
|
41022
|
+
const bytesNMatch = /^bytes(\d+)$/.exec(t);
|
|
41023
|
+
if (bytesNMatch) {
|
|
41024
|
+
const size3 = Number(bytesNMatch[1]);
|
|
41025
|
+
return { dynamic: false, bytes: padRight32(toBytesFix(value, size3, param, methodName)) };
|
|
41026
|
+
}
|
|
41027
|
+
if (/^u?int\d*$/.test(t)) {
|
|
41028
|
+
return { dynamic: false, bytes: encodeIntWord(t, value, param, methodName) };
|
|
41029
|
+
}
|
|
41030
|
+
if (t === "bool") {
|
|
41031
|
+
if (typeof value !== "boolean") {
|
|
41032
|
+
throw argTypeMismatch(methodName, param, value, "boolean");
|
|
41033
|
+
}
|
|
41034
|
+
return { dynamic: false, bytes: numberToWord(value ? 1 : 0) };
|
|
41035
|
+
}
|
|
41036
|
+
throw new TwakValidationError(
|
|
41037
|
+
`Unsupported ABI param type "${t}" for ${methodName}.${param.name}`,
|
|
41038
|
+
{
|
|
41039
|
+
kind: "argTypeMismatch",
|
|
41040
|
+
methodName,
|
|
41041
|
+
paramName: param.name,
|
|
41042
|
+
type: t
|
|
41043
|
+
}
|
|
41044
|
+
);
|
|
41045
|
+
}
|
|
41046
|
+
function encodeFunctionCallHandRoll(methodName, inputs, args) {
|
|
41047
|
+
const signature = `${methodName}(${inputs.map(canonicalType).join(",")})`;
|
|
41048
|
+
const selector = getAbiBridge().keccak256(new TextEncoder().encode(signature)).slice(0, 4);
|
|
41049
|
+
const body = encodeHeadTail(inputs.map((p3, i2) => encodeAbiValue(p3, args[i2], methodName)));
|
|
41050
|
+
return bytesToHex3(concatBytes3([selector, body]));
|
|
41051
|
+
}
|
|
41426
41052
|
function decodeFunctionResult(abi, methodName, returnHex) {
|
|
41427
41053
|
const fnDef = findAbiFunction(abi, methodName);
|
|
41428
41054
|
if (fnDef.outputs.length === 0) return void 0;
|
|
@@ -41806,14 +41432,14 @@ function buildWriteProxy(abi, address, chainKey, client) {
|
|
|
41806
41432
|
});
|
|
41807
41433
|
}
|
|
41808
41434
|
const data = encodeFunctionCall(abi, prop, args);
|
|
41809
|
-
const
|
|
41435
|
+
const hash = await signer.sendTransaction({
|
|
41810
41436
|
chainId: chainKeyToCaip2(chainKey),
|
|
41811
41437
|
to: address,
|
|
41812
41438
|
data,
|
|
41813
41439
|
value: "0x0"
|
|
41814
41440
|
});
|
|
41815
41441
|
return makeContractPendingTransaction({
|
|
41816
|
-
|
|
41442
|
+
hash,
|
|
41817
41443
|
abi,
|
|
41818
41444
|
address,
|
|
41819
41445
|
chainKey,
|
|
@@ -41825,22 +41451,22 @@ function buildWriteProxy(abi, address, chainKey, client) {
|
|
|
41825
41451
|
});
|
|
41826
41452
|
}
|
|
41827
41453
|
function makeContractPendingTransaction(opts) {
|
|
41828
|
-
const {
|
|
41454
|
+
const { hash, abi, address, chainKey, client, methodName } = opts;
|
|
41829
41455
|
return {
|
|
41830
|
-
|
|
41456
|
+
hash,
|
|
41831
41457
|
async wait(waitOpts) {
|
|
41832
|
-
const receipt = await client.waitForReceipt(chainKey,
|
|
41458
|
+
const receipt = await client.waitForReceipt(chainKey, hash, {
|
|
41833
41459
|
timeoutMs: waitOpts?.timeoutMs
|
|
41834
41460
|
});
|
|
41835
41461
|
if (receipt.status === "0x0") {
|
|
41836
41462
|
throw new TwakError(
|
|
41837
41463
|
`Transaction reverted on-chain: ${receipt.transactionHash}`,
|
|
41838
41464
|
"TX_FAILED",
|
|
41839
|
-
{
|
|
41465
|
+
{ hash: receipt.transactionHash, methodName, receipt }
|
|
41840
41466
|
);
|
|
41841
41467
|
}
|
|
41842
41468
|
return {
|
|
41843
|
-
|
|
41469
|
+
hash: receipt.transactionHash,
|
|
41844
41470
|
blockNumber: hexToSafeNumber(receipt.blockNumber, "blockNumber"),
|
|
41845
41471
|
events: extractEvents(abi, receipt.logs, address)
|
|
41846
41472
|
};
|
|
@@ -41937,6 +41563,17 @@ function lookupAddress(id, addresses, chainKey) {
|
|
|
41937
41563
|
}
|
|
41938
41564
|
return address;
|
|
41939
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
|
+
}
|
|
41940
41577
|
var ERC20_ABI = [
|
|
41941
41578
|
{
|
|
41942
41579
|
type: "function",
|
|
@@ -42005,6 +41642,25 @@ var ERC8004_ABI = [
|
|
|
42005
41642
|
outputs: [{ name: "agentId", type: "uint256" }],
|
|
42006
41643
|
stateMutability: "nonpayable"
|
|
42007
41644
|
},
|
|
41645
|
+
{
|
|
41646
|
+
// register(agentURI, metadata[]) — mints + sets metadata atomically in one
|
|
41647
|
+
// tx. metadata is an array of (key, value) where value is raw bytes.
|
|
41648
|
+
type: "function",
|
|
41649
|
+
name: "register",
|
|
41650
|
+
inputs: [
|
|
41651
|
+
{ name: "agentURI", type: "string" },
|
|
41652
|
+
{
|
|
41653
|
+
name: "metadata",
|
|
41654
|
+
type: "tuple[]",
|
|
41655
|
+
components: [
|
|
41656
|
+
{ name: "key", type: "string" },
|
|
41657
|
+
{ name: "value", type: "bytes" }
|
|
41658
|
+
]
|
|
41659
|
+
}
|
|
41660
|
+
],
|
|
41661
|
+
outputs: [{ name: "agentId", type: "uint256" }],
|
|
41662
|
+
stateMutability: "nonpayable"
|
|
41663
|
+
},
|
|
42008
41664
|
{
|
|
42009
41665
|
type: "function",
|
|
42010
41666
|
name: "setAgentURI",
|
|
@@ -42100,7 +41756,8 @@ var ERC8004_ABI = [
|
|
|
42100
41756
|
}
|
|
42101
41757
|
];
|
|
42102
41758
|
var ERC8004_ADDRESSES = {
|
|
42103
|
-
bsc: "0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"
|
|
41759
|
+
bsc: "0x8004a169fb4a3325136eb29fa0ceb6d2e539a432",
|
|
41760
|
+
bsctestnet: "0x8004a818bfb912233c491871b3d84c89a494bd9e"
|
|
42104
41761
|
};
|
|
42105
41762
|
var erc8004 = defineContract({
|
|
42106
41763
|
id: "erc8004",
|
|
@@ -42496,6 +42153,29 @@ var ERC8183_POLICY_ABI = [
|
|
|
42496
42153
|
outputs: [],
|
|
42497
42154
|
stateMutability: "nonpayable"
|
|
42498
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
|
+
},
|
|
42499
42179
|
{
|
|
42500
42180
|
type: "function",
|
|
42501
42181
|
name: "disputed",
|
|
@@ -42547,13 +42227,16 @@ var ERC8183_POLICY_ABI = [
|
|
|
42547
42227
|
}
|
|
42548
42228
|
];
|
|
42549
42229
|
var ERC8183_COMMERCE_ADDRESSES = {
|
|
42550
|
-
bsc: "0xea4daa3100a767e86fded867729ae7446476eba6"
|
|
42230
|
+
bsc: "0xea4daa3100a767e86fded867729ae7446476eba6",
|
|
42231
|
+
bsctestnet: "0xa206c0517b6371c6638cd9e4a42cc9f02a33b0de"
|
|
42551
42232
|
};
|
|
42552
42233
|
var ERC8183_ROUTER_ADDRESSES = {
|
|
42553
|
-
bsc: "0x51895229e12f9876011789b04f8698af06ccd6da"
|
|
42234
|
+
bsc: "0x51895229e12f9876011789b04f8698af06ccd6da",
|
|
42235
|
+
bsctestnet: "0xd7d36d66d2f1b608a0f943f722d27e3744f66f25"
|
|
42554
42236
|
};
|
|
42555
42237
|
var ERC8183_POLICY_ADDRESSES = {
|
|
42556
|
-
bsc: "0x9c01845705b3078aa2e8cff7520a6376fd766de5"
|
|
42238
|
+
bsc: "0x9c01845705b3078aa2e8cff7520a6376fd766de5",
|
|
42239
|
+
bsctestnet: "0x4f4678d4439fec812ac7674bb3efb4c8f5fb78a6"
|
|
42557
42240
|
};
|
|
42558
42241
|
var erc8183Commerce = defineContract({
|
|
42559
42242
|
id: "erc8183-commerce",
|
|
@@ -42604,8 +42287,640 @@ function resolveErc8183Contracts(client, chainInput) {
|
|
|
42604
42287
|
};
|
|
42605
42288
|
}
|
|
42606
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
|
+
|
|
42607
42920
|
// ../swap/dist/index.mjs
|
|
42608
42921
|
init_dist();
|
|
42922
|
+
init_dist();
|
|
42923
|
+
init_dist();
|
|
42609
42924
|
var SwapClient = class {
|
|
42610
42925
|
constructor(httpClient) {
|
|
42611
42926
|
this.httpClient = httpClient;
|
|
@@ -42887,9 +43202,9 @@ var SwapExecutor = class {
|
|
|
42887
43202
|
);
|
|
42888
43203
|
const chainConfig = getChainById(params.fromChain);
|
|
42889
43204
|
const transactions = await withRetry(() => this.swapClient.getSwapTransactions(route));
|
|
42890
|
-
let
|
|
43205
|
+
let approvalHash;
|
|
42891
43206
|
try {
|
|
42892
|
-
|
|
43207
|
+
approvalHash = await this.ensureStepApproval(
|
|
42893
43208
|
route,
|
|
42894
43209
|
transactions,
|
|
42895
43210
|
chainConfig,
|
|
@@ -42897,10 +43212,10 @@ var SwapExecutor = class {
|
|
|
42897
43212
|
address,
|
|
42898
43213
|
parsedAmount
|
|
42899
43214
|
);
|
|
42900
|
-
if (
|
|
42901
|
-
await this.pollForConfirmation(params.fromChain, address,
|
|
43215
|
+
if (approvalHash) {
|
|
43216
|
+
await this.pollForConfirmation(params.fromChain, address, approvalHash, 6e4);
|
|
42902
43217
|
}
|
|
42903
|
-
let
|
|
43218
|
+
let hash = "";
|
|
42904
43219
|
for (const txData of transactions) {
|
|
42905
43220
|
const txType = txData.transaction.type;
|
|
42906
43221
|
const isApproval = txType === "approval" || txType === "revokeApproval";
|
|
@@ -42909,30 +43224,30 @@ var SwapExecutor = class {
|
|
|
42909
43224
|
txType === "revokeApproval" ? "Revoking prior approval..." : "Sending token approval..."
|
|
42910
43225
|
);
|
|
42911
43226
|
}
|
|
42912
|
-
|
|
42913
|
-
if (isApproval)
|
|
43227
|
+
hash = await this.sendTransaction(txData, chainConfig, params.fromChain);
|
|
43228
|
+
if (isApproval) approvalHash = hash;
|
|
42914
43229
|
this.log(
|
|
42915
|
-
`${isApproval ? "Approval" : "Swap"} tx: ${getExplorerTxUrl(params.fromChain,
|
|
43230
|
+
`${isApproval ? "Approval" : "Swap"} tx: ${getExplorerTxUrl(params.fromChain, hash)}`
|
|
42916
43231
|
);
|
|
42917
43232
|
await this.pollForConfirmation(
|
|
42918
43233
|
params.fromChain,
|
|
42919
43234
|
address,
|
|
42920
|
-
|
|
43235
|
+
hash,
|
|
42921
43236
|
isApproval ? 6e4 : 12e4
|
|
42922
43237
|
);
|
|
42923
43238
|
}
|
|
42924
43239
|
return {
|
|
42925
43240
|
success: true,
|
|
42926
|
-
|
|
43241
|
+
hash,
|
|
42927
43242
|
route,
|
|
42928
|
-
explorerUrl: getExplorerTxUrl(params.fromChain,
|
|
43243
|
+
explorerUrl: getExplorerTxUrl(params.fromChain, hash)
|
|
42929
43244
|
};
|
|
42930
43245
|
} catch (err) {
|
|
42931
43246
|
let msg = err instanceof Error ? err.message : "Unknown error";
|
|
42932
43247
|
let code2 = classifySwapError(msg);
|
|
42933
|
-
if (
|
|
43248
|
+
if (approvalHash) {
|
|
42934
43249
|
code2 = "APPROVAL_SENT_SWAP_FAILED";
|
|
42935
|
-
msg += `. Approval was sent (tx: ${
|
|
43250
|
+
msg += `. Approval was sent (tx: ${approvalHash}). Check allowance before retrying.`;
|
|
42936
43251
|
}
|
|
42937
43252
|
return { success: false, route, error: msg, code: code2 };
|
|
42938
43253
|
}
|
|
@@ -42964,8 +43279,8 @@ var SwapExecutor = class {
|
|
|
42964
43279
|
if (allowance >= required) return void 0;
|
|
42965
43280
|
this.log("Sending token approval...");
|
|
42966
43281
|
const approveResult = await blockchainClient.contract(erc20).withAddress(fromAssetAddr, fromChain).write.approve([stepApproval.operatorAddress, required], this.walletProvider);
|
|
42967
|
-
this.log(`Approval tx: ${getExplorerTxUrl(fromChain, approveResult.
|
|
42968
|
-
return approveResult.
|
|
43282
|
+
this.log(`Approval tx: ${getExplorerTxUrl(fromChain, approveResult.hash)}`);
|
|
43283
|
+
return approveResult.hash;
|
|
42969
43284
|
}
|
|
42970
43285
|
getBlockchainClient() {
|
|
42971
43286
|
const blockchainClient = this.walletProvider.getBlockchainClient?.() ?? this.options.blockchainClient;
|
|
@@ -43049,7 +43364,13 @@ function mapBroadcastError(err) {
|
|
|
43049
43364
|
throw err;
|
|
43050
43365
|
}
|
|
43051
43366
|
function registerTransferCommand(program3) {
|
|
43052
|
-
program3.command("transfer").description("Transfer tokens to an address").requiredOption("--to <address>", "Destination address or ENS name (e.g., vitalik.eth)").requiredOption("--amount <n>", "Amount to transfer in human-readable format (e.g., 1.5)").
|
|
43367
|
+
program3.command("transfer").description("Transfer tokens to an address").requiredOption("--to <address>", "Destination address or ENS name (e.g., vitalik.eth)").requiredOption("--amount <n>", "Amount to transfer in human-readable format (e.g., 1.5)").option(
|
|
43368
|
+
"--token <assetIdOrAddress>",
|
|
43369
|
+
"Without --chain: asset ID (e.g., c60, c60_t0xA0b8...). With --chain: a token contract address (omit for the native coin)."
|
|
43370
|
+
).option(
|
|
43371
|
+
"--chain <key>",
|
|
43372
|
+
"Chain key (e.g., base, ethereum). When set, --token is a token contract address; omit --token to send the native coin."
|
|
43373
|
+
).option(
|
|
43053
43374
|
"--decimals <n>",
|
|
43054
43375
|
"Token decimals (overrides auto-resolution for tokens not in the registry)"
|
|
43055
43376
|
).option(
|
|
@@ -43066,19 +43387,40 @@ function registerTransferCommand(program3) {
|
|
|
43066
43387
|
await ensureTrustSDK();
|
|
43067
43388
|
const password3 = await resolvePassword(opts);
|
|
43068
43389
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
43069
|
-
let
|
|
43390
|
+
let assetId;
|
|
43391
|
+
let chainKey;
|
|
43070
43392
|
let contractAddress;
|
|
43071
|
-
|
|
43072
|
-
(
|
|
43073
|
-
|
|
43074
|
-
|
|
43075
|
-
|
|
43076
|
-
|
|
43077
|
-
|
|
43078
|
-
|
|
43079
|
-
|
|
43080
|
-
|
|
43081
|
-
)
|
|
43393
|
+
if (opts.chain) {
|
|
43394
|
+
if (opts.token && /^c\d+(_t.+)?$/i.test(opts.token)) {
|
|
43395
|
+
throw new TransferError(
|
|
43396
|
+
"VALIDATION_ERROR",
|
|
43397
|
+
"Pass either --token <assetId> on its own, or --chain with --token <contractAddress> \u2014 not an asset ID together with --chain."
|
|
43398
|
+
);
|
|
43399
|
+
}
|
|
43400
|
+
({ chainKey, assetId } = resolveAsset(opts.chain, opts.token));
|
|
43401
|
+
contractAddress = opts.token;
|
|
43402
|
+
} else {
|
|
43403
|
+
if (!opts.token) {
|
|
43404
|
+
throw new TransferError(
|
|
43405
|
+
"VALIDATION_ERROR",
|
|
43406
|
+
"Provide --token <assetId>, or --chain <key> with an optional --token <contractAddress>."
|
|
43407
|
+
);
|
|
43408
|
+
}
|
|
43409
|
+
let coinId;
|
|
43410
|
+
try {
|
|
43411
|
+
({ coinId, contractAddress } = parseTokenId(opts.token));
|
|
43412
|
+
} catch {
|
|
43413
|
+
throw new TransferError("VALIDATION_ERROR", `Invalid token ID: ${opts.token}`);
|
|
43414
|
+
}
|
|
43415
|
+
const resolvedKey = coinTypeToChainKey(coinId);
|
|
43416
|
+
if (!resolvedKey) {
|
|
43417
|
+
throw new TransferError(
|
|
43418
|
+
"CHAIN_UNSUPPORTED",
|
|
43419
|
+
`Unsupported coin type in asset ID: ${opts.token}`
|
|
43420
|
+
);
|
|
43421
|
+
}
|
|
43422
|
+
assetId = opts.token;
|
|
43423
|
+
chainKey = resolvedKey;
|
|
43082
43424
|
}
|
|
43083
43425
|
let resolvedTo;
|
|
43084
43426
|
try {
|
|
@@ -43101,15 +43443,17 @@ function registerTransferCommand(program3) {
|
|
|
43101
43443
|
}
|
|
43102
43444
|
const httpClient = await getClient();
|
|
43103
43445
|
const swapClient = new SwapClient(httpClient);
|
|
43104
|
-
const tokenInfo = resolveToken(
|
|
43446
|
+
const tokenInfo = resolveToken(assetId, chainKey);
|
|
43105
43447
|
if (!tokenInfo) {
|
|
43106
43448
|
throw new TransferError(
|
|
43107
43449
|
"TOKEN_NOT_FOUND",
|
|
43108
|
-
`Unknown token: ${
|
|
43450
|
+
`Unknown token: ${assetId} on ${chainKey}. Use a contract address (0x...) or a supported symbol.`
|
|
43109
43451
|
);
|
|
43110
43452
|
}
|
|
43111
43453
|
const { decimals } = await resolveTokenDecimals(swapClient, chainKey, {
|
|
43112
|
-
|
|
43454
|
+
// assetId is always a string (never undefined in --chain native mode) and
|
|
43455
|
+
// is equivalent to opts.token for raw-address detection.
|
|
43456
|
+
token: assetId,
|
|
43113
43457
|
address: tokenInfo.address,
|
|
43114
43458
|
isNative: !contractAddress,
|
|
43115
43459
|
explicitDecimals: opts.decimals
|
|
@@ -43151,25 +43495,26 @@ function registerTransferCommand(program3) {
|
|
|
43151
43495
|
let result;
|
|
43152
43496
|
try {
|
|
43153
43497
|
result = await client.transfer({
|
|
43154
|
-
assetId
|
|
43498
|
+
assetId,
|
|
43155
43499
|
to: resolvedTo,
|
|
43156
43500
|
amount: opts.amount,
|
|
43157
43501
|
decimals,
|
|
43158
|
-
hdWallet
|
|
43502
|
+
hdWallet,
|
|
43503
|
+
chainKey
|
|
43159
43504
|
});
|
|
43160
43505
|
} catch (err) {
|
|
43161
43506
|
mapBroadcastError(err);
|
|
43162
43507
|
}
|
|
43163
|
-
const explorerUrl = getExplorerTxUrl(result.chainKey, result.
|
|
43508
|
+
const explorerUrl = getExplorerTxUrl(result.chainKey, result.hash);
|
|
43164
43509
|
success("Transfer sent!");
|
|
43165
43510
|
output(
|
|
43166
43511
|
{
|
|
43167
|
-
hash: result.
|
|
43512
|
+
hash: result.hash,
|
|
43168
43513
|
chain: result.chainKey,
|
|
43169
43514
|
from: address,
|
|
43170
43515
|
to: resolvedTo,
|
|
43171
43516
|
amount: opts.amount,
|
|
43172
|
-
token:
|
|
43517
|
+
token: assetId,
|
|
43173
43518
|
explorer: explorerUrl
|
|
43174
43519
|
},
|
|
43175
43520
|
opts.json
|
|
@@ -43381,7 +43726,7 @@ function registerSwapCommand(program3) {
|
|
|
43381
43726
|
output(
|
|
43382
43727
|
{
|
|
43383
43728
|
...quoteData,
|
|
43384
|
-
hash: result.
|
|
43729
|
+
hash: result.hash,
|
|
43385
43730
|
fromChain,
|
|
43386
43731
|
toChain,
|
|
43387
43732
|
explorer: result.explorerUrl
|
|
@@ -43401,9 +43746,41 @@ function registerSwapCommand(program3) {
|
|
|
43401
43746
|
// src/commands/erc20.ts
|
|
43402
43747
|
init_dist();
|
|
43403
43748
|
init_dist3();
|
|
43749
|
+
function resolveErc20WriteTarget(opts, nativeMsg) {
|
|
43750
|
+
if (opts.chain) {
|
|
43751
|
+
if (/^c\d+(_t.+)?$/i.test(opts.token)) {
|
|
43752
|
+
throw new Erc20Error(
|
|
43753
|
+
"VALIDATION_ERROR",
|
|
43754
|
+
"With --chain, pass --token as a token contract address (0x\u2026), not an asset ID."
|
|
43755
|
+
);
|
|
43756
|
+
}
|
|
43757
|
+
return { chainKey: resolveChain(opts.chain), contractAddress: opts.token };
|
|
43758
|
+
}
|
|
43759
|
+
let coinId;
|
|
43760
|
+
let contractAddress;
|
|
43761
|
+
try {
|
|
43762
|
+
({ coinId, contractAddress } = parseTokenId(opts.token));
|
|
43763
|
+
} catch {
|
|
43764
|
+
throw new Erc20Error("VALIDATION_ERROR", `Invalid token ID: ${opts.token}`);
|
|
43765
|
+
}
|
|
43766
|
+
if (!contractAddress) {
|
|
43767
|
+
throw new Erc20Error("NOT_ERC20", nativeMsg);
|
|
43768
|
+
}
|
|
43769
|
+
const chainKey = coinTypeToChainKey(coinId);
|
|
43770
|
+
if (!chainKey) {
|
|
43771
|
+
throw new Erc20Error("CHAIN_UNSUPPORTED", `Unsupported coin type in asset ID: ${opts.token}`);
|
|
43772
|
+
}
|
|
43773
|
+
return { chainKey, contractAddress };
|
|
43774
|
+
}
|
|
43404
43775
|
function registerErc20Command(program3) {
|
|
43405
43776
|
const erc202 = program3.command("erc20").description("ERC-20 token operations");
|
|
43406
|
-
erc202.command("approve").description("Approve a spender for token spending").requiredOption(
|
|
43777
|
+
erc202.command("approve").description("Approve a spender for token spending").requiredOption(
|
|
43778
|
+
"--token <assetIdOrAddress>",
|
|
43779
|
+
"Without --chain: asset ID (e.g., c60_t0xA0b8...). With --chain: the token contract address."
|
|
43780
|
+
).requiredOption("--spender <address>", "Spender address").requiredOption("--amount <n>", 'Amount to approve (in smallest unit, or "unlimited")').option(
|
|
43781
|
+
"--chain <key>",
|
|
43782
|
+
"Chain key (e.g., base). When set, --token is the token contract address."
|
|
43783
|
+
).option(
|
|
43407
43784
|
"--password <password>",
|
|
43408
43785
|
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
43409
43786
|
).option(
|
|
@@ -43414,26 +43791,10 @@ function registerErc20Command(program3) {
|
|
|
43414
43791
|
await ensureTrustSDK();
|
|
43415
43792
|
const password3 = await resolvePassword(opts);
|
|
43416
43793
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
43417
|
-
|
|
43418
|
-
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
} catch {
|
|
43422
|
-
throw new Erc20Error("VALIDATION_ERROR", `Invalid token ID: ${opts.token}`);
|
|
43423
|
-
}
|
|
43424
|
-
if (!contractAddress) {
|
|
43425
|
-
throw new Erc20Error(
|
|
43426
|
-
"NOT_ERC20",
|
|
43427
|
-
"Cannot approve native tokens. Provide an ERC-20 asset ID (e.g., c60_t0xA0b8...)"
|
|
43428
|
-
);
|
|
43429
|
-
}
|
|
43430
|
-
const chainKey = coinTypeToChainKey(coinId);
|
|
43431
|
-
if (!chainKey) {
|
|
43432
|
-
throw new Erc20Error(
|
|
43433
|
-
"CHAIN_UNSUPPORTED",
|
|
43434
|
-
`Unsupported coin type in asset ID: ${opts.token}`
|
|
43435
|
-
);
|
|
43436
|
-
}
|
|
43794
|
+
const { chainKey, contractAddress } = resolveErc20WriteTarget(
|
|
43795
|
+
opts,
|
|
43796
|
+
"Cannot approve native tokens. Provide an ERC-20 asset ID (e.g., c60_t0xA0b8...)"
|
|
43797
|
+
);
|
|
43437
43798
|
const address = await provider.getAddress(chainKey);
|
|
43438
43799
|
const amount = opts.amount === "unlimited" ? "115792089237316195423570985008687907853269984665640564039457584007913129639935" : opts.amount;
|
|
43439
43800
|
if (opts.amount === "unlimited") {
|
|
@@ -43448,11 +43809,11 @@ function registerErc20Command(program3) {
|
|
|
43448
43809
|
info(`Approving ${opts.spender} to spend from ${address} on ${chainKey}...`);
|
|
43449
43810
|
const client = provider.getBlockchainClient();
|
|
43450
43811
|
const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, BigInt(amount)], provider);
|
|
43451
|
-
const explorerUrl = getExplorerTxUrl(chainKey, pending.
|
|
43812
|
+
const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
|
|
43452
43813
|
success("Approval sent!");
|
|
43453
43814
|
output(
|
|
43454
43815
|
{
|
|
43455
|
-
hash: pending.
|
|
43816
|
+
hash: pending.hash,
|
|
43456
43817
|
chain: chainKey,
|
|
43457
43818
|
owner: address,
|
|
43458
43819
|
spender: opts.spender,
|
|
@@ -43467,7 +43828,13 @@ function registerErc20Command(program3) {
|
|
|
43467
43828
|
}
|
|
43468
43829
|
safeExit();
|
|
43469
43830
|
});
|
|
43470
|
-
erc202.command("revoke").description("Revoke token approval (set allowance to 0)").requiredOption(
|
|
43831
|
+
erc202.command("revoke").description("Revoke token approval (set allowance to 0)").requiredOption(
|
|
43832
|
+
"--token <assetIdOrAddress>",
|
|
43833
|
+
"Without --chain: asset ID (e.g., c60_t0xA0b8...). With --chain: the token contract address."
|
|
43834
|
+
).requiredOption("--spender <address>", "Spender address to revoke").option(
|
|
43835
|
+
"--chain <key>",
|
|
43836
|
+
"Chain key (e.g., base). When set, --token is the token contract address."
|
|
43837
|
+
).option(
|
|
43471
43838
|
"--password <password>",
|
|
43472
43839
|
"Wallet password (falls back to keychain / TWAK_WALLET_PASSWORD)"
|
|
43473
43840
|
).option("--json", "JSON output").action(async (opts) => {
|
|
@@ -43475,35 +43842,19 @@ function registerErc20Command(program3) {
|
|
|
43475
43842
|
await ensureTrustSDK();
|
|
43476
43843
|
const password3 = await resolvePassword(opts);
|
|
43477
43844
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
43478
|
-
|
|
43479
|
-
|
|
43480
|
-
|
|
43481
|
-
|
|
43482
|
-
} catch {
|
|
43483
|
-
throw new Erc20Error("VALIDATION_ERROR", `Invalid token ID: ${opts.token}`);
|
|
43484
|
-
}
|
|
43485
|
-
if (!contractAddress) {
|
|
43486
|
-
throw new Erc20Error(
|
|
43487
|
-
"NOT_ERC20",
|
|
43488
|
-
"Cannot revoke approval for native tokens. Provide an ERC-20 asset ID."
|
|
43489
|
-
);
|
|
43490
|
-
}
|
|
43491
|
-
const chainKey = coinTypeToChainKey(coinId);
|
|
43492
|
-
if (!chainKey) {
|
|
43493
|
-
throw new Erc20Error(
|
|
43494
|
-
"CHAIN_UNSUPPORTED",
|
|
43495
|
-
`Unsupported coin type in asset ID: ${opts.token}`
|
|
43496
|
-
);
|
|
43497
|
-
}
|
|
43845
|
+
const { chainKey, contractAddress } = resolveErc20WriteTarget(
|
|
43846
|
+
opts,
|
|
43847
|
+
"Cannot revoke approval for native tokens. Provide an ERC-20 asset ID."
|
|
43848
|
+
);
|
|
43498
43849
|
const address = await provider.getAddress(chainKey);
|
|
43499
43850
|
info(`Revoking approval for ${opts.spender} on ${chainKey}...`);
|
|
43500
43851
|
const client = provider.getBlockchainClient();
|
|
43501
43852
|
const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, 0n], provider);
|
|
43502
|
-
const explorerUrl = getExplorerTxUrl(chainKey, pending.
|
|
43853
|
+
const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
|
|
43503
43854
|
success("Approval revoked!");
|
|
43504
43855
|
output(
|
|
43505
43856
|
{
|
|
43506
|
-
hash: pending.
|
|
43857
|
+
hash: pending.hash,
|
|
43507
43858
|
chain: chainKey,
|
|
43508
43859
|
owner: address,
|
|
43509
43860
|
spender: opts.spender,
|
|
@@ -43517,44 +43868,65 @@ function registerErc20Command(program3) {
|
|
|
43517
43868
|
}
|
|
43518
43869
|
safeExit();
|
|
43519
43870
|
});
|
|
43520
|
-
erc202.command("allowance").description("Check token allowance").requiredOption(
|
|
43871
|
+
erc202.command("allowance").description("Check token allowance").requiredOption(
|
|
43872
|
+
"--token <assetIdOrAddress>",
|
|
43873
|
+
"Without --chain: asset ID (e.g., c60_t0xA0b8...). With --chain: the token contract address."
|
|
43874
|
+
).requiredOption("--owner <address>", "Owner address").requiredOption("--spender <address>", "Spender address").option(
|
|
43875
|
+
"--chain <key>",
|
|
43876
|
+
"Chain key (e.g., base). When set, --token is the token contract address."
|
|
43877
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
43521
43878
|
try {
|
|
43522
43879
|
await ensureTrustSDK();
|
|
43523
|
-
let coinId;
|
|
43524
43880
|
let contractAddress;
|
|
43525
|
-
|
|
43526
|
-
|
|
43527
|
-
|
|
43528
|
-
throw new Erc20Error(
|
|
43529
|
-
"VALIDATION_ERROR",
|
|
43530
|
-
err instanceof Error ? err.message : `Invalid token ID: ${opts.token}`
|
|
43531
|
-
);
|
|
43532
|
-
}
|
|
43533
|
-
if (!contractAddress) {
|
|
43534
|
-
throw new Erc20Error(
|
|
43535
|
-
"NOT_ERC20",
|
|
43536
|
-
`Not an ERC-20 asset ID (missing _t<address>): ${opts.token}`
|
|
43537
|
-
);
|
|
43538
|
-
}
|
|
43539
|
-
try {
|
|
43540
|
-
const { getWalletCore: getWalletCore2, getCoinType: getCoinType2 } = await Promise.resolve().then(() => (init_dist3(), dist_exports2));
|
|
43541
|
-
const wc3 = getWalletCore2();
|
|
43542
|
-
const ct5 = getCoinType2(coinId);
|
|
43543
|
-
if (ct5 && !wc3.CoinTypeExt.validate(ct5, contractAddress)) {
|
|
43881
|
+
let chainKey;
|
|
43882
|
+
if (opts.chain) {
|
|
43883
|
+
if (/^c\d+(_t.+)?$/i.test(opts.token)) {
|
|
43544
43884
|
throw new Erc20Error(
|
|
43545
43885
|
"VALIDATION_ERROR",
|
|
43546
|
-
|
|
43886
|
+
"With --chain, pass --token as a token contract address (0x\u2026), not an asset ID."
|
|
43547
43887
|
);
|
|
43548
43888
|
}
|
|
43549
|
-
|
|
43550
|
-
|
|
43551
|
-
}
|
|
43552
|
-
|
|
43553
|
-
|
|
43554
|
-
|
|
43555
|
-
|
|
43556
|
-
|
|
43557
|
-
|
|
43889
|
+
chainKey = resolveChain(opts.chain);
|
|
43890
|
+
contractAddress = opts.token;
|
|
43891
|
+
} else {
|
|
43892
|
+
let coinId;
|
|
43893
|
+
let parsed;
|
|
43894
|
+
try {
|
|
43895
|
+
({ coinId, contractAddress: parsed } = parseTokenId(opts.token));
|
|
43896
|
+
} catch (err) {
|
|
43897
|
+
throw new Erc20Error(
|
|
43898
|
+
"VALIDATION_ERROR",
|
|
43899
|
+
err instanceof Error ? err.message : `Invalid token ID: ${opts.token}`
|
|
43900
|
+
);
|
|
43901
|
+
}
|
|
43902
|
+
if (!parsed) {
|
|
43903
|
+
throw new Erc20Error(
|
|
43904
|
+
"NOT_ERC20",
|
|
43905
|
+
`Not an ERC-20 asset ID (missing _t<address>): ${opts.token}`
|
|
43906
|
+
);
|
|
43907
|
+
}
|
|
43908
|
+
try {
|
|
43909
|
+
const { getWalletCore: getWalletCore2, getCoinType: getCoinType2 } = await Promise.resolve().then(() => (init_dist3(), dist_exports2));
|
|
43910
|
+
const wc3 = getWalletCore2();
|
|
43911
|
+
const ct5 = getCoinType2(coinId);
|
|
43912
|
+
if (ct5 && !wc3.CoinTypeExt.validate(ct5, parsed)) {
|
|
43913
|
+
throw new Erc20Error(
|
|
43914
|
+
"VALIDATION_ERROR",
|
|
43915
|
+
`Invalid contract address in asset ID: ${parsed}`
|
|
43916
|
+
);
|
|
43917
|
+
}
|
|
43918
|
+
} catch (err) {
|
|
43919
|
+
if (err instanceof CommandError) throw err;
|
|
43920
|
+
}
|
|
43921
|
+
const k4 = coinTypeToChainKey(coinId);
|
|
43922
|
+
if (!k4) {
|
|
43923
|
+
throw new Erc20Error(
|
|
43924
|
+
"CHAIN_UNSUPPORTED",
|
|
43925
|
+
`Unsupported coin type in asset ID: ${opts.token}`
|
|
43926
|
+
);
|
|
43927
|
+
}
|
|
43928
|
+
contractAddress = parsed;
|
|
43929
|
+
chainKey = k4;
|
|
43558
43930
|
}
|
|
43559
43931
|
const client = new BlockchainClient();
|
|
43560
43932
|
const allowance = await client.contract(erc20).withAddress(contractAddress, chainKey).read.allowance([opts.owner, opts.spender]);
|
|
@@ -43583,11 +43955,29 @@ function parseAgentId(value) {
|
|
|
43583
43955
|
}
|
|
43584
43956
|
return BigInt(value);
|
|
43585
43957
|
}
|
|
43958
|
+
function collectKeyValue(value, previous) {
|
|
43959
|
+
previous.push(value);
|
|
43960
|
+
return previous;
|
|
43961
|
+
}
|
|
43962
|
+
function parseMetadataPairs(pairs) {
|
|
43963
|
+
return pairs.map((pair) => {
|
|
43964
|
+
const eq = pair.indexOf("=");
|
|
43965
|
+
if (eq <= 0) {
|
|
43966
|
+
throw new WalletError("VALIDATION_ERROR", `--metadata must be key=value (got "${pair}")`);
|
|
43967
|
+
}
|
|
43968
|
+
return [pair.slice(0, eq), hexOrUtf8ToBytesHex(pair.slice(eq + 1))];
|
|
43969
|
+
});
|
|
43970
|
+
}
|
|
43586
43971
|
function registerErc8004Command(program3) {
|
|
43587
43972
|
const erc8004Cmd = program3.command("erc8004").description("ERC-8004 Identity Registry \u2014 manage AI-agent identities");
|
|
43588
|
-
erc8004Cmd.command("register").description("Mint a new ERC-8004 agent identity (NFT)").requiredOption("--uri <url>", "Agent registration URI (https
|
|
43973
|
+
erc8004Cmd.command("register").description("Mint a new ERC-8004 agent identity (NFT)").requiredOption("--uri <url>", "Agent registration URI (https://, ipfs://, or data: inline)").option(
|
|
43974
|
+
"--metadata <key=value>",
|
|
43975
|
+
"Metadata entry to set atomically with the mint (repeatable). value is 0x-hex bytes or a UTF-8 string",
|
|
43976
|
+
collectKeyValue,
|
|
43977
|
+
[]
|
|
43978
|
+
).option(
|
|
43589
43979
|
"--chain <key>",
|
|
43590
|
-
"EVM chain key (
|
|
43980
|
+
"EVM chain key (`bsc` and `bsctestnet` have known deployments; set ERC8004_REGISTRY_ADDRESS for other EVM chains)",
|
|
43591
43981
|
"bsc"
|
|
43592
43982
|
).option(
|
|
43593
43983
|
"--password <password>",
|
|
@@ -43601,14 +43991,20 @@ function registerErc8004Command(program3) {
|
|
|
43601
43991
|
provider.getBlockchainClient(),
|
|
43602
43992
|
opts.chain
|
|
43603
43993
|
);
|
|
43604
|
-
|
|
43605
|
-
|
|
43994
|
+
const metadata = parseMetadataPairs(opts.metadata);
|
|
43995
|
+
info(
|
|
43996
|
+
`Minting agent on ${chainKey}${metadata.length > 0 ? ` with ${metadata.length} metadata entr${metadata.length === 1 ? "y" : "ies"}` : ""}...`
|
|
43997
|
+
);
|
|
43998
|
+
const pending = await contract.write.register(
|
|
43999
|
+
metadata.length > 0 ? [opts.uri, metadata] : [opts.uri],
|
|
44000
|
+
provider
|
|
44001
|
+
);
|
|
43606
44002
|
const confirmed = await pending.wait();
|
|
43607
44003
|
const registered = confirmed.events.Registered?.[0];
|
|
43608
44004
|
if (!registered) {
|
|
43609
44005
|
throw new WalletError(
|
|
43610
44006
|
"TX_FAILED",
|
|
43611
|
-
`No Registered event emitted (
|
|
44007
|
+
`No Registered event emitted (hash=${confirmed.hash})`
|
|
43612
44008
|
);
|
|
43613
44009
|
}
|
|
43614
44010
|
success("Agent registered!");
|
|
@@ -43617,9 +44013,10 @@ function registerErc8004Command(program3) {
|
|
|
43617
44013
|
agentId: registered.agentId.toString(),
|
|
43618
44014
|
owner: registered.owner,
|
|
43619
44015
|
agentURI: registered.agentURI,
|
|
43620
|
-
|
|
44016
|
+
...metadata.length > 0 ? { metadata: Object.fromEntries(metadata) } : {},
|
|
44017
|
+
hash: confirmed.hash,
|
|
43621
44018
|
chain: chainKey,
|
|
43622
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44019
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43623
44020
|
},
|
|
43624
44021
|
opts.json
|
|
43625
44022
|
);
|
|
@@ -43628,9 +44025,12 @@ function registerErc8004Command(program3) {
|
|
|
43628
44025
|
}
|
|
43629
44026
|
safeExit();
|
|
43630
44027
|
});
|
|
43631
|
-
erc8004Cmd.command("set-uri <agentId>").description("Update the agentURI of an existing identity").requiredOption(
|
|
44028
|
+
erc8004Cmd.command("set-uri <agentId>").description("Update the agentURI of an existing identity").requiredOption(
|
|
44029
|
+
"--uri <url>",
|
|
44030
|
+
"New agent registration URI (https://, ipfs://, or data: inline)"
|
|
44031
|
+
).option(
|
|
43632
44032
|
"--chain <key>",
|
|
43633
|
-
"EVM chain key (
|
|
44033
|
+
"EVM chain key (`bsc` and `bsctestnet` have known deployments; set ERC8004_REGISTRY_ADDRESS for other EVM chains)",
|
|
43634
44034
|
"bsc"
|
|
43635
44035
|
).option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (agentId, opts) => {
|
|
43636
44036
|
try {
|
|
@@ -43650,9 +44050,9 @@ function registerErc8004Command(program3) {
|
|
|
43650
44050
|
{
|
|
43651
44051
|
agentId,
|
|
43652
44052
|
agentURI: opts.uri,
|
|
43653
|
-
hash: confirmed.
|
|
44053
|
+
hash: confirmed.hash,
|
|
43654
44054
|
chain: chainKey,
|
|
43655
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44055
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43656
44056
|
},
|
|
43657
44057
|
opts.json
|
|
43658
44058
|
);
|
|
@@ -43663,7 +44063,7 @@ function registerErc8004Command(program3) {
|
|
|
43663
44063
|
});
|
|
43664
44064
|
erc8004Cmd.command("set-metadata <agentId>").description("Set a metadata entry on an identity (value can be 0x-hex or plain string)").requiredOption("--key <string>", "Metadata key").requiredOption("--value <hex|string>", "0x-hex bytes or plain string (UTF-8 encoded)").option(
|
|
43665
44065
|
"--chain <key>",
|
|
43666
|
-
"EVM chain key (
|
|
44066
|
+
"EVM chain key (`bsc` and `bsctestnet` have known deployments; set ERC8004_REGISTRY_ADDRESS for other EVM chains)",
|
|
43667
44067
|
"bsc"
|
|
43668
44068
|
).option("--password <password>", "Wallet password").option("--json", "JSON output").action(async (agentId, opts) => {
|
|
43669
44069
|
try {
|
|
@@ -43685,9 +44085,9 @@ function registerErc8004Command(program3) {
|
|
|
43685
44085
|
agentId,
|
|
43686
44086
|
key: opts.key,
|
|
43687
44087
|
value: valueBytes,
|
|
43688
|
-
hash: confirmed.
|
|
44088
|
+
hash: confirmed.hash,
|
|
43689
44089
|
chain: chainKey,
|
|
43690
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44090
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43691
44091
|
},
|
|
43692
44092
|
opts.json
|
|
43693
44093
|
);
|
|
@@ -43698,7 +44098,7 @@ function registerErc8004Command(program3) {
|
|
|
43698
44098
|
});
|
|
43699
44099
|
erc8004Cmd.command("get-metadata <agentId>").description("Read a metadata entry from an identity (returns raw bytes as 0x-hex)").requiredOption("--key <string>", "Metadata key").option(
|
|
43700
44100
|
"--chain <key>",
|
|
43701
|
-
"EVM chain key (
|
|
44101
|
+
"EVM chain key (`bsc` and `bsctestnet` have known deployments; set ERC8004_REGISTRY_ADDRESS for other EVM chains)",
|
|
43702
44102
|
"bsc"
|
|
43703
44103
|
).option("--json", "JSON output").action(async (agentId, opts) => {
|
|
43704
44104
|
try {
|
|
@@ -43714,7 +44114,7 @@ function registerErc8004Command(program3) {
|
|
|
43714
44114
|
});
|
|
43715
44115
|
erc8004Cmd.command("show <agentId>").description("Show on-chain state of an ERC-8004 agent identity").option(
|
|
43716
44116
|
"--chain <key>",
|
|
43717
|
-
"EVM chain key (
|
|
44117
|
+
"EVM chain key (`bsc` and `bsctestnet` have known deployments; set ERC8004_REGISTRY_ADDRESS for other EVM chains)",
|
|
43718
44118
|
"bsc"
|
|
43719
44119
|
).option("--json", "JSON output").action(async (agentId, opts) => {
|
|
43720
44120
|
try {
|
|
@@ -43746,7 +44146,9 @@ function registerErc8004Command(program3) {
|
|
|
43746
44146
|
// src/commands/erc8183.ts
|
|
43747
44147
|
init_dist();
|
|
43748
44148
|
init_dist3();
|
|
43749
|
-
var CHAIN_OPT = "EVM chain key (
|
|
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": "..."}`;
|
|
43750
44152
|
var ZERO_BYTES32 = `0x${"0".repeat(64)}`;
|
|
43751
44153
|
function parseUint(value, label) {
|
|
43752
44154
|
if (!/^\d+$/.test(value)) {
|
|
@@ -43757,6 +44159,16 @@ function parseUint(value, label) {
|
|
|
43757
44159
|
}
|
|
43758
44160
|
return BigInt(value);
|
|
43759
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
|
+
}
|
|
43760
44172
|
function registerErc8183Command(program3) {
|
|
43761
44173
|
const cmd = program3.command("erc8183").description("ERC-8183 Agentic Commerce \u2014 on-chain job escrows between AI agents");
|
|
43762
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) => {
|
|
@@ -43779,7 +44191,7 @@ function registerErc8183Command(program3) {
|
|
|
43779
44191
|
if (!created) {
|
|
43780
44192
|
throw new WalletError(
|
|
43781
44193
|
"TX_FAILED",
|
|
43782
|
-
`No JobCreated event emitted (
|
|
44194
|
+
`No JobCreated event emitted (hash=${confirmed.hash})`
|
|
43783
44195
|
);
|
|
43784
44196
|
}
|
|
43785
44197
|
success("Job created!");
|
|
@@ -43787,9 +44199,9 @@ function registerErc8183Command(program3) {
|
|
|
43787
44199
|
{
|
|
43788
44200
|
jobId: created.jobId.toString(),
|
|
43789
44201
|
status: "Open",
|
|
43790
|
-
hash: confirmed.
|
|
44202
|
+
hash: confirmed.hash,
|
|
43791
44203
|
chain: chainKey,
|
|
43792
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44204
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43793
44205
|
},
|
|
43794
44206
|
opts.json
|
|
43795
44207
|
);
|
|
@@ -43798,9 +44210,10 @@ function registerErc8183Command(program3) {
|
|
|
43798
44210
|
}
|
|
43799
44211
|
safeExit();
|
|
43800
44212
|
});
|
|
43801
|
-
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) => {
|
|
43802
44214
|
try {
|
|
43803
44215
|
const id = parseUint(jobId, "jobId");
|
|
44216
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43804
44217
|
await ensureTrustSDK();
|
|
43805
44218
|
const password3 = await resolvePassword(opts);
|
|
43806
44219
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -43809,16 +44222,16 @@ function registerErc8183Command(program3) {
|
|
|
43809
44222
|
opts.chain
|
|
43810
44223
|
);
|
|
43811
44224
|
info(`Setting provider for job ${jobId} on ${chainKey}...`);
|
|
43812
|
-
const pending = await commerce.write.setProvider([id, opts.provider,
|
|
44225
|
+
const pending = await commerce.write.setProvider([id, opts.provider, optParams], provider);
|
|
43813
44226
|
const confirmed = await pending.wait();
|
|
43814
44227
|
success("Provider set!");
|
|
43815
44228
|
output(
|
|
43816
44229
|
{
|
|
43817
44230
|
jobId,
|
|
43818
44231
|
provider: opts.provider,
|
|
43819
|
-
hash: confirmed.
|
|
44232
|
+
hash: confirmed.hash,
|
|
43820
44233
|
chain: chainKey,
|
|
43821
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44234
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43822
44235
|
},
|
|
43823
44236
|
opts.json
|
|
43824
44237
|
);
|
|
@@ -43827,10 +44240,11 @@ function registerErc8183Command(program3) {
|
|
|
43827
44240
|
}
|
|
43828
44241
|
safeExit();
|
|
43829
44242
|
});
|
|
43830
|
-
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) => {
|
|
43831
44244
|
try {
|
|
43832
44245
|
const id = parseUint(jobId, "jobId");
|
|
43833
44246
|
const amount = parseUint(opts.amount, "amount");
|
|
44247
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43834
44248
|
await ensureTrustSDK();
|
|
43835
44249
|
const password3 = await resolvePassword(opts);
|
|
43836
44250
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -43839,16 +44253,16 @@ function registerErc8183Command(program3) {
|
|
|
43839
44253
|
opts.chain
|
|
43840
44254
|
);
|
|
43841
44255
|
info(`Setting budget for job ${jobId} on ${chainKey}...`);
|
|
43842
|
-
const pending = await commerce.write.setBudget([id, amount,
|
|
44256
|
+
const pending = await commerce.write.setBudget([id, amount, optParams], provider);
|
|
43843
44257
|
const confirmed = await pending.wait();
|
|
43844
44258
|
success("Budget set!");
|
|
43845
44259
|
output(
|
|
43846
44260
|
{
|
|
43847
44261
|
jobId,
|
|
43848
44262
|
amount: opts.amount,
|
|
43849
|
-
hash: confirmed.
|
|
44263
|
+
hash: confirmed.hash,
|
|
43850
44264
|
chain: chainKey,
|
|
43851
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44265
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43852
44266
|
},
|
|
43853
44267
|
opts.json
|
|
43854
44268
|
);
|
|
@@ -43857,37 +44271,53 @@ function registerErc8183Command(program3) {
|
|
|
43857
44271
|
}
|
|
43858
44272
|
safeExit();
|
|
43859
44273
|
});
|
|
43860
|
-
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) => {
|
|
43861
44278
|
try {
|
|
43862
44279
|
const id = parseUint(jobId, "jobId");
|
|
44280
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43863
44281
|
await ensureTrustSDK();
|
|
43864
44282
|
const password3 = await resolvePassword(opts);
|
|
43865
44283
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
43866
44284
|
const client = provider.getBlockchainClient();
|
|
43867
44285
|
const { commerce, chainKey } = resolveErc8183Contracts(client, opts.chain);
|
|
43868
|
-
|
|
43869
|
-
if (
|
|
43870
|
-
|
|
43871
|
-
|
|
43872
|
-
|
|
43873
|
-
|
|
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;
|
|
43874
44304
|
}
|
|
43875
44305
|
const token = await commerce.read.paymentToken([]);
|
|
43876
|
-
info(`Approving ${
|
|
43877
|
-
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);
|
|
43878
44308
|
const approveConfirmed = await approvePending.wait();
|
|
43879
44309
|
info(`Funding job ${jobId}...`);
|
|
43880
|
-
const fundPending = await commerce.write.fund([id,
|
|
44310
|
+
const fundPending = await commerce.write.fund([id, budget, optParams], provider);
|
|
43881
44311
|
const fundConfirmed = await fundPending.wait();
|
|
43882
44312
|
success("Job funded!");
|
|
43883
44313
|
output(
|
|
43884
44314
|
{
|
|
43885
44315
|
jobId,
|
|
43886
44316
|
status: "Funded",
|
|
43887
|
-
approveHash: approveConfirmed.
|
|
43888
|
-
hash: fundConfirmed.
|
|
44317
|
+
approveHash: approveConfirmed.hash,
|
|
44318
|
+
hash: fundConfirmed.hash,
|
|
43889
44319
|
chain: chainKey,
|
|
43890
|
-
explorer: getExplorerTxUrl(chainKey, fundConfirmed.
|
|
44320
|
+
explorer: getExplorerTxUrl(chainKey, fundConfirmed.hash)
|
|
43891
44321
|
},
|
|
43892
44322
|
opts.json
|
|
43893
44323
|
);
|
|
@@ -43896,9 +44326,10 @@ function registerErc8183Command(program3) {
|
|
|
43896
44326
|
}
|
|
43897
44327
|
safeExit();
|
|
43898
44328
|
});
|
|
43899
|
-
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) => {
|
|
43900
44330
|
try {
|
|
43901
44331
|
const id = parseUint(jobId, "jobId");
|
|
44332
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43902
44333
|
await ensureTrustSDK();
|
|
43903
44334
|
const password3 = await resolvePassword(opts);
|
|
43904
44335
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -43907,16 +44338,16 @@ function registerErc8183Command(program3) {
|
|
|
43907
44338
|
opts.chain
|
|
43908
44339
|
);
|
|
43909
44340
|
info(`Submitting deliverable for job ${jobId} on ${chainKey}...`);
|
|
43910
|
-
const pending = await commerce.write.submit([id, opts.deliverable,
|
|
44341
|
+
const pending = await commerce.write.submit([id, opts.deliverable, optParams], provider);
|
|
43911
44342
|
const confirmed = await pending.wait();
|
|
43912
44343
|
success("Deliverable submitted!");
|
|
43913
44344
|
output(
|
|
43914
44345
|
{
|
|
43915
44346
|
jobId,
|
|
43916
44347
|
status: "Submitted",
|
|
43917
|
-
hash: confirmed.
|
|
44348
|
+
hash: confirmed.hash,
|
|
43918
44349
|
chain: chainKey,
|
|
43919
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44350
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43920
44351
|
},
|
|
43921
44352
|
opts.json
|
|
43922
44353
|
);
|
|
@@ -43925,9 +44356,10 @@ function registerErc8183Command(program3) {
|
|
|
43925
44356
|
}
|
|
43926
44357
|
safeExit();
|
|
43927
44358
|
});
|
|
43928
|
-
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) => {
|
|
43929
44360
|
try {
|
|
43930
44361
|
const id = parseUint(jobId, "jobId");
|
|
44362
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43931
44363
|
await ensureTrustSDK();
|
|
43932
44364
|
const password3 = await resolvePassword(opts);
|
|
43933
44365
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -43937,7 +44369,7 @@ function registerErc8183Command(program3) {
|
|
|
43937
44369
|
);
|
|
43938
44370
|
info(`Completing job ${jobId} on ${chainKey}...`);
|
|
43939
44371
|
const pending = await commerce.write.complete(
|
|
43940
|
-
[id, opts.reason ?? ZERO_BYTES32,
|
|
44372
|
+
[id, opts.reason ?? ZERO_BYTES32, optParams],
|
|
43941
44373
|
provider
|
|
43942
44374
|
);
|
|
43943
44375
|
const confirmed = await pending.wait();
|
|
@@ -43948,9 +44380,9 @@ function registerErc8183Command(program3) {
|
|
|
43948
44380
|
jobId,
|
|
43949
44381
|
status: "Completed",
|
|
43950
44382
|
released: released ? released.amount.toString() : null,
|
|
43951
|
-
hash: confirmed.
|
|
44383
|
+
hash: confirmed.hash,
|
|
43952
44384
|
chain: chainKey,
|
|
43953
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44385
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43954
44386
|
},
|
|
43955
44387
|
opts.json
|
|
43956
44388
|
);
|
|
@@ -43959,9 +44391,10 @@ function registerErc8183Command(program3) {
|
|
|
43959
44391
|
}
|
|
43960
44392
|
safeExit();
|
|
43961
44393
|
});
|
|
43962
|
-
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) => {
|
|
43963
44395
|
try {
|
|
43964
44396
|
const id = parseUint(jobId, "jobId");
|
|
44397
|
+
const optParams = parseOptParams(opts.optParams);
|
|
43965
44398
|
await ensureTrustSDK();
|
|
43966
44399
|
const password3 = await resolvePassword(opts);
|
|
43967
44400
|
const provider = await AgentWalletProvider.fromStorage(password3);
|
|
@@ -43971,7 +44404,7 @@ function registerErc8183Command(program3) {
|
|
|
43971
44404
|
);
|
|
43972
44405
|
info(`Rejecting job ${jobId} on ${chainKey}...`);
|
|
43973
44406
|
const pending = await commerce.write.reject(
|
|
43974
|
-
[id, opts.reason ?? ZERO_BYTES32,
|
|
44407
|
+
[id, opts.reason ?? ZERO_BYTES32, optParams],
|
|
43975
44408
|
provider
|
|
43976
44409
|
);
|
|
43977
44410
|
const confirmed = await pending.wait();
|
|
@@ -43982,9 +44415,9 @@ function registerErc8183Command(program3) {
|
|
|
43982
44415
|
jobId,
|
|
43983
44416
|
status: "Rejected",
|
|
43984
44417
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
43985
|
-
hash: confirmed.
|
|
44418
|
+
hash: confirmed.hash,
|
|
43986
44419
|
chain: chainKey,
|
|
43987
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44420
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
43988
44421
|
},
|
|
43989
44422
|
opts.json
|
|
43990
44423
|
);
|
|
@@ -44013,9 +44446,9 @@ function registerErc8183Command(program3) {
|
|
|
44013
44446
|
jobId,
|
|
44014
44447
|
status: "Expired",
|
|
44015
44448
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
44016
|
-
hash: confirmed.
|
|
44449
|
+
hash: confirmed.hash,
|
|
44017
44450
|
chain: chainKey,
|
|
44018
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44451
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44019
44452
|
},
|
|
44020
44453
|
opts.json
|
|
44021
44454
|
);
|
|
@@ -44075,9 +44508,9 @@ function registerErc8183Command(program3) {
|
|
|
44075
44508
|
{
|
|
44076
44509
|
jobId,
|
|
44077
44510
|
policy: policyAddr,
|
|
44078
|
-
hash: confirmed.
|
|
44511
|
+
hash: confirmed.hash,
|
|
44079
44512
|
chain: chainKey,
|
|
44080
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44513
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44081
44514
|
},
|
|
44082
44515
|
opts.json
|
|
44083
44516
|
);
|
|
@@ -44103,9 +44536,9 @@ function registerErc8183Command(program3) {
|
|
|
44103
44536
|
output(
|
|
44104
44537
|
{
|
|
44105
44538
|
jobId,
|
|
44106
|
-
hash: confirmed.
|
|
44539
|
+
hash: confirmed.hash,
|
|
44107
44540
|
chain: chainKey,
|
|
44108
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44541
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44109
44542
|
},
|
|
44110
44543
|
opts.json
|
|
44111
44544
|
);
|
|
@@ -44132,9 +44565,9 @@ function registerErc8183Command(program3) {
|
|
|
44132
44565
|
{
|
|
44133
44566
|
jobId,
|
|
44134
44567
|
status: "Expired",
|
|
44135
|
-
hash: confirmed.
|
|
44568
|
+
hash: confirmed.hash,
|
|
44136
44569
|
chain: chainKey,
|
|
44137
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44570
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44138
44571
|
},
|
|
44139
44572
|
opts.json
|
|
44140
44573
|
);
|
|
@@ -44143,6 +44576,45 @@ function registerErc8183Command(program3) {
|
|
|
44143
44576
|
}
|
|
44144
44577
|
safeExit();
|
|
44145
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
|
+
});
|
|
44146
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) => {
|
|
44147
44619
|
try {
|
|
44148
44620
|
const id = parseUint(jobId, "jobId");
|
|
@@ -44160,9 +44632,9 @@ function registerErc8183Command(program3) {
|
|
|
44160
44632
|
output(
|
|
44161
44633
|
{
|
|
44162
44634
|
jobId,
|
|
44163
|
-
hash: confirmed.
|
|
44635
|
+
hash: confirmed.hash,
|
|
44164
44636
|
chain: chainKey,
|
|
44165
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44637
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44166
44638
|
},
|
|
44167
44639
|
opts.json
|
|
44168
44640
|
);
|
|
@@ -44188,9 +44660,9 @@ function registerErc8183Command(program3) {
|
|
|
44188
44660
|
output(
|
|
44189
44661
|
{
|
|
44190
44662
|
jobId,
|
|
44191
|
-
hash: confirmed.
|
|
44663
|
+
hash: confirmed.hash,
|
|
44192
44664
|
chain: chainKey,
|
|
44193
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44665
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44194
44666
|
},
|
|
44195
44667
|
opts.json
|
|
44196
44668
|
);
|
|
@@ -44256,7 +44728,7 @@ function registerCompeteCommand(program3) {
|
|
|
44256
44728
|
if (!confirmed.events.Registered?.[0]) {
|
|
44257
44729
|
throw new WalletError(
|
|
44258
44730
|
"TX_FAILED",
|
|
44259
|
-
`no Registered event emitted (
|
|
44731
|
+
`no Registered event emitted (hash=${confirmed.hash})`
|
|
44260
44732
|
);
|
|
44261
44733
|
}
|
|
44262
44734
|
success("Registered for BNB HACK: AI TRADING AGENT EDITION!");
|
|
@@ -44265,9 +44737,9 @@ function registerCompeteCommand(program3) {
|
|
|
44265
44737
|
registered: true,
|
|
44266
44738
|
participant,
|
|
44267
44739
|
deadline: toIso(deadline),
|
|
44268
|
-
hash: confirmed.
|
|
44740
|
+
hash: confirmed.hash,
|
|
44269
44741
|
chain: chainKey,
|
|
44270
|
-
explorer: getExplorerTxUrl(chainKey, confirmed.
|
|
44742
|
+
explorer: getExplorerTxUrl(chainKey, confirmed.hash)
|
|
44271
44743
|
},
|
|
44272
44744
|
opts.json
|
|
44273
44745
|
);
|
|
@@ -45945,15 +46417,15 @@ async function ensurePermit2Allowance(args) {
|
|
|
45945
46417
|
[PERMIT2_ADDRESS, BigInt(MAX_UINT256_DECIMAL)],
|
|
45946
46418
|
args.walletProvider
|
|
45947
46419
|
);
|
|
45948
|
-
await waitForTxConfirmation(args.blockchainClient, args.chainKey, args.owner, pending.
|
|
45949
|
-
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 };
|
|
45950
46422
|
}
|
|
45951
46423
|
var APPROVE_TIMEOUT_MS = 6e4;
|
|
45952
46424
|
var APPROVE_POLL_MS = 2e3;
|
|
45953
|
-
async function waitForTxConfirmation(bc2, chainKey, address,
|
|
46425
|
+
async function waitForTxConfirmation(bc2, chainKey, address, hash) {
|
|
45954
46426
|
const start = Date.now();
|
|
45955
46427
|
while (Date.now() - start < APPROVE_TIMEOUT_MS) {
|
|
45956
|
-
const status = await bc2.findTransactionStatus(chainKey, address,
|
|
46428
|
+
const status = await bc2.findTransactionStatus(chainKey, address, hash);
|
|
45957
46429
|
if (status.confirmed) return;
|
|
45958
46430
|
if (status.failed) {
|
|
45959
46431
|
throw new X402Error(
|
|
@@ -45965,7 +46437,7 @@ async function waitForTxConfirmation(bc2, chainKey, address, txHash) {
|
|
|
45965
46437
|
}
|
|
45966
46438
|
throw new X402Error(
|
|
45967
46439
|
"TX_FAILED",
|
|
45968
|
-
`Permit2 approval ${
|
|
46440
|
+
`Permit2 approval ${hash} not confirmed within ${APPROVE_TIMEOUT_MS / 1e3}s`
|
|
45969
46441
|
);
|
|
45970
46442
|
}
|
|
45971
46443
|
function ipv4MappedToDotted(ip) {
|
|
@@ -46482,7 +46954,7 @@ var TransferActionProvider = class extends ActionProvider {
|
|
|
46482
46954
|
const resolvedTo = await resolveAddressOrName(input2.to);
|
|
46483
46955
|
const atomicAmount = parseAmount(input2.amount, decimals);
|
|
46484
46956
|
const isErc20 = Boolean(tokenAddress);
|
|
46485
|
-
let
|
|
46957
|
+
let hash;
|
|
46486
46958
|
if (isErc20) {
|
|
46487
46959
|
if (!this.blockchainClient) {
|
|
46488
46960
|
throw new TransferError(
|
|
@@ -46491,19 +46963,19 @@ var TransferActionProvider = class extends ActionProvider {
|
|
|
46491
46963
|
);
|
|
46492
46964
|
}
|
|
46493
46965
|
const pending = await this.blockchainClient.contract(erc20).withAddress(tokenAddress, chainKey).write.transfer([resolvedTo, BigInt(atomicAmount)], signer);
|
|
46494
|
-
|
|
46966
|
+
hash = pending.hash;
|
|
46495
46967
|
} else {
|
|
46496
|
-
|
|
46968
|
+
hash = await signer.sendTransaction({
|
|
46497
46969
|
chainId: caip2,
|
|
46498
46970
|
to: resolvedTo,
|
|
46499
46971
|
data: "0x",
|
|
46500
46972
|
value: "0x" + BigInt(atomicAmount).toString(16)
|
|
46501
46973
|
});
|
|
46502
46974
|
}
|
|
46503
|
-
const explorerUrl = getExplorerTxUrl(chainKey,
|
|
46975
|
+
const explorerUrl = getExplorerTxUrl(chainKey, hash);
|
|
46504
46976
|
return {
|
|
46505
46977
|
success: true,
|
|
46506
|
-
|
|
46978
|
+
hash,
|
|
46507
46979
|
to: resolvedTo,
|
|
46508
46980
|
resolvedFrom: input2.to !== resolvedTo ? input2.to : void 0,
|
|
46509
46981
|
explorer: explorerUrl || void 0
|
|
@@ -46588,7 +47060,7 @@ var SwapActionProvider = class extends ActionProvider {
|
|
|
46588
47060
|
const outputAmt = formatAmount(lastStep.to.amount, lastStep.to.asset.metadata.decimals);
|
|
46589
47061
|
return {
|
|
46590
47062
|
success: true,
|
|
46591
|
-
|
|
47063
|
+
hash: result.hash,
|
|
46592
47064
|
summary: `${inputAmt} ${firstStep.from.asset.metadata.symbol} -> ${outputAmt} ${lastStep.to.asset.metadata.symbol}`,
|
|
46593
47065
|
provider: result.route.steps.map((s2) => s2.provider.name).join(" -> "),
|
|
46594
47066
|
explorer: result.explorerUrl || void 0
|
|
@@ -46970,7 +47442,7 @@ var AgentWalletActionProvider = class extends ActionProvider {
|
|
|
46970
47442
|
if (!this.blockchainClient) {
|
|
46971
47443
|
return { chain: chainKey, address, balance: "BlockchainClient not available" };
|
|
46972
47444
|
}
|
|
46973
|
-
const balance = await this.blockchainClient.getBalance(assetId, address);
|
|
47445
|
+
const balance = await this.blockchainClient.getBalance(assetId, address, chainKey);
|
|
46974
47446
|
return { chain: chainKey, address, balance };
|
|
46975
47447
|
}
|
|
46976
47448
|
};
|
|
@@ -47007,7 +47479,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47007
47479
|
throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
|
|
47008
47480
|
}
|
|
47009
47481
|
const { chainKey, assetId } = resolveAsset(input2.chain, input2.tokenAddress);
|
|
47010
|
-
const balance = await this.blockchainClient.getBalance(assetId, input2.address);
|
|
47482
|
+
const balance = await this.blockchainClient.getBalance(assetId, input2.address, chainKey);
|
|
47011
47483
|
return { chain: chainKey, address: input2.address, balance };
|
|
47012
47484
|
}
|
|
47013
47485
|
};
|
|
@@ -47047,9 +47519,10 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47047
47519
|
amount: input2.amount,
|
|
47048
47520
|
decimals,
|
|
47049
47521
|
memo: input2.memo,
|
|
47050
|
-
hdWallet
|
|
47522
|
+
hdWallet,
|
|
47523
|
+
chainKey
|
|
47051
47524
|
});
|
|
47052
|
-
return { hash: result.
|
|
47525
|
+
return { hash: result.hash, chain: result.chainKey };
|
|
47053
47526
|
}
|
|
47054
47527
|
const chain2 = requireChain(chainKey);
|
|
47055
47528
|
if (chain2.namespace !== "eip155") {
|
|
@@ -47061,24 +47534,24 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47061
47534
|
if (input2.tokenAddress) assertEvmAddress(input2.tokenAddress, "tokenAddress");
|
|
47062
47535
|
const caipChainId = `${chain2.namespace}:${chain2.chainId}`;
|
|
47063
47536
|
const atomicAmount = parseAmount(input2.amount, decimals);
|
|
47064
|
-
let
|
|
47537
|
+
let hash;
|
|
47065
47538
|
if (input2.tokenAddress) {
|
|
47066
47539
|
if (!this.blockchainClient) {
|
|
47067
47540
|
throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
|
|
47068
47541
|
}
|
|
47069
47542
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.transfer([input2.to, BigInt(atomicAmount)], wallet);
|
|
47070
|
-
|
|
47543
|
+
hash = pending.hash;
|
|
47071
47544
|
} else {
|
|
47072
47545
|
assertEvmAddress(input2.to, "to");
|
|
47073
47546
|
const valueHex = "0x" + BigInt(atomicAmount).toString(16);
|
|
47074
|
-
|
|
47547
|
+
hash = await wallet.sendTransaction({
|
|
47075
47548
|
chainId: caipChainId,
|
|
47076
47549
|
to: input2.to,
|
|
47077
47550
|
data: "0x",
|
|
47078
47551
|
value: valueHex
|
|
47079
47552
|
});
|
|
47080
47553
|
}
|
|
47081
|
-
return { hash
|
|
47554
|
+
return { hash, chain: chainKey };
|
|
47082
47555
|
}
|
|
47083
47556
|
};
|
|
47084
47557
|
}
|
|
@@ -47109,7 +47582,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47109
47582
|
}
|
|
47110
47583
|
const amount = input2.amount === "unlimited" ? "115792089237316195423570985008687907853269984665640564039457584007913129639935" : input2.amount;
|
|
47111
47584
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, BigInt(amount)], wallet);
|
|
47112
|
-
return { hash: pending.
|
|
47585
|
+
return { hash: pending.hash, chain: chainKey };
|
|
47113
47586
|
}
|
|
47114
47587
|
};
|
|
47115
47588
|
}
|
|
@@ -47138,7 +47611,7 @@ var TokenActionProvider = class extends ActionProvider {
|
|
|
47138
47611
|
throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
|
|
47139
47612
|
}
|
|
47140
47613
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, 0n], wallet);
|
|
47141
|
-
return { hash: pending.
|
|
47614
|
+
return { hash: pending.hash, chain: chainKey };
|
|
47142
47615
|
}
|
|
47143
47616
|
};
|
|
47144
47617
|
}
|
|
@@ -47608,7 +48081,7 @@ var OnrampActionProvider = class extends ActionProvider {
|
|
|
47608
48081
|
if (cap) return { success: false, ...cap };
|
|
47609
48082
|
}
|
|
47610
48083
|
const atomic = parseAmount(input2.cryptoAmount, decimals);
|
|
47611
|
-
let
|
|
48084
|
+
let hash;
|
|
47612
48085
|
if (input2.tokenAddress) {
|
|
47613
48086
|
if (!this.blockchainClient) {
|
|
47614
48087
|
throw new TransferError(
|
|
@@ -47617,19 +48090,19 @@ var OnrampActionProvider = class extends ActionProvider {
|
|
|
47617
48090
|
);
|
|
47618
48091
|
}
|
|
47619
48092
|
const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.transfer([input2.depositAddress, BigInt(atomic)], signer);
|
|
47620
|
-
|
|
48093
|
+
hash = pending.hash;
|
|
47621
48094
|
} else {
|
|
47622
|
-
|
|
48095
|
+
hash = await signer.sendTransaction({
|
|
47623
48096
|
chainId: caip2,
|
|
47624
48097
|
to: input2.depositAddress,
|
|
47625
48098
|
data: "0x",
|
|
47626
48099
|
value: "0x" + BigInt(atomic).toString(16)
|
|
47627
48100
|
});
|
|
47628
48101
|
}
|
|
47629
|
-
const explorerUrl = getExplorerTxUrl(chainKey,
|
|
48102
|
+
const explorerUrl = getExplorerTxUrl(chainKey, hash) || void 0;
|
|
47630
48103
|
return {
|
|
47631
48104
|
success: true,
|
|
47632
|
-
|
|
48105
|
+
hash,
|
|
47633
48106
|
chain: chainKey,
|
|
47634
48107
|
tokenAddress: input2.tokenAddress,
|
|
47635
48108
|
to: input2.depositAddress,
|
|
@@ -47799,7 +48272,7 @@ var AutomateActionProvider = class extends ActionProvider {
|
|
|
47799
48272
|
await this.automationStore.update(record2.id, { lastRunAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
47800
48273
|
return {
|
|
47801
48274
|
success: true,
|
|
47802
|
-
|
|
48275
|
+
hash: result.hash,
|
|
47803
48276
|
automationId: record2.id,
|
|
47804
48277
|
swapped: `${record2.amount} ${record2.fromToken} \u2192 ${record2.toToken}`,
|
|
47805
48278
|
explorer: result.explorerUrl || void 0
|
|
@@ -47991,17 +48464,23 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
47991
48464
|
register() {
|
|
47992
48465
|
return {
|
|
47993
48466
|
name: "erc8004_register",
|
|
47994
|
-
description: "Mint a new ERC-8004 agent identity on-chain. The caller becomes the owner of an NFT token whose ID is the agentId. The supplied agentURI is stored on-chain as the token URI and should point to the agent registration JSON (https or
|
|
48467
|
+
description: "Mint a new ERC-8004 agent identity on-chain. The caller becomes the owner of an NFT token whose ID is the agentId. The supplied agentURI is stored on-chain as the token URI and should point to the agent registration JSON (https, ipfs, or a data: inline). Optionally pass metadata entries to set them atomically in the same mint transaction.",
|
|
47995
48468
|
schema: import_zod16.z.object({
|
|
47996
48469
|
agentURI: import_zod16.z.string().min(1).describe(
|
|
47997
|
-
"URI of the agent registration file (https
|
|
48470
|
+
"URI of the agent registration file (https://, ipfs://, or data: inline). Stored on-chain as the token URI."
|
|
48471
|
+
),
|
|
48472
|
+
metadata: import_zod16.z.record(import_zod16.z.string().min(1), import_zod16.z.string().min(1)).optional().describe(
|
|
48473
|
+
"Optional metadata entries (key \u2192 value) to set atomically in the mint transaction. Each value: `0x`-prefixed hex is sent as raw bytes; any other string is UTF-8 encoded."
|
|
47998
48474
|
),
|
|
47999
48475
|
chain: import_zod16.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48000
48476
|
}),
|
|
48001
48477
|
invoke: async (_ctx, input2) => {
|
|
48002
48478
|
const { contract, chainKey } = this.bind(input2.chain);
|
|
48479
|
+
const entries = Object.entries(input2.metadata ?? {}).map(
|
|
48480
|
+
([key, value]) => [key, hexOrUtf8ToBytesHex(value)]
|
|
48481
|
+
);
|
|
48003
48482
|
const pending = await contract.write.register(
|
|
48004
|
-
[input2.agentURI],
|
|
48483
|
+
entries.length > 0 ? [input2.agentURI, entries] : [input2.agentURI],
|
|
48005
48484
|
this.walletContext.activeWallet()
|
|
48006
48485
|
);
|
|
48007
48486
|
const confirmed = await pending.wait();
|
|
@@ -48009,15 +48488,16 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48009
48488
|
if (!registered) {
|
|
48010
48489
|
throw new WalletError(
|
|
48011
48490
|
"TX_FAILED",
|
|
48012
|
-
`erc8004_register: no Registered event emitted (
|
|
48491
|
+
`erc8004_register: no Registered event emitted (hash=${confirmed.hash})`
|
|
48013
48492
|
);
|
|
48014
48493
|
}
|
|
48015
48494
|
return {
|
|
48016
48495
|
success: true,
|
|
48017
48496
|
agentId: registered.agentId.toString(),
|
|
48018
|
-
|
|
48497
|
+
hash: confirmed.hash,
|
|
48019
48498
|
owner: registered.owner,
|
|
48020
48499
|
agentURI: registered.agentURI,
|
|
48500
|
+
...entries.length > 0 ? { metadata: Object.fromEntries(entries) } : {},
|
|
48021
48501
|
chain: chainKey
|
|
48022
48502
|
};
|
|
48023
48503
|
}
|
|
@@ -48029,7 +48509,9 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48029
48509
|
description: "Update the agentURI of an existing ERC-8004 agent identity. Caller must own the NFT.",
|
|
48030
48510
|
schema: import_zod16.z.object({
|
|
48031
48511
|
agentId: agentIdSchema,
|
|
48032
|
-
agentURI: import_zod16.z.string().min(1).describe(
|
|
48512
|
+
agentURI: import_zod16.z.string().min(1).describe(
|
|
48513
|
+
"New agent URI (https://, ipfs://, or data: inline). Replaces the on-chain stored URI."
|
|
48514
|
+
),
|
|
48033
48515
|
chain: import_zod16.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48034
48516
|
}),
|
|
48035
48517
|
invoke: async (_ctx, input2) => {
|
|
@@ -48039,7 +48521,7 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48039
48521
|
this.walletContext.activeWallet()
|
|
48040
48522
|
);
|
|
48041
48523
|
const confirmed = await pending.wait();
|
|
48042
|
-
return { success: true,
|
|
48524
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48043
48525
|
}
|
|
48044
48526
|
};
|
|
48045
48527
|
}
|
|
@@ -48063,7 +48545,7 @@ var Erc8004ActionProvider = class extends ActionProvider {
|
|
|
48063
48545
|
this.walletContext.activeWallet()
|
|
48064
48546
|
);
|
|
48065
48547
|
const confirmed = await pending.wait();
|
|
48066
|
-
return { success: true,
|
|
48548
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48067
48549
|
}
|
|
48068
48550
|
};
|
|
48069
48551
|
}
|
|
@@ -48129,6 +48611,7 @@ var jobIdSchema = import_zod17.z.string().regex(/^\d+$/, "jobId must be a decima
|
|
|
48129
48611
|
var amountSchema = import_zod17.z.string().regex(/^\d+$/, "amount must be an atomic (base-unit) integer string.");
|
|
48130
48612
|
var evmAddressSchema = import_zod17.z.string().refine(isEvmAddress, "must be a 0x-prefixed 40-hex EVM address.");
|
|
48131
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).");
|
|
48132
48615
|
var ZERO_BYTES322 = `0x${"0".repeat(64)}`;
|
|
48133
48616
|
var Erc8183ActionProvider = class extends ActionProvider {
|
|
48134
48617
|
constructor(blockchainClient, walletContext) {
|
|
@@ -48149,6 +48632,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48149
48632
|
this.reject(),
|
|
48150
48633
|
this.claimRefund(),
|
|
48151
48634
|
this.status(),
|
|
48635
|
+
this.policyInfo(),
|
|
48152
48636
|
this.registerJob(),
|
|
48153
48637
|
this.settle(),
|
|
48154
48638
|
this.markExpired(),
|
|
@@ -48190,13 +48674,13 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48190
48674
|
if (!created) {
|
|
48191
48675
|
throw new WalletError(
|
|
48192
48676
|
"TX_FAILED",
|
|
48193
|
-
`erc8183_create_job: no JobCreated event emitted (
|
|
48677
|
+
`erc8183_create_job: no JobCreated event emitted (hash=${confirmed.hash})`
|
|
48194
48678
|
);
|
|
48195
48679
|
}
|
|
48196
48680
|
return {
|
|
48197
48681
|
success: true,
|
|
48198
48682
|
jobId: created.jobId.toString(),
|
|
48199
|
-
|
|
48683
|
+
hash: confirmed.hash,
|
|
48200
48684
|
status: "Open",
|
|
48201
48685
|
chain: chainKey
|
|
48202
48686
|
};
|
|
@@ -48210,16 +48694,17 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48210
48694
|
schema: import_zod17.z.object({
|
|
48211
48695
|
jobId: jobIdSchema,
|
|
48212
48696
|
provider: evmAddressSchema.describe("New provider (worker) address."),
|
|
48697
|
+
optParams: optParamsSchema,
|
|
48213
48698
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48214
48699
|
}),
|
|
48215
48700
|
invoke: async (_ctx, input2) => {
|
|
48216
48701
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48217
48702
|
const pending = await commerce.write.setProvider(
|
|
48218
|
-
[BigInt(input2.jobId), input2.provider, "0x"],
|
|
48703
|
+
[BigInt(input2.jobId), input2.provider, input2.optParams ?? "0x"],
|
|
48219
48704
|
this.walletContext.activeWallet()
|
|
48220
48705
|
);
|
|
48221
48706
|
const confirmed = await pending.wait();
|
|
48222
|
-
return { success: true,
|
|
48707
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48223
48708
|
}
|
|
48224
48709
|
};
|
|
48225
48710
|
}
|
|
@@ -48230,47 +48715,64 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48230
48715
|
schema: import_zod17.z.object({
|
|
48231
48716
|
jobId: jobIdSchema,
|
|
48232
48717
|
amount: amountSchema.describe("Budget in atomic units of the payment token."),
|
|
48718
|
+
optParams: optParamsSchema,
|
|
48233
48719
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48234
48720
|
}),
|
|
48235
48721
|
invoke: async (_ctx, input2) => {
|
|
48236
48722
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48237
48723
|
const pending = await commerce.write.setBudget(
|
|
48238
|
-
[BigInt(input2.jobId), BigInt(input2.amount), "0x"],
|
|
48724
|
+
[BigInt(input2.jobId), BigInt(input2.amount), input2.optParams ?? "0x"],
|
|
48239
48725
|
this.walletContext.activeWallet()
|
|
48240
48726
|
);
|
|
48241
48727
|
const confirmed = await pending.wait();
|
|
48242
|
-
return { success: true,
|
|
48728
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48243
48729
|
}
|
|
48244
48730
|
};
|
|
48245
48731
|
}
|
|
48246
48732
|
fund() {
|
|
48247
48733
|
return {
|
|
48248
48734
|
name: "erc8183_fund",
|
|
48249
|
-
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.",
|
|
48250
48736
|
schema: import_zod17.z.object({
|
|
48251
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,
|
|
48252
48742
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48253
48743
|
}),
|
|
48254
48744
|
invoke: async (_ctx, input2) => {
|
|
48255
48745
|
const { client, commerce, chainKey } = this.bind(input2.chain);
|
|
48256
48746
|
const jobId = BigInt(input2.jobId);
|
|
48257
|
-
|
|
48258
|
-
if (
|
|
48259
|
-
|
|
48260
|
-
|
|
48261
|
-
|
|
48262
|
-
|
|
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;
|
|
48263
48762
|
}
|
|
48264
48763
|
const token = await commerce.read.paymentToken([]);
|
|
48265
48764
|
const wallet = this.walletContext.activeWallet();
|
|
48266
|
-
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);
|
|
48267
48766
|
const approveConfirmed = await approvePending.wait();
|
|
48268
|
-
const fundPending = await commerce.write.fund(
|
|
48767
|
+
const fundPending = await commerce.write.fund(
|
|
48768
|
+
[jobId, budget, input2.optParams ?? "0x"],
|
|
48769
|
+
wallet
|
|
48770
|
+
);
|
|
48269
48771
|
const fundConfirmed = await fundPending.wait();
|
|
48270
48772
|
return {
|
|
48271
48773
|
success: true,
|
|
48272
|
-
approveHash: approveConfirmed.
|
|
48273
|
-
|
|
48774
|
+
approveHash: approveConfirmed.hash,
|
|
48775
|
+
hash: fundConfirmed.hash,
|
|
48274
48776
|
status: "Funded",
|
|
48275
48777
|
chain: chainKey
|
|
48276
48778
|
};
|
|
@@ -48286,16 +48788,19 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48286
48788
|
deliverable: bytes32Schema.describe(
|
|
48287
48789
|
"bytes32 deliverable commitment (e.g. a content hash)."
|
|
48288
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
|
+
),
|
|
48289
48794
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48290
48795
|
}),
|
|
48291
48796
|
invoke: async (_ctx, input2) => {
|
|
48292
48797
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48293
48798
|
const pending = await commerce.write.submit(
|
|
48294
|
-
[BigInt(input2.jobId), input2.deliverable, "0x"],
|
|
48799
|
+
[BigInt(input2.jobId), input2.deliverable, input2.optParams ?? "0x"],
|
|
48295
48800
|
this.walletContext.activeWallet()
|
|
48296
48801
|
);
|
|
48297
48802
|
const confirmed = await pending.wait();
|
|
48298
|
-
return { success: true,
|
|
48803
|
+
return { success: true, hash: confirmed.hash, status: "Submitted", chain: chainKey };
|
|
48299
48804
|
}
|
|
48300
48805
|
};
|
|
48301
48806
|
}
|
|
@@ -48306,19 +48811,20 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48306
48811
|
schema: import_zod17.z.object({
|
|
48307
48812
|
jobId: jobIdSchema,
|
|
48308
48813
|
reason: bytes32Schema.optional().describe("Optional bytes32 reason/attestation (defaults to zero)."),
|
|
48814
|
+
optParams: optParamsSchema,
|
|
48309
48815
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48310
48816
|
}),
|
|
48311
48817
|
invoke: async (_ctx, input2) => {
|
|
48312
48818
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48313
48819
|
const pending = await commerce.write.complete(
|
|
48314
|
-
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, "0x"],
|
|
48820
|
+
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, input2.optParams ?? "0x"],
|
|
48315
48821
|
this.walletContext.activeWallet()
|
|
48316
48822
|
);
|
|
48317
48823
|
const confirmed = await pending.wait();
|
|
48318
48824
|
const released = confirmed.events.PaymentReleased?.[0];
|
|
48319
48825
|
return {
|
|
48320
48826
|
success: true,
|
|
48321
|
-
|
|
48827
|
+
hash: confirmed.hash,
|
|
48322
48828
|
status: "Completed",
|
|
48323
48829
|
released: released ? released.amount.toString() : null,
|
|
48324
48830
|
chain: chainKey
|
|
@@ -48333,19 +48839,20 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48333
48839
|
schema: import_zod17.z.object({
|
|
48334
48840
|
jobId: jobIdSchema,
|
|
48335
48841
|
reason: bytes32Schema.optional().describe("Optional bytes32 reason (defaults to zero)."),
|
|
48842
|
+
optParams: optParamsSchema,
|
|
48336
48843
|
chain: import_zod17.z.string().default("bsc").describe(CHAIN_DESC)
|
|
48337
48844
|
}),
|
|
48338
48845
|
invoke: async (_ctx, input2) => {
|
|
48339
48846
|
const { commerce, chainKey } = this.bind(input2.chain);
|
|
48340
48847
|
const pending = await commerce.write.reject(
|
|
48341
|
-
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, "0x"],
|
|
48848
|
+
[BigInt(input2.jobId), input2.reason ?? ZERO_BYTES322, input2.optParams ?? "0x"],
|
|
48342
48849
|
this.walletContext.activeWallet()
|
|
48343
48850
|
);
|
|
48344
48851
|
const confirmed = await pending.wait();
|
|
48345
48852
|
const refunded = confirmed.events.Refunded?.[0];
|
|
48346
48853
|
return {
|
|
48347
48854
|
success: true,
|
|
48348
|
-
|
|
48855
|
+
hash: confirmed.hash,
|
|
48349
48856
|
status: "Rejected",
|
|
48350
48857
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
48351
48858
|
chain: chainKey
|
|
@@ -48371,7 +48878,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48371
48878
|
const refunded = confirmed.events.Refunded?.[0];
|
|
48372
48879
|
return {
|
|
48373
48880
|
success: true,
|
|
48374
|
-
|
|
48881
|
+
hash: confirmed.hash,
|
|
48375
48882
|
status: "Expired",
|
|
48376
48883
|
refunded: refunded ? refunded.amount.toString() : null,
|
|
48377
48884
|
chain: chainKey
|
|
@@ -48413,6 +48920,46 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48413
48920
|
}
|
|
48414
48921
|
};
|
|
48415
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
|
+
}
|
|
48416
48963
|
// ----- Router -------------------------------------------------------------
|
|
48417
48964
|
registerJob() {
|
|
48418
48965
|
return {
|
|
@@ -48430,7 +48977,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48430
48977
|
this.walletContext.activeWallet()
|
|
48431
48978
|
);
|
|
48432
48979
|
const confirmed = await pending.wait();
|
|
48433
|
-
return { success: true,
|
|
48980
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48434
48981
|
}
|
|
48435
48982
|
};
|
|
48436
48983
|
}
|
|
@@ -48450,7 +48997,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48450
48997
|
this.walletContext.activeWallet()
|
|
48451
48998
|
);
|
|
48452
48999
|
const confirmed = await pending.wait();
|
|
48453
|
-
return { success: true,
|
|
49000
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48454
49001
|
}
|
|
48455
49002
|
};
|
|
48456
49003
|
}
|
|
@@ -48469,7 +49016,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48469
49016
|
this.walletContext.activeWallet()
|
|
48470
49017
|
);
|
|
48471
49018
|
const confirmed = await pending.wait();
|
|
48472
|
-
return { success: true,
|
|
49019
|
+
return { success: true, hash: confirmed.hash, status: "Expired", chain: chainKey };
|
|
48473
49020
|
}
|
|
48474
49021
|
};
|
|
48475
49022
|
}
|
|
@@ -48489,7 +49036,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48489
49036
|
this.walletContext.activeWallet()
|
|
48490
49037
|
);
|
|
48491
49038
|
const confirmed = await pending.wait();
|
|
48492
|
-
return { success: true,
|
|
49039
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48493
49040
|
}
|
|
48494
49041
|
};
|
|
48495
49042
|
}
|
|
@@ -48508,7 +49055,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
|
|
|
48508
49055
|
this.walletContext.activeWallet()
|
|
48509
49056
|
);
|
|
48510
49057
|
const confirmed = await pending.wait();
|
|
48511
|
-
return { success: true,
|
|
49058
|
+
return { success: true, hash: confirmed.hash, chain: chainKey };
|
|
48512
49059
|
}
|
|
48513
49060
|
};
|
|
48514
49061
|
}
|
|
@@ -48579,14 +49126,14 @@ var CompetitionActionProvider = class extends ActionProvider {
|
|
|
48579
49126
|
if (!confirmed.events.Registered?.[0]) {
|
|
48580
49127
|
throw new WalletError(
|
|
48581
49128
|
"TX_FAILED",
|
|
48582
|
-
`competition_register: no Registered event emitted (
|
|
49129
|
+
`competition_register: no Registered event emitted (hash=${confirmed.hash})`
|
|
48583
49130
|
);
|
|
48584
49131
|
}
|
|
48585
49132
|
return {
|
|
48586
49133
|
success: true,
|
|
48587
49134
|
registered: true,
|
|
48588
49135
|
participant,
|
|
48589
|
-
|
|
49136
|
+
hash: confirmed.hash,
|
|
48590
49137
|
deadline: toIso2(deadline),
|
|
48591
49138
|
chain: CHAIN
|
|
48592
49139
|
};
|
|
@@ -53591,7 +54138,7 @@ async function runAutomationsTick(deps) {
|
|
|
53591
54138
|
runCount: (auto.runCount ?? 0) + 1
|
|
53592
54139
|
});
|
|
53593
54140
|
log("info", `DCA executed: ${res.explorerUrl}`);
|
|
53594
|
-
result.executed.push({ id: auto.id, type: "dca",
|
|
54141
|
+
result.executed.push({ id: auto.id, type: "dca", hash: res.hash });
|
|
53595
54142
|
} else {
|
|
53596
54143
|
log("warn", `DCA ${auto.id} failed: ${res.error}`);
|
|
53597
54144
|
result.errors++;
|
|
@@ -53639,7 +54186,7 @@ async function runAutomationsTick(deps) {
|
|
|
53639
54186
|
lastRunAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
53640
54187
|
});
|
|
53641
54188
|
log("info", `Limit order executed: ${res.explorerUrl}`);
|
|
53642
|
-
result.executed.push({ id: auto.id, type: "limit",
|
|
54189
|
+
result.executed.push({ id: auto.id, type: "limit", hash: res.hash });
|
|
53643
54190
|
} else {
|
|
53644
54191
|
log("warn", `Limit order ${auto.id} failed: ${res.error}`);
|
|
53645
54192
|
result.errors++;
|
|
@@ -54187,12 +54734,15 @@ ${url}`);
|
|
|
54187
54734
|
amount: opts.amount,
|
|
54188
54735
|
decimals,
|
|
54189
54736
|
memo: opts.memo,
|
|
54737
|
+
// Mainnet by construction — onramp has no --chain input and derives
|
|
54738
|
+
// chainKey from the asset's coinId via the CHAINS-only resolver.
|
|
54739
|
+
chainKey,
|
|
54190
54740
|
hdWallet
|
|
54191
54741
|
});
|
|
54192
54742
|
} catch (err) {
|
|
54193
54743
|
mapBroadcastError(err);
|
|
54194
54744
|
}
|
|
54195
|
-
const explorerUrl = getExplorerTxUrl(result.chainKey, result.
|
|
54745
|
+
const explorerUrl = getExplorerTxUrl(result.chainKey, result.hash);
|
|
54196
54746
|
success("Off-ramp payout broadcast!");
|
|
54197
54747
|
if (!opts.json) {
|
|
54198
54748
|
info(
|
|
@@ -54201,7 +54751,7 @@ ${url}`);
|
|
|
54201
54751
|
}
|
|
54202
54752
|
output(
|
|
54203
54753
|
{
|
|
54204
|
-
hash: result.
|
|
54754
|
+
hash: result.hash,
|
|
54205
54755
|
chain: result.chainKey,
|
|
54206
54756
|
from: address,
|
|
54207
54757
|
to: opts.to,
|
|
@@ -54586,7 +55136,7 @@ function registerX402Command(program3) {
|
|
|
54586
55136
|
confirmApproval: opts.autoApprove ? autoApproveConfirm : makeReadlineApprovalConfirm()
|
|
54587
55137
|
});
|
|
54588
55138
|
if (approval) {
|
|
54589
|
-
info(`x402: Permit2 approved (one-time): tx ${approval.
|
|
55139
|
+
info(`x402: Permit2 approved (one-time): tx ${approval.hash}`);
|
|
54590
55140
|
}
|
|
54591
55141
|
if (payment) {
|
|
54592
55142
|
info(
|
|
@@ -54701,7 +55251,7 @@ var crypto7 = __toESM(require("crypto"));
|
|
|
54701
55251
|
// package.json
|
|
54702
55252
|
var package_default = {
|
|
54703
55253
|
name: "@trustwallet/cli",
|
|
54704
|
-
version: "0.
|
|
55254
|
+
version: "0.19.0",
|
|
54705
55255
|
description: "TWAK CLI \u2014 command-line interface for Trust Wallet Agent Kit",
|
|
54706
55256
|
main: "dist/index.js",
|
|
54707
55257
|
types: "dist/index.d.ts",
|
|
@@ -55077,7 +55627,7 @@ function registerWatchCommand(program3) {
|
|
|
55077
55627
|
tickResults.automations.executed.push({
|
|
55078
55628
|
id: auto.id,
|
|
55079
55629
|
type: "dca",
|
|
55080
|
-
|
|
55630
|
+
hash: result.hash,
|
|
55081
55631
|
explorer: result.explorerUrl
|
|
55082
55632
|
});
|
|
55083
55633
|
} else {
|
|
@@ -55145,7 +55695,7 @@ function registerWatchCommand(program3) {
|
|
|
55145
55695
|
tickResults.automations.executed.push({
|
|
55146
55696
|
id: auto.id,
|
|
55147
55697
|
type: "limit",
|
|
55148
|
-
|
|
55698
|
+
hash: result.hash,
|
|
55149
55699
|
explorer: result.explorerUrl
|
|
55150
55700
|
});
|
|
55151
55701
|
} else {
|