@aura-protocol/cli 0.1.2 → 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 (120) hide show
  1. package/README.md +84 -67
  2. package/bin/aura.js +0 -0
  3. package/dist/commands/confidential.d.ts +1 -1
  4. package/dist/commands/confidential.js +276 -597
  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/ika.d.ts +0 -9
  64. package/dist/ika.js +0 -48
  65. package/dist/ika.js.map +1 -1
  66. package/dist/index.js +56 -13
  67. package/dist/index.js.map +1 -1
  68. package/dist/lib/domain.d.ts +16 -0
  69. package/dist/lib/domain.js +88 -0
  70. package/dist/lib/domain.js.map +1 -0
  71. package/dist/lib/ika.d.ts +81 -0
  72. package/dist/lib/ika.js +192 -0
  73. package/dist/lib/ika.js.map +1 -0
  74. package/dist/lib/instructions.d.ts +79 -0
  75. package/dist/lib/instructions.js +421 -0
  76. package/dist/lib/instructions.js.map +1 -0
  77. package/dist/lib/protocol.d.ts +99 -0
  78. package/dist/lib/protocol.js +327 -0
  79. package/dist/lib/protocol.js.map +1 -0
  80. package/dist/lib/treasury-view.d.ts +11 -0
  81. package/dist/lib/treasury-view.js +126 -0
  82. package/dist/lib/treasury-view.js.map +1 -0
  83. package/dist/output.js +0 -3
  84. package/dist/output.js.map +1 -1
  85. package/dist/program-instructions.d.ts +1 -1
  86. package/dist/protocol.d.ts +0 -1
  87. package/dist/protocol.js +0 -7
  88. package/dist/protocol.js.map +1 -1
  89. package/dist/treasury-view.js +1 -1
  90. package/dist/treasury-view.js.map +1 -1
  91. package/dist/ui/dashboard.d.ts +7 -0
  92. package/dist/ui/dashboard.js +99 -0
  93. package/dist/ui/dashboard.js.map +1 -0
  94. package/dist/ui/format.d.ts +9 -0
  95. package/dist/ui/format.js +92 -0
  96. package/dist/ui/format.js.map +1 -0
  97. package/dist/ui/output.d.ts +58 -0
  98. package/dist/ui/output.js +208 -0
  99. package/dist/ui/output.js.map +1 -0
  100. package/dist/ui/theme.d.ts +52 -0
  101. package/dist/ui/theme.js +110 -0
  102. package/dist/ui/theme.js.map +1 -0
  103. package/dist/vendor/encrypt/generated/grpc/encrypt_service.d.ts +1 -1
  104. package/dist/vendor/encrypt/generated/grpc/encrypt_service.js +36 -13
  105. package/dist/vendor/encrypt/generated/grpc/encrypt_service.js.map +1 -1
  106. package/dist/vendor/encrypt/grpc.d.ts +2 -2
  107. package/dist/vendor/encrypt/grpc.js +1 -3
  108. package/dist/vendor/encrypt/grpc.js.map +1 -1
  109. package/dist/vendor/ika/bcs-types.js +107 -50
  110. package/dist/vendor/ika/bcs-types.js.map +1 -1
  111. package/dist/vendor/ika/generated/grpc/ika_dwallet.d.ts +1 -1
  112. package/dist/vendor/ika/generated/grpc/ika_dwallet.js +14 -4
  113. package/dist/vendor/ika/generated/grpc/ika_dwallet.js.map +1 -1
  114. package/dist/vendor/ika/grpc.d.ts +1 -1
  115. package/dist/vendor/ika/grpc.js +49 -24
  116. package/dist/vendor/ika/grpc.js.map +1 -1
  117. package/package.json +16 -13
  118. package/dist/ascii.d.ts +0 -1
  119. package/dist/ascii.js +0 -2
  120. package/dist/ascii.js.map +0 -1
@@ -1,99 +1,69 @@
1
+ import { accounts, instructions } from "@aura-protocol/sdk-ts";
1
2
  import { PublicKey, SystemProgram } from "@solana/web3.js";
2
3
  import BN from "bn.js";
3
- import {} from "commander";
4
- import { buildCliContext } from "../context.js";
5
- import { printBanner, printSuccess, emitJson, serializeInstruction, startSpinner } from "../output.js";
6
- import { buildDryRunKeypair, deriveEncryptAccounts, ensureEncryptDeposit, getActivePendingProposal, markInstructionSigner, resolvePendingPolicyOutput, resolvePendingRequestAccount, resolveScalarGuardrails, resolveVectorGuardrail, sendInstructionsWithBudget, waitForCiphertextVerified, waitForDecryptionReady, } from "../protocol.js";
7
- import { encryptU64, encryptU64Batch, encryptU64Vector, readU64Ciphertext, } from "../ika.js";
8
- import { renderTreasurySections } from "../treasury-view.js";
9
- import { loadKeypair } from "../wallet.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";
10
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
+ }
11
23
  function parsePublicKey(value, label) {
12
24
  try {
13
25
  return new PublicKey(value);
14
26
  }
15
27
  catch {
16
- throw new Error(`${label} must be a valid base58 pubkey`);
17
- }
18
- }
19
- function normalizeDigestHex(value, label) {
20
- if (!value) {
21
- return null;
22
- }
23
- if (!/^[0-9a-fA-F]{64}$/.test(value)) {
24
- throw new Error(`${label} must be a 32-byte hex digest`);
28
+ throw CliError.invalidInput(label, "base58 public key");
25
29
  }
26
- return value.toLowerCase();
27
- }
28
- function normalizePublicKeyHex(value) {
29
- if (!value) {
30
- return null;
31
- }
32
- if (!/^[0-9a-fA-F]+$/.test(value) || value.length % 2 !== 0) {
33
- throw new Error("publicKeyHex must contain valid hex bytes");
34
- }
35
- return value.toLowerCase();
36
- }
37
- const U64_MODULUS = 1n << 64n;
38
- const U64_VECTOR_LANES = 1024;
39
- const VECTOR_CIPHERTEXT_TIMEOUT_MS = 600_000;
40
- function wrappingNegU64(value) {
41
- const amount = BigInt(value);
42
- return (U64_MODULUS - (amount % U64_MODULUS)) % U64_MODULUS;
43
- }
44
- function vectorFlagIndices() {
45
- return Array.from({ length: U64_VECTOR_LANES }, (_, index) => {
46
- if (index === 0)
47
- return 3n;
48
- if (index === 1)
49
- return 4n;
50
- return BigInt(Math.min(index + 3, U64_VECTOR_LANES - 1));
51
- });
52
- }
53
- function parseOptionalPubkeyOption(options, name, label) {
54
- return typeof options[name] === "string"
55
- ? parsePublicKey(options[name], label)
56
- : null;
57
30
  }
58
- async function sendPreparedInstruction(options) {
59
- const { ctx, instruction, extraSigners = [] } = options;
60
- if (!ctx.wallet) {
61
- throw new Error("A wallet is required for this command.");
62
- }
63
- return await sendInstructionsWithBudget({
64
- connection: ctx.connection,
65
- payer: ctx.wallet,
66
- instructions: [instruction],
67
- extraSigners,
68
- });
31
+ function nowBn() {
32
+ return new BN(Math.floor(Date.now() / 1000));
69
33
  }
70
34
  export function registerConfidentialCommands(program) {
71
35
  const confidential = program
72
36
  .command("confidential")
73
- .description("Manage confidential guardrails and policy decryption");
74
- 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");
75
42
  deposit
76
43
  .command("ensure")
77
44
  .description("Ensure the configured wallet has an Encrypt deposit account")
78
45
  .action(async function confidentialDepositEnsure() {
79
46
  const ctx = buildCliContext(this);
80
- if (!ctx.wallet) {
81
- throw new Error("A wallet is required to manage Encrypt deposit accounts.");
82
- }
83
- const dryRunAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
47
+ const wallet = requireWallet(ctx);
48
+ const derived = deriveEncryptAccounts(wallet.publicKey, {
84
49
  auraProgramId: ctx.programId,
85
50
  });
86
51
  if (ctx.dryRun) {
87
- emitJson(ctx.output, {
88
- action: "confidential.deposit.ensure",
89
- accounts: dryRunAccounts,
90
- });
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
+ }
91
61
  return;
92
62
  }
93
63
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
94
64
  const result = await ensureEncryptDeposit({
95
65
  connection: ctx.connection,
96
- payer: ctx.wallet,
66
+ payer: wallet,
97
67
  auraProgramId: ctx.programId,
98
68
  });
99
69
  spinner.succeed(result.created ? "Encrypt deposit created" : "Encrypt deposit ready");
@@ -101,61 +71,62 @@ export function registerConfidentialCommands(program) {
101
71
  emitJson(ctx.output, result);
102
72
  return;
103
73
  }
104
- printSuccess(ctx.output, result.created
105
- ? `Encrypt deposit created: ${result.accounts.deposit.toBase58()}`
106
- : `Encrypt deposit ready: ${result.accounts.deposit.toBase58()}`);
74
+ printSuccess(ctx.output, `${result.created ? "Encrypt deposit created" : "Encrypt deposit ready"}: ${result.accounts.deposit.toBase58()}`);
107
75
  });
76
+ // --- guardrails ------------------------------------------------------
108
77
  const guardrails = confidential
109
78
  .command("guardrails")
110
79
  .description("Configure confidential guardrail ciphertexts");
111
80
  guardrails
112
81
  .command("scalar")
113
- .description("Attach scalar guardrail ciphertext accounts")
82
+ .description("Attach scalar guardrail ciphertext accounts (auto-encrypts via Ika Encrypt)")
114
83
  .option("--agent-id <id>", "treasury agent ID")
115
84
  .option("--treasury <pda>", "treasury PDA")
116
- .option("--daily-limit <usd>", "daily limit in USD — auto-encrypted via Ika Encrypt", Number)
117
- .option("--per-tx-limit <usd>", "per-transaction limit in USD — auto-encrypted via Ika Encrypt", Number)
118
- .option("--spent-today <usd>", "current spent-today counter in USD (default: 0) — auto-encrypted", Number)
119
- .option("--daily-limit-ciphertext <pubkey>", "use a pre-created daily limit ciphertext account instead")
120
- .option("--per-tx-ciphertext <pubkey>", "use a pre-created per-tx limit ciphertext account instead")
121
- .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")
122
91
  .action(async function confidentialGuardrailsScalar() {
123
92
  const ctx = buildCliContext(this);
124
- if (!ctx.wallet) {
125
- throw new Error("A wallet is required to configure guardrails.");
126
- }
93
+ const wallet = requireWallet(ctx);
127
94
  const options = this.opts();
128
95
  const treasuryState = await resolveTreasuryAccount(ctx, {
129
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
130
- 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,
131
98
  });
132
- const existing = treasuryState.account.confidentialGuardrails;
99
+ const usingPreCreated = typeof options.dailyLimitCiphertext === "string" &&
100
+ typeof options.perTxCiphertext === "string" &&
101
+ typeof options.spentTodayCiphertext === "string";
133
102
  let dailyLimitCiphertext;
134
103
  let perTxLimitCiphertext;
135
104
  let spentTodayCiphertext;
136
- // If pre-created ciphertext pubkeys are provided, use them directly.
137
- // Otherwise encrypt the plaintext values via the Ika Encrypt gRPC.
138
- if (typeof options["dailyLimitCiphertext"] === "string" &&
139
- typeof options["perTxCiphertext"] === "string" &&
140
- typeof options["spentTodayCiphertext"] === "string") {
141
- dailyLimitCiphertext = parsePublicKey(options["dailyLimitCiphertext"], "Daily limit ciphertext");
142
- perTxLimitCiphertext = parsePublicKey(options["perTxCiphertext"], "Per-tx limit ciphertext");
143
- 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");
144
109
  }
145
110
  else {
146
- // Prompt for plaintext values and auto-encrypt
147
- const dailyLimit = await promptNumber(typeof options["dailyLimit"] === "number" ? options["dailyLimit"] : undefined, "Daily limit (USD)", { validate: (v) => { if (v <= 0)
148
- throw new Error("Must be > 0"); } });
149
- const perTxLimit = await promptNumber(typeof options["perTxLimit"] === "number" ? options["perTxLimit"] : undefined, "Per-transaction limit (USD)", { validate: (v) => { if (v <= 0)
150
- throw new Error("Must be > 0"); } });
151
- 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;
152
128
  if (ctx.dryRun) {
153
- emitJson(ctx.output, {
154
- action: "confidential.guardrails.scalar",
155
- treasury: treasuryState.treasury,
156
- note: "dry-run: would encrypt dailyLimit, perTxLimit, spentToday via Ika Encrypt gRPC",
157
- values: { dailyLimit, perTxLimit, spentToday },
158
- });
129
+ printNote(ctx.output, `Dry run: would encrypt daily=$${dailyLimit}, per-tx=$${perTxLimit}, spent=$${spentToday} via Ika Encrypt, then configure scalar guardrails.`);
159
130
  return;
160
131
  }
161
132
  const spinner = startSpinner(ctx.output, "Encrypting guardrail values via Ika Encrypt...");
@@ -166,111 +137,33 @@ export function registerConfidentialCommands(program) {
166
137
  waitForCiphertextVerified(ctx.connection, perTx),
167
138
  waitForCiphertextVerified(ctx.connection, spent),
168
139
  ]);
140
+ spinner.succeed("Ciphertexts verified");
169
141
  dailyLimitCiphertext = daily;
170
142
  perTxLimitCiphertext = perTx;
171
143
  spentTodayCiphertext = spent;
172
- spinner.setText("Configuring scalar guardrails...");
173
- const now = Math.floor(Date.now() / 1000);
174
- const signature = await ctx.client.configureConfidentialGuardrails(ctx.wallet, {
175
- owner: ctx.wallet.publicKey,
144
+ }
145
+ const instruction = await instructions.confidential.configureConfidentialGuardrails(ctx.client, {
146
+ accounts: {
147
+ owner: wallet.publicKey,
176
148
  treasury: treasuryState.treasury,
177
149
  dailyLimitCiphertext,
178
150
  perTxLimitCiphertext,
179
151
  spentTodayCiphertext,
180
- }, now);
181
- spinner.succeed("Scalar guardrails configured");
182
- if (ctx.output.json) {
183
- emitJson(ctx.output, {
184
- treasury: treasuryState.treasury,
185
- signature,
186
- dailyLimitCiphertext,
187
- perTxLimitCiphertext,
188
- spentTodayCiphertext,
189
- });
190
- return;
191
- }
192
- printSuccess(ctx.output, `Scalar guardrails configured: ${signature}`);
193
- return;
194
- }
195
- // Pre-created ciphertext path
196
- const now = Math.floor(Date.now() / 1000);
197
- if (ctx.dryRun) {
198
- const instruction = await ctx.client.configureConfidentialGuardrailsInstruction({
199
- 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: {
200
159
  treasury: treasuryState.treasury,
201
160
  dailyLimitCiphertext,
202
161
  perTxLimitCiphertext,
203
162
  spentTodayCiphertext,
204
- }, now);
205
- emitJson(ctx.output, {
206
- action: "confidential.guardrails.scalar",
207
- treasury: treasuryState.treasury,
208
- instruction: serializeInstruction(instruction),
209
- });
210
- return;
211
- }
212
- const spinner = startSpinner(ctx.output, "Configuring scalar guardrails...");
213
- const signature = await ctx.client.configureConfidentialGuardrails(ctx.wallet, {
214
- owner: ctx.wallet.publicKey,
215
- treasury: treasuryState.treasury,
216
- dailyLimitCiphertext,
217
- perTxLimitCiphertext,
218
- spentTodayCiphertext,
219
- }, now);
220
- spinner.succeed("Scalar guardrails configured");
221
- if (ctx.output.json) {
222
- emitJson(ctx.output, { treasury: treasuryState.treasury, signature });
223
- return;
224
- }
225
- printSuccess(ctx.output, `Scalar guardrails configured: ${signature}`);
226
- });
227
- guardrails
228
- .command("vector")
229
- .description("Attach a vector guardrail ciphertext account")
230
- .option("--agent-id <id>", "treasury agent ID")
231
- .option("--treasury <pda>", "treasury PDA")
232
- .option("--guardrail-ciphertext <pubkey>", "guardrail vector ciphertext account")
233
- .action(async function confidentialGuardrailsVector() {
234
- const ctx = buildCliContext(this);
235
- if (!ctx.wallet) {
236
- throw new Error("A wallet is required to configure vector guardrails.");
237
- }
238
- const options = this.opts();
239
- const treasuryState = await resolveTreasuryAccount(ctx, {
240
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
241
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
163
+ },
242
164
  });
243
- const existing = treasuryState.account.confidentialGuardrails?.guardrailVectorCiphertext;
244
- const guardrailVectorCiphertext = parsePublicKey(await promptString(typeof options["guardrailCiphertext"] === "string"
245
- ? options["guardrailCiphertext"]
246
- : existing?.toBase58(), "Guardrail vector ciphertext"), "Guardrail vector ciphertext");
247
- const now = Math.floor(Date.now() / 1000);
248
- if (ctx.dryRun) {
249
- const instruction = await ctx.client.configureConfidentialVectorGuardrailsInstruction({
250
- owner: ctx.wallet.publicKey,
251
- treasury: treasuryState.treasury,
252
- guardrailVectorCiphertext,
253
- }, now);
254
- emitJson(ctx.output, {
255
- action: "confidential.guardrails.vector",
256
- treasury: treasuryState.treasury,
257
- instruction: serializeInstruction(instruction),
258
- });
259
- return;
260
- }
261
- const spinner = startSpinner(ctx.output, "Configuring vector guardrails...");
262
- const signature = await ctx.client.configureConfidentialVectorGuardrails(ctx.wallet, {
263
- owner: ctx.wallet.publicKey,
264
- treasury: treasuryState.treasury,
265
- guardrailVectorCiphertext,
266
- }, now);
267
- spinner.succeed("Vector guardrails configured");
268
- if (ctx.output.json) {
269
- emitJson(ctx.output, { treasury: treasuryState.treasury, signature });
270
- return;
271
- }
272
- printSuccess(ctx.output, `Vector guardrails configured: ${signature}`);
273
165
  });
166
+ // --- status ----------------------------------------------------------
274
167
  confidential
275
168
  .command("status")
276
169
  .description("Show confidential guardrails and pending confidential state")
@@ -280,8 +173,8 @@ export function registerConfidentialCommands(program) {
280
173
  const ctx = buildCliContext(this);
281
174
  const options = this.opts();
282
175
  const treasuryState = await resolveTreasuryAccount(ctx, {
283
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
284
- 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,
285
178
  });
286
179
  const sections = renderTreasurySections(treasuryState.treasury, treasuryState.account);
287
180
  if (ctx.output.json) {
@@ -293,17 +186,14 @@ export function registerConfidentialCommands(program) {
293
186
  return;
294
187
  }
295
188
  printBanner(ctx.output, `Confidential: ${treasuryState.account.agentId}`);
296
- if (sections.confidential) {
297
- console.log(sections.confidential);
298
- }
299
- else {
300
- console.log("No confidential guardrails configured.");
301
- }
189
+ console.log(sections.confidential ??
190
+ style.muted("No confidential guardrails configured."));
302
191
  if (sections.pending) {
303
192
  console.log("");
304
193
  console.log(sections.pending);
305
194
  }
306
195
  });
196
+ // --- propose ---------------------------------------------------------
307
197
  confidential
308
198
  .command("propose")
309
199
  .description("Propose a confidential scalar transaction")
@@ -318,404 +208,214 @@ export function registerConfidentialCommands(program) {
318
208
  .option("--actual-output <usd>", "actual output in USD", Number)
319
209
  .option("--quote-age <secs>", "quote age in seconds", Number)
320
210
  .option("--counterparty-risk <score>", "counterparty risk score", Number)
321
- .option("--amount-ciphertext <pubkey>", "use a pre-created verified Encrypt ciphertext instead of auto-encrypting")
322
- .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")
323
213
  .option("--wait", "wait until the policy output ciphertext is verified")
324
214
  .action(async function confidentialPropose() {
325
215
  const ctx = buildCliContext(this);
326
- if (!ctx.wallet) {
327
- throw new Error("A wallet is required to submit a confidential proposal.");
328
- }
216
+ const wallet = requireWallet(ctx);
329
217
  const options = this.opts();
330
218
  const treasuryState = await resolveTreasuryAccount(ctx, {
331
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
332
- 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,
333
221
  });
334
222
  const guardrails = resolveScalarGuardrails(treasuryState.account);
335
- const amountUsd = await promptNumber(typeof options["amount"] === "number" ? options["amount"] : undefined, "Amount (USD)", { validate: (value) => { if (value <= 0)
336
- throw new Error("Amount must be > 0"); } });
337
- const chain = await promptChain(typeof options["chain"] === "string" || typeof options["chain"] === "number"
338
- ? 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
339
231
  : undefined, "Chain");
340
- const recipient = await promptString(typeof options["recipient"] === "string" ? options["recipient"] : undefined, "Recipient");
341
- const txType = await promptTransactionType(typeof options["txType"] === "string" || typeof options["txType"] === "number"
342
- ? 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
343
235
  : undefined, "Transaction type");
344
236
  const args = buildProposeConfidentialArgs({
345
237
  amountUsd,
346
238
  chain,
347
239
  txType,
348
240
  recipient,
349
- protocolId: typeof options["protocolId"] === "number" ? options["protocolId"] : undefined,
350
- expectedOutputUsd: typeof options["expectedOutput"] === "number" ? options["expectedOutput"] : undefined,
351
- actualOutputUsd: typeof options["actualOutput"] === "number" ? options["actualOutput"] : undefined,
352
- quoteAgeSecs: typeof options["quoteAge"] === "number" ? options["quoteAge"] : undefined,
353
- counterpartyRiskScore: typeof options["counterpartyRisk"] === "number"
354
- ? 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
355
253
  : undefined,
356
- });
357
- const policyOutputSigner = buildDryRunKeypair(typeof options["policyOutputKeypair"] === "string"
358
- ? options["policyOutputKeypair"]
359
- : undefined, loadKeypair);
360
- const encryptAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
361
- auraProgramId: ctx.programId,
362
254
  });
363
255
  if (ctx.dryRun) {
364
- emitJson(ctx.output, {
365
- action: "confidential.propose",
366
- treasury: treasuryState.treasury,
367
- policyOutputCiphertext: policyOutputSigner.publicKey,
368
- encryptAccounts,
369
- args,
370
- note: typeof options["amountCiphertext"] === "string"
371
- ? "using pre-created amount ciphertext"
372
- : "would auto-encrypt amount via Ika Encrypt gRPC",
373
- });
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
+ }
374
264
  return;
375
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
+ });
376
272
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
377
273
  await ensureEncryptDeposit({
378
274
  connection: ctx.connection,
379
- payer: ctx.wallet,
275
+ payer: wallet,
380
276
  auraProgramId: ctx.programId,
381
277
  });
382
- // Resolve the amount ciphertext — auto-encrypt if not provided
383
278
  let amountCiphertext;
384
- if (typeof options["amountCiphertext"] === "string") {
385
- amountCiphertext = parsePublicKey(options["amountCiphertext"], "Amount ciphertext");
279
+ if (typeof options.amountCiphertext === "string") {
280
+ amountCiphertext = parsePublicKey(options.amountCiphertext, "amount-ciphertext");
386
281
  }
387
282
  else {
388
- spinner.setText(`Encrypting amount (${amountUsd} USD) via Ika Encrypt...`);
283
+ spinner.setText(`Encrypting amount ($${amountUsd}) via Ika Encrypt...`);
389
284
  amountCiphertext = await encryptU64(amountUsd, ctx.programId);
390
285
  spinner.setText("Waiting for amount ciphertext to be verified on-chain...");
391
286
  await waitForCiphertextVerified(ctx.connection, amountCiphertext);
392
287
  }
393
- const instruction = await ctx.client.proposeConfidentialTransactionInstruction({
394
- aiAuthority: ctx.wallet.publicKey,
395
- treasury: treasuryState.treasury,
396
- dailyLimitCiphertext: guardrails.dailyLimitCiphertext,
397
- perTxLimitCiphertext: guardrails.perTxLimitCiphertext,
398
- spentTodayCiphertext: guardrails.spentTodayCiphertext,
399
- amountCiphertext,
400
- policyOutputCiphertext: policyOutputSigner.publicKey,
401
- encryptProgram: encryptAccounts.encryptProgram,
402
- config: encryptAccounts.config,
403
- deposit: encryptAccounts.deposit,
404
- callerProgram: ctx.programId,
405
- cpiAuthority: encryptAccounts.cpiAuthority,
406
- networkEncryptionKey: encryptAccounts.networkEncryptionKey,
407
- eventAuthority: encryptAccounts.eventAuthority,
408
- systemProgram: SystemProgram.programId,
409
- }, args);
410
- markInstructionSigner(instruction, policyOutputSigner.publicKey);
411
- spinner.setText("Submitting confidential proposal...");
412
- const signature = await sendPreparedInstruction({
413
- ctx,
414
- instruction,
415
- extraSigners: [policyOutputSigner],
416
- });
417
- if (options["wait"] === true) {
418
- spinner.setText("Waiting for output ciphertext verification...");
419
- await waitForCiphertextVerified(ctx.connection, policyOutputSigner.publicKey);
420
- }
421
- spinner.succeed("Confidential proposal submitted");
422
- if (ctx.output.json) {
423
- emitJson(ctx.output, {
288
+ spinner.succeed("Amount ciphertext ready");
289
+ const instruction = await instructions.confidential.proposeConfidentialTransaction(ctx.client, {
290
+ accounts: {
291
+ aiAuthority: wallet.publicKey,
424
292
  treasury: treasuryState.treasury,
425
- signature,
293
+ dailyLimitCiphertext: guardrails.dailyLimitCiphertext,
294
+ perTxLimitCiphertext: guardrails.perTxLimitCiphertext,
295
+ spentTodayCiphertext: guardrails.spentTodayCiphertext,
426
296
  amountCiphertext,
427
297
  policyOutputCiphertext: policyOutputSigner.publicKey,
428
- });
429
- return;
430
- }
431
- printSuccess(ctx.output, `Confidential proposal submitted: ${signature}\n amount ciphertext: ${amountCiphertext.toBase58()}\n output ciphertext: ${policyOutputSigner.publicKey.toBase58()}`);
432
- });
433
- confidential
434
- .command("propose-vector")
435
- .description("Propose a confidential vector transaction and execute vector FHE")
436
- .option("--agent-id <id>", "treasury agent ID")
437
- .option("--treasury <pda>", "treasury PDA")
438
- .option("--amount <usd>", "amount in USD — auto-encrypted into vector helper ciphertexts", Number)
439
- .option("--chain <name|number>", "target chain")
440
- .option("--recipient <address>", "recipient address or contract")
441
- .option("--tx-type <type>", "transaction type")
442
- .option("--protocol-id <id>", "protocol ID", Number)
443
- .option("--expected-output <usd>", "expected output in USD", Number)
444
- .option("--actual-output <usd>", "actual output in USD", Number)
445
- .option("--quote-age <secs>", "quote age in seconds", Number)
446
- .option("--counterparty-risk <score>", "counterparty risk score", Number)
447
- .option("--spend-delta-ciphertext <pubkey>", "pre-created vector ciphertext for [-amount mod u64, 0, amount]")
448
- .option("--comparison-ciphertext <pubkey>", "pre-created vector ciphertext for [amount, amount]")
449
- .option("--flag-indices-ciphertext <pubkey>", "pre-created vector ciphertext for assign lanes [3,4,5,...]")
450
- .option("--policy-output-ciphertext <pubkey>", "pre-created zero EUint64Vector output ciphertext")
451
- .option("--wait", "wait until the vector policy output ciphertext is verified")
452
- .action(async function confidentialProposeVector() {
453
- const ctx = buildCliContext(this);
454
- if (!ctx.wallet) {
455
- throw new Error("A wallet is required to submit a confidential vector proposal.");
456
- }
457
- const options = this.opts();
458
- const treasuryState = await resolveTreasuryAccount(ctx, {
459
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
460
- treasury: typeof options["treasury"] === "string" ? options["treasury"] : undefined,
461
- });
462
- const guardrailVectorCiphertext = resolveVectorGuardrail(treasuryState.account);
463
- const amountUsd = await promptNumber(typeof options["amount"] === "number" ? options["amount"] : undefined, "Amount (USD)", { validate: (value) => { if (value <= 0)
464
- throw new Error("Amount must be > 0"); } });
465
- const chain = await promptChain(typeof options["chain"] === "string" || typeof options["chain"] === "number"
466
- ? options["chain"]
467
- : undefined, "Chain");
468
- const recipient = await promptString(typeof options["recipient"] === "string" ? options["recipient"] : undefined, "Recipient");
469
- const txType = await promptTransactionType(typeof options["txType"] === "string" || typeof options["txType"] === "number"
470
- ? options["txType"]
471
- : undefined, "Transaction type");
472
- const args = buildProposeConfidentialArgs({
473
- amountUsd,
474
- chain,
475
- txType,
476
- recipient,
477
- protocolId: typeof options["protocolId"] === "number" ? options["protocolId"] : undefined,
478
- expectedOutputUsd: typeof options["expectedOutput"] === "number" ? options["expectedOutput"] : undefined,
479
- actualOutputUsd: typeof options["actualOutput"] === "number" ? options["actualOutput"] : undefined,
480
- quoteAgeSecs: typeof options["quoteAge"] === "number" ? options["quoteAge"] : undefined,
481
- counterpartyRiskScore: typeof options["counterpartyRisk"] === "number"
482
- ? options["counterpartyRisk"]
483
- : undefined,
484
- });
485
- const suppliedInputs = {
486
- spendDeltaVectorCiphertext: parseOptionalPubkeyOption(options, "spendDeltaCiphertext", "Spend delta ciphertext"),
487
- comparisonVectorCiphertext: parseOptionalPubkeyOption(options, "comparisonCiphertext", "Comparison ciphertext"),
488
- flagIndicesVectorCiphertext: parseOptionalPubkeyOption(options, "flagIndicesCiphertext", "Flag indices ciphertext"),
489
- policyOutputVectorCiphertext: parseOptionalPubkeyOption(options, "policyOutputCiphertext", "Policy output ciphertext"),
490
- };
491
- const suppliedCount = Object.values(suppliedInputs).filter(Boolean).length;
492
- if (suppliedCount > 0 && suppliedCount < 4) {
493
- throw new Error("Vector proposal ciphertext overrides must include spend-delta, comparison, flag-indices, and policy-output accounts together.");
494
- }
495
- const encryptAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
496
- auraProgramId: ctx.programId,
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,
497
312
  });
498
- const proposalId = new BN(treasuryState.account.nextProposalId.toString());
499
- const executeArgs = {
500
- proposalId,
501
- currentTimestamp: new BN(args.currentTimestamp.toString()).addn(1),
502
- };
503
- if (ctx.dryRun && suppliedCount === 0) {
504
- emitJson(ctx.output, {
505
- action: "confidential.propose-vector",
506
- treasury: treasuryState.treasury,
507
- guardrailVectorCiphertext,
508
- encryptAccounts,
509
- args,
510
- executeArgs,
511
- note: "dry-run: would create spend-delta, comparison, flag-indices, and zero output EUint64Vector ciphertexts via Ika Encrypt gRPC",
512
- });
513
- return;
514
- }
515
- const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
516
- if (!ctx.dryRun) {
517
- await ensureEncryptDeposit({
518
- connection: ctx.connection,
519
- payer: ctx.wallet,
520
- auraProgramId: ctx.programId,
521
- });
522
- }
523
- let spendDeltaVectorCiphertext = suppliedInputs.spendDeltaVectorCiphertext;
524
- let comparisonVectorCiphertext = suppliedInputs.comparisonVectorCiphertext;
525
- let flagIndicesVectorCiphertext = suppliedInputs.flagIndicesVectorCiphertext;
526
- let policyOutputVectorCiphertext = suppliedInputs.policyOutputVectorCiphertext;
527
- if (suppliedCount === 0) {
528
- spinner.setText("Encrypting vector helper ciphertexts via Ika Encrypt...");
529
- const amount = BigInt(amountUsd);
530
- [
531
- spendDeltaVectorCiphertext,
532
- comparisonVectorCiphertext,
533
- flagIndicesVectorCiphertext,
534
- policyOutputVectorCiphertext,
535
- ] = await Promise.all([
536
- encryptU64Vector([wrappingNegU64(amount), 0n, amount], ctx.programId),
537
- encryptU64Vector([amount, amount], ctx.programId),
538
- encryptU64Vector(vectorFlagIndices(), ctx.programId),
539
- encryptU64Vector([], ctx.programId),
540
- ]);
541
- }
542
- if (!spendDeltaVectorCiphertext ||
543
- !comparisonVectorCiphertext ||
544
- !flagIndicesVectorCiphertext ||
545
- !policyOutputVectorCiphertext) {
546
- throw new Error("Vector helper ciphertext resolution failed.");
547
- }
548
- if (!ctx.dryRun) {
549
- spinner.setText("Waiting for vector ciphertexts to be verified on-chain...");
550
- await Promise.all([
551
- waitForCiphertextVerified(ctx.connection, spendDeltaVectorCiphertext, {
552
- timeoutMs: VECTOR_CIPHERTEXT_TIMEOUT_MS,
553
- }),
554
- waitForCiphertextVerified(ctx.connection, comparisonVectorCiphertext, {
555
- timeoutMs: VECTOR_CIPHERTEXT_TIMEOUT_MS,
556
- }),
557
- waitForCiphertextVerified(ctx.connection, flagIndicesVectorCiphertext, {
558
- timeoutMs: VECTOR_CIPHERTEXT_TIMEOUT_MS,
559
- }),
560
- waitForCiphertextVerified(ctx.connection, policyOutputVectorCiphertext, {
561
- timeoutMs: VECTOR_CIPHERTEXT_TIMEOUT_MS,
562
- }),
563
- ]);
564
- }
565
- const proposeInstruction = await ctx.client.proposeConfidentialVectorTransactionInstruction({
566
- aiAuthority: ctx.wallet.publicKey,
567
- treasury: treasuryState.treasury,
568
- guardrailVectorCiphertext,
569
- spendDeltaVectorCiphertext,
570
- comparisonVectorCiphertext,
571
- flagIndicesVectorCiphertext,
572
- policyResultVectorCiphertext: policyOutputVectorCiphertext,
573
- encryptProgram: encryptAccounts.encryptProgram,
574
- }, args);
575
- const executeInstruction = await ctx.client.executePendingVectorFheInstruction({
576
- aiAuthority: ctx.wallet.publicKey,
577
- treasury: treasuryState.treasury,
578
- guardrailVectorCiphertext,
579
- spendDeltaVectorCiphertext,
580
- comparisonVectorCiphertext,
581
- flagIndicesVectorCiphertext,
582
- policyResultVectorCiphertext: policyOutputVectorCiphertext,
583
- encryptProgram: encryptAccounts.encryptProgram,
584
- config: encryptAccounts.config,
585
- deposit: encryptAccounts.deposit,
586
- callerProgram: ctx.programId,
587
- cpiAuthority: encryptAccounts.cpiAuthority,
588
- networkEncryptionKey: encryptAccounts.networkEncryptionKey,
589
- eventAuthority: encryptAccounts.eventAuthority,
590
- systemProgram: SystemProgram.programId,
591
- }, executeArgs);
592
- if (ctx.dryRun) {
593
- emitJson(ctx.output, {
594
- action: "confidential.propose-vector",
313
+ // The freshly created output ciphertext account must sign its own creation.
314
+ markInstructionSigner(instruction, policyOutputSigner.publicKey);
315
+ const outcome = await runInstructions(ctx, [instruction], {
316
+ action: "Propose confidential transaction",
317
+ instructionName: "propose_confidential_transaction",
318
+ extraSigners: [policyOutputSigner],
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: {
595
326
  treasury: treasuryState.treasury,
596
- spendDeltaVectorCiphertext,
597
- comparisonVectorCiphertext,
598
- flagIndicesVectorCiphertext,
599
- policyOutputVectorCiphertext,
600
- instructions: {
601
- propose: serializeInstruction(proposeInstruction),
602
- executeVectorFhe: serializeInstruction(executeInstruction),
603
- },
604
- });
605
- return;
606
- }
607
- spinner.setText("Submitting vector confidential proposal...");
608
- const signature = await sendPreparedInstruction({
609
- ctx,
610
- instruction: proposeInstruction,
611
- });
612
- spinner.setText("Executing vector FHE graph...");
613
- const executeSignature = await sendPreparedInstruction({
614
- ctx,
615
- instruction: executeInstruction,
327
+ amountCiphertext,
328
+ policyOutputCiphertext: policyOutputSigner.publicKey,
329
+ },
616
330
  });
617
- if (options["wait"] === true) {
618
- spinner.setText("Waiting for vector policy output verification...");
619
- await waitForCiphertextVerified(ctx.connection, policyOutputVectorCiphertext, {
620
- timeoutMs: VECTOR_CIPHERTEXT_TIMEOUT_MS,
621
- });
622
- }
623
- spinner.succeed("Vector confidential proposal submitted");
624
- if (ctx.output.json) {
625
- emitJson(ctx.output, {
626
- treasury: treasuryState.treasury,
627
- signature,
628
- executeSignature,
629
- spendDeltaVectorCiphertext,
630
- comparisonVectorCiphertext,
631
- flagIndicesVectorCiphertext,
632
- policyOutputCiphertext: policyOutputVectorCiphertext,
633
- });
634
- return;
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");
635
335
  }
636
- printSuccess(ctx.output, `Vector confidential proposal submitted:\n propose: ${signature}\n execute FHE: ${executeSignature}\n output ciphertext: ${policyOutputVectorCiphertext.toBase58()}`);
637
336
  });
337
+ // --- request-decryption ---------------------------------------------
638
338
  confidential
639
339
  .command("request-decryption")
640
340
  .description("Request Encrypt decryption for the pending policy output")
641
341
  .option("--agent-id <id>", "treasury agent ID")
642
342
  .option("--treasury <pda>", "treasury PDA")
643
343
  .option("--ciphertext <pubkey>", "override the pending policy output ciphertext")
644
- .option("--request-keypair <path>", "optional keypair path for the decryption request account")
344
+ .option("--request-keypair <path>", "keypair path for the decryption request account")
645
345
  .option("--wait", "wait until the plaintext is ready on-chain")
646
346
  .action(async function confidentialRequestDecryption() {
647
347
  const ctx = buildCliContext(this);
648
- if (!ctx.wallet) {
649
- throw new Error("A wallet is required to request policy decryption.");
650
- }
348
+ const wallet = requireWallet(ctx);
651
349
  const options = this.opts();
652
350
  const treasuryState = await resolveTreasuryAccount(ctx, {
653
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
654
- 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,
655
353
  });
656
- const ciphertext = typeof options["ciphertext"] === "string"
657
- ? parsePublicKey(options["ciphertext"], "Ciphertext")
354
+ const ciphertext = typeof options.ciphertext === "string"
355
+ ? parsePublicKey(options.ciphertext, "ciphertext")
658
356
  : resolvePendingPolicyOutput(treasuryState.account);
659
- const requestSigner = buildDryRunKeypair(typeof options["requestKeypair"] === "string"
660
- ? options["requestKeypair"]
661
- : undefined, loadKeypair);
662
- const encryptAccounts = deriveEncryptAccounts(ctx.wallet.publicKey, {
663
- auraProgramId: ctx.programId,
664
- });
665
- const now = Math.floor(Date.now() / 1000);
666
- const instruction = await ctx.client.requestPolicyDecryptionInstruction({
667
- operator: ctx.wallet.publicKey,
668
- treasury: treasuryState.treasury,
669
- requestAccount: requestSigner.publicKey,
670
- ciphertext,
671
- encryptProgram: encryptAccounts.encryptProgram,
672
- config: encryptAccounts.config,
673
- deposit: encryptAccounts.deposit,
674
- callerProgram: ctx.programId,
675
- cpiAuthority: encryptAccounts.cpiAuthority,
676
- networkEncryptionKey: encryptAccounts.networkEncryptionKey,
677
- eventAuthority: encryptAccounts.eventAuthority,
678
- systemProgram: SystemProgram.programId,
679
- }, now);
680
- markInstructionSigner(instruction, requestSigner.publicKey);
681
357
  if (ctx.dryRun) {
682
- emitJson(ctx.output, {
683
- action: "confidential.request-decryption",
684
- treasury: treasuryState.treasury,
685
- ciphertext,
686
- requestAccount: requestSigner.publicKey,
687
- instruction: serializeInstruction(instruction),
688
- });
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
+ }
689
366
  return;
690
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
+ });
691
374
  const spinner = startSpinner(ctx.output, "Ensuring Encrypt deposit account...");
692
- const depositResult = await ensureEncryptDeposit({
375
+ await ensureEncryptDeposit({
693
376
  connection: ctx.connection,
694
- payer: ctx.wallet,
377
+ payer: wallet,
695
378
  auraProgramId: ctx.programId,
696
379
  });
697
- spinner.setText("Submitting decryption request...");
698
- const signature = await sendPreparedInstruction({
699
- ctx,
700
- instruction,
701
- 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) },
702
398
  });
703
- if (options["wait"] === true) {
704
- spinner.setText("Waiting for decrypted plaintext...");
705
- await waitForDecryptionReady(ctx.connection, requestSigner.publicKey);
706
- }
707
- spinner.succeed("Policy decryption requested");
708
- if (ctx.output.json) {
709
- 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: {
710
408
  treasury: treasuryState.treasury,
711
- signature,
712
409
  requestAccount: requestSigner.publicKey,
713
- deposit: depositResult,
714
- });
715
- 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");
716
416
  }
717
- printSuccess(ctx.output, `Policy decryption requested: ${signature} (request ${requestSigner.publicKey.toBase58()})`);
718
417
  });
418
+ // --- confirm-decryption ---------------------------------------------
719
419
  confidential
720
420
  .command("confirm-decryption")
721
421
  .description("Confirm a completed policy decryption request on-chain")
@@ -724,72 +424,51 @@ export function registerConfidentialCommands(program) {
724
424
  .option("--request-account <pubkey>", "override the pending decryption request account")
725
425
  .action(async function confidentialConfirmDecryption() {
726
426
  const ctx = buildCliContext(this);
727
- if (!ctx.wallet) {
728
- throw new Error("A wallet is required to confirm policy decryption.");
729
- }
427
+ const wallet = requireWallet(ctx);
730
428
  const options = this.opts();
731
429
  const treasuryState = await resolveTreasuryAccount(ctx, {
732
- agentId: typeof options["agentId"] === "string" ? options["agentId"] : undefined,
733
- 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,
734
432
  });
735
- const requestAccount = typeof options["requestAccount"] === "string"
736
- ? parsePublicKey(options["requestAccount"], "Request account")
433
+ const requestAccount = typeof options.requestAccount === "string"
434
+ ? parsePublicKey(options.requestAccount, "request-account")
737
435
  : resolvePendingRequestAccount(treasuryState.account);
738
- const now = Math.floor(Date.now() / 1000);
739
- if (ctx.dryRun) {
740
- const instruction = await ctx.client.confirmPolicyDecryptionInstruction({
741
- operator: ctx.wallet.publicKey,
742
- treasury: treasuryState.treasury,
743
- requestAccount,
744
- }, now);
745
- emitJson(ctx.output, {
746
- action: "confidential.confirm-decryption",
436
+ const instruction = await instructions.confidential.confirmPolicyDecryption(ctx.client, {
437
+ accounts: {
438
+ operator: wallet.publicKey,
747
439
  treasury: treasuryState.treasury,
748
440
  requestAccount,
749
- instruction: serializeInstruction(instruction),
750
- });
751
- return;
752
- }
753
- const spinner = startSpinner(ctx.output, "Confirming policy decryption...");
754
- const signature = await ctx.client.confirmPolicyDecryption(ctx.wallet, {
755
- operator: ctx.wallet.publicKey,
756
- treasury: treasuryState.treasury,
757
- requestAccount,
758
- }, now);
759
- // Read scalar decrypted policy outputs for display. Vector outputs encode
760
- // state and flags across lanes, so the on-chain decision is clearer.
761
- let violationCode = null;
762
- try {
763
- const pendingBeforeConfirm = getActivePendingProposal(treasuryState.account);
764
- if (pendingBeforeConfirm?.policyOutputFheType !== 35) {
765
- spinner.setText("Reading decrypted policy result from Encrypt network...");
766
- const policyOutput = resolvePendingPolicyOutput(treasuryState.account);
767
- violationCode = await readU64Ciphertext(policyOutput, ctx.wallet.publicKey);
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.
768
470
  }
769
471
  }
770
- catch {
771
- // Non-fatal — the on-chain state is the source of truth
772
- }
773
- spinner.succeed("Policy decryption confirmed");
774
- const refreshed = await ctx.client.getTreasuryAccount(treasuryState.treasury);
775
- const decision = getActivePendingProposal(refreshed)?.decision;
776
- if (ctx.output.json) {
777
- emitJson(ctx.output, {
778
- treasury: treasuryState.treasury,
779
- requestAccount,
780
- signature,
781
- approved: decision?.approved ?? null,
782
- violation: decision?.violation ?? null,
783
- violationCode: violationCode !== null ? violationCode.toString() : null,
784
- });
785
- return;
786
- }
787
- const resultLine = decision
788
- ? decision.approved
789
- ? "approved ✓"
790
- : `denied — violation code ${violationCode ?? decision.violation}`
791
- : "";
792
- printSuccess(ctx.output, `Policy decryption confirmed: ${signature}${resultLine ? `\n result: ${resultLine}` : ""}`);
793
472
  });
794
473
  }
795
474
  //# sourceMappingURL=confidential.js.map