arc402-cli 0.4.3 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/client.js.map +1 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +6 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/wallet.d.ts.map +1 -1
- package/dist/commands/wallet.js +323 -20
- package/dist/commands/wallet.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/index.js +22 -111
- package/dist/index.js.map +1 -1
- package/dist/program.d.ts +3 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +85 -0
- package/dist/program.js.map +1 -0
- package/dist/repl.d.ts +2 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +576 -0
- package/dist/repl.js.map +1 -0
- package/dist/ui/banner.d.ts +2 -0
- package/dist/ui/banner.d.ts.map +1 -1
- package/dist/ui/banner.js +27 -18
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/spinner.d.ts.map +1 -1
- package/dist/ui/spinner.js +11 -0
- package/dist/ui/spinner.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +3 -1
- package/src/commands/config.ts +6 -0
- package/src/commands/wallet.ts +372 -32
- package/src/config.ts +1 -0
- package/src/index.ts +22 -115
- package/src/program.ts +83 -0
- package/src/repl.ts +680 -0
- package/src/ui/banner.ts +26 -19
- package/src/ui/spinner.ts +10 -0
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAY3E;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC,eAAe,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAUvF"}
|
package/dist/client.js
CHANGED
|
@@ -10,7 +10,9 @@ async function getClient(config) {
|
|
|
10
10
|
const address = await signer.getAddress();
|
|
11
11
|
return { provider, signer, address };
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
// No private key — use walletContractAddress for read-only operations
|
|
14
|
+
const address = config.walletContractAddress ?? null;
|
|
15
|
+
return { provider, signer: null, address };
|
|
14
16
|
}
|
|
15
17
|
async function requireSigner(config) {
|
|
16
18
|
const { provider, signer } = await getClient(config);
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AASA,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":";;AASA,8BAYC;AAED,sCAYC;AAnCD,mCAAgC;AASzB,KAAK,UAAU,SAAS,CAAC,MAAoB;IAClD,MAAM,QAAQ,GAAG,IAAI,eAAM,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAE3D,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,eAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;QAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;IACvC,CAAC;IAED,sEAAsE;IACtE,MAAM,OAAO,GAAG,MAAM,CAAC,qBAAqB,IAAI,IAAI,CAAC;IACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAC7C,CAAC;AAEM,KAAK,UAAU,aAAa,CACjC,MAAoB;IAEpB,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;IACrD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,KAAK,CACX,gFAAgF,CACjF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmD7D"}
|
package/dist/commands/config.js
CHANGED
|
@@ -53,5 +53,11 @@ function registerConfigCommands(program) {
|
|
|
53
53
|
const cfg = (0, config_1.loadConfig)();
|
|
54
54
|
console.log(JSON.stringify({ ...cfg, privateKey: cfg.privateKey ? "***" : undefined, subdomainApi: (0, config_1.getSubdomainApi)(cfg) }, null, 2));
|
|
55
55
|
});
|
|
56
|
+
config.command("set <key> <value>").description("Set a config value: arc402 config set <key> <value>").action((key, value) => {
|
|
57
|
+
const cfg = (0, config_1.loadConfig)();
|
|
58
|
+
cfg[key] = value;
|
|
59
|
+
(0, config_1.saveConfig)(cfg);
|
|
60
|
+
console.log(' ' + colors_1.c.success + colors_1.c.white(` ${key} = ${value}`));
|
|
61
|
+
});
|
|
56
62
|
}
|
|
57
63
|
//# sourceMappingURL=config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":";;;;;AAMA,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../../src/commands/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"wallet.d.ts","sourceRoot":"","sources":["../../src/commands/wallet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgdpC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+vF7D"}
|
package/dist/commands/wallet.js
CHANGED
|
@@ -114,6 +114,294 @@ async function runWalletOnboardingCeremony(walletAddress, ownerAddress, config,
|
|
|
114
114
|
console.log(" " + colors_1.c.dim("arc402 wallet set-velocity-limit <eth> — wallet-level hourly ETH cap"));
|
|
115
115
|
console.log(" " + colors_1.c.dim("arc402 wallet policy set-daily-limit --category general --amount <eth> — daily per-category cap"));
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Complete ARC-402 onboarding ceremony — matches web flow at app.arc402.xyz/onboard.
|
|
119
|
+
* Runs in a single WalletConnect session (or any sendTx provider). Idempotent.
|
|
120
|
+
*
|
|
121
|
+
* Steps:
|
|
122
|
+
* 2. Machine key — generate + authorizeMachineKey
|
|
123
|
+
* 3. Passkey — CLI shows browser URL (WebAuthn requires browser)
|
|
124
|
+
* 4. Policy — v5 protocol bypass; set hire limit + optional guardian
|
|
125
|
+
* 5. Agent — register on AgentRegistry via executeContractCall
|
|
126
|
+
* 6. Summary — branded tree
|
|
127
|
+
*/
|
|
128
|
+
async function runCompleteOnboardingCeremony(walletAddress, ownerAddress, config, provider, sendTx) {
|
|
129
|
+
const policyAddress = config.policyEngineAddress ?? POLICY_ENGINE_DEFAULT;
|
|
130
|
+
const agentRegistryAddress = config.agentRegistryV2Address ??
|
|
131
|
+
config_1.NETWORK_DEFAULTS[config.network]?.agentRegistryV2Address;
|
|
132
|
+
const handshakeAddress = config.handshakeAddress ??
|
|
133
|
+
config_1.NETWORK_DEFAULTS[config.network]?.handshakeAddress ??
|
|
134
|
+
"0x4F5A38Bb746d7E5d49d8fd26CA6beD141Ec2DDb3";
|
|
135
|
+
// ── Step 2: Machine Key ────────────────────────────────────────────────────
|
|
136
|
+
console.log("\n" + colors_1.c.dim("── Step 2: Machine Key ────────────────────────────────────────"));
|
|
137
|
+
let machineKeyAddress;
|
|
138
|
+
if (config.privateKey) {
|
|
139
|
+
machineKeyAddress = new ethers_1.ethers.Wallet(config.privateKey).address;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const mk = ethers_1.ethers.Wallet.createRandom();
|
|
143
|
+
machineKeyAddress = mk.address;
|
|
144
|
+
config.privateKey = mk.privateKey;
|
|
145
|
+
(0, config_1.saveConfig)(config);
|
|
146
|
+
console.log(" " + colors_1.c.dim("Machine key generated: ") + colors_1.c.white(machineKeyAddress));
|
|
147
|
+
console.log(" " + colors_1.c.dim("Private key saved to ~/.arc402/config.json (chmod 600)"));
|
|
148
|
+
}
|
|
149
|
+
let mkAlreadyAuthorized = false;
|
|
150
|
+
try {
|
|
151
|
+
const mkContract = new ethers_1.ethers.Contract(walletAddress, abis_1.ARC402_WALLET_MACHINE_KEY_ABI, provider);
|
|
152
|
+
mkAlreadyAuthorized = await mkContract.authorizedMachineKeys(machineKeyAddress);
|
|
153
|
+
}
|
|
154
|
+
catch { /* older wallet — will try to authorize */ }
|
|
155
|
+
if (mkAlreadyAuthorized) {
|
|
156
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(" Machine key already authorized: ") + colors_1.c.white(machineKeyAddress));
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
console.log(" " + colors_1.c.dim("Authorizing machine key: ") + colors_1.c.white(machineKeyAddress));
|
|
160
|
+
const mkIface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_MACHINE_KEY_ABI);
|
|
161
|
+
await sendTx({ to: walletAddress, data: mkIface.encodeFunctionData("authorizeMachineKey", [machineKeyAddress]), value: "0x0" }, "authorizeMachineKey");
|
|
162
|
+
console.log(" " + colors_1.c.success + " Machine key authorized");
|
|
163
|
+
}
|
|
164
|
+
// ── Step 3: Passkey ───────────────────────────────────────────────────────
|
|
165
|
+
console.log("\n" + colors_1.c.dim("── Step 3: Passkey (Face ID / WebAuthn) ──────────────────────"));
|
|
166
|
+
let passkeyActive = false;
|
|
167
|
+
try {
|
|
168
|
+
const walletC = new ethers_1.ethers.Contract(walletAddress, abis_1.ARC402_WALLET_PASSKEY_ABI, provider);
|
|
169
|
+
const auth = await walletC.ownerAuth();
|
|
170
|
+
passkeyActive = Number(auth[0]) === 1;
|
|
171
|
+
}
|
|
172
|
+
catch { /* ignore */ }
|
|
173
|
+
if (passkeyActive) {
|
|
174
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(" Passkey already active"));
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const passkeyUrl = `https://app.arc402.xyz/passkey-setup?wallet=${walletAddress}`;
|
|
178
|
+
console.log("\n " + colors_1.c.white("Open this URL in your browser to set up Face ID:"));
|
|
179
|
+
console.log(" " + colors_1.c.cyan(passkeyUrl));
|
|
180
|
+
console.log(" " + colors_1.c.dim("Complete Face ID registration, then press Enter. Type 'n' + Enter to skip.\n"));
|
|
181
|
+
const passkeyAns = await (0, prompts_1.default)({
|
|
182
|
+
type: "text",
|
|
183
|
+
name: "done",
|
|
184
|
+
message: "Press Enter when done (or type 'n' to skip)",
|
|
185
|
+
initial: "",
|
|
186
|
+
});
|
|
187
|
+
if (passkeyAns.done?.toLowerCase() === "n") {
|
|
188
|
+
console.log(" " + colors_1.c.warning + " Passkey skipped");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
passkeyActive = true;
|
|
192
|
+
console.log(" " + colors_1.c.success + " Passkey set (via browser)");
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// ── Step 4: Policy ────────────────────────────────────────────────────────
|
|
196
|
+
console.log("\n" + colors_1.c.dim("── Step 4: Policy ─────────────────────────────────────────────"));
|
|
197
|
+
// 4a) setVelocityLimit
|
|
198
|
+
let velocityLimitEth = "0.05";
|
|
199
|
+
let velocityAlreadySet = false;
|
|
200
|
+
try {
|
|
201
|
+
const ownerC = new ethers_1.ethers.Contract(walletAddress, abis_1.ARC402_WALLET_OWNER_ABI, provider);
|
|
202
|
+
const existing = await ownerC.velocityLimit();
|
|
203
|
+
if (existing > 0n) {
|
|
204
|
+
velocityAlreadySet = true;
|
|
205
|
+
velocityLimitEth = ethers_1.ethers.formatEther(existing);
|
|
206
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(` Velocity limit already set: ${velocityLimitEth} ETH`));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
catch { /* ignore */ }
|
|
210
|
+
if (!velocityAlreadySet) {
|
|
211
|
+
const velAns = await (0, prompts_1.default)({
|
|
212
|
+
type: "text",
|
|
213
|
+
name: "limit",
|
|
214
|
+
message: "Velocity limit (ETH / rolling window)?",
|
|
215
|
+
initial: "0.05",
|
|
216
|
+
});
|
|
217
|
+
velocityLimitEth = velAns.limit || "0.05";
|
|
218
|
+
const velIface = new ethers_1.ethers.Interface(["function setVelocityLimit(uint256 limit) external"]);
|
|
219
|
+
await sendTx({ to: walletAddress, data: velIface.encodeFunctionData("setVelocityLimit", [ethers_1.ethers.parseEther(velocityLimitEth)]), value: "0x0" }, `setVelocityLimit: ${velocityLimitEth} ETH`);
|
|
220
|
+
(0, config_1.saveConfig)(config);
|
|
221
|
+
}
|
|
222
|
+
// 4b) setGuardian (optional — address, 'g' to generate, or skip)
|
|
223
|
+
let guardianAddress = null;
|
|
224
|
+
try {
|
|
225
|
+
const guardianC = new ethers_1.ethers.Contract(walletAddress, abis_1.ARC402_WALLET_GUARDIAN_ABI, provider);
|
|
226
|
+
const existing = await guardianC.guardian();
|
|
227
|
+
if (existing && existing !== ethers_1.ethers.ZeroAddress) {
|
|
228
|
+
guardianAddress = existing;
|
|
229
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(` Guardian already set: ${existing}`));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
catch { /* ignore */ }
|
|
233
|
+
if (!guardianAddress) {
|
|
234
|
+
const guardianAns = await (0, prompts_1.default)({
|
|
235
|
+
type: "text",
|
|
236
|
+
name: "guardian",
|
|
237
|
+
message: "Guardian address? (address, 'g' to generate, Enter to skip)",
|
|
238
|
+
initial: "",
|
|
239
|
+
});
|
|
240
|
+
const guardianInput = guardianAns.guardian?.trim() ?? "";
|
|
241
|
+
if (guardianInput.toLowerCase() === "g") {
|
|
242
|
+
const generatedGuardian = ethers_1.ethers.Wallet.createRandom();
|
|
243
|
+
config.guardianPrivateKey = generatedGuardian.privateKey;
|
|
244
|
+
config.guardianAddress = generatedGuardian.address;
|
|
245
|
+
(0, config_1.saveConfig)(config);
|
|
246
|
+
guardianAddress = generatedGuardian.address;
|
|
247
|
+
console.log("\n " + colors_1.c.warning + " IMPORTANT: Save this guardian private key (emergency freeze key):");
|
|
248
|
+
console.log(" " + colors_1.c.dim(generatedGuardian.privateKey));
|
|
249
|
+
console.log(" " + colors_1.c.dim("Address: ") + colors_1.c.white(generatedGuardian.address) + "\n");
|
|
250
|
+
const guardianIface = new ethers_1.ethers.Interface(["function setGuardian(address _guardian) external"]);
|
|
251
|
+
await sendTx({ to: walletAddress, data: guardianIface.encodeFunctionData("setGuardian", [guardianAddress]), value: "0x0" }, "setGuardian");
|
|
252
|
+
(0, config_1.saveConfig)(config);
|
|
253
|
+
}
|
|
254
|
+
else if (guardianInput && ethers_1.ethers.isAddress(guardianInput)) {
|
|
255
|
+
guardianAddress = guardianInput;
|
|
256
|
+
config.guardianAddress = guardianInput;
|
|
257
|
+
const guardianIface = new ethers_1.ethers.Interface(["function setGuardian(address _guardian) external"]);
|
|
258
|
+
await sendTx({ to: walletAddress, data: guardianIface.encodeFunctionData("setGuardian", [guardianAddress]), value: "0x0" }, "setGuardian");
|
|
259
|
+
(0, config_1.saveConfig)(config);
|
|
260
|
+
}
|
|
261
|
+
else if (guardianInput) {
|
|
262
|
+
console.log(" " + colors_1.c.warning + " Invalid address — guardian skipped");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
// 4c) setCategoryLimitFor('hire')
|
|
266
|
+
let hireLimit = "0.1";
|
|
267
|
+
let hireLimitAlreadySet = false;
|
|
268
|
+
try {
|
|
269
|
+
const limitsContract = new ethers_1.ethers.Contract(policyAddress, abis_1.POLICY_ENGINE_LIMITS_ABI, provider);
|
|
270
|
+
const existing = await limitsContract.categoryLimits(walletAddress, "hire");
|
|
271
|
+
if (existing > 0n) {
|
|
272
|
+
hireLimitAlreadySet = true;
|
|
273
|
+
hireLimit = ethers_1.ethers.formatEther(existing);
|
|
274
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(` Hire limit already set: ${hireLimit} ETH`));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch { /* ignore */ }
|
|
278
|
+
if (!hireLimitAlreadySet) {
|
|
279
|
+
const limitAns = await (0, prompts_1.default)({
|
|
280
|
+
type: "text",
|
|
281
|
+
name: "limit",
|
|
282
|
+
message: "Max price per hire (ETH)?",
|
|
283
|
+
initial: "0.1",
|
|
284
|
+
});
|
|
285
|
+
hireLimit = limitAns.limit || "0.1";
|
|
286
|
+
const hireLimitWei = ethers_1.ethers.parseEther(hireLimit);
|
|
287
|
+
const policyIface = new ethers_1.ethers.Interface([
|
|
288
|
+
"function setCategoryLimitFor(address wallet, string category, uint256 limitPerTx) external",
|
|
289
|
+
]);
|
|
290
|
+
await sendTx({ to: policyAddress, data: policyIface.encodeFunctionData("setCategoryLimitFor", [walletAddress, "hire", hireLimitWei]), value: "0x0" }, `setCategoryLimitFor: hire → ${hireLimit} ETH`);
|
|
291
|
+
(0, config_1.saveConfig)(config);
|
|
292
|
+
}
|
|
293
|
+
// 4d) enableContractInteraction(wallet, Handshake)
|
|
294
|
+
const contractInteractionIface = new ethers_1.ethers.Interface([
|
|
295
|
+
"function enableContractInteraction(address wallet, address target) external",
|
|
296
|
+
]);
|
|
297
|
+
await sendTx({ to: policyAddress, data: contractInteractionIface.encodeFunctionData("enableContractInteraction", [walletAddress, handshakeAddress]), value: "0x0" }, "enableContractInteraction: Handshake");
|
|
298
|
+
(0, config_1.saveConfig)(config);
|
|
299
|
+
console.log(" " + colors_1.c.success + " Policy configured");
|
|
300
|
+
// ── Step 5: Agent Registration ─────────────────────────────────────────────
|
|
301
|
+
console.log("\n" + colors_1.c.dim("── Step 5: Agent Registration ─────────────────────────────────"));
|
|
302
|
+
let agentAlreadyRegistered = false;
|
|
303
|
+
let agentName = "";
|
|
304
|
+
let agentServiceType = "";
|
|
305
|
+
let agentEndpoint = "";
|
|
306
|
+
if (agentRegistryAddress) {
|
|
307
|
+
try {
|
|
308
|
+
const regContract = new ethers_1.ethers.Contract(agentRegistryAddress, abis_1.AGENT_REGISTRY_ABI, provider);
|
|
309
|
+
agentAlreadyRegistered = await regContract.isRegistered(walletAddress);
|
|
310
|
+
if (agentAlreadyRegistered) {
|
|
311
|
+
const info = await regContract.getAgent(walletAddress);
|
|
312
|
+
agentName = info.name;
|
|
313
|
+
agentServiceType = info.serviceType;
|
|
314
|
+
agentEndpoint = info.endpoint;
|
|
315
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(` Agent already registered: ${agentName}`));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch { /* ignore */ }
|
|
319
|
+
if (!agentAlreadyRegistered) {
|
|
320
|
+
const rawHostname = os_1.default.hostname();
|
|
321
|
+
const cleanHostname = rawHostname.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
322
|
+
const answers = await (0, prompts_1.default)([
|
|
323
|
+
{ type: "text", name: "name", message: "Agent name?", initial: cleanHostname },
|
|
324
|
+
{ type: "text", name: "serviceType", message: "Service type?", initial: "intelligence" },
|
|
325
|
+
{ type: "text", name: "caps", message: "Capabilities? (comma-separated)", initial: "research" },
|
|
326
|
+
{ type: "text", name: "endpoint", message: "Endpoint?", initial: `https://${cleanHostname}.arc402.xyz` },
|
|
327
|
+
]);
|
|
328
|
+
agentName = answers.name || cleanHostname;
|
|
329
|
+
agentServiceType = answers.serviceType || "intelligence";
|
|
330
|
+
agentEndpoint = answers.endpoint || `https://${cleanHostname}.arc402.xyz`;
|
|
331
|
+
const capabilities = (answers.caps || "research")
|
|
332
|
+
.split(",").map((s) => s.trim()).filter(Boolean);
|
|
333
|
+
// 5a) enableDefiAccess (check first)
|
|
334
|
+
const peExtIface = new ethers_1.ethers.Interface([
|
|
335
|
+
"function enableDefiAccess(address wallet) external",
|
|
336
|
+
"function whitelistContract(address wallet, address target) external",
|
|
337
|
+
"function defiAccessEnabled(address) external view returns (bool)",
|
|
338
|
+
"function isContractWhitelisted(address wallet, address target) external view returns (bool)",
|
|
339
|
+
]);
|
|
340
|
+
const peContract = new ethers_1.ethers.Contract(policyAddress, peExtIface, provider);
|
|
341
|
+
const defiEnabled = await peContract.defiAccessEnabled(walletAddress).catch(() => false);
|
|
342
|
+
if (!defiEnabled) {
|
|
343
|
+
await sendTx({ to: policyAddress, data: peExtIface.encodeFunctionData("enableDefiAccess", [walletAddress]), value: "0x0" }, "enableDefiAccess on PolicyEngine");
|
|
344
|
+
(0, config_1.saveConfig)(config);
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(" enableDefiAccess — already done"));
|
|
348
|
+
}
|
|
349
|
+
// 5b) whitelistContract for AgentRegistry (check first)
|
|
350
|
+
const whitelisted = await peContract.isContractWhitelisted(walletAddress, agentRegistryAddress).catch(() => false);
|
|
351
|
+
if (!whitelisted) {
|
|
352
|
+
await sendTx({ to: policyAddress, data: peExtIface.encodeFunctionData("whitelistContract", [walletAddress, agentRegistryAddress]), value: "0x0" }, "whitelistContract: AgentRegistry on PolicyEngine");
|
|
353
|
+
(0, config_1.saveConfig)(config);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
console.log(" " + colors_1.c.success + colors_1.c.dim(" whitelistContract(AgentRegistry) — already done"));
|
|
357
|
+
}
|
|
358
|
+
// 5c+d) executeContractCall → register
|
|
359
|
+
const regIface = new ethers_1.ethers.Interface(abis_1.AGENT_REGISTRY_ABI);
|
|
360
|
+
const execIface = new ethers_1.ethers.Interface(abis_1.ARC402_WALLET_EXECUTE_ABI);
|
|
361
|
+
const regData = regIface.encodeFunctionData("register", [agentName, capabilities, agentServiceType, agentEndpoint, ""]);
|
|
362
|
+
const execData = execIface.encodeFunctionData("executeContractCall", [{
|
|
363
|
+
target: agentRegistryAddress,
|
|
364
|
+
data: regData,
|
|
365
|
+
value: 0n,
|
|
366
|
+
minReturnValue: 0n,
|
|
367
|
+
maxApprovalAmount: 0n,
|
|
368
|
+
approvalToken: ethers_1.ethers.ZeroAddress,
|
|
369
|
+
}]);
|
|
370
|
+
await sendTx({ to: walletAddress, data: execData, value: "0x0" }, `register agent: ${agentName}`);
|
|
371
|
+
console.log(" " + colors_1.c.success + " Agent registered: " + agentName);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
console.log(" " + colors_1.c.warning + " AgentRegistry address not configured — skipping");
|
|
376
|
+
}
|
|
377
|
+
// ── Step 6: Summary ───────────────────────────────────────────────────────
|
|
378
|
+
const trustScore = await (async () => {
|
|
379
|
+
try {
|
|
380
|
+
const trust = new ethers_1.ethers.Contract(config.trustRegistryAddress, abis_1.TRUST_REGISTRY_ABI, provider);
|
|
381
|
+
const s = await trust.getScore(walletAddress);
|
|
382
|
+
return s.toString();
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return "100";
|
|
386
|
+
}
|
|
387
|
+
})();
|
|
388
|
+
console.log("\n " + colors_1.c.success + colors_1.c.white(" Onboarding complete"));
|
|
389
|
+
(0, tree_1.renderTree)([
|
|
390
|
+
{ label: "Wallet", value: colors_1.c.white(walletAddress) },
|
|
391
|
+
{ label: "Owner", value: colors_1.c.white(ownerAddress) },
|
|
392
|
+
{ label: "Machine", value: colors_1.c.white(machineKeyAddress) + colors_1.c.dim(" (authorized)") },
|
|
393
|
+
{ label: "Passkey", value: passkeyActive ? colors_1.c.green("✓ set") : colors_1.c.yellow("⚠ skipped") },
|
|
394
|
+
{ label: "Velocity", value: colors_1.c.white(velocityLimitEth + " ETH") },
|
|
395
|
+
{ label: "Guardian", value: guardianAddress ? colors_1.c.white(guardianAddress) : colors_1.c.dim("none") },
|
|
396
|
+
{ label: "Hire limit", value: colors_1.c.white(hireLimit + " ETH") },
|
|
397
|
+
{ label: "Agent", value: agentName ? colors_1.c.white(agentName) : colors_1.c.dim("not registered") },
|
|
398
|
+
{ label: "Service", value: agentServiceType ? colors_1.c.white(agentServiceType) : colors_1.c.dim("—") },
|
|
399
|
+
{ label: "Endpoint", value: agentEndpoint ? colors_1.c.white(agentEndpoint) : colors_1.c.dim("—") },
|
|
400
|
+
{ label: "Trust", value: colors_1.c.white(`${trustScore}`), last: true },
|
|
401
|
+
]);
|
|
402
|
+
console.log("\n " + colors_1.c.dim("Next: fund your wallet with 0.002 ETH on Base"));
|
|
403
|
+
console.log(" " + colors_1.c.dim(" arc402 daemon start"));
|
|
404
|
+
}
|
|
117
405
|
function printOpenShellHint() {
|
|
118
406
|
const r = (0, child_process_1.spawnSync)("which", ["openshell"], { encoding: "utf-8" });
|
|
119
407
|
if (r.status === 0 && r.stdout.trim()) {
|
|
@@ -604,30 +892,29 @@ function registerWalletCommands(program) {
|
|
|
604
892
|
console.error("Could not find WalletCreated event in receipt. Check the transaction on-chain.");
|
|
605
893
|
process.exit(1);
|
|
606
894
|
}
|
|
895
|
+
// ── Step 1 complete: save wallet + owner immediately ─────────────────
|
|
607
896
|
config.walletContractAddress = walletAddress;
|
|
608
897
|
config.ownerAddress = account;
|
|
609
898
|
(0, config_1.saveConfig)(config);
|
|
610
|
-
|
|
899
|
+
try {
|
|
900
|
+
fs_1.default.chmodSync((0, config_1.getConfigPath)(), 0o600);
|
|
901
|
+
}
|
|
902
|
+
catch { /* best-effort */ }
|
|
903
|
+
console.log("\n " + colors_1.c.success + colors_1.c.white(" Wallet deployed"));
|
|
611
904
|
(0, tree_1.renderTree)([
|
|
612
905
|
{ label: "Wallet", value: walletAddress },
|
|
613
|
-
{ label: "Owner", value: account
|
|
906
|
+
{ label: "Owner", value: account, last: true },
|
|
614
907
|
]);
|
|
615
|
-
// ──
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
console.log(" " + colors_1.c.dim(`Sending: ${description}`));
|
|
908
|
+
// ── Steps 2–6: Complete onboarding ceremony (same WalletConnect session)
|
|
909
|
+
const sendTxCeremony = async (call, description) => {
|
|
910
|
+
console.log(" " + colors_1.c.dim(`◈ ${description}`));
|
|
619
911
|
const hash = await (0, walletconnect_1.sendTransactionWithSession)(client, session, account, chainId, call);
|
|
912
|
+
console.log(" " + colors_1.c.dim(" waiting for confirmation..."));
|
|
620
913
|
await provider.waitForTransaction(hash, 1);
|
|
621
|
-
console.log(" " + colors_1.c.success + " " + colors_1.c.
|
|
914
|
+
console.log(" " + colors_1.c.success + " " + colors_1.c.white(description));
|
|
622
915
|
return hash;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
const paymasterUrl2 = config.paymasterUrl ?? config_1.NETWORK_DEFAULTS[config.network]?.paymasterUrl;
|
|
626
|
-
const deployedBalance = await provider.getBalance(walletAddress);
|
|
627
|
-
if (paymasterUrl2 && deployedBalance < BigInt(1000000000000000)) {
|
|
628
|
-
console.log(colors_1.c.dim("Gas sponsorship active — initial setup ops are free"));
|
|
629
|
-
}
|
|
630
|
-
console.log(colors_1.c.dim("\nNext: run 'arc402 wallet set-guardian' to configure the emergency guardian key."));
|
|
916
|
+
};
|
|
917
|
+
await runCompleteOnboardingCeremony(walletAddress, account, config, provider, sendTxCeremony);
|
|
631
918
|
printOpenShellHint();
|
|
632
919
|
}
|
|
633
920
|
else {
|
|
@@ -657,6 +944,7 @@ function registerWalletCommands(program) {
|
|
|
657
944
|
// Generate guardian key (separate from hot key) and call setGuardian
|
|
658
945
|
const guardianWallet = ethers_1.ethers.Wallet.createRandom();
|
|
659
946
|
config.walletContractAddress = walletAddress;
|
|
947
|
+
config.ownerAddress = address;
|
|
660
948
|
config.guardianPrivateKey = guardianWallet.privateKey;
|
|
661
949
|
config.guardianAddress = guardianWallet.address;
|
|
662
950
|
(0, config_1.saveConfig)(config);
|
|
@@ -1367,14 +1655,29 @@ function registerWalletCommands(program) {
|
|
|
1367
1655
|
console.error("walletConnectProjectId not set in config. Run `arc402 config set walletConnectProjectId <id>`.");
|
|
1368
1656
|
process.exit(1);
|
|
1369
1657
|
}
|
|
1370
|
-
const ownerAddress = config.ownerAddress;
|
|
1371
|
-
if (!ownerAddress) {
|
|
1372
|
-
console.error("ownerAddress not set in config. Run `arc402 wallet deploy` first.");
|
|
1373
|
-
process.exit(1);
|
|
1374
|
-
}
|
|
1375
1658
|
const policyAddress = config.policyEngineAddress ?? POLICY_ENGINE_DEFAULT;
|
|
1376
1659
|
const chainId = config.network === "base-mainnet" ? 8453 : 84532;
|
|
1377
1660
|
const provider = new ethers_1.ethers.JsonRpcProvider(config.rpcUrl);
|
|
1661
|
+
let ownerAddress = config.ownerAddress;
|
|
1662
|
+
if (!ownerAddress) {
|
|
1663
|
+
// Fallback 1: WalletConnect session account
|
|
1664
|
+
if (config.wcSession?.account) {
|
|
1665
|
+
ownerAddress = config.wcSession.account;
|
|
1666
|
+
console.log(colors_1.c.dim(`Owner resolved from WalletConnect session: ${ownerAddress}`));
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
// Fallback 2: call owner() on the wallet contract
|
|
1670
|
+
try {
|
|
1671
|
+
const walletOwnerContract = new ethers_1.ethers.Contract(config.walletContractAddress, ["function owner() external view returns (address)"], provider);
|
|
1672
|
+
ownerAddress = await walletOwnerContract.owner();
|
|
1673
|
+
console.log(colors_1.c.dim(`Owner resolved from contract: ${ownerAddress}`));
|
|
1674
|
+
}
|
|
1675
|
+
catch {
|
|
1676
|
+
console.error("ownerAddress not set in config and could not be resolved from contract or WalletConnect session.");
|
|
1677
|
+
process.exit(1);
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1378
1681
|
// Encode registerWallet(wallet, owner) calldata — called on PolicyEngine
|
|
1379
1682
|
const policyInterface = new ethers_1.ethers.Interface([
|
|
1380
1683
|
"function registerWallet(address wallet, address owner) external",
|