arc402-cli 1.8.7 → 1.8.9
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/abis.js +1 -1
- package/dist/abis.js.map +1 -1
- package/dist/approval/broker.d.ts +9 -0
- package/dist/approval/broker.d.ts.map +1 -0
- package/dist/approval/broker.js +45 -0
- package/dist/approval/broker.js.map +1 -0
- package/dist/approval/config.d.ts +20 -0
- package/dist/approval/config.d.ts.map +1 -0
- package/dist/approval/config.js +42 -0
- package/dist/approval/config.js.map +1 -0
- package/dist/approval/init.d.ts +4 -0
- package/dist/approval/init.d.ts.map +1 -0
- package/dist/approval/init.js +128 -0
- package/dist/approval/init.js.map +1 -0
- package/dist/approval/passkey-requests.d.ts +22 -0
- package/dist/approval/passkey-requests.d.ts.map +1 -0
- package/dist/approval/passkey-requests.js +85 -0
- package/dist/approval/passkey-requests.js.map +1 -0
- package/dist/approval/transports/local-qr.d.ts +3 -0
- package/dist/approval/transports/local-qr.d.ts.map +1 -0
- package/dist/approval/transports/local-qr.js +42 -0
- package/dist/approval/transports/local-qr.js.map +1 -0
- package/dist/approval/transports/telegram-passkey-link.d.ts +3 -0
- package/dist/approval/transports/telegram-passkey-link.d.ts.map +1 -0
- package/dist/approval/transports/telegram-passkey-link.js +137 -0
- package/dist/approval/transports/telegram-passkey-link.js.map +1 -0
- package/dist/approval/transports/telegram-walletconnect.d.ts +3 -0
- package/dist/approval/transports/telegram-walletconnect.d.ts.map +1 -0
- package/dist/approval/transports/telegram-walletconnect.js +53 -0
- package/dist/approval/transports/telegram-walletconnect.js.map +1 -0
- package/dist/approval/types.d.ts +66 -0
- package/dist/approval/types.d.ts.map +1 -0
- package/dist/approval/types.js +3 -0
- package/dist/approval/types.js.map +1 -0
- package/dist/bundler.d.ts +1 -0
- package/dist/bundler.d.ts.map +1 -1
- package/dist/bundler.js +31 -0
- package/dist/bundler.js.map +1 -1
- package/dist/commands/accept.js +1 -1
- package/dist/commands/accept.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +22 -7
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/approvals.d.ts +3 -0
- package/dist/commands/approvals.d.ts.map +1 -0
- package/dist/commands/approvals.js +78 -0
- package/dist/commands/approvals.js.map +1 -0
- package/dist/commands/arena-handshake.d.ts.map +1 -1
- package/dist/commands/arena-handshake.js +9 -18
- package/dist/commands/arena-handshake.js.map +1 -1
- package/dist/commands/arena-v2.d.ts.map +1 -1
- package/dist/commands/arena-v2.js +23 -38
- package/dist/commands/arena-v2.js.map +1 -1
- package/dist/commands/compute.d.ts.map +1 -1
- package/dist/commands/compute.js +3 -4
- package/dist/commands/compute.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +1 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/deliver.js +1 -1
- package/dist/commands/deliver.js.map +1 -1
- package/dist/commands/hire.d.ts.map +1 -1
- package/dist/commands/hire.js +3 -4
- package/dist/commands/hire.js.map +1 -1
- package/dist/commands/job.d.ts.map +1 -1
- package/dist/commands/job.js +1 -1
- package/dist/commands/job.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +4 -8
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +598 -204
- package/dist/commands/wallet.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +30 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +59 -0
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/passkey-approvals.d.ts +24 -0
- package/dist/daemon/passkey-approvals.d.ts.map +1 -0
- package/dist/daemon/passkey-approvals.js +31 -0
- package/dist/daemon/passkey-approvals.js.map +1 -0
- package/dist/endpoint-notify.d.ts +1 -2
- package/dist/endpoint-notify.d.ts.map +1 -1
- package/dist/endpoint-notify.js +1 -3
- package/dist/endpoint-notify.js.map +1 -1
- package/dist/program.d.ts.map +1 -1
- package/dist/program.js +2 -0
- package/dist/program.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/wallet.js
CHANGED
|
@@ -1,37 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
4
|
};
|
|
@@ -50,6 +17,8 @@ const format_1 = require("../utils/format");
|
|
|
50
17
|
const abis_1 = require("../abis");
|
|
51
18
|
const config_2 = require("../config");
|
|
52
19
|
const walletconnect_1 = require("../walletconnect");
|
|
20
|
+
const config_3 = require("../approval/config");
|
|
21
|
+
const broker_1 = require("../approval/broker");
|
|
53
22
|
const bundler_1 = require("../bundler");
|
|
54
23
|
const walletconnect_session_1 = require("../walletconnect-session");
|
|
55
24
|
const wallet_router_1 = require("../wallet-router");
|
|
@@ -60,6 +29,89 @@ const spinner_1 = require("../ui/spinner");
|
|
|
60
29
|
const colors_1 = require("../ui/colors");
|
|
61
30
|
const rpc_fallback_1 = require("../ui/rpc-fallback");
|
|
62
31
|
const GUARDIAN_KEY_PATH = path_1.default.join(os_1.default.homedir(), ".arc402", "guardian.key");
|
|
32
|
+
function requireApprovedWalletConnectSession(approval) {
|
|
33
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
34
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
return approval.session;
|
|
38
|
+
}
|
|
39
|
+
async function requestWalletConnectApprovalSession(config, intent) {
|
|
40
|
+
return requireApprovedWalletConnectSession(await (0, broker_1.requestOwnerApproval)(intent, config));
|
|
41
|
+
}
|
|
42
|
+
const PASSKEY_GOVERNANCE_SELECTORS = new Set([
|
|
43
|
+
ethers_1.ethers.id("unfreeze()").slice(0, 10).toLowerCase(),
|
|
44
|
+
ethers_1.ethers.id("setGuardian(address)").slice(0, 10).toLowerCase(),
|
|
45
|
+
ethers_1.ethers.id("proposeRegistryUpdate(address)").slice(0, 10).toLowerCase(),
|
|
46
|
+
ethers_1.ethers.id("executeRegistryUpdate()").slice(0, 10).toLowerCase(),
|
|
47
|
+
ethers_1.ethers.id("cancelRegistryUpdate()").slice(0, 10).toLowerCase(),
|
|
48
|
+
ethers_1.ethers.id("setAuthorizedInterceptor(address)").slice(0, 10).toLowerCase(),
|
|
49
|
+
ethers_1.ethers.id("setVelocityLimit(uint256)").slice(0, 10).toLowerCase(),
|
|
50
|
+
ethers_1.ethers.id("authorizeMachineKey(address)").slice(0, 10).toLowerCase(),
|
|
51
|
+
ethers_1.ethers.id("revokeMachineKey(address)").slice(0, 10).toLowerCase(),
|
|
52
|
+
]);
|
|
53
|
+
function canUsePasskeyForWalletGovernance(config, walletAddress, tx) {
|
|
54
|
+
const approval = (0, config_3.getApprovalConfig)(config);
|
|
55
|
+
const selector = tx.data.slice(0, 10).toLowerCase();
|
|
56
|
+
return approval.defaultTransport === "telegram_passkey_link"
|
|
57
|
+
&& tx.to.toLowerCase() === walletAddress.toLowerCase()
|
|
58
|
+
&& PASSKEY_GOVERNANCE_SELECTORS.has(selector);
|
|
59
|
+
}
|
|
60
|
+
async function requestWalletGovernanceExecution(config, intent) {
|
|
61
|
+
const walletAddress = intent.walletAddress;
|
|
62
|
+
const tx = intent.txs[0];
|
|
63
|
+
if (!walletAddress || !tx || intent.txs.length !== 1) {
|
|
64
|
+
return {
|
|
65
|
+
kind: "walletconnect",
|
|
66
|
+
session: await requestWalletConnectApprovalSession(config, intent),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (!canUsePasskeyForWalletGovernance(config, walletAddress, tx)) {
|
|
70
|
+
return {
|
|
71
|
+
kind: "walletconnect",
|
|
72
|
+
session: await requestWalletConnectApprovalSession(config, intent),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
76
|
+
const nonceReader = new ethers_1.ethers.Contract(bundler_1.DEFAULT_ENTRY_POINT, ["function getNonce(address sender, uint192 key) external view returns (uint256)"], provider);
|
|
77
|
+
const nonce = await nonceReader.getNonce(walletAddress, 0);
|
|
78
|
+
const bundler = new bundler_1.BundlerClient(process.env.BUNDLER_URL ?? bundler_1.DEFAULT_BUNDLER_URL, bundler_1.DEFAULT_ENTRY_POINT, intent.chainId);
|
|
79
|
+
const userOp = await (0, bundler_1.buildUserOp)(tx.data, walletAddress, nonce, config);
|
|
80
|
+
try {
|
|
81
|
+
const estimate = await bundler.estimateUserOperationGas(userOp);
|
|
82
|
+
userOp.callGasLimit = estimate.callGasLimit;
|
|
83
|
+
userOp.verificationGasLimit = estimate.verificationGasLimit;
|
|
84
|
+
userOp.preVerificationGas = estimate.preVerificationGas;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// keep conservative defaults if estimation is unavailable
|
|
88
|
+
}
|
|
89
|
+
const challenge = (0, bundler_1.getUserOperationHash)(userOp, bundler_1.DEFAULT_ENTRY_POINT, intent.chainId);
|
|
90
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
91
|
+
...intent,
|
|
92
|
+
signerMode: "passkey",
|
|
93
|
+
metadata: {
|
|
94
|
+
...intent.metadata,
|
|
95
|
+
passkeyChallenge: challenge,
|
|
96
|
+
},
|
|
97
|
+
}, config);
|
|
98
|
+
if (approval.status !== "approved" || !approval.passkeyApproval?.signature) {
|
|
99
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Passkey approval failed."));
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
userOp.signature = approval.passkeyApproval.signature;
|
|
103
|
+
const userOpHash = await bundler.sendUserOperation(userOp);
|
|
104
|
+
const receipt = await bundler.getUserOperationReceipt(userOpHash);
|
|
105
|
+
if (!receipt.success) {
|
|
106
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red("UserOperation failed on-chain."));
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
kind: "passkey",
|
|
111
|
+
userOpHash,
|
|
112
|
+
txHash: String(receipt.receipt.transactionHash),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
63
115
|
function buildFreshConfigFromDefaults(existing, network, privateKey, ownerAddress) {
|
|
64
116
|
const defaults = config_1.NETWORK_DEFAULTS[network];
|
|
65
117
|
if (!defaults)
|
|
@@ -74,6 +126,7 @@ function buildFreshConfigFromDefaults(existing, network, privateKey, ownerAddres
|
|
|
74
126
|
telegramBotToken: existing?.telegramBotToken,
|
|
75
127
|
telegramChatId: existing?.telegramChatId,
|
|
76
128
|
telegramThreadId: existing?.telegramThreadId,
|
|
129
|
+
approval: existing?.approval,
|
|
77
130
|
deviceId: existing?.deviceId,
|
|
78
131
|
chat: existing?.chat,
|
|
79
132
|
policyEngineAddress: defaults.policyEngineAddress,
|
|
@@ -131,9 +184,7 @@ function parseAmount(raw) {
|
|
|
131
184
|
return BigInt(raw);
|
|
132
185
|
}
|
|
133
186
|
function resolvePolicyEngineAddress(config) {
|
|
134
|
-
return (config
|
|
135
|
-
config_1.NETWORK_DEFAULTS[config.network]?.policyEngineAddress ??
|
|
136
|
-
"0x9449B15268bE7042C0b473F3f711a41A29220866");
|
|
187
|
+
return (0, config_1.getCanonicalNetworkAddress)(config, "policyEngineAddress");
|
|
137
188
|
}
|
|
138
189
|
function getWalletAddressFromFactoryLogs(factoryInterface, logs) {
|
|
139
190
|
for (const log of logs) {
|
|
@@ -158,6 +209,13 @@ function getWalletAddressFromFactoryLogs(factoryInterface, logs) {
|
|
|
158
209
|
}
|
|
159
210
|
return null;
|
|
160
211
|
}
|
|
212
|
+
async function assertAddressHasCode(provider, address, label) {
|
|
213
|
+
const code = await provider.getCode(address);
|
|
214
|
+
if (code !== "0x")
|
|
215
|
+
return;
|
|
216
|
+
throw new Error(`${label} ${address} has no contract code. ` +
|
|
217
|
+
`This usually means an owner EOA was saved instead of the deployed ARC402Wallet contract.`);
|
|
218
|
+
}
|
|
161
219
|
// Standard onboarding categories required for a newly deployed wallet.
|
|
162
220
|
// These cover the full ARC-402 flow: spending, hiring, compute, research, protocol ops.
|
|
163
221
|
const ONBOARDING_CATEGORIES = [
|
|
@@ -175,7 +233,6 @@ const ONBOARDING_CATEGORIES = [
|
|
|
175
233
|
*/
|
|
176
234
|
async function runWalletOnboardingCeremony(walletAddress, ownerAddress, config, provider, sendTx) {
|
|
177
235
|
const policyAddress = resolvePolicyEngineAddress(config);
|
|
178
|
-
const executeIface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_EXECUTE_ABI);
|
|
179
236
|
const govIface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_GOVERNANCE_ABI);
|
|
180
237
|
const limitsIface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_LIMITS_ABI);
|
|
181
238
|
const policyGov = new ethers_1.ethers.Contract(policyAddress, abis_1.POLICY_ENGINE_GOVERNANCE_ABI, provider);
|
|
@@ -198,15 +255,8 @@ async function runWalletOnboardingCeremony(walletAddress, ownerAddress, config,
|
|
|
198
255
|
if (!alreadyRegistered) {
|
|
199
256
|
const registerCalldata = govIface.encodeFunctionData("registerWallet", [walletAddress, ownerAddress]);
|
|
200
257
|
await sendTx({
|
|
201
|
-
to:
|
|
202
|
-
data:
|
|
203
|
-
target: policyAddress,
|
|
204
|
-
data: registerCalldata,
|
|
205
|
-
value: 0n,
|
|
206
|
-
minReturnValue: 0n,
|
|
207
|
-
maxApprovalAmount: 0n,
|
|
208
|
-
approvalToken: ethers_1.ethers.ZeroAddress,
|
|
209
|
-
}]),
|
|
258
|
+
to: policyAddress,
|
|
259
|
+
data: registerCalldata,
|
|
210
260
|
value: "0x0",
|
|
211
261
|
}, "registerWallet on PolicyEngine");
|
|
212
262
|
}
|
|
@@ -254,11 +304,8 @@ async function runWalletOnboardingCeremony(walletAddress, ownerAddress, config,
|
|
|
254
304
|
*/
|
|
255
305
|
async function runCompleteOnboardingCeremony(walletAddress, ownerAddress, config, provider, sendTx) {
|
|
256
306
|
const policyAddress = resolvePolicyEngineAddress(config);
|
|
257
|
-
const agentRegistryAddress = config
|
|
258
|
-
|
|
259
|
-
const handshakeAddress = config.handshakeAddress ??
|
|
260
|
-
config_1.NETWORK_DEFAULTS[config.network]?.handshakeAddress ??
|
|
261
|
-
"0x4F5A38Bb746d7E5d49d8fd26CA6beD141Ec2DDb3";
|
|
307
|
+
const agentRegistryAddress = (0, config_1.getCanonicalAgentRegistryAddress)(config);
|
|
308
|
+
const handshakeAddress = (0, config_1.getCanonicalNetworkAddress)(config, "handshakeAddress");
|
|
262
309
|
// ── Step 2: Machine Key ────────────────────────────────────────────────────
|
|
263
310
|
console.log("\n" + colors_1.c.dim("── Step 2: Machine Key ────────────────────────────────────────"));
|
|
264
311
|
let machineKeyAddress;
|
|
@@ -486,11 +533,11 @@ async function runCompleteOnboardingCeremony(walletAddress, ownerAddress, config
|
|
|
486
533
|
// Whitelist all contracts an agent will need for the full ARC-402 flow.
|
|
487
534
|
const protocolContracts = [
|
|
488
535
|
{ address: agentRegistryAddress ?? "", name: "AgentRegistry" },
|
|
489
|
-
{ address:
|
|
490
|
-
{ address:
|
|
491
|
-
{ address:
|
|
492
|
-
{ address:
|
|
493
|
-
{ address:
|
|
536
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.serviceAgreementAddress ?? "", name: "ServiceAgreement" },
|
|
537
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.computeAgreementAddress ?? "", name: "ComputeAgreement" },
|
|
538
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.subscriptionAgreementAddress ?? "", name: "SubscriptionAgreement" },
|
|
539
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.handshakeAddress ?? "", name: "Handshake" },
|
|
540
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.sessionChannelsAddress ?? "", name: "SessionChannels" },
|
|
494
541
|
].filter(c => c.address && c.address !== "");
|
|
495
542
|
for (const contract of protocolContracts) {
|
|
496
543
|
const isWhitelisted = await peContract.isContractWhitelisted(walletAddress, contract.address).catch(() => false);
|
|
@@ -1002,7 +1049,7 @@ function registerWalletCommands(program) {
|
|
|
1002
1049
|
console.log(colors_1.c.dim(` ◈ --force: cleared wallet config. Factory reset to ${config.walletFactoryAddress} (V6).`));
|
|
1003
1050
|
}
|
|
1004
1051
|
if (opts.dryRun) {
|
|
1005
|
-
const factoryAddr =
|
|
1052
|
+
const factoryAddr = config_1.NETWORK_DEFAULTS[config.network]?.walletFactoryAddress ?? "(not configured)";
|
|
1006
1053
|
const chainId = config.network === "base-mainnet" ? 8453 : 84532;
|
|
1007
1054
|
console.log();
|
|
1008
1055
|
console.log(" " + colors_1.c.dim("── Dry run: wallet deploy ──────────────────────────────────────"));
|
|
@@ -1100,6 +1147,7 @@ function registerWalletCommands(program) {
|
|
|
1100
1147
|
console.error("UserOperation failed on-chain.");
|
|
1101
1148
|
process.exit(1);
|
|
1102
1149
|
}
|
|
1150
|
+
await assertAddressHasCode(provider, senderAddress, "Deployed wallet");
|
|
1103
1151
|
config.walletContractAddress = senderAddress;
|
|
1104
1152
|
config.ownerAddress = ownerAddress;
|
|
1105
1153
|
(0, config_1.saveConfig)(config);
|
|
@@ -1137,6 +1185,7 @@ function registerWalletCommands(program) {
|
|
|
1137
1185
|
console.error("Could not find WalletDeployed/WalletCreated event in receipt. Check the transaction on-chain.");
|
|
1138
1186
|
process.exit(1);
|
|
1139
1187
|
}
|
|
1188
|
+
await assertAddressHasCode(provider, walletAddress, "Deployed wallet");
|
|
1140
1189
|
config.walletContractAddress = walletAddress;
|
|
1141
1190
|
config.ownerAddress = account;
|
|
1142
1191
|
(0, config_1.saveConfig)(config);
|
|
@@ -1229,6 +1278,7 @@ function registerWalletCommands(program) {
|
|
|
1229
1278
|
console.error("Could not find WalletDeployed/WalletCreated event in receipt. Check the transaction on-chain.");
|
|
1230
1279
|
process.exit(1);
|
|
1231
1280
|
}
|
|
1281
|
+
await assertAddressHasCode(provider, deployedWallet, "Deployed wallet");
|
|
1232
1282
|
walletAddress = deployedWallet;
|
|
1233
1283
|
// ── Step 1 complete: save wallet + owner immediately ─────────────────
|
|
1234
1284
|
config.walletContractAddress = walletAddress;
|
|
@@ -1269,6 +1319,7 @@ function registerWalletCommands(program) {
|
|
|
1269
1319
|
deploySpinner.fail("Could not find WalletDeployed/WalletCreated event in receipt. Check the transaction on-chain.");
|
|
1270
1320
|
process.exit(1);
|
|
1271
1321
|
}
|
|
1322
|
+
await assertAddressHasCode(provider, walletAddress, "Deployed wallet");
|
|
1272
1323
|
deploySpinner.succeed("Wallet deployed");
|
|
1273
1324
|
// Generate guardian key (separate from hot key) and call setGuardian
|
|
1274
1325
|
const guardianWallet = ethers_1.ethers.Wallet.createRandom();
|
|
@@ -1327,14 +1378,20 @@ function registerWalletCommands(program) {
|
|
|
1327
1378
|
const policyAddress = resolvePolicyEngineAddress(config);
|
|
1328
1379
|
const chainId = config.network === "base-mainnet" ? 8453 : 84532;
|
|
1329
1380
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1381
|
+
try {
|
|
1382
|
+
await assertAddressHasCode(provider, walletAddress, "Configured walletContractAddress");
|
|
1383
|
+
}
|
|
1384
|
+
catch (error) {
|
|
1385
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(error instanceof Error ? error.message : String(error)));
|
|
1386
|
+
console.error(colors_1.c.dim("Tip: use the deployed wallet contract address, not the owner EOA, then rerun onboarding."));
|
|
1387
|
+
process.exit(1);
|
|
1388
|
+
}
|
|
1330
1389
|
// Resolve protocol contracts to whitelist
|
|
1331
|
-
const handshakeAddress = config.handshakeAddress ??
|
|
1332
|
-
config_1.NETWORK_DEFAULTS[config.network]?.handshakeAddress ??
|
|
1333
|
-
"0x4F5A38Bb746d7E5d49d8fd26CA6beD141Ec2DDb3";
|
|
1390
|
+
const handshakeAddress = config_1.NETWORK_DEFAULTS[config.network]?.handshakeAddress ?? "";
|
|
1334
1391
|
const protocolContracts = [
|
|
1335
|
-
{ address:
|
|
1336
|
-
{ address:
|
|
1337
|
-
{ address:
|
|
1392
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.serviceAgreementAddress ?? "", name: "ServiceAgreement" },
|
|
1393
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.computeAgreementAddress ?? "", name: "ComputeAgreement" },
|
|
1394
|
+
{ address: config_1.NETWORK_DEFAULTS[config.network]?.subscriptionAgreementAddress ?? "", name: "SubscriptionAgreement" },
|
|
1338
1395
|
{ address: handshakeAddress, name: "Handshake" },
|
|
1339
1396
|
].filter(pc => pc.address && pc.address !== "");
|
|
1340
1397
|
// Pre-check on-chain state to count pending txs and decide what to skip
|
|
@@ -1408,23 +1465,31 @@ function registerWalletCommands(program) {
|
|
|
1408
1465
|
return;
|
|
1409
1466
|
}
|
|
1410
1467
|
console.log(" " + colors_1.c.dim(`◈ ${pendingTxCount} transaction(s) pending — your phone will need to approve each.`));
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1468
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
1469
|
+
actionType: "wallet_onboard",
|
|
1470
|
+
signerMode: "owner_wallet",
|
|
1471
|
+
chainId,
|
|
1472
|
+
walletAddress,
|
|
1473
|
+
txs: Array.from({ length: pendingTxCount }, () => ({ to: walletAddress, data: "0x", value: "0x0" })),
|
|
1474
|
+
ui: {
|
|
1475
|
+
title: "Wallet onboarding",
|
|
1476
|
+
summary: `Approve ${pendingTxCount} wallet onboarding transaction(s)`,
|
|
1477
|
+
risk: "medium",
|
|
1478
|
+
},
|
|
1479
|
+
metadata: {
|
|
1480
|
+
expectedApprovalCount: pendingTxCount,
|
|
1481
|
+
sourceRuntime: "cli",
|
|
1482
|
+
hardware: !!opts.hardware,
|
|
1483
|
+
},
|
|
1484
|
+
}, config);
|
|
1485
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
1486
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
1487
|
+
process.exit(1);
|
|
1488
|
+
}
|
|
1489
|
+
const { client, session, account } = approval.session;
|
|
1417
1490
|
const networkName = chainId === 8453 ? "Base" : "Base Sepolia";
|
|
1418
1491
|
const shortAddr = `${account.slice(0, 6)}...${account.slice(-5)}`;
|
|
1419
1492
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${shortAddr} on ${networkName}`));
|
|
1420
|
-
if (telegramOpts) {
|
|
1421
|
-
await (0, telegram_notify_1.sendTelegramMessage)({
|
|
1422
|
-
botToken: telegramOpts.botToken,
|
|
1423
|
-
chatId: telegramOpts.chatId,
|
|
1424
|
-
threadId: telegramOpts.threadId,
|
|
1425
|
-
text: `◈ arc402 wallet onboard: ${pendingTxCount} txs pending for ${shortAddr}`,
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
1493
|
const sendTx = async (call, description) => {
|
|
1429
1494
|
const txSpin = (0, spinner_1.startSpinner)(description);
|
|
1430
1495
|
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, call);
|
|
@@ -1432,24 +1497,22 @@ function registerWalletCommands(program) {
|
|
|
1432
1497
|
txSpin.succeed(description);
|
|
1433
1498
|
return hash;
|
|
1434
1499
|
};
|
|
1435
|
-
const executeIface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_EXECUTE_ABI);
|
|
1436
1500
|
const govIface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_GOVERNANCE_ABI);
|
|
1437
1501
|
const limitsIface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_LIMITS_ABI);
|
|
1438
1502
|
const ownerIface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_OWNER_ABI);
|
|
1503
|
+
const walletOwnerReader = new ethers_1.ethers.Contract(walletAddress, ["function owner() external view returns (address)"], provider);
|
|
1504
|
+
const walletOwner = await walletOwnerReader.owner().catch(() => account);
|
|
1505
|
+
if (walletOwner.toLowerCase() !== account.toLowerCase()) {
|
|
1506
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(`Connected wallet ${account} is not the ARC402Wallet owner ${walletOwner}.`));
|
|
1507
|
+
process.exit(1);
|
|
1508
|
+
}
|
|
1439
1509
|
console.log("\n" + colors_1.c.dim("── Onboarding ceremony ────────────────────────────────────────"));
|
|
1440
1510
|
// 1. registerWallet
|
|
1441
1511
|
if (needsRegister) {
|
|
1442
|
-
const registerCalldata = govIface.encodeFunctionData("registerWallet", [walletAddress,
|
|
1512
|
+
const registerCalldata = govIface.encodeFunctionData("registerWallet", [walletAddress, walletOwner]);
|
|
1443
1513
|
await sendTx({
|
|
1444
|
-
to:
|
|
1445
|
-
data:
|
|
1446
|
-
target: policyAddress,
|
|
1447
|
-
data: registerCalldata,
|
|
1448
|
-
value: 0n,
|
|
1449
|
-
minReturnValue: 0n,
|
|
1450
|
-
maxApprovalAmount: 0n,
|
|
1451
|
-
approvalToken: ethers_1.ethers.ZeroAddress,
|
|
1452
|
-
}]),
|
|
1514
|
+
to: policyAddress,
|
|
1515
|
+
data: registerCalldata,
|
|
1453
1516
|
value: "0x0",
|
|
1454
1517
|
}, "registerWallet on PolicyEngine");
|
|
1455
1518
|
}
|
|
@@ -1574,15 +1637,33 @@ function registerWalletCommands(program) {
|
|
|
1574
1637
|
process.exit(1);
|
|
1575
1638
|
}
|
|
1576
1639
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1577
|
-
const
|
|
1640
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
1641
|
+
actionType: "spend_limit_set",
|
|
1642
|
+
signerMode: "owner_wallet",
|
|
1643
|
+
chainId,
|
|
1644
|
+
walletAddress: walletAddr,
|
|
1645
|
+
txs: [{
|
|
1646
|
+
to: policyAddress,
|
|
1647
|
+
data: policyInterface.encodeFunctionData("setCategoryLimitFor", [walletAddr, opts.category, amount]),
|
|
1648
|
+
value: "0x0",
|
|
1649
|
+
}],
|
|
1650
|
+
ui: {
|
|
1651
|
+
title: "Set spend limit",
|
|
1652
|
+
summary: `Approve spend limit: ${opts.category} → ${opts.amount} ETH`,
|
|
1653
|
+
risk: "medium",
|
|
1654
|
+
},
|
|
1655
|
+
metadata: { sourceRuntime: "cli" },
|
|
1656
|
+
}, config);
|
|
1657
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
1658
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
1659
|
+
process.exit(1);
|
|
1660
|
+
}
|
|
1661
|
+
const { client, session, account } = approval.session;
|
|
1662
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, {
|
|
1578
1663
|
to: policyAddress,
|
|
1579
1664
|
data: policyInterface.encodeFunctionData("setCategoryLimitFor", [walletAddr, opts.category, amount]),
|
|
1580
1665
|
value: "0x0",
|
|
1581
|
-
})
|
|
1582
|
-
botToken: config.telegramBotToken,
|
|
1583
|
-
chatId: config.telegramChatId,
|
|
1584
|
-
threadId: config.telegramThreadId,
|
|
1585
|
-
} : undefined, config);
|
|
1666
|
+
});
|
|
1586
1667
|
console.log(`\nTransaction submitted: ${txHash}`);
|
|
1587
1668
|
await provider.waitForTransaction(txHash);
|
|
1588
1669
|
console.log(`Spend limit for ${opts.category} set to ${opts.amount} ETH`);
|
|
@@ -1625,15 +1706,33 @@ function registerWalletCommands(program) {
|
|
|
1625
1706
|
const policyInterface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_LIMITS_ABI);
|
|
1626
1707
|
if (config.walletConnectProjectId) {
|
|
1627
1708
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1628
|
-
const
|
|
1709
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
1710
|
+
actionType: "policy_update",
|
|
1711
|
+
signerMode: "owner_wallet",
|
|
1712
|
+
chainId,
|
|
1713
|
+
walletAddress: walletAddr,
|
|
1714
|
+
txs: [{
|
|
1715
|
+
to: policyAddress,
|
|
1716
|
+
data: policyInterface.encodeFunctionData("setDailyLimitFor", [walletAddr, opts.category, amount]),
|
|
1717
|
+
value: "0x0",
|
|
1718
|
+
}],
|
|
1719
|
+
ui: {
|
|
1720
|
+
title: "Set daily limit",
|
|
1721
|
+
summary: `Approve daily limit: ${opts.category} → ${opts.amount} ETH`,
|
|
1722
|
+
risk: "medium",
|
|
1723
|
+
},
|
|
1724
|
+
metadata: { sourceRuntime: "cli" },
|
|
1725
|
+
}, config);
|
|
1726
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
1727
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
1728
|
+
process.exit(1);
|
|
1729
|
+
}
|
|
1730
|
+
const { client, session, account } = approval.session;
|
|
1731
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, {
|
|
1629
1732
|
to: policyAddress,
|
|
1630
1733
|
data: policyInterface.encodeFunctionData("setDailyLimitFor", [walletAddr, opts.category, amount]),
|
|
1631
1734
|
value: "0x0",
|
|
1632
|
-
})
|
|
1633
|
-
botToken: config.telegramBotToken,
|
|
1634
|
-
chatId: config.telegramChatId,
|
|
1635
|
-
threadId: config.telegramThreadId,
|
|
1636
|
-
} : undefined, config);
|
|
1735
|
+
});
|
|
1637
1736
|
await provider.waitForTransaction(txHash);
|
|
1638
1737
|
console.log(`Daily limit for ${opts.category} set to ${opts.amount} ETH (12/24h rolling window)`);
|
|
1639
1738
|
}
|
|
@@ -1674,24 +1773,30 @@ function registerWalletCommands(program) {
|
|
|
1674
1773
|
];
|
|
1675
1774
|
const policyInterface = new ethers_1.ethers.Interface(abis_1.POLICY_ENGINE_LIMITS_ABI);
|
|
1676
1775
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1677
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId ? {
|
|
1678
|
-
botToken: config.telegramBotToken,
|
|
1679
|
-
chatId: config.telegramChatId,
|
|
1680
|
-
threadId: config.telegramThreadId,
|
|
1681
|
-
} : undefined;
|
|
1682
1776
|
console.log(colors_1.c.white("\n◈ Spend limit init — 1 connection, 5 approvals\n"));
|
|
1683
1777
|
console.log(colors_1.c.dim(" Connect once — MetaMask will prompt 5 times in sequence."));
|
|
1684
|
-
|
|
1685
|
-
|
|
1778
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
1779
|
+
actionType: "spend_limit_set",
|
|
1780
|
+
signerMode: "owner_wallet",
|
|
1781
|
+
chainId,
|
|
1782
|
+
walletAddress: walletAddr,
|
|
1783
|
+
txs: categories.map(() => ({ to: policyAddress, data: "0x", value: "0x0" })),
|
|
1784
|
+
ui: {
|
|
1785
|
+
title: "Initialize spend limits",
|
|
1786
|
+
summary: "Connect wallet for spend limit setup (5 approvals)",
|
|
1787
|
+
risk: "medium",
|
|
1788
|
+
},
|
|
1789
|
+
metadata: { expectedApprovalCount: categories.length, sourceRuntime: "cli" },
|
|
1790
|
+
}, config);
|
|
1791
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
1792
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
1793
|
+
process.exit(1);
|
|
1794
|
+
}
|
|
1795
|
+
const { client, session, account } = approval.session;
|
|
1686
1796
|
for (const cat of categories) {
|
|
1687
1797
|
const amount = ethers_1.ethers.parseEther(cat.amount);
|
|
1688
1798
|
const data = policyInterface.encodeFunctionData("setCategoryLimitFor", [walletAddr, cat.name, amount]);
|
|
1689
1799
|
console.log(colors_1.c.dim(`\n Setting ${cat.name} → ${cat.amount} ETH...`));
|
|
1690
|
-
// Send Telegram notification for each
|
|
1691
|
-
if (telegramOpts) {
|
|
1692
|
-
const { sendTelegramMessage: sendTg } = await Promise.resolve().then(() => __importStar(require("../telegram-notify.js")));
|
|
1693
|
-
await sendTg({ ...telegramOpts, text: `Approve spend limit: ${cat.name} → ${cat.amount} ETH` });
|
|
1694
|
-
}
|
|
1695
1800
|
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, {
|
|
1696
1801
|
to: policyAddress,
|
|
1697
1802
|
data,
|
|
@@ -1736,14 +1841,33 @@ function registerWalletCommands(program) {
|
|
|
1736
1841
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
1737
1842
|
console.log(`Current policy: ${currentPolicy}`);
|
|
1738
1843
|
console.log(`New policy: ${policyIdHex}`);
|
|
1739
|
-
const
|
|
1740
|
-
|
|
1741
|
-
:
|
|
1742
|
-
|
|
1844
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
1845
|
+
actionType: "policy_update",
|
|
1846
|
+
signerMode: "owner_wallet",
|
|
1847
|
+
chainId,
|
|
1848
|
+
walletAddress: config.walletContractAddress,
|
|
1849
|
+
txs: [{
|
|
1850
|
+
to: config.walletContractAddress,
|
|
1851
|
+
data: ownerInterface.encodeFunctionData("updatePolicy", [policyIdHex]),
|
|
1852
|
+
value: "0x0",
|
|
1853
|
+
}],
|
|
1854
|
+
ui: {
|
|
1855
|
+
title: "Update active policy",
|
|
1856
|
+
summary: `Approve: update policy to ${policyIdHex}`,
|
|
1857
|
+
risk: "medium",
|
|
1858
|
+
},
|
|
1859
|
+
metadata: { sourceRuntime: "cli" },
|
|
1860
|
+
}, config);
|
|
1861
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
1862
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
1863
|
+
process.exit(1);
|
|
1864
|
+
}
|
|
1865
|
+
const { client, session, account } = approval.session;
|
|
1866
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, {
|
|
1743
1867
|
to: config.walletContractAddress,
|
|
1744
1868
|
data: ownerInterface.encodeFunctionData("updatePolicy", [policyIdHex]),
|
|
1745
1869
|
value: "0x0",
|
|
1746
|
-
})
|
|
1870
|
+
});
|
|
1747
1871
|
await provider.waitForTransaction(txHash);
|
|
1748
1872
|
console.log("\n" + colors_1.c.success + colors_1.c.white(" Active policy updated"));
|
|
1749
1873
|
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(txHash));
|
|
@@ -1814,10 +1938,35 @@ function registerWalletCommands(program) {
|
|
|
1814
1938
|
const chainId = config.network === "base-mainnet" ? 8453 : 84532;
|
|
1815
1939
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1816
1940
|
const walletInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_GUARDIAN_ABI);
|
|
1817
|
-
const
|
|
1818
|
-
|
|
1819
|
-
:
|
|
1820
|
-
|
|
1941
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
1942
|
+
actionType: "custom_tx",
|
|
1943
|
+
signerMode: "owner_wallet",
|
|
1944
|
+
chainId,
|
|
1945
|
+
walletAddress: config.walletContractAddress,
|
|
1946
|
+
txs: [{
|
|
1947
|
+
to: config.walletContractAddress,
|
|
1948
|
+
data: walletInterface.encodeFunctionData("unfreeze", []),
|
|
1949
|
+
value: "0x0",
|
|
1950
|
+
}],
|
|
1951
|
+
ui: {
|
|
1952
|
+
title: "Unfreeze wallet",
|
|
1953
|
+
summary: "Approve: unfreeze ARC402Wallet",
|
|
1954
|
+
risk: "high",
|
|
1955
|
+
},
|
|
1956
|
+
metadata: { sourceRuntime: "cli", hardware: !!opts.hardware },
|
|
1957
|
+
});
|
|
1958
|
+
if (execution.kind === "passkey") {
|
|
1959
|
+
if (opts.json) {
|
|
1960
|
+
console.log(JSON.stringify({ txHash: execution.txHash, walletAddress: config.walletContractAddress, userOpHash: execution.userOpHash }));
|
|
1961
|
+
}
|
|
1962
|
+
else {
|
|
1963
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(` Wallet ${config.walletContractAddress} unfrozen`));
|
|
1964
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
1965
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
1966
|
+
}
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
const { client, session, account } = execution.session;
|
|
1821
1970
|
const networkName = chainId === 8453 ? "Base" : "Base Sepolia";
|
|
1822
1971
|
const shortAddr = `${account.slice(0, 6)}...${account.slice(-5)}`;
|
|
1823
1972
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${shortAddr} on ${networkName}`));
|
|
@@ -1875,10 +2024,37 @@ function registerWalletCommands(program) {
|
|
|
1875
2024
|
const walletInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_GUARDIAN_ABI);
|
|
1876
2025
|
console.log(`\nGuardian address: ${guardianWallet.address}`);
|
|
1877
2026
|
console.log(`Wallet contract: ${config.walletContractAddress}`);
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1880
|
-
:
|
|
1881
|
-
|
|
2027
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2028
|
+
actionType: "custom_tx",
|
|
2029
|
+
signerMode: "owner_wallet",
|
|
2030
|
+
chainId,
|
|
2031
|
+
walletAddress: config.walletContractAddress,
|
|
2032
|
+
txs: [{
|
|
2033
|
+
to: config.walletContractAddress,
|
|
2034
|
+
data: walletInterface.encodeFunctionData("setGuardian", [guardianWallet.address]),
|
|
2035
|
+
value: "0x0",
|
|
2036
|
+
}],
|
|
2037
|
+
ui: {
|
|
2038
|
+
title: "Set guardian",
|
|
2039
|
+
summary: `Approve: set guardian to ${guardianWallet.address}`,
|
|
2040
|
+
risk: "high",
|
|
2041
|
+
},
|
|
2042
|
+
metadata: { sourceRuntime: "cli", hardware: !!opts.hardware },
|
|
2043
|
+
});
|
|
2044
|
+
if (execution.kind === "passkey") {
|
|
2045
|
+
saveGuardianKey(guardianWallet.privateKey);
|
|
2046
|
+
if (config.guardianPrivateKey)
|
|
2047
|
+
delete config.guardianPrivateKey;
|
|
2048
|
+
config.guardianAddress = guardianWallet.address;
|
|
2049
|
+
(0, config_1.saveConfig)(config);
|
|
2050
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(` Guardian set to: ${guardianWallet.address}`));
|
|
2051
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2052
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2053
|
+
console.log(" " + colors_1.c.dim("Guardian private key saved to ~/.arc402/guardian.key (chmod 400)."));
|
|
2054
|
+
console.log(" " + colors_1.c.warning + " " + colors_1.c.yellow("The guardian key can freeze your wallet. Store it separately from your hot key."));
|
|
2055
|
+
return;
|
|
2056
|
+
}
|
|
2057
|
+
const { client, session, account } = execution.session;
|
|
1882
2058
|
const networkName = chainId === 8453 ? "Base" : "Base Sepolia";
|
|
1883
2059
|
const shortAddr = `${account.slice(0, 6)}...${account.slice(-5)}`;
|
|
1884
2060
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${shortAddr} on ${networkName}`));
|
|
@@ -1974,10 +2150,36 @@ function registerWalletCommands(program) {
|
|
|
1974
2150
|
console.log(` Value: 0x0`);
|
|
1975
2151
|
return;
|
|
1976
2152
|
}
|
|
1977
|
-
const
|
|
1978
|
-
|
|
1979
|
-
:
|
|
1980
|
-
|
|
2153
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2154
|
+
actionType: "custom_tx",
|
|
2155
|
+
signerMode: "owner_wallet",
|
|
2156
|
+
chainId,
|
|
2157
|
+
walletAddress: config.walletContractAddress,
|
|
2158
|
+
txs: [{ to: config.walletContractAddress, data: calldata, value: "0x0" }],
|
|
2159
|
+
ui: {
|
|
2160
|
+
title: "Propose registry upgrade",
|
|
2161
|
+
summary: "Approve registry upgrade proposal on ARC402Wallet",
|
|
2162
|
+
risk: "high",
|
|
2163
|
+
},
|
|
2164
|
+
metadata: {
|
|
2165
|
+
sourceRuntime: "cli",
|
|
2166
|
+
hardware: !!opts.hardware,
|
|
2167
|
+
},
|
|
2168
|
+
});
|
|
2169
|
+
if (execution.kind === "passkey") {
|
|
2170
|
+
const unlockAt = new Date(Date.now() + 2 * 24 * 60 * 60 * 1000);
|
|
2171
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(" Registry upgrade proposed"));
|
|
2172
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2173
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2174
|
+
console.log(" " + colors_1.c.dim("Unlock at:") + " " + colors_1.c.white(unlockAt.toISOString()) + colors_1.c.dim(" (approximately)"));
|
|
2175
|
+
console.log(`\nNext steps:`);
|
|
2176
|
+
console.log(` Wait 2 days, then run:`);
|
|
2177
|
+
console.log(` arc402 wallet execute-registry-upgrade`);
|
|
2178
|
+
console.log(`\nTo cancel before execution:`);
|
|
2179
|
+
console.log(` arc402 wallet cancel-registry-upgrade`);
|
|
2180
|
+
return;
|
|
2181
|
+
}
|
|
2182
|
+
const { client, session, account } = execution.session;
|
|
1981
2183
|
const networkName = chainId === 8453 ? "Base" : "Base Sepolia";
|
|
1982
2184
|
const shortAddr = `${account.slice(0, 6)}...${account.slice(-5)}`;
|
|
1983
2185
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${shortAddr} on ${networkName}`));
|
|
@@ -2043,15 +2245,39 @@ function registerWalletCommands(program) {
|
|
|
2043
2245
|
}
|
|
2044
2246
|
console.log(`Pending registry: ${pendingRegistry}`);
|
|
2045
2247
|
console.log("Timelock elapsed — proceeding with executeRegistryUpdate()");
|
|
2046
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2047
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2048
|
-
: undefined;
|
|
2049
2248
|
const walletInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_REGISTRY_ABI);
|
|
2050
|
-
const
|
|
2249
|
+
const txData = {
|
|
2051
2250
|
to: config.walletContractAddress,
|
|
2052
2251
|
data: walletInterface.encodeFunctionData("executeRegistryUpdate", []),
|
|
2053
2252
|
value: "0x0",
|
|
2054
|
-
}
|
|
2253
|
+
};
|
|
2254
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2255
|
+
actionType: "custom_tx",
|
|
2256
|
+
signerMode: "owner_wallet",
|
|
2257
|
+
chainId,
|
|
2258
|
+
walletAddress: config.walletContractAddress,
|
|
2259
|
+
txs: [txData],
|
|
2260
|
+
ui: {
|
|
2261
|
+
title: "Execute registry upgrade",
|
|
2262
|
+
summary: "Approve registry upgrade execution on ARC402Wallet",
|
|
2263
|
+
risk: "high",
|
|
2264
|
+
},
|
|
2265
|
+
metadata: { sourceRuntime: "cli" },
|
|
2266
|
+
});
|
|
2267
|
+
if (execution.kind === "passkey") {
|
|
2268
|
+
let confirmedRegistry = pendingRegistry;
|
|
2269
|
+
try {
|
|
2270
|
+
confirmedRegistry = await walletContract.registry();
|
|
2271
|
+
}
|
|
2272
|
+
catch { /* use pendingRegistry as fallback */ }
|
|
2273
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(" Registry upgrade executed"));
|
|
2274
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2275
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2276
|
+
console.log(" " + colors_1.c.dim("New registry:") + " " + colors_1.c.white(confirmedRegistry));
|
|
2277
|
+
return;
|
|
2278
|
+
}
|
|
2279
|
+
const { client, session, account } = execution.session;
|
|
2280
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2055
2281
|
// Wait for tx to confirm, then read back the active registry (J6-02)
|
|
2056
2282
|
await provider.waitForTransaction(txHash);
|
|
2057
2283
|
let confirmedRegistry = pendingRegistry;
|
|
@@ -2118,18 +2344,33 @@ function registerWalletCommands(program) {
|
|
|
2118
2344
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2119
2345
|
console.log(`PolicyEngine: ${policyAddress}`);
|
|
2120
2346
|
console.log(`Whitelisting: ${checksumTarget}`);
|
|
2121
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2122
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2123
|
-
: undefined;
|
|
2124
2347
|
const policyIface = new ethers_1.ethers.Interface(peAbi);
|
|
2125
|
-
const
|
|
2348
|
+
const txData = {
|
|
2126
2349
|
to: policyAddress,
|
|
2127
2350
|
data: policyIface.encodeFunctionData("whitelistContract", [
|
|
2128
2351
|
config.walletContractAddress,
|
|
2129
2352
|
checksumTarget,
|
|
2130
2353
|
]),
|
|
2131
2354
|
value: "0x0",
|
|
2132
|
-
}
|
|
2355
|
+
};
|
|
2356
|
+
const { client, session, account } = await requestWalletConnectApprovalSession(config, {
|
|
2357
|
+
actionType: "policy_update",
|
|
2358
|
+
signerMode: "owner_wallet",
|
|
2359
|
+
chainId,
|
|
2360
|
+
walletAddress: config.walletContractAddress,
|
|
2361
|
+
txs: [txData],
|
|
2362
|
+
ui: {
|
|
2363
|
+
title: "Whitelist contract",
|
|
2364
|
+
summary: `Approve: whitelist ${checksumTarget} on PolicyEngine for your wallet`,
|
|
2365
|
+
risk: "high",
|
|
2366
|
+
},
|
|
2367
|
+
metadata: {
|
|
2368
|
+
category: "policy",
|
|
2369
|
+
sourceRuntime: "cli",
|
|
2370
|
+
hardware: !!opts.hardware,
|
|
2371
|
+
},
|
|
2372
|
+
});
|
|
2373
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2133
2374
|
await provider.waitForTransaction(txHash);
|
|
2134
2375
|
if (opts.json) {
|
|
2135
2376
|
console.log(JSON.stringify({ ok: true, txHash, wallet: config.walletContractAddress, target: checksumTarget }));
|
|
@@ -2176,14 +2417,33 @@ function registerWalletCommands(program) {
|
|
|
2176
2417
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2177
2418
|
console.log(`Current interceptor: ${currentInterceptor}`);
|
|
2178
2419
|
console.log(`New interceptor: ${checksumAddress}`);
|
|
2179
|
-
const
|
|
2180
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2181
|
-
: undefined;
|
|
2182
|
-
const { txHash } = await (0, walletconnect_1.requestPhoneWalletSignature)(config.walletConnectProjectId, chainId, () => ({
|
|
2420
|
+
const txData = {
|
|
2183
2421
|
to: config.walletContractAddress,
|
|
2184
2422
|
data: ownerInterface.encodeFunctionData("setAuthorizedInterceptor", [checksumAddress]),
|
|
2185
2423
|
value: "0x0",
|
|
2186
|
-
}
|
|
2424
|
+
};
|
|
2425
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2426
|
+
actionType: "custom_tx",
|
|
2427
|
+
signerMode: "owner_wallet",
|
|
2428
|
+
chainId,
|
|
2429
|
+
walletAddress: config.walletContractAddress,
|
|
2430
|
+
txs: [txData],
|
|
2431
|
+
ui: {
|
|
2432
|
+
title: "Set X402 interceptor",
|
|
2433
|
+
summary: `Approve: set X402 interceptor to ${checksumAddress}`,
|
|
2434
|
+
risk: "high",
|
|
2435
|
+
},
|
|
2436
|
+
metadata: { sourceRuntime: "cli" },
|
|
2437
|
+
});
|
|
2438
|
+
if (execution.kind === "passkey") {
|
|
2439
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(" X402 interceptor updated"));
|
|
2440
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2441
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2442
|
+
console.log(" " + colors_1.c.dim("Interceptor:") + " " + colors_1.c.white(checksumAddress));
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
const { client, session, account } = execution.session;
|
|
2446
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2187
2447
|
await provider.waitForTransaction(txHash);
|
|
2188
2448
|
console.log("\n" + colors_1.c.success + colors_1.c.white(" X402 interceptor updated"));
|
|
2189
2449
|
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(txHash));
|
|
@@ -2227,14 +2487,36 @@ function registerWalletCommands(program) {
|
|
|
2227
2487
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2228
2488
|
console.log(`Current limit: ${currentLimit}`);
|
|
2229
2489
|
console.log(`New limit: ${limitEth} ETH (max ETH per rolling window)`);
|
|
2230
|
-
const
|
|
2231
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2232
|
-
: undefined;
|
|
2233
|
-
const { txHash } = await (0, walletconnect_1.requestPhoneWalletSignature)(config.walletConnectProjectId, chainId, () => ({
|
|
2490
|
+
const txData = {
|
|
2234
2491
|
to: config.walletContractAddress,
|
|
2235
2492
|
data: ownerInterface.encodeFunctionData("setVelocityLimit", [limitWei]),
|
|
2236
2493
|
value: "0x0",
|
|
2237
|
-
}
|
|
2494
|
+
};
|
|
2495
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2496
|
+
actionType: "policy_update",
|
|
2497
|
+
signerMode: "owner_wallet",
|
|
2498
|
+
chainId,
|
|
2499
|
+
walletAddress: config.walletContractAddress,
|
|
2500
|
+
txs: [txData],
|
|
2501
|
+
ui: {
|
|
2502
|
+
title: "Set velocity limit",
|
|
2503
|
+
summary: `Approve: set velocity limit to ${limitEth} ETH`,
|
|
2504
|
+
risk: "high",
|
|
2505
|
+
},
|
|
2506
|
+
metadata: {
|
|
2507
|
+
category: "policy",
|
|
2508
|
+
sourceRuntime: "cli",
|
|
2509
|
+
},
|
|
2510
|
+
});
|
|
2511
|
+
if (execution.kind === "passkey") {
|
|
2512
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(" Velocity limit updated"));
|
|
2513
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2514
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2515
|
+
console.log(" " + colors_1.c.dim("New limit:") + " " + colors_1.c.white(`${limitEth} ETH per rolling window`));
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
const { client, session, account } = execution.session;
|
|
2519
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2238
2520
|
await provider.waitForTransaction(txHash);
|
|
2239
2521
|
console.log("\n" + colors_1.c.success + colors_1.c.white(" Velocity limit updated"));
|
|
2240
2522
|
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(txHash));
|
|
@@ -2242,9 +2524,8 @@ function registerWalletCommands(program) {
|
|
|
2242
2524
|
});
|
|
2243
2525
|
// ─── register-policy ───────────────────────────────────────────────────────
|
|
2244
2526
|
//
|
|
2245
|
-
// Calls registerWallet(walletAddress, ownerAddress) on PolicyEngine
|
|
2246
|
-
//
|
|
2247
|
-
// so this must go through the wallet contract — not called directly by the owner key.
|
|
2527
|
+
// Calls registerWallet(walletAddress, ownerAddress) directly on PolicyEngine
|
|
2528
|
+
// from the owner wallet.
|
|
2248
2529
|
wallet.command("register-policy")
|
|
2249
2530
|
.description("Register this wallet on PolicyEngine (required before spend limits can be set)")
|
|
2250
2531
|
.option("--hardware", "Hardware wallet mode: show raw wc: URI only")
|
|
@@ -2281,33 +2562,45 @@ function registerWalletCommands(program) {
|
|
|
2281
2562
|
}
|
|
2282
2563
|
}
|
|
2283
2564
|
}
|
|
2565
|
+
const resolvedOwnerAddress = ownerAddress;
|
|
2284
2566
|
// Encode registerWallet(wallet, owner) calldata — called on PolicyEngine
|
|
2285
2567
|
const policyInterface = new ethers_1.ethers.Interface([
|
|
2286
2568
|
"function registerWallet(address wallet, address owner) external",
|
|
2287
2569
|
]);
|
|
2288
2570
|
const registerCalldata = policyInterface.encodeFunctionData("registerWallet", [
|
|
2289
2571
|
config.walletContractAddress,
|
|
2290
|
-
|
|
2572
|
+
resolvedOwnerAddress,
|
|
2291
2573
|
]);
|
|
2292
|
-
const executeInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_EXECUTE_ABI);
|
|
2293
2574
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2294
2575
|
console.log(`PolicyEngine: ${policyAddress}`);
|
|
2295
|
-
console.log(`Owner: ${
|
|
2296
|
-
const
|
|
2297
|
-
|
|
2298
|
-
:
|
|
2299
|
-
const { txHash } = await (0, walletconnect_1.requestPhoneWalletSignature)(config.walletConnectProjectId, chainId, () => ({
|
|
2300
|
-
to: config.walletContractAddress,
|
|
2301
|
-
data: executeInterface.encodeFunctionData("executeContractCall", [{
|
|
2302
|
-
target: policyAddress,
|
|
2303
|
-
data: registerCalldata,
|
|
2304
|
-
value: 0n,
|
|
2305
|
-
minReturnValue: 0n,
|
|
2306
|
-
maxApprovalAmount: 0n,
|
|
2307
|
-
approvalToken: ethers_1.ethers.ZeroAddress,
|
|
2308
|
-
}]),
|
|
2576
|
+
console.log(`Owner: ${resolvedOwnerAddress}`);
|
|
2577
|
+
const txData = {
|
|
2578
|
+
to: policyAddress,
|
|
2579
|
+
data: registerCalldata,
|
|
2309
2580
|
value: "0x0",
|
|
2310
|
-
}
|
|
2581
|
+
};
|
|
2582
|
+
const { client, session, account } = await requestWalletConnectApprovalSession(config, {
|
|
2583
|
+
actionType: "policy_update",
|
|
2584
|
+
signerMode: "owner_wallet",
|
|
2585
|
+
chainId,
|
|
2586
|
+
walletAddress: config.walletContractAddress,
|
|
2587
|
+
txs: [txData],
|
|
2588
|
+
ui: {
|
|
2589
|
+
title: "Register wallet on PolicyEngine",
|
|
2590
|
+
summary: "Approve: register wallet on PolicyEngine",
|
|
2591
|
+
risk: "high",
|
|
2592
|
+
},
|
|
2593
|
+
metadata: {
|
|
2594
|
+
category: "policy",
|
|
2595
|
+
sourceRuntime: "cli",
|
|
2596
|
+
hardware: !!opts.hardware,
|
|
2597
|
+
},
|
|
2598
|
+
});
|
|
2599
|
+
if (account.toLowerCase() !== resolvedOwnerAddress.toLowerCase()) {
|
|
2600
|
+
console.error(`Connected wallet ${account} is not the wallet owner ${resolvedOwnerAddress}.`);
|
|
2601
|
+
process.exit(1);
|
|
2602
|
+
}
|
|
2603
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2311
2604
|
await provider.waitForTransaction(txHash);
|
|
2312
2605
|
console.log("\n" + colors_1.c.success + colors_1.c.white(" Wallet registered on PolicyEngine"));
|
|
2313
2606
|
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(txHash));
|
|
@@ -2356,15 +2649,33 @@ function registerWalletCommands(program) {
|
|
|
2356
2649
|
console.log(` Pending address: ${pendingRegistry}`);
|
|
2357
2650
|
console.log(` Timelock: ${timelockStatus}`);
|
|
2358
2651
|
console.log(`\nCancelling pending registry upgrade to: ${pendingRegistry}`);
|
|
2359
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2360
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2361
|
-
: undefined;
|
|
2362
2652
|
const walletInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_REGISTRY_ABI);
|
|
2363
|
-
const
|
|
2653
|
+
const txData = {
|
|
2364
2654
|
to: config.walletContractAddress,
|
|
2365
2655
|
data: walletInterface.encodeFunctionData("cancelRegistryUpdate", []),
|
|
2366
2656
|
value: "0x0",
|
|
2367
|
-
}
|
|
2657
|
+
};
|
|
2658
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
2659
|
+
actionType: "custom_tx",
|
|
2660
|
+
signerMode: "owner_wallet",
|
|
2661
|
+
chainId,
|
|
2662
|
+
walletAddress: config.walletContractAddress,
|
|
2663
|
+
txs: [txData],
|
|
2664
|
+
ui: {
|
|
2665
|
+
title: "Cancel registry upgrade",
|
|
2666
|
+
summary: "Approve registry upgrade cancellation on ARC402Wallet",
|
|
2667
|
+
risk: "high",
|
|
2668
|
+
},
|
|
2669
|
+
metadata: { sourceRuntime: "cli" },
|
|
2670
|
+
});
|
|
2671
|
+
if (execution.kind === "passkey") {
|
|
2672
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(" Registry upgrade cancelled"));
|
|
2673
|
+
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(execution.txHash));
|
|
2674
|
+
console.log(" " + colors_1.c.dim("UserOp:") + " " + colors_1.c.white(execution.userOpHash));
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
const { client, session, account } = execution.session;
|
|
2678
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2368
2679
|
console.log("\n" + colors_1.c.success + colors_1.c.white(" Registry upgrade cancelled"));
|
|
2369
2680
|
console.log(" " + colors_1.c.dim("Tx:") + " " + colors_1.c.white(txHash));
|
|
2370
2681
|
});
|
|
@@ -2505,11 +2816,6 @@ function registerWalletCommands(program) {
|
|
|
2505
2816
|
return;
|
|
2506
2817
|
}
|
|
2507
2818
|
// ── Step 6: connect WalletConnect once, send all transactions ─────────
|
|
2508
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2509
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2510
|
-
: undefined;
|
|
2511
|
-
console.log("\nConnecting wallet...");
|
|
2512
|
-
const { client, session, account } = await (0, walletconnect_1.connectPhoneWallet)(config.walletConnectProjectId, chainId, config, { telegramOpts, prompt: "Approve governance setup transactions on ARC402Wallet" });
|
|
2513
2819
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
2514
2820
|
const ownerInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_OWNER_ABI);
|
|
2515
2821
|
const guardianInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_GUARDIAN_ABI);
|
|
@@ -2531,6 +2837,33 @@ function registerWalletCommands(program) {
|
|
|
2531
2837
|
govAlreadyDefiEnabled = await policyGovContract.defiAccessEnabled(config.walletContractAddress);
|
|
2532
2838
|
}
|
|
2533
2839
|
catch { /* assume not enabled */ }
|
|
2840
|
+
const expectedApprovalCount = (govAlreadyRegistered ? 0 : 1) +
|
|
2841
|
+
(govAlreadyDefiEnabled ? 0 : 1) +
|
|
2842
|
+
1 +
|
|
2843
|
+
(guardianWallet ? 1 : 0) +
|
|
2844
|
+
categories.length;
|
|
2845
|
+
console.log("\nConnecting wallet...");
|
|
2846
|
+
const { client, session, account } = await requestWalletConnectApprovalSession(config, {
|
|
2847
|
+
actionType: "policy_update",
|
|
2848
|
+
signerMode: "owner_wallet",
|
|
2849
|
+
chainId,
|
|
2850
|
+
walletAddress: config.walletContractAddress,
|
|
2851
|
+
txs: Array.from({ length: expectedApprovalCount }, () => ({
|
|
2852
|
+
to: config.walletContractAddress,
|
|
2853
|
+
data: "0x",
|
|
2854
|
+
value: "0x0",
|
|
2855
|
+
})),
|
|
2856
|
+
ui: {
|
|
2857
|
+
title: "Governance setup",
|
|
2858
|
+
summary: "Approve governance setup transactions on ARC402Wallet",
|
|
2859
|
+
risk: "high",
|
|
2860
|
+
},
|
|
2861
|
+
metadata: {
|
|
2862
|
+
category: "policy",
|
|
2863
|
+
expectedApprovalCount,
|
|
2864
|
+
sourceRuntime: "cli",
|
|
2865
|
+
},
|
|
2866
|
+
});
|
|
2534
2867
|
if (!govAlreadyRegistered) {
|
|
2535
2868
|
const registerCalldata = govInterface.encodeFunctionData("registerWallet", [config.walletContractAddress, account]);
|
|
2536
2869
|
calls.push({
|
|
@@ -2665,19 +2998,37 @@ function registerWalletCommands(program) {
|
|
|
2665
2998
|
}
|
|
2666
2999
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2667
3000
|
console.log(`Machine key: ${checksumKey}`);
|
|
2668
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2669
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2670
|
-
: undefined;
|
|
2671
3001
|
const walletInterface = new ethers_1.ethers.Interface(machineKeyAbi);
|
|
2672
3002
|
const txData = {
|
|
2673
3003
|
to: config.walletContractAddress,
|
|
2674
3004
|
data: walletInterface.encodeFunctionData("authorizeMachineKey", [checksumKey]),
|
|
2675
3005
|
value: "0x0",
|
|
2676
3006
|
};
|
|
2677
|
-
const
|
|
2678
|
-
|
|
2679
|
-
|
|
3007
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
3008
|
+
actionType: "custom_tx",
|
|
3009
|
+
signerMode: "owner_wallet",
|
|
3010
|
+
chainId,
|
|
3011
|
+
walletAddress: config.walletContractAddress,
|
|
3012
|
+
txs: [txData],
|
|
3013
|
+
ui: {
|
|
3014
|
+
title: "Authorize machine key",
|
|
3015
|
+
summary: `Authorize machine key ${checksumKey} on ARC402Wallet — allows autonomous protocol ops`,
|
|
3016
|
+
risk: "high",
|
|
3017
|
+
},
|
|
3018
|
+
metadata: { sourceRuntime: "cli" },
|
|
2680
3019
|
});
|
|
3020
|
+
if (execution.kind === "passkey") {
|
|
3021
|
+
const confirmed = await walletContract.authorizedMachineKeys(checksumKey);
|
|
3022
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(` Machine key authorized: ${confirmed ? "YES" : "NO"}`));
|
|
3023
|
+
(0, tree_1.renderTree)([
|
|
3024
|
+
{ label: "Wallet", value: config.walletContractAddress ?? "" },
|
|
3025
|
+
{ label: "Machine key", value: checksumKey },
|
|
3026
|
+
{ label: "Tx", value: execution.txHash },
|
|
3027
|
+
{ label: "UserOp", value: execution.userOpHash, last: true },
|
|
3028
|
+
]);
|
|
3029
|
+
return;
|
|
3030
|
+
}
|
|
3031
|
+
const { client, session, account } = execution.session;
|
|
2681
3032
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${account}`));
|
|
2682
3033
|
console.log(colors_1.c.dim("Sending authorizeMachineKey transaction..."));
|
|
2683
3034
|
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
@@ -2738,18 +3089,40 @@ function registerWalletCommands(program) {
|
|
|
2738
3089
|
}
|
|
2739
3090
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
2740
3091
|
console.log(`Revoking: ${checksumKey}`);
|
|
2741
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
2742
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
2743
|
-
: undefined;
|
|
2744
3092
|
const walletInterface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_MACHINE_KEY_ABI);
|
|
2745
|
-
const
|
|
2746
|
-
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${account}`));
|
|
2747
|
-
console.log(colors_1.c.dim("Sending revokeMachineKey transaction..."));
|
|
2748
|
-
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, {
|
|
3093
|
+
const txData = {
|
|
2749
3094
|
to: config.walletContractAddress,
|
|
2750
3095
|
data: walletInterface.encodeFunctionData("revokeMachineKey", [checksumKey]),
|
|
2751
3096
|
value: "0x0",
|
|
3097
|
+
};
|
|
3098
|
+
const execution = await requestWalletGovernanceExecution(config, {
|
|
3099
|
+
actionType: "custom_tx",
|
|
3100
|
+
signerMode: "owner_wallet",
|
|
3101
|
+
chainId,
|
|
3102
|
+
walletAddress: config.walletContractAddress,
|
|
3103
|
+
txs: [txData],
|
|
3104
|
+
ui: {
|
|
3105
|
+
title: "Revoke machine key",
|
|
3106
|
+
summary: `Revoke machine key ${checksumKey} on ARC402Wallet`,
|
|
3107
|
+
risk: "high",
|
|
3108
|
+
},
|
|
3109
|
+
metadata: { sourceRuntime: "cli" },
|
|
2752
3110
|
});
|
|
3111
|
+
if (execution.kind === "passkey") {
|
|
3112
|
+
const stillAuthorized = await walletContract.authorizedMachineKeys(checksumKey);
|
|
3113
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(` Machine key revoked: ${stillAuthorized ? "NO (still authorized — check tx)" : "YES"}`));
|
|
3114
|
+
(0, tree_1.renderTree)([
|
|
3115
|
+
{ label: "Wallet", value: config.walletContractAddress ?? "" },
|
|
3116
|
+
{ label: "Machine key", value: checksumKey },
|
|
3117
|
+
{ label: "Tx", value: execution.txHash },
|
|
3118
|
+
{ label: "UserOp", value: execution.userOpHash, last: true },
|
|
3119
|
+
]);
|
|
3120
|
+
return;
|
|
3121
|
+
}
|
|
3122
|
+
const { client, session, account } = execution.session;
|
|
3123
|
+
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${account}`));
|
|
3124
|
+
console.log(colors_1.c.dim("Sending revokeMachineKey transaction..."));
|
|
3125
|
+
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
2753
3126
|
console.log("\n" + colors_1.c.dim("Transaction submitted:") + " " + colors_1.c.white(hash));
|
|
2754
3127
|
console.log(colors_1.c.dim("Waiting for confirmation..."));
|
|
2755
3128
|
const receipt = await provider.waitForTransaction(hash, 1, 60000);
|
|
@@ -3248,7 +3621,7 @@ function registerWalletCommands(program) {
|
|
|
3248
3621
|
console.error("walletConnectProjectId not set. Run `arc402 config set walletConnectProjectId <id>`.");
|
|
3249
3622
|
process.exit(1);
|
|
3250
3623
|
}
|
|
3251
|
-
const migrationRegistryAddress = config
|
|
3624
|
+
const migrationRegistryAddress = (0, config_1.getCanonicalNetworkAddress)(config, "migrationRegistryAddress");
|
|
3252
3625
|
let oldWallet;
|
|
3253
3626
|
let newWallet;
|
|
3254
3627
|
try {
|
|
@@ -3274,10 +3647,20 @@ function registerWalletCommands(program) {
|
|
|
3274
3647
|
"function registerMigration(address oldWallet, address newWallet) external"
|
|
3275
3648
|
]);
|
|
3276
3649
|
const callData = mrIface.encodeFunctionData("registerMigration", [oldWallet, newWallet]);
|
|
3277
|
-
const
|
|
3278
|
-
|
|
3279
|
-
:
|
|
3280
|
-
|
|
3650
|
+
const txData = { to: migrationRegistryAddress, data: callData, value: "0x0" };
|
|
3651
|
+
const { client, session, account } = await requestWalletConnectApprovalSession(config, {
|
|
3652
|
+
actionType: "custom_tx",
|
|
3653
|
+
signerMode: "owner_wallet",
|
|
3654
|
+
chainId,
|
|
3655
|
+
txs: [txData],
|
|
3656
|
+
ui: {
|
|
3657
|
+
title: "Register wallet migration",
|
|
3658
|
+
summary: `Approve: migrate wallet identity ${oldWallet.slice(0, 10)}... → ${newWallet.slice(0, 10)}...`,
|
|
3659
|
+
risk: "high",
|
|
3660
|
+
},
|
|
3661
|
+
metadata: { sourceRuntime: "cli" },
|
|
3662
|
+
});
|
|
3663
|
+
const txHash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|
|
3281
3664
|
await provider.waitForTransaction(txHash);
|
|
3282
3665
|
if (opts.json) {
|
|
3283
3666
|
console.log(JSON.stringify({ ok: true, txHash, from: oldWallet, to: newWallet }));
|
|
@@ -3501,18 +3884,29 @@ function registerWalletCommands(program) {
|
|
|
3501
3884
|
console.log(`\nWallet: ${config.walletContractAddress}`);
|
|
3502
3885
|
console.log(`pubKeyX: ${pubKeyX}`);
|
|
3503
3886
|
console.log(`pubKeyY: ${pubKeyY}`);
|
|
3504
|
-
const telegramOpts = config.telegramBotToken && config.telegramChatId
|
|
3505
|
-
? { botToken: config.telegramBotToken, chatId: config.telegramChatId, threadId: config.telegramThreadId }
|
|
3506
|
-
: undefined;
|
|
3507
3887
|
const txData = {
|
|
3508
3888
|
to: config.walletContractAddress,
|
|
3509
3889
|
data: walletInterface.encodeFunctionData("setPasskey", [pubKeyX, pubKeyY]),
|
|
3510
3890
|
value: "0x0",
|
|
3511
3891
|
};
|
|
3512
|
-
const
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3892
|
+
const approval = await (0, broker_1.requestOwnerApproval)({
|
|
3893
|
+
actionType: "custom_tx",
|
|
3894
|
+
signerMode: "owner_wallet",
|
|
3895
|
+
chainId,
|
|
3896
|
+
walletAddress: config.walletContractAddress,
|
|
3897
|
+
txs: [txData],
|
|
3898
|
+
ui: {
|
|
3899
|
+
title: "Activate passkey",
|
|
3900
|
+
summary: "Activate passkey (Face ID) on ARC402Wallet — enables P256 governance signing",
|
|
3901
|
+
risk: "high",
|
|
3902
|
+
},
|
|
3903
|
+
metadata: { sourceRuntime: "cli" },
|
|
3904
|
+
}, config);
|
|
3905
|
+
if (approval.status !== "approved" || !approval.session || approval.session.kind !== "walletconnect") {
|
|
3906
|
+
console.error(colors_1.c.failure + " " + colors_1.c.red(approval.error ?? "Approval transport failed."));
|
|
3907
|
+
process.exit(1);
|
|
3908
|
+
}
|
|
3909
|
+
const { client, session, account } = approval.session;
|
|
3516
3910
|
console.log("\n" + colors_1.c.success + colors_1.c.white(` Connected: ${account}`));
|
|
3517
3911
|
console.log(colors_1.c.dim("Sending setPasskey transaction..."));
|
|
3518
3912
|
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, txData);
|