@trustwallet/cli 0.20.0 → 0.21.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/commands/onramp.d.ts.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/index.js +597 -254
- package/dist/output.d.ts.map +1 -1
- package/dist/walletconnect-config.d.ts +16 -0
- package/dist/walletconnect-config.d.ts.map +1 -0
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -1046,8 +1046,8 @@ var require_command = __commonJS({
|
|
|
1046
1046
|
"use strict";
|
|
1047
1047
|
var EventEmitter = require("events").EventEmitter;
|
|
1048
1048
|
var childProcess = require("child_process");
|
|
1049
|
-
var
|
|
1050
|
-
var
|
|
1049
|
+
var path7 = require("path");
|
|
1050
|
+
var fs10 = require("fs");
|
|
1051
1051
|
var process3 = require("process");
|
|
1052
1052
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
1053
1053
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1979,11 +1979,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1979
1979
|
let launchWithNode = false;
|
|
1980
1980
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1981
1981
|
function findFile(baseDir, baseName) {
|
|
1982
|
-
const localBin =
|
|
1983
|
-
if (
|
|
1984
|
-
if (sourceExt.includes(
|
|
1982
|
+
const localBin = path7.resolve(baseDir, baseName);
|
|
1983
|
+
if (fs10.existsSync(localBin)) return localBin;
|
|
1984
|
+
if (sourceExt.includes(path7.extname(baseName))) return void 0;
|
|
1985
1985
|
const foundExt = sourceExt.find(
|
|
1986
|
-
(ext) =>
|
|
1986
|
+
(ext) => fs10.existsSync(`${localBin}${ext}`)
|
|
1987
1987
|
);
|
|
1988
1988
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1989
1989
|
return void 0;
|
|
@@ -1995,21 +1995,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1995
1995
|
if (this._scriptPath) {
|
|
1996
1996
|
let resolvedScriptPath;
|
|
1997
1997
|
try {
|
|
1998
|
-
resolvedScriptPath =
|
|
1998
|
+
resolvedScriptPath = fs10.realpathSync(this._scriptPath);
|
|
1999
1999
|
} catch (err) {
|
|
2000
2000
|
resolvedScriptPath = this._scriptPath;
|
|
2001
2001
|
}
|
|
2002
|
-
executableDir =
|
|
2003
|
-
|
|
2002
|
+
executableDir = path7.resolve(
|
|
2003
|
+
path7.dirname(resolvedScriptPath),
|
|
2004
2004
|
executableDir
|
|
2005
2005
|
);
|
|
2006
2006
|
}
|
|
2007
2007
|
if (executableDir) {
|
|
2008
2008
|
let localFile = findFile(executableDir, executableFile);
|
|
2009
2009
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
2010
|
-
const legacyName =
|
|
2010
|
+
const legacyName = path7.basename(
|
|
2011
2011
|
this._scriptPath,
|
|
2012
|
-
|
|
2012
|
+
path7.extname(this._scriptPath)
|
|
2013
2013
|
);
|
|
2014
2014
|
if (legacyName !== this._name) {
|
|
2015
2015
|
localFile = findFile(
|
|
@@ -2020,7 +2020,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2020
2020
|
}
|
|
2021
2021
|
executableFile = localFile || executableFile;
|
|
2022
2022
|
}
|
|
2023
|
-
launchWithNode = sourceExt.includes(
|
|
2023
|
+
launchWithNode = sourceExt.includes(path7.extname(executableFile));
|
|
2024
2024
|
let proc;
|
|
2025
2025
|
if (process3.platform !== "win32") {
|
|
2026
2026
|
if (launchWithNode) {
|
|
@@ -2860,7 +2860,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2860
2860
|
* @return {Command}
|
|
2861
2861
|
*/
|
|
2862
2862
|
nameFromFilename(filename) {
|
|
2863
|
-
this._name =
|
|
2863
|
+
this._name = path7.basename(filename, path7.extname(filename));
|
|
2864
2864
|
return this;
|
|
2865
2865
|
}
|
|
2866
2866
|
/**
|
|
@@ -2874,9 +2874,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2874
2874
|
* @param {string} [path]
|
|
2875
2875
|
* @return {(string|null|Command)}
|
|
2876
2876
|
*/
|
|
2877
|
-
executableDir(
|
|
2878
|
-
if (
|
|
2879
|
-
this._executableDir =
|
|
2877
|
+
executableDir(path8) {
|
|
2878
|
+
if (path8 === void 0) return this._executableDir;
|
|
2879
|
+
this._executableDir = path8;
|
|
2880
2880
|
return this;
|
|
2881
2881
|
}
|
|
2882
2882
|
/**
|
|
@@ -3158,6 +3158,7 @@ __export(dist_exports, {
|
|
|
3158
3158
|
coinTypeToChainKey: () => coinTypeToChainKey,
|
|
3159
3159
|
createTwakClient: () => createTwakClient,
|
|
3160
3160
|
encodeErc20Transfer: () => encodeErc20Transfer,
|
|
3161
|
+
errorMessage: () => errorMessage,
|
|
3161
3162
|
fetchBalance: () => fetchBalance,
|
|
3162
3163
|
fetchBalances: () => fetchBalances,
|
|
3163
3164
|
formatAmount: () => formatAmount,
|
|
@@ -3315,6 +3316,20 @@ function getSupportedCoinTypes() {
|
|
|
3315
3316
|
function isCoinTypeSupported(coinType) {
|
|
3316
3317
|
return Object.values(CHAINS).some((chain2) => chain2.coinId === coinType);
|
|
3317
3318
|
}
|
|
3319
|
+
function errorMessage(err) {
|
|
3320
|
+
if (err instanceof Error) return err.message;
|
|
3321
|
+
if (typeof err === "string") return err;
|
|
3322
|
+
if (err && typeof err === "object") {
|
|
3323
|
+
const { message } = err;
|
|
3324
|
+
if (typeof message === "string") return message;
|
|
3325
|
+
try {
|
|
3326
|
+
const json = JSON.stringify(err);
|
|
3327
|
+
if (typeof json === "string") return json;
|
|
3328
|
+
} catch {
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
return String(err);
|
|
3332
|
+
}
|
|
3318
3333
|
function classifyApiError(err) {
|
|
3319
3334
|
if (err instanceof TwakApiError) {
|
|
3320
3335
|
const status = err.statusCode;
|
|
@@ -3357,7 +3372,7 @@ function classifyStorageError(err) {
|
|
|
3357
3372
|
syscall
|
|
3358
3373
|
);
|
|
3359
3374
|
if (isFsByCode || isFsBySyscall) {
|
|
3360
|
-
const msg =
|
|
3375
|
+
const msg = errorMessage(err);
|
|
3361
3376
|
return { code: "STORAGE_ERROR", message: msg };
|
|
3362
3377
|
}
|
|
3363
3378
|
}
|
|
@@ -3367,7 +3382,7 @@ function classifyStorageError(err) {
|
|
|
3367
3382
|
return null;
|
|
3368
3383
|
}
|
|
3369
3384
|
function classifyWalletLoadError(err) {
|
|
3370
|
-
const msg =
|
|
3385
|
+
const msg = errorMessage(err);
|
|
3371
3386
|
if (/no wallet password/i.test(msg)) {
|
|
3372
3387
|
return { code: "PASSWORD_MISSING", message: msg };
|
|
3373
3388
|
}
|
|
@@ -3678,11 +3693,11 @@ function sortQueryRaw(query) {
|
|
|
3678
3693
|
});
|
|
3679
3694
|
return parts.join("&");
|
|
3680
3695
|
}
|
|
3681
|
-
function signRequest(method,
|
|
3696
|
+
function signRequest(method, path7, query, accessId, hmacSecret) {
|
|
3682
3697
|
const date = (/* @__PURE__ */ new Date()).toUTCString();
|
|
3683
3698
|
const nonce = (0, import_crypto.randomUUID)();
|
|
3684
3699
|
const sortedQuery = sortQueryRaw(query);
|
|
3685
|
-
const plaintext = [method.toUpperCase(),
|
|
3700
|
+
const plaintext = [method.toUpperCase(), path7, sortedQuery, accessId, nonce, date].join(";");
|
|
3686
3701
|
const signature = (0, import_crypto.createHmac)("sha256", hmacSecret).update(plaintext).digest("base64");
|
|
3687
3702
|
return {
|
|
3688
3703
|
"X-TW-CREDENTIAL": accessId,
|
|
@@ -4329,7 +4344,13 @@ var init_dist = __esm({
|
|
|
4329
4344
|
// Raised by signing-path action providers when no wallet mode has been
|
|
4330
4345
|
// selected yet for this server lifetime. Actionable: agent calls
|
|
4331
4346
|
// switch_wallet_mode (local or walletconnect) and retries.
|
|
4332
|
-
WALLET_NOT_BOUND: "WALLET_NOT_BOUND"
|
|
4347
|
+
WALLET_NOT_BOUND: "WALLET_NOT_BOUND",
|
|
4348
|
+
// The user declined a signing request in their wallet (WalletConnect).
|
|
4349
|
+
// Not retryable: the agent should ask the user instead of re-sending.
|
|
4350
|
+
USER_REJECTED: "USER_REJECTED",
|
|
4351
|
+
// The connected wallet answered a WalletConnect request with an error other
|
|
4352
|
+
// than a user rejection (e.g. unsupported method, invalid params).
|
|
4353
|
+
WC_REQUEST_FAILED: "WC_REQUEST_FAILED"
|
|
4333
4354
|
};
|
|
4334
4355
|
WalletError = class extends CommandError {
|
|
4335
4356
|
constructor(code2, message) {
|
|
@@ -4441,12 +4462,12 @@ var init_dist = __esm({
|
|
|
4441
4462
|
...config
|
|
4442
4463
|
};
|
|
4443
4464
|
}
|
|
4444
|
-
async gateway(method,
|
|
4445
|
-
const url = new URL(
|
|
4465
|
+
async gateway(method, path7, body, query) {
|
|
4466
|
+
const url = new URL(path7, this.config.gatewayBaseUrl);
|
|
4446
4467
|
if (query) url.search = query;
|
|
4447
4468
|
const headers = signRequest(
|
|
4448
4469
|
method,
|
|
4449
|
-
|
|
4470
|
+
path7,
|
|
4450
4471
|
query || "",
|
|
4451
4472
|
this.config.accessId,
|
|
4452
4473
|
this.config.hmacSecret
|
|
@@ -4461,14 +4482,14 @@ var init_dist = __esm({
|
|
|
4461
4482
|
body: body ? JSON.stringify(body) : void 0
|
|
4462
4483
|
});
|
|
4463
4484
|
}
|
|
4464
|
-
async amber(method,
|
|
4465
|
-
if (!
|
|
4485
|
+
async amber(method, path7, body) {
|
|
4486
|
+
if (!path7.startsWith("/amber-api/")) {
|
|
4466
4487
|
throw new Error("Amber API path must start with '/amber-api/'.");
|
|
4467
4488
|
}
|
|
4468
|
-
return this.gateway(method,
|
|
4489
|
+
return this.gateway(method, path7, body);
|
|
4469
4490
|
}
|
|
4470
|
-
async market(method,
|
|
4471
|
-
const url = new URL(
|
|
4491
|
+
async market(method, path7, body) {
|
|
4492
|
+
const url = new URL(path7, this.config.marketBaseUrl);
|
|
4472
4493
|
const raw = await this.fetch(url.toString(), {
|
|
4473
4494
|
method,
|
|
4474
4495
|
headers: { "Content-Type": "application/json" },
|
|
@@ -5803,15 +5824,15 @@ var require_route = __commonJS({
|
|
|
5803
5824
|
};
|
|
5804
5825
|
}
|
|
5805
5826
|
function wrapConversion(toModel, graph) {
|
|
5806
|
-
const
|
|
5827
|
+
const path7 = [graph[toModel].parent, toModel];
|
|
5807
5828
|
let fn2 = conversions[graph[toModel].parent][toModel];
|
|
5808
5829
|
let cur = graph[toModel].parent;
|
|
5809
5830
|
while (graph[cur].parent) {
|
|
5810
|
-
|
|
5831
|
+
path7.unshift(graph[cur].parent);
|
|
5811
5832
|
fn2 = link(conversions[graph[cur].parent][cur], fn2);
|
|
5812
5833
|
cur = graph[cur].parent;
|
|
5813
5834
|
}
|
|
5814
|
-
fn2.conversion =
|
|
5835
|
+
fn2.conversion = path7;
|
|
5815
5836
|
return fn2;
|
|
5816
5837
|
}
|
|
5817
5838
|
module2.exports = function(fromModel) {
|
|
@@ -6976,8 +6997,10 @@ async function initTrustSDK(config) {
|
|
|
6976
6997
|
new import_trust_sdk.Node(cfg.rpcUrl)
|
|
6977
6998
|
);
|
|
6978
6999
|
} catch (err) {
|
|
6979
|
-
process.stderr.write(
|
|
6980
|
-
`)
|
|
7000
|
+
process.stderr.write(
|
|
7001
|
+
`twak: could not register testnet node for ${cfg.id}: ${errorMessage(err)}
|
|
7002
|
+
`
|
|
7003
|
+
);
|
|
6981
7004
|
}
|
|
6982
7005
|
}
|
|
6983
7006
|
initialized = true;
|
|
@@ -7269,7 +7292,7 @@ async function verifyCredentials(config) {
|
|
|
7269
7292
|
try {
|
|
7270
7293
|
response = await gatewayFetch("PUT", `/v2/devices/${deviceId}`, config, DEVICE_INFO_BODY);
|
|
7271
7294
|
} catch (err) {
|
|
7272
|
-
const message =
|
|
7295
|
+
const message = errorMessage(err);
|
|
7273
7296
|
throw new VerifyCredentialsError(
|
|
7274
7297
|
"NETWORK_ERROR",
|
|
7275
7298
|
`Could not reach Trust Wallet gateway: ${message}`
|
|
@@ -8092,10 +8115,11 @@ var init_dist3 = __esm({
|
|
|
8092
8115
|
signal: AbortSignal.timeout(timeoutMs)
|
|
8093
8116
|
});
|
|
8094
8117
|
} catch (err) {
|
|
8095
|
-
throw new TwakNetworkError(
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8118
|
+
throw new TwakNetworkError(`RPC fetch failed on ${method}: ${errorMessage(err)}`, {
|
|
8119
|
+
method,
|
|
8120
|
+
rpcUrl,
|
|
8121
|
+
timeoutMs
|
|
8122
|
+
});
|
|
8099
8123
|
}
|
|
8100
8124
|
if (!response.ok) {
|
|
8101
8125
|
const body = await response.text().catch(() => "");
|
|
@@ -8112,7 +8136,7 @@ var init_dist3 = __esm({
|
|
|
8112
8136
|
json = await response.json();
|
|
8113
8137
|
} catch (err) {
|
|
8114
8138
|
throw new TwakNetworkError(
|
|
8115
|
-
`RPC response JSON parse failed on ${method}: ${
|
|
8139
|
+
`RPC response JSON parse failed on ${method}: ${errorMessage(err)}`,
|
|
8116
8140
|
{ method, rpcUrl }
|
|
8117
8141
|
);
|
|
8118
8142
|
}
|
|
@@ -8523,50 +8547,83 @@ var init_dist3 = __esm({
|
|
|
8523
8547
|
WalletContext = class {
|
|
8524
8548
|
_state = "unbound";
|
|
8525
8549
|
_wallet;
|
|
8526
|
-
/**
|
|
8527
|
-
* The WC instance we're currently pairing with. Used to ignore callbacks
|
|
8528
|
-
* from a previous pairing if the user re-calls `beginWalletConnect` while
|
|
8529
|
-
* already in `wc-pairing` (e.g. the first QR went stale and they want a
|
|
8530
|
-
* fresh one). Without this guard, the first wc's session-established
|
|
8531
|
-
* callback could land later and overwrite `_wallet` with the wrong instance.
|
|
8532
|
-
*/
|
|
8533
|
-
_pendingWc;
|
|
8534
8550
|
_pairing;
|
|
8535
8551
|
_peerName;
|
|
8536
8552
|
_lastError;
|
|
8553
|
+
_walletConnectFactory;
|
|
8554
|
+
_wc;
|
|
8537
8555
|
/**
|
|
8538
8556
|
* Mode-switch serializer. Concurrent `bindLocal` / `beginWalletConnect` /
|
|
8539
|
-
* `reset` calls otherwise interleave their state writes
|
|
8540
|
-
*
|
|
8541
|
-
* `_pairing` can land in an inconsistent shape. We queue each entry so the
|
|
8557
|
+
* `reset` calls otherwise interleave their state writes, leaving `_state`
|
|
8558
|
+
* and `_pairing` in an inconsistent shape. We queue each entry so the
|
|
8542
8559
|
* second call waits for the first to settle. `.catch(()=>{})` on the field
|
|
8543
8560
|
* itself keeps a rejected switch from poisoning the queue for later calls
|
|
8544
8561
|
* (the caller still sees the original rejection via the awaited promise
|
|
8545
8562
|
* we return from each entry method).
|
|
8546
8563
|
*/
|
|
8547
8564
|
_switchInflight = Promise.resolve();
|
|
8565
|
+
/** Bumped by every explicit mode switch, so a session restore that
|
|
8566
|
+
* resolves after the user already chose a mode is not bound. */
|
|
8567
|
+
_generation = 0;
|
|
8568
|
+
constructor(options = {}) {
|
|
8569
|
+
this._walletConnectFactory = options.walletConnectFactory;
|
|
8570
|
+
}
|
|
8571
|
+
/** Whether WalletConnect can be used (a project ID was configured). */
|
|
8572
|
+
get walletConnectAvailable() {
|
|
8573
|
+
return this._walletConnectFactory !== void 0;
|
|
8574
|
+
}
|
|
8548
8575
|
/**
|
|
8549
|
-
*
|
|
8550
|
-
*
|
|
8551
|
-
*
|
|
8552
|
-
*
|
|
8553
|
-
* Covers both `wc-connected` (via `_wallet`) and `wc-pairing` (via
|
|
8554
|
-
* `_pendingWc`). Without the pending-wc disconnect, switching away from
|
|
8555
|
-
* `wc-pairing` would leave the relay client open until expiry.
|
|
8576
|
+
* If the peer wallet later revokes the session (user dismisses on their
|
|
8577
|
+
* phone, relay-side expiry, etc.), flip context back to `unbound` so the
|
|
8578
|
+
* next sign attempt surfaces WALLET_NOT_BOUND with a recoverable hint
|
|
8579
|
+
* instead of a deep WC-RPC failure. Only reacts while bound to WC.
|
|
8556
8580
|
*/
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8581
|
+
handleSessionEnded(reason) {
|
|
8582
|
+
if (!this._wc || this._wallet !== this._wc) return;
|
|
8583
|
+
this._wallet = void 0;
|
|
8584
|
+
this._pairing = void 0;
|
|
8585
|
+
this._peerName = void 0;
|
|
8586
|
+
this._state = "unbound";
|
|
8587
|
+
this._lastError = {
|
|
8588
|
+
code: "WC_NOT_CONNECTED",
|
|
8589
|
+
message: `WalletConnect session ended (${reason}). Call switch_wallet_mode to re-pair or switch to local.`
|
|
8590
|
+
};
|
|
8591
|
+
}
|
|
8592
|
+
/** Bind the approved pairing, unless the user switched away meanwhile. */
|
|
8593
|
+
handleSessionEstablished(session) {
|
|
8594
|
+
if (this._state !== "wc-pairing" || !this._wc) return;
|
|
8595
|
+
this._wallet = this._wc;
|
|
8596
|
+
this._peerName = session.peerName;
|
|
8597
|
+
this._state = "wc-connected";
|
|
8598
|
+
this._pairing = void 0;
|
|
8599
|
+
}
|
|
8600
|
+
/** The process's single WC provider, created on first use. */
|
|
8601
|
+
walletConnect() {
|
|
8602
|
+
if (this._wc) return this._wc;
|
|
8603
|
+
if (!this._walletConnectFactory) {
|
|
8604
|
+
throw new WalletError(
|
|
8605
|
+
"VALIDATION_ERROR",
|
|
8606
|
+
"WalletConnect is not configured: no project ID. Set WALLETCONNECT_PROJECT_ID or run `twak init --wc-project-id <id>`, then restart the server."
|
|
8607
|
+
);
|
|
8564
8608
|
}
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8609
|
+
const wc3 = this._walletConnectFactory();
|
|
8610
|
+
wc3.onSessionEstablished((session) => this.handleSessionEstablished(session));
|
|
8611
|
+
wc3.onSessionEnded((reason) => this.handleSessionEnded(reason));
|
|
8612
|
+
this._wc = wc3;
|
|
8613
|
+
return wc3;
|
|
8614
|
+
}
|
|
8615
|
+
/**
|
|
8616
|
+
* Revoke the WC session, if a provider was ever used. Covers bound,
|
|
8617
|
+
* pairing and still-restoring sessions alike (the provider waits for an
|
|
8618
|
+
* in-flight init). Bounded: peer notification is time-limited by the
|
|
8619
|
+
* provider and local removal never needs the relay. Best-effort: failures
|
|
8620
|
+
* are swallowed so the switch still lands in a clean state.
|
|
8621
|
+
*/
|
|
8622
|
+
async disconnectWcIfAny() {
|
|
8623
|
+
if (!this._wc) return;
|
|
8624
|
+
try {
|
|
8625
|
+
await this._wc.disconnect();
|
|
8626
|
+
} catch {
|
|
8570
8627
|
}
|
|
8571
8628
|
}
|
|
8572
8629
|
get state() {
|
|
@@ -8608,102 +8665,101 @@ var init_dist3 = __esm({
|
|
|
8608
8665
|
return base3;
|
|
8609
8666
|
}
|
|
8610
8667
|
/**
|
|
8611
|
-
*
|
|
8612
|
-
*
|
|
8613
|
-
*
|
|
8614
|
-
*
|
|
8668
|
+
* Run `task` after any in-flight mode switch finishes. The returned promise
|
|
8669
|
+
* settles with `task`'s outcome (success or failure). The internal queue
|
|
8670
|
+
* promise always resolves so a failing switch can't block subsequent
|
|
8671
|
+
* switches.
|
|
8672
|
+
*/
|
|
8673
|
+
enqueue(task) {
|
|
8674
|
+
const next = this._switchInflight.then(task);
|
|
8675
|
+
this._switchInflight = next.catch(() => void 0);
|
|
8676
|
+
return next;
|
|
8677
|
+
}
|
|
8678
|
+
/**
|
|
8679
|
+
* Bind to the local agent wallet. This is an explicit choice: any WC
|
|
8680
|
+
* session (bound, pairing, or still being restored) is revoked first, so a
|
|
8681
|
+
* restart does not resume it.
|
|
8615
8682
|
*/
|
|
8616
8683
|
async bindLocal(agent) {
|
|
8617
8684
|
return this.enqueue(() => this.bindLocalImpl(agent));
|
|
8618
8685
|
}
|
|
8619
8686
|
async bindLocalImpl(agent) {
|
|
8687
|
+
this._generation++;
|
|
8620
8688
|
await this.disconnectWcIfAny();
|
|
8621
|
-
this._pendingWc = void 0;
|
|
8622
8689
|
this._wallet = agent;
|
|
8623
8690
|
this._pairing = void 0;
|
|
8624
8691
|
this._peerName = void 0;
|
|
8625
8692
|
this._state = "local";
|
|
8626
8693
|
this._lastError = void 0;
|
|
8627
8694
|
}
|
|
8628
|
-
/**
|
|
8629
|
-
* Run `task` after any in-flight mode switch finishes. The returned promise
|
|
8630
|
-
* settles with `task`'s outcome (success or failure). The internal queue
|
|
8631
|
-
* promise always resolves so a failing switch can't block subsequent
|
|
8632
|
-
* switches.
|
|
8633
|
-
*/
|
|
8634
|
-
enqueue(task) {
|
|
8635
|
-
const next = this._switchInflight.then(task);
|
|
8636
|
-
this._switchInflight = next.catch(() => void 0);
|
|
8637
|
-
return next;
|
|
8638
|
-
}
|
|
8639
8695
|
/**
|
|
8640
8696
|
* Start a WalletConnect pairing. Returns the pairing payload immediately;
|
|
8641
8697
|
* the caller surfaces it (QR code, deep link). When any compatible client
|
|
8642
8698
|
* approves, the provider's session_established event fires and the context
|
|
8643
|
-
* transitions to `wc-connected`.
|
|
8644
|
-
*
|
|
8645
|
-
* V1 does not restrict the peer wallet — any WC v2 client can pair. The
|
|
8646
|
-
* user's choice to scan the QR is the consent moment. A peer-identity gate
|
|
8647
|
-
* (e.g. Trust-Wallet-only) is deferred until we have a real pairing log to
|
|
8648
|
-
* write it against.
|
|
8699
|
+
* transitions to `wc-connected`. The previous session is revoked first:
|
|
8700
|
+
* asking to pair again expresses the intent to invalidate it.
|
|
8649
8701
|
*
|
|
8650
|
-
*
|
|
8651
|
-
*
|
|
8652
|
-
* MCP action provider) constructs the WC provider and passes it in.
|
|
8702
|
+
* V1 does not restrict the peer wallet: any WC v2 client can pair. The
|
|
8703
|
+
* user's choice to scan the QR is the consent moment.
|
|
8653
8704
|
*/
|
|
8654
|
-
async beginWalletConnect(
|
|
8655
|
-
return this.enqueue(() => this.beginWalletConnectImpl(
|
|
8705
|
+
async beginWalletConnect(chains) {
|
|
8706
|
+
return this.enqueue(() => this.beginWalletConnectImpl(chains));
|
|
8656
8707
|
}
|
|
8657
|
-
async beginWalletConnectImpl(
|
|
8708
|
+
async beginWalletConnectImpl(chains) {
|
|
8709
|
+
const wc3 = this.walletConnect();
|
|
8710
|
+
this._generation++;
|
|
8658
8711
|
await this.disconnectWcIfAny();
|
|
8659
8712
|
try {
|
|
8660
8713
|
this._pairing = await wc3.connect(chains);
|
|
8661
8714
|
} catch (err) {
|
|
8662
8715
|
this._wallet = void 0;
|
|
8663
|
-
this._pendingWc = void 0;
|
|
8664
8716
|
this._pairing = void 0;
|
|
8665
8717
|
this._peerName = void 0;
|
|
8666
8718
|
this._state = "unbound";
|
|
8667
8719
|
this._lastError = {
|
|
8668
8720
|
code: "WC_PAIRING_FAILED",
|
|
8669
|
-
message: `WalletConnect pairing failed: ${
|
|
8721
|
+
message: `WalletConnect pairing failed: ${errorMessage(err)}`
|
|
8670
8722
|
};
|
|
8671
8723
|
throw err;
|
|
8672
8724
|
}
|
|
8673
8725
|
this._wallet = void 0;
|
|
8674
|
-
this._pendingWc = wc3;
|
|
8675
8726
|
this._state = "wc-pairing";
|
|
8676
8727
|
this._lastError = void 0;
|
|
8677
8728
|
this._peerName = void 0;
|
|
8678
|
-
|
|
8679
|
-
|
|
8729
|
+
return this.snapshot().pairing;
|
|
8730
|
+
}
|
|
8731
|
+
/**
|
|
8732
|
+
* Bind the WC session persisted by a previous process, if any. Returns
|
|
8733
|
+
* true and moves to `wc-connected` when the provider finds a live session;
|
|
8734
|
+
* leaves the context untouched otherwise (and when WC is not configured).
|
|
8735
|
+
*
|
|
8736
|
+
* Runs outside the mode-switch queue so a switch made meanwhile is never
|
|
8737
|
+
* blocked; that switch wins (the late session is not bound) and, being
|
|
8738
|
+
* explicit, revokes the session through the shared provider.
|
|
8739
|
+
*/
|
|
8740
|
+
async restoreWalletConnect() {
|
|
8741
|
+
if (!this.walletConnectAvailable) return false;
|
|
8742
|
+
const generation = this._generation;
|
|
8743
|
+
const wc3 = this.walletConnect();
|
|
8744
|
+
const session = await wc3.restore();
|
|
8745
|
+
return this.enqueue(async () => {
|
|
8746
|
+
if (!session || this._generation !== generation) return false;
|
|
8680
8747
|
this._wallet = wc3;
|
|
8748
|
+
this._pairing = void 0;
|
|
8681
8749
|
this._peerName = session.peerName;
|
|
8682
8750
|
this._state = "wc-connected";
|
|
8683
|
-
this.
|
|
8684
|
-
|
|
8685
|
-
});
|
|
8686
|
-
wc3.onSessionEnded((reason) => {
|
|
8687
|
-
if (this._wallet !== wc3) return;
|
|
8688
|
-
this._wallet = void 0;
|
|
8689
|
-
this._pairing = void 0;
|
|
8690
|
-
this._peerName = void 0;
|
|
8691
|
-
this._state = "unbound";
|
|
8692
|
-
this._lastError = {
|
|
8693
|
-
code: "WC_NOT_CONNECTED",
|
|
8694
|
-
message: `WalletConnect session ended (${reason}). Call switch_wallet_mode to re-pair or switch to local.`
|
|
8695
|
-
};
|
|
8751
|
+
this._lastError = void 0;
|
|
8752
|
+
return true;
|
|
8696
8753
|
});
|
|
8697
|
-
return this.snapshot().pairing;
|
|
8698
8754
|
}
|
|
8699
|
-
/**
|
|
8755
|
+
/** Revoke any WC session (best-effort) and return to `unbound`. */
|
|
8700
8756
|
async reset() {
|
|
8701
8757
|
return this.enqueue(() => this.resetImpl());
|
|
8702
8758
|
}
|
|
8703
8759
|
async resetImpl() {
|
|
8760
|
+
this._generation++;
|
|
8704
8761
|
await this.disconnectWcIfAny();
|
|
8705
8762
|
this._wallet = void 0;
|
|
8706
|
-
this._pendingWc = void 0;
|
|
8707
8763
|
this._pairing = void 0;
|
|
8708
8764
|
this._peerName = void 0;
|
|
8709
8765
|
this._state = "unbound";
|
|
@@ -9317,9 +9373,9 @@ var require_cjs3 = __commonJS({
|
|
|
9317
9373
|
if (href.indexOf("/") === 0) {
|
|
9318
9374
|
absoluteHref += href;
|
|
9319
9375
|
} else {
|
|
9320
|
-
const
|
|
9321
|
-
|
|
9322
|
-
const finalPath =
|
|
9376
|
+
const path7 = loc.pathname.split("/");
|
|
9377
|
+
path7.pop();
|
|
9378
|
+
const finalPath = path7.join("/");
|
|
9323
9379
|
absoluteHref += finalPath + "/" + href;
|
|
9324
9380
|
}
|
|
9325
9381
|
icons2.push(absoluteHref);
|
|
@@ -12179,7 +12235,7 @@ var require_websocket = __commonJS({
|
|
|
12179
12235
|
var http2 = require("http");
|
|
12180
12236
|
var net = require("net");
|
|
12181
12237
|
var tls = require("tls");
|
|
12182
|
-
var { randomBytes:
|
|
12238
|
+
var { randomBytes: randomBytes8, createHash: createHash2 } = require("crypto");
|
|
12183
12239
|
var { Readable } = require("stream");
|
|
12184
12240
|
var { URL: URL2 } = require("url");
|
|
12185
12241
|
var PerMessageDeflate = require_permessage_deflate();
|
|
@@ -12639,7 +12695,7 @@ var require_websocket = __commonJS({
|
|
|
12639
12695
|
}
|
|
12640
12696
|
const isSecure = parsedUrl.protocol === "wss:" || parsedUrl.protocol === "https:";
|
|
12641
12697
|
const defaultPort = isSecure ? 443 : 80;
|
|
12642
|
-
const key =
|
|
12698
|
+
const key = randomBytes8(16).toString("base64");
|
|
12643
12699
|
const get2 = isSecure ? https2.get : http2.get;
|
|
12644
12700
|
let perMessageDeflate;
|
|
12645
12701
|
opts.createConnection = isSecure ? tlsConnect : netConnect;
|
|
@@ -16261,15 +16317,15 @@ var dapps_service_exports = {};
|
|
|
16261
16317
|
__export(dapps_service_exports, {
|
|
16262
16318
|
DappsService: () => DappsService
|
|
16263
16319
|
});
|
|
16264
|
-
var
|
|
16320
|
+
var fs7, path5, os3, CACHE_FILE, CACHE_TTL_MS, DappsService;
|
|
16265
16321
|
var init_dapps_service = __esm({
|
|
16266
16322
|
"../security/dist/services/dapps-service.mjs"() {
|
|
16267
16323
|
"use strict";
|
|
16268
|
-
|
|
16269
|
-
|
|
16324
|
+
fs7 = __toESM(require("fs"), 1);
|
|
16325
|
+
path5 = __toESM(require("path"), 1);
|
|
16270
16326
|
os3 = __toESM(require("os"), 1);
|
|
16271
16327
|
init_dist();
|
|
16272
|
-
CACHE_FILE =
|
|
16328
|
+
CACHE_FILE = path5.join(os3.homedir(), ".twak", "dapps-cache.json");
|
|
16273
16329
|
CACHE_TTL_MS = 6 * 36e5;
|
|
16274
16330
|
DappsService = class {
|
|
16275
16331
|
protocols = null;
|
|
@@ -16286,9 +16342,7 @@ var init_dapps_service = __esm({
|
|
|
16286
16342
|
signal: AbortSignal.timeout(15e3)
|
|
16287
16343
|
});
|
|
16288
16344
|
} catch (e2) {
|
|
16289
|
-
throw new TwakNetworkError(
|
|
16290
|
-
`DeFi Llama unreachable: ${e2 instanceof Error ? e2.message : String(e2)}`
|
|
16291
|
-
);
|
|
16345
|
+
throw new TwakNetworkError(`DeFi Llama unreachable: ${errorMessage(e2)}`);
|
|
16292
16346
|
}
|
|
16293
16347
|
if (!resp.ok) {
|
|
16294
16348
|
throw new TwakApiError(`DeFi Llama API error: ${resp.status}`, resp.status);
|
|
@@ -16337,7 +16391,7 @@ var init_dapps_service = __esm({
|
|
|
16337
16391
|
}
|
|
16338
16392
|
readCache() {
|
|
16339
16393
|
try {
|
|
16340
|
-
const raw =
|
|
16394
|
+
const raw = fs7.readFileSync(CACHE_FILE, "utf-8");
|
|
16341
16395
|
const data = JSON.parse(raw);
|
|
16342
16396
|
if (Date.now() - data.fetchedAt < CACHE_TTL_MS) {
|
|
16343
16397
|
return data.protocols;
|
|
@@ -16348,10 +16402,10 @@ var init_dapps_service = __esm({
|
|
|
16348
16402
|
}
|
|
16349
16403
|
writeCache(protocols) {
|
|
16350
16404
|
try {
|
|
16351
|
-
const dir =
|
|
16352
|
-
|
|
16405
|
+
const dir = path5.dirname(CACHE_FILE);
|
|
16406
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
16353
16407
|
const data = { fetchedAt: Date.now(), protocols };
|
|
16354
|
-
|
|
16408
|
+
fs7.writeFileSync(CACHE_FILE, JSON.stringify(data));
|
|
16355
16409
|
} catch {
|
|
16356
16410
|
}
|
|
16357
16411
|
}
|
|
@@ -19552,8 +19606,8 @@ var require_utils2 = __commonJS({
|
|
|
19552
19606
|
}
|
|
19553
19607
|
return ind;
|
|
19554
19608
|
}
|
|
19555
|
-
function removeDotSegments(
|
|
19556
|
-
let input2 =
|
|
19609
|
+
function removeDotSegments(path7) {
|
|
19610
|
+
let input2 = path7;
|
|
19557
19611
|
const output2 = [];
|
|
19558
19612
|
let nextSlash = -1;
|
|
19559
19613
|
let len = 0;
|
|
@@ -19752,8 +19806,8 @@ var require_schemes = __commonJS({
|
|
|
19752
19806
|
wsComponent.secure = void 0;
|
|
19753
19807
|
}
|
|
19754
19808
|
if (wsComponent.resourceName) {
|
|
19755
|
-
const [
|
|
19756
|
-
wsComponent.path =
|
|
19809
|
+
const [path7, query] = wsComponent.resourceName.split("?");
|
|
19810
|
+
wsComponent.path = path7 && path7 !== "/" ? path7 : void 0;
|
|
19757
19811
|
wsComponent.query = query;
|
|
19758
19812
|
wsComponent.resourceName = void 0;
|
|
19759
19813
|
}
|
|
@@ -23115,12 +23169,12 @@ var require_dist = __commonJS({
|
|
|
23115
23169
|
throw new Error(`Unknown format "${name2}"`);
|
|
23116
23170
|
return f3;
|
|
23117
23171
|
};
|
|
23118
|
-
function addFormats(ajv, list,
|
|
23172
|
+
function addFormats(ajv, list, fs10, exportName) {
|
|
23119
23173
|
var _a2;
|
|
23120
23174
|
var _b;
|
|
23121
23175
|
(_a2 = (_b = ajv.opts.code).formats) !== null && _a2 !== void 0 ? _a2 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
23122
23176
|
for (const f3 of list)
|
|
23123
|
-
ajv.addFormat(f3,
|
|
23177
|
+
ajv.addFormat(f3, fs10[f3]);
|
|
23124
23178
|
}
|
|
23125
23179
|
module2.exports = exports2 = formatsPlugin;
|
|
23126
23180
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -24660,12 +24714,12 @@ var init_debug = __esm({
|
|
|
24660
24714
|
};
|
|
24661
24715
|
};
|
|
24662
24716
|
};
|
|
24663
|
-
getValueByStringPath = function(obj,
|
|
24717
|
+
getValueByStringPath = function(obj, path7) {
|
|
24664
24718
|
var e_1, _a2;
|
|
24665
|
-
|
|
24666
|
-
|
|
24719
|
+
path7 = path7.replace(/\[(\w+)\]/g, ".$1");
|
|
24720
|
+
path7 = path7.replace(/^\./, "");
|
|
24667
24721
|
try {
|
|
24668
|
-
for (var _b = __values2(
|
|
24722
|
+
for (var _b = __values2(path7.split(".")), _c2 = _b.next(); !_c2.done; _c2 = _b.next()) {
|
|
24669
24723
|
var attr = _c2.value;
|
|
24670
24724
|
if (attr in obj) {
|
|
24671
24725
|
obj = obj[attr];
|
|
@@ -24690,8 +24744,8 @@ var init_debug = __esm({
|
|
|
24690
24744
|
var res = {};
|
|
24691
24745
|
try {
|
|
24692
24746
|
for (var paths_1 = __values2(paths), paths_1_1 = paths_1.next(); !paths_1_1.done; paths_1_1 = paths_1.next()) {
|
|
24693
|
-
var
|
|
24694
|
-
res[
|
|
24747
|
+
var path7 = paths_1_1.value;
|
|
24748
|
+
res[path7] = getValueByStringPath(client, path7);
|
|
24695
24749
|
}
|
|
24696
24750
|
} catch (e_2_1) {
|
|
24697
24751
|
e_2 = { error: e_2_1 };
|
|
@@ -24951,7 +25005,7 @@ var init_destination = __esm({
|
|
|
24951
25005
|
useRetry = true;
|
|
24952
25006
|
}
|
|
24953
25007
|
return __awaiter2(this, void 0, void 0, function() {
|
|
24954
|
-
var payload, serverUrl, res, e_1,
|
|
25008
|
+
var payload, serverUrl, res, e_1, errorMessage2;
|
|
24955
25009
|
return __generator2(this, function(_b) {
|
|
24956
25010
|
switch (_b.label) {
|
|
24957
25011
|
case 0:
|
|
@@ -25000,13 +25054,13 @@ var init_destination = __esm({
|
|
|
25000
25054
|
return [3, 4];
|
|
25001
25055
|
case 3:
|
|
25002
25056
|
e_1 = _b.sent();
|
|
25003
|
-
|
|
25004
|
-
this.config.loggerProvider.error(
|
|
25057
|
+
errorMessage2 = getErrorMessage(e_1);
|
|
25058
|
+
this.config.loggerProvider.error(errorMessage2);
|
|
25005
25059
|
(_a2 = this.diagnosticsClient) === null || _a2 === void 0 ? void 0 : _a2.recordEvent("analytics.events.unsuccessful.from.catch.error", {
|
|
25006
25060
|
events: list.map(function(context) {
|
|
25007
25061
|
return context.event.event_type;
|
|
25008
25062
|
}),
|
|
25009
|
-
message:
|
|
25063
|
+
message: errorMessage2,
|
|
25010
25064
|
stack_trace: getStacktrace()
|
|
25011
25065
|
});
|
|
25012
25066
|
this.handleResponse({ status: Status.Failed, statusCode: 0 }, list);
|
|
@@ -25638,7 +25692,7 @@ function classifyError(err) {
|
|
|
25638
25692
|
if (err instanceof CommandError) return err;
|
|
25639
25693
|
const cls = classifyApiError(err) ?? classifyStorageError(err) ?? classifyWalletLoadError(err);
|
|
25640
25694
|
if (cls) return new CommandError(cls.code, cls.message);
|
|
25641
|
-
return new CommandError("UNKNOWN_ERROR",
|
|
25695
|
+
return new CommandError("UNKNOWN_ERROR", errorMessage(err));
|
|
25642
25696
|
}
|
|
25643
25697
|
function handleCommandError(err, json, fallbackPrefix) {
|
|
25644
25698
|
const classified = classifyError(err);
|
|
@@ -25670,7 +25724,7 @@ var import_chalk2 = __toESM(require_source());
|
|
|
25670
25724
|
init_dist();
|
|
25671
25725
|
init_dist3();
|
|
25672
25726
|
init_dist2();
|
|
25673
|
-
var EMBEDDED_NAAS_SESSION_ID = "
|
|
25727
|
+
var EMBEDDED_NAAS_SESSION_ID = "NDVjMWRjY2MtYTYwNy00NGNhLWIxZGUtMmJiZDIyNmEyODQ4";
|
|
25674
25728
|
function resolveNaasSessionId() {
|
|
25675
25729
|
if (process.env.TWAK_NAAS_SESSION_ID) return process.env.TWAK_NAAS_SESSION_ID;
|
|
25676
25730
|
if (EMBEDDED_NAAS_SESSION_ID && !EMBEDDED_NAAS_SESSION_ID.startsWith("__"))
|
|
@@ -31522,7 +31576,7 @@ function weierstrass(curveDef) {
|
|
|
31522
31576
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
31523
31577
|
if (["recovered", "canonical"].some((k4) => k4 in opts))
|
|
31524
31578
|
throw new Error("sign() legacy options not supported");
|
|
31525
|
-
const { hash, randomBytes:
|
|
31579
|
+
const { hash, randomBytes: randomBytes8 } = CURVE;
|
|
31526
31580
|
let { lowS, prehash, extraEntropy: ent } = opts;
|
|
31527
31581
|
if (lowS == null)
|
|
31528
31582
|
lowS = true;
|
|
@@ -31534,7 +31588,7 @@ function weierstrass(curveDef) {
|
|
|
31534
31588
|
const d3 = normPrivateKeyToScalar(privateKey);
|
|
31535
31589
|
const seedArgs = [int2octets(d3), int2octets(h1int)];
|
|
31536
31590
|
if (ent != null && ent !== false) {
|
|
31537
|
-
const e2 = ent === true ?
|
|
31591
|
+
const e2 = ent === true ? randomBytes8(Fp.BYTES) : ent;
|
|
31538
31592
|
seedArgs.push(ensureBytes("extraEntropy", e2));
|
|
31539
31593
|
}
|
|
31540
31594
|
const seed = concatBytes2(...seedArgs);
|
|
@@ -41568,6 +41622,10 @@ var Os3 = ut4;
|
|
|
41568
41622
|
// ../walletconnect/dist/index.mjs
|
|
41569
41623
|
init_dist3();
|
|
41570
41624
|
init_dist();
|
|
41625
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
41626
|
+
var path3 = __toESM(require("path"), 1);
|
|
41627
|
+
var crypto7 = __toESM(require("crypto"), 1);
|
|
41628
|
+
init_dist();
|
|
41571
41629
|
var __require2 = /* @__PURE__ */ ((x6) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x6, {
|
|
41572
41630
|
get: (a3, b3) => (typeof require !== "undefined" ? require : a3)[b3]
|
|
41573
41631
|
}) : x6)(function(x6) {
|
|
@@ -41586,12 +41644,111 @@ async function renderPngDataUrl(uri) {
|
|
|
41586
41644
|
const qrcode = __require2("qrcode");
|
|
41587
41645
|
return qrcode.toDataURL(uri, { errorCorrectionLevel: "M" });
|
|
41588
41646
|
}
|
|
41647
|
+
var FileKeyValueStorage = class {
|
|
41648
|
+
constructor(filePath, opts = {}) {
|
|
41649
|
+
this.filePath = filePath;
|
|
41650
|
+
this.opts = opts;
|
|
41651
|
+
}
|
|
41652
|
+
cache = null;
|
|
41653
|
+
warn(msg) {
|
|
41654
|
+
this.opts.onWarning?.(msg);
|
|
41655
|
+
}
|
|
41656
|
+
readFile() {
|
|
41657
|
+
let raw;
|
|
41658
|
+
try {
|
|
41659
|
+
raw = fs5.readFileSync(this.filePath, "utf-8");
|
|
41660
|
+
} catch (err) {
|
|
41661
|
+
if (err.code !== "ENOENT") {
|
|
41662
|
+
this.warn(`Could not read ${this.filePath}: ${errorMessage(err)}`);
|
|
41663
|
+
}
|
|
41664
|
+
return /* @__PURE__ */ new Map();
|
|
41665
|
+
}
|
|
41666
|
+
try {
|
|
41667
|
+
return new Map(Object.entries(JSON.parse(raw)));
|
|
41668
|
+
} catch {
|
|
41669
|
+
const corruptPath = `${this.filePath}.corrupt`;
|
|
41670
|
+
try {
|
|
41671
|
+
fs5.renameSync(this.filePath, corruptPath);
|
|
41672
|
+
this.warn(`WalletConnect storage file was corrupt; moved it to ${corruptPath}`);
|
|
41673
|
+
} catch (err) {
|
|
41674
|
+
this.warn(
|
|
41675
|
+
`WalletConnect storage file is corrupt and could not be moved: ${errorMessage(err)}`
|
|
41676
|
+
);
|
|
41677
|
+
}
|
|
41678
|
+
return /* @__PURE__ */ new Map();
|
|
41679
|
+
}
|
|
41680
|
+
}
|
|
41681
|
+
load() {
|
|
41682
|
+
if (!this.cache) this.cache = this.readFile();
|
|
41683
|
+
return this.cache;
|
|
41684
|
+
}
|
|
41685
|
+
persist() {
|
|
41686
|
+
const snapshot = JSON.stringify(Object.fromEntries(this.load()));
|
|
41687
|
+
const tmpPath = `${this.filePath}.tmp.${crypto7.randomBytes(8).toString("hex")}`;
|
|
41688
|
+
try {
|
|
41689
|
+
fs5.mkdirSync(path3.dirname(this.filePath), { recursive: true, mode: 448 });
|
|
41690
|
+
fs5.writeFileSync(tmpPath, snapshot, { encoding: "utf-8", mode: 384 });
|
|
41691
|
+
fs5.renameSync(tmpPath, this.filePath);
|
|
41692
|
+
} catch (err) {
|
|
41693
|
+
try {
|
|
41694
|
+
fs5.rmSync(tmpPath, { force: true });
|
|
41695
|
+
} catch {
|
|
41696
|
+
}
|
|
41697
|
+
this.warn(`Could not save WalletConnect session to ${this.filePath}: ${errorMessage(err)}`);
|
|
41698
|
+
}
|
|
41699
|
+
}
|
|
41700
|
+
async getKeys() {
|
|
41701
|
+
return [...this.load().keys()];
|
|
41702
|
+
}
|
|
41703
|
+
async getEntries() {
|
|
41704
|
+
return [...this.load().entries()];
|
|
41705
|
+
}
|
|
41706
|
+
async getItem(key) {
|
|
41707
|
+
return this.load().get(key);
|
|
41708
|
+
}
|
|
41709
|
+
async setItem(key, value) {
|
|
41710
|
+
this.load().set(key, value);
|
|
41711
|
+
this.persist();
|
|
41712
|
+
}
|
|
41713
|
+
async removeItem(key) {
|
|
41714
|
+
if (this.load().delete(key)) this.persist();
|
|
41715
|
+
}
|
|
41716
|
+
};
|
|
41589
41717
|
var DEFAULT_METADATA = {
|
|
41590
41718
|
name: "TWAK Agent",
|
|
41591
41719
|
description: "AI Agent for Trust Wallet operations",
|
|
41592
41720
|
url: "https://portal.trustwallet.com",
|
|
41593
41721
|
icons: ["https://avatars.githubusercontent.com/u/32179365"]
|
|
41594
41722
|
};
|
|
41723
|
+
var SESSION_CLEARED_REASON = { code: 6e3, message: "Session cleared" };
|
|
41724
|
+
var PEER_NOTIFY_TIMEOUT_MS = 5e3;
|
|
41725
|
+
var USER_REJECTION_CODES = /* @__PURE__ */ new Set([5e3, 4001]);
|
|
41726
|
+
var GENERIC_SERVER_ERROR_CODE = -32e3;
|
|
41727
|
+
var USER_REJECTION_MESSAGE_RE = /\buser (cancell?ed|rejected|denied)\b/i;
|
|
41728
|
+
function isUserRejection(code2, message) {
|
|
41729
|
+
if (USER_REJECTION_CODES.has(code2)) return true;
|
|
41730
|
+
return code2 === GENERIC_SERVER_ERROR_CODE && USER_REJECTION_MESSAGE_RE.test(message);
|
|
41731
|
+
}
|
|
41732
|
+
function toRequestError(err) {
|
|
41733
|
+
if (err instanceof Error || !err || typeof err !== "object") return err;
|
|
41734
|
+
const { code: code2, message } = err;
|
|
41735
|
+
if (typeof code2 !== "number" || typeof message !== "string") return err;
|
|
41736
|
+
if (isUserRejection(code2, message)) {
|
|
41737
|
+
return new WalletError("USER_REJECTED", `Request rejected in the wallet: ${message}`);
|
|
41738
|
+
}
|
|
41739
|
+
return new WalletError("WC_REQUEST_FAILED", `${message} (code ${code2})`);
|
|
41740
|
+
}
|
|
41741
|
+
async function settleWithin(promise, ms3) {
|
|
41742
|
+
let timer;
|
|
41743
|
+
const elapsed = new Promise((resolve2) => {
|
|
41744
|
+
timer = setTimeout(resolve2, ms3);
|
|
41745
|
+
});
|
|
41746
|
+
try {
|
|
41747
|
+
await Promise.race([promise.catch(() => void 0), elapsed]);
|
|
41748
|
+
} finally {
|
|
41749
|
+
clearTimeout(timer);
|
|
41750
|
+
}
|
|
41751
|
+
}
|
|
41595
41752
|
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.';
|
|
41596
41753
|
var WalletConnectProvider = class extends WalletProvider {
|
|
41597
41754
|
name = "walletconnect";
|
|
@@ -41599,12 +41756,17 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41599
41756
|
initPromise = null;
|
|
41600
41757
|
currentSession = null;
|
|
41601
41758
|
config;
|
|
41759
|
+
storage;
|
|
41760
|
+
/** Bumped by each pairing request and by disconnect(); an approval that
|
|
41761
|
+
* arrives for an older pairing is revoked instead of bound. */
|
|
41762
|
+
pairingGeneration = 0;
|
|
41602
41763
|
sessionCallback = null;
|
|
41603
41764
|
sessionEndedCallback = null;
|
|
41604
41765
|
pairingEventCallback = null;
|
|
41605
41766
|
constructor(config) {
|
|
41606
41767
|
super();
|
|
41607
41768
|
this.config = config;
|
|
41769
|
+
this.storage = config.storagePath ? new FileKeyValueStorage(config.storagePath, { onWarning: config.onStorageWarning }) : null;
|
|
41608
41770
|
}
|
|
41609
41771
|
async ensureClient() {
|
|
41610
41772
|
if (this.client) return this.client;
|
|
@@ -41612,12 +41774,26 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41612
41774
|
this.initPromise = Os3.init({
|
|
41613
41775
|
projectId: this.config.projectId,
|
|
41614
41776
|
relayUrl: this.config.relayUrl || "wss://relay.walletconnect.com",
|
|
41615
|
-
metadata: this.config.metadata || DEFAULT_METADATA
|
|
41777
|
+
metadata: this.config.metadata || DEFAULT_METADATA,
|
|
41778
|
+
...this.storage ? { storage: this.storage } : {}
|
|
41616
41779
|
});
|
|
41617
|
-
|
|
41780
|
+
try {
|
|
41781
|
+
this.client = await this.initPromise;
|
|
41782
|
+
} catch (err) {
|
|
41783
|
+
this.initPromise = null;
|
|
41784
|
+
throw err;
|
|
41785
|
+
}
|
|
41618
41786
|
this.setupEventHandlers(this.client);
|
|
41619
41787
|
return this.client;
|
|
41620
41788
|
}
|
|
41789
|
+
/** `client.request` with wallet-side errors converted (see toRequestError). */
|
|
41790
|
+
async request(client, args) {
|
|
41791
|
+
try {
|
|
41792
|
+
return await client.request(args);
|
|
41793
|
+
} catch (err) {
|
|
41794
|
+
throw toRequestError(err);
|
|
41795
|
+
}
|
|
41796
|
+
}
|
|
41621
41797
|
onPairingEvent(callback) {
|
|
41622
41798
|
this.pairingEventCallback = callback;
|
|
41623
41799
|
}
|
|
@@ -41704,7 +41880,7 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41704
41880
|
if (!session) throw new WalletError("WC_NOT_CONNECTED", WC_NOT_CONNECTED_MSG);
|
|
41705
41881
|
const client = await this.ensureClient();
|
|
41706
41882
|
const hexMessage = `0x${Buffer.from(message, "utf8").toString("hex")}`;
|
|
41707
|
-
return
|
|
41883
|
+
return this.request(client, {
|
|
41708
41884
|
topic: session.topic,
|
|
41709
41885
|
chainId,
|
|
41710
41886
|
request: {
|
|
@@ -41718,7 +41894,7 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41718
41894
|
if (!session) throw new WalletError("WC_NOT_CONNECTED", WC_NOT_CONNECTED_MSG);
|
|
41719
41895
|
const client = await this.ensureClient();
|
|
41720
41896
|
const caipChainId = chainKey.includes(":") ? chainKey : `eip155:${chainId}`;
|
|
41721
|
-
return
|
|
41897
|
+
return this.request(client, {
|
|
41722
41898
|
topic: session.topic,
|
|
41723
41899
|
chainId: caipChainId,
|
|
41724
41900
|
request: {
|
|
@@ -41742,7 +41918,7 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41742
41918
|
if (value && !value.startsWith("0x")) {
|
|
41743
41919
|
value = "0x" + BigInt(value).toString(16);
|
|
41744
41920
|
}
|
|
41745
|
-
return
|
|
41921
|
+
return this.request(client, {
|
|
41746
41922
|
topic: session.topic,
|
|
41747
41923
|
chainId: params.chainId,
|
|
41748
41924
|
request: {
|
|
@@ -41763,8 +41939,38 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41763
41939
|
supportsChain(chainId) {
|
|
41764
41940
|
return chainId.startsWith("eip155:");
|
|
41765
41941
|
}
|
|
41942
|
+
/**
|
|
41943
|
+
* Ends a session in two phases:
|
|
41944
|
+
* 1. Tell the peer wallet (best-effort, bounded by PEER_NOTIFY_TIMEOUT_MS:
|
|
41945
|
+
* the relay may be unreachable and `client.disconnect` then never
|
|
41946
|
+
* settles).
|
|
41947
|
+
* 2. Always drop the session locally if it is still stored, so it never
|
|
41948
|
+
* lingers in persisted storage. If the peer was not reached, it keeps
|
|
41949
|
+
* a dead entry until the session expires.
|
|
41950
|
+
*/
|
|
41951
|
+
async revokeSession(client, topic) {
|
|
41952
|
+
await settleWithin(
|
|
41953
|
+
client.disconnect({ topic, reason: SESSION_CLEARED_REASON }),
|
|
41954
|
+
PEER_NOTIFY_TIMEOUT_MS
|
|
41955
|
+
);
|
|
41956
|
+
if (!client.session.getAll().some((s2) => s2.topic === topic)) return;
|
|
41957
|
+
try {
|
|
41958
|
+
await client.session.delete(topic, SESSION_CLEARED_REASON);
|
|
41959
|
+
} catch {
|
|
41960
|
+
}
|
|
41961
|
+
}
|
|
41962
|
+
/**
|
|
41963
|
+
* Starts a new pairing. Only one session is kept per storage, so any
|
|
41964
|
+
* existing session is revoked first: asking to pair again expresses the
|
|
41965
|
+
* intent to invalidate the previous one.
|
|
41966
|
+
*/
|
|
41766
41967
|
async connect(chains = getDefaultWcChains()) {
|
|
41767
41968
|
const client = await this.ensureClient();
|
|
41969
|
+
const generation = ++this.pairingGeneration;
|
|
41970
|
+
for (const session of client.session.getAll()) {
|
|
41971
|
+
await this.revokeSession(client, session.topic);
|
|
41972
|
+
}
|
|
41973
|
+
this.currentSession = null;
|
|
41768
41974
|
const nsMap = {};
|
|
41769
41975
|
for (const chain2 of chains) {
|
|
41770
41976
|
const ns2 = chain2.split(":")[0];
|
|
@@ -41786,7 +41992,7 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41786
41992
|
"WalletConnect relay handshake failed: no pairing URI returned. Check network and project ID, then retry."
|
|
41787
41993
|
);
|
|
41788
41994
|
}
|
|
41789
|
-
this.handleApproval(approval());
|
|
41995
|
+
this.handleApproval(approval(), generation);
|
|
41790
41996
|
const encodedUri = encodeURIComponent(uri);
|
|
41791
41997
|
const terminal = renderTerminalQR(uri);
|
|
41792
41998
|
const imageUrl = await renderPngDataUrl(uri);
|
|
@@ -41803,9 +42009,13 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41803
42009
|
expiresAt: Date.now() + 5 * 60 * 1e3
|
|
41804
42010
|
};
|
|
41805
42011
|
}
|
|
41806
|
-
async handleApproval(approval) {
|
|
42012
|
+
async handleApproval(approval, generation) {
|
|
41807
42013
|
try {
|
|
41808
42014
|
const session = await approval;
|
|
42015
|
+
if (generation !== this.pairingGeneration) {
|
|
42016
|
+
if (this.client) await this.revokeSession(this.client, session.topic);
|
|
42017
|
+
return;
|
|
42018
|
+
}
|
|
41809
42019
|
this.currentSession = this.sessionToWalletSession(session);
|
|
41810
42020
|
if (this.currentSession && this.sessionCallback) {
|
|
41811
42021
|
this.sessionCallback(this.currentSession);
|
|
@@ -41832,20 +42042,42 @@ var WalletConnectProvider = class extends WalletProvider {
|
|
|
41832
42042
|
`Timed out after ${Math.round(timeoutMs / 1e3)}s waiting for WalletConnect pairing approval.`
|
|
41833
42043
|
);
|
|
41834
42044
|
}
|
|
42045
|
+
/**
|
|
42046
|
+
* Revokes every stored session. Waits for an in-flight client init (e.g. a
|
|
42047
|
+
* restore still loading storage) so a session being restored is revoked
|
|
42048
|
+
* too; a no-op when the client was never started.
|
|
42049
|
+
*/
|
|
41835
42050
|
async disconnect() {
|
|
41836
|
-
|
|
41837
|
-
|
|
41838
|
-
|
|
42051
|
+
this.pairingGeneration++;
|
|
42052
|
+
let client = this.client;
|
|
42053
|
+
if (!client && this.initPromise) {
|
|
41839
42054
|
try {
|
|
41840
|
-
await this.
|
|
41841
|
-
topic: session.topic,
|
|
41842
|
-
reason: { code: 6e3, message: "Session cleared" }
|
|
41843
|
-
});
|
|
42055
|
+
client = await this.initPromise;
|
|
41844
42056
|
} catch {
|
|
42057
|
+
return;
|
|
41845
42058
|
}
|
|
41846
42059
|
}
|
|
42060
|
+
if (!client) return;
|
|
42061
|
+
for (const session of client.session.getAll()) {
|
|
42062
|
+
await this.revokeSession(client, session.topic);
|
|
42063
|
+
}
|
|
41847
42064
|
this.currentSession = null;
|
|
41848
42065
|
}
|
|
42066
|
+
/**
|
|
42067
|
+
* Resumes the session persisted by a previous process. Keeps the live
|
|
42068
|
+
* session with the latest expiry and revokes any other, so at most one
|
|
42069
|
+
* session remains. Returns null when none is live.
|
|
42070
|
+
*/
|
|
42071
|
+
async restore() {
|
|
42072
|
+
const client = await this.ensureClient();
|
|
42073
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
42074
|
+
const live = client.session.getAll().filter((s2) => s2.expiry > now).sort((a3, b3) => b3.expiry - a3.expiry);
|
|
42075
|
+
for (const stale of live.slice(1)) {
|
|
42076
|
+
await this.revokeSession(client, stale.topic);
|
|
42077
|
+
}
|
|
42078
|
+
this.currentSession = live.length > 0 ? this.sessionToWalletSession(live[0]) : null;
|
|
42079
|
+
return this.currentSession;
|
|
42080
|
+
}
|
|
41849
42081
|
isConnected() {
|
|
41850
42082
|
return this.getActiveSession() !== null;
|
|
41851
42083
|
}
|
|
@@ -42058,18 +42290,18 @@ var import_promises2 = require("fs/promises");
|
|
|
42058
42290
|
var import_node_crypto = require("crypto");
|
|
42059
42291
|
var import_promises = require("fs/promises");
|
|
42060
42292
|
var import_node_path = require("path");
|
|
42061
|
-
async function writeAtomic(
|
|
42062
|
-
await (0, import_promises.mkdir)((0, import_node_path.dirname)(
|
|
42293
|
+
async function writeAtomic(path7, contents, mode = 420) {
|
|
42294
|
+
await (0, import_promises.mkdir)((0, import_node_path.dirname)(path7), { recursive: true });
|
|
42063
42295
|
let effectiveMode = mode;
|
|
42064
42296
|
try {
|
|
42065
|
-
const st4 = await (0, import_promises.stat)(
|
|
42297
|
+
const st4 = await (0, import_promises.stat)(path7);
|
|
42066
42298
|
effectiveMode = st4.mode & 511;
|
|
42067
42299
|
} catch {
|
|
42068
42300
|
}
|
|
42069
|
-
const tmpPath = `${
|
|
42301
|
+
const tmpPath = `${path7}.tmp.${(0, import_node_crypto.randomBytes)(8).toString("hex")}`;
|
|
42070
42302
|
await (0, import_promises.writeFile)(tmpPath, contents, { mode: effectiveMode });
|
|
42071
42303
|
try {
|
|
42072
|
-
await (0, import_promises.rename)(tmpPath,
|
|
42304
|
+
await (0, import_promises.rename)(tmpPath, path7);
|
|
42073
42305
|
} catch (err) {
|
|
42074
42306
|
try {
|
|
42075
42307
|
await (0, import_promises.rm)(tmpPath, { force: true });
|
|
@@ -42481,7 +42713,7 @@ async function processHarness(writer, deps, verbose, entry) {
|
|
|
42481
42713
|
try {
|
|
42482
42714
|
current = await writer.getCurrentEntry();
|
|
42483
42715
|
} catch (err) {
|
|
42484
|
-
const msg =
|
|
42716
|
+
const msg = errorMessage(err);
|
|
42485
42717
|
error(
|
|
42486
42718
|
`Skipping ${writer.displayName}: config at ${writer.configPath()} is invalid (${msg}). Fix it manually and re-run \`twak setup --harness ${writer.name}\`.`
|
|
42487
42719
|
);
|
|
@@ -42535,7 +42767,7 @@ async function runSkillsInstall(harness, deps) {
|
|
|
42535
42767
|
await deps.skillsInstaller.install(agent);
|
|
42536
42768
|
success(` Skills installed for ${harness}.`);
|
|
42537
42769
|
} catch (err) {
|
|
42538
|
-
const msg =
|
|
42770
|
+
const msg = errorMessage(err);
|
|
42539
42771
|
warn(
|
|
42540
42772
|
` Skills install for ${harness} failed (${msg}). The MCP wiring is in place; you can re-run \`npx skills add trustwallet/tw-agent-skills -a ${agent}\` manually.`
|
|
42541
42773
|
);
|
|
@@ -42567,7 +42799,7 @@ async function runNonInteractive2(opts, deps) {
|
|
|
42567
42799
|
try {
|
|
42568
42800
|
current = await writer.getCurrentEntry();
|
|
42569
42801
|
} catch (err) {
|
|
42570
|
-
const msg =
|
|
42802
|
+
const msg = errorMessage(err);
|
|
42571
42803
|
throw new CommandError(
|
|
42572
42804
|
"VALIDATION_ERROR",
|
|
42573
42805
|
`Cannot wire ${writer.displayName}: config at ${writer.configPath()} is invalid (${msg}). Fix it manually and re-run.`
|
|
@@ -42903,6 +43135,7 @@ function registerAuthCommand(program3) {
|
|
|
42903
43135
|
}
|
|
42904
43136
|
|
|
42905
43137
|
// src/commands/wallet.ts
|
|
43138
|
+
var fs6 = __toESM(require("fs"));
|
|
42906
43139
|
init_dist2();
|
|
42907
43140
|
var import_chalk6 = __toESM(require_source());
|
|
42908
43141
|
init_dist();
|
|
@@ -42930,7 +43163,7 @@ function mapBroadcastError(err) {
|
|
|
42930
43163
|
throw new TransferError("BROADCAST_FAILED", err.message);
|
|
42931
43164
|
}
|
|
42932
43165
|
}
|
|
42933
|
-
const msg =
|
|
43166
|
+
const msg = errorMessage(err);
|
|
42934
43167
|
if (/\binsufficient\b/i.test(msg)) {
|
|
42935
43168
|
throw new TransferError("INSUFFICIENT_BALANCE", msg);
|
|
42936
43169
|
}
|
|
@@ -42961,7 +43194,7 @@ var TransferExecutor = class {
|
|
|
42961
43194
|
return {
|
|
42962
43195
|
success: false,
|
|
42963
43196
|
code: "UNKNOWN_ERROR",
|
|
42964
|
-
message:
|
|
43197
|
+
message: errorMessage(err)
|
|
42965
43198
|
};
|
|
42966
43199
|
}
|
|
42967
43200
|
}
|
|
@@ -42981,7 +43214,7 @@ var TransferExecutor = class {
|
|
|
42981
43214
|
try {
|
|
42982
43215
|
resolvedTo = await resolveAddressOrName(params.to);
|
|
42983
43216
|
} catch (err) {
|
|
42984
|
-
const msg =
|
|
43217
|
+
const msg = errorMessage(err);
|
|
42985
43218
|
if (msg.includes("Could not resolve name")) {
|
|
42986
43219
|
throw new TransferError("ENS_NOT_FOUND", `Could not resolve ENS name: ${params.to}`);
|
|
42987
43220
|
}
|
|
@@ -43122,7 +43355,7 @@ function parseInterval(value) {
|
|
|
43122
43355
|
return num;
|
|
43123
43356
|
}
|
|
43124
43357
|
function errMsg(err) {
|
|
43125
|
-
return
|
|
43358
|
+
return errorMessage(err);
|
|
43126
43359
|
}
|
|
43127
43360
|
async function fetchPriceMap(client, assetIds) {
|
|
43128
43361
|
const assets = [...new Set(assetIds)];
|
|
@@ -43572,6 +43805,46 @@ function box(content) {
|
|
|
43572
43805
|
});
|
|
43573
43806
|
}
|
|
43574
43807
|
|
|
43808
|
+
// src/walletconnect-config.ts
|
|
43809
|
+
var path4 = __toESM(require("path"));
|
|
43810
|
+
init_dist();
|
|
43811
|
+
init_dist2();
|
|
43812
|
+
var RESTORE_TIMEOUT_MS = 1e4;
|
|
43813
|
+
function wcStoragePath() {
|
|
43814
|
+
return path4.join(new FileStore().getDataDir(), "walletconnect.json");
|
|
43815
|
+
}
|
|
43816
|
+
async function resolveWcProjectId(flag) {
|
|
43817
|
+
const fromFlagOrEnv = flag || process.env.WALLETCONNECT_PROJECT_ID;
|
|
43818
|
+
if (fromFlagOrEnv) return fromFlagOrEnv;
|
|
43819
|
+
try {
|
|
43820
|
+
const creds = await new CredentialManager().load();
|
|
43821
|
+
return creds?.walletConnectProjectId || void 0;
|
|
43822
|
+
} catch {
|
|
43823
|
+
return void 0;
|
|
43824
|
+
}
|
|
43825
|
+
}
|
|
43826
|
+
function createWalletConnectProvider(projectId) {
|
|
43827
|
+
return new WalletConnectProvider({
|
|
43828
|
+
projectId,
|
|
43829
|
+
storagePath: wcStoragePath(),
|
|
43830
|
+
onStorageWarning: (msg) => warn(msg)
|
|
43831
|
+
});
|
|
43832
|
+
}
|
|
43833
|
+
async function withTimeout(promise, ms3) {
|
|
43834
|
+
let timer;
|
|
43835
|
+
const timeout = new Promise((_2, reject) => {
|
|
43836
|
+
timer = setTimeout(
|
|
43837
|
+
() => reject(new WalletError("NETWORK_ERROR", `Timed out after ${ms3 / 1e3}s`)),
|
|
43838
|
+
ms3
|
|
43839
|
+
);
|
|
43840
|
+
});
|
|
43841
|
+
try {
|
|
43842
|
+
return await Promise.race([promise, timeout]);
|
|
43843
|
+
} finally {
|
|
43844
|
+
clearTimeout(timer);
|
|
43845
|
+
}
|
|
43846
|
+
}
|
|
43847
|
+
|
|
43575
43848
|
// src/commands/wallet.ts
|
|
43576
43849
|
function getQRString(address) {
|
|
43577
43850
|
try {
|
|
@@ -43585,6 +43858,36 @@ function getQRString(address) {
|
|
|
43585
43858
|
return "";
|
|
43586
43859
|
}
|
|
43587
43860
|
}
|
|
43861
|
+
var WC_PROJECT_ID_HINT = "Use --project-id, set WALLETCONNECT_PROJECT_ID, or run `twak init --wc-project-id <id>`";
|
|
43862
|
+
async function openStoredWalletConnect(projectIdFlag) {
|
|
43863
|
+
if (!fs6.existsSync(wcStoragePath())) return null;
|
|
43864
|
+
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);
|
|
43872
|
+
const session = await withTimeout(provider.restore(), RESTORE_TIMEOUT_MS);
|
|
43873
|
+
return { provider, session };
|
|
43874
|
+
}
|
|
43875
|
+
async function getWalletConnectStatus(projectIdFlag) {
|
|
43876
|
+
try {
|
|
43877
|
+
const stored = await openStoredWalletConnect(projectIdFlag);
|
|
43878
|
+
if (!stored?.session) return { connected: false };
|
|
43879
|
+
const { peerName, address, expiry } = stored.session;
|
|
43880
|
+
return {
|
|
43881
|
+
connected: true,
|
|
43882
|
+
peer: peerName,
|
|
43883
|
+
address,
|
|
43884
|
+
expiresAt: new Date(expiry * 1e3).toISOString()
|
|
43885
|
+
};
|
|
43886
|
+
} catch (err) {
|
|
43887
|
+
warn(`Could not check WalletConnect session: ${errorMessage(err)}`);
|
|
43888
|
+
return { connected: false };
|
|
43889
|
+
}
|
|
43890
|
+
}
|
|
43588
43891
|
function registerWalletCommand(program3) {
|
|
43589
43892
|
const wallet = program3.command("wallet").description("Manage agent wallet");
|
|
43590
43893
|
wallet.command("create").description("Create a new agent wallet").requiredOption("--password <password>", "Password to encrypt the wallet").option("--no-keychain", "Do not save password to OS keychain").option("--skip-password-check", "Skip password strength validation").option("--json", "JSON output").action(async (opts) => {
|
|
@@ -43864,21 +44167,23 @@ ${qr3}`;
|
|
|
43864
44167
|
}
|
|
43865
44168
|
safeExit();
|
|
43866
44169
|
});
|
|
43867
|
-
wallet.command("connect").description("Connect external wallet via WalletConnect").option(
|
|
44170
|
+
wallet.command("connect").description("Connect external wallet via WalletConnect").option(
|
|
44171
|
+
"--project-id <id>",
|
|
44172
|
+
"WalletConnect project ID (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
|
|
44173
|
+
).option(
|
|
43868
44174
|
"--chains <list>",
|
|
43869
|
-
"Comma-separated CAIP-2 chain IDs"
|
|
43870
|
-
"eip155:1,eip155:56,eip155:137,eip155:8453,eip155:42161"
|
|
44175
|
+
"Comma-separated CAIP-2 chain IDs (default: all supported EVM chains)"
|
|
43871
44176
|
).option("--timeout <seconds>", "Connection timeout in seconds", "300").option("--json", "JSON output").action(async (opts) => {
|
|
43872
44177
|
try {
|
|
43873
|
-
const projectId = opts.projectId
|
|
44178
|
+
const projectId = await resolveWcProjectId(opts.projectId);
|
|
43874
44179
|
if (!projectId) {
|
|
43875
44180
|
throw new WalletError(
|
|
43876
44181
|
"VALIDATION_ERROR",
|
|
43877
|
-
|
|
44182
|
+
`WalletConnect project ID required. ${WC_PROJECT_ID_HINT}`
|
|
43878
44183
|
);
|
|
43879
44184
|
}
|
|
43880
|
-
const provider =
|
|
43881
|
-
const chains = opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
44185
|
+
const provider = createWalletConnectProvider(projectId);
|
|
44186
|
+
const chains = opts.chains ? opts.chains.split(",").map((s2) => s2.trim()).filter(Boolean) : getDefaultWcChains();
|
|
43882
44187
|
info("Connecting via WalletConnect...");
|
|
43883
44188
|
const result = await provider.connect(chains);
|
|
43884
44189
|
const qr3 = getQRString(result.uri);
|
|
@@ -43910,7 +44215,32 @@ ${qr3}`;
|
|
|
43910
44215
|
}
|
|
43911
44216
|
safeExit();
|
|
43912
44217
|
});
|
|
43913
|
-
wallet.command("
|
|
44218
|
+
wallet.command("disconnect").description("Revoke the stored WalletConnect session").option(
|
|
44219
|
+
"--project-id <id>",
|
|
44220
|
+
"WalletConnect project ID (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
|
|
44221
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
44222
|
+
try {
|
|
44223
|
+
const stored = await openStoredWalletConnect(opts.projectId);
|
|
44224
|
+
const disconnected = !!stored?.session;
|
|
44225
|
+
if (stored?.session) {
|
|
44226
|
+
await withTimeout(stored.provider.disconnect(), RESTORE_TIMEOUT_MS);
|
|
44227
|
+
}
|
|
44228
|
+
if (opts.json) {
|
|
44229
|
+
output({ disconnected }, true);
|
|
44230
|
+
} else if (disconnected) {
|
|
44231
|
+
success("WalletConnect session disconnected");
|
|
44232
|
+
} else {
|
|
44233
|
+
info("No WalletConnect session");
|
|
44234
|
+
}
|
|
44235
|
+
} catch (err) {
|
|
44236
|
+
handleCommandError(err, opts.json, "WalletConnect disconnect failed");
|
|
44237
|
+
}
|
|
44238
|
+
safeExit();
|
|
44239
|
+
});
|
|
44240
|
+
wallet.command("status").description("Check wallet configuration status").option(
|
|
44241
|
+
"--project-id <id>",
|
|
44242
|
+
"WalletConnect project ID used to check the stored session (or WALLETCONNECT_PROJECT_ID / twak init --wc-project-id)"
|
|
44243
|
+
).option("--json", "JSON output").action(async (opts) => {
|
|
43914
44244
|
try {
|
|
43915
44245
|
const store = new WalletConfigStore();
|
|
43916
44246
|
const exists = await store.exists();
|
|
@@ -43924,13 +44254,15 @@ ${qr3}`;
|
|
|
43924
44254
|
createdAt = config?.createdAt;
|
|
43925
44255
|
addressCount = config?.chains?.length ?? totalChains;
|
|
43926
44256
|
}
|
|
44257
|
+
const walletConnect = await getWalletConnectStatus(opts.projectId);
|
|
43927
44258
|
const result = {
|
|
43928
44259
|
agentWallet: exists ? "configured" : "not configured",
|
|
43929
44260
|
keychainPassword: keychainHasPassword ? "stored" : "not stored",
|
|
43930
44261
|
chains: totalChains,
|
|
43931
44262
|
supportedChains: totalChains,
|
|
43932
44263
|
...createdAt ? { createdAt } : {},
|
|
43933
|
-
...addressCount !== void 0 ? { addressCount } : {}
|
|
44264
|
+
...addressCount !== void 0 ? { addressCount } : {},
|
|
44265
|
+
walletConnect
|
|
43934
44266
|
};
|
|
43935
44267
|
if (opts.json) {
|
|
43936
44268
|
output(result, true);
|
|
@@ -43945,6 +44277,11 @@ ${qr3}`;
|
|
|
43945
44277
|
console.log(` ${import_chalk6.default.dim("Chains")} ${totalChains} supported`);
|
|
43946
44278
|
if (addressCount !== void 0)
|
|
43947
44279
|
console.log(` ${import_chalk6.default.dim("Addresses")} ${addressCount}`);
|
|
44280
|
+
console.log(
|
|
44281
|
+
` ${import_chalk6.default.dim("WalletConnect")} ${walletConnect.connected ? import_chalk6.default.green(
|
|
44282
|
+
`connected to ${walletConnect.peer || "wallet"} (${walletConnect.address}), expires ${walletConnect.expiresAt}`
|
|
44283
|
+
) : import_chalk6.default.yellow("not connected")}`
|
|
44284
|
+
);
|
|
43948
44285
|
if (!exists) info("\nRun `twak wallet create --password <pw>` to create a wallet.");
|
|
43949
44286
|
}
|
|
43950
44287
|
} catch (err) {
|
|
@@ -44312,8 +44649,8 @@ var SwapExecutor = class {
|
|
|
44312
44649
|
explorerUrl: getExplorerTxUrl(params.fromChain, hash)
|
|
44313
44650
|
};
|
|
44314
44651
|
} catch (err) {
|
|
44315
|
-
let msg = err
|
|
44316
|
-
let code2 = classifySwapError(msg);
|
|
44652
|
+
let msg = errorMessage(err);
|
|
44653
|
+
let code2 = err instanceof CommandError ? err.code : classifySwapError(msg);
|
|
44317
44654
|
if (approvalHash) {
|
|
44318
44655
|
code2 = "APPROVAL_SENT_SWAP_FAILED";
|
|
44319
44656
|
msg += `. Approval was sent (tx: ${approvalHash}). Check allowance before retrying.`;
|
|
@@ -44387,7 +44724,7 @@ var SwapExecutor = class {
|
|
|
44387
44724
|
if (status.failed)
|
|
44388
44725
|
throw new Error(`Transaction failed: ${status.error || "unknown error"}`);
|
|
44389
44726
|
} catch (e2) {
|
|
44390
|
-
const err = e2 instanceof Error ? e2 : new Error(
|
|
44727
|
+
const err = e2 instanceof Error ? e2 : new Error(errorMessage(e2));
|
|
44391
44728
|
if (err.message.startsWith("Transaction failed")) throw err;
|
|
44392
44729
|
if (!err.message.includes("not found") && !err.message.includes("Transaction not found"))
|
|
44393
44730
|
throw err;
|
|
@@ -45704,7 +46041,7 @@ var SecurityService = class {
|
|
|
45704
46041
|
query.toString()
|
|
45705
46042
|
);
|
|
45706
46043
|
} catch (err) {
|
|
45707
|
-
const msg =
|
|
46044
|
+
const msg = errorMessage(err);
|
|
45708
46045
|
const details = err?.details;
|
|
45709
46046
|
let detailsStr = "";
|
|
45710
46047
|
if (details != null) {
|
|
@@ -46788,6 +47125,9 @@ function registerQueryCommand(program3) {
|
|
|
46788
47125
|
});
|
|
46789
47126
|
}
|
|
46790
47127
|
|
|
47128
|
+
// src/commands/serve.ts
|
|
47129
|
+
var fs8 = __toESM(require("fs"));
|
|
47130
|
+
|
|
46791
47131
|
// ../actions/dist/index.mjs
|
|
46792
47132
|
init_dist();
|
|
46793
47133
|
var import_zod3 = require("zod");
|
|
@@ -48533,7 +48873,7 @@ function validateOfframpInput(input2, chainKey, nativeDecimals) {
|
|
|
48533
48873
|
try {
|
|
48534
48874
|
assertStrictPositiveAmount(input2.cryptoAmount, decimals);
|
|
48535
48875
|
} catch (err) {
|
|
48536
|
-
throw new TransferError("VALIDATION_ERROR",
|
|
48876
|
+
throw new TransferError("VALIDATION_ERROR", errorMessage(err));
|
|
48537
48877
|
}
|
|
48538
48878
|
return decimals;
|
|
48539
48879
|
}
|
|
@@ -49198,12 +49538,10 @@ var WalletModeActionProvider = class extends ActionProvider {
|
|
|
49198
49538
|
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).";
|
|
49199
49539
|
walletContext;
|
|
49200
49540
|
agentWallet;
|
|
49201
|
-
walletConnectFactory;
|
|
49202
49541
|
constructor(options) {
|
|
49203
49542
|
super();
|
|
49204
49543
|
this.walletContext = options.walletContext;
|
|
49205
49544
|
this.agentWallet = options.agentWallet;
|
|
49206
|
-
this.walletConnectFactory = options.walletConnectFactory;
|
|
49207
49545
|
}
|
|
49208
49546
|
getActions() {
|
|
49209
49547
|
return [this.switchWalletMode(), this.getWalletStatus()];
|
|
@@ -49246,14 +49584,13 @@ var WalletModeActionProvider = class extends ActionProvider {
|
|
|
49246
49584
|
await this.walletContext.bindLocal(this.agentWallet);
|
|
49247
49585
|
return this.snapshotResponse(this.walletContext.snapshot());
|
|
49248
49586
|
}
|
|
49249
|
-
if (!this.
|
|
49587
|
+
if (!this.walletContext.walletConnectAvailable) {
|
|
49250
49588
|
throw new WalletError(
|
|
49251
49589
|
"VALIDATION_ERROR",
|
|
49252
49590
|
"WalletConnect is not configured. Set WALLETCONNECT_PROJECT_ID (env var or `twak init --wc-project-id <id>`) and restart the MCP server."
|
|
49253
49591
|
);
|
|
49254
49592
|
}
|
|
49255
|
-
|
|
49256
|
-
await this.walletContext.beginWalletConnect(wc3);
|
|
49593
|
+
await this.walletContext.beginWalletConnect();
|
|
49257
49594
|
return this.snapshotResponse(this.walletContext.snapshot());
|
|
49258
49595
|
}
|
|
49259
49596
|
};
|
|
@@ -51539,19 +51876,19 @@ var getRefs = (options) => {
|
|
|
51539
51876
|
};
|
|
51540
51877
|
|
|
51541
51878
|
// ../../node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/errorMessages.js
|
|
51542
|
-
function addErrorMessage(res, key,
|
|
51879
|
+
function addErrorMessage(res, key, errorMessage2, refs) {
|
|
51543
51880
|
if (!refs?.errorMessages)
|
|
51544
51881
|
return;
|
|
51545
|
-
if (
|
|
51882
|
+
if (errorMessage2) {
|
|
51546
51883
|
res.errorMessage = {
|
|
51547
51884
|
...res.errorMessage,
|
|
51548
|
-
[key]:
|
|
51885
|
+
[key]: errorMessage2
|
|
51549
51886
|
};
|
|
51550
51887
|
}
|
|
51551
51888
|
}
|
|
51552
|
-
function setResponseValueAndErrors(res, key, value,
|
|
51889
|
+
function setResponseValueAndErrors(res, key, value, errorMessage2, refs) {
|
|
51553
51890
|
res[key] = value;
|
|
51554
|
-
addErrorMessage(res, key,
|
|
51891
|
+
addErrorMessage(res, key, errorMessage2, refs);
|
|
51555
51892
|
}
|
|
51556
51893
|
|
|
51557
51894
|
// ../../node_modules/.pnpm/zod-to-json-schema@3.25.1_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js
|
|
@@ -52848,8 +53185,8 @@ var Protocol = class {
|
|
|
52848
53185
|
if (queuedMessage.type === "response") {
|
|
52849
53186
|
resolver(message);
|
|
52850
53187
|
} else {
|
|
52851
|
-
const
|
|
52852
|
-
const error2 = new McpError(
|
|
53188
|
+
const errorMessage2 = message;
|
|
53189
|
+
const error2 = new McpError(errorMessage2.error.code, errorMessage2.error.message, errorMessage2.error.data);
|
|
52853
53190
|
resolver(error2);
|
|
52854
53191
|
}
|
|
52855
53192
|
} else {
|
|
@@ -54143,23 +54480,23 @@ var Server = class extends Protocol {
|
|
|
54143
54480
|
const wrappedHandler = async (request, extra) => {
|
|
54144
54481
|
const validatedRequest = safeParse2(CallToolRequestSchema, request);
|
|
54145
54482
|
if (!validatedRequest.success) {
|
|
54146
|
-
const
|
|
54147
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${
|
|
54483
|
+
const errorMessage2 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
|
54484
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call request: ${errorMessage2}`);
|
|
54148
54485
|
}
|
|
54149
54486
|
const { params } = validatedRequest.data;
|
|
54150
54487
|
const result = await Promise.resolve(handler(request, extra));
|
|
54151
54488
|
if (params.task) {
|
|
54152
54489
|
const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
|
|
54153
54490
|
if (!taskValidationResult.success) {
|
|
54154
|
-
const
|
|
54155
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${
|
|
54491
|
+
const errorMessage2 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
|
|
54492
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage2}`);
|
|
54156
54493
|
}
|
|
54157
54494
|
return taskValidationResult.data;
|
|
54158
54495
|
}
|
|
54159
54496
|
const validationResult = safeParse2(CallToolResultSchema, result);
|
|
54160
54497
|
if (!validationResult.success) {
|
|
54161
|
-
const
|
|
54162
|
-
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${
|
|
54498
|
+
const errorMessage2 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
|
54499
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid tools/call result: ${errorMessage2}`);
|
|
54163
54500
|
}
|
|
54164
54501
|
return validationResult.data;
|
|
54165
54502
|
};
|
|
@@ -54605,7 +54942,7 @@ var TwakMcpServer = class {
|
|
|
54605
54942
|
const isZodValidation = error2 instanceof Error && error2.name === "ZodError";
|
|
54606
54943
|
const payload = classified ?? (isZodValidation ? { code: "VALIDATION_ERROR", message: error2.message } : {
|
|
54607
54944
|
code: "UNKNOWN_ERROR",
|
|
54608
|
-
message: error2
|
|
54945
|
+
message: errorMessage(error2)
|
|
54609
54946
|
});
|
|
54610
54947
|
return {
|
|
54611
54948
|
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
@@ -54639,6 +54976,8 @@ function errorCodeToHttpStatus(code2) {
|
|
|
54639
54976
|
case "SLIPPAGE_EXCEEDED":
|
|
54640
54977
|
case "VALUE_LIMIT_EXCEEDED":
|
|
54641
54978
|
case "TX_FAILED":
|
|
54979
|
+
case "USER_REJECTED":
|
|
54980
|
+
case "WC_REQUEST_FAILED":
|
|
54642
54981
|
return 422;
|
|
54643
54982
|
case "RATE_LIMITED":
|
|
54644
54983
|
return 429;
|
|
@@ -54777,7 +55116,7 @@ var TwakRestServer = class {
|
|
|
54777
55116
|
const isZodValidation = err instanceof Error && err.name === "ZodError";
|
|
54778
55117
|
const payload = classified ?? (isZodValidation ? { code: "VALIDATION_ERROR", message: err.message } : {
|
|
54779
55118
|
code: err instanceof CommandError ? err.code : "UNKNOWN_ERROR",
|
|
54780
|
-
message: err
|
|
55119
|
+
message: errorMessage(err)
|
|
54781
55120
|
});
|
|
54782
55121
|
const status = isZodValidation ? 400 : errorCodeToHttpStatus(payload.code);
|
|
54783
55122
|
res.writeHead(status);
|
|
@@ -54788,6 +55127,7 @@ var TwakRestServer = class {
|
|
|
54788
55127
|
};
|
|
54789
55128
|
|
|
54790
55129
|
// src/commands/serve.ts
|
|
55130
|
+
init_dist();
|
|
54791
55131
|
function registerServeCommand(program3) {
|
|
54792
55132
|
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(
|
|
54793
55133
|
"--host <host>",
|
|
@@ -54823,25 +55163,33 @@ function registerServeCommand(program3) {
|
|
|
54823
55163
|
passwordResolver: () => resolvePassword(opts)
|
|
54824
55164
|
});
|
|
54825
55165
|
}
|
|
54826
|
-
|
|
54827
|
-
|
|
55166
|
+
const wcProjectId = await resolveWcProjectId(opts.wcProjectId);
|
|
55167
|
+
const walletContext = new WalletContext({
|
|
55168
|
+
walletConnectFactory: wcProjectId ? () => createWalletConnectProvider(wcProjectId) : void 0
|
|
55169
|
+
});
|
|
55170
|
+
let resumeOutcome = "none";
|
|
55171
|
+
if (walletContext.walletConnectAvailable && fs8.existsSync(wcStoragePath())) {
|
|
54828
55172
|
try {
|
|
54829
|
-
const
|
|
54830
|
-
|
|
54831
|
-
|
|
55173
|
+
const resumed = await withTimeout(
|
|
55174
|
+
walletContext.restoreWalletConnect(),
|
|
55175
|
+
RESTORE_TIMEOUT_MS
|
|
55176
|
+
);
|
|
55177
|
+
if (resumed) {
|
|
55178
|
+
resumeOutcome = "resumed";
|
|
55179
|
+
info("Resumed WalletConnect session");
|
|
55180
|
+
}
|
|
55181
|
+
} catch (err) {
|
|
55182
|
+
resumeOutcome = "pending";
|
|
55183
|
+
warn(`Could not resume WalletConnect session: ${errorMessage(err)}`);
|
|
54832
55184
|
}
|
|
54833
55185
|
}
|
|
54834
|
-
|
|
54835
|
-
const walletContext = new WalletContext();
|
|
54836
|
-
if (agentWallet) {
|
|
55186
|
+
if (agentWallet && resumeOutcome === "none") {
|
|
54837
55187
|
await walletContext.bindLocal(agentWallet);
|
|
54838
55188
|
blockchainClient.setSigner(agentWallet.getSigner());
|
|
54839
55189
|
}
|
|
54840
55190
|
const registry = new ActionRegistry();
|
|
54841
55191
|
registry.register(new BalanceActionProvider());
|
|
54842
|
-
registry.register(
|
|
54843
|
-
new WalletModeActionProvider({ walletContext, agentWallet, walletConnectFactory })
|
|
54844
|
-
);
|
|
55192
|
+
registry.register(new WalletModeActionProvider({ walletContext, agentWallet }));
|
|
54845
55193
|
registry.register(new SwapActionProvider(swapClient, walletContext, blockchainClient));
|
|
54846
55194
|
registry.register(new SecurityActionProvider());
|
|
54847
55195
|
registry.register(new HistoryActionProvider());
|
|
@@ -54890,7 +55238,7 @@ function registerServeCommand(program3) {
|
|
|
54890
55238
|
},
|
|
54891
55239
|
{
|
|
54892
55240
|
intervalSec,
|
|
54893
|
-
onTickError: (err) => error(`Automation tick error: ${
|
|
55241
|
+
onTickError: (err) => error(`Automation tick error: ${errorMessage(err)}`)
|
|
54894
55242
|
}
|
|
54895
55243
|
);
|
|
54896
55244
|
info(
|
|
@@ -54908,21 +55256,19 @@ function registerServeCommand(program3) {
|
|
|
54908
55256
|
host: opts.host,
|
|
54909
55257
|
apiKey: client.hmacSecret
|
|
54910
55258
|
});
|
|
54911
|
-
registerShutdownHandlers([agentWallet],
|
|
55259
|
+
registerShutdownHandlers([agentWallet], () => {
|
|
54912
55260
|
watcher?.stop();
|
|
54913
|
-
await walletContext.reset();
|
|
54914
55261
|
restServer.stop();
|
|
54915
55262
|
});
|
|
54916
55263
|
try {
|
|
54917
55264
|
await restServer.start();
|
|
54918
55265
|
} catch (err) {
|
|
54919
|
-
error(`Error: ${
|
|
55266
|
+
error(`Error: ${errorMessage(err)}`);
|
|
54920
55267
|
process.exit(1);
|
|
54921
55268
|
}
|
|
54922
55269
|
} else {
|
|
54923
55270
|
registerShutdownHandlers([agentWallet], () => {
|
|
54924
55271
|
watcher?.stop();
|
|
54925
|
-
return walletContext.reset();
|
|
54926
55272
|
});
|
|
54927
55273
|
const mcpServer = new TwakMcpServer(registry, context);
|
|
54928
55274
|
console.error("TW Agent MCP server starting...");
|
|
@@ -55273,10 +55619,7 @@ ${url}`);
|
|
|
55273
55619
|
try {
|
|
55274
55620
|
assertStrictPositiveAmount(opts.amount, decimals);
|
|
55275
55621
|
} catch (err) {
|
|
55276
|
-
throw new TransferError(
|
|
55277
|
-
"VALIDATION_ERROR",
|
|
55278
|
-
err instanceof Error ? err.message : String(err)
|
|
55279
|
-
);
|
|
55622
|
+
throw new TransferError("VALIDATION_ERROR", errorMessage(err));
|
|
55280
55623
|
}
|
|
55281
55624
|
if (!opts.skipSafetyCheck) {
|
|
55282
55625
|
const maxUsd = parseFloat(opts.maxUsd ?? String(DEFAULT_MAX_OFFRAMP_USD2));
|
|
@@ -55831,15 +56174,15 @@ function registerX402Command(program3) {
|
|
|
55831
56174
|
}
|
|
55832
56175
|
|
|
55833
56176
|
// src/analytics.ts
|
|
55834
|
-
var
|
|
56177
|
+
var fs9 = __toESM(require("fs"));
|
|
55835
56178
|
var os4 = __toESM(require("os"));
|
|
55836
|
-
var
|
|
55837
|
-
var
|
|
56179
|
+
var path6 = __toESM(require("path"));
|
|
56180
|
+
var crypto8 = __toESM(require("crypto"));
|
|
55838
56181
|
|
|
55839
56182
|
// package.json
|
|
55840
56183
|
var package_default = {
|
|
55841
56184
|
name: "@trustwallet/cli",
|
|
55842
|
-
version: "0.
|
|
56185
|
+
version: "0.21.0",
|
|
55843
56186
|
description: "TWAK CLI \u2014 command-line interface for Trust Wallet Agent Kit",
|
|
55844
56187
|
main: "dist/index.js",
|
|
55845
56188
|
types: "dist/index.d.ts",
|
|
@@ -55916,10 +56259,10 @@ try {
|
|
|
55916
56259
|
} catch (_e6) {
|
|
55917
56260
|
}
|
|
55918
56261
|
var AMPLITUDE_API_KEY = process.env.AMPLITUDE_API_KEY || "__AMPLITUDE_API_KEY__";
|
|
55919
|
-
var CONFIG_DIR =
|
|
55920
|
-
var ID_FILE =
|
|
55921
|
-
var OPT_IN_FILE =
|
|
55922
|
-
var OPT_OUT_FILE =
|
|
56262
|
+
var CONFIG_DIR = path6.join(os4.homedir(), ".twak");
|
|
56263
|
+
var ID_FILE = path6.join(CONFIG_DIR, "analytics-id");
|
|
56264
|
+
var OPT_IN_FILE = path6.join(CONFIG_DIR, "telemetry-on");
|
|
56265
|
+
var OPT_OUT_FILE = path6.join(CONFIG_DIR, "telemetry-off");
|
|
55923
56266
|
var initialized2 = false;
|
|
55924
56267
|
function isOptedOut() {
|
|
55925
56268
|
if (process.argv.includes("--no-analytics")) return true;
|
|
@@ -55927,31 +56270,31 @@ function isOptedOut() {
|
|
|
55927
56270
|
if (env === "off" || env === "0" || env === "false") return true;
|
|
55928
56271
|
if (env === "on" || env === "1" || env === "true") return false;
|
|
55929
56272
|
try {
|
|
55930
|
-
if (
|
|
55931
|
-
return !
|
|
56273
|
+
if (fs9.existsSync(OPT_OUT_FILE)) return true;
|
|
56274
|
+
return !fs9.existsSync(OPT_IN_FILE);
|
|
55932
56275
|
} catch (_e6) {
|
|
55933
56276
|
return true;
|
|
55934
56277
|
}
|
|
55935
56278
|
}
|
|
55936
56279
|
function setOptOut2(optOut) {
|
|
55937
|
-
|
|
56280
|
+
fs9.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
55938
56281
|
if (optOut) {
|
|
55939
|
-
if (
|
|
55940
|
-
|
|
56282
|
+
if (fs9.existsSync(OPT_IN_FILE)) fs9.unlinkSync(OPT_IN_FILE);
|
|
56283
|
+
fs9.writeFileSync(OPT_OUT_FILE, "");
|
|
55941
56284
|
} else {
|
|
55942
|
-
|
|
55943
|
-
if (
|
|
56285
|
+
fs9.writeFileSync(OPT_IN_FILE, "");
|
|
56286
|
+
if (fs9.existsSync(OPT_OUT_FILE)) fs9.unlinkSync(OPT_OUT_FILE);
|
|
55944
56287
|
}
|
|
55945
56288
|
}
|
|
55946
56289
|
function getUserId() {
|
|
55947
56290
|
try {
|
|
55948
|
-
if (
|
|
56291
|
+
if (fs9.existsSync(ID_FILE)) return fs9.readFileSync(ID_FILE, "utf-8").trim();
|
|
55949
56292
|
} catch (_e6) {
|
|
55950
56293
|
}
|
|
55951
|
-
const id =
|
|
56294
|
+
const id = crypto8.randomUUID();
|
|
55952
56295
|
try {
|
|
55953
|
-
|
|
55954
|
-
|
|
56296
|
+
fs9.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
56297
|
+
fs9.writeFileSync(ID_FILE, id);
|
|
55955
56298
|
} catch (_e6) {
|
|
55956
56299
|
}
|
|
55957
56300
|
return id;
|