@trustwallet/cli 0.21.0 → 0.23.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/index.js CHANGED
@@ -4282,7 +4282,8 @@ var init_dist = __esm({
4282
4282
  PASSWORD_MISSING: "PASSWORD_MISSING",
4283
4283
  WALLET_NOT_FOUND: "WALLET_NOT_FOUND",
4284
4284
  WALLET_AUTH_FAILED: "WALLET_AUTH_FAILED",
4285
- STORAGE_ERROR: "STORAGE_ERROR"
4285
+ STORAGE_ERROR: "STORAGE_ERROR",
4286
+ CREDENTIALS_MISSING: "CREDENTIALS_MISSING"
4286
4287
  };
4287
4288
  EXECUTION_REVERTED_RE = /\bexecution reverted\b/i;
4288
4289
  FS_ERRNO_CODES = /* @__PURE__ */ new Set([
@@ -4452,6 +4453,7 @@ var init_dist = __esm({
4452
4453
  DEFAULT_X_ORIGIN = "Trust/2.15.0 AgentKit";
4453
4454
  TwakHttpClient = class {
4454
4455
  config;
4456
+ resolveCredentials;
4455
4457
  constructor(config) {
4456
4458
  this.config = {
4457
4459
  gatewayBaseUrl: DEFAULT_GATEWAY_URL,
@@ -4461,17 +4463,18 @@ var init_dist = __esm({
4461
4463
  xOrigin: DEFAULT_X_ORIGIN,
4462
4464
  ...config
4463
4465
  };
4466
+ if ("credentials" in config) {
4467
+ this.resolveCredentials = config.credentials;
4468
+ } else {
4469
+ const fixed = { accessId: config.accessId, hmacSecret: config.hmacSecret };
4470
+ this.resolveCredentials = () => fixed;
4471
+ }
4464
4472
  }
4465
4473
  async gateway(method, path7, body, query) {
4466
4474
  const url = new URL(path7, this.config.gatewayBaseUrl);
4467
4475
  if (query) url.search = query;
4468
- const headers = signRequest(
4469
- method,
4470
- path7,
4471
- query || "",
4472
- this.config.accessId,
4473
- this.config.hmacSecret
4474
- );
4476
+ const { accessId, hmacSecret } = this.resolveCredentials();
4477
+ const headers = signRequest(method, path7, query || "", accessId, hmacSecret);
4475
4478
  return this.fetch(url.toString(), {
4476
4479
  method,
4477
4480
  headers: {
@@ -4547,10 +4550,10 @@ var init_dist = __esm({
4547
4550
  }
4548
4551
  }
4549
4552
  get accessId() {
4550
- return this.config.accessId;
4553
+ return this.resolveCredentials().accessId;
4551
4554
  }
4552
4555
  get hmacSecret() {
4553
- return this.config.hmacSecret;
4556
+ return this.resolveCredentials().hmacSecret;
4554
4557
  }
4555
4558
  };
4556
4559
  ALLOWED_OFFRAMP_PROVIDERS = /* @__PURE__ */ new Set(["MoonPay"]);
@@ -6506,7 +6509,7 @@ var require_source = __commonJS({
6506
6509
  var dist_exports2 = {};
6507
6510
  __export(dist_exports2, {
6508
6511
  AgentWalletProvider: () => AgentWalletProvider,
6509
- BlockchainClient: () => BlockchainClient,
6512
+ ChainClient: () => ChainClient,
6510
6513
  TeeWalletProvider: () => TeeWalletProvider,
6511
6514
  VerifyCredentialsError: () => VerifyCredentialsError,
6512
6515
  WalletContext: () => WalletContext,
@@ -7366,7 +7369,7 @@ function registerShutdownHandlers(providers, onBeforeExit) {
7366
7369
  process.removeListener("SIGTERM", handler);
7367
7370
  };
7368
7371
  }
7369
- var fs2, path2, import_trust_sdk, import_trust_sdk2, import_trust_sdk3, import_trust_sdk4, import_trust_sdk5, import_crypto2, __require, polyfillsApplied, _credentials, _naasSessionId, nodeStubsPatched, sponsorNonceByAddress, NAAS_SESSION_RE, naasSessionPatched, coinTypeByValue, walletCore, initialized, BSC_COIN_ID, DEFAULT_BSC_SPONSORED_RPC, SPONSOR_PRECHECK_TIMEOUT_MS, SPONSOR_USER_AGENT, RPC_TIMEOUT_MS, RECEIPT_POLL_INTERVAL_MS, RECEIPT_DEFAULT_TIMEOUT_MS, BlockchainClient, WalletCoreSigner, domainsByCoinId, GATEWAY_URL, DEVICE_INFO_BODY, VerifyCredentialsError, WALLET_ID_SUFFIX, WALLET_ID_LENGTH, EVM_COIN_IDS, MAINTAINED_COIN_IDS, WalletProvider, AgentWalletProvider, TeeWalletProvider, WalletContext, SHUTDOWN_TIMEOUT_MS;
7372
+ var fs2, path2, import_trust_sdk, import_trust_sdk2, import_trust_sdk3, import_trust_sdk4, import_trust_sdk5, import_crypto2, __require, polyfillsApplied, _credentials, _naasSessionId, nodeStubsPatched, sponsorNonceByAddress, NAAS_SESSION_RE, naasSessionPatched, coinTypeByValue, walletCore, initialized, BSC_COIN_ID, DEFAULT_BSC_SPONSORED_RPC, SPONSOR_PRECHECK_TIMEOUT_MS, SPONSOR_USER_AGENT, RPC_TIMEOUT_MS, RECEIPT_POLL_INTERVAL_MS, RECEIPT_DEFAULT_TIMEOUT_MS, ChainClient, SigningChainClient, WalletCoreSigner, domainsByCoinId, GATEWAY_URL, DEVICE_INFO_BODY, VerifyCredentialsError, WALLET_ID_SUFFIX, WALLET_ID_LENGTH, EVM_COIN_IDS, MAINTAINED_COIN_IDS, WalletProvider, AgentWalletProvider, TeeWalletProvider, WalletContext, SHUTDOWN_TIMEOUT_MS;
7370
7373
  var init_dist3 = __esm({
7371
7374
  "../wallet-core/dist/index.mjs"() {
7372
7375
  "use strict";
@@ -7409,18 +7412,20 @@ var init_dist3 = __esm({
7409
7412
  RPC_TIMEOUT_MS = 15e3;
7410
7413
  RECEIPT_POLL_INTERVAL_MS = 1500;
7411
7414
  RECEIPT_DEFAULT_TIMEOUT_MS = 6e4;
7412
- BlockchainClient = class _BlockchainClient {
7413
- signer;
7414
- constructor(signer) {
7415
- this.signer = signer;
7416
- }
7417
- setSigner(signer) {
7418
- this.signer = signer;
7419
- }
7415
+ ChainClient = class {
7416
+ /** Balance of `address`, read through an account built from that address alone. */
7420
7417
  async getBalance(assetId, address, chainKey) {
7418
+ const { coinId } = parseTokenId(assetId);
7419
+ return this.loadBalance(
7420
+ assetId,
7421
+ this.createAccountForAddress(coinId, address, chainKey),
7422
+ address
7423
+ );
7424
+ }
7425
+ /** `address` feeds the Bitcoin REST fallback when the SDK load fails. */
7426
+ async loadBalance(assetId, account, address) {
7421
7427
  const { coinId, contractAddress } = parseTokenId(assetId);
7422
7428
  const ct5 = requireCoinType(coinId);
7423
- const account = this.createAccountForAddress(coinId, address, chainKey);
7424
7429
  const asset = contractAddress ? new import_trust_sdk2.Asset.Token(account, contractAddress, tokenTypeForCoinId(coinId)) : new import_trust_sdk2.Asset.Coin(account);
7425
7430
  let results;
7426
7431
  try {
@@ -7513,47 +7518,6 @@ var init_dist3 = __esm({
7513
7518
  }
7514
7519
  return result;
7515
7520
  }
7516
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
7517
- async transfer(params) {
7518
- const { coinId, contractAddress } = parseTokenId(params.assetId);
7519
- const chainKey = params.chainKey;
7520
- const ct5 = requireCoinType(coinId);
7521
- const account = this.getAccountFromSigner(chainKey);
7522
- const asset = contractAddress ? new import_trust_sdk2.Asset.Token(account, contractAddress, tokenTypeForCoinId(coinId)) : new import_trust_sdk2.Asset.Coin(account);
7523
- let decimals;
7524
- if (params.decimals !== void 0) {
7525
- decimals = params.decimals;
7526
- } else if (contractAddress) {
7527
- const known = lookupKnownTokenDecimals(chainKey, contractAddress);
7528
- if (known === void 0) {
7529
- throw new TwakValidationError(
7530
- `Cannot determine decimals for ${params.assetId}; pass decimals explicitly.`
7531
- );
7532
- }
7533
- decimals = known;
7534
- } else {
7535
- decimals = getCoinDecimals(coinId);
7536
- }
7537
- const amountWei = humanAmountToWei(params.amount, decimals);
7538
- const transaction = new import_trust_sdk2.TransactionTransfer(
7539
- params.to,
7540
- asset,
7541
- amountWei.toString(),
7542
- false,
7543
- params.memo || null
7544
- );
7545
- return this.signAndBroadcast(transaction, account, coinId, chainKey, ct5, params.hdWallet);
7546
- }
7547
- async executeContract(params) {
7548
- const { coinId } = parseTokenId(params.assetId);
7549
- const chainKey = params.chainKey;
7550
- const ct5 = requireCoinType(coinId);
7551
- const account = this.getAccountFromSigner(chainKey);
7552
- const asset = new import_trust_sdk2.Asset.Coin(account);
7553
- const valueWei = params.value && params.value !== "0x0" && params.value !== "0x" ? BigInt(params.value).toString() : "0";
7554
- const transaction = new import_trust_sdk2.TransactionSmartContract(asset, params.to, valueWei, params.data);
7555
- return this.signAndBroadcast(transaction, account, coinId, chainKey, ct5, params.hdWallet);
7556
- }
7557
7521
  /**
7558
7522
  * Execute a read-only EVM `eth_call` against the chain's default RPC node.
7559
7523
  * Returns the raw hex result string from the JSON-RPC envelope, or `'0x'`
@@ -7617,6 +7581,177 @@ var init_dist3 = __esm({
7617
7581
  contract(def) {
7618
7582
  return def.using(this);
7619
7583
  }
7584
+ async findTransactionStatus(chainKey, address, hash) {
7585
+ const coinId = chainKeyToCoinType(chainKey);
7586
+ if (coinId === void 0) throw new Error(`Unsupported chain: ${chainKey}`);
7587
+ const account = this.createAccountForAddress(coinId, address);
7588
+ let result;
7589
+ try {
7590
+ result = await import_trust_sdk2.BlockchainService.findTransaction(account, hash);
7591
+ } catch {
7592
+ return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
7593
+ }
7594
+ if (!result) {
7595
+ return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
7596
+ }
7597
+ const failed = result.status instanceof import_trust_sdk2.TransactionResult.Status.Failed;
7598
+ return {
7599
+ confirmed: result.status === import_trust_sdk2.TransactionResult.Status.Confirmed,
7600
+ pending: result.status === import_trust_sdk2.TransactionResult.Status.Pending,
7601
+ failed,
7602
+ error: failed ? result.status.error : void 0,
7603
+ meta: result.meta || void 0
7604
+ };
7605
+ }
7606
+ async getNodes(chainKey) {
7607
+ const coinId = chainKeyToCoinType(chainKey);
7608
+ if (coinId === void 0) {
7609
+ throw new Error(`Unsupported chain: ${chainKey}`);
7610
+ }
7611
+ const ct5 = requireCoinType(coinId);
7612
+ const chain2 = new import_trust_sdk2.DefinedChain(ct5);
7613
+ const nodes = await import_trust_sdk2.BlockchainService.getNodes(chain2);
7614
+ return nodes.map((n4) => ({ url: n4.url }));
7615
+ }
7616
+ async setNode(chainKey, rpcUrl) {
7617
+ const coinId = chainKeyToCoinType(chainKey);
7618
+ if (coinId === void 0) {
7619
+ throw new Error(`Unsupported chain: ${chainKey}`);
7620
+ }
7621
+ const ct5 = requireCoinType(coinId);
7622
+ const chain2 = new import_trust_sdk2.DefinedChain(ct5);
7623
+ await import_trust_sdk2.BlockchainService.setNode(chain2, new import_trust_sdk2.Node(rpcUrl));
7624
+ }
7625
+ createAccountForAddress(coinId, address, chainKey) {
7626
+ const ct5 = requireCoinType(coinId);
7627
+ const chain2 = chainKey !== void 0 && isTestnetChain(chainKey) ? chainKeyToDefinedChain(chainKey).chain : new import_trust_sdk2.DefinedChain(ct5);
7628
+ const wc3 = getWalletCore();
7629
+ const derivation = coinId === 0 && address.startsWith("bc1p") ? wc3.Derivation.bitcoinTaproot : coinId === 0 && address.startsWith("bc1") ? wc3.Derivation.bitcoinSegwit : wc3.Derivation.default;
7630
+ return new import_trust_sdk2.Account(address, derivation, "", "", "", chain2);
7631
+ }
7632
+ async fetchBitcoinBalanceFromBlockbook(address) {
7633
+ const res = await fetch(
7634
+ `https://btc-blockbook.twnodes.com/api/v2/address/${encodeURIComponent(address)}?details=basic`
7635
+ );
7636
+ if (!res.ok) throw new Error(`Blockbook error: ${res.status}`);
7637
+ const data = await res.json();
7638
+ const confirmed = data.balance || "0";
7639
+ const unconfirmed = data.unconfirmedBalance || "0";
7640
+ const total = BigInt(confirmed) + BigInt(unconfirmed);
7641
+ return { available: confirmed, total: total.toString() };
7642
+ }
7643
+ async resolveRpcUrl(chainKey) {
7644
+ const { chain: chain2 } = chainKeyToDefinedChain(chainKey);
7645
+ return this.rpcUrlForChain(chain2, chainKey);
7646
+ }
7647
+ async rpcUrlForChain(chain2, chainKey) {
7648
+ const nodes = await import_trust_sdk2.BlockchainService.getNodes(chain2);
7649
+ const rpcUrl = nodes[0]?.url;
7650
+ if (!rpcUrl) {
7651
+ throw new TwakNetworkError(`No RPC node available for ${chainKey}`, { chainKey });
7652
+ }
7653
+ return rpcUrl;
7654
+ }
7655
+ async postJsonRpc(rpcUrl, method, params, opts) {
7656
+ const timeoutMs = opts?.timeoutMs ?? RPC_TIMEOUT_MS;
7657
+ let response;
7658
+ try {
7659
+ response = await fetch(rpcUrl, {
7660
+ method: "POST",
7661
+ headers: { "Content-Type": "application/json", ...opts?.headers },
7662
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
7663
+ signal: AbortSignal.timeout(timeoutMs)
7664
+ });
7665
+ } catch (err) {
7666
+ throw new TwakNetworkError(`RPC fetch failed on ${method}: ${errorMessage(err)}`, {
7667
+ method,
7668
+ rpcUrl,
7669
+ timeoutMs
7670
+ });
7671
+ }
7672
+ if (!response.ok) {
7673
+ const body = await response.text().catch(() => "");
7674
+ const truncated = body.slice(0, 500);
7675
+ throw new TwakNetworkError(`RPC HTTP error ${response.status} on ${method}: ${truncated}`, {
7676
+ status: response.status,
7677
+ method,
7678
+ rpcUrl,
7679
+ body: truncated
7680
+ });
7681
+ }
7682
+ let json;
7683
+ try {
7684
+ json = await response.json();
7685
+ } catch (err) {
7686
+ throw new TwakNetworkError(
7687
+ `RPC response JSON parse failed on ${method}: ${errorMessage(err)}`,
7688
+ { method, rpcUrl }
7689
+ );
7690
+ }
7691
+ if (json.error) {
7692
+ const { message, data } = json.error;
7693
+ const suffix = revertDataSuffix(message, data);
7694
+ throw new TwakNetworkError(`RPC error on ${method}: ${message}${suffix}`, {
7695
+ method,
7696
+ rpcUrl,
7697
+ rpcError: json.error
7698
+ });
7699
+ }
7700
+ return json.result;
7701
+ }
7702
+ };
7703
+ SigningChainClient = class _SigningChainClient extends ChainClient {
7704
+ constructor(signer) {
7705
+ super();
7706
+ this.signer = signer;
7707
+ }
7708
+ /** This wallet's own balance, read through its derived account (for UTXO
7709
+ * chains such as Bitcoin it carries the extended public key). */
7710
+ async getOwnBalance(assetId, chainKey) {
7711
+ const account = this.getAccountFromSigner(chainKey);
7712
+ return this.loadBalance(assetId, account, account.address);
7713
+ }
7714
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7715
+ async transfer(params) {
7716
+ const { coinId, contractAddress } = parseTokenId(params.assetId);
7717
+ const chainKey = params.chainKey;
7718
+ const ct5 = requireCoinType(coinId);
7719
+ const account = this.getAccountFromSigner(chainKey);
7720
+ const asset = contractAddress ? new import_trust_sdk2.Asset.Token(account, contractAddress, tokenTypeForCoinId(coinId)) : new import_trust_sdk2.Asset.Coin(account);
7721
+ let decimals;
7722
+ if (params.decimals !== void 0) {
7723
+ decimals = params.decimals;
7724
+ } else if (contractAddress) {
7725
+ const known = lookupKnownTokenDecimals(chainKey, contractAddress);
7726
+ if (known === void 0) {
7727
+ throw new TwakValidationError(
7728
+ `Cannot determine decimals for ${params.assetId}; pass decimals explicitly.`
7729
+ );
7730
+ }
7731
+ decimals = known;
7732
+ } else {
7733
+ decimals = getCoinDecimals(coinId);
7734
+ }
7735
+ const amountWei = humanAmountToWei(params.amount, decimals);
7736
+ const transaction = new import_trust_sdk2.TransactionTransfer(
7737
+ params.to,
7738
+ asset,
7739
+ amountWei.toString(),
7740
+ false,
7741
+ params.memo || null
7742
+ );
7743
+ return this.signAndBroadcast(transaction, account, coinId, chainKey, ct5, params.hdWallet);
7744
+ }
7745
+ async executeContract(params) {
7746
+ const { coinId } = parseTokenId(params.assetId);
7747
+ const chainKey = params.chainKey;
7748
+ const ct5 = requireCoinType(coinId);
7749
+ const account = this.getAccountFromSigner(chainKey);
7750
+ const asset = new import_trust_sdk2.Asset.Coin(account);
7751
+ const valueWei = params.value && params.value !== "0x0" && params.value !== "0x" ? BigInt(params.value).toString() : "0";
7752
+ const transaction = new import_trust_sdk2.TransactionSmartContract(asset, params.to, valueWei, params.data);
7753
+ return this.signAndBroadcast(transaction, account, coinId, chainKey, ct5, params.hdWallet);
7754
+ }
7620
7755
  async transferRawSolana(params) {
7621
7756
  const ct5 = requireCoinType(501);
7622
7757
  const chain2 = new import_trust_sdk2.DefinedChain(ct5);
@@ -7702,47 +7837,6 @@ var init_dist3 = __esm({
7702
7837
  currency: chainKey
7703
7838
  };
7704
7839
  }
7705
- async findTransactionStatus(chainKey, address, hash) {
7706
- const coinId = chainKeyToCoinType(chainKey);
7707
- if (coinId === void 0) throw new Error(`Unsupported chain: ${chainKey}`);
7708
- const account = this.createAccountForAddress(coinId, address);
7709
- let result;
7710
- try {
7711
- result = await import_trust_sdk2.BlockchainService.findTransaction(account, hash);
7712
- } catch {
7713
- return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
7714
- }
7715
- if (!result) {
7716
- return { confirmed: false, pending: false, failed: false, error: "Transaction not found" };
7717
- }
7718
- const failed = result.status instanceof import_trust_sdk2.TransactionResult.Status.Failed;
7719
- return {
7720
- confirmed: result.status === import_trust_sdk2.TransactionResult.Status.Confirmed,
7721
- pending: result.status === import_trust_sdk2.TransactionResult.Status.Pending,
7722
- failed,
7723
- error: failed ? result.status.error : void 0,
7724
- meta: result.meta || void 0
7725
- };
7726
- }
7727
- async getNodes(chainKey) {
7728
- const coinId = chainKeyToCoinType(chainKey);
7729
- if (coinId === void 0) {
7730
- throw new Error(`Unsupported chain: ${chainKey}`);
7731
- }
7732
- const ct5 = requireCoinType(coinId);
7733
- const chain2 = new import_trust_sdk2.DefinedChain(ct5);
7734
- const nodes = await import_trust_sdk2.BlockchainService.getNodes(chain2);
7735
- return nodes.map((n4) => ({ url: n4.url }));
7736
- }
7737
- async setNode(chainKey, rpcUrl) {
7738
- const coinId = chainKeyToCoinType(chainKey);
7739
- if (coinId === void 0) {
7740
- throw new Error(`Unsupported chain: ${chainKey}`);
7741
- }
7742
- const ct5 = requireCoinType(coinId);
7743
- const chain2 = new import_trust_sdk2.DefinedChain(ct5);
7744
- await import_trust_sdk2.BlockchainService.setNode(chain2, new import_trust_sdk2.Node(rpcUrl));
7745
- }
7746
7840
  // EIP-7702 sponsorship-eligible chain coin IDs
7747
7841
  static SPONSORABLE_COINS = [60, 20000714];
7748
7842
  /**
@@ -7902,7 +7996,7 @@ var init_dist3 = __esm({
7902
7996
  } catch {
7903
7997
  }
7904
7998
  const seen = new Set(candidates.map((a3) => a3.toLowerCase()));
7905
- for (const addr of _BlockchainClient.FALLBACK_GAS_TOKENS[coinId] || []) {
7999
+ for (const addr of _SigningChainClient.FALLBACK_GAS_TOKENS[coinId] || []) {
7906
8000
  if (!seen.has(addr.toLowerCase())) candidates.push(addr);
7907
8001
  }
7908
8002
  if (candidates.length === 0) return void 0;
@@ -7929,7 +8023,7 @@ var init_dist3 = __esm({
7929
8023
  * Trust SDK routes through the Smart Wallet fee service internally.
7930
8024
  */
7931
8025
  async calculateFeeWithSponsorship(transaction, account, coinId, chainKey) {
7932
- if (!_BlockchainClient.SPONSORABLE_COINS.includes(coinId) || chainKey !== void 0 && isTestnetChain(chainKey)) {
8026
+ if (!_SigningChainClient.SPONSORABLE_COINS.includes(coinId) || chainKey !== void 0 && isTestnetChain(chainKey)) {
7933
8027
  return { fee: await import_trust_sdk2.BlockchainService.calculateFee(transaction) };
7934
8028
  }
7935
8029
  let supports7702 = false;
@@ -8060,97 +8154,8 @@ var init_dist3 = __esm({
8060
8154
  return { fee: baseFee, transaction7702: tx7702 };
8061
8155
  }
8062
8156
  getAccountFromSigner(chainKey) {
8063
- if (!this.signer) {
8064
- throw new Error("BlockchainClient requires a signer for this operation");
8065
- }
8066
8157
  return this.signer.getAccount(chainKey);
8067
8158
  }
8068
- createAccountForAddress(coinId, address, chainKey) {
8069
- if (this.signer) {
8070
- const key = chainKey ?? coinTypeToChainKey(coinId);
8071
- if (key) {
8072
- try {
8073
- return this.signer.getAccount(key);
8074
- } catch {
8075
- }
8076
- }
8077
- }
8078
- const ct5 = requireCoinType(coinId);
8079
- const chain2 = chainKey !== void 0 && isTestnetChain(chainKey) ? chainKeyToDefinedChain(chainKey).chain : new import_trust_sdk2.DefinedChain(ct5);
8080
- const wc3 = getWalletCore();
8081
- const derivation = coinId === 0 && address.startsWith("bc1p") ? wc3.Derivation.bitcoinTaproot : coinId === 0 && address.startsWith("bc1") ? wc3.Derivation.bitcoinSegwit : wc3.Derivation.default;
8082
- return new import_trust_sdk2.Account(address, derivation, "", "", "", chain2);
8083
- }
8084
- async fetchBitcoinBalanceFromBlockbook(address) {
8085
- const res = await fetch(
8086
- `https://btc-blockbook.twnodes.com/api/v2/address/${encodeURIComponent(address)}?details=basic`
8087
- );
8088
- if (!res.ok) throw new Error(`Blockbook error: ${res.status}`);
8089
- const data = await res.json();
8090
- const confirmed = data.balance || "0";
8091
- const unconfirmed = data.unconfirmedBalance || "0";
8092
- const total = BigInt(confirmed) + BigInt(unconfirmed);
8093
- return { available: confirmed, total: total.toString() };
8094
- }
8095
- async resolveRpcUrl(chainKey) {
8096
- const { chain: chain2 } = chainKeyToDefinedChain(chainKey);
8097
- return this.rpcUrlForChain(chain2, chainKey);
8098
- }
8099
- async rpcUrlForChain(chain2, chainKey) {
8100
- const nodes = await import_trust_sdk2.BlockchainService.getNodes(chain2);
8101
- const rpcUrl = nodes[0]?.url;
8102
- if (!rpcUrl) {
8103
- throw new TwakNetworkError(`No RPC node available for ${chainKey}`, { chainKey });
8104
- }
8105
- return rpcUrl;
8106
- }
8107
- async postJsonRpc(rpcUrl, method, params, opts) {
8108
- const timeoutMs = opts?.timeoutMs ?? RPC_TIMEOUT_MS;
8109
- let response;
8110
- try {
8111
- response = await fetch(rpcUrl, {
8112
- method: "POST",
8113
- headers: { "Content-Type": "application/json", ...opts?.headers },
8114
- body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
8115
- signal: AbortSignal.timeout(timeoutMs)
8116
- });
8117
- } catch (err) {
8118
- throw new TwakNetworkError(`RPC fetch failed on ${method}: ${errorMessage(err)}`, {
8119
- method,
8120
- rpcUrl,
8121
- timeoutMs
8122
- });
8123
- }
8124
- if (!response.ok) {
8125
- const body = await response.text().catch(() => "");
8126
- const truncated = body.slice(0, 500);
8127
- throw new TwakNetworkError(`RPC HTTP error ${response.status} on ${method}: ${truncated}`, {
8128
- status: response.status,
8129
- method,
8130
- rpcUrl,
8131
- body: truncated
8132
- });
8133
- }
8134
- let json;
8135
- try {
8136
- json = await response.json();
8137
- } catch (err) {
8138
- throw new TwakNetworkError(
8139
- `RPC response JSON parse failed on ${method}: ${errorMessage(err)}`,
8140
- { method, rpcUrl }
8141
- );
8142
- }
8143
- if (json.error) {
8144
- const { message, data } = json.error;
8145
- const suffix = revertDataSuffix(message, data);
8146
- throw new TwakNetworkError(`RPC error on ${method}: ${message}${suffix}`, {
8147
- method,
8148
- rpcUrl,
8149
- rpcError: json.error
8150
- });
8151
- }
8152
- return json.result;
8153
- }
8154
8159
  };
8155
8160
  WalletCoreSigner = class _WalletCoreSigner {
8156
8161
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -8299,6 +8304,7 @@ var init_dist3 = __esm({
8299
8304
  };
8300
8305
  AgentWalletProvider = class _AgentWalletProvider extends WalletProvider {
8301
8306
  name = "agent";
8307
+ kind = "local";
8302
8308
  signer;
8303
8309
  blockchainClient;
8304
8310
  connected = true;
@@ -8355,7 +8361,7 @@ var init_dist3 = __esm({
8355
8361
  const store = new WalletConfigStore();
8356
8362
  const mnemonic = await store.loadMnemonic(password3);
8357
8363
  this.signer = await WalletCoreSigner.fromMnemonic(mnemonic);
8358
- this.blockchainClient = new BlockchainClient(this.signer);
8364
+ this.blockchainClient = new SigningChainClient(this.signer);
8359
8365
  this.connected = true;
8360
8366
  })();
8361
8367
  try {
@@ -8371,21 +8377,21 @@ var init_dist3 = __esm({
8371
8377
  const store = new WalletConfigStore();
8372
8378
  await store.saveMnemonic(mnemonic, password3, Object.keys(CHAINS));
8373
8379
  const signer = WalletCoreSigner.fromHDWallet(hdWallet);
8374
- const client = new BlockchainClient(signer);
8380
+ const client = new SigningChainClient(signer);
8375
8381
  return new _AgentWalletProvider(signer, client);
8376
8382
  }
8377
8383
  static async fromStorage(password3) {
8378
8384
  const store = new WalletConfigStore();
8379
8385
  const mnemonic = await store.loadMnemonic(password3);
8380
8386
  const signer = await WalletCoreSigner.fromMnemonic(mnemonic);
8381
- const client = new BlockchainClient(signer);
8387
+ const client = new SigningChainClient(signer);
8382
8388
  return new _AgentWalletProvider(signer, client);
8383
8389
  }
8384
8390
  static async fromMnemonic(mnemonic, password3) {
8385
8391
  const store = new WalletConfigStore();
8386
8392
  await store.saveMnemonic(mnemonic, password3, Object.keys(CHAINS));
8387
8393
  const signer = await WalletCoreSigner.fromMnemonic(mnemonic);
8388
- const client = new BlockchainClient(signer);
8394
+ const client = new SigningChainClient(signer);
8389
8395
  return new _AgentWalletProvider(signer, client);
8390
8396
  }
8391
8397
  async getAddress(chainId) {
@@ -8473,6 +8479,20 @@ var init_dist3 = __esm({
8473
8479
  });
8474
8480
  return result.hash;
8475
8481
  }
8482
+ async transfer(request) {
8483
+ await this.ensureConnected();
8484
+ this.resetAutoLockTimer();
8485
+ const { hash, chainKey } = await this.blockchainClient.transfer({
8486
+ ...request,
8487
+ hdWallet: this.signer.getHDWallet()
8488
+ });
8489
+ return { hash, chainKey };
8490
+ }
8491
+ async getBalance(assetId, chainKey) {
8492
+ await this.ensureConnected();
8493
+ this.resetAutoLockTimer();
8494
+ return this.blockchainClient.getOwnBalance(assetId, chainKey);
8495
+ }
8476
8496
  supportsChain(chainId) {
8477
8497
  return isChainSupported(chainId);
8478
8498
  }
@@ -8500,19 +8520,10 @@ var init_dist3 = __esm({
8500
8520
  isConnected() {
8501
8521
  return this.connected;
8502
8522
  }
8503
- getBlockchainClient() {
8504
- if (!this.connected)
8505
- throw new Error("Wallet is locked. Use an async method to trigger re-auth.");
8506
- return this.blockchainClient;
8507
- }
8508
- getSigner() {
8509
- if (!this.connected)
8510
- throw new Error("Wallet is locked. Use an async method to trigger re-auth.");
8511
- return this.signer;
8512
- }
8513
8523
  };
8514
8524
  TeeWalletProvider = class extends WalletProvider {
8515
8525
  name = "tee";
8526
+ kind = "remote";
8516
8527
  address = null;
8517
8528
  async getAddress(_chainId) {
8518
8529
  if (!this.address) throw new Error("TEE wallet not initialized");
@@ -8531,6 +8542,12 @@ var init_dist3 = __esm({
8531
8542
  async sendTransaction(_params) {
8532
8543
  throw new Error("TEE transaction sending not yet implemented");
8533
8544
  }
8545
+ async transfer() {
8546
+ throw new Error("TEE transfers not yet implemented");
8547
+ }
8548
+ async getBalance() {
8549
+ throw new Error("TEE balances not yet implemented");
8550
+ }
8534
8551
  supportsChain(_chainId) {
8535
8552
  return false;
8536
8553
  }
@@ -25724,6 +25741,17 @@ var import_chalk2 = __toESM(require_source());
25724
25741
  init_dist();
25725
25742
  init_dist3();
25726
25743
  init_dist2();
25744
+
25745
+ // src/credentials-error.ts
25746
+ init_dist();
25747
+ function credentialsMissingError() {
25748
+ return new CommandError(
25749
+ "CREDENTIALS_MISSING",
25750
+ "No API credentials found. Run `twak init` or `twak setup` (or set TWAK_ACCESS_ID and TWAK_HMAC_SECRET env vars)."
25751
+ );
25752
+ }
25753
+
25754
+ // src/config-loader.ts
25727
25755
  var EMBEDDED_NAAS_SESSION_ID = "NDVjMWRjY2MtYTYwNy00NGNhLWIxZGUtMmJiZDIyNmEyODQ4";
25728
25756
  function resolveNaasSessionId() {
25729
25757
  if (process.env.TWAK_NAAS_SESSION_ID) return process.env.TWAK_NAAS_SESSION_ID;
@@ -25731,45 +25759,41 @@ function resolveNaasSessionId() {
25731
25759
  return EMBEDDED_NAAS_SESSION_ID;
25732
25760
  return void 0;
25733
25761
  }
25734
- async function getCredentials() {
25762
+ async function loadCredentials() {
25735
25763
  const envAccessId = process.env.TWAK_ACCESS_ID;
25736
25764
  const envSecret = process.env.TWAK_HMAC_SECRET;
25737
25765
  if (envAccessId && envSecret) {
25738
25766
  return { accessId: envAccessId, hmacSecret: envSecret };
25739
25767
  }
25740
- const credManager = new CredentialManager();
25741
- const credentials = await credManager.load();
25768
+ const credentials = await new CredentialManager().load();
25742
25769
  if (credentials) {
25743
25770
  return { accessId: credentials.accessId, hmacSecret: credentials.hmacSecret };
25744
25771
  }
25745
- throw new CommandError(
25746
- "VALIDATION_ERROR",
25747
- "No API credentials found. Run `twak setup` (or set TWAK_ACCESS_ID and TWAK_HMAC_SECRET env vars)."
25748
- );
25772
+ return null;
25773
+ }
25774
+ async function getCredentials() {
25775
+ const credentials = await loadCredentials();
25776
+ if (credentials) return credentials;
25777
+ throw credentialsMissingError();
25749
25778
  }
25750
25779
  async function getClient() {
25751
25780
  const creds = await getCredentials();
25752
25781
  return createTwakClient({ ...creds });
25753
25782
  }
25754
25783
  async function tryGetClient() {
25755
- const envAccessId = process.env.TWAK_ACCESS_ID;
25756
- const envSecret = process.env.TWAK_HMAC_SECRET;
25757
- if (envAccessId && envSecret) {
25758
- return createTwakClient({ accessId: envAccessId, hmacSecret: envSecret });
25759
- }
25760
- const credentials = await new CredentialManager().load();
25761
- if (credentials) {
25762
- return createTwakClient({ accessId: credentials.accessId, hmacSecret: credentials.hmacSecret });
25763
- }
25764
- return void 0;
25784
+ const credentials = await loadCredentials();
25785
+ return credentials ? createTwakClient(credentials) : void 0;
25765
25786
  }
25766
- async function ensureTrustSDK() {
25767
- const creds = await getCredentials();
25787
+ async function initTrustSDKWithCredentials(creds) {
25768
25788
  await initTrustSDK({
25769
25789
  accessId: creds.accessId,
25770
25790
  hmacSecret: creds.hmacSecret,
25771
25791
  naasSessionId: resolveNaasSessionId()
25772
25792
  });
25793
+ }
25794
+ async function ensureTrustSDK() {
25795
+ const creds = await getCredentials();
25796
+ await initTrustSDKWithCredentials(creds);
25773
25797
  return creds;
25774
25798
  }
25775
25799
  async function registerWalletWithBackend(creds, provider) {
@@ -41715,10 +41739,10 @@ var FileKeyValueStorage = class {
41715
41739
  }
41716
41740
  };
41717
41741
  var DEFAULT_METADATA = {
41718
- name: "TWAK Agent",
41719
- description: "AI Agent for Trust Wallet operations",
41742
+ name: "TWAK",
41743
+ description: "Trust Wallet Agent Kit",
41720
41744
  url: "https://portal.trustwallet.com",
41721
- icons: ["https://avatars.githubusercontent.com/u/32179365"]
41745
+ icons: ["https://avatars.githubusercontent.com/u/32179889"]
41722
41746
  };
41723
41747
  var SESSION_CLEARED_REASON = { code: 6e3, message: "Session cleared" };
41724
41748
  var PEER_NOTIFY_TIMEOUT_MS = 5e3;
@@ -41752,6 +41776,7 @@ async function settleWithin(promise, ms3) {
41752
41776
  var WC_NOT_CONNECTED_MSG = 'WalletConnect session not established. If pairing is in progress, complete the approval in Trust Wallet mobile and retry; otherwise call switch_wallet_mode({mode: "walletconnect"}) to start pairing.';
41753
41777
  var WalletConnectProvider = class extends WalletProvider {
41754
41778
  name = "walletconnect";
41779
+ kind = "remote";
41755
41780
  client = null;
41756
41781
  initPromise = null;
41757
41782
  currentSession = null;
@@ -41903,6 +41928,43 @@ var WalletConnectProvider = class extends WalletProvider {
41903
41928
  }
41904
41929
  });
41905
41930
  }
41931
+ /**
41932
+ * EVM only: the phone signs and broadcasts. Native coins go out as a value
41933
+ * transfer, tokens as an ERC-20 `transfer` call built by the chain client.
41934
+ */
41935
+ async transfer(request) {
41936
+ const { chainKey } = request;
41937
+ const chain2 = requireChain(chainKey);
41938
+ if (chain2.namespace !== "eip155") {
41939
+ throw new TransferError(
41940
+ "CHAIN_UNSUPPORTED",
41941
+ `transfer on ${chainKey} is not supported in WalletConnect mode (EVM-only). Switch to local wallet mode for ${chainKey} transfers.`
41942
+ );
41943
+ }
41944
+ if (request.decimals === void 0) {
41945
+ throw new TransferError("VALIDATION_ERROR", `Decimals are required for ${request.assetId}`);
41946
+ }
41947
+ const atomicAmount = BigInt(parseAmount(request.amount, request.decimals));
41948
+ const { contractAddress } = parseTokenId(request.assetId);
41949
+ if (contractAddress) {
41950
+ assertEvmAddress(contractAddress, "tokenAddress");
41951
+ const { erc20: erc202 } = await Promise.resolve().then(() => (init_dist4(), dist_exports3));
41952
+ const pending = await this.config.chainClient.contract(erc202).withAddress(contractAddress, chainKey).write.transfer([request.to, atomicAmount], this);
41953
+ return { hash: pending.hash, chainKey };
41954
+ }
41955
+ assertEvmAddress(request.to, "to");
41956
+ const hash = await this.sendTransaction({
41957
+ chainId: `${chain2.namespace}:${chain2.chainId}`,
41958
+ to: request.to,
41959
+ data: "0x",
41960
+ value: "0x" + atomicAmount.toString(16)
41961
+ });
41962
+ return { hash, chainKey };
41963
+ }
41964
+ async getBalance(assetId, chainKey) {
41965
+ const address = await this.getAddress(chainKey);
41966
+ return this.config.chainClient.getBalance(assetId, address, chainKey);
41967
+ }
41906
41968
  async sendTransaction(params) {
41907
41969
  const session = this.getActiveSession();
41908
41970
  if (!session) throw new WalletError("WC_NOT_CONNECTED", WC_NOT_CONNECTED_MSG);
@@ -42193,7 +42255,10 @@ async function tryRegisterWallet() {
42193
42255
  }
42194
42256
  }
42195
42257
  function registerInitCommand(program3) {
42196
- program3.command("init").description("Initialize twak configuration").option("--api-key <key>", "TWAK API access ID (prefer TWAK_ACCESS_ID env var)").option("--api-secret <secret>", "TWAK HMAC secret (prefer TWAK_HMAC_SECRET env var)").option("--wc-project-id <id>", "WalletConnect project ID").option("--json", "JSON output").action(async (opts) => {
42258
+ program3.command("init").description("Initialize twak configuration").option("--api-key <key>", "TWAK API access ID (prefer TWAK_ACCESS_ID env var)").option("--api-secret <secret>", "TWAK HMAC secret (prefer TWAK_HMAC_SECRET env var)").option(
42259
+ "--wc-project-id <id>",
42260
+ "WalletConnect project ID override (default: Trust Wallet project)"
42261
+ ).option("--json", "JSON output").action(async (opts) => {
42197
42262
  try {
42198
42263
  const credManager = new CredentialManager();
42199
42264
  if (opts.apiKey && opts.apiSecret) {
@@ -42558,8 +42623,8 @@ async function runInteractive(deps) {
42558
42623
  const hmacSecret = (await deps.prompter.promptHmacSecret()).trim();
42559
42624
  info(
42560
42625
  `
42561
- WalletConnect Project ID is only used when signing via WalletConnect in MCP mode.
42562
- Skip if you only plan to use the local agent wallet. Get one at: ${WC_DASHBOARD_URL}
42626
+ WalletConnect Project ID is optional: twak uses Trust Wallet's project by default.
42627
+ Set one only to use your own project. Get one at: ${WC_DASHBOARD_URL}
42563
42628
  `
42564
42629
  );
42565
42630
  const walletConnectProjectId = (await deps.prompter.promptWalletConnectProjectId())?.trim() || void 0;
@@ -43107,7 +43172,10 @@ var import_chalk4 = __toESM(require_source());
43107
43172
  init_dist2();
43108
43173
  function registerAuthCommand(program3) {
43109
43174
  const auth = program3.command("auth").description("Manage authentication");
43110
- auth.command("setup").description("Set up API credentials").requiredOption("--api-key <key>", "TWAK API access ID").requiredOption("--api-secret <secret>", "TWAK HMAC secret").option("--wc-project-id <id>", "WalletConnect project ID").action(async (opts) => {
43175
+ auth.command("setup").description("Set up API credentials").requiredOption("--api-key <key>", "TWAK API access ID").requiredOption("--api-secret <secret>", "TWAK HMAC secret").option(
43176
+ "--wc-project-id <id>",
43177
+ "WalletConnect project ID override (default: Trust Wallet project)"
43178
+ ).action(async (opts) => {
43111
43179
  const credManager = new CredentialManager();
43112
43180
  await credManager.save({
43113
43181
  accessId: opts.apiKey,
@@ -43126,7 +43194,9 @@ function registerAuthCommand(program3) {
43126
43194
  if (opts.json) {
43127
43195
  output({ configured, source, accessId }, true);
43128
43196
  } else {
43129
- console.log(` ${import_chalk4.default.dim("Status")} ${configured ? import_chalk4.default.green("configured") : import_chalk4.default.yellow("not configured")}`);
43197
+ console.log(
43198
+ ` ${import_chalk4.default.dim("Status")} ${configured ? import_chalk4.default.green("configured") : import_chalk4.default.yellow("not configured")}`
43199
+ );
43130
43200
  console.log(` ${import_chalk4.default.dim("Source")} ${source}`);
43131
43201
  if (accessId) console.log(` ${import_chalk4.default.dim("Access ID")} ${accessId}...`);
43132
43202
  if (!configured) info("\nRun `twak init` to set up credentials.");
@@ -43178,9 +43248,6 @@ function mapBroadcastError(err) {
43178
43248
  }
43179
43249
  throw err;
43180
43250
  }
43181
- function hasLocalSigner(wallet) {
43182
- return typeof wallet.getSigner === "function";
43183
- }
43184
43251
  var TransferExecutor = class {
43185
43252
  constructor(deps) {
43186
43253
  this.deps = deps;
@@ -43199,7 +43266,7 @@ var TransferExecutor = class {
43199
43266
  }
43200
43267
  }
43201
43268
  async run(params) {
43202
- const { wallet, swapClient, blockchainClient, onInfo, onWarn } = this.deps;
43269
+ const { wallet, swapClient, onInfo, onWarn } = this.deps;
43203
43270
  const chainKey = resolveChain(params.chain);
43204
43271
  const contractAddress = params.tokenAddress && params.tokenAddress.toLowerCase() !== NATIVE_TOKEN_ADDRESS.toLowerCase() ? params.tokenAddress : void 0;
43205
43272
  const { assetId } = resolveAsset(chainKey, contractAddress);
@@ -43237,7 +43304,7 @@ var TransferExecutor = class {
43237
43304
  isNative: !contractAddress,
43238
43305
  explicitDecimals: params.decimals ?? null
43239
43306
  });
43240
- const atomicAmount = parseAmount(params.amount, decimals);
43307
+ parseAmount(params.amount, decimals);
43241
43308
  if (!params.safety?.skip) {
43242
43309
  const maxUsd = params.safety?.maxUsd ?? DEFAULT_MAX_TRANSFER_USD;
43243
43310
  const warnThreshold = params.safety?.warnThresholdUsd ?? DEFAULT_WARN_THRESHOLD_USD;
@@ -43263,80 +43330,30 @@ var TransferExecutor = class {
43263
43330
  );
43264
43331
  }
43265
43332
  }
43266
- let hash;
43267
- let resultChainKey = chainKey;
43268
- if (hasLocalSigner(wallet)) {
43269
- if (!blockchainClient) {
43270
- throw new TransferError(
43271
- "WALLET_NOT_FOUND",
43272
- "BlockchainClient not available \u2014 local transfer requires a configured blockchain client"
43273
- );
43274
- }
43275
- const from8 = await wallet.getAddress(chainKey);
43276
- onInfo?.(`Sending from ${from8} on ${chainKey}...`);
43277
- const hdWallet = wallet.getSigner().getHDWallet();
43278
- try {
43279
- const result = await blockchainClient.transfer({
43280
- assetId,
43281
- to: resolvedTo,
43282
- amount: params.amount,
43283
- decimals,
43284
- memo: params.memo,
43285
- hdWallet,
43286
- chainKey
43287
- });
43288
- hash = result.hash;
43289
- resultChainKey = result.chainKey;
43290
- } catch (err) {
43291
- mapBroadcastError(err);
43292
- }
43293
- const explorerUrl2 = getExplorerTxUrl(resultChainKey, hash);
43294
- return {
43295
- success: true,
43296
- hash,
43297
- chainKey: resultChainKey,
43333
+ const local = wallet.kind === "local";
43334
+ const from8 = local ? await wallet.getAddress(chainKey) : "";
43335
+ if (local) onInfo?.(`Sending from ${from8} on ${chainKey}...`);
43336
+ let receipt;
43337
+ try {
43338
+ receipt = await wallet.transfer({
43339
+ chainKey,
43298
43340
  assetId,
43299
- from: from8,
43300
- to: resolvedTo,
43301
- resolvedFrom,
43302
- explorerUrl: explorerUrl2 || void 0
43303
- };
43304
- }
43305
- const chain2 = requireChain(chainKey);
43306
- if (chain2.namespace !== "eip155") {
43307
- throw new TransferError(
43308
- "CHAIN_UNSUPPORTED",
43309
- `transfer on ${chainKey} is not supported in WalletConnect mode (EVM-only). Switch to local wallet mode for ${chainKey} transfers.`
43310
- );
43311
- }
43312
- const caip2 = `${chain2.namespace}:${chain2.chainId}`;
43313
- if (contractAddress) {
43314
- assertEvmAddress(contractAddress, "tokenAddress");
43315
- if (!blockchainClient) {
43316
- throw new TransferError(
43317
- "WALLET_NOT_FOUND",
43318
- "BlockchainClient not available \u2014 ERC-20 transfer requires a configured blockchain client"
43319
- );
43320
- }
43321
- const { erc20: erc202 } = await Promise.resolve().then(() => (init_dist4(), dist_exports3));
43322
- const pending = await blockchainClient.contract(erc202).withAddress(contractAddress, chainKey).write.transfer([resolvedTo, BigInt(atomicAmount)], wallet);
43323
- hash = pending.hash;
43324
- } else {
43325
- assertEvmAddress(resolvedTo, "to");
43326
- hash = await wallet.sendTransaction({
43327
- chainId: caip2,
43328
43341
  to: resolvedTo,
43329
- data: "0x",
43330
- value: "0x" + BigInt(atomicAmount).toString(16)
43342
+ amount: params.amount,
43343
+ decimals,
43344
+ memo: params.memo
43331
43345
  });
43346
+ } catch (err) {
43347
+ if (local) mapBroadcastError(err);
43348
+ throw err;
43332
43349
  }
43333
- const explorerUrl = getExplorerTxUrl(chainKey, hash);
43350
+ const explorerUrl = getExplorerTxUrl(receipt.chainKey, receipt.hash);
43334
43351
  return {
43335
43352
  success: true,
43336
- hash,
43337
- chainKey,
43353
+ hash: receipt.hash,
43354
+ chainKey: receipt.chainKey,
43338
43355
  assetId,
43339
- from: "",
43356
+ from: from8,
43340
43357
  to: resolvedTo,
43341
43358
  resolvedFrom,
43342
43359
  explorerUrl: explorerUrl || void 0
@@ -43813,19 +43830,21 @@ var RESTORE_TIMEOUT_MS = 1e4;
43813
43830
  function wcStoragePath() {
43814
43831
  return path4.join(new FileStore().getDataDir(), "walletconnect.json");
43815
43832
  }
43833
+ var DEFAULT_WC_PROJECT_ID = "a863b78b54c4222603c8db4d6d880172";
43816
43834
  async function resolveWcProjectId(flag) {
43817
43835
  const fromFlagOrEnv = flag || process.env.WALLETCONNECT_PROJECT_ID;
43818
43836
  if (fromFlagOrEnv) return fromFlagOrEnv;
43819
43837
  try {
43820
43838
  const creds = await new CredentialManager().load();
43821
- return creds?.walletConnectProjectId || void 0;
43839
+ return creds?.walletConnectProjectId || DEFAULT_WC_PROJECT_ID;
43822
43840
  } catch {
43823
- return void 0;
43841
+ return DEFAULT_WC_PROJECT_ID;
43824
43842
  }
43825
43843
  }
43826
- function createWalletConnectProvider(projectId) {
43844
+ function createWalletConnectProvider(projectId, chainClient) {
43827
43845
  return new WalletConnectProvider({
43828
43846
  projectId,
43847
+ chainClient,
43829
43848
  storagePath: wcStoragePath(),
43830
43849
  onStorageWarning: (msg) => warn(msg)
43831
43850
  });
@@ -43858,17 +43877,10 @@ function getQRString(address) {
43858
43877
  return "";
43859
43878
  }
43860
43879
  }
43861
- var WC_PROJECT_ID_HINT = "Use --project-id, set WALLETCONNECT_PROJECT_ID, or run `twak init --wc-project-id <id>`";
43862
43880
  async function openStoredWalletConnect(projectIdFlag) {
43863
43881
  if (!fs6.existsSync(wcStoragePath())) return null;
43864
43882
  const projectId = await resolveWcProjectId(projectIdFlag);
43865
- if (!projectId) {
43866
- throw new WalletError(
43867
- "VALIDATION_ERROR",
43868
- `A WalletConnect session is stored but no project ID is configured. ${WC_PROJECT_ID_HINT}`
43869
- );
43870
- }
43871
- const provider = createWalletConnectProvider(projectId);
43883
+ const provider = createWalletConnectProvider(projectId, new ChainClient());
43872
43884
  const session = await withTimeout(provider.restore(), RESTORE_TIMEOUT_MS);
43873
43885
  return { provider, session };
43874
43886
  }
@@ -44169,20 +44181,14 @@ ${qr3}`;
44169
44181
  });
44170
44182
  wallet.command("connect").description("Connect external wallet via WalletConnect").option(
44171
44183
  "--project-id <id>",
44172
- "WalletConnect project ID (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44184
+ "WalletConnect project ID override (default: Trust Wallet project; or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44173
44185
  ).option(
44174
44186
  "--chains <list>",
44175
44187
  "Comma-separated CAIP-2 chain IDs (default: all supported EVM chains)"
44176
44188
  ).option("--timeout <seconds>", "Connection timeout in seconds", "300").option("--json", "JSON output").action(async (opts) => {
44177
44189
  try {
44178
44190
  const projectId = await resolveWcProjectId(opts.projectId);
44179
- if (!projectId) {
44180
- throw new WalletError(
44181
- "VALIDATION_ERROR",
44182
- `WalletConnect project ID required. ${WC_PROJECT_ID_HINT}`
44183
- );
44184
- }
44185
- const provider = createWalletConnectProvider(projectId);
44191
+ const provider = createWalletConnectProvider(projectId, new ChainClient());
44186
44192
  const chains = opts.chains ? opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean) : getDefaultWcChains();
44187
44193
  info("Connecting via WalletConnect...");
44188
44194
  const result = await provider.connect(chains);
@@ -44217,7 +44223,7 @@ ${qr3}`;
44217
44223
  });
44218
44224
  wallet.command("disconnect").description("Revoke the stored WalletConnect session").option(
44219
44225
  "--project-id <id>",
44220
- "WalletConnect project ID (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44226
+ "WalletConnect project ID override (default: Trust Wallet project; or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44221
44227
  ).option("--json", "JSON output").action(async (opts) => {
44222
44228
  try {
44223
44229
  const stored = await openStoredWalletConnect(opts.projectId);
@@ -44239,7 +44245,7 @@ ${qr3}`;
44239
44245
  });
44240
44246
  wallet.command("status").description("Check wallet configuration status").option(
44241
44247
  "--project-id <id>",
44242
- "WalletConnect project ID used to check the stored session (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44248
+ "WalletConnect project ID override used to check the stored session (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
44243
44249
  ).option("--json", "JSON output").action(async (opts) => {
44244
44250
  try {
44245
44251
  const store = new WalletConfigStore();
@@ -44543,7 +44549,7 @@ function classifySwapError(message) {
44543
44549
  return "TX_FAILED";
44544
44550
  }
44545
44551
  var SwapExecutor = class {
44546
- constructor(swapClient, walletProvider, options = {}) {
44552
+ constructor(swapClient, walletProvider, options) {
44547
44553
  this.swapClient = swapClient;
44548
44554
  this.walletProvider = walletProvider;
44549
44555
  this.options = options;
@@ -44679,7 +44685,7 @@ var SwapExecutor = class {
44679
44685
  const fromAssetAddr = route.steps[0].from.asset.address;
44680
44686
  if (!fromAssetAddr || fromAssetAddr.toLowerCase() === NATIVE_TOKEN_ADDRESS.toLowerCase())
44681
44687
  return void 0;
44682
- const blockchainClient = this.getBlockchainClient();
44688
+ const blockchainClient = this.options.chainClient;
44683
44689
  const allowance = await blockchainClient.contract(erc20).withAddress(fromAssetAddr, fromChain).read.allowance([address, stepApproval.operatorAddress]);
44684
44690
  const required = BigInt(stepApproval.minAmount || parsedAmount);
44685
44691
  if (allowance >= required) return void 0;
@@ -44688,14 +44694,6 @@ var SwapExecutor = class {
44688
44694
  this.log(`Approval tx: ${getExplorerTxUrl(fromChain, approveResult.hash)}`);
44689
44695
  return approveResult.hash;
44690
44696
  }
44691
- getBlockchainClient() {
44692
- const blockchainClient = this.walletProvider.getBlockchainClient?.() ?? this.options.blockchainClient;
44693
- if (!blockchainClient)
44694
- throw new Error(
44695
- "Wallet provider does not support on-chain reads; cannot check allowance or confirm transactions"
44696
- );
44697
- return blockchainClient;
44698
- }
44699
44697
  async sendTransaction(txData, chainConfig, fromChain) {
44700
44698
  if (chainConfig?.namespace === "solana" && txData.transaction.solanaTx) {
44701
44699
  return this.walletProvider.sendTransaction({
@@ -44714,7 +44712,7 @@ var SwapExecutor = class {
44714
44712
  throw new Error(`No transaction data returned for swap step on ${fromChain}`);
44715
44713
  }
44716
44714
  async pollForConfirmation(chainKey, address, hash, timeoutMs) {
44717
- const blockchainClient = this.getBlockchainClient();
44715
+ const blockchainClient = this.options.chainClient;
44718
44716
  const deadline = Date.now() + timeoutMs;
44719
44717
  while (Date.now() < deadline) {
44720
44718
  await new Promise((r3) => setTimeout(r3, 2e3));
@@ -44851,7 +44849,6 @@ function registerTransferCommand(program3) {
44851
44849
  const executor = new TransferExecutor({
44852
44850
  wallet: provider,
44853
44851
  swapClient,
44854
- blockchainClient: provider.getBlockchainClient(),
44855
44852
  onInfo: info,
44856
44853
  onWarn: warn
44857
44854
  });
@@ -45058,6 +45055,7 @@ function registerSwapCommand(program3) {
45058
45055
  return;
45059
45056
  }
45060
45057
  const executor = new SwapExecutor(swapClient, provider, {
45058
+ chainClient: new ChainClient(),
45061
45059
  onStatus: info
45062
45060
  });
45063
45061
  const result = await executor.execute({
@@ -45158,7 +45156,7 @@ function registerErc20Command(program3) {
45158
45156
  warn("WARNING: Unlimited approval grants the spender access to ALL tokens of this type.");
45159
45157
  }
45160
45158
  info(`Approving ${opts.spender} to spend from ${address} on ${chainKey}...`);
45161
- const client = provider.getBlockchainClient();
45159
+ const client = new ChainClient();
45162
45160
  const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, BigInt(amount)], provider);
45163
45161
  const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
45164
45162
  success("Approval sent!");
@@ -45199,7 +45197,7 @@ function registerErc20Command(program3) {
45199
45197
  );
45200
45198
  const address = await provider.getAddress(chainKey);
45201
45199
  info(`Revoking approval for ${opts.spender} on ${chainKey}...`);
45202
- const client = provider.getBlockchainClient();
45200
+ const client = new ChainClient();
45203
45201
  const pending = await client.contract(erc20).withAddress(contractAddress, chainKey).write.approve([opts.spender, 0n], provider);
45204
45202
  const explorerUrl = getExplorerTxUrl(chainKey, pending.hash);
45205
45203
  success("Approval revoked!");
@@ -45279,7 +45277,7 @@ function registerErc20Command(program3) {
45279
45277
  contractAddress = parsed;
45280
45278
  chainKey = k4;
45281
45279
  }
45282
- const client = new BlockchainClient();
45280
+ const client = new ChainClient();
45283
45281
  const allowance = await client.contract(erc20).withAddress(contractAddress, chainKey).read.allowance([opts.owner, opts.spender]);
45284
45282
  output(
45285
45283
  {
@@ -45333,10 +45331,10 @@ function registerErc8004Command(program3) {
45333
45331
  await ensureTrustSDK();
45334
45332
  const password3 = await resolvePassword(opts);
45335
45333
  const provider = await AgentWalletProvider.fromStorage(password3);
45336
- const ops = new Erc8004Operations(
45337
- resolveErc8004Contract(provider.getBlockchainClient(), opts.chain),
45338
- { signer: provider, onInfo: info }
45339
- );
45334
+ const ops = new Erc8004Operations(resolveErc8004Contract(new ChainClient(), opts.chain), {
45335
+ signer: provider,
45336
+ onInfo: info
45337
+ });
45340
45338
  const result = await ops.register({
45341
45339
  agentURI: opts.uri,
45342
45340
  metadata: parseMetadataPairs(opts.metadata)
@@ -45372,10 +45370,10 @@ function registerErc8004Command(program3) {
45372
45370
  await ensureTrustSDK();
45373
45371
  const password3 = await resolvePassword(opts);
45374
45372
  const provider = await AgentWalletProvider.fromStorage(password3);
45375
- const ops = new Erc8004Operations(
45376
- resolveErc8004Contract(provider.getBlockchainClient(), opts.chain),
45377
- { signer: provider, onInfo: info }
45378
- );
45373
+ const ops = new Erc8004Operations(resolveErc8004Contract(new ChainClient(), opts.chain), {
45374
+ signer: provider,
45375
+ onInfo: info
45376
+ });
45379
45377
  const result = await ops.setUri({ agentId, agentURI: opts.uri });
45380
45378
  success("agentURI updated!");
45381
45379
  output(
@@ -45403,10 +45401,10 @@ function registerErc8004Command(program3) {
45403
45401
  await ensureTrustSDK();
45404
45402
  const password3 = await resolvePassword(opts);
45405
45403
  const provider = await AgentWalletProvider.fromStorage(password3);
45406
- const ops = new Erc8004Operations(
45407
- resolveErc8004Contract(provider.getBlockchainClient(), opts.chain),
45408
- { signer: provider, onInfo: info }
45409
- );
45404
+ const ops = new Erc8004Operations(resolveErc8004Contract(new ChainClient(), opts.chain), {
45405
+ signer: provider,
45406
+ onInfo: info
45407
+ });
45410
45408
  const result = await ops.setMetadata({ agentId, key: opts.key, value: opts.value });
45411
45409
  success("Metadata set!");
45412
45410
  output(
@@ -45433,9 +45431,7 @@ function registerErc8004Command(program3) {
45433
45431
  try {
45434
45432
  parseAgentId(agentId);
45435
45433
  await ensureTrustSDK();
45436
- const ops = new Erc8004Operations(
45437
- resolveErc8004Contract(new BlockchainClient(), opts.chain)
45438
- );
45434
+ const ops = new Erc8004Operations(resolveErc8004Contract(new ChainClient(), opts.chain));
45439
45435
  const result = await ops.getMetadata({ agentId, key: opts.key });
45440
45436
  output(
45441
45437
  { agentId, key: result.key, value: result.value, chain: result.chainKey },
@@ -45454,9 +45450,7 @@ function registerErc8004Command(program3) {
45454
45450
  try {
45455
45451
  parseAgentId(agentId);
45456
45452
  await ensureTrustSDK();
45457
- const ops = new Erc8004Operations(
45458
- resolveErc8004Contract(new BlockchainClient(), opts.chain)
45459
- );
45453
+ const ops = new Erc8004Operations(resolveErc8004Contract(new ChainClient(), opts.chain));
45460
45454
  const result = await ops.show({ agentId });
45461
45455
  output(
45462
45456
  {
@@ -45498,7 +45492,7 @@ function registerErc8183Command(program3) {
45498
45492
  await ensureTrustSDK();
45499
45493
  const password3 = await resolvePassword(opts);
45500
45494
  const provider = await AgentWalletProvider.fromStorage(password3);
45501
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45495
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45502
45496
  const result = await ops.createJob({
45503
45497
  provider: opts.provider,
45504
45498
  evaluator: opts.evaluator,
@@ -45529,7 +45523,7 @@ function registerErc8183Command(program3) {
45529
45523
  await ensureTrustSDK();
45530
45524
  const password3 = await resolvePassword(opts);
45531
45525
  const provider = await AgentWalletProvider.fromStorage(password3);
45532
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45526
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45533
45527
  const result = await ops.setProvider({
45534
45528
  jobId,
45535
45529
  provider: opts.provider,
@@ -45559,7 +45553,7 @@ function registerErc8183Command(program3) {
45559
45553
  await ensureTrustSDK();
45560
45554
  const password3 = await resolvePassword(opts);
45561
45555
  const provider = await AgentWalletProvider.fromStorage(password3);
45562
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45556
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45563
45557
  const result = await ops.setBudget({
45564
45558
  jobId,
45565
45559
  amount: opts.amount,
@@ -45591,7 +45585,7 @@ function registerErc8183Command(program3) {
45591
45585
  await ensureTrustSDK();
45592
45586
  const password3 = await resolvePassword(opts);
45593
45587
  const provider = await AgentWalletProvider.fromStorage(password3);
45594
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45588
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45595
45589
  const result = await ops.fund({
45596
45590
  jobId,
45597
45591
  expectedBudget: opts.expectedBudget,
@@ -45621,7 +45615,7 @@ function registerErc8183Command(program3) {
45621
45615
  await ensureTrustSDK();
45622
45616
  const password3 = await resolvePassword(opts);
45623
45617
  const provider = await AgentWalletProvider.fromStorage(password3);
45624
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45618
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45625
45619
  const result = await ops.submit({
45626
45620
  jobId,
45627
45621
  deliverable: opts.deliverable,
@@ -45650,7 +45644,7 @@ function registerErc8183Command(program3) {
45650
45644
  await ensureTrustSDK();
45651
45645
  const password3 = await resolvePassword(opts);
45652
45646
  const provider = await AgentWalletProvider.fromStorage(password3);
45653
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45647
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45654
45648
  const result = await ops.complete({
45655
45649
  jobId,
45656
45650
  reason: opts.reason,
@@ -45680,7 +45674,7 @@ function registerErc8183Command(program3) {
45680
45674
  await ensureTrustSDK();
45681
45675
  const password3 = await resolvePassword(opts);
45682
45676
  const provider = await AgentWalletProvider.fromStorage(password3);
45683
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45677
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45684
45678
  const result = await ops.reject({
45685
45679
  jobId,
45686
45680
  reason: opts.reason,
@@ -45709,7 +45703,7 @@ function registerErc8183Command(program3) {
45709
45703
  await ensureTrustSDK();
45710
45704
  const password3 = await resolvePassword(opts);
45711
45705
  const provider = await AgentWalletProvider.fromStorage(password3);
45712
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45706
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45713
45707
  const result = await ops.claimRefund({ jobId });
45714
45708
  success("Refund claimed!");
45715
45709
  output(
@@ -45732,7 +45726,7 @@ function registerErc8183Command(program3) {
45732
45726
  try {
45733
45727
  parseUint(jobId, "jobId");
45734
45728
  await ensureTrustSDK();
45735
- const ops = buildOps(new BlockchainClient(), opts.chain);
45729
+ const ops = buildOps(new ChainClient(), opts.chain);
45736
45730
  const result = await ops.status({ jobId });
45737
45731
  output(
45738
45732
  {
@@ -45763,7 +45757,7 @@ function registerErc8183Command(program3) {
45763
45757
  await ensureTrustSDK();
45764
45758
  const password3 = await resolvePassword(opts);
45765
45759
  const provider = await AgentWalletProvider.fromStorage(password3);
45766
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45760
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45767
45761
  const result = await ops.registerJob({ jobId, policy: opts.policy });
45768
45762
  success("Job registered!");
45769
45763
  output(
@@ -45787,7 +45781,7 @@ function registerErc8183Command(program3) {
45787
45781
  await ensureTrustSDK();
45788
45782
  const password3 = await resolvePassword(opts);
45789
45783
  const provider = await AgentWalletProvider.fromStorage(password3);
45790
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45784
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45791
45785
  const result = await ops.settle({ jobId, evidence: opts.evidence });
45792
45786
  success("Job settled!");
45793
45787
  output(
@@ -45810,7 +45804,7 @@ function registerErc8183Command(program3) {
45810
45804
  await ensureTrustSDK();
45811
45805
  const password3 = await resolvePassword(opts);
45812
45806
  const provider = await AgentWalletProvider.fromStorage(password3);
45813
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45807
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45814
45808
  const result = await ops.markExpired({ jobId });
45815
45809
  success("Job marked expired!");
45816
45810
  output(
@@ -45832,7 +45826,7 @@ function registerErc8183Command(program3) {
45832
45826
  try {
45833
45827
  parseUint(jobId, "jobId");
45834
45828
  await ensureTrustSDK();
45835
- const ops = buildOps(new BlockchainClient(), opts.chain);
45829
+ const ops = buildOps(new ChainClient(), opts.chain);
45836
45830
  const result = await ops.policyInfo({ jobId });
45837
45831
  output(
45838
45832
  {
@@ -45861,7 +45855,7 @@ function registerErc8183Command(program3) {
45861
45855
  await ensureTrustSDK();
45862
45856
  const password3 = await resolvePassword(opts);
45863
45857
  const provider = await AgentWalletProvider.fromStorage(password3);
45864
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45858
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45865
45859
  const result = await ops.dispute({ jobId });
45866
45860
  success("Dispute raised!");
45867
45861
  output(
@@ -45884,7 +45878,7 @@ function registerErc8183Command(program3) {
45884
45878
  await ensureTrustSDK();
45885
45879
  const password3 = await resolvePassword(opts);
45886
45880
  const provider = await AgentWalletProvider.fromStorage(password3);
45887
- const ops = buildOps(provider.getBlockchainClient(), opts.chain, provider);
45881
+ const ops = buildOps(new ChainClient(), opts.chain, provider);
45888
45882
  const result = await ops.voteReject({ jobId });
45889
45883
  success("Reject vote cast!");
45890
45884
  output(
@@ -45919,7 +45913,7 @@ function registerCompeteCommand(program3) {
45919
45913
  await ensureTrustSDK();
45920
45914
  const password3 = await resolvePassword(opts);
45921
45915
  const provider = await AgentWalletProvider.fromStorage(password3);
45922
- const { contract, chainKey } = resolveCompetitionContract(provider.getBlockchainClient());
45916
+ const { contract, chainKey } = resolveCompetitionContract(new ChainClient());
45923
45917
  const participant = await provider.getAddress(chainKey);
45924
45918
  const [start, deadline, alreadyRegistered] = await Promise.all([
45925
45919
  contract.read.registrationStart([]),
@@ -45988,7 +45982,7 @@ function registerCompeteCommand(program3) {
45988
45982
  await ensureTrustSDK();
45989
45983
  const password3 = await resolvePassword(opts);
45990
45984
  const provider = await AgentWalletProvider.fromStorage(password3);
45991
- const { contract, chainKey } = resolveCompetitionContract(provider.getBlockchainClient());
45985
+ const { contract, chainKey } = resolveCompetitionContract(new ChainClient());
45992
45986
  const participant = await provider.getAddress(chainKey);
45993
45987
  const [registered, start, deadline] = await Promise.all([
45994
45988
  contract.read.isRegistered([participant]),
@@ -46799,8 +46793,8 @@ function registerQueryCommand(program3) {
46799
46793
  }
46800
46794
  if (address) {
46801
46795
  await ensureTrustSDK();
46802
- const blockchainClient = new BlockchainClient();
46803
- const status = await blockchainClient.findTransactionStatus(opts.chain, address, hash);
46796
+ const chainClient = new ChainClient();
46797
+ const status = await chainClient.findTransactionStatus(opts.chain, address, hash);
46804
46798
  output(
46805
46799
  {
46806
46800
  hash,
@@ -47548,7 +47542,7 @@ async function payAndFetch(args) {
47548
47542
  if (!confirmed) {
47549
47543
  throw new X402Error("PAYMENT_CANCELLED", "Payment cancelled by user");
47550
47544
  }
47551
- const bc2 = new BlockchainClient();
47545
+ const bc2 = new ChainClient();
47552
47546
  const fromAddress = await args.provider.getAddress(chainKey);
47553
47547
  const tokenAddress = getAsset(kind);
47554
47548
  const amount = getAmount(kind);
@@ -48126,11 +48120,10 @@ var BalanceActionProvider = class extends ActionProvider {
48126
48120
  };
48127
48121
  var DEFAULT_MAX_TRANSFER_USD3 = 1e4;
48128
48122
  var TransferActionProvider = class extends ActionProvider {
48129
- constructor(walletContext, swapClient, blockchainClient, maxTransferUsd = DEFAULT_MAX_TRANSFER_USD3) {
48123
+ constructor(walletContext, swapClient, maxTransferUsd = DEFAULT_MAX_TRANSFER_USD3) {
48130
48124
  super();
48131
48125
  this.walletContext = walletContext;
48132
48126
  this.swapClient = swapClient;
48133
- this.blockchainClient = blockchainClient;
48134
48127
  this.maxTransferUsd = maxTransferUsd;
48135
48128
  }
48136
48129
  name = "transfer";
@@ -48159,8 +48152,7 @@ var TransferActionProvider = class extends ActionProvider {
48159
48152
  const wallet = this.walletContext.activeWallet();
48160
48153
  const executor = new TransferExecutor({
48161
48154
  wallet,
48162
- swapClient: this.swapClient,
48163
- blockchainClient: this.blockchainClient
48155
+ swapClient: this.swapClient
48164
48156
  });
48165
48157
  const result = await executor.execute({
48166
48158
  chain: input2.chain,
@@ -48240,8 +48232,11 @@ var SwapActionProvider = class extends ActionProvider {
48240
48232
  message: `Unknown token: ${input2.toToken} on ${toChain}`
48241
48233
  };
48242
48234
  }
48235
+ if (!this.blockchainClient) {
48236
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
48237
+ }
48243
48238
  const executor = new SwapExecutor(this.swapClient, signer, {
48244
- blockchainClient: this.blockchainClient
48239
+ chainClient: this.blockchainClient
48245
48240
  });
48246
48241
  const result = await executor.execute({
48247
48242
  fromChain,
@@ -48590,9 +48585,8 @@ var AlertActionProvider = class extends ActionProvider {
48590
48585
  }
48591
48586
  };
48592
48587
  var AgentWalletActionProvider = class extends ActionProvider {
48593
- constructor(blockchainClient, walletContext) {
48588
+ constructor(walletContext) {
48594
48589
  super();
48595
- this.blockchainClient = blockchainClient;
48596
48590
  this.walletContext = walletContext;
48597
48591
  }
48598
48592
  name = "agent-wallet";
@@ -48641,10 +48635,7 @@ var AgentWalletActionProvider = class extends ActionProvider {
48641
48635
  const { chainKey, assetId } = resolveAsset(input2.chain);
48642
48636
  const wallet = this.requireWallet();
48643
48637
  const address = await wallet.getAddress(chainKey);
48644
- if (!this.blockchainClient) {
48645
- return { chain: chainKey, address, balance: "BlockchainClient not available" };
48646
- }
48647
- const balance = await this.blockchainClient.getBalance(assetId, address, chainKey);
48638
+ const balance = await wallet.getBalance(assetId, chainKey);
48648
48639
  return { chain: chainKey, address, balance };
48649
48640
  }
48650
48641
  };
@@ -48695,7 +48686,7 @@ var TokenActionProvider = class extends ActionProvider {
48695
48686
  }),
48696
48687
  invoke: async (_ctx, input2) => {
48697
48688
  if (!this.blockchainClient) {
48698
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
48689
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
48699
48690
  }
48700
48691
  const { chainKey, assetId } = resolveAsset(input2.chain, input2.tokenAddress);
48701
48692
  const balance = await this.blockchainClient.getBalance(assetId, input2.address, chainKey);
@@ -48726,7 +48717,7 @@ var TokenActionProvider = class extends ActionProvider {
48726
48717
  assertEvmAddress(input2.tokenAddress, "tokenAddress");
48727
48718
  assertEvmAddress(input2.spender, "spender");
48728
48719
  if (!this.blockchainClient) {
48729
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
48720
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
48730
48721
  }
48731
48722
  const amount = input2.amount === "unlimited" ? "115792089237316195423570985008687907853269984665640564039457584007913129639935" : input2.amount;
48732
48723
  const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, BigInt(amount)], wallet);
@@ -48756,7 +48747,7 @@ var TokenActionProvider = class extends ActionProvider {
48756
48747
  assertEvmAddress(input2.tokenAddress, "tokenAddress");
48757
48748
  assertEvmAddress(input2.spender, "spender");
48758
48749
  if (!this.blockchainClient) {
48759
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
48750
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
48760
48751
  }
48761
48752
  const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.approve([input2.spender, 0n], wallet);
48762
48753
  return { hash: pending.hash, chain: chainKey };
@@ -48775,7 +48766,7 @@ var TokenActionProvider = class extends ActionProvider {
48775
48766
  }),
48776
48767
  invoke: async (_ctx, input2) => {
48777
48768
  if (!this.blockchainClient) {
48778
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
48769
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
48779
48770
  }
48780
48771
  const chainKey = resolveChain(input2.chain);
48781
48772
  const allowance = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).read.allowance([input2.owner, input2.spender]);
@@ -49234,7 +49225,7 @@ var OnrampActionProvider = class extends ActionProvider {
49234
49225
  if (!this.blockchainClient) {
49235
49226
  throw new TransferError(
49236
49227
  "WALLET_NOT_FOUND",
49237
- "BlockchainClient not available \u2014 off-ramp token payout requires a configured blockchain client"
49228
+ "Chain client not available \u2014 off-ramp token payout requires a configured blockchain client"
49238
49229
  );
49239
49230
  }
49240
49231
  const pending = await this.blockchainClient.contract(erc20).withAddress(input2.tokenAddress, chainKey).write.transfer([input2.depositAddress, BigInt(atomic)], signer);
@@ -49413,8 +49404,11 @@ var AutomateActionProvider = class extends ActionProvider {
49413
49404
  message: `Unknown token: ${record2.toToken} on ${record2.chain}`
49414
49405
  };
49415
49406
  }
49407
+ if (!this.blockchainClient) {
49408
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
49409
+ }
49416
49410
  const executor = new SwapExecutor(this.swapClient, walletProvider, {
49417
- blockchainClient: this.blockchainClient
49411
+ chainClient: this.blockchainClient
49418
49412
  });
49419
49413
  const result = await executeAutomation(record2, {
49420
49414
  executor,
@@ -49538,10 +49532,21 @@ var WalletModeActionProvider = class extends ActionProvider {
49538
49532
  description = "Switch wallet modes mid-session. The local agent wallet is auto-bound at server startup when configured, so signing actions work out of the box without calling this. Only call switch_wallet_mode when the user explicitly asks to use WalletConnect (or to return to the local wallet afterwards).";
49539
49533
  walletContext;
49540
49534
  agentWallet;
49535
+ /**
49536
+ * `agentWallet` resolves the agent wallet on each switch to local mode,
49537
+ * loading it if needed, so a wallet created or unlocked after construction
49538
+ * is used. It rejects with a typed WalletError (WALLET_NOT_FOUND,
49539
+ * PASSWORD_MISSING, WALLET_AUTH_FAILED), which surfaces as is.
49540
+ */
49541
49541
  constructor(options) {
49542
49542
  super();
49543
49543
  this.walletContext = options.walletContext;
49544
- this.agentWallet = options.agentWallet;
49544
+ this.agentWallet = options.agentWallet ?? (async () => {
49545
+ throw new WalletError(
49546
+ "WALLET_NOT_FOUND",
49547
+ "No local agent wallet is available. Create one with `twak wallet create`."
49548
+ );
49549
+ });
49545
49550
  }
49546
49551
  getActions() {
49547
49552
  return [this.switchWalletMode(), this.getWalletStatus()];
@@ -49575,13 +49580,8 @@ var WalletModeActionProvider = class extends ActionProvider {
49575
49580
  }),
49576
49581
  invoke: async (_ctx, input2) => {
49577
49582
  if (input2.mode === "local") {
49578
- if (!this.agentWallet) {
49579
- throw new WalletError(
49580
- "WALLET_NOT_FOUND",
49581
- "No local agent wallet found. Create one with `twak init` (CLI), then restart the MCP client (e.g. Claude Desktop)."
49582
- );
49583
- }
49584
- await this.walletContext.bindLocal(this.agentWallet);
49583
+ const agentWallet = await this.agentWallet();
49584
+ await this.walletContext.bindLocal(agentWallet);
49585
49585
  return this.snapshotResponse(this.walletContext.snapshot());
49586
49586
  }
49587
49587
  if (!this.walletContext.walletConnectAvailable) {
@@ -49733,7 +49733,7 @@ var Erc8004ActionProvider = class extends ActionProvider {
49733
49733
  }
49734
49734
  ops(chainInput, signer) {
49735
49735
  if (!this.blockchainClient) {
49736
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
49736
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
49737
49737
  }
49738
49738
  return new Erc8004Operations(resolveErc8004Contract(this.blockchainClient, chainInput), {
49739
49739
  signer
@@ -50118,7 +50118,7 @@ var Erc8183ActionProvider = class extends ActionProvider {
50118
50118
  }
50119
50119
  ops(chainInput, signer) {
50120
50120
  if (!this.blockchainClient) {
50121
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
50121
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
50122
50122
  }
50123
50123
  const client = this.blockchainClient;
50124
50124
  return new Erc8183Operations(resolveErc8183Contracts(client, chainInput), {
@@ -50230,7 +50230,7 @@ var CompetitionActionProvider = class extends ActionProvider {
50230
50230
  }
50231
50231
  bind() {
50232
50232
  if (!this.blockchainClient) {
50233
- throw new WalletError("WALLET_NOT_FOUND", "BlockchainClient not available");
50233
+ throw new WalletError("WALLET_NOT_FOUND", "Chain client not available");
50234
50234
  }
50235
50235
  return resolveCompetitionContract(this.blockchainClient).contract;
50236
50236
  }
@@ -54875,20 +54875,24 @@ var import_crypto7 = require("crypto");
54875
54875
  init_dist();
54876
54876
  var SERVER_INSTRUCTIONS = `twak signs blockchain operations through one of two wallet modes:
54877
54877
 
54878
- LOCAL (default): an HD wallet auto-bound at server startup. In-process signing, no user-side prompts.
54878
+ LOCAL (default): an HD wallet auto-bound at server startup when no WalletConnect session was resumed. In-process signing, no user-side prompts.
54879
54879
 
54880
- WALLETCONNECT: a remote wallet (e.g. Trust Wallet on phone) paired via WC v2. Each signing action prompts the user on their device. More secure: the private key never leaves the user's device.
54880
+ WALLETCONNECT: a remote wallet (e.g. Trust Wallet on phone) paired via WC v2. Each signing action must be approved on the user's device; Trust Wallet shows the request only once the app is open (no push notification), so tell the user to open it. More secure: the private key never leaves the user's device.
54881
54881
 
54882
54882
  When the user first engages with signing operations in a fresh conversation, briefly mention that they can optionally switch to phone-based signing via \`switch_wallet_mode({mode: "walletconnect"})\` \u2014 many users don't know this is an option. Mention once; don't repeat on every signing call.
54883
54883
 
54884
- To switch mid-session, call \`switch_wallet_mode\`. The new mode applies to subsequent calls; in-flight signing keeps using its captured wallet. Mode persists for the MCP server's lifetime; restarting the MCP client (e.g. Claude Desktop) resets to local.`;
54884
+ To switch mid-session, call \`switch_wallet_mode\`. The new mode applies to subsequent calls; in-flight signing keeps using its captured wallet. A WalletConnect session is stored on disk and resumed when the server restarts, until it expires (about 7 days) or is revoked; choosing local mode revokes it.
54885
+
54886
+ If a tool returns CREDENTIALS_MISSING, the Trust Wallet API credentials are not set up yet: ask the user to run \`twak init\` (or \`twak setup\`) with their access ID and HMAC secret. The tools work as soon as the credentials are saved; no server restart is needed.`;
54885
54887
  var TwakMcpServer = class {
54886
54888
  server;
54887
54889
  registry;
54888
54890
  context;
54889
- constructor(registry, context) {
54891
+ beforeInvoke;
54892
+ constructor(registry, context, options = {}) {
54890
54893
  this.registry = registry;
54891
54894
  this.context = context;
54895
+ this.beforeInvoke = options.beforeInvoke;
54892
54896
  this.server = new Server(
54893
54897
  { name: "twak", version: "0.1.0" },
54894
54898
  { capabilities: { tools: {} }, instructions: SERVER_INSTRUCTIONS }
@@ -54924,6 +54928,7 @@ var TwakMcpServer = class {
54924
54928
  };
54925
54929
  }
54926
54930
  try {
54931
+ await this.beforeInvoke?.();
54927
54932
  const parsed = action.schema.parse(args);
54928
54933
  const result = await action.invoke(this.context, parsed);
54929
54934
  if (result instanceof McpResponse) {
@@ -55128,11 +55133,103 @@ var TwakRestServer = class {
55128
55133
 
55129
55134
  // src/commands/serve.ts
55130
55135
  init_dist();
55136
+
55137
+ // src/serve-bootstrap.ts
55138
+ var ServeBootstrap = class {
55139
+ constructor(deps) {
55140
+ this.deps = deps;
55141
+ }
55142
+ ready;
55143
+ attempt;
55144
+ async run() {
55145
+ const credentials = await this.deps.loadCredentials();
55146
+ if (!credentials) throw credentialsMissingError();
55147
+ await this.deps.initTrustSDK(credentials);
55148
+ await this.deps.onReady();
55149
+ this.ready = { credentials };
55150
+ }
55151
+ async ensureReady() {
55152
+ if (this.ready) return;
55153
+ if (!this.attempt) {
55154
+ this.attempt = this.run().finally(() => {
55155
+ this.attempt = void 0;
55156
+ });
55157
+ }
55158
+ return this.attempt;
55159
+ }
55160
+ /** Credentials once ready; throws CREDENTIALS_MISSING before. */
55161
+ credentials() {
55162
+ if (!this.ready) throw credentialsMissingError();
55163
+ return this.ready.credentials;
55164
+ }
55165
+ };
55166
+
55167
+ // src/agent-wallet-loader.ts
55168
+ init_dist();
55169
+ var AgentWalletLoader = class {
55170
+ constructor(deps) {
55171
+ this.deps = deps;
55172
+ }
55173
+ loaded;
55174
+ attempt;
55175
+ async open() {
55176
+ if (!await this.deps.walletExists()) {
55177
+ throw new WalletError(
55178
+ "WALLET_NOT_FOUND",
55179
+ "No local agent wallet found. Create one with `twak wallet create`, then switch to local mode again."
55180
+ );
55181
+ }
55182
+ const password3 = await this.deps.resolvePassword();
55183
+ if (!password3) {
55184
+ throw new WalletError(
55185
+ "PASSWORD_MISSING",
55186
+ "No wallet password available to the server. Run `twak wallet keychain save`, or start the server with TWAK_WALLET_PASSWORD or --password."
55187
+ );
55188
+ }
55189
+ let wallet;
55190
+ try {
55191
+ wallet = await this.deps.open(password3);
55192
+ } catch (err) {
55193
+ const classified = classifyWalletLoadError(err);
55194
+ if (classified) throw new WalletError(classified.code, classified.message);
55195
+ throw err;
55196
+ }
55197
+ this.deps.onLoaded(wallet);
55198
+ this.loaded = wallet;
55199
+ return wallet;
55200
+ }
55201
+ /** The loaded wallet; never loads. */
55202
+ get current() {
55203
+ return this.loaded;
55204
+ }
55205
+ /** Rejects with WalletError WALLET_NOT_FOUND, PASSWORD_MISSING or
55206
+ * WALLET_AUTH_FAILED, or the underlying error when unclassified. */
55207
+ async load() {
55208
+ if (this.loaded) return this.loaded;
55209
+ if (!this.attempt) {
55210
+ this.attempt = this.open().finally(() => {
55211
+ this.attempt = void 0;
55212
+ });
55213
+ }
55214
+ return this.attempt;
55215
+ }
55216
+ };
55217
+
55218
+ // src/stdio-console.ts
55219
+ var import_node_console = require("console");
55220
+ function routeConsoleToStderr(target = console, stderr = process.stderr) {
55221
+ Object.assign(target, new import_node_console.Console({ stdout: stderr, stderr }));
55222
+ }
55223
+
55224
+ // src/commands/serve.ts
55131
55225
  function registerServeCommand(program3) {
55132
55226
  program3.command("serve").description("Start MCP server (stdio) or REST API server for AI agent connection").option("--rest", "Start REST HTTP server instead of MCP stdio server").option("--port <n>", "Port for REST server", "3000").option(
55133
55227
  "--host <host>",
55134
55228
  "Host to bind REST server (default: 127.0.0.1; use 0.0.0.0 to expose externally)"
55135
- ).option("--password <password>", "Wallet password (falls back to keychain)").option("--auto-lock <minutes>", "Auto-lock wallet after N minutes of inactivity").option("--wc-project-id <id>", "WalletConnect project ID (or set WALLETCONNECT_PROJECT_ID)").option(
55229
+ ).option("--password <password>", "Wallet password (falls back to keychain)").option("--auto-lock <minutes>", "Auto-lock wallet after N minutes of inactivity").option(
55230
+ "--wc-project-id <id>",
55231
+ "WalletConnect project ID override (default: Trust Wallet project; or set WALLETCONNECT_PROJECT_ID)"
55232
+ ).option(
55136
55233
  "--watch",
55137
55234
  "Run a background watcher that fires DCA/limit automations (created via CLI or the create_automation MCP action); requires the local agent wallet"
55138
55235
  ).option(
@@ -55140,35 +55237,24 @@ function registerServeCommand(program3) {
55140
55237
  "Automation poll interval when --watch is set \u2014 e.g. 30s, 5m, 1h (min 5s)",
55141
55238
  "60"
55142
55239
  ).action(async (opts) => {
55143
- await ensureTrustSDK();
55144
- const client = await getClient();
55145
- const swapClient = new SwapClient(client);
55146
- const alertStore = new AlertStore();
55147
- const automationStore = new AutomationStore();
55148
- const blockchainClient = new BlockchainClient();
55149
- let agentWallet;
55150
- try {
55151
- const password3 = opts.password || process.env.TWAK_WALLET_PASSWORD || await new KeychainManager().getWalletPassword();
55152
- if (password3) agentWallet = await AgentWalletProvider.fromStorage(password3);
55153
- } catch {
55154
- }
55155
- if (opts.autoLock && agentWallet) {
55156
- const minutes = parseInt(opts.autoLock, 10);
55157
- if (isNaN(minutes) || minutes <= 0) {
55240
+ if (!opts.rest) routeConsoleToStderr();
55241
+ let autoLockMinutes;
55242
+ if (opts.autoLock) {
55243
+ autoLockMinutes = parseInt(opts.autoLock, 10);
55244
+ if (isNaN(autoLockMinutes) || autoLockMinutes <= 0) {
55158
55245
  error("--auto-lock must be a positive number of minutes");
55159
55246
  process.exit(1);
55160
55247
  }
55161
- agentWallet.setAutoLock({
55162
- autoLockMinutes: minutes,
55163
- passwordResolver: () => resolvePassword(opts)
55164
- });
55165
55248
  }
55249
+ const alertStore = new AlertStore();
55250
+ const automationStore = new AutomationStore();
55251
+ const chainClient = new ChainClient();
55166
55252
  const wcProjectId = await resolveWcProjectId(opts.wcProjectId);
55167
55253
  const walletContext = new WalletContext({
55168
- walletConnectFactory: wcProjectId ? () => createWalletConnectProvider(wcProjectId) : void 0
55254
+ walletConnectFactory: () => createWalletConnectProvider(wcProjectId, chainClient)
55169
55255
  });
55170
55256
  let resumeOutcome = "none";
55171
- if (walletContext.walletConnectAvailable && fs8.existsSync(wcStoragePath())) {
55257
+ if (fs8.existsSync(wcStoragePath())) {
55172
55258
  try {
55173
55259
  const resumed = await withTimeout(
55174
55260
  walletContext.restoreWalletConnect(),
@@ -55183,37 +55269,75 @@ function registerServeCommand(program3) {
55183
55269
  warn(`Could not resume WalletConnect session: ${errorMessage(err)}`);
55184
55270
  }
55185
55271
  }
55186
- if (agentWallet && resumeOutcome === "none") {
55187
- await walletContext.bindLocal(agentWallet);
55188
- blockchainClient.setSigner(agentWallet.getSigner());
55272
+ const walletLoader = new AgentWalletLoader({
55273
+ walletExists: () => new WalletConfigStore().exists(),
55274
+ resolvePassword: async () => opts.password || process.env.TWAK_WALLET_PASSWORD || await new KeychainManager().getWalletPassword() || void 0,
55275
+ open: (password3) => AgentWalletProvider.fromStorage(password3),
55276
+ onLoaded: (agentWallet) => {
55277
+ if (autoLockMinutes) {
55278
+ agentWallet.setAutoLock({
55279
+ autoLockMinutes,
55280
+ passwordResolver: () => resolvePassword(opts)
55281
+ });
55282
+ }
55283
+ }
55284
+ });
55285
+ const bootstrap = new ServeBootstrap({
55286
+ loadCredentials,
55287
+ initTrustSDK: initTrustSDKWithCredentials,
55288
+ onReady: async () => {
55289
+ let agentWallet;
55290
+ try {
55291
+ agentWallet = await walletLoader.load();
55292
+ } catch (err) {
55293
+ if (!(err instanceof CommandError && err.code === "WALLET_NOT_FOUND")) {
55294
+ warn(`Local agent wallet not loaded: ${errorMessage(err)}`);
55295
+ }
55296
+ return;
55297
+ }
55298
+ if (resumeOutcome === "none") await walletContext.bindLocal(agentWallet);
55299
+ }
55300
+ });
55301
+ const client = createTwakClient({ credentials: () => bootstrap.credentials() });
55302
+ const swapClient = new SwapClient(client);
55303
+ if (opts.rest || opts.watch) {
55304
+ await bootstrap.ensureReady();
55305
+ } else {
55306
+ try {
55307
+ await bootstrap.ensureReady();
55308
+ } catch (err) {
55309
+ warn(`${errorMessage(err)} Tool calls report this error until it is resolved.`);
55310
+ }
55189
55311
  }
55190
55312
  const registry = new ActionRegistry();
55191
55313
  registry.register(new BalanceActionProvider());
55192
- registry.register(new WalletModeActionProvider({ walletContext, agentWallet }));
55193
- registry.register(new SwapActionProvider(swapClient, walletContext, blockchainClient));
55314
+ registry.register(
55315
+ new WalletModeActionProvider({ walletContext, agentWallet: () => walletLoader.load() })
55316
+ );
55317
+ registry.register(new SwapActionProvider(swapClient, walletContext, chainClient));
55194
55318
  registry.register(new SecurityActionProvider());
55195
55319
  registry.register(new HistoryActionProvider());
55196
- registry.register(new TransferActionProvider(walletContext, swapClient, blockchainClient));
55320
+ registry.register(new TransferActionProvider(walletContext, swapClient));
55197
55321
  registry.register(new AlertActionProvider(alertStore));
55198
- registry.register(new AgentWalletActionProvider(blockchainClient, walletContext));
55199
- registry.register(new TokenActionProvider(blockchainClient, walletContext));
55322
+ registry.register(new AgentWalletActionProvider(walletContext));
55323
+ registry.register(new TokenActionProvider(chainClient, walletContext));
55200
55324
  registry.register(new MarketActionProvider());
55201
55325
  registry.register(
55202
- new OnrampActionProvider(walletContext, swapClient, void 0, blockchainClient)
55326
+ new OnrampActionProvider(walletContext, swapClient, void 0, chainClient)
55203
55327
  );
55204
55328
  registry.register(
55205
55329
  new AutomateActionProvider(
55206
55330
  automationStore,
55207
55331
  swapClient,
55208
55332
  walletContext,
55209
- blockchainClient,
55333
+ chainClient,
55210
55334
  Boolean(opts.watch)
55211
55335
  )
55212
55336
  );
55213
55337
  registry.register(new X402ActionProvider(walletContext));
55214
- registry.register(new Erc8004ActionProvider(blockchainClient, walletContext));
55215
- registry.register(new Erc8183ActionProvider(blockchainClient, walletContext));
55216
- registry.register(new CompetitionActionProvider(blockchainClient, walletContext));
55338
+ registry.register(new Erc8004ActionProvider(chainClient, walletContext));
55339
+ registry.register(new Erc8183ActionProvider(chainClient, walletContext));
55340
+ registry.register(new CompetitionActionProvider(chainClient, walletContext));
55217
55341
  let watcher;
55218
55342
  if (opts.watch) {
55219
55343
  const intervalSec = parseInterval(opts.watchInterval);
@@ -55227,7 +55351,7 @@ function registerServeCommand(program3) {
55227
55351
  automationStore,
55228
55352
  client,
55229
55353
  getExecutor: () => walletContext.state === "local" ? new SwapExecutor(swapClient, walletContext.activeWallet(), {
55230
- blockchainClient,
55354
+ chainClient,
55231
55355
  onStatus: (msg) => info(msg)
55232
55356
  }) : null,
55233
55357
  log: (level, msg) => {
@@ -55242,7 +55366,7 @@ function registerServeCommand(program3) {
55242
55366
  }
55243
55367
  );
55244
55368
  info(
55245
- `Automation watcher active (every ${intervalSec}s)${agentWallet ? "" : " \u2014 idle until a local wallet is unlocked"}`
55369
+ `Automation watcher active (every ${intervalSec}s)${walletLoader.current ? "" : " \u2014 idle until a local wallet is unlocked"}`
55246
55370
  );
55247
55371
  watcher.start();
55248
55372
  }
@@ -55250,15 +55374,21 @@ function registerServeCommand(program3) {
55250
55374
  const context = {
55251
55375
  httpClient: client
55252
55376
  };
55377
+ const disconnectLoadedWallet = async () => {
55378
+ const agentWallet = walletLoader.current;
55379
+ if (agentWallet?.isConnected()) await agentWallet.disconnect().catch(() => {
55380
+ });
55381
+ };
55253
55382
  if (opts.rest) {
55254
55383
  const restServer = new TwakRestServer(registry, context, {
55255
55384
  port: parseInt(opts.port),
55256
55385
  host: opts.host,
55257
55386
  apiKey: client.hmacSecret
55258
55387
  });
55259
- registerShutdownHandlers([agentWallet], () => {
55388
+ registerShutdownHandlers([], async () => {
55260
55389
  watcher?.stop();
55261
55390
  restServer.stop();
55391
+ await disconnectLoadedWallet();
55262
55392
  });
55263
55393
  try {
55264
55394
  await restServer.start();
@@ -55267,10 +55397,13 @@ function registerServeCommand(program3) {
55267
55397
  process.exit(1);
55268
55398
  }
55269
55399
  } else {
55270
- registerShutdownHandlers([agentWallet], () => {
55400
+ registerShutdownHandlers([], async () => {
55271
55401
  watcher?.stop();
55402
+ await disconnectLoadedWallet();
55403
+ });
55404
+ const mcpServer = new TwakMcpServer(registry, context, {
55405
+ beforeInvoke: () => bootstrap.ensureReady()
55272
55406
  });
55273
- const mcpServer = new TwakMcpServer(registry, context);
55274
55407
  console.error("TW Agent MCP server starting...");
55275
55408
  await mcpServer.start();
55276
55409
  }
@@ -55655,11 +55788,9 @@ ${url}`);
55655
55788
  warn(
55656
55789
  `About to send ${opts.amount} ${opts.asset} from ${address} to third-party off-ramp deposit address ${opts.to}${opts.memo ? ` (memo: ${opts.memo})` : ""}. This address is not under your control \u2014 verify it matches what the provider displayed before continuing.`
55657
55790
  );
55658
- const client = provider.getBlockchainClient();
55659
- const hdWallet = provider.getSigner().getHDWallet();
55660
55791
  let result;
55661
55792
  try {
55662
- result = await client.transfer({
55793
+ result = await provider.transfer({
55663
55794
  assetId: opts.asset,
55664
55795
  to: opts.to,
55665
55796
  amount: opts.amount,
@@ -55667,8 +55798,7 @@ ${url}`);
55667
55798
  memo: opts.memo,
55668
55799
  // Mainnet by construction — onramp has no --chain input and derives
55669
55800
  // chainKey from the asset's coinId via the CHAINS-only resolver.
55670
- chainKey,
55671
- hdWallet
55801
+ chainKey
55672
55802
  });
55673
55803
  } catch (err) {
55674
55804
  mapBroadcastError(err);
@@ -56182,7 +56312,7 @@ var crypto8 = __toESM(require("crypto"));
56182
56312
  // package.json
56183
56313
  var package_default = {
56184
56314
  name: "@trustwallet/cli",
56185
- version: "0.21.0",
56315
+ version: "0.23.0",
56186
56316
  description: "TWAK CLI \u2014 command-line interface for Trust Wallet Agent Kit",
56187
56317
  main: "dist/index.js",
56188
56318
  types: "dist/index.d.ts",
@@ -56396,6 +56526,7 @@ function registerWatchCommand(program3) {
56396
56526
  });
56397
56527
  }
56398
56528
  executor = new SwapExecutor(swapClient, provider, {
56529
+ chainClient: new ChainClient(),
56399
56530
  onStatus: (msg) => {
56400
56531
  info(`[${ts3()}] ${msg}`);
56401
56532
  }