@aomi-labs/client 0.1.5 → 0.1.7
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/cli.js +1033 -100
- package/dist/index.cjs +772 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +249 -1
- package/dist/index.d.ts +249 -1
- package/dist/index.js +749 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/cli.js
CHANGED
|
@@ -67,6 +67,30 @@ ${list}`);
|
|
|
67
67
|
}
|
|
68
68
|
return n;
|
|
69
69
|
}
|
|
70
|
+
function resolveExecutionMode(flags) {
|
|
71
|
+
const flagAA = flags["aa"] === "true";
|
|
72
|
+
const flagEoa = flags["eoa"] === "true";
|
|
73
|
+
if (flagAA && flagEoa) {
|
|
74
|
+
fatal("Choose only one of `--aa` or `--eoa`.");
|
|
75
|
+
}
|
|
76
|
+
if (flagAA) return "aa";
|
|
77
|
+
if (flagEoa) return "eoa";
|
|
78
|
+
return "aa";
|
|
79
|
+
}
|
|
80
|
+
function parseAAProvider(value) {
|
|
81
|
+
if (value === void 0) return void 0;
|
|
82
|
+
if (value === "alchemy" || value === "pimlico") {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
fatal("Unsupported AA provider. Use `alchemy` or `pimlico`.");
|
|
86
|
+
}
|
|
87
|
+
function parseAAMode(value) {
|
|
88
|
+
if (value === void 0) return void 0;
|
|
89
|
+
if (value === "4337" || value === "7702") {
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
fatal("Unsupported AA mode. Use `4337` or `7702`.");
|
|
93
|
+
}
|
|
70
94
|
function parseArgs(argv) {
|
|
71
95
|
const raw = argv.slice(2);
|
|
72
96
|
const command = raw[0] && !raw[0].startsWith("--") ? raw[0] : void 0;
|
|
@@ -96,16 +120,35 @@ function parseArgs(argv) {
|
|
|
96
120
|
return { command, positional, flags };
|
|
97
121
|
}
|
|
98
122
|
function getConfig(parsed) {
|
|
99
|
-
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
123
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
124
|
+
const usesSignFlags = parsed.flags["aa"] === "true" || parsed.flags["eoa"] === "true" || parsed.flags["aa-provider"] !== void 0 || parsed.flags["aa-mode"] !== void 0;
|
|
125
|
+
if (usesSignFlags && parsed.command !== "sign") {
|
|
126
|
+
fatal(
|
|
127
|
+
"AA/EOA execution flags are only supported on `aomi sign <tx-id>`."
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
const execution = resolveExecutionMode(parsed.flags);
|
|
131
|
+
const aaProvider = parseAAProvider(
|
|
132
|
+
(_a3 = parsed.flags["aa-provider"]) != null ? _a3 : process.env.AOMI_AA_PROVIDER
|
|
133
|
+
);
|
|
134
|
+
const aaMode = parseAAMode(
|
|
135
|
+
(_b = parsed.flags["aa-mode"]) != null ? _b : process.env.AOMI_AA_MODE
|
|
136
|
+
);
|
|
137
|
+
if (execution === "eoa" && (aaProvider || aaMode)) {
|
|
138
|
+
fatal("`--aa-provider` and `--aa-mode` cannot be used with `--eoa`.");
|
|
139
|
+
}
|
|
100
140
|
return {
|
|
101
|
-
baseUrl: (
|
|
102
|
-
apiKey: (
|
|
103
|
-
app: (
|
|
104
|
-
model: (
|
|
105
|
-
publicKey: (
|
|
106
|
-
privateKey: (
|
|
107
|
-
chainRpcUrl: (
|
|
108
|
-
chain: parseChainId((
|
|
141
|
+
baseUrl: (_d = (_c = parsed.flags["backend-url"]) != null ? _c : process.env.AOMI_BASE_URL) != null ? _d : "https://api.aomi.dev",
|
|
142
|
+
apiKey: (_e = parsed.flags["api-key"]) != null ? _e : process.env.AOMI_API_KEY,
|
|
143
|
+
app: (_g = (_f = parsed.flags["app"]) != null ? _f : process.env.AOMI_APP) != null ? _g : "default",
|
|
144
|
+
model: (_h = parsed.flags["model"]) != null ? _h : process.env.AOMI_MODEL,
|
|
145
|
+
publicKey: (_i = parsed.flags["public-key"]) != null ? _i : process.env.AOMI_PUBLIC_KEY,
|
|
146
|
+
privateKey: (_j = parsed.flags["private-key"]) != null ? _j : process.env.PRIVATE_KEY,
|
|
147
|
+
chainRpcUrl: (_k = parsed.flags["rpc-url"]) != null ? _k : process.env.CHAIN_RPC_URL,
|
|
148
|
+
chain: parseChainId((_l = parsed.flags["chain"]) != null ? _l : process.env.AOMI_CHAIN_ID),
|
|
149
|
+
execution,
|
|
150
|
+
aaProvider,
|
|
151
|
+
aaMode
|
|
109
152
|
};
|
|
110
153
|
}
|
|
111
154
|
function createRuntime(argv) {
|
|
@@ -1514,12 +1557,12 @@ var ClientSession = class extends TypedEventEmitter {
|
|
|
1514
1557
|
}
|
|
1515
1558
|
}
|
|
1516
1559
|
assertUserStateAligned(actualUserState) {
|
|
1517
|
-
if (!this.userState) {
|
|
1560
|
+
if (!this.userState || !actualUserState) {
|
|
1518
1561
|
return;
|
|
1519
1562
|
}
|
|
1520
|
-
if (!
|
|
1563
|
+
if (!isSubsetMatch(this.userState, actualUserState)) {
|
|
1521
1564
|
const expected = JSON.stringify(sortJson(this.userState));
|
|
1522
|
-
const actual = JSON.stringify(sortJson(actualUserState
|
|
1565
|
+
const actual = JSON.stringify(sortJson(actualUserState));
|
|
1523
1566
|
throw new Error(
|
|
1524
1567
|
`Backend user_state mismatch. expected subset=${expected} actual=${actual}`
|
|
1525
1568
|
);
|
|
@@ -1623,6 +1666,40 @@ function walletRequestToPendingTx(request) {
|
|
|
1623
1666
|
payload: request.payload
|
|
1624
1667
|
};
|
|
1625
1668
|
}
|
|
1669
|
+
function pendingTxToCallList(tx) {
|
|
1670
|
+
var _a3, _b;
|
|
1671
|
+
if (tx.kind !== "transaction" || !tx.to) {
|
|
1672
|
+
throw new Error("pending_transaction_missing_call_data");
|
|
1673
|
+
}
|
|
1674
|
+
return [
|
|
1675
|
+
{
|
|
1676
|
+
to: tx.to,
|
|
1677
|
+
value: (_a3 = tx.value) != null ? _a3 : "0",
|
|
1678
|
+
data: tx.data,
|
|
1679
|
+
chainId: (_b = tx.chainId) != null ? _b : 1
|
|
1680
|
+
}
|
|
1681
|
+
];
|
|
1682
|
+
}
|
|
1683
|
+
function toSignedTransactionRecord(tx, execution, from, chainId, timestamp, aaProvider, aaMode) {
|
|
1684
|
+
return {
|
|
1685
|
+
id: tx.id,
|
|
1686
|
+
kind: "transaction",
|
|
1687
|
+
txHash: execution.txHash,
|
|
1688
|
+
txHashes: execution.txHashes,
|
|
1689
|
+
executionKind: execution.executionKind,
|
|
1690
|
+
aaProvider,
|
|
1691
|
+
aaMode,
|
|
1692
|
+
batched: execution.batched,
|
|
1693
|
+
sponsored: execution.sponsored,
|
|
1694
|
+
AAAddress: execution.AAAddress,
|
|
1695
|
+
delegationAddress: execution.delegationAddress,
|
|
1696
|
+
from,
|
|
1697
|
+
to: tx.to,
|
|
1698
|
+
value: tx.value,
|
|
1699
|
+
chainId,
|
|
1700
|
+
timestamp
|
|
1701
|
+
};
|
|
1702
|
+
}
|
|
1626
1703
|
function formatTxLine(tx, prefix) {
|
|
1627
1704
|
var _a3;
|
|
1628
1705
|
const parts = [`${prefix} ${tx.id}`];
|
|
@@ -1638,6 +1715,29 @@ function formatTxLine(tx, prefix) {
|
|
|
1638
1715
|
parts.push(`(${new Date(tx.timestamp).toLocaleTimeString()})`);
|
|
1639
1716
|
return parts.join(" ");
|
|
1640
1717
|
}
|
|
1718
|
+
function formatSignedTxLine(tx, prefix) {
|
|
1719
|
+
var _a3;
|
|
1720
|
+
const parts = [`${prefix} ${tx.id}`];
|
|
1721
|
+
if (tx.kind === "eip712_sign") {
|
|
1722
|
+
parts.push(`sig: ${(_a3 = tx.signature) == null ? void 0 : _a3.slice(0, 20)}...`);
|
|
1723
|
+
if (tx.description) parts.push(tx.description);
|
|
1724
|
+
} else {
|
|
1725
|
+
parts.push(`hash: ${tx.txHash}`);
|
|
1726
|
+
if (tx.executionKind) parts.push(`exec: ${tx.executionKind}`);
|
|
1727
|
+
if (tx.aaProvider) parts.push(`provider: ${tx.aaProvider}`);
|
|
1728
|
+
if (tx.aaMode) parts.push(`mode: ${tx.aaMode}`);
|
|
1729
|
+
if (tx.txHashes && tx.txHashes.length > 1) {
|
|
1730
|
+
parts.push(`txs: ${tx.txHashes.length}`);
|
|
1731
|
+
}
|
|
1732
|
+
if (tx.sponsored) parts.push("sponsored");
|
|
1733
|
+
if (tx.AAAddress) parts.push(`aa: ${tx.AAAddress}`);
|
|
1734
|
+
if (tx.delegationAddress) parts.push(`delegation: ${tx.delegationAddress}`);
|
|
1735
|
+
if (tx.to) parts.push(`to: ${tx.to}`);
|
|
1736
|
+
if (tx.value) parts.push(`value: ${tx.value}`);
|
|
1737
|
+
}
|
|
1738
|
+
parts.push(`(${new Date(tx.timestamp).toLocaleTimeString()})`);
|
|
1739
|
+
return parts.join(" ");
|
|
1740
|
+
}
|
|
1641
1741
|
|
|
1642
1742
|
// src/cli/commands/chat.ts
|
|
1643
1743
|
async function chatCommand(runtime) {
|
|
@@ -1914,17 +2014,25 @@ function toPendingTxMetadata(tx) {
|
|
|
1914
2014
|
};
|
|
1915
2015
|
}
|
|
1916
2016
|
function toSignedTxMetadata(tx) {
|
|
1917
|
-
var _a3, _b, _c, _d, _e, _f, _g;
|
|
2017
|
+
var _a3, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
1918
2018
|
return {
|
|
1919
2019
|
id: tx.id,
|
|
1920
2020
|
kind: tx.kind,
|
|
1921
2021
|
txHash: (_a3 = tx.txHash) != null ? _a3 : null,
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
2022
|
+
txHashes: (_b = tx.txHashes) != null ? _b : null,
|
|
2023
|
+
executionKind: (_c = tx.executionKind) != null ? _c : null,
|
|
2024
|
+
aaProvider: (_d = tx.aaProvider) != null ? _d : null,
|
|
2025
|
+
aaMode: (_e = tx.aaMode) != null ? _e : null,
|
|
2026
|
+
batched: (_f = tx.batched) != null ? _f : null,
|
|
2027
|
+
sponsored: (_g = tx.sponsored) != null ? _g : null,
|
|
2028
|
+
AAAddress: (_h = tx.AAAddress) != null ? _h : null,
|
|
2029
|
+
delegationAddress: (_i = tx.delegationAddress) != null ? _i : null,
|
|
2030
|
+
signature: (_j = tx.signature) != null ? _j : null,
|
|
2031
|
+
from: (_k = tx.from) != null ? _k : null,
|
|
2032
|
+
to: (_l = tx.to) != null ? _l : null,
|
|
2033
|
+
value: (_m = tx.value) != null ? _m : null,
|
|
2034
|
+
chainId: (_n = tx.chainId) != null ? _n : null,
|
|
2035
|
+
description: (_o = tx.description) != null ? _o : null,
|
|
1928
2036
|
timestamp: new Date(tx.timestamp).toISOString()
|
|
1929
2037
|
};
|
|
1930
2038
|
}
|
|
@@ -2183,10 +2291,647 @@ function sessionCommand(runtime) {
|
|
|
2183
2291
|
|
|
2184
2292
|
// src/cli/commands/wallet.ts
|
|
2185
2293
|
import { createWalletClient, http } from "viem";
|
|
2186
|
-
import {
|
|
2294
|
+
import { createInterface } from "readline/promises";
|
|
2295
|
+
import { privateKeyToAccount as privateKeyToAccount2 } from "viem/accounts";
|
|
2187
2296
|
import * as viemChains from "viem/chains";
|
|
2297
|
+
|
|
2298
|
+
// src/aa/types.ts
|
|
2299
|
+
function getAAChainConfig(config, calls, chainsById) {
|
|
2300
|
+
if (!config.enabled || calls.length === 0) {
|
|
2301
|
+
return null;
|
|
2302
|
+
}
|
|
2303
|
+
const chainIds = Array.from(new Set(calls.map((call) => call.chainId)));
|
|
2304
|
+
if (chainIds.length !== 1) {
|
|
2305
|
+
return null;
|
|
2306
|
+
}
|
|
2307
|
+
const chainId = chainIds[0];
|
|
2308
|
+
if (!chainsById[chainId]) {
|
|
2309
|
+
return null;
|
|
2310
|
+
}
|
|
2311
|
+
const chainConfig = config.chains.find((item) => item.chainId === chainId);
|
|
2312
|
+
if (!(chainConfig == null ? void 0 : chainConfig.enabled)) {
|
|
2313
|
+
return null;
|
|
2314
|
+
}
|
|
2315
|
+
if (calls.length > 1 && !chainConfig.allowBatching) {
|
|
2316
|
+
return null;
|
|
2317
|
+
}
|
|
2318
|
+
return chainConfig;
|
|
2319
|
+
}
|
|
2320
|
+
function buildAAExecutionPlan(config, chainConfig) {
|
|
2321
|
+
const mode = chainConfig.supportedModes.includes(chainConfig.defaultMode) ? chainConfig.defaultMode : chainConfig.supportedModes[0];
|
|
2322
|
+
if (!mode) {
|
|
2323
|
+
throw new Error(`No smart account mode configured for chain ${chainConfig.chainId}`);
|
|
2324
|
+
}
|
|
2325
|
+
return {
|
|
2326
|
+
provider: config.provider,
|
|
2327
|
+
chainId: chainConfig.chainId,
|
|
2328
|
+
mode,
|
|
2329
|
+
batchingEnabled: chainConfig.allowBatching,
|
|
2330
|
+
sponsorship: chainConfig.sponsorship,
|
|
2331
|
+
fallbackToEoa: config.fallbackToEoa
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
function mapCall(call) {
|
|
2335
|
+
return {
|
|
2336
|
+
to: call.to,
|
|
2337
|
+
value: BigInt(call.value),
|
|
2338
|
+
data: call.data ? call.data : void 0
|
|
2339
|
+
};
|
|
2340
|
+
}
|
|
2341
|
+
var DEFAULT_AA_CONFIG = {
|
|
2342
|
+
enabled: true,
|
|
2343
|
+
provider: "alchemy",
|
|
2344
|
+
fallbackToEoa: true,
|
|
2345
|
+
chains: [
|
|
2346
|
+
{
|
|
2347
|
+
chainId: 1,
|
|
2348
|
+
enabled: true,
|
|
2349
|
+
defaultMode: "7702",
|
|
2350
|
+
supportedModes: ["4337", "7702"],
|
|
2351
|
+
allowBatching: true,
|
|
2352
|
+
sponsorship: "optional"
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
chainId: 137,
|
|
2356
|
+
enabled: true,
|
|
2357
|
+
defaultMode: "4337",
|
|
2358
|
+
supportedModes: ["4337", "7702"],
|
|
2359
|
+
allowBatching: true,
|
|
2360
|
+
sponsorship: "optional"
|
|
2361
|
+
},
|
|
2362
|
+
{
|
|
2363
|
+
chainId: 42161,
|
|
2364
|
+
enabled: true,
|
|
2365
|
+
defaultMode: "4337",
|
|
2366
|
+
supportedModes: ["4337", "7702"],
|
|
2367
|
+
allowBatching: true,
|
|
2368
|
+
sponsorship: "optional"
|
|
2369
|
+
},
|
|
2370
|
+
{
|
|
2371
|
+
chainId: 10,
|
|
2372
|
+
enabled: true,
|
|
2373
|
+
defaultMode: "4337",
|
|
2374
|
+
supportedModes: ["4337", "7702"],
|
|
2375
|
+
allowBatching: true,
|
|
2376
|
+
sponsorship: "optional"
|
|
2377
|
+
},
|
|
2378
|
+
{
|
|
2379
|
+
chainId: 8453,
|
|
2380
|
+
enabled: true,
|
|
2381
|
+
defaultMode: "4337",
|
|
2382
|
+
supportedModes: ["4337", "7702"],
|
|
2383
|
+
allowBatching: true,
|
|
2384
|
+
sponsorship: "optional"
|
|
2385
|
+
}
|
|
2386
|
+
]
|
|
2387
|
+
};
|
|
2388
|
+
var DISABLED_PROVIDER_STATE = {
|
|
2389
|
+
plan: null,
|
|
2390
|
+
AA: void 0,
|
|
2391
|
+
isPending: false,
|
|
2392
|
+
error: null
|
|
2393
|
+
};
|
|
2394
|
+
async function executeWalletCalls(params) {
|
|
2395
|
+
const {
|
|
2396
|
+
callList,
|
|
2397
|
+
currentChainId,
|
|
2398
|
+
capabilities,
|
|
2399
|
+
localPrivateKey,
|
|
2400
|
+
providerState,
|
|
2401
|
+
sendCallsSyncAsync,
|
|
2402
|
+
sendTransactionAsync,
|
|
2403
|
+
switchChainAsync,
|
|
2404
|
+
chainsById,
|
|
2405
|
+
getPreferredRpcUrl: getPreferredRpcUrl2
|
|
2406
|
+
} = params;
|
|
2407
|
+
if (providerState.plan && providerState.AA) {
|
|
2408
|
+
return executeViaAA(callList, providerState);
|
|
2409
|
+
}
|
|
2410
|
+
if (providerState.plan && providerState.error && !providerState.plan.fallbackToEoa) {
|
|
2411
|
+
throw providerState.error;
|
|
2412
|
+
}
|
|
2413
|
+
return executeViaEoa({
|
|
2414
|
+
callList,
|
|
2415
|
+
currentChainId,
|
|
2416
|
+
capabilities,
|
|
2417
|
+
localPrivateKey,
|
|
2418
|
+
sendCallsSyncAsync,
|
|
2419
|
+
sendTransactionAsync,
|
|
2420
|
+
switchChainAsync,
|
|
2421
|
+
chainsById,
|
|
2422
|
+
getPreferredRpcUrl: getPreferredRpcUrl2
|
|
2423
|
+
});
|
|
2424
|
+
}
|
|
2425
|
+
async function executeViaAA(callList, providerState) {
|
|
2426
|
+
var _a3;
|
|
2427
|
+
const AA = providerState.AA;
|
|
2428
|
+
const plan = providerState.plan;
|
|
2429
|
+
if (!AA || !plan) {
|
|
2430
|
+
throw (_a3 = providerState.error) != null ? _a3 : new Error("smart_account_unavailable");
|
|
2431
|
+
}
|
|
2432
|
+
const callsPayload = callList.map(mapCall);
|
|
2433
|
+
const receipt = callList.length > 1 ? await AA.sendBatchTransaction(callsPayload) : await AA.sendTransaction(callsPayload[0]);
|
|
2434
|
+
const txHash = receipt.transactionHash;
|
|
2435
|
+
const providerPrefix = AA.provider.toLowerCase();
|
|
2436
|
+
return {
|
|
2437
|
+
txHash,
|
|
2438
|
+
txHashes: [txHash],
|
|
2439
|
+
executionKind: `${providerPrefix}_${AA.mode}`,
|
|
2440
|
+
batched: callList.length > 1,
|
|
2441
|
+
sponsored: plan.sponsorship !== "disabled",
|
|
2442
|
+
AAAddress: AA.AAAddress,
|
|
2443
|
+
delegationAddress: AA.mode === "7702" ? AA.delegationAddress : void 0
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
async function executeViaEoa({
|
|
2447
|
+
callList,
|
|
2448
|
+
currentChainId,
|
|
2449
|
+
capabilities,
|
|
2450
|
+
localPrivateKey,
|
|
2451
|
+
sendCallsSyncAsync,
|
|
2452
|
+
sendTransactionAsync,
|
|
2453
|
+
switchChainAsync,
|
|
2454
|
+
chainsById,
|
|
2455
|
+
getPreferredRpcUrl: getPreferredRpcUrl2
|
|
2456
|
+
}) {
|
|
2457
|
+
var _a3, _b;
|
|
2458
|
+
const { createPublicClient, createWalletClient: createWalletClient2, http: http2 } = await import("viem");
|
|
2459
|
+
const { privateKeyToAccount: privateKeyToAccount3 } = await import("viem/accounts");
|
|
2460
|
+
const hashes = [];
|
|
2461
|
+
if (localPrivateKey) {
|
|
2462
|
+
for (const call of callList) {
|
|
2463
|
+
const chain = chainsById[call.chainId];
|
|
2464
|
+
if (!chain) {
|
|
2465
|
+
throw new Error(`Unsupported chain ${call.chainId}`);
|
|
2466
|
+
}
|
|
2467
|
+
const rpcUrl = getPreferredRpcUrl2(chain);
|
|
2468
|
+
if (!rpcUrl) {
|
|
2469
|
+
throw new Error(`No RPC for chain ${call.chainId}`);
|
|
2470
|
+
}
|
|
2471
|
+
const account = privateKeyToAccount3(localPrivateKey);
|
|
2472
|
+
const walletClient = createWalletClient2({
|
|
2473
|
+
account,
|
|
2474
|
+
chain,
|
|
2475
|
+
transport: http2(rpcUrl)
|
|
2476
|
+
});
|
|
2477
|
+
const hash = await walletClient.sendTransaction({
|
|
2478
|
+
account,
|
|
2479
|
+
to: call.to,
|
|
2480
|
+
value: BigInt(call.value),
|
|
2481
|
+
data: call.data ? call.data : void 0
|
|
2482
|
+
});
|
|
2483
|
+
const publicClient = createPublicClient({
|
|
2484
|
+
chain,
|
|
2485
|
+
transport: http2(rpcUrl)
|
|
2486
|
+
});
|
|
2487
|
+
await publicClient.waitForTransactionReceipt({ hash });
|
|
2488
|
+
hashes.push(hash);
|
|
2489
|
+
}
|
|
2490
|
+
return {
|
|
2491
|
+
txHash: hashes[hashes.length - 1],
|
|
2492
|
+
txHashes: hashes,
|
|
2493
|
+
executionKind: "eoa",
|
|
2494
|
+
batched: hashes.length > 1,
|
|
2495
|
+
sponsored: false
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
const chainIds = Array.from(new Set(callList.map((call) => call.chainId)));
|
|
2499
|
+
if (chainIds.length > 1) {
|
|
2500
|
+
throw new Error("mixed_chain_bundle_not_supported");
|
|
2501
|
+
}
|
|
2502
|
+
const chainId = chainIds[0];
|
|
2503
|
+
if (currentChainId !== chainId) {
|
|
2504
|
+
await switchChainAsync({ chainId });
|
|
2505
|
+
}
|
|
2506
|
+
const chainCaps = capabilities == null ? void 0 : capabilities[`eip155:${chainId}`];
|
|
2507
|
+
const atomicStatus = (_a3 = chainCaps == null ? void 0 : chainCaps.atomic) == null ? void 0 : _a3.status;
|
|
2508
|
+
const canUseSendCalls = atomicStatus === "supported" || atomicStatus === "ready";
|
|
2509
|
+
if (canUseSendCalls) {
|
|
2510
|
+
const batchResult = await sendCallsSyncAsync({
|
|
2511
|
+
calls: callList.map(mapCall),
|
|
2512
|
+
capabilities: {
|
|
2513
|
+
atomic: {
|
|
2514
|
+
required: true
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
});
|
|
2518
|
+
const receipts = (_b = batchResult.receipts) != null ? _b : [];
|
|
2519
|
+
for (const receipt of receipts) {
|
|
2520
|
+
if (receipt.transactionHash) {
|
|
2521
|
+
hashes.push(receipt.transactionHash);
|
|
2522
|
+
}
|
|
2523
|
+
}
|
|
2524
|
+
} else {
|
|
2525
|
+
for (const call of callList) {
|
|
2526
|
+
const hash = await sendTransactionAsync({
|
|
2527
|
+
chainId: call.chainId,
|
|
2528
|
+
to: call.to,
|
|
2529
|
+
value: BigInt(call.value),
|
|
2530
|
+
data: call.data ? call.data : void 0
|
|
2531
|
+
});
|
|
2532
|
+
hashes.push(hash);
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
return {
|
|
2536
|
+
txHash: hashes[hashes.length - 1],
|
|
2537
|
+
txHashes: hashes,
|
|
2538
|
+
executionKind: "eoa",
|
|
2539
|
+
batched: hashes.length > 1,
|
|
2540
|
+
sponsored: false
|
|
2541
|
+
};
|
|
2542
|
+
}
|
|
2543
|
+
|
|
2544
|
+
// src/aa/env.ts
|
|
2545
|
+
var ALCHEMY_API_KEY_ENVS = [
|
|
2546
|
+
"ALCHEMY_API_KEY",
|
|
2547
|
+
"NEXT_PUBLIC_ALCHEMY_API_KEY"
|
|
2548
|
+
];
|
|
2549
|
+
var ALCHEMY_GAS_POLICY_ENVS = [
|
|
2550
|
+
"ALCHEMY_GAS_POLICY_ID",
|
|
2551
|
+
"NEXT_PUBLIC_ALCHEMY_GAS_POLICY_ID"
|
|
2552
|
+
];
|
|
2553
|
+
var PIMLICO_API_KEY_ENVS = [
|
|
2554
|
+
"PIMLICO_API_KEY",
|
|
2555
|
+
"NEXT_PUBLIC_PIMLICO_API_KEY"
|
|
2556
|
+
];
|
|
2557
|
+
function readEnv(candidates, options = {}) {
|
|
2558
|
+
var _a3;
|
|
2559
|
+
const { publicOnly = false } = options;
|
|
2560
|
+
for (const name of candidates) {
|
|
2561
|
+
if (publicOnly && !name.startsWith("NEXT_PUBLIC_")) {
|
|
2562
|
+
continue;
|
|
2563
|
+
}
|
|
2564
|
+
const value = (_a3 = process.env[name]) == null ? void 0 : _a3.trim();
|
|
2565
|
+
if (value) return value;
|
|
2566
|
+
}
|
|
2567
|
+
return void 0;
|
|
2568
|
+
}
|
|
2569
|
+
function readGasPolicyEnv(chainId, chainSlugById, baseCandidates, options = {}) {
|
|
2570
|
+
const slug = chainSlugById[chainId];
|
|
2571
|
+
if (slug) {
|
|
2572
|
+
const chainSpecific = baseCandidates.map(
|
|
2573
|
+
(base) => `${base}_${slug.toUpperCase()}`
|
|
2574
|
+
);
|
|
2575
|
+
const found = readEnv(chainSpecific, options);
|
|
2576
|
+
if (found) return found;
|
|
2577
|
+
}
|
|
2578
|
+
return readEnv(baseCandidates, options);
|
|
2579
|
+
}
|
|
2580
|
+
function isProviderConfigured(provider, options = {}) {
|
|
2581
|
+
return provider === "alchemy" ? Boolean(readEnv(ALCHEMY_API_KEY_ENVS, options)) : Boolean(readEnv(PIMLICO_API_KEY_ENVS, options));
|
|
2582
|
+
}
|
|
2583
|
+
function resolveDefaultProvider(options = {}) {
|
|
2584
|
+
if (isProviderConfigured("alchemy", options)) return "alchemy";
|
|
2585
|
+
if (isProviderConfigured("pimlico", options)) return "pimlico";
|
|
2586
|
+
throw new Error(
|
|
2587
|
+
"AA requires provider credentials. Set ALCHEMY_API_KEY or PIMLICO_API_KEY, or use --eoa."
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
// src/aa/resolve.ts
|
|
2592
|
+
function resolveAlchemyConfig(options) {
|
|
2593
|
+
const {
|
|
2594
|
+
calls,
|
|
2595
|
+
localPrivateKey,
|
|
2596
|
+
accountAbstractionConfig = DEFAULT_AA_CONFIG,
|
|
2597
|
+
chainsById,
|
|
2598
|
+
chainSlugById = {},
|
|
2599
|
+
getPreferredRpcUrl: getPreferredRpcUrl2 = (chain2) => {
|
|
2600
|
+
var _a3;
|
|
2601
|
+
return (_a3 = chain2.rpcUrls.default.http[0]) != null ? _a3 : "";
|
|
2602
|
+
},
|
|
2603
|
+
modeOverride,
|
|
2604
|
+
publicOnly = false,
|
|
2605
|
+
throwOnMissingConfig = false
|
|
2606
|
+
} = options;
|
|
2607
|
+
if (!calls || localPrivateKey) {
|
|
2608
|
+
return null;
|
|
2609
|
+
}
|
|
2610
|
+
const config = __spreadProps(__spreadValues({}, accountAbstractionConfig), {
|
|
2611
|
+
provider: "alchemy"
|
|
2612
|
+
});
|
|
2613
|
+
const chainConfig = getAAChainConfig(config, calls, chainsById);
|
|
2614
|
+
if (!chainConfig) {
|
|
2615
|
+
if (throwOnMissingConfig) {
|
|
2616
|
+
const chainIds = Array.from(new Set(calls.map((c) => c.chainId)));
|
|
2617
|
+
throw new Error(
|
|
2618
|
+
`AA is not configured for chain ${chainIds[0]}, or batching is disabled for that chain.`
|
|
2619
|
+
);
|
|
2620
|
+
}
|
|
2621
|
+
return null;
|
|
2622
|
+
}
|
|
2623
|
+
const apiKey = readEnv(ALCHEMY_API_KEY_ENVS, { publicOnly });
|
|
2624
|
+
if (!apiKey) {
|
|
2625
|
+
if (throwOnMissingConfig) {
|
|
2626
|
+
throw new Error("Alchemy AA requires ALCHEMY_API_KEY.");
|
|
2627
|
+
}
|
|
2628
|
+
return null;
|
|
2629
|
+
}
|
|
2630
|
+
const chain = chainsById[chainConfig.chainId];
|
|
2631
|
+
if (!chain) {
|
|
2632
|
+
return null;
|
|
2633
|
+
}
|
|
2634
|
+
const gasPolicyId = readGasPolicyEnv(
|
|
2635
|
+
chainConfig.chainId,
|
|
2636
|
+
chainSlugById,
|
|
2637
|
+
ALCHEMY_GAS_POLICY_ENVS,
|
|
2638
|
+
{ publicOnly }
|
|
2639
|
+
);
|
|
2640
|
+
if (chainConfig.sponsorship === "required" && !gasPolicyId) {
|
|
2641
|
+
if (throwOnMissingConfig) {
|
|
2642
|
+
throw new Error(
|
|
2643
|
+
`Alchemy gas policy required for chain ${chainConfig.chainId} but not configured.`
|
|
2644
|
+
);
|
|
2645
|
+
}
|
|
2646
|
+
return null;
|
|
2647
|
+
}
|
|
2648
|
+
if (modeOverride && !chainConfig.supportedModes.includes(modeOverride)) {
|
|
2649
|
+
if (throwOnMissingConfig) {
|
|
2650
|
+
throw new Error(
|
|
2651
|
+
`AA mode "${modeOverride}" is not supported on chain ${chainConfig.chainId}.`
|
|
2652
|
+
);
|
|
2653
|
+
}
|
|
2654
|
+
return null;
|
|
2655
|
+
}
|
|
2656
|
+
const resolvedChainConfig = modeOverride ? __spreadProps(__spreadValues({}, chainConfig), { defaultMode: modeOverride }) : chainConfig;
|
|
2657
|
+
const plan = buildAAExecutionPlan(config, resolvedChainConfig);
|
|
2658
|
+
return {
|
|
2659
|
+
chainConfig: resolvedChainConfig,
|
|
2660
|
+
plan,
|
|
2661
|
+
apiKey,
|
|
2662
|
+
chain,
|
|
2663
|
+
rpcUrl: getPreferredRpcUrl2(chain),
|
|
2664
|
+
gasPolicyId,
|
|
2665
|
+
mode: resolvedChainConfig.defaultMode
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2668
|
+
function resolvePimlicoConfig(options) {
|
|
2669
|
+
const {
|
|
2670
|
+
calls,
|
|
2671
|
+
localPrivateKey,
|
|
2672
|
+
accountAbstractionConfig = DEFAULT_AA_CONFIG,
|
|
2673
|
+
chainsById,
|
|
2674
|
+
rpcUrl,
|
|
2675
|
+
modeOverride,
|
|
2676
|
+
publicOnly = false,
|
|
2677
|
+
throwOnMissingConfig = false
|
|
2678
|
+
} = options;
|
|
2679
|
+
if (!calls || localPrivateKey) {
|
|
2680
|
+
return null;
|
|
2681
|
+
}
|
|
2682
|
+
const config = __spreadProps(__spreadValues({}, accountAbstractionConfig), {
|
|
2683
|
+
provider: "pimlico"
|
|
2684
|
+
});
|
|
2685
|
+
const chainConfig = getAAChainConfig(config, calls, chainsById);
|
|
2686
|
+
if (!chainConfig) {
|
|
2687
|
+
if (throwOnMissingConfig) {
|
|
2688
|
+
const chainIds = Array.from(new Set(calls.map((c) => c.chainId)));
|
|
2689
|
+
throw new Error(
|
|
2690
|
+
`AA is not configured for chain ${chainIds[0]}, or batching is disabled for that chain.`
|
|
2691
|
+
);
|
|
2692
|
+
}
|
|
2693
|
+
return null;
|
|
2694
|
+
}
|
|
2695
|
+
const apiKey = readEnv(PIMLICO_API_KEY_ENVS, { publicOnly });
|
|
2696
|
+
if (!apiKey) {
|
|
2697
|
+
if (throwOnMissingConfig) {
|
|
2698
|
+
throw new Error("Pimlico AA requires PIMLICO_API_KEY.");
|
|
2699
|
+
}
|
|
2700
|
+
return null;
|
|
2701
|
+
}
|
|
2702
|
+
const chain = chainsById[chainConfig.chainId];
|
|
2703
|
+
if (!chain) {
|
|
2704
|
+
return null;
|
|
2705
|
+
}
|
|
2706
|
+
if (modeOverride && !chainConfig.supportedModes.includes(modeOverride)) {
|
|
2707
|
+
if (throwOnMissingConfig) {
|
|
2708
|
+
throw new Error(
|
|
2709
|
+
`AA mode "${modeOverride}" is not supported on chain ${chainConfig.chainId}.`
|
|
2710
|
+
);
|
|
2711
|
+
}
|
|
2712
|
+
return null;
|
|
2713
|
+
}
|
|
2714
|
+
const resolvedChainConfig = modeOverride ? __spreadProps(__spreadValues({}, chainConfig), { defaultMode: modeOverride }) : chainConfig;
|
|
2715
|
+
const plan = buildAAExecutionPlan(config, resolvedChainConfig);
|
|
2716
|
+
return {
|
|
2717
|
+
chainConfig: resolvedChainConfig,
|
|
2718
|
+
plan,
|
|
2719
|
+
apiKey,
|
|
2720
|
+
chain,
|
|
2721
|
+
rpcUrl,
|
|
2722
|
+
mode: resolvedChainConfig.defaultMode
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/aa/adapt.ts
|
|
2727
|
+
function adaptSmartAccount(account) {
|
|
2728
|
+
return {
|
|
2729
|
+
provider: account.provider,
|
|
2730
|
+
mode: account.mode,
|
|
2731
|
+
AAAddress: account.smartAccountAddress,
|
|
2732
|
+
delegationAddress: account.delegationAddress,
|
|
2733
|
+
sendTransaction: async (call) => {
|
|
2734
|
+
const receipt = await account.sendTransaction(call);
|
|
2735
|
+
return { transactionHash: receipt.transactionHash };
|
|
2736
|
+
},
|
|
2737
|
+
sendBatchTransaction: async (calls) => {
|
|
2738
|
+
const receipt = await account.sendBatchTransaction(calls);
|
|
2739
|
+
return { transactionHash: receipt.transactionHash };
|
|
2740
|
+
}
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
function isAlchemySponsorshipLimitError(error) {
|
|
2744
|
+
const message = error instanceof Error ? error.message : String(error != null ? error : "");
|
|
2745
|
+
const normalized = message.toLowerCase();
|
|
2746
|
+
return normalized.includes("gas sponsorship limit") || normalized.includes("put your team over your gas sponsorship limit") || normalized.includes("buy gas credits in your gas manager dashboard");
|
|
2747
|
+
}
|
|
2748
|
+
|
|
2749
|
+
// src/aa/create.ts
|
|
2750
|
+
import { createAlchemySmartAccount } from "@getpara/aa-alchemy";
|
|
2751
|
+
import { createPimlicoSmartAccount } from "@getpara/aa-pimlico";
|
|
2752
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
2753
|
+
async function createAAProviderState(options) {
|
|
2754
|
+
if (options.provider === "alchemy") {
|
|
2755
|
+
return createAlchemyAAState(options);
|
|
2756
|
+
}
|
|
2757
|
+
return createPimlicoAAState(options);
|
|
2758
|
+
}
|
|
2759
|
+
async function createAlchemyAAState(options) {
|
|
2760
|
+
var _a3, _b;
|
|
2761
|
+
const {
|
|
2762
|
+
chain,
|
|
2763
|
+
privateKey,
|
|
2764
|
+
rpcUrl,
|
|
2765
|
+
callList,
|
|
2766
|
+
mode,
|
|
2767
|
+
sponsored = true
|
|
2768
|
+
} = options;
|
|
2769
|
+
const resolved = resolveAlchemyConfig({
|
|
2770
|
+
calls: callList,
|
|
2771
|
+
chainsById: { [chain.id]: chain },
|
|
2772
|
+
modeOverride: mode,
|
|
2773
|
+
throwOnMissingConfig: true,
|
|
2774
|
+
getPreferredRpcUrl: () => rpcUrl
|
|
2775
|
+
});
|
|
2776
|
+
if (!resolved) {
|
|
2777
|
+
throw new Error("Alchemy AA config resolution failed.");
|
|
2778
|
+
}
|
|
2779
|
+
const apiKey = (_a3 = options.apiKey) != null ? _a3 : resolved.apiKey;
|
|
2780
|
+
const gasPolicyId = sponsored ? (_b = options.gasPolicyId) != null ? _b : readEnv(ALCHEMY_GAS_POLICY_ENVS) : void 0;
|
|
2781
|
+
const plan = __spreadProps(__spreadValues({}, resolved.plan), {
|
|
2782
|
+
sponsorship: gasPolicyId ? resolved.plan.sponsorship : "disabled",
|
|
2783
|
+
fallbackToEoa: false
|
|
2784
|
+
});
|
|
2785
|
+
const signer = privateKeyToAccount(privateKey);
|
|
2786
|
+
try {
|
|
2787
|
+
const smartAccount = await createAlchemySmartAccount({
|
|
2788
|
+
para: void 0,
|
|
2789
|
+
signer,
|
|
2790
|
+
apiKey,
|
|
2791
|
+
gasPolicyId,
|
|
2792
|
+
chain,
|
|
2793
|
+
rpcUrl,
|
|
2794
|
+
mode: plan.mode
|
|
2795
|
+
});
|
|
2796
|
+
if (!smartAccount) {
|
|
2797
|
+
return {
|
|
2798
|
+
plan,
|
|
2799
|
+
AA: null,
|
|
2800
|
+
isPending: false,
|
|
2801
|
+
error: new Error("Alchemy AA account could not be initialized.")
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
return {
|
|
2805
|
+
plan,
|
|
2806
|
+
AA: adaptSmartAccount(smartAccount),
|
|
2807
|
+
isPending: false,
|
|
2808
|
+
error: null
|
|
2809
|
+
};
|
|
2810
|
+
} catch (error) {
|
|
2811
|
+
return {
|
|
2812
|
+
plan,
|
|
2813
|
+
AA: null,
|
|
2814
|
+
isPending: false,
|
|
2815
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
2816
|
+
};
|
|
2817
|
+
}
|
|
2818
|
+
}
|
|
2819
|
+
async function createPimlicoAAState(options) {
|
|
2820
|
+
var _a3;
|
|
2821
|
+
const {
|
|
2822
|
+
chain,
|
|
2823
|
+
privateKey,
|
|
2824
|
+
rpcUrl,
|
|
2825
|
+
callList,
|
|
2826
|
+
mode
|
|
2827
|
+
} = options;
|
|
2828
|
+
const resolved = resolvePimlicoConfig({
|
|
2829
|
+
calls: callList,
|
|
2830
|
+
chainsById: { [chain.id]: chain },
|
|
2831
|
+
rpcUrl,
|
|
2832
|
+
modeOverride: mode,
|
|
2833
|
+
throwOnMissingConfig: true
|
|
2834
|
+
});
|
|
2835
|
+
if (!resolved) {
|
|
2836
|
+
throw new Error("Pimlico AA config resolution failed.");
|
|
2837
|
+
}
|
|
2838
|
+
const apiKey = (_a3 = options.apiKey) != null ? _a3 : resolved.apiKey;
|
|
2839
|
+
const plan = __spreadProps(__spreadValues({}, resolved.plan), {
|
|
2840
|
+
fallbackToEoa: false
|
|
2841
|
+
});
|
|
2842
|
+
const signer = privateKeyToAccount(privateKey);
|
|
2843
|
+
try {
|
|
2844
|
+
const smartAccount = await createPimlicoSmartAccount({
|
|
2845
|
+
para: void 0,
|
|
2846
|
+
signer,
|
|
2847
|
+
apiKey,
|
|
2848
|
+
chain,
|
|
2849
|
+
rpcUrl,
|
|
2850
|
+
mode: plan.mode
|
|
2851
|
+
});
|
|
2852
|
+
if (!smartAccount) {
|
|
2853
|
+
return {
|
|
2854
|
+
plan,
|
|
2855
|
+
AA: null,
|
|
2856
|
+
isPending: false,
|
|
2857
|
+
error: new Error("Pimlico AA account could not be initialized.")
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
return {
|
|
2861
|
+
plan,
|
|
2862
|
+
AA: adaptSmartAccount(smartAccount),
|
|
2863
|
+
isPending: false,
|
|
2864
|
+
error: null
|
|
2865
|
+
};
|
|
2866
|
+
} catch (error) {
|
|
2867
|
+
return {
|
|
2868
|
+
plan,
|
|
2869
|
+
AA: null,
|
|
2870
|
+
isPending: false,
|
|
2871
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
|
|
2876
|
+
// src/cli/execution.ts
|
|
2877
|
+
function resolveAAProvider(config) {
|
|
2878
|
+
var _a3;
|
|
2879
|
+
const provider = (_a3 = config.aaProvider) != null ? _a3 : resolveDefaultProvider();
|
|
2880
|
+
if (!isProviderConfigured(provider)) {
|
|
2881
|
+
const envName = provider === "alchemy" ? "ALCHEMY_API_KEY" : "PIMLICO_API_KEY";
|
|
2882
|
+
throw new Error(
|
|
2883
|
+
`AA provider "${provider}" is selected but ${envName} is not configured.`
|
|
2884
|
+
);
|
|
2885
|
+
}
|
|
2886
|
+
return provider;
|
|
2887
|
+
}
|
|
2888
|
+
function resolveCliExecutionDecision(params) {
|
|
2889
|
+
const { config, chain, callList } = params;
|
|
2890
|
+
if (config.execution === "eoa") {
|
|
2891
|
+
return { execution: "eoa" };
|
|
2892
|
+
}
|
|
2893
|
+
const provider = resolveAAProvider(config);
|
|
2894
|
+
const resolveOpts = {
|
|
2895
|
+
calls: callList,
|
|
2896
|
+
chainsById: { [chain.id]: chain },
|
|
2897
|
+
modeOverride: config.aaMode,
|
|
2898
|
+
throwOnMissingConfig: true
|
|
2899
|
+
};
|
|
2900
|
+
const resolved = provider === "alchemy" ? resolveAlchemyConfig(resolveOpts) : resolvePimlicoConfig(resolveOpts);
|
|
2901
|
+
if (!resolved) {
|
|
2902
|
+
throw new Error(`AA config resolution failed for provider "${provider}".`);
|
|
2903
|
+
}
|
|
2904
|
+
return {
|
|
2905
|
+
execution: "aa",
|
|
2906
|
+
provider,
|
|
2907
|
+
aaMode: resolved.plan.mode
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
async function createCliProviderState(params) {
|
|
2911
|
+
const { decision, chain, privateKey, rpcUrl, callList, sponsored } = params;
|
|
2912
|
+
if (decision.execution === "eoa") {
|
|
2913
|
+
return DISABLED_PROVIDER_STATE;
|
|
2914
|
+
}
|
|
2915
|
+
return createAAProviderState({
|
|
2916
|
+
provider: decision.provider,
|
|
2917
|
+
chain,
|
|
2918
|
+
privateKey,
|
|
2919
|
+
rpcUrl,
|
|
2920
|
+
callList,
|
|
2921
|
+
mode: decision.aaMode,
|
|
2922
|
+
sponsored
|
|
2923
|
+
});
|
|
2924
|
+
}
|
|
2925
|
+
function describeExecutionDecision(decision) {
|
|
2926
|
+
if (decision.execution === "eoa") {
|
|
2927
|
+
return "eoa";
|
|
2928
|
+
}
|
|
2929
|
+
return `aa (${decision.provider}, ${decision.aaMode})`;
|
|
2930
|
+
}
|
|
2931
|
+
|
|
2932
|
+
// src/cli/commands/wallet.ts
|
|
2188
2933
|
function txCommand() {
|
|
2189
|
-
var _a3, _b
|
|
2934
|
+
var _a3, _b;
|
|
2190
2935
|
const state = readState();
|
|
2191
2936
|
if (!state) {
|
|
2192
2937
|
console.log("No active session");
|
|
@@ -2210,17 +2955,7 @@ function txCommand() {
|
|
|
2210
2955
|
if (pending.length > 0) console.log();
|
|
2211
2956
|
console.log(`Signed (${signed.length}):`);
|
|
2212
2957
|
for (const tx of signed) {
|
|
2213
|
-
|
|
2214
|
-
if (tx.kind === "eip712_sign") {
|
|
2215
|
-
parts.push(`sig: ${(_c = tx.signature) == null ? void 0 : _c.slice(0, 20)}...`);
|
|
2216
|
-
if (tx.description) parts.push(tx.description);
|
|
2217
|
-
} else {
|
|
2218
|
-
parts.push(`hash: ${tx.txHash}`);
|
|
2219
|
-
if (tx.to) parts.push(`to: ${tx.to}`);
|
|
2220
|
-
if (tx.value) parts.push(`value: ${tx.value}`);
|
|
2221
|
-
}
|
|
2222
|
-
parts.push(`(${new Date(tx.timestamp).toLocaleTimeString()})`);
|
|
2223
|
-
console.log(parts.join(" "));
|
|
2958
|
+
console.log(formatSignedTxLine(tx, " \u2705"));
|
|
2224
2959
|
}
|
|
2225
2960
|
}
|
|
2226
2961
|
printDataFileLocation();
|
|
@@ -2236,6 +2971,13 @@ Run \`aomi tx\` to see available IDs.`
|
|
|
2236
2971
|
}
|
|
2237
2972
|
return pendingTx;
|
|
2238
2973
|
}
|
|
2974
|
+
function requirePendingTxs(state, txIds) {
|
|
2975
|
+
const uniqueIds = Array.from(new Set(txIds));
|
|
2976
|
+
if (uniqueIds.length !== txIds.length) {
|
|
2977
|
+
fatal("Duplicate transaction IDs are not allowed in a single `aomi sign` call.");
|
|
2978
|
+
}
|
|
2979
|
+
return uniqueIds.map((txId) => requirePendingTx(state, txId));
|
|
2980
|
+
}
|
|
2239
2981
|
function rewriteSessionState(runtime, state) {
|
|
2240
2982
|
let changed = false;
|
|
2241
2983
|
if (runtime.config.baseUrl !== state.baseUrl) {
|
|
@@ -2279,12 +3021,147 @@ async function persistResolvedSignerState(session, state, address, chainId) {
|
|
|
2279
3021
|
session.resolveWallet(address, chainId);
|
|
2280
3022
|
await session.syncUserState();
|
|
2281
3023
|
}
|
|
3024
|
+
function resolveChain(targetChainId, rpcUrl) {
|
|
3025
|
+
var _a3;
|
|
3026
|
+
return (_a3 = Object.values(viemChains).find(
|
|
3027
|
+
(candidate) => typeof candidate === "object" && candidate !== null && "id" in candidate && candidate.id === targetChainId
|
|
3028
|
+
)) != null ? _a3 : {
|
|
3029
|
+
id: targetChainId,
|
|
3030
|
+
name: `Chain ${targetChainId}`,
|
|
3031
|
+
nativeCurrency: {
|
|
3032
|
+
name: "ETH",
|
|
3033
|
+
symbol: "ETH",
|
|
3034
|
+
decimals: 18
|
|
3035
|
+
},
|
|
3036
|
+
rpcUrls: {
|
|
3037
|
+
default: {
|
|
3038
|
+
http: rpcUrl ? [rpcUrl] : []
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
};
|
|
3042
|
+
}
|
|
3043
|
+
function getPreferredRpcUrl(chain, override) {
|
|
3044
|
+
var _a3, _b, _c;
|
|
3045
|
+
return (_c = (_b = override != null ? override : chain.rpcUrls.default.http[0]) != null ? _b : (_a3 = chain.rpcUrls.public) == null ? void 0 : _a3.http[0]) != null ? _c : "";
|
|
3046
|
+
}
|
|
3047
|
+
async function promptForEoaFallback() {
|
|
3048
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
3049
|
+
return false;
|
|
3050
|
+
}
|
|
3051
|
+
const rl = createInterface({
|
|
3052
|
+
input: process.stdin,
|
|
3053
|
+
output: process.stdout
|
|
3054
|
+
});
|
|
3055
|
+
try {
|
|
3056
|
+
const answer = await rl.question(
|
|
3057
|
+
"Account abstraction not available, use EOA? [yes/no] "
|
|
3058
|
+
);
|
|
3059
|
+
const normalized = answer.trim().toLowerCase();
|
|
3060
|
+
return normalized === "y" || normalized === "yes";
|
|
3061
|
+
} finally {
|
|
3062
|
+
rl.close();
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
async function executeCliTransaction(params) {
|
|
3066
|
+
const { privateKey, currentChainId, chainsById, rpcUrl, providerState, callList } = params;
|
|
3067
|
+
const unsupportedWalletMethod = async () => {
|
|
3068
|
+
throw new Error("wallet_client_path_unavailable_in_cli_private_key_mode");
|
|
3069
|
+
};
|
|
3070
|
+
return executeWalletCalls({
|
|
3071
|
+
callList,
|
|
3072
|
+
currentChainId,
|
|
3073
|
+
capabilities: void 0,
|
|
3074
|
+
localPrivateKey: privateKey,
|
|
3075
|
+
providerState,
|
|
3076
|
+
sendCallsSyncAsync: unsupportedWalletMethod,
|
|
3077
|
+
sendTransactionAsync: unsupportedWalletMethod,
|
|
3078
|
+
switchChainAsync: async () => void 0,
|
|
3079
|
+
chainsById,
|
|
3080
|
+
getPreferredRpcUrl: (resolvedChain) => getPreferredRpcUrl(resolvedChain, rpcUrl)
|
|
3081
|
+
});
|
|
3082
|
+
}
|
|
3083
|
+
async function executeTransactionWithFallback(params) {
|
|
3084
|
+
const { decision, privateKey, currentChainId, chainsById, primaryChain, rpcUrl, callList } = params;
|
|
3085
|
+
const runExecution = async (providerState2) => executeCliTransaction({
|
|
3086
|
+
privateKey,
|
|
3087
|
+
currentChainId,
|
|
3088
|
+
chainsById,
|
|
3089
|
+
rpcUrl,
|
|
3090
|
+
providerState: providerState2,
|
|
3091
|
+
callList
|
|
3092
|
+
});
|
|
3093
|
+
if (decision.execution === "eoa") {
|
|
3094
|
+
const providerState2 = await createCliProviderState({
|
|
3095
|
+
decision,
|
|
3096
|
+
chain: primaryChain,
|
|
3097
|
+
privateKey,
|
|
3098
|
+
rpcUrl: rpcUrl != null ? rpcUrl : "",
|
|
3099
|
+
callList
|
|
3100
|
+
});
|
|
3101
|
+
return {
|
|
3102
|
+
execution: await runExecution(providerState2),
|
|
3103
|
+
finalDecision: decision
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
let providerState = await createCliProviderState({
|
|
3107
|
+
decision,
|
|
3108
|
+
chain: primaryChain,
|
|
3109
|
+
privateKey,
|
|
3110
|
+
rpcUrl: rpcUrl != null ? rpcUrl : "",
|
|
3111
|
+
callList,
|
|
3112
|
+
sponsored: true
|
|
3113
|
+
});
|
|
3114
|
+
try {
|
|
3115
|
+
return {
|
|
3116
|
+
execution: await runExecution(providerState),
|
|
3117
|
+
finalDecision: decision
|
|
3118
|
+
};
|
|
3119
|
+
} catch (error) {
|
|
3120
|
+
const shouldRetryUnsponsored = decision.provider === "alchemy" && isAlchemySponsorshipLimitError(error);
|
|
3121
|
+
if (shouldRetryUnsponsored) {
|
|
3122
|
+
console.log("AA sponsorship unavailable. Retrying AA with user-funded gas...");
|
|
3123
|
+
providerState = await createCliProviderState({
|
|
3124
|
+
decision,
|
|
3125
|
+
chain: primaryChain,
|
|
3126
|
+
privateKey,
|
|
3127
|
+
rpcUrl: rpcUrl != null ? rpcUrl : "",
|
|
3128
|
+
callList,
|
|
3129
|
+
sponsored: false
|
|
3130
|
+
});
|
|
3131
|
+
try {
|
|
3132
|
+
return {
|
|
3133
|
+
execution: await runExecution(providerState),
|
|
3134
|
+
finalDecision: decision
|
|
3135
|
+
};
|
|
3136
|
+
} catch (retryError) {
|
|
3137
|
+
error = retryError;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
const useEoa = await promptForEoaFallback();
|
|
3141
|
+
if (!useEoa) {
|
|
3142
|
+
throw error;
|
|
3143
|
+
}
|
|
3144
|
+
const eoaDecision = { execution: "eoa" };
|
|
3145
|
+
console.log("Retrying with EOA execution...");
|
|
3146
|
+
const eoaProviderState = await createCliProviderState({
|
|
3147
|
+
decision: eoaDecision,
|
|
3148
|
+
chain: primaryChain,
|
|
3149
|
+
privateKey,
|
|
3150
|
+
rpcUrl: rpcUrl != null ? rpcUrl : "",
|
|
3151
|
+
callList
|
|
3152
|
+
});
|
|
3153
|
+
return {
|
|
3154
|
+
execution: await runExecution(eoaProviderState),
|
|
3155
|
+
finalDecision: eoaDecision
|
|
3156
|
+
};
|
|
3157
|
+
}
|
|
3158
|
+
}
|
|
2282
3159
|
async function signCommand(runtime) {
|
|
2283
|
-
var _a3, _b
|
|
2284
|
-
const
|
|
2285
|
-
if (
|
|
3160
|
+
var _a3, _b;
|
|
3161
|
+
const txIds = runtime.parsed.positional;
|
|
3162
|
+
if (txIds.length === 0) {
|
|
2286
3163
|
fatal(
|
|
2287
|
-
"Usage: aomi sign <tx-id
|
|
3164
|
+
"Usage: aomi sign <tx-id> [<tx-id> ...]\nRun `aomi tx` to see pending transaction IDs."
|
|
2288
3165
|
);
|
|
2289
3166
|
}
|
|
2290
3167
|
const privateKey = runtime.config.privateKey;
|
|
@@ -2303,10 +3180,10 @@ async function signCommand(runtime) {
|
|
|
2303
3180
|
fatal("No active session. Run `aomi chat` first.");
|
|
2304
3181
|
}
|
|
2305
3182
|
rewriteSessionState(runtime, state);
|
|
2306
|
-
const
|
|
3183
|
+
const pendingTxs = requirePendingTxs(state, txIds);
|
|
2307
3184
|
const session = createSessionFromState(state);
|
|
2308
3185
|
try {
|
|
2309
|
-
const account =
|
|
3186
|
+
const account = privateKeyToAccount2(privateKey);
|
|
2310
3187
|
if (state.publicKey && account.address.toLowerCase() !== state.publicKey.toLowerCase()) {
|
|
2311
3188
|
console.log(
|
|
2312
3189
|
`\u26A0\uFE0F Signer ${account.address} differs from session public key ${state.publicKey}`
|
|
@@ -2314,62 +3191,95 @@ async function signCommand(runtime) {
|
|
|
2314
3191
|
console.log(" Updating session to match the signing key...");
|
|
2315
3192
|
}
|
|
2316
3193
|
const rpcUrl = runtime.config.chainRpcUrl;
|
|
2317
|
-
const
|
|
2318
|
-
|
|
2319
|
-
(
|
|
2320
|
-
)) != null ? _c : {
|
|
2321
|
-
id: targetChainId,
|
|
2322
|
-
name: `Chain ${targetChainId}`,
|
|
2323
|
-
nativeCurrency: {
|
|
2324
|
-
name: "ETH",
|
|
2325
|
-
symbol: "ETH",
|
|
2326
|
-
decimals: 18
|
|
2327
|
-
},
|
|
2328
|
-
rpcUrls: {
|
|
2329
|
-
default: {
|
|
2330
|
-
http: [rpcUrl != null ? rpcUrl : ""]
|
|
2331
|
-
}
|
|
2332
|
-
}
|
|
2333
|
-
};
|
|
2334
|
-
const walletClient = createWalletClient({
|
|
2335
|
-
account,
|
|
2336
|
-
chain,
|
|
2337
|
-
transport: http(rpcUrl)
|
|
3194
|
+
const resolvedChainIds = pendingTxs.map((tx) => {
|
|
3195
|
+
var _a4, _b2;
|
|
3196
|
+
return (_b2 = (_a4 = tx.chainId) != null ? _a4 : state.chainId) != null ? _b2 : 1;
|
|
2338
3197
|
});
|
|
3198
|
+
const primaryChainId = resolvedChainIds[0];
|
|
3199
|
+
const chain = resolveChain(primaryChainId, rpcUrl);
|
|
3200
|
+
const resolvedRpcUrl = getPreferredRpcUrl(chain, rpcUrl);
|
|
3201
|
+
const chainsById = Object.fromEntries(
|
|
3202
|
+
Array.from(new Set(resolvedChainIds)).map((chainId) => [
|
|
3203
|
+
chainId,
|
|
3204
|
+
resolveChain(chainId, rpcUrl)
|
|
3205
|
+
])
|
|
3206
|
+
);
|
|
2339
3207
|
console.log(`Signer: ${account.address}`);
|
|
2340
|
-
console.log(`
|
|
2341
|
-
|
|
2342
|
-
let
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
3208
|
+
console.log(`IDs: ${pendingTxs.map((tx) => tx.id).join(", ")}`);
|
|
3209
|
+
let signedRecords = [];
|
|
3210
|
+
let backendNotifications = [];
|
|
3211
|
+
if (pendingTxs.every((tx) => tx.kind === "transaction")) {
|
|
3212
|
+
console.log(`Kind: transaction${pendingTxs.length > 1 ? " (batch)" : ""}`);
|
|
3213
|
+
for (const tx of pendingTxs) {
|
|
3214
|
+
console.log(`Tx: ${tx.id} -> ${tx.to}`);
|
|
3215
|
+
if (tx.value) console.log(`Value: ${tx.value}`);
|
|
3216
|
+
if ((_a3 = tx.chainId) != null ? _a3 : state.chainId) console.log(`Chain: ${(_b = tx.chainId) != null ? _b : state.chainId}`);
|
|
3217
|
+
if (tx.data) {
|
|
3218
|
+
console.log(`Data: ${tx.data.slice(0, 40)}...`);
|
|
3219
|
+
}
|
|
2350
3220
|
}
|
|
2351
3221
|
console.log();
|
|
2352
|
-
const
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
3222
|
+
const callList = pendingTxs.flatMap(
|
|
3223
|
+
(tx, index) => pendingTxToCallList(__spreadProps(__spreadValues({}, tx), {
|
|
3224
|
+
chainId: resolvedChainIds[index]
|
|
3225
|
+
}))
|
|
3226
|
+
);
|
|
3227
|
+
if (callList.length > 1 && rpcUrl && new Set(callList.map((call) => call.chainId)).size > 1) {
|
|
3228
|
+
fatal("A single `--rpc-url` override cannot be used for a mixed-chain multi-sign request.");
|
|
3229
|
+
}
|
|
3230
|
+
const decision = resolveCliExecutionDecision({
|
|
3231
|
+
config: runtime.config,
|
|
3232
|
+
chain,
|
|
3233
|
+
callList
|
|
2356
3234
|
});
|
|
2357
|
-
console.log(
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
};
|
|
2368
|
-
|
|
3235
|
+
console.log(`Exec: ${describeExecutionDecision(decision)}`);
|
|
3236
|
+
const { execution, finalDecision } = await executeTransactionWithFallback({
|
|
3237
|
+
decision,
|
|
3238
|
+
privateKey,
|
|
3239
|
+
currentChainId: primaryChainId,
|
|
3240
|
+
chainsById,
|
|
3241
|
+
primaryChain: chain,
|
|
3242
|
+
rpcUrl,
|
|
3243
|
+
callList
|
|
3244
|
+
});
|
|
3245
|
+
console.log(`\u2705 Sent! Hash: ${execution.txHash}`);
|
|
3246
|
+
if (execution.txHashes.length > 1) {
|
|
3247
|
+
console.log(`Count: ${execution.txHashes.length}`);
|
|
3248
|
+
}
|
|
3249
|
+
if (execution.sponsored) {
|
|
3250
|
+
console.log("Gas: sponsored");
|
|
3251
|
+
}
|
|
3252
|
+
if (execution.AAAddress) {
|
|
3253
|
+
console.log(`AA: ${execution.AAAddress}`);
|
|
3254
|
+
}
|
|
3255
|
+
if (execution.delegationAddress) {
|
|
3256
|
+
console.log(`Deleg: ${execution.delegationAddress}`);
|
|
3257
|
+
}
|
|
3258
|
+
signedRecords = pendingTxs.map(
|
|
3259
|
+
(tx, index) => toSignedTransactionRecord(
|
|
3260
|
+
tx,
|
|
3261
|
+
execution,
|
|
3262
|
+
account.address,
|
|
3263
|
+
resolvedChainIds[index],
|
|
3264
|
+
Date.now(),
|
|
3265
|
+
finalDecision.execution === "aa" ? finalDecision.provider : void 0,
|
|
3266
|
+
finalDecision.execution === "aa" ? finalDecision.aaMode : void 0
|
|
3267
|
+
)
|
|
3268
|
+
);
|
|
3269
|
+
backendNotifications = pendingTxs.map(() => ({
|
|
2369
3270
|
type: "wallet:tx_complete",
|
|
2370
|
-
payload: { txHash:
|
|
2371
|
-
};
|
|
3271
|
+
payload: { txHash: execution.txHash, status: "success" }
|
|
3272
|
+
}));
|
|
2372
3273
|
} else {
|
|
3274
|
+
if (pendingTxs.length > 1) {
|
|
3275
|
+
fatal("Batch signing is only supported for transaction requests, not EIP-712 requests.");
|
|
3276
|
+
}
|
|
3277
|
+
const pendingTx = pendingTxs[0];
|
|
3278
|
+
const walletClient = createWalletClient({
|
|
3279
|
+
account,
|
|
3280
|
+
chain,
|
|
3281
|
+
transport: http(resolvedRpcUrl)
|
|
3282
|
+
});
|
|
2373
3283
|
const typedData = pendingTx.payload.typed_data;
|
|
2374
3284
|
if (!typedData) {
|
|
2375
3285
|
fatal("EIP-712 request is missing typed_data payload.");
|
|
@@ -2391,36 +3301,42 @@ async function signCommand(runtime) {
|
|
|
2391
3301
|
message
|
|
2392
3302
|
});
|
|
2393
3303
|
console.log(`\u2705 Signed! Signature: ${signature.slice(0, 20)}...`);
|
|
2394
|
-
|
|
2395
|
-
id:
|
|
3304
|
+
signedRecords = [{
|
|
3305
|
+
id: pendingTx.id,
|
|
2396
3306
|
kind: "eip712_sign",
|
|
2397
3307
|
signature,
|
|
2398
3308
|
from: account.address,
|
|
2399
3309
|
description: pendingTx.description,
|
|
2400
3310
|
timestamp: Date.now()
|
|
2401
|
-
};
|
|
2402
|
-
|
|
3311
|
+
}];
|
|
3312
|
+
backendNotifications = [{
|
|
2403
3313
|
type: "wallet_eip712_response",
|
|
2404
3314
|
payload: {
|
|
2405
3315
|
status: "success",
|
|
2406
3316
|
signature,
|
|
2407
3317
|
description: pendingTx.description
|
|
2408
3318
|
}
|
|
2409
|
-
};
|
|
3319
|
+
}];
|
|
2410
3320
|
}
|
|
2411
3321
|
await persistResolvedSignerState(
|
|
2412
3322
|
session,
|
|
2413
3323
|
state,
|
|
2414
3324
|
account.address,
|
|
2415
|
-
|
|
3325
|
+
primaryChainId
|
|
2416
3326
|
);
|
|
2417
|
-
|
|
3327
|
+
for (const txId of txIds) {
|
|
3328
|
+
removePendingTx(state, txId);
|
|
3329
|
+
}
|
|
2418
3330
|
const freshState = readState();
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
3331
|
+
for (const signedRecord of signedRecords) {
|
|
3332
|
+
addSignedTx(freshState, signedRecord);
|
|
3333
|
+
}
|
|
3334
|
+
for (const backendNotification of backendNotifications) {
|
|
3335
|
+
await session.client.sendSystemMessage(
|
|
3336
|
+
state.sessionId,
|
|
3337
|
+
JSON.stringify(backendNotification)
|
|
3338
|
+
);
|
|
3339
|
+
}
|
|
2424
3340
|
console.log("Backend notified.");
|
|
2425
3341
|
} catch (err) {
|
|
2426
3342
|
if (err instanceof CliExit) throw err;
|
|
@@ -2450,7 +3366,8 @@ Usage:
|
|
|
2450
3366
|
Delete a local session file (session-id or session-N)
|
|
2451
3367
|
aomi log Show full conversation history with tool results
|
|
2452
3368
|
aomi tx List pending and signed transactions
|
|
2453
|
-
aomi sign <tx-id>
|
|
3369
|
+
aomi sign <tx-id> [<tx-id> ...] [--aa | --eoa] [--aa-provider <name>] [--aa-mode <mode>]
|
|
3370
|
+
Sign and submit a pending transaction
|
|
2454
3371
|
aomi status Show current session state
|
|
2455
3372
|
aomi events List system events
|
|
2456
3373
|
aomi close Close the current session
|
|
@@ -2465,12 +3382,28 @@ Options:
|
|
|
2465
3382
|
--rpc-url <url> RPC URL for transaction submission
|
|
2466
3383
|
--verbose, -v Show tool calls and streaming output (for chat)
|
|
2467
3384
|
|
|
3385
|
+
Sign options:
|
|
3386
|
+
aomi sign <tx-id> --aa
|
|
3387
|
+
Require account-abstraction execution (default)
|
|
3388
|
+
aomi sign <tx-id> --eoa
|
|
3389
|
+
Force plain EOA execution
|
|
3390
|
+
aomi sign <tx-id> --aa-provider <name>
|
|
3391
|
+
AA provider: alchemy | pimlico
|
|
3392
|
+
aomi sign <tx-id> --aa-mode <mode>
|
|
3393
|
+
AA mode: 4337 | 7702
|
|
3394
|
+
|
|
2468
3395
|
Environment (overridden by flags):
|
|
2469
3396
|
AOMI_BASE_URL Backend URL
|
|
2470
3397
|
AOMI_API_KEY API key
|
|
2471
3398
|
AOMI_APP App
|
|
2472
3399
|
AOMI_MODEL Model rig
|
|
2473
3400
|
AOMI_PUBLIC_KEY Wallet address
|
|
3401
|
+
AOMI_AA_PROVIDER AA provider: alchemy | pimlico
|
|
3402
|
+
AOMI_AA_MODE AA mode: 4337 | 7702
|
|
3403
|
+
ALCHEMY_API_KEY Alchemy AA API key
|
|
3404
|
+
ALCHEMY_GAS_POLICY_ID
|
|
3405
|
+
Optional Alchemy gas sponsorship policy ID
|
|
3406
|
+
PIMLICO_API_KEY Pimlico AA API key
|
|
2474
3407
|
PRIVATE_KEY Hex private key for signing
|
|
2475
3408
|
CHAIN_RPC_URL RPC URL for transaction submission
|
|
2476
3409
|
`.trim());
|