@aura-protocol/cli 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +84 -53
  2. package/bin/aura.js +0 -0
  3. package/dist/commands/confidential.d.ts +1 -1
  4. package/dist/commands/confidential.js +280 -325
  5. package/dist/commands/confidential.js.map +1 -1
  6. package/dist/commands/config.d.ts +1 -1
  7. package/dist/commands/config.js +26 -8
  8. package/dist/commands/config.js.map +1 -1
  9. package/dist/commands/dashboard.d.ts +1 -1
  10. package/dist/commands/dashboard.js +6 -7
  11. package/dist/commands/dashboard.js.map +1 -1
  12. package/dist/commands/dwallet.d.ts +1 -1
  13. package/dist/commands/dwallet.js +52 -41
  14. package/dist/commands/dwallet.js.map +1 -1
  15. package/dist/commands/execution.d.ts +1 -1
  16. package/dist/commands/execution.js +111 -175
  17. package/dist/commands/execution.js.map +1 -1
  18. package/dist/commands/features.d.ts +1 -1
  19. package/dist/commands/features.js +15 -10
  20. package/dist/commands/features.js.map +1 -1
  21. package/dist/commands/generated.d.ts +20 -0
  22. package/dist/commands/generated.js +61 -0
  23. package/dist/commands/generated.js.map +1 -0
  24. package/dist/commands/governance.d.ts +1 -1
  25. package/dist/commands/governance.js +113 -99
  26. package/dist/commands/governance.js.map +1 -1
  27. package/dist/commands/helpers.d.ts +5 -2
  28. package/dist/commands/helpers.js +79 -16
  29. package/dist/commands/helpers.js.map +1 -1
  30. package/dist/commands/instruction-exec.d.ts +27 -0
  31. package/dist/commands/instruction-exec.js +171 -0
  32. package/dist/commands/instruction-exec.js.map +1 -0
  33. package/dist/commands/instruction.d.ts +9 -0
  34. package/dist/commands/instruction.js +81 -0
  35. package/dist/commands/instruction.js.map +1 -0
  36. package/dist/commands/pda.d.ts +1 -1
  37. package/dist/commands/pda.js +15 -7
  38. package/dist/commands/pda.js.map +1 -1
  39. package/dist/commands/treasury.d.ts +1 -1
  40. package/dist/commands/treasury.js +201 -186
  41. package/dist/commands/treasury.js.map +1 -1
  42. package/dist/core/config.d.ts +35 -0
  43. package/dist/core/config.js +97 -0
  44. package/dist/core/config.js.map +1 -0
  45. package/dist/core/context.d.ts +51 -0
  46. package/dist/core/context.js +60 -0
  47. package/dist/core/context.js.map +1 -0
  48. package/dist/core/errors.d.ts +38 -0
  49. package/dist/core/errors.js +138 -0
  50. package/dist/core/errors.js.map +1 -0
  51. package/dist/core/network.d.ts +18 -0
  52. package/dist/core/network.js +38 -0
  53. package/dist/core/network.js.map +1 -0
  54. package/dist/core/runner.d.ts +45 -0
  55. package/dist/core/runner.js +219 -0
  56. package/dist/core/runner.js.map +1 -0
  57. package/dist/core/security.d.ts +28 -0
  58. package/dist/core/security.js +83 -0
  59. package/dist/core/security.js.map +1 -0
  60. package/dist/core/wallet.d.ts +2 -0
  61. package/dist/core/wallet.js +21 -0
  62. package/dist/core/wallet.js.map +1 -0
  63. package/dist/index.js +56 -13
  64. package/dist/index.js.map +1 -1
  65. package/dist/lib/domain.d.ts +16 -0
  66. package/dist/lib/domain.js +88 -0
  67. package/dist/lib/domain.js.map +1 -0
  68. package/dist/lib/ika.d.ts +81 -0
  69. package/dist/lib/ika.js +192 -0
  70. package/dist/lib/ika.js.map +1 -0
  71. package/dist/lib/instructions.d.ts +79 -0
  72. package/dist/lib/instructions.js +421 -0
  73. package/dist/lib/instructions.js.map +1 -0
  74. package/dist/lib/protocol.d.ts +99 -0
  75. package/dist/lib/protocol.js +327 -0
  76. package/dist/lib/protocol.js.map +1 -0
  77. package/dist/lib/treasury-view.d.ts +11 -0
  78. package/dist/lib/treasury-view.js +126 -0
  79. package/dist/lib/treasury-view.js.map +1 -0
  80. package/dist/program-instructions.d.ts +1 -1
  81. package/dist/ui/dashboard.d.ts +7 -0
  82. package/dist/ui/dashboard.js +99 -0
  83. package/dist/ui/dashboard.js.map +1 -0
  84. package/dist/ui/format.d.ts +9 -0
  85. package/dist/ui/format.js +92 -0
  86. package/dist/ui/format.js.map +1 -0
  87. package/dist/ui/output.d.ts +58 -0
  88. package/dist/ui/output.js +208 -0
  89. package/dist/ui/output.js.map +1 -0
  90. package/dist/ui/theme.d.ts +52 -0
  91. package/dist/ui/theme.js +110 -0
  92. package/dist/ui/theme.js.map +1 -0
  93. package/dist/vendor/encrypt/generated/grpc/encrypt_service.d.ts +1 -1
  94. package/dist/vendor/encrypt/generated/grpc/encrypt_service.js +36 -13
  95. package/dist/vendor/encrypt/generated/grpc/encrypt_service.js.map +1 -1
  96. package/dist/vendor/encrypt/grpc.d.ts +2 -2
  97. package/dist/vendor/encrypt/grpc.js +1 -3
  98. package/dist/vendor/encrypt/grpc.js.map +1 -1
  99. package/dist/vendor/ika/bcs-types.js +107 -50
  100. package/dist/vendor/ika/bcs-types.js.map +1 -1
  101. package/dist/vendor/ika/generated/grpc/ika_dwallet.d.ts +1 -1
  102. package/dist/vendor/ika/generated/grpc/ika_dwallet.js +14 -4
  103. package/dist/vendor/ika/generated/grpc/ika_dwallet.js.map +1 -1
  104. package/dist/vendor/ika/grpc.d.ts +1 -1
  105. package/dist/vendor/ika/grpc.js +49 -24
  106. package/dist/vendor/ika/grpc.js.map +1 -1
  107. package/package.json +15 -12
  108. package/dist/ascii.d.ts +0 -1
  109. package/dist/ascii.js +0 -2
  110. package/dist/ascii.js.map +0 -1
@@ -1,77 +1,69 @@
1
+ import { accounts, instructions } from "@aura-protocol/sdk-ts";
1
2
  import { PublicKey, SystemProgram } from "@solana/web3.js";
2
- import {} from "commander";
3
- import { buildCliContext } from "../context.js";
4
- import { printBanner, printSuccess, emitJson, serializeInstruction, startSpinner } from "../output.js";
5
- import { buildDryRunKeypair, deriveEncryptAccounts, ensureEncryptDeposit, getActivePendingProposal, markInstructionSigner, resolvePendingPolicyOutput, resolvePendingRequestAccount, resolveScalarGuardrails, sendInstructionsWithBudget, waitForCiphertextVerified, waitForDecryptionReady, } from "../protocol.js";
6
- import { encryptU64, encryptU64Batch, readU64Ciphertext, } from "../ika.js";
7
- import { renderTreasurySections } from "../treasury-view.js";
8
- import { loadKeypair } from "../wallet.js";
3
+ import BN from "bn.js";
4
+ import { buildCliContext } from "../core/context.js";
5
+ import { CliError } from "../core/errors.js";
6
+ import { runInstructions } from "../core/runner.js";
7
+ import { loadKeypair } from "../core/wallet.js";
8
+ import { encryptU64, encryptU64Batch, readU64Ciphertext } from "../lib/ika.js";
9
+ import { buildDryRunKeypair, deriveEncryptAccounts, ensureEncryptDeposit, getActivePendingProposal, markInstructionSigner, resolvePendingPolicyOutput, resolvePendingRequestAccount, resolveScalarGuardrails, waitForCiphertextVerified, waitForDecryptionReady, } from "../lib/protocol.js";
10
+ import { renderTreasurySections } from "../lib/treasury-view.js";
11
+ import { emitJson, printBanner, printInfo, printNote, printSuccess, startSpinner, } from "../ui/output.js";
12
+ import { style } from "../ui/theme.js";
9
13
  import { buildProposeConfidentialArgs, promptChain, promptNumber, promptString, promptTransactionType, resolveTreasuryAccount, } from "./helpers.js";
14
+ function requireWallet(ctx) {
15
+ if (!ctx.wallet) {
16
+ throw new CliError("A wallet is required for this command.", {
17
+ code: "WALLET_REQUIRED",
18
+ tip: "Run `aura config init` or pass --wallet <path>.",
19
+ });
20
+ }
21
+ return ctx.wallet;
22
+ }
10
23
  function parsePublicKey(value, label) {
11
24
  try {
12
25
  return new PublicKey(value);
13
26
  }
14
27
  catch {
15
- throw new Error(`${label} must be a valid base58 pubkey`);
16
- }
17
- }
18
- function normalizeDigestHex(value, label) {
19
- if (!value) {
20
- return null;
21
- }
22
- if (!/^[0-9a-fA-F]{64}$/.test(value)) {
23
- throw new Error(`${label} must be a 32-byte hex digest`);
24
- }
25
- return value.toLowerCase();
26
- }
27
- function normalizePublicKeyHex(value) {
28
- if (!value) {
29
- return null;
28
+ throw CliError.invalidInput(label, "base58 public key");
30
29
  }
31
- if (!/^[0-9a-fA-F]+$/.test(value) || value.length % 2 !== 0) {
32
- throw new Error("publicKeyHex must contain valid hex bytes");
33
- }
34
- return value.toLowerCase();
35
30
  }
36
- async function sendPreparedInstruction(options) {
37
- const { ctx, instruction, extraSigners = [] } = options;
38
- if (!ctx.wallet) {
39
- throw new Error("A wallet is required for this command.");
40
- }
41
- return await sendInstructionsWithBudget({
42
- connection: ctx.connection,
43
- payer: ctx.wallet,
44
- instructions: [instruction],
45
- extraSigners,
46
- });
31
+ function nowBn() {
32
+ return new BN(Math.floor(Date.now() / 1000));
47
33
  }
48
34
  export function registerConfidentialCommands(program) {
49
35
  const confidential = program
50
36
  .command("confidential")
51
- .description("Manage confidential guardrails and policy decryption");
52
- const deposit = confidential.command("deposit").description("Manage Encrypt deposit accounts");
37
+ .description("Manage confidential guardrails and the policy decryption flow");
38
+ // --- deposit ---------------------------------------------------------
39
+ const deposit = confidential
40
+ .command("deposit")
41
+ .description("Manage Encrypt deposit accounts");
53
42
  deposit
54
43
  .command("ensure")
55
44
  .description("Ensure the configured wallet has an Encrypt deposit account")
56
45
  .action(async function confidentialDepositEnsure() {
57
46
  const ctx = buildCliContext(this);
58
- if (!ctx.wallet) {
59
- throw new Error("A wallet is required to manage Encrypt deposit accounts.");
60
- }
61
- const dryRunAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
47
+ const wallet = requireWallet(ctx);
48
+ const derived = deriveEncryptAccounts(wallet.publicKey, {
62
49
  auraProgramId: ctx.programId,
63
50
  });
64
51
  if (ctx.dryRun) {
65
- emitJson(ctx.output, {
66
- action: "confidential.deposit.ensure",
67
- accounts: dryRunAccounts,
68
- });
52
+ if (ctx.output.json) {
53
+ emitJson(ctx.output, {
54
+ action: "confidential.deposit.ensure",
55
+ accounts: derived,
56
+ });
57
+ }
58
+ else {
59
+ printNote(ctx.output, `Dry run: would ensure Encrypt deposit ${derived.deposit.toBase58()}`);
60
+ }
69
61
  return;
70
62
  }
71
63
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
72
64
  const result = await ensureEncryptDeposit({
73
65
  connection: ctx.connection,
74
- payer: ctx.wallet,
66
+ payer: wallet,
75
67
  auraProgramId: ctx.programId,
76
68
  });
77
69
  spinner.succeed(result.created ? "Encrypt deposit created" : "Encrypt deposit ready");
@@ -79,61 +71,62 @@ export function registerConfidentialCommands(program) {
79
71
  emitJson(ctx.output, result);
80
72
  return;
81
73
  }
82
- printSuccess(ctx.output, result.created
83
- ? `Encrypt deposit created: ${result.accounts.deposit.toBase58()}`
84
- : `Encrypt deposit ready: ${result.accounts.deposit.toBase58()}`);
74
+ printSuccess(ctx.output, `${result.created ? "Encrypt deposit created" : "Encrypt deposit ready"}: ${result.accounts.deposit.toBase58()}`);
85
75
  });
76
+ // --- guardrails ------------------------------------------------------
86
77
  const guardrails = confidential
87
78
  .command("guardrails")
88
79
  .description("Configure confidential guardrail ciphertexts");
89
80
  guardrails
90
81
  .command("scalar")
91
- .description("Attach scalar guardrail ciphertext accounts")
82
+ .description("Attach scalar guardrail ciphertext accounts (auto-encrypts via Ika Encrypt)")
92
83
  .option("--agent-id <id>", "treasury agent ID")
93
84
  .option("--treasury <pda>", "treasury PDA")
94
- .option("--daily-limit <usd>", "daily limit in USD — auto-encrypted via Ika Encrypt", Number)
95
- .option("--per-tx-limit <usd>", "per-transaction limit in USD — auto-encrypted via Ika Encrypt", Number)
96
- .option("--spent-today <usd>", "current spent-today counter in USD (default: 0) — auto-encrypted", Number)
97
- .option("--daily-limit-ciphertext <pubkey>", "use a pre-created daily limit ciphertext account instead")
98
- .option("--per-tx-ciphertext <pubkey>", "use a pre-created per-tx limit ciphertext account instead")
99
- .option("--spent-today-ciphertext <pubkey>", "use a pre-created spent-today ciphertext account instead")
85
+ .option("--daily-limit <usd>", "daily limit in USD", Number)
86
+ .option("--per-tx-limit <usd>", "per-transaction limit in USD", Number)
87
+ .option("--spent-today <usd>", "current spent-today counter in USD (default 0)", Number)
88
+ .option("--daily-limit-ciphertext <pubkey>", "use a pre-created daily limit ciphertext")
89
+ .option("--per-tx-ciphertext <pubkey>", "use a pre-created per-tx limit ciphertext")
90
+ .option("--spent-today-ciphertext <pubkey>", "use a pre-created spent-today ciphertext")
100
91
  .action(async function confidentialGuardrailsScalar() {
101
92
  const ctx = buildCliContext(this);
102
- if (!ctx.wallet) {
103
- throw new Error("A wallet is required to configure guardrails.");
104
- }
93
+ const wallet = requireWallet(ctx);
105
94
  const options = this.opts();
106
95
  const treasuryState = await resolveTreasuryAccount(ctx, {
107
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
108
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
96
+ agentId: typeof options.agentId === "string" ? options.agentId : undefined,
97
+ treasury: typeof options.treasury === "string" ? options.treasury : undefined,
109
98
  });
110
- const existing = treasuryState.account.confidentialGuardrails;
99
+ const usingPreCreated = typeof options.dailyLimitCiphertext === "string" &&
100
+ typeof options.perTxCiphertext === "string" &&
101
+ typeof options.spentTodayCiphertext === "string";
111
102
  let dailyLimitCiphertext;
112
103
  let perTxLimitCiphertext;
113
104
  let spentTodayCiphertext;
114
- // If pre-created ciphertext pubkeys are provided, use them directly.
115
- // Otherwise encrypt the plaintext values via the Ika Encrypt gRPC.
116
- if (typeof options["dailyLimitCiphertext"] === "string" &&
117
- typeof options["perTxCiphertext"] === "string" &&
118
- typeof options["spentTodayCiphertext"] === "string") {
119
- dailyLimitCiphertext = parsePublicKey(options["dailyLimitCiphertext"], "Daily limit ciphertext");
120
- perTxLimitCiphertext = parsePublicKey(options["perTxCiphertext"], "Per-tx limit ciphertext");
121
- spentTodayCiphertext = parsePublicKey(options["spentTodayCiphertext"], "Spent-today ciphertext");
105
+ if (usingPreCreated) {
106
+ dailyLimitCiphertext = parsePublicKey(options.dailyLimitCiphertext, "daily-limit-ciphertext");
107
+ perTxLimitCiphertext = parsePublicKey(options.perTxCiphertext, "per-tx-ciphertext");
108
+ spentTodayCiphertext = parsePublicKey(options.spentTodayCiphertext, "spent-today-ciphertext");
122
109
  }
123
110
  else {
124
- // Prompt for plaintext values and auto-encrypt
125
- const dailyLimit = await promptNumber(typeof options["dailyLimit"] === "number" ? options["dailyLimit"] : undefined, "Daily limit (USD)", { validate: (v) => { if (v <= 0)
126
- throw new Error("Must be > 0"); } });
127
- const perTxLimit = await promptNumber(typeof options["perTxLimit"] === "number" ? options["perTxLimit"] : undefined, "Per-transaction limit (USD)", { validate: (v) => { if (v <= 0)
128
- throw new Error("Must be > 0"); } });
129
- const spentToday = typeof options["spentToday"] === "number" ? options["spentToday"] : 0;
111
+ const dailyLimit = await promptNumber(typeof options.dailyLimit === "number"
112
+ ? options.dailyLimit
113
+ : undefined, "Daily limit (USD)", {
114
+ validate: (v) => {
115
+ if (v <= 0)
116
+ throw new Error("Must be > 0");
117
+ },
118
+ });
119
+ const perTxLimit = await promptNumber(typeof options.perTxLimit === "number"
120
+ ? options.perTxLimit
121
+ : undefined, "Per-transaction limit (USD)", {
122
+ validate: (v) => {
123
+ if (v <= 0)
124
+ throw new Error("Must be > 0");
125
+ },
126
+ });
127
+ const spentToday = typeof options.spentToday === "number" ? options.spentToday : 0;
130
128
  if (ctx.dryRun) {
131
- emitJson(ctx.output, {
132
- action: "confidential.guardrails.scalar",
133
- treasury: treasuryState.treasury,
134
- note: "dry-run: would encrypt dailyLimit, perTxLimit, spentToday via Ika Encrypt gRPC",
135
- values: { dailyLimit, perTxLimit, spentToday },
136
- });
129
+ printNote(ctx.output, `Dry run: would encrypt daily=$${dailyLimit}, per-tx=$${perTxLimit}, spent=$${spentToday} via Ika Encrypt, then configure scalar guardrails.`);
137
130
  return;
138
131
  }
139
132
  const spinner = startSpinner(ctx.output, "Encrypting guardrail values via Ika Encrypt...");
@@ -144,64 +137,33 @@ export function registerConfidentialCommands(program) {
144
137
  waitForCiphertextVerified(ctx.connection, perTx),
145
138
  waitForCiphertextVerified(ctx.connection, spent),
146
139
  ]);
140
+ spinner.succeed("Ciphertexts verified");
147
141
  dailyLimitCiphertext = daily;
148
142
  perTxLimitCiphertext = perTx;
149
143
  spentTodayCiphertext = spent;
150
- spinner.setText("Configuring scalar guardrails...");
151
- const now = Math.floor(Date.now() / 1000);
152
- const signature = await ctx.client.configureConfidentialGuardrails(ctx.wallet, {
153
- owner: ctx.wallet.publicKey,
144
+ }
145
+ const instruction = await instructions.confidential.configureConfidentialGuardrails(ctx.client, {
146
+ accounts: {
147
+ owner: wallet.publicKey,
154
148
  treasury: treasuryState.treasury,
155
149
  dailyLimitCiphertext,
156
150
  perTxLimitCiphertext,
157
151
  spentTodayCiphertext,
158
- }, now);
159
- spinner.succeed("Scalar guardrails configured");
160
- if (ctx.output.json) {
161
- emitJson(ctx.output, {
162
- treasury: treasuryState.treasury,
163
- signature,
164
- dailyLimitCiphertext,
165
- perTxLimitCiphertext,
166
- spentTodayCiphertext,
167
- });
168
- return;
169
- }
170
- printSuccess(ctx.output, `Scalar guardrails configured: ${signature}`);
171
- return;
172
- }
173
- // Pre-created ciphertext path
174
- const now = Math.floor(Date.now() / 1000);
175
- if (ctx.dryRun) {
176
- const instruction = await ctx.client.configureConfidentialGuardrailsInstruction({
177
- owner: ctx.wallet.publicKey,
152
+ },
153
+ args: { now: nowBn() },
154
+ });
155
+ await runInstructions(ctx, [instruction], {
156
+ action: "Configure scalar guardrails",
157
+ instructionName: "configure_confidential_guardrails",
158
+ result: {
178
159
  treasury: treasuryState.treasury,
179
160
  dailyLimitCiphertext,
180
161
  perTxLimitCiphertext,
181
162
  spentTodayCiphertext,
182
- }, now);
183
- emitJson(ctx.output, {
184
- action: "confidential.guardrails.scalar",
185
- treasury: treasuryState.treasury,
186
- instruction: serializeInstruction(instruction),
187
- });
188
- return;
189
- }
190
- const spinner = startSpinner(ctx.output, "Configuring scalar guardrails...");
191
- const signature = await ctx.client.configureConfidentialGuardrails(ctx.wallet, {
192
- owner: ctx.wallet.publicKey,
193
- treasury: treasuryState.treasury,
194
- dailyLimitCiphertext,
195
- perTxLimitCiphertext,
196
- spentTodayCiphertext,
197
- }, now);
198
- spinner.succeed("Scalar guardrails configured");
199
- if (ctx.output.json) {
200
- emitJson(ctx.output, { treasury: treasuryState.treasury, signature });
201
- return;
202
- }
203
- printSuccess(ctx.output, `Scalar guardrails configured: ${signature}`);
163
+ },
164
+ });
204
165
  });
166
+ // --- status ----------------------------------------------------------
205
167
  confidential
206
168
  .command("status")
207
169
  .description("Show confidential guardrails and pending confidential state")
@@ -211,8 +173,8 @@ export function registerConfidentialCommands(program) {
211
173
  const ctx = buildCliContext(this);
212
174
  const options = this.opts();
213
175
  const treasuryState = await resolveTreasuryAccount(ctx, {
214
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
215
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
176
+ agentId: typeof options.agentId === "string" ? options.agentId : undefined,
177
+ treasury: typeof options.treasury === "string" ? options.treasury : undefined,
216
178
  });
217
179
  const sections = renderTreasurySections(treasuryState.treasury, treasuryState.account);
218
180
  if (ctx.output.json) {
@@ -224,17 +186,14 @@ export function registerConfidentialCommands(program) {
224
186
  return;
225
187
  }
226
188
  printBanner(ctx.output, `Confidential: ${treasuryState.account.agentId}`);
227
- if (sections.confidential) {
228
- console.log(sections.confidential);
229
- }
230
- else {
231
- console.log("No confidential guardrails configured.");
232
- }
189
+ console.log(sections.confidential ??
190
+ style.muted("No confidential guardrails configured."));
233
191
  if (sections.pending) {
234
192
  console.log("");
235
193
  console.log(sections.pending);
236
194
  }
237
195
  });
196
+ // --- propose ---------------------------------------------------------
238
197
  confidential
239
198
  .command("propose")
240
199
  .description("Propose a confidential scalar transaction")
@@ -249,199 +208,214 @@ export function registerConfidentialCommands(program) {
249
208
  .option("--actual-output <usd>", "actual output in USD", Number)
250
209
  .option("--quote-age <secs>", "quote age in seconds", Number)
251
210
  .option("--counterparty-risk <score>", "counterparty risk score", Number)
252
- .option("--amount-ciphertext <pubkey>", "use a pre-created verified Encrypt ciphertext instead of auto-encrypting")
253
- .option("--policy-output-keypair <path>", "optional keypair path for the output ciphertext")
211
+ .option("--amount-ciphertext <pubkey>", "use a pre-created verified Encrypt ciphertext")
212
+ .option("--policy-output-keypair <path>", "keypair path for the output ciphertext account")
254
213
  .option("--wait", "wait until the policy output ciphertext is verified")
255
214
  .action(async function confidentialPropose() {
256
215
  const ctx = buildCliContext(this);
257
- if (!ctx.wallet) {
258
- throw new Error("A wallet is required to submit a confidential proposal.");
259
- }
216
+ const wallet = requireWallet(ctx);
260
217
  const options = this.opts();
261
218
  const treasuryState = await resolveTreasuryAccount(ctx, {
262
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
263
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
219
+ agentId: typeof options.agentId === "string" ? options.agentId : undefined,
220
+ treasury: typeof options.treasury === "string" ? options.treasury : undefined,
264
221
  });
265
222
  const guardrails = resolveScalarGuardrails(treasuryState.account);
266
- const amountUsd = await promptNumber(typeof options["amount"] === "number" ? options["amount"] : undefined, "Amount (USD)", { validate: (value) => { if (value <= 0)
267
- throw new Error("Amount must be > 0"); } });
268
- const chain = await promptChain(typeof options["chain"] === "string" || typeof options["chain"] === "number"
269
- ? options["chain"]
223
+ const amountUsd = await promptNumber(typeof options.amount === "number" ? options.amount : undefined, "Amount (USD)", {
224
+ validate: (v) => {
225
+ if (v <= 0)
226
+ throw new Error("Amount must be > 0");
227
+ },
228
+ });
229
+ const chain = await promptChain(typeof options.chain === "string" || typeof options.chain === "number"
230
+ ? options.chain
270
231
  : undefined, "Chain");
271
- const recipient = await promptString(typeof options["recipient"] === "string" ? options["recipient"] : undefined, "Recipient");
272
- const txType = await promptTransactionType(typeof options["txType"] === "string" || typeof options["txType"] === "number"
273
- ? options["txType"]
232
+ const recipient = await promptString(typeof options.recipient === "string" ? options.recipient : undefined, "Recipient");
233
+ const txType = await promptTransactionType(typeof options.txType === "string" || typeof options.txType === "number"
234
+ ? options.txType
274
235
  : undefined, "Transaction type");
275
236
  const args = buildProposeConfidentialArgs({
276
237
  amountUsd,
277
238
  chain,
278
239
  txType,
279
240
  recipient,
280
- protocolId: typeof options["protocolId"] === "number" ? options["protocolId"] : undefined,
281
- expectedOutputUsd: typeof options["expectedOutput"] === "number" ? options["expectedOutput"] : undefined,
282
- actualOutputUsd: typeof options["actualOutput"] === "number" ? options["actualOutput"] : undefined,
283
- quoteAgeSecs: typeof options["quoteAge"] === "number" ? options["quoteAge"] : undefined,
284
- counterpartyRiskScore: typeof options["counterpartyRisk"] === "number"
285
- ? options["counterpartyRisk"]
241
+ protocolId: typeof options.protocolId === "number"
242
+ ? options.protocolId
243
+ : undefined,
244
+ expectedOutputUsd: typeof options.expectedOutput === "number"
245
+ ? options.expectedOutput
246
+ : undefined,
247
+ actualOutputUsd: typeof options.actualOutput === "number"
248
+ ? options.actualOutput
249
+ : undefined,
250
+ quoteAgeSecs: typeof options.quoteAge === "number" ? options.quoteAge : undefined,
251
+ counterpartyRiskScore: typeof options.counterpartyRisk === "number"
252
+ ? options.counterpartyRisk
286
253
  : undefined,
287
- });
288
- const policyOutputSigner = buildDryRunKeypair(typeof options["policyOutputKeypair"] === "string"
289
- ? options["policyOutputKeypair"]
290
- : undefined, loadKeypair);
291
- const encryptAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
292
- auraProgramId: ctx.programId,
293
254
  });
294
255
  if (ctx.dryRun) {
295
- emitJson(ctx.output, {
296
- action: "confidential.propose",
297
- treasury: treasuryState.treasury,
298
- policyOutputCiphertext: policyOutputSigner.publicKey,
299
- encryptAccounts,
300
- args,
301
- note: typeof options["amountCiphertext"] === "string"
302
- ? "using pre-created amount ciphertext"
303
- : "would auto-encrypt amount via Ika Encrypt gRPC",
304
- });
256
+ printNote(ctx.output, "Dry run: would ensure an Encrypt deposit, encrypt the amount via Ika, then submit propose_confidential_transaction.");
257
+ if (ctx.output.json) {
258
+ emitJson(ctx.output, {
259
+ action: "confidential.propose",
260
+ treasury: treasuryState.treasury,
261
+ args,
262
+ });
263
+ }
305
264
  return;
306
265
  }
266
+ const policyOutputSigner = buildDryRunKeypair(typeof options.policyOutputKeypair === "string"
267
+ ? options.policyOutputKeypair
268
+ : undefined, loadKeypair);
269
+ const encryptAccounts = deriveEncryptAccounts(wallet.publicKey, {
270
+ auraProgramId: ctx.programId,
271
+ });
307
272
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
308
273
  await ensureEncryptDeposit({
309
274
  connection: ctx.connection,
310
- payer: ctx.wallet,
275
+ payer: wallet,
311
276
  auraProgramId: ctx.programId,
312
277
  });
313
- // Resolve the amount ciphertext — auto-encrypt if not provided
314
278
  let amountCiphertext;
315
- if (typeof options["amountCiphertext"] === "string") {
316
- amountCiphertext = parsePublicKey(options["amountCiphertext"], "Amount ciphertext");
279
+ if (typeof options.amountCiphertext === "string") {
280
+ amountCiphertext = parsePublicKey(options.amountCiphertext, "amount-ciphertext");
317
281
  }
318
282
  else {
319
- spinner.setText(`Encrypting amount (${amountUsd} USD) via Ika Encrypt...`);
283
+ spinner.setText(`Encrypting amount ($${amountUsd}) via Ika Encrypt...`);
320
284
  amountCiphertext = await encryptU64(amountUsd, ctx.programId);
321
285
  spinner.setText("Waiting for amount ciphertext to be verified on-chain...");
322
286
  await waitForCiphertextVerified(ctx.connection, amountCiphertext);
323
287
  }
324
- const instruction = await ctx.client.proposeConfidentialTransactionInstruction({
325
- aiAuthority: ctx.wallet.publicKey,
326
- treasury: treasuryState.treasury,
327
- dailyLimitCiphertext: guardrails.dailyLimitCiphertext,
328
- perTxLimitCiphertext: guardrails.perTxLimitCiphertext,
329
- spentTodayCiphertext: guardrails.spentTodayCiphertext,
330
- amountCiphertext,
331
- policyOutputCiphertext: policyOutputSigner.publicKey,
332
- encryptProgram: encryptAccounts.encryptProgram,
333
- config: encryptAccounts.config,
334
- deposit: encryptAccounts.deposit,
335
- callerProgram: ctx.programId,
336
- cpiAuthority: encryptAccounts.cpiAuthority,
337
- networkEncryptionKey: encryptAccounts.networkEncryptionKey,
338
- eventAuthority: encryptAccounts.eventAuthority,
339
- systemProgram: SystemProgram.programId,
340
- }, args);
288
+ spinner.succeed("Amount ciphertext ready");
289
+ const instruction = await instructions.confidential.proposeConfidentialTransaction(ctx.client, {
290
+ accounts: {
291
+ aiAuthority: wallet.publicKey,
292
+ treasury: treasuryState.treasury,
293
+ dailyLimitCiphertext: guardrails.dailyLimitCiphertext,
294
+ perTxLimitCiphertext: guardrails.perTxLimitCiphertext,
295
+ spentTodayCiphertext: guardrails.spentTodayCiphertext,
296
+ amountCiphertext,
297
+ policyOutputCiphertext: policyOutputSigner.publicKey,
298
+ encryptProgram: encryptAccounts.encryptProgram,
299
+ config: encryptAccounts.config,
300
+ deposit: encryptAccounts.deposit,
301
+ callerProgram: ctx.programId,
302
+ cpiAuthority: encryptAccounts.cpiAuthority,
303
+ networkEncryptionKey: encryptAccounts.networkEncryptionKey,
304
+ eventAuthority: encryptAccounts.eventAuthority,
305
+ externalLiveness: null,
306
+ weeklyLimitCiphertext: null,
307
+ weeklySpentCiphertext: null,
308
+ confidentialGuardrails: null,
309
+ systemProgram: SystemProgram.programId,
310
+ },
311
+ args,
312
+ });
313
+ // The freshly created output ciphertext account must sign its own creation.
341
314
  markInstructionSigner(instruction, policyOutputSigner.publicKey);
342
- spinner.setText("Submitting confidential proposal...");
343
- const signature = await sendPreparedInstruction({
344
- ctx,
345
- instruction,
315
+ const outcome = await runInstructions(ctx, [instruction], {
316
+ action: "Propose confidential transaction",
317
+ instructionName: "propose_confidential_transaction",
346
318
  extraSigners: [policyOutputSigner],
347
- });
348
- if (options["wait"] === true) {
349
- spinner.setText("Waiting for output ciphertext verification...");
350
- await waitForCiphertextVerified(ctx.connection, policyOutputSigner.publicKey);
351
- }
352
- spinner.succeed("Confidential proposal submitted");
353
- if (ctx.output.json) {
354
- emitJson(ctx.output, {
319
+ computeUnits: 1_400_000,
320
+ heapFrameBytes: 256 * 1024,
321
+ summary: [
322
+ ["amount ct", amountCiphertext.toBase58()],
323
+ ["output ct", policyOutputSigner.publicKey.toBase58()],
324
+ ],
325
+ result: {
355
326
  treasury: treasuryState.treasury,
356
- signature,
357
327
  amountCiphertext,
358
328
  policyOutputCiphertext: policyOutputSigner.publicKey,
359
- });
360
- return;
329
+ },
330
+ });
331
+ if (outcome.signature && options.wait === true) {
332
+ const waitSpinner = startSpinner(ctx.output, "Waiting for output ciphertext verification...");
333
+ await waitForCiphertextVerified(ctx.connection, policyOutputSigner.publicKey);
334
+ waitSpinner.succeed("Output ciphertext verified");
361
335
  }
362
- printSuccess(ctx.output, `Confidential proposal submitted: ${signature}\n amount ciphertext: ${amountCiphertext.toBase58()}\n output ciphertext: ${policyOutputSigner.publicKey.toBase58()}`);
363
336
  });
337
+ // --- request-decryption ---------------------------------------------
364
338
  confidential
365
339
  .command("request-decryption")
366
340
  .description("Request Encrypt decryption for the pending policy output")
367
341
  .option("--agent-id <id>", "treasury agent ID")
368
342
  .option("--treasury <pda>", "treasury PDA")
369
343
  .option("--ciphertext <pubkey>", "override the pending policy output ciphertext")
370
- .option("--request-keypair <path>", "optional keypair path for the decryption request account")
344
+ .option("--request-keypair <path>", "keypair path for the decryption request account")
371
345
  .option("--wait", "wait until the plaintext is ready on-chain")
372
346
  .action(async function confidentialRequestDecryption() {
373
347
  const ctx = buildCliContext(this);
374
- if (!ctx.wallet) {
375
- throw new Error("A wallet is required to request policy decryption.");
376
- }
348
+ const wallet = requireWallet(ctx);
377
349
  const options = this.opts();
378
350
  const treasuryState = await resolveTreasuryAccount(ctx, {
379
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
380
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
351
+ agentId: typeof options.agentId === "string" ? options.agentId : undefined,
352
+ treasury: typeof options.treasury === "string" ? options.treasury : undefined,
381
353
  });
382
- const ciphertext = typeof options["ciphertext"] === "string"
383
- ? parsePublicKey(options["ciphertext"], "Ciphertext")
354
+ const ciphertext = typeof options.ciphertext === "string"
355
+ ? parsePublicKey(options.ciphertext, "ciphertext")
384
356
  : resolvePendingPolicyOutput(treasuryState.account);
385
- const requestSigner = buildDryRunKeypair(typeof options["requestKeypair"] === "string"
386
- ? options["requestKeypair"]
387
- : undefined, loadKeypair);
388
- const encryptAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
389
- auraProgramId: ctx.programId,
390
- });
391
- const now = Math.floor(Date.now() / 1000);
392
- const instruction = await ctx.client.requestPolicyDecryptionInstruction({
393
- operator: ctx.wallet.publicKey,
394
- treasury: treasuryState.treasury,
395
- requestAccount: requestSigner.publicKey,
396
- ciphertext,
397
- encryptProgram: encryptAccounts.encryptProgram,
398
- config: encryptAccounts.config,
399
- deposit: encryptAccounts.deposit,
400
- callerProgram: ctx.programId,
401
- cpiAuthority: encryptAccounts.cpiAuthority,
402
- networkEncryptionKey: encryptAccounts.networkEncryptionKey,
403
- eventAuthority: encryptAccounts.eventAuthority,
404
- systemProgram: SystemProgram.programId,
405
- }, now);
406
- markInstructionSigner(instruction, requestSigner.publicKey);
407
357
  if (ctx.dryRun) {
408
- emitJson(ctx.output, {
409
- action: "confidential.request-decryption",
410
- treasury: treasuryState.treasury,
411
- ciphertext,
412
- requestAccount: requestSigner.publicKey,
413
- instruction: serializeInstruction(instruction),
414
- });
358
+ printNote(ctx.output, "Dry run: would ensure an Encrypt deposit and submit request_policy_decryption.");
359
+ if (ctx.output.json) {
360
+ emitJson(ctx.output, {
361
+ action: "confidential.request-decryption",
362
+ treasury: treasuryState.treasury,
363
+ ciphertext,
364
+ });
365
+ }
415
366
  return;
416
367
  }
368
+ const requestSigner = buildDryRunKeypair(typeof options.requestKeypair === "string"
369
+ ? options.requestKeypair
370
+ : undefined, loadKeypair);
371
+ const encryptAccounts = deriveEncryptAccounts(wallet.publicKey, {
372
+ auraProgramId: ctx.programId,
373
+ });
417
374
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
418
- const depositResult = await ensureEncryptDeposit({
375
+ await ensureEncryptDeposit({
419
376
  connection: ctx.connection,
420
- payer: ctx.wallet,
377
+ payer: wallet,
421
378
  auraProgramId: ctx.programId,
422
379
  });
423
- spinner.setText("Submitting decryption request...");
424
- const signature = await sendPreparedInstruction({
425
- ctx,
426
- instruction,
427
- extraSigners: [requestSigner],
380
+ spinner.succeed("Encrypt deposit ready");
381
+ const instruction = await instructions.confidential.requestPolicyDecryption(ctx.client, {
382
+ accounts: {
383
+ operator: wallet.publicKey,
384
+ treasury: treasuryState.treasury,
385
+ requestAccount: requestSigner.publicKey,
386
+ ciphertext,
387
+ encryptProgram: encryptAccounts.encryptProgram,
388
+ config: encryptAccounts.config,
389
+ deposit: encryptAccounts.deposit,
390
+ callerProgram: ctx.programId,
391
+ cpiAuthority: encryptAccounts.cpiAuthority,
392
+ networkEncryptionKey: encryptAccounts.networkEncryptionKey,
393
+ eventAuthority: encryptAccounts.eventAuthority,
394
+ confidentialGuardrails: null,
395
+ systemProgram: SystemProgram.programId,
396
+ },
397
+ args: { now: nowBn(), currentEpochId: new BN(0) },
428
398
  });
429
- if (options["wait"] === true) {
430
- spinner.setText("Waiting for decrypted plaintext...");
431
- await waitForDecryptionReady(ctx.connection, requestSigner.publicKey);
432
- }
433
- spinner.succeed("Policy decryption requested");
434
- if (ctx.output.json) {
435
- emitJson(ctx.output, {
399
+ markInstructionSigner(instruction, requestSigner.publicKey);
400
+ const outcome = await runInstructions(ctx, [instruction], {
401
+ action: "Request policy decryption",
402
+ instructionName: "request_policy_decryption",
403
+ extraSigners: [requestSigner],
404
+ computeUnits: 1_400_000,
405
+ heapFrameBytes: 256 * 1024,
406
+ summary: [["request", requestSigner.publicKey.toBase58()]],
407
+ result: {
436
408
  treasury: treasuryState.treasury,
437
- signature,
438
409
  requestAccount: requestSigner.publicKey,
439
- deposit: depositResult,
440
- });
441
- return;
410
+ },
411
+ });
412
+ if (outcome.signature && options.wait === true) {
413
+ const waitSpinner = startSpinner(ctx.output, "Waiting for decrypted plaintext...");
414
+ await waitForDecryptionReady(ctx.connection, requestSigner.publicKey);
415
+ waitSpinner.succeed("Plaintext ready");
442
416
  }
443
- printSuccess(ctx.output, `Policy decryption requested: ${signature} (request ${requestSigner.publicKey.toBase58()})`);
444
417
  });
418
+ // --- confirm-decryption ---------------------------------------------
445
419
  confidential
446
420
  .command("confirm-decryption")
447
421
  .description("Confirm a completed policy decryption request on-chain")
@@ -450,70 +424,51 @@ export function registerConfidentialCommands(program) {
450
424
  .option("--request-account <pubkey>", "override the pending decryption request account")
451
425
  .action(async function confidentialConfirmDecryption() {
452
426
  const ctx = buildCliContext(this);
453
- if (!ctx.wallet) {
454
- throw new Error("A wallet is required to confirm policy decryption.");
455
- }
427
+ const wallet = requireWallet(ctx);
456
428
  const options = this.opts();
457
429
  const treasuryState = await resolveTreasuryAccount(ctx, {
458
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
459
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
430
+ agentId: typeof options.agentId === "string" ? options.agentId : undefined,
431
+ treasury: typeof options.treasury === "string" ? options.treasury : undefined,
460
432
  });
461
- const requestAccount = typeof options["requestAccount"] === "string"
462
- ? parsePublicKey(options["requestAccount"], "Request account")
433
+ const requestAccount = typeof options.requestAccount === "string"
434
+ ? parsePublicKey(options.requestAccount, "request-account")
463
435
  : resolvePendingRequestAccount(treasuryState.account);
464
- const now = Math.floor(Date.now() / 1000);
465
- if (ctx.dryRun) {
466
- const instruction = await ctx.client.confirmPolicyDecryptionInstruction({
467
- operator: ctx.wallet.publicKey,
468
- treasury: treasuryState.treasury,
469
- requestAccount,
470
- }, now);
471
- emitJson(ctx.output, {
472
- action: "confidential.confirm-decryption",
436
+ const instruction = await instructions.confidential.confirmPolicyDecryption(ctx.client, {
437
+ accounts: {
438
+ operator: wallet.publicKey,
473
439
  treasury: treasuryState.treasury,
474
440
  requestAccount,
475
- instruction: serializeInstruction(instruction),
476
- });
477
- return;
478
- }
479
- const spinner = startSpinner(ctx.output, "Confirming policy decryption...");
480
- const instruction = await ctx.client.confirmPolicyDecryptionInstruction({
481
- operator: ctx.wallet.publicKey,
482
- treasury: treasuryState.treasury,
483
- requestAccount,
484
- }, now);
485
- const signature = await sendPreparedInstruction({ ctx, instruction });
486
- // Read the decrypted scalar violation code for display. The on-chain
487
- // treasury remains the source of truth if the read is unavailable.
488
- let violationCode = null;
489
- try {
490
- spinner.setText("Reading decrypted policy result from Encrypt network...");
491
- const policyOutput = resolvePendingPolicyOutput(treasuryState.account);
492
- violationCode = await readU64Ciphertext(policyOutput, ctx.wallet.publicKey);
493
- }
494
- catch {
495
- // Non-fatal the on-chain state is the source of truth
496
- }
497
- spinner.succeed("Policy decryption confirmed");
498
- const refreshed = await ctx.client.getTreasuryAccount(treasuryState.treasury);
499
- const decision = getActivePendingProposal(refreshed)?.decision;
500
- if (ctx.output.json) {
501
- emitJson(ctx.output, {
502
- treasury: treasuryState.treasury,
503
- requestAccount,
504
- signature,
505
- approved: decision?.approved ?? null,
506
- violation: decision?.violation ?? null,
507
- violationCode: violationCode !== null ? violationCode.toString() : null,
508
- });
509
- return;
441
+ confidentialGuardrails: null,
442
+ },
443
+ args: { now: nowBn(), currentEpochId: new BN(0) },
444
+ });
445
+ const outcome = await runInstructions(ctx, [instruction], {
446
+ action: "Confirm policy decryption",
447
+ instructionName: "confirm_policy_decryption",
448
+ summary: [["request", requestAccount.toBase58()]],
449
+ result: { treasury: treasuryState.treasury, requestAccount },
450
+ });
451
+ if (outcome.signature && !ctx.output.json) {
452
+ let violationCode = null;
453
+ try {
454
+ violationCode = await readU64Ciphertext(resolvePendingPolicyOutput(treasuryState.account), wallet.publicKey);
455
+ }
456
+ catch {
457
+ // Non-fatal on-chain state remains the source of truth.
458
+ }
459
+ try {
460
+ const refreshed = await accounts.fetchTreasuryAccount(ctx.client, treasuryState.treasury);
461
+ const decision = getActivePendingProposal(refreshed)?.decision;
462
+ if (decision) {
463
+ printInfo(ctx.output, decision.approved
464
+ ? style.success("result: approved")
465
+ : style.danger(`result: denied — violation code ${violationCode ?? decision.violation}`));
466
+ }
467
+ }
468
+ catch {
469
+ // Non-fatal.
470
+ }
510
471
  }
511
- const resultLine = decision
512
- ? decision.approved
513
- ? "approved ✓"
514
- : `denied — violation code ${violationCode ?? decision.violation}`
515
- : "";
516
- printSuccess(ctx.output, `Policy decryption confirmed: ${signature}${resultLine ? `\n result: ${resultLine}` : ""}`);
517
472
  });
518
473
  }
519
474
  //# sourceMappingURL=confidential.js.map