@jaw.id/cli 0.1.26 → 0.2.1
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/base-command.js +3 -1
- package/dist/base-command.js.map +1 -1
- package/dist/commands/config/set.js +140 -12
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +3 -1
- package/dist/commands/config/show.js.map +1 -1
- package/dist/commands/config/write.js +6 -4
- package/dist/commands/config/write.js.map +1 -1
- package/dist/commands/disconnect.js +24 -10
- package/dist/commands/disconnect.js.map +1 -1
- package/dist/commands/mcp/index.js +2426 -94
- package/dist/commands/mcp/index.js.map +1 -1
- package/dist/commands/rpc/call.js +197 -45
- package/dist/commands/rpc/call.js.map +1 -1
- package/dist/commands/session/add.js +1547 -0
- package/dist/commands/session/add.js.map +1 -0
- package/dist/commands/session/revoke.js +181 -54
- package/dist/commands/session/revoke.js.map +1 -1
- package/dist/commands/session/setup.js +516 -65
- package/dist/commands/session/setup.js.map +1 -1
- package/dist/commands/session/status.js +315 -6
- package/dist/commands/session/status.js.map +1 -1
- package/dist/commands/version.js +3 -1
- package/dist/commands/version.js.map +1 -1
- package/dist/commands/x402/log.js +344 -0
- package/dist/commands/x402/log.js.map +1 -0
- package/dist/commands/x402/pay.js +2122 -0
- package/dist/commands/x402/pay.js.map +1 -0
- package/dist/commands/x402/status.js +1047 -0
- package/dist/commands/x402/status.js.map +1 -0
- package/dist/index.js +41 -14
- package/dist/index.js.map +1 -1
- package/dist/lib/bridge-singleton.js +41 -14
- package/dist/lib/bridge-singleton.js.map +1 -1
- package/dist/lib/config.js +26 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/keystore.js +13 -2
- package/dist/lib/keystore.js.map +1 -1
- package/dist/lib/paths.js +3 -1
- package/dist/lib/paths.js.map +1 -1
- package/dist/lib/payment-lock.js +121 -0
- package/dist/lib/payment-lock.js.map +1 -0
- package/dist/lib/session-bridge.js +148 -24
- package/dist/lib/session-bridge.js.map +1 -1
- package/dist/lib/session-config.js +78 -11
- package/dist/lib/session-config.js.map +1 -1
- package/dist/lib/terminal.js +22 -0
- package/dist/lib/terminal.js.map +1 -0
- package/dist/lib/validation.js +3 -3
- package/dist/lib/validation.js.map +1 -1
- package/dist/lib/ws-bridge.js +22 -10
- package/dist/lib/ws-bridge.js.map +1 -1
- package/dist/mcp/handlers/config.js +73 -6
- package/dist/mcp/handlers/config.js.map +1 -1
- package/dist/mcp/handlers/daemon.js +43 -12
- package/dist/mcp/handlers/daemon.js.map +1 -1
- package/dist/mcp/handlers/resources.js +119 -0
- package/dist/mcp/handlers/resources.js.map +1 -1
- package/dist/mcp/handlers/rpc.js +269 -60
- package/dist/mcp/handlers/rpc.js.map +1 -1
- package/dist/mcp/helpers.js +50 -3
- package/dist/mcp/helpers.js.map +1 -1
- package/dist/mcp/server.js +2426 -94
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +43 -3
- package/dist/mcp/tools.js.map +1 -1
- package/dist/x402/log-view.js +160 -0
- package/dist/x402/log-view.js.map +1 -0
- package/dist/x402/status-report.js +90 -0
- package/dist/x402/status-report.js.map +1 -0
- package/oclif.manifest.json +405 -11
- package/package.json +5 -2
|
@@ -4,6 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
import * as crypto from 'crypto';
|
|
6
6
|
import WebSocket from 'ws';
|
|
7
|
+
import { encodeFunctionData, maxUint256, erc20Abi } from 'viem';
|
|
7
8
|
|
|
8
9
|
// src/commands/rpc/call.ts
|
|
9
10
|
var JAW_DIR = path.join(os.homedir(), ".jaw");
|
|
@@ -13,7 +14,9 @@ var PATHS = {
|
|
|
13
14
|
session: path.join(JAW_DIR, "session.json"),
|
|
14
15
|
relay: path.join(JAW_DIR, "relay.json"),
|
|
15
16
|
keystore: path.join(JAW_DIR, "keystore.json"),
|
|
16
|
-
sessionConfig: path.join(JAW_DIR, "session-config.json")
|
|
17
|
+
sessionConfig: path.join(JAW_DIR, "session-config.json"),
|
|
18
|
+
x402Log: path.join(JAW_DIR, "x402-log.jsonl"),
|
|
19
|
+
paymentLock: path.join(JAW_DIR, "x402-payment.lock")
|
|
17
20
|
};
|
|
18
21
|
|
|
19
22
|
// src/lib/validation.ts
|
|
@@ -223,7 +226,18 @@ function bufferToBase64(buf) {
|
|
|
223
226
|
}
|
|
224
227
|
|
|
225
228
|
// src/lib/ws-bridge.ts
|
|
229
|
+
function buildInitPayload(config) {
|
|
230
|
+
return {
|
|
231
|
+
type: "init",
|
|
232
|
+
apiKey: config.apiKey,
|
|
233
|
+
chainId: config.chainId,
|
|
234
|
+
ens: config.ens,
|
|
235
|
+
paymasterUrl: config.paymasterUrl,
|
|
236
|
+
...config.paymasterUrl && config.paymasterContext ? { paymasterContext: config.paymasterContext } : {}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
226
239
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
240
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
|
|
227
241
|
var MAX_MESSAGE_BYTES = 5 * 1024 * 1024;
|
|
228
242
|
var BROWSER_REOPEN_COOLDOWN_MS = 5e3;
|
|
229
243
|
var MAX_RECONNECT_ATTEMPTS = 3;
|
|
@@ -232,6 +246,7 @@ var WSBridge = class {
|
|
|
232
246
|
relayUrl;
|
|
233
247
|
session;
|
|
234
248
|
timeout;
|
|
249
|
+
connectTimeout;
|
|
235
250
|
config;
|
|
236
251
|
privateKeyHex;
|
|
237
252
|
publicKeyHex;
|
|
@@ -253,6 +268,7 @@ var WSBridge = class {
|
|
|
253
268
|
this.relayUrl = options.relayUrl;
|
|
254
269
|
this.session = options.session;
|
|
255
270
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
271
|
+
this.connectTimeout = options.connectTimeout ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
256
272
|
this.config = options.config;
|
|
257
273
|
this.privateKeyHex = options.privateKeyHex;
|
|
258
274
|
this.publicKeyHex = options.publicKeyHex;
|
|
@@ -281,17 +297,16 @@ var WSBridge = class {
|
|
|
281
297
|
let expectingKeyExchange = !this.peerPublicKeyHex;
|
|
282
298
|
const timer = setTimeout(() => {
|
|
283
299
|
ws.close();
|
|
284
|
-
reject(
|
|
285
|
-
|
|
300
|
+
reject(
|
|
301
|
+
new Error(
|
|
302
|
+
`Browser did not connect within ${Math.round(this.connectTimeout / 1e3)}s.
|
|
303
|
+
Run \`jaw disconnect\` then try again, or raise JAW_BRIDGE_TIMEOUT_MS.`
|
|
304
|
+
)
|
|
305
|
+
);
|
|
306
|
+
}, this.connectTimeout);
|
|
286
307
|
const sendEncryptedInit = async () => {
|
|
287
308
|
if (!this.sharedSecret) return;
|
|
288
|
-
const envelope = await encryptMessage(this.sharedSecret,
|
|
289
|
-
type: "init",
|
|
290
|
-
apiKey: this.config.apiKey,
|
|
291
|
-
chainId: this.config.chainId,
|
|
292
|
-
ens: this.config.ens,
|
|
293
|
-
paymasterUrl: this.config.paymasterUrl
|
|
294
|
-
});
|
|
309
|
+
const envelope = await encryptMessage(this.sharedSecret, buildInitPayload(this.config));
|
|
295
310
|
this.sendRaw(ws, JSON.stringify({ type: "encrypted", ...envelope }));
|
|
296
311
|
};
|
|
297
312
|
const waitForReady = () => {
|
|
@@ -569,6 +584,10 @@ var DEFAULT_KEYS_URL = "https://keys.jaw.id";
|
|
|
569
584
|
var DEFAULT_RELAY_URL = "wss://relay.jaw.id";
|
|
570
585
|
async function getBridge(options) {
|
|
571
586
|
const config = loadConfig();
|
|
587
|
+
const envTimeout = Number(process.env["JAW_BRIDGE_TIMEOUT_MS"]);
|
|
588
|
+
const fromEnv = Number.isFinite(envTimeout) && envTimeout > 0 ? envTimeout : void 0;
|
|
589
|
+
const timeout = options.timeout ?? fromEnv;
|
|
590
|
+
const connectTimeout = options.connectTimeout ?? fromEnv;
|
|
572
591
|
const keysUrl = options.keysUrl ?? config.keysUrl ?? DEFAULT_KEYS_URL;
|
|
573
592
|
const relayUrl = options.relayUrl ?? config.relayUrl ?? DEFAULT_RELAY_URL;
|
|
574
593
|
const chainId = options.chainId ?? config.defaultChain ?? 1;
|
|
@@ -581,7 +600,7 @@ async function getBridge(options) {
|
|
|
581
600
|
let relaySession = loadRelaySession();
|
|
582
601
|
if (relaySession && relaySession.relayUrl === relayUrl && relaySession.peerPublicKey) {
|
|
583
602
|
try {
|
|
584
|
-
return await connectBridge(
|
|
603
|
+
return await connectBridge({ ...options, timeout }, relaySession, chainId, keysUrl, relayUrl, false);
|
|
585
604
|
} catch {
|
|
586
605
|
deleteRelaySession();
|
|
587
606
|
relaySession = null;
|
|
@@ -591,7 +610,7 @@ async function getBridge(options) {
|
|
|
591
610
|
}
|
|
592
611
|
const session = await createNewSession(relayUrl);
|
|
593
612
|
saveRelaySession(session);
|
|
594
|
-
return await connectBridge(
|
|
613
|
+
return await connectBridge({ ...options, timeout, connectTimeout }, session, chainId, keysUrl, relayUrl, true);
|
|
595
614
|
}
|
|
596
615
|
async function createNewSession(relayUrl) {
|
|
597
616
|
const kp = await generateKeyPair();
|
|
@@ -606,17 +625,20 @@ async function createNewSession(relayUrl) {
|
|
|
606
625
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
607
626
|
};
|
|
608
627
|
}
|
|
609
|
-
async function connectBridge(
|
|
628
|
+
async function connectBridge(options, relaySession, chainId, keysUrl, relayUrl, openBrowser) {
|
|
610
629
|
const config = loadConfig();
|
|
630
|
+
const paymaster = config.paymasters?.[chainId];
|
|
611
631
|
const bridge = new WSBridge({
|
|
612
632
|
relayUrl,
|
|
613
633
|
session: relaySession.session,
|
|
614
634
|
timeout: options.timeout,
|
|
635
|
+
connectTimeout: options.connectTimeout,
|
|
615
636
|
config: {
|
|
616
637
|
apiKey: options.apiKey,
|
|
617
638
|
chainId,
|
|
618
639
|
ens: options.ens ?? config.ens,
|
|
619
|
-
paymasterUrl:
|
|
640
|
+
paymasterUrl: paymaster?.url,
|
|
641
|
+
paymasterContext: paymaster?.context
|
|
620
642
|
},
|
|
621
643
|
privateKeyHex: relaySession.privateKey,
|
|
622
644
|
publicKeyHex: relaySession.publicKey,
|
|
@@ -626,6 +648,12 @@ async function connectBridge(relaySession, options, chainId, keysUrl, relayUrl,
|
|
|
626
648
|
// onBrowserNeeded — only open a browser for new sessions
|
|
627
649
|
openBrowser ? async () => {
|
|
628
650
|
const bridgeUrl = buildBridgeUrl(keysUrl, relaySession.session, relayUrl, relaySession.publicKey);
|
|
651
|
+
if (process.env["JAW_NO_BROWSER"]) {
|
|
652
|
+
process.stderr.write(`Open this URL to approve:
|
|
653
|
+
${bridgeUrl}
|
|
654
|
+
`);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
629
657
|
const { default: open } = await import('open');
|
|
630
658
|
await open(bridgeUrl);
|
|
631
659
|
} : void 0,
|
|
@@ -668,9 +696,7 @@ var SESSION_SUPPORTED_METHODS = /* @__PURE__ */ new Set([
|
|
|
668
696
|
"eth_requestAccounts",
|
|
669
697
|
"eth_accounts",
|
|
670
698
|
"wallet_sendCalls",
|
|
671
|
-
"wallet_getCallsStatus"
|
|
672
|
-
"personal_sign",
|
|
673
|
-
"eth_signTypedData_v4"
|
|
699
|
+
"wallet_getCallsStatus"
|
|
674
700
|
]);
|
|
675
701
|
function supportsSessionMode(method) {
|
|
676
702
|
return SESSION_SUPPORTED_METHODS.has(method);
|
|
@@ -688,6 +714,9 @@ function loadSessionKey() {
|
|
|
688
714
|
}
|
|
689
715
|
return parsed.privateKey;
|
|
690
716
|
}
|
|
717
|
+
function isLegacySession(config) {
|
|
718
|
+
return config.mode !== "eip7702";
|
|
719
|
+
}
|
|
691
720
|
function loadSessionConfig() {
|
|
692
721
|
if (!fs.existsSync(PATHS.sessionConfig)) {
|
|
693
722
|
throw new Error("No session configured. Run `jaw session setup` first.");
|
|
@@ -700,20 +729,86 @@ function loadSessionConfig() {
|
|
|
700
729
|
}
|
|
701
730
|
}
|
|
702
731
|
|
|
732
|
+
// src/x402/asset-registry.ts
|
|
733
|
+
var USDC_BY_NETWORK = {
|
|
734
|
+
"eip155:8453": {
|
|
735
|
+
address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
736
|
+
chainId: 8453,
|
|
737
|
+
wireNetwork: "eip155:8453",
|
|
738
|
+
usdcName: "USD Coin",
|
|
739
|
+
usdcVersion: "2",
|
|
740
|
+
decimals: 6
|
|
741
|
+
},
|
|
742
|
+
"eip155:84532": {
|
|
743
|
+
address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
|
|
744
|
+
chainId: 84532,
|
|
745
|
+
wireNetwork: "eip155:84532",
|
|
746
|
+
usdcName: "USDC",
|
|
747
|
+
usdcVersion: "2",
|
|
748
|
+
decimals: 6
|
|
749
|
+
},
|
|
750
|
+
"eip155:137": {
|
|
751
|
+
address: "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359",
|
|
752
|
+
chainId: 137,
|
|
753
|
+
wireNetwork: "eip155:137",
|
|
754
|
+
usdcName: "USD Coin",
|
|
755
|
+
usdcVersion: "2",
|
|
756
|
+
decimals: 6
|
|
757
|
+
},
|
|
758
|
+
"eip155:80002": {
|
|
759
|
+
address: "0x41E94Eb019C0762f9Bfcf9Fb1E58725BfB0e7582",
|
|
760
|
+
chainId: 80002,
|
|
761
|
+
wireNetwork: "eip155:80002",
|
|
762
|
+
usdcName: "USDC",
|
|
763
|
+
usdcVersion: "2",
|
|
764
|
+
decimals: 6
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
function usdcForNetwork(network) {
|
|
768
|
+
return Object.hasOwn(USDC_BY_NETWORK, network) ? USDC_BY_NETWORK[network] : void 0;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// src/x402/permit2.ts
|
|
772
|
+
var PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3";
|
|
773
|
+
|
|
703
774
|
// src/lib/session-bridge.ts
|
|
775
|
+
var JAW_ERC20_PAYMASTER_URL = "https://api.justaname.id/proxy/v1/rpc/erc20-paymaster";
|
|
776
|
+
function resolvePaymaster(options) {
|
|
777
|
+
if (options.paymasterUrl) {
|
|
778
|
+
return { paymasterUrl: options.paymasterUrl, paymasterContext: options.paymasterContext };
|
|
779
|
+
}
|
|
780
|
+
const configured = loadConfig().paymasters?.[options.chainId];
|
|
781
|
+
if (configured) {
|
|
782
|
+
return { paymasterUrl: configured.url, paymasterContext: configured.context };
|
|
783
|
+
}
|
|
784
|
+
if (!options.apiKey) return {};
|
|
785
|
+
const asset = usdcForNetwork(`eip155:${options.chainId}`);
|
|
786
|
+
if (!asset) {
|
|
787
|
+
console.warn(
|
|
788
|
+
`[jaw] No USDC in the x402 asset registry for chain ${options.chainId}, so no ERC-20 paymaster can be engaged. Gas will come out of the account\u2019s native balance. Set \`paymasters\` in your config to sponsor this chain.`
|
|
789
|
+
);
|
|
790
|
+
return {};
|
|
791
|
+
}
|
|
792
|
+
const url = new URL(JAW_ERC20_PAYMASTER_URL);
|
|
793
|
+
url.searchParams.set("chainId", String(options.chainId));
|
|
794
|
+
url.searchParams.set("api-key", options.apiKey);
|
|
795
|
+
return { paymasterUrl: url.toString(), paymasterContext: { token: asset.address } };
|
|
796
|
+
}
|
|
797
|
+
function explainUnchargeableSender(err, sessionAddress) {
|
|
798
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
799
|
+
if (!message.includes("Could not size the ERC-20 paymaster approval")) return err;
|
|
800
|
+
return new Error(
|
|
801
|
+
`${message}
|
|
802
|
+
|
|
803
|
+
If ${sessionAddress} holds no USDC, that is why: it pays for its own gas and cannot be charged with an empty balance. Send it 0.1 USDC, or run \`jaw session setup\` again.`,
|
|
804
|
+
{ cause: err }
|
|
805
|
+
);
|
|
806
|
+
}
|
|
704
807
|
var SessionBridge = class {
|
|
705
808
|
options;
|
|
706
809
|
session = null;
|
|
707
810
|
constructor(options) {
|
|
708
|
-
this.options = { ...options };
|
|
709
|
-
if (!this.options.paymasterUrl) {
|
|
710
|
-
const config = loadConfig();
|
|
711
|
-
const pm = config.paymasters?.[this.options.chainId];
|
|
712
|
-
if (pm) {
|
|
713
|
-
this.options.paymasterUrl = pm.url;
|
|
714
|
-
this.options.paymasterContext = pm.context;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
811
|
+
this.options = { ...options, ...resolvePaymaster(options) };
|
|
717
812
|
}
|
|
718
813
|
async getSession() {
|
|
719
814
|
if (this.session) {
|
|
@@ -722,6 +817,11 @@ var SessionBridge = class {
|
|
|
722
817
|
}
|
|
723
818
|
const config = loadSessionConfig();
|
|
724
819
|
this.checkExpiry(config);
|
|
820
|
+
if (isLegacySession(config)) {
|
|
821
|
+
throw new Error(
|
|
822
|
+
"This session was created by an older CLI and uses a session address separate from the session key. Run `jaw session setup` to recreate it, which offers to revoke the old permission first. `jaw session status` still shows the old session, and `jaw session revoke` still revokes it."
|
|
823
|
+
);
|
|
824
|
+
}
|
|
725
825
|
if (config.chainId !== this.options.chainId) {
|
|
726
826
|
throw new Error(
|
|
727
827
|
`Session was created for chain ${config.chainId}, but --chain ${this.options.chainId} was requested. Run \`jaw session setup --chain ${this.options.chainId}\` to create a session for that chain.`
|
|
@@ -739,8 +839,14 @@ var SessionBridge = class {
|
|
|
739
839
|
paymasterUrl: this.options.paymasterUrl,
|
|
740
840
|
paymasterContext: this.options.paymasterContext
|
|
741
841
|
},
|
|
742
|
-
localAccount
|
|
842
|
+
localAccount,
|
|
843
|
+
{ eip7702: true }
|
|
743
844
|
);
|
|
845
|
+
if (account.address.toLowerCase() !== config.sessionAddress.toLowerCase()) {
|
|
846
|
+
throw new Error(
|
|
847
|
+
`Session key derives ${account.address}, but the stored session address is ${config.sessionAddress}. The keystore and session config are out of sync. Run \`jaw session setup\` to recreate the session.`
|
|
848
|
+
);
|
|
849
|
+
}
|
|
744
850
|
this.session = { account, config };
|
|
745
851
|
return this.session;
|
|
746
852
|
}
|
|
@@ -750,6 +856,46 @@ var SessionBridge = class {
|
|
|
750
856
|
throw new Error(`Session expired on ${expiryDate}. Run \`jaw session setup\` to create a new session.`);
|
|
751
857
|
}
|
|
752
858
|
}
|
|
859
|
+
/**
|
|
860
|
+
* Approve Permit2 to move one of the payer's tokens, and return the batch id.
|
|
861
|
+
*
|
|
862
|
+
* The only call this session sends outside its permission, and the only one
|
|
863
|
+
* that can be: `JustaPermissionManager` checks every call's selector against
|
|
864
|
+
* the grant, and the x402 grant permits `transfer` alone, so an approval
|
|
865
|
+
* routed through the permission reverts before anything else happens. Sent by
|
|
866
|
+
* the session on its own balance it never reaches the manager at all, whose
|
|
867
|
+
* approval revocation and Permit2 lockdown act on the granting account and
|
|
868
|
+
* only within their own execution.
|
|
869
|
+
*
|
|
870
|
+
* Being outside the permission is exactly why it is not a general send. It
|
|
871
|
+
* takes a token and nothing else: the spender is Permit2 and the amount is
|
|
872
|
+
* the maximum, neither reachable by a caller, and the token has to be the
|
|
873
|
+
* registry's USDC for this session's chain. There is no shape of argument
|
|
874
|
+
* that turns this into an arbitrary transfer, which matters because an agent
|
|
875
|
+
* reaches the tools that reach this.
|
|
876
|
+
*/
|
|
877
|
+
async approvePermit2(token) {
|
|
878
|
+
const { account, config } = await this.getSession();
|
|
879
|
+
const usdc = usdcForNetwork(`eip155:${config.chainId}`);
|
|
880
|
+
if (!usdc || token.toLowerCase() !== usdc.address.toLowerCase()) {
|
|
881
|
+
throw new Error(
|
|
882
|
+
`Refusing to approve Permit2 for ${token}: only the registry USDC on chain ${config.chainId} is allowed.`
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
const data = encodeFunctionData({
|
|
886
|
+
abi: erc20Abi,
|
|
887
|
+
functionName: "approve",
|
|
888
|
+
args: [PERMIT2_ADDRESS, maxUint256]
|
|
889
|
+
});
|
|
890
|
+
try {
|
|
891
|
+
const sent = await account.sendCalls([{ to: usdc.address, data }]);
|
|
892
|
+
const id = typeof sent === "string" ? sent : sent?.id;
|
|
893
|
+
if (!id) throw new Error("approval submitted but no call id was returned");
|
|
894
|
+
return id;
|
|
895
|
+
} catch (err) {
|
|
896
|
+
throw explainUnchargeableSender(err, config.sessionAddress);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
753
899
|
async request(method, params) {
|
|
754
900
|
const { account, config } = await this.getSession();
|
|
755
901
|
switch (method) {
|
|
@@ -759,24 +905,25 @@ var SessionBridge = class {
|
|
|
759
905
|
case "wallet_sendCalls": {
|
|
760
906
|
const payload = Array.isArray(params) ? params[0] : params;
|
|
761
907
|
const { calls } = payload;
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
908
|
+
const sendOptions = { permissionId: config.permissionId };
|
|
909
|
+
try {
|
|
910
|
+
return await account.sendCalls(calls, sendOptions);
|
|
911
|
+
} catch (err) {
|
|
912
|
+
throw explainUnchargeableSender(err, config.sessionAddress);
|
|
913
|
+
}
|
|
765
914
|
}
|
|
766
915
|
case "wallet_getCallsStatus": {
|
|
767
916
|
const batchId = Array.isArray(params) ? params[0] : params;
|
|
768
917
|
return account.getCallStatus(batchId);
|
|
769
918
|
}
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
case "eth_signTypedData_v4":
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
return account.signTypedData(typedData);
|
|
779
|
-
}
|
|
919
|
+
// Refused rather than absent, so the reason is on screen instead of a
|
|
920
|
+
// caller reading "not supported in auto mode" and looking for a flag. See
|
|
921
|
+
// `supportsSessionMode` in rpc-classifier.ts for why.
|
|
922
|
+
case "personal_sign":
|
|
923
|
+
case "eth_signTypedData_v4":
|
|
924
|
+
throw new Error(
|
|
925
|
+
`${method} is not available in auto mode: a signature the session makes is not a call, so it never reaches the spend caps or the ledger. Run it through the browser instead.`
|
|
926
|
+
);
|
|
780
927
|
case "wallet_grantPermissions":
|
|
781
928
|
throw new Error("Requires browser \u2014 run `jaw session setup`.");
|
|
782
929
|
case "wallet_revokePermissions":
|
|
@@ -814,8 +961,13 @@ var RpcCall = class _RpcCall extends BaseCommand {
|
|
|
814
961
|
...BaseCommand.baseFlags,
|
|
815
962
|
timeout: Flags.integer({
|
|
816
963
|
char: "t",
|
|
817
|
-
|
|
818
|
-
|
|
964
|
+
// No default. A default is indistinguishable from an explicit value, and
|
|
965
|
+
// this one was passed to getBridge on every run, which made
|
|
966
|
+
// JAW_BRIDGE_TIMEOUT_MS dead here: the env only applies when no caller
|
|
967
|
+
// named a timeout. The error text tells people to raise that knob, so it
|
|
968
|
+
// has to work in the command most likely to hit it. Unset falls through
|
|
969
|
+
// to the env, then to the built-in 120 seconds.
|
|
970
|
+
description: "Request timeout in seconds (default 120, or JAW_BRIDGE_TIMEOUT_MS)"
|
|
819
971
|
}),
|
|
820
972
|
session: Flags.boolean({
|
|
821
973
|
char: "s",
|
|
@@ -851,14 +1003,14 @@ var RpcCall = class _RpcCall extends BaseCommand {
|
|
|
851
1003
|
this.log(`Sending ${method} (session mode)...`);
|
|
852
1004
|
}
|
|
853
1005
|
} else {
|
|
854
|
-
const pm = config.paymasters?.[chainId];
|
|
855
1006
|
bridge = await getBridge({
|
|
856
1007
|
keysUrl: config.keysUrl,
|
|
857
1008
|
apiKey,
|
|
858
1009
|
chainId,
|
|
859
1010
|
ens: config.ens,
|
|
860
|
-
|
|
861
|
-
|
|
1011
|
+
// Undefined when the flag was not given, so getBridge falls through to
|
|
1012
|
+
// the env knob and then to its own default.
|
|
1013
|
+
timeout: flags.timeout === void 0 ? void 0 : flags.timeout * 1e3
|
|
862
1014
|
});
|
|
863
1015
|
if (!flags.quiet) {
|
|
864
1016
|
if (requiresBrowser(method)) {
|