@veilo/sdk-core 0.3.3 → 0.5.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.
- package/LICENSE +15 -0
- package/README.md +289 -1262
- package/dist/cjs/accounts/admin.d.ts +84 -0
- package/dist/cjs/accounts/admin.js +208 -0
- package/dist/cjs/accounts/errors.d.ts +6 -0
- package/dist/cjs/accounts/errors.js +98 -0
- package/dist/cjs/accounts/index.d.ts +4 -0
- package/dist/cjs/accounts/index.js +20 -0
- package/dist/cjs/accounts/pdas.d.ts +23 -0
- package/dist/cjs/accounts/pdas.js +44 -0
- package/dist/cjs/accounts/queries.d.ts +41 -0
- package/dist/cjs/accounts/queries.js +95 -0
- package/dist/cjs/client.d.ts +2 -407
- package/dist/cjs/client.js +17 -912
- package/dist/cjs/cloak/client.d.ts +28 -0
- package/dist/cjs/cloak/client.js +68 -0
- package/dist/cjs/cloak/errors.d.ts +13 -0
- package/dist/cjs/cloak/errors.js +25 -0
- package/dist/cjs/cloak/helpers.d.ts +6 -0
- package/dist/cjs/cloak/helpers.js +35 -0
- package/dist/cjs/cloak/index.d.ts +6 -0
- package/dist/cjs/cloak/index.js +24 -0
- package/dist/cjs/cloak/polling.d.ts +7 -0
- package/dist/cjs/cloak/polling.js +66 -0
- package/dist/cjs/cloak/transport.d.ts +15 -0
- package/dist/cjs/cloak/transport.js +119 -0
- package/dist/cjs/cloak/types.d.ts +188 -0
- package/dist/cjs/cloak/types.js +5 -0
- package/dist/cjs/cloak.d.ts +1 -0
- package/dist/cjs/cloak.js +18 -0
- package/dist/cjs/compactNote.d.ts +128 -0
- package/dist/cjs/compactNote.js +191 -0
- package/dist/cjs/events.d.ts +1 -1
- package/dist/cjs/events.js +2 -2
- package/dist/cjs/idl/privacy_pool.d.ts +5 -0
- package/dist/cjs/idl/privacy_pool.js +15218 -0
- package/dist/cjs/index.d.ts +17 -13
- package/dist/cjs/index.js +43 -30
- package/dist/cjs/merkle.d.ts +13 -0
- package/dist/cjs/merkle.js +31 -8
- package/dist/cjs/notes/encryption.d.ts +41 -0
- package/dist/cjs/notes/encryption.js +75 -0
- package/dist/cjs/notes/index.d.ts +5 -0
- package/dist/cjs/notes/index.js +21 -0
- package/dist/cjs/notes/mailbox.d.ts +70 -0
- package/dist/cjs/notes/mailbox.js +164 -0
- package/dist/cjs/notes/model.d.ts +91 -0
- package/dist/cjs/notes/model.js +109 -0
- package/dist/cjs/notes/nullifier.d.ts +27 -0
- package/dist/cjs/notes/nullifier.js +45 -0
- package/dist/cjs/notes/recovery.d.ts +10 -0
- package/dist/cjs/notes/recovery.js +31 -0
- package/dist/cjs/program.d.ts +11 -0
- package/dist/cjs/program.js +26 -3
- package/dist/cjs/proof.d.ts +1 -183
- package/dist/cjs/proof.js +16 -290
- package/dist/cjs/proofs/encoding.d.ts +17 -0
- package/dist/cjs/proofs/encoding.js +72 -0
- package/dist/cjs/proofs/formatting.d.ts +6 -0
- package/dist/cjs/proofs/formatting.js +34 -0
- package/dist/cjs/proofs/index.d.ts +5 -0
- package/dist/cjs/proofs/index.js +21 -0
- package/dist/cjs/proofs/swap.d.ts +87 -0
- package/dist/cjs/proofs/swap.js +144 -0
- package/dist/cjs/proofs/transaction.d.ts +28 -0
- package/dist/cjs/proofs/transaction.js +110 -0
- package/dist/cjs/proofs/types.d.ts +70 -0
- package/dist/cjs/proofs/types.js +2 -0
- package/dist/cjs/prover.d.ts +4 -1
- package/dist/cjs/prover.js +12 -2
- package/dist/cjs/random.d.ts +16 -0
- package/dist/cjs/random.js +28 -0
- package/dist/cjs/relayer/client.d.ts +61 -0
- package/dist/cjs/relayer/client.js +151 -0
- package/dist/cjs/relayer/crypto.d.ts +5 -0
- package/dist/cjs/relayer/crypto.js +26 -0
- package/dist/cjs/relayer/encoding.d.ts +2 -0
- package/dist/cjs/relayer/encoding.js +23 -0
- package/dist/cjs/relayer/errors.d.ts +7 -0
- package/dist/cjs/relayer/errors.js +17 -0
- package/dist/cjs/relayer/index.d.ts +3 -0
- package/dist/cjs/relayer/index.js +19 -0
- package/dist/cjs/relayer/transport.d.ts +17 -0
- package/dist/cjs/relayer/transport.js +63 -0
- package/dist/cjs/relayer/types.d.ts +276 -0
- package/dist/cjs/relayer/types.js +5 -0
- package/dist/cjs/relayer.d.ts +1 -295
- package/dist/cjs/relayer.js +15 -243
- package/dist/cjs/shield/alt.d.ts +87 -0
- package/dist/cjs/shield/alt.js +194 -0
- package/dist/cjs/shield/computeBudget.d.ts +61 -0
- package/dist/cjs/shield/computeBudget.js +64 -0
- package/dist/cjs/shield/errors.d.ts +58 -0
- package/dist/cjs/shield/errors.js +121 -0
- package/dist/cjs/shield/finalize.d.ts +45 -0
- package/dist/cjs/shield/finalize.js +119 -0
- package/dist/cjs/shield/index.d.ts +35 -0
- package/dist/cjs/shield/index.js +68 -0
- package/dist/cjs/shield/ix.d.ts +54 -0
- package/dist/cjs/shield/ix.js +119 -0
- package/dist/cjs/shield/owner.d.ts +36 -0
- package/dist/cjs/shield/owner.js +127 -0
- package/dist/cjs/shield/ports.d.ts +43 -0
- package/dist/cjs/shield/ports.js +153 -0
- package/dist/cjs/shield/preflight.d.ts +30 -0
- package/dist/cjs/shield/preflight.js +154 -0
- package/dist/cjs/shield/shield.d.ts +68 -0
- package/dist/cjs/shield/shield.js +500 -0
- package/dist/cjs/shield/types.d.ts +202 -0
- package/dist/cjs/shield/types.js +2 -0
- package/dist/cjs/transactions/deposit.d.ts +94 -0
- package/dist/cjs/transactions/deposit.js +234 -0
- package/dist/cjs/transactions/index.d.ts +7 -0
- package/dist/cjs/transactions/index.js +26 -0
- package/dist/cjs/transactions/swap.d.ts +71 -0
- package/dist/cjs/transactions/swap.js +184 -0
- package/dist/cjs/transactions/transact.d.ts +34 -0
- package/dist/cjs/transactions/transact.js +146 -0
- package/dist/cjs/transactions/transfer.d.ts +51 -0
- package/dist/cjs/transactions/transfer.js +106 -0
- package/dist/cjs/transactions/withdraw.d.ts +52 -0
- package/dist/cjs/transactions/withdraw.js +104 -0
- package/dist/cjs/utxo.d.ts +1 -215
- package/dist/cjs/utxo.js +15 -391
- package/dist/esm/accounts/admin.d.ts +84 -0
- package/dist/esm/accounts/admin.js +165 -0
- package/dist/esm/accounts/errors.d.ts +6 -0
- package/dist/esm/accounts/errors.js +95 -0
- package/dist/esm/accounts/index.d.ts +4 -0
- package/dist/esm/accounts/index.js +4 -0
- package/dist/esm/accounts/pdas.d.ts +23 -0
- package/dist/esm/accounts/pdas.js +38 -0
- package/dist/esm/accounts/queries.d.ts +41 -0
- package/dist/esm/accounts/queries.js +88 -0
- package/dist/esm/client.d.ts +2 -0
- package/dist/esm/client.js +3 -887
- package/dist/esm/cloak/client.d.ts +28 -0
- package/dist/esm/cloak/client.js +64 -0
- package/dist/esm/cloak/errors.d.ts +13 -0
- package/dist/esm/cloak/errors.js +21 -0
- package/dist/esm/cloak/helpers.d.ts +6 -0
- package/dist/esm/cloak/helpers.js +31 -0
- package/dist/esm/cloak/index.d.ts +6 -0
- package/dist/esm/cloak/index.js +6 -0
- package/dist/esm/cloak/polling.d.ts +7 -0
- package/dist/esm/cloak/polling.js +63 -0
- package/dist/esm/cloak/transport.d.ts +15 -0
- package/dist/esm/cloak/transport.js +115 -0
- package/dist/esm/cloak/types.d.ts +188 -0
- package/dist/esm/cloak/types.js +4 -0
- package/dist/esm/cloak.d.ts +1 -0
- package/dist/esm/cloak.js +2 -0
- package/dist/esm/compactNote.d.ts +128 -0
- package/dist/esm/compactNote.js +179 -0
- package/dist/esm/config.d.ts +82 -0
- package/dist/esm/events.d.ts +77 -0
- package/dist/esm/events.js +1 -1
- package/dist/esm/idl/privacy_pool.d.ts +5 -0
- package/dist/esm/idl/privacy_pool.js +15216 -0
- package/dist/esm/index.d.ts +17 -0
- package/dist/esm/index.js +20 -11
- package/dist/esm/merkle.d.ts +77 -0
- package/dist/esm/merkle.js +23 -1
- package/dist/esm/notes/encryption.d.ts +41 -0
- package/dist/esm/notes/encryption.js +67 -0
- package/dist/esm/notes/index.d.ts +5 -0
- package/dist/esm/notes/index.js +5 -0
- package/dist/esm/notes/mailbox.d.ts +70 -0
- package/dist/esm/notes/mailbox.js +154 -0
- package/dist/esm/notes/model.d.ts +91 -0
- package/dist/esm/notes/model.js +99 -0
- package/dist/esm/notes/nullifier.d.ts +27 -0
- package/dist/esm/notes/nullifier.js +40 -0
- package/dist/esm/notes/recovery.d.ts +10 -0
- package/dist/esm/notes/recovery.js +28 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/poseidon.d.ts +29 -0
- package/dist/esm/program.d.ts +37 -0
- package/dist/esm/program.js +23 -1
- package/dist/esm/proof.d.ts +1 -0
- package/dist/esm/proof.js +2 -281
- package/dist/esm/proofs/encoding.d.ts +17 -0
- package/dist/esm/proofs/encoding.js +68 -0
- package/dist/esm/proofs/formatting.d.ts +6 -0
- package/dist/esm/proofs/formatting.js +31 -0
- package/dist/esm/proofs/index.d.ts +5 -0
- package/dist/esm/proofs/index.js +5 -0
- package/dist/esm/proofs/swap.d.ts +87 -0
- package/dist/esm/proofs/swap.js +138 -0
- package/dist/esm/proofs/transaction.d.ts +28 -0
- package/dist/esm/proofs/transaction.js +105 -0
- package/dist/esm/proofs/types.d.ts +70 -0
- package/dist/esm/proofs/types.js +1 -0
- package/dist/esm/prover.d.ts +57 -0
- package/dist/esm/prover.js +10 -1
- package/dist/esm/random.d.ts +16 -0
- package/dist/esm/random.js +21 -0
- package/dist/esm/relayer/client.d.ts +61 -0
- package/dist/esm/relayer/client.js +144 -0
- package/dist/esm/relayer/crypto.d.ts +5 -0
- package/dist/esm/relayer/crypto.js +20 -0
- package/dist/esm/relayer/encoding.d.ts +2 -0
- package/dist/esm/relayer/encoding.js +19 -0
- package/dist/esm/relayer/errors.d.ts +7 -0
- package/dist/esm/relayer/errors.js +13 -0
- package/dist/esm/relayer/index.d.ts +3 -0
- package/dist/esm/relayer/index.js +3 -0
- package/dist/esm/relayer/transport.d.ts +17 -0
- package/dist/esm/relayer/transport.js +59 -0
- package/dist/esm/relayer/types.d.ts +276 -0
- package/dist/esm/relayer/types.js +4 -0
- package/dist/esm/relayer.d.ts +1 -0
- package/dist/esm/relayer.js +2 -238
- package/dist/esm/retry.d.ts +32 -0
- package/dist/esm/shield/alt.d.ts +87 -0
- package/dist/esm/shield/alt.js +186 -0
- package/dist/esm/shield/computeBudget.d.ts +61 -0
- package/dist/esm/shield/computeBudget.js +61 -0
- package/dist/esm/shield/errors.d.ts +58 -0
- package/dist/esm/shield/errors.js +115 -0
- package/dist/esm/shield/finalize.d.ts +45 -0
- package/dist/esm/shield/finalize.js +83 -0
- package/dist/esm/shield/index.d.ts +35 -0
- package/dist/esm/shield/index.js +32 -0
- package/dist/esm/shield/ix.d.ts +54 -0
- package/dist/esm/shield/ix.js +82 -0
- package/dist/esm/shield/owner.d.ts +36 -0
- package/dist/esm/shield/owner.js +123 -0
- package/dist/esm/shield/ports.d.ts +43 -0
- package/dist/esm/shield/ports.js +147 -0
- package/dist/esm/shield/preflight.d.ts +30 -0
- package/dist/esm/shield/preflight.js +151 -0
- package/dist/esm/shield/shield.d.ts +68 -0
- package/dist/esm/shield/shield.js +493 -0
- package/dist/esm/shield/types.d.ts +202 -0
- package/dist/esm/shield/types.js +1 -0
- package/dist/esm/transactions/deposit.d.ts +94 -0
- package/dist/esm/transactions/deposit.js +198 -0
- package/dist/esm/transactions/index.d.ts +7 -0
- package/dist/esm/transactions/index.js +7 -0
- package/dist/esm/transactions/swap.d.ts +71 -0
- package/dist/esm/transactions/swap.js +144 -0
- package/dist/esm/transactions/transact.d.ts +34 -0
- package/dist/esm/transactions/transact.js +110 -0
- package/dist/esm/transactions/transfer.d.ts +51 -0
- package/dist/esm/transactions/transfer.js +103 -0
- package/dist/esm/transactions/withdraw.d.ts +52 -0
- package/dist/esm/transactions/withdraw.js +101 -0
- package/dist/esm/utxo.d.ts +1 -0
- package/dist/esm/utxo.js +2 -372
- package/package.json +111 -15
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
/**
|
|
3
|
+
* Error taxonomy for the shield path.
|
|
4
|
+
*
|
|
5
|
+
* `parseOnChainError` already turns program codes into readable sentences. What
|
|
6
|
+
* it does not give you is a *decision*: can this be retried, and how? That is
|
|
7
|
+
* what integrators actually need, because the three retry classes have wildly
|
|
8
|
+
* different costs:
|
|
9
|
+
*
|
|
10
|
+
* - `rebuild` — reuse the proof, new blockhash. Milliseconds.
|
|
11
|
+
* - `reshield` — the proof is stale, prove again. 10–30 seconds.
|
|
12
|
+
* - `none` — retrying cannot help; something must change first.
|
|
13
|
+
*/
|
|
14
|
+
export type ShieldRetryClass = "rebuild" | "reshield" | "none";
|
|
15
|
+
export type ShieldErrorCode = "POOL_NOT_FOUND" | "POOL_PAUSED" | "AMOUNT_BELOW_MINIMUM" | "AMOUNT_ABOVE_MAXIMUM" | "TREE_FULL" | "INSUFFICIENT_SOL" | "INSUFFICIENT_TOKEN_BALANCE" | "TOKEN_ACCOUNT_MISSING" | "TOKEN_ACCOUNT_WRONG_MINT" | "TOKEN_ACCOUNT_WRONG_OWNER" | "TOKEN_ACCOUNT_DELEGATED" | "TOKEN_ACCOUNT_FROZEN" | "VAULT_ATA_MISSING" | "ALT_NOT_FOUND" | "ALT_INCOMPLETE" | "TX_TOO_LARGE" | "OWNER_INVARIANT_UNACKNOWLEDGED" | "UNRESOLVED_ACCOUNT" | "BLOCKHASH_EXPIRED" | "DEADLINE_EXPIRED" | "ROOT_STALE" | "NULLIFIER_COLLISION" | "COMPUTE_BUDGET_EXCEEDED" | "PROOF_REJECTED" | "UNKNOWN";
|
|
16
|
+
export type ShieldErrorRemedy = {
|
|
17
|
+
/** Human-readable description of what would fix this. */
|
|
18
|
+
description: string;
|
|
19
|
+
/** Instructions that, once executed, clear the condition. */
|
|
20
|
+
instructions: TransactionInstruction[];
|
|
21
|
+
};
|
|
22
|
+
export declare class ShieldError extends Error {
|
|
23
|
+
readonly code: ShieldErrorCode;
|
|
24
|
+
/** Program error code (6000–6060) when this was derived from a chain error. */
|
|
25
|
+
readonly programCode?: number;
|
|
26
|
+
/** Whether and how a retry can succeed. */
|
|
27
|
+
readonly retryable: ShieldRetryClass;
|
|
28
|
+
/** Machine-readable detail: which account, what value, what was expected. */
|
|
29
|
+
readonly context?: Record<string, unknown>;
|
|
30
|
+
/** Present when the condition is fixable by executing instructions first. */
|
|
31
|
+
readonly remedy?: ShieldErrorRemedy;
|
|
32
|
+
readonly cause?: unknown;
|
|
33
|
+
constructor(code: ShieldErrorCode, message: string, opts?: {
|
|
34
|
+
programCode?: number;
|
|
35
|
+
retryable?: ShieldRetryClass;
|
|
36
|
+
context?: Record<string, unknown>;
|
|
37
|
+
remedy?: ShieldErrorRemedy;
|
|
38
|
+
cause?: unknown;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/** Extract a privacy_pool program error code from an arbitrary thrown value. */
|
|
42
|
+
export declare function extractProgramCode(error: any): number | null;
|
|
43
|
+
/**
|
|
44
|
+
* Map a submission failure onto the taxonomy.
|
|
45
|
+
*
|
|
46
|
+
* Two mappings here are not obvious and are worth stating plainly:
|
|
47
|
+
*
|
|
48
|
+
* **Nullifier collision means "already landed", not "already spent."** The
|
|
49
|
+
* marker PDAs are `init`, not `init_if_needed`, so a second submission of the
|
|
50
|
+
* same shield fails at account resolution. For a deposit the nullifiers derive
|
|
51
|
+
* from freshly generated random keys, so a genuine collision is impossible —
|
|
52
|
+
* in practice this only ever means the first attempt succeeded. Telling a user
|
|
53
|
+
* their funds were "already spent" here would be alarming and wrong.
|
|
54
|
+
*
|
|
55
|
+
* **`UnknownRoot` is recoverable but not by `rebuild()`.** The proof commits to
|
|
56
|
+
* the root, so a stale root needs a fresh proof, not a fresh blockhash.
|
|
57
|
+
*/
|
|
58
|
+
export declare function mapShieldError(error: unknown): ShieldError;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { parseOnChainError } from "../accounts/errors.js";
|
|
2
|
+
export class ShieldError extends Error {
|
|
3
|
+
constructor(code, message, opts = {}) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "ShieldError";
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.programCode = opts.programCode;
|
|
8
|
+
this.retryable = opts.retryable ?? "none";
|
|
9
|
+
this.context = opts.context;
|
|
10
|
+
this.remedy = opts.remedy;
|
|
11
|
+
this.cause = opts.cause;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** Extract a privacy_pool program error code from an arbitrary thrown value. */
|
|
15
|
+
export function extractProgramCode(error) {
|
|
16
|
+
const raw = (error?.message ?? error?.toString() ?? "").toLowerCase();
|
|
17
|
+
const hex = raw.match(/custom program error:\s*0x([0-9a-f]+)/);
|
|
18
|
+
if (hex)
|
|
19
|
+
return parseInt(hex[1], 16);
|
|
20
|
+
const num = raw.match(/error number:\s*(\d+)/);
|
|
21
|
+
if (num)
|
|
22
|
+
return parseInt(num[1], 10);
|
|
23
|
+
if (typeof error?.error?.errorCode?.number === "number") {
|
|
24
|
+
return error.error.errorCode.number;
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Map a submission failure onto the taxonomy.
|
|
30
|
+
*
|
|
31
|
+
* Two mappings here are not obvious and are worth stating plainly:
|
|
32
|
+
*
|
|
33
|
+
* **Nullifier collision means "already landed", not "already spent."** The
|
|
34
|
+
* marker PDAs are `init`, not `init_if_needed`, so a second submission of the
|
|
35
|
+
* same shield fails at account resolution. For a deposit the nullifiers derive
|
|
36
|
+
* from freshly generated random keys, so a genuine collision is impossible —
|
|
37
|
+
* in practice this only ever means the first attempt succeeded. Telling a user
|
|
38
|
+
* their funds were "already spent" here would be alarming and wrong.
|
|
39
|
+
*
|
|
40
|
+
* **`UnknownRoot` is recoverable but not by `rebuild()`.** The proof commits to
|
|
41
|
+
* the root, so a stale root needs a fresh proof, not a fresh blockhash.
|
|
42
|
+
*/
|
|
43
|
+
export function mapShieldError(error) {
|
|
44
|
+
if (error instanceof ShieldError)
|
|
45
|
+
return error;
|
|
46
|
+
const err = error;
|
|
47
|
+
const raw = (err?.message ?? String(err ?? "")).toLowerCase();
|
|
48
|
+
const programCode = extractProgramCode(err);
|
|
49
|
+
const readable = parseOnChainError(err);
|
|
50
|
+
if (programCode !== null) {
|
|
51
|
+
switch (programCode) {
|
|
52
|
+
case 6000:
|
|
53
|
+
return new ShieldError("POOL_PAUSED", readable, { programCode, cause: err });
|
|
54
|
+
case 6007:
|
|
55
|
+
return new ShieldError("ROOT_STALE", "The Merkle root this shield was proven against is no longer in the on-chain " +
|
|
56
|
+
"history. Build a new shield — the proof cannot be reused.", { programCode, retryable: "reshield", cause: err });
|
|
57
|
+
case 6012:
|
|
58
|
+
return new ShieldError("PROOF_REJECTED", readable, { programCode, cause: err });
|
|
59
|
+
case 6013:
|
|
60
|
+
return new ShieldError("TREE_FULL", readable, {
|
|
61
|
+
programCode,
|
|
62
|
+
retryable: "reshield",
|
|
63
|
+
cause: err,
|
|
64
|
+
});
|
|
65
|
+
case 6017:
|
|
66
|
+
return new ShieldError("TOKEN_ACCOUNT_WRONG_MINT", readable, {
|
|
67
|
+
programCode,
|
|
68
|
+
cause: err,
|
|
69
|
+
});
|
|
70
|
+
case 6029:
|
|
71
|
+
return new ShieldError("TOKEN_ACCOUNT_DELEGATED", "The source token account has an active delegate. Revoke it, then shield again.", { programCode, cause: err });
|
|
72
|
+
case 6033:
|
|
73
|
+
return new ShieldError("TOKEN_ACCOUNT_WRONG_OWNER", "The source token account is not owned by the signing wallet.", { programCode, cause: err });
|
|
74
|
+
case 6035:
|
|
75
|
+
return new ShieldError("AMOUNT_BELOW_MINIMUM", readable, { programCode, cause: err });
|
|
76
|
+
case 6036:
|
|
77
|
+
return new ShieldError("AMOUNT_ABOVE_MAXIMUM", readable, { programCode, cause: err });
|
|
78
|
+
case 6050:
|
|
79
|
+
return new ShieldError("VAULT_ATA_MISSING", readable, { programCode, cause: err });
|
|
80
|
+
case 6005:
|
|
81
|
+
case 6046:
|
|
82
|
+
case 6052:
|
|
83
|
+
return new ShieldError("NULLIFIER_COLLISION", ALREADY_SHIELDED_MESSAGE, {
|
|
84
|
+
programCode,
|
|
85
|
+
cause: err,
|
|
86
|
+
});
|
|
87
|
+
case 6060:
|
|
88
|
+
return new ShieldError("DEADLINE_EXPIRED", "The shield's deadline passed before it landed. Rebuild it — the proof is still valid.", { programCode, retryable: "rebuild", cause: err });
|
|
89
|
+
default:
|
|
90
|
+
return new ShieldError("UNKNOWN", readable, { programCode, cause: err });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Non-program failures.
|
|
94
|
+
if (raw.includes("block height exceeded") ||
|
|
95
|
+
raw.includes("blockhash not found") ||
|
|
96
|
+
err?.name === "TransactionExpiredBlockheightExceededError") {
|
|
97
|
+
return new ShieldError("BLOCKHASH_EXPIRED", "The blockhash expired before the shield landed. Rebuild it — the proof is still valid.", { retryable: "rebuild", cause: err });
|
|
98
|
+
}
|
|
99
|
+
if (raw.includes("already in use")) {
|
|
100
|
+
return new ShieldError("NULLIFIER_COLLISION", ALREADY_SHIELDED_MESSAGE, { cause: err });
|
|
101
|
+
}
|
|
102
|
+
if (raw.includes("exceeded cus") ||
|
|
103
|
+
raw.includes("computational budget exceeded") ||
|
|
104
|
+
raw.includes("exceeded compute")) {
|
|
105
|
+
return new ShieldError("COMPUTE_BUDGET_EXCEEDED", `The shield exceeded its compute budget. Real usage has grown past the reserved ` +
|
|
106
|
+
`limit — SHIELD_COMPUTE_UNIT_LIMIT needs revisiting.`, { cause: err });
|
|
107
|
+
}
|
|
108
|
+
if (raw.includes("too large") || raw.includes("transaction too large")) {
|
|
109
|
+
return new ShieldError("TX_TOO_LARGE", readable, { cause: err });
|
|
110
|
+
}
|
|
111
|
+
return new ShieldError("UNKNOWN", readable, { cause: err });
|
|
112
|
+
}
|
|
113
|
+
const ALREADY_SHIELDED_MESSAGE = "This shield has already been submitted — check the transaction signature before " +
|
|
114
|
+
"retrying. (The nullifier markers already exist on-chain, which for a deposit means " +
|
|
115
|
+
"the original transaction landed; it does not mean the funds were spent.)";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Connection, PublicKey } from "@solana/web3.js";
|
|
2
|
+
import type { ShieldNote, ShieldOwner } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Read the authoritative leaf index for a landed shield, and produce the
|
|
5
|
+
* mailbox blob for optional relayer delivery.
|
|
6
|
+
*
|
|
7
|
+
* ## Why this is a separate step
|
|
8
|
+
*
|
|
9
|
+
* Every existing deposit implementation records `tree.nextIndex` read *before*
|
|
10
|
+
* submission as the note's leaf index. Under concurrent deposits into the same
|
|
11
|
+
* tree that value is wrong, and it is wrong permanently — the stored index is
|
|
12
|
+
* what a later withdrawal builds its Merkle path from, so the note becomes
|
|
13
|
+
* unspendable through the normal path.
|
|
14
|
+
*
|
|
15
|
+
* That race is rare for a single wallet and constant for an SDK: a platform
|
|
16
|
+
* batching shields for many users will hit it routinely. So `shield()` reports
|
|
17
|
+
* only a `predictedLeafIndex`, and the real one is read here from the
|
|
18
|
+
* transaction's own `CommitmentEvent` after it confirms.
|
|
19
|
+
*
|
|
20
|
+
* ## What is optional
|
|
21
|
+
*
|
|
22
|
+
* Everything, strictly. The note is recoverable from chain data alone via the
|
|
23
|
+
* on-chain compact cipher, so a caller that skips finalization has not lost the
|
|
24
|
+
* funds — only the fast path to finding them. Persist nothing that depends on a
|
|
25
|
+
* leaf index without calling this first.
|
|
26
|
+
*/
|
|
27
|
+
export declare function finalizeShield(params: {
|
|
28
|
+
connection: Connection;
|
|
29
|
+
signature: string;
|
|
30
|
+
note: ShieldNote;
|
|
31
|
+
owner: ShieldOwner;
|
|
32
|
+
programId?: PublicKey;
|
|
33
|
+
/** Defaults to "confirmed". Use "finalized" if the index will be persisted. */
|
|
34
|
+
commitment?: "confirmed" | "finalized";
|
|
35
|
+
}): Promise<{
|
|
36
|
+
leafIndex: number;
|
|
37
|
+
newRoot: Uint8Array;
|
|
38
|
+
treeId: number;
|
|
39
|
+
slot: number;
|
|
40
|
+
/** Encrypted note blob, ready for POST /notes/save if the caller wants mailbox delivery. */
|
|
41
|
+
blob: {
|
|
42
|
+
ephemeralPublicKey: Uint8Array;
|
|
43
|
+
encryptedBlob: string;
|
|
44
|
+
};
|
|
45
|
+
}>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as anchor from "@coral-xyz/anchor";
|
|
2
|
+
import { PRIVACY_POOL_IDL, PRIVACY_POOL_PROGRAM_ID } from "../program.js";
|
|
3
|
+
import { encryptBlindMailboxNote } from "../notes/mailbox.js";
|
|
4
|
+
import { bigIntToBytesBE } from "../poseidon.js";
|
|
5
|
+
import { ShieldError } from "./errors.js";
|
|
6
|
+
/**
|
|
7
|
+
* Read the authoritative leaf index for a landed shield, and produce the
|
|
8
|
+
* mailbox blob for optional relayer delivery.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this is a separate step
|
|
11
|
+
*
|
|
12
|
+
* Every existing deposit implementation records `tree.nextIndex` read *before*
|
|
13
|
+
* submission as the note's leaf index. Under concurrent deposits into the same
|
|
14
|
+
* tree that value is wrong, and it is wrong permanently — the stored index is
|
|
15
|
+
* what a later withdrawal builds its Merkle path from, so the note becomes
|
|
16
|
+
* unspendable through the normal path.
|
|
17
|
+
*
|
|
18
|
+
* That race is rare for a single wallet and constant for an SDK: a platform
|
|
19
|
+
* batching shields for many users will hit it routinely. So `shield()` reports
|
|
20
|
+
* only a `predictedLeafIndex`, and the real one is read here from the
|
|
21
|
+
* transaction's own `CommitmentEvent` after it confirms.
|
|
22
|
+
*
|
|
23
|
+
* ## What is optional
|
|
24
|
+
*
|
|
25
|
+
* Everything, strictly. The note is recoverable from chain data alone via the
|
|
26
|
+
* on-chain compact cipher, so a caller that skips finalization has not lost the
|
|
27
|
+
* funds — only the fast path to finding them. Persist nothing that depends on a
|
|
28
|
+
* leaf index without calling this first.
|
|
29
|
+
*/
|
|
30
|
+
export async function finalizeShield(params) {
|
|
31
|
+
const { connection, signature, note, owner, programId = PRIVACY_POOL_PROGRAM_ID, commitment = "confirmed", } = params;
|
|
32
|
+
const tx = await connection.getTransaction(signature, {
|
|
33
|
+
commitment: commitment === "finalized" ? "finalized" : "confirmed",
|
|
34
|
+
maxSupportedTransactionVersion: 0,
|
|
35
|
+
});
|
|
36
|
+
if (!tx) {
|
|
37
|
+
throw new ShieldError("UNKNOWN", `Transaction ${signature} not found at ${commitment} commitment. ` +
|
|
38
|
+
`If it was just submitted, wait for confirmation and retry.`, { context: { signature } });
|
|
39
|
+
}
|
|
40
|
+
if (tx.meta?.err) {
|
|
41
|
+
throw new ShieldError("UNKNOWN", `Transaction ${signature} failed on-chain; there is no note to finalize.`, { context: { signature, err: tx.meta.err } });
|
|
42
|
+
}
|
|
43
|
+
const parser = new anchor.EventParser(programId, new anchor.BorshCoder(PRIVACY_POOL_IDL));
|
|
44
|
+
const wantCommitment = Buffer.from(note.commitment).toString("hex");
|
|
45
|
+
let match = null;
|
|
46
|
+
for (const event of parser.parseLogs(tx.meta?.logMessages ?? [])) {
|
|
47
|
+
if (event.name !== "CommitmentEvent" && event.name !== "commitmentEvent")
|
|
48
|
+
continue;
|
|
49
|
+
const data = event.data;
|
|
50
|
+
const emitted = Buffer.from(data.commitment).toString("hex");
|
|
51
|
+
if (emitted === wantCommitment) {
|
|
52
|
+
match = data;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (!match) {
|
|
57
|
+
throw new ShieldError("UNKNOWN", `Transaction ${signature} landed but emitted no CommitmentEvent for this note's ` +
|
|
58
|
+
`commitment. The note may belong to a different transaction.`, { context: { signature, commitment: wantCommitment } });
|
|
59
|
+
}
|
|
60
|
+
const leafIndex = Number(match.leafIndex ?? match.leaf_index);
|
|
61
|
+
const treeId = Number(match.treeId ?? match.tree_id ?? note.treeId);
|
|
62
|
+
const newRoot = new Uint8Array(match.newRoot ?? match.new_root);
|
|
63
|
+
// Mailbox copy. Sending this to the relayer with a `recipientWalletPublicKey`
|
|
64
|
+
// buys instant delivery and a push notification, at the cost of writing the
|
|
65
|
+
// sender→recipient association into the relayer's database AND removing the
|
|
66
|
+
// note from the chain-recovery feed. For shield-to-someone-else, chain-only
|
|
67
|
+
// discovery is usually the better default — see the plan's Phase 3 note.
|
|
68
|
+
const blob = encryptBlindMailboxNote(owner.noteViewingKey.toBytes(), {
|
|
69
|
+
blinding: bigIntToBytesBE(note.blinding),
|
|
70
|
+
leafIndex,
|
|
71
|
+
commitment: note.commitment,
|
|
72
|
+
amount: note.amount,
|
|
73
|
+
mintAddress: note.mint.toBase58(),
|
|
74
|
+
treeId,
|
|
75
|
+
});
|
|
76
|
+
return {
|
|
77
|
+
leafIndex,
|
|
78
|
+
newRoot,
|
|
79
|
+
treeId,
|
|
80
|
+
slot: tx.slot,
|
|
81
|
+
blob,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet-agnostic shielding.
|
|
3
|
+
*
|
|
4
|
+
* `shield()` builds an unsigned transaction that deposits public funds into the
|
|
5
|
+
* privacy pool, creating a note owned by an arbitrary recipient. Any external
|
|
6
|
+
* wallet — a browser extension, or a third-party platform's managed wallet —
|
|
7
|
+
* signs and submits it. The SDK never touches a secret key.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const owner = await resolveShieldOwner({ username: "alice" });
|
|
11
|
+
* const { transaction, note, proofCache } = await shield({
|
|
12
|
+
* connection, amount, mint, owner,
|
|
13
|
+
* signer: { publicKey: wallet.publicKey },
|
|
14
|
+
* prover: createTransactionProver(artifacts),
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const signed = await wallet.signTransaction(transaction);
|
|
18
|
+
* const sig = await connection.sendRawTransaction(signed.serialize());
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* On blockhash expiry, `rebuild(result, { connection })` re-assembles with a
|
|
22
|
+
* fresh blockhash and deadline without re-proving.
|
|
23
|
+
*/
|
|
24
|
+
export { shield, rebuild, serializeProofCache, deserializeProofCache } from "./shield.js";
|
|
25
|
+
export { resolveShieldOwner, unsafeShieldOwner } from "./owner.js";
|
|
26
|
+
export { finalizeShield } from "./finalize.js";
|
|
27
|
+
export { preflightShield } from "./preflight.js";
|
|
28
|
+
export { buildTransactInstruction, TRANSACT_ACCOUNT_NAMES } from "./ix.js";
|
|
29
|
+
export type { TransactAccounts, TransactArgs } from "./ix.js";
|
|
30
|
+
export { sharedDepositAlt, explicitAlt, auditDepositAlt, expectedDepositAltKeys, requiredAltKeys, SHARED_DEPOSIT_ALT, SHARED_ALT_MINTS, } from "./alt.js";
|
|
31
|
+
export { onChainTreeSource, staticTreeSource, memoryCache, noCache } from "./ports.js";
|
|
32
|
+
export { ShieldError, mapShieldError, extractProgramCode, } from "./errors.js";
|
|
33
|
+
export type { ShieldErrorCode, ShieldRetryClass, ShieldErrorRemedy } from "./errors.js";
|
|
34
|
+
export { SHIELD_COMPUTE_UNIT_LIMIT, SHIELD_COMPUTE_UNIT_PRICE_MICRO_LAMPORTS, SHIELD_COMPUTE_UNITS_MEASURED_TYPICAL, MAX_TRANSACTION_BYTES, SIGNATURE_BYTES, TRANSACT_INSTRUCTION_DATA_BYTES, NULLIFIER_MARKER_ACCOUNT_BYTES, NULLIFIER_MARKERS_PER_TRANSACT, DEFAULT_DEADLINE_SECONDS, } from "./computeBudget.js";
|
|
35
|
+
export type { ShieldOwner, ShieldSigner, ShieldParams, ShieldResult, ShieldNote, ShieldProofCache, ShieldQuote, TreeSource, AltSource, ShieldCachePort, DepositTarget, PreflightOptions, } from "./types.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wallet-agnostic shielding.
|
|
3
|
+
*
|
|
4
|
+
* `shield()` builds an unsigned transaction that deposits public funds into the
|
|
5
|
+
* privacy pool, creating a note owned by an arbitrary recipient. Any external
|
|
6
|
+
* wallet — a browser extension, or a third-party platform's managed wallet —
|
|
7
|
+
* signs and submits it. The SDK never touches a secret key.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* const owner = await resolveShieldOwner({ username: "alice" });
|
|
11
|
+
* const { transaction, note, proofCache } = await shield({
|
|
12
|
+
* connection, amount, mint, owner,
|
|
13
|
+
* signer: { publicKey: wallet.publicKey },
|
|
14
|
+
* prover: createTransactionProver(artifacts),
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const signed = await wallet.signTransaction(transaction);
|
|
18
|
+
* const sig = await connection.sendRawTransaction(signed.serialize());
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* On blockhash expiry, `rebuild(result, { connection })` re-assembles with a
|
|
22
|
+
* fresh blockhash and deadline without re-proving.
|
|
23
|
+
*/
|
|
24
|
+
export { shield, rebuild, serializeProofCache, deserializeProofCache } from "./shield.js";
|
|
25
|
+
export { resolveShieldOwner, unsafeShieldOwner } from "./owner.js";
|
|
26
|
+
export { finalizeShield } from "./finalize.js";
|
|
27
|
+
export { preflightShield } from "./preflight.js";
|
|
28
|
+
export { buildTransactInstruction, TRANSACT_ACCOUNT_NAMES } from "./ix.js";
|
|
29
|
+
export { sharedDepositAlt, explicitAlt, auditDepositAlt, expectedDepositAltKeys, requiredAltKeys, SHARED_DEPOSIT_ALT, SHARED_ALT_MINTS, } from "./alt.js";
|
|
30
|
+
export { onChainTreeSource, staticTreeSource, memoryCache, noCache } from "./ports.js";
|
|
31
|
+
export { ShieldError, mapShieldError, extractProgramCode, } from "./errors.js";
|
|
32
|
+
export { SHIELD_COMPUTE_UNIT_LIMIT, SHIELD_COMPUTE_UNIT_PRICE_MICRO_LAMPORTS, SHIELD_COMPUTE_UNITS_MEASURED_TYPICAL, MAX_TRANSACTION_BYTES, SIGNATURE_BYTES, TRANSACT_INSTRUCTION_DATA_BYTES, NULLIFIER_MARKER_ACCOUNT_BYTES, NULLIFIER_MARKERS_PER_TRANSACT, DEFAULT_DEADLINE_SECONDS, } from "./computeBudget.js";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import type { TransactionProofStruct } from "../proofs/types.js";
|
|
3
|
+
/**
|
|
4
|
+
* `transact` instruction assembly, driven by the IDL rather than by a
|
|
5
|
+
* hand-written account list.
|
|
6
|
+
*
|
|
7
|
+
* Every existing deposit implementation spells out all sixteen accounts by hand
|
|
8
|
+
* in an `accountsStrict({...})` literal. That works until the IDL changes, at
|
|
9
|
+
* which point a silently misordered or missing account produces a runtime
|
|
10
|
+
* failure that is very hard to trace. Here the account list and the ordering
|
|
11
|
+
* come from the IDL itself, and an unresolved name throws at build time.
|
|
12
|
+
*
|
|
13
|
+
* Building the instruction directly also means no Anchor `Provider` and no
|
|
14
|
+
* `Wallet` — which is the whole point of a wallet-agnostic shield.
|
|
15
|
+
*/
|
|
16
|
+
/** Account names the IDL declares for `transact`, in order. */
|
|
17
|
+
export type TransactAccounts = Record<string, PublicKey>;
|
|
18
|
+
export type TransactArgs = {
|
|
19
|
+
root: Uint8Array;
|
|
20
|
+
inputTreeId: number;
|
|
21
|
+
outputTreeId: number;
|
|
22
|
+
publicAmount: bigint;
|
|
23
|
+
extDataHash: Uint8Array;
|
|
24
|
+
mintAddress: PublicKey;
|
|
25
|
+
inputNullifiers: [Uint8Array, Uint8Array];
|
|
26
|
+
outputCommitments: [Uint8Array, Uint8Array];
|
|
27
|
+
deadline: bigint;
|
|
28
|
+
extData: {
|
|
29
|
+
recipient: PublicKey;
|
|
30
|
+
relayer: PublicKey;
|
|
31
|
+
fee: bigint;
|
|
32
|
+
refund: bigint;
|
|
33
|
+
claimant: PublicKey;
|
|
34
|
+
};
|
|
35
|
+
proof: TransactionProofStruct;
|
|
36
|
+
noteCiphers: {
|
|
37
|
+
note0EphemeralKey: Uint8Array;
|
|
38
|
+
note0Encrypted: Uint8Array;
|
|
39
|
+
note0ViewTag: number;
|
|
40
|
+
note1EphemeralKey: Uint8Array;
|
|
41
|
+
note1Encrypted: Uint8Array;
|
|
42
|
+
note1ViewTag: number;
|
|
43
|
+
} | null;
|
|
44
|
+
};
|
|
45
|
+
/** Account names in IDL order. Exported so callers can see what must be resolved. */
|
|
46
|
+
export declare const TRANSACT_ACCOUNT_NAMES: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Build the `transact` instruction.
|
|
49
|
+
*
|
|
50
|
+
* @throws ShieldError('UNRESOLVED_ACCOUNT') if the IDL declares an account the
|
|
51
|
+
* caller did not supply — a loud failure is the point, because the
|
|
52
|
+
* alternative is a misordered account list that fails opaquely on-chain.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildTransactInstruction(accounts: TransactAccounts, args: TransactArgs, programId?: PublicKey): TransactionInstruction;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as anchor from "@coral-xyz/anchor";
|
|
2
|
+
import { TransactionInstruction, } from "@solana/web3.js";
|
|
3
|
+
import { PRIVACY_POOL_IDL, PRIVACY_POOL_PROGRAM_ID } from "../program.js";
|
|
4
|
+
import { ShieldError } from "./errors.js";
|
|
5
|
+
import { TRANSACT_INSTRUCTION_DATA_BYTES } from "./computeBudget.js";
|
|
6
|
+
// Anchor is CommonJS and does not expose BN as a detectable named export to
|
|
7
|
+
// Node ESM. Pull both runtime values from the namespace so CJS and ESM agree.
|
|
8
|
+
const { BN, BorshInstructionCoder } = anchor;
|
|
9
|
+
const IDL_TRANSACT = PRIVACY_POOL_IDL.instructions.find((i) => i.name === "transact");
|
|
10
|
+
if (!IDL_TRANSACT) {
|
|
11
|
+
throw new Error("privacy_pool IDL has no `transact` instruction");
|
|
12
|
+
}
|
|
13
|
+
/** Account names in IDL order. Exported so callers can see what must be resolved. */
|
|
14
|
+
export const TRANSACT_ACCOUNT_NAMES = IDL_TRANSACT.accounts.map((a) => a.name);
|
|
15
|
+
/**
|
|
16
|
+
* Build the `transact` instruction.
|
|
17
|
+
*
|
|
18
|
+
* @throws ShieldError('UNRESOLVED_ACCOUNT') if the IDL declares an account the
|
|
19
|
+
* caller did not supply — a loud failure is the point, because the
|
|
20
|
+
* alternative is a misordered account list that fails opaquely on-chain.
|
|
21
|
+
*/
|
|
22
|
+
export function buildTransactInstruction(accounts, args, programId = PRIVACY_POOL_PROGRAM_ID) {
|
|
23
|
+
const keys = IDL_TRANSACT.accounts.map((a) => {
|
|
24
|
+
const pubkey = accounts[a.name];
|
|
25
|
+
if (!pubkey) {
|
|
26
|
+
throw new ShieldError("UNRESOLVED_ACCOUNT", `The IDL declares account "${a.name}" for transact, but it was not resolved. ` +
|
|
27
|
+
`Expected accounts: ${TRANSACT_ACCOUNT_NAMES.join(", ")}`, { context: { missing: a.name, supplied: Object.keys(accounts) } });
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
pubkey,
|
|
31
|
+
isWritable: !!a.writable,
|
|
32
|
+
isSigner: !!a.signer,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
const coder = new BorshInstructionCoder(PRIVACY_POOL_IDL);
|
|
36
|
+
const data = coder.encode("transact", toBorshArgs(args));
|
|
37
|
+
if (data.length !== TRANSACT_INSTRUCTION_DATA_BYTES) {
|
|
38
|
+
// Not fatal — the size budget assertion downstream is authoritative — but a
|
|
39
|
+
// change here means the size arithmetic in computeBudget.ts is stale.
|
|
40
|
+
console.warn(`[veilo] transact instruction data is ${data.length} bytes, expected ` +
|
|
41
|
+
`${TRANSACT_INSTRUCTION_DATA_BYTES}. The shield size budget may no longer hold.`);
|
|
42
|
+
}
|
|
43
|
+
return new TransactionInstruction({ programId, keys, data });
|
|
44
|
+
}
|
|
45
|
+
/** Anchor's Borsh coder wants camelCase field names, BNs, and plain arrays. */
|
|
46
|
+
function toBorshArgs(args) {
|
|
47
|
+
return {
|
|
48
|
+
root: Array.from(args.root),
|
|
49
|
+
input_tree_id: args.inputTreeId,
|
|
50
|
+
output_tree_id: args.outputTreeId,
|
|
51
|
+
public_amount: new BN(args.publicAmount.toString()),
|
|
52
|
+
ext_data_hash: Array.from(args.extDataHash),
|
|
53
|
+
mint_address: args.mintAddress,
|
|
54
|
+
input_nullifier_0: Array.from(args.inputNullifiers[0]),
|
|
55
|
+
input_nullifier_1: Array.from(args.inputNullifiers[1]),
|
|
56
|
+
output_commitment_0: Array.from(args.outputCommitments[0]),
|
|
57
|
+
output_commitment_1: Array.from(args.outputCommitments[1]),
|
|
58
|
+
deadline: new BN(args.deadline.toString()),
|
|
59
|
+
ext_data: {
|
|
60
|
+
recipient: args.extData.recipient,
|
|
61
|
+
relayer: args.extData.relayer,
|
|
62
|
+
fee: new BN(args.extData.fee.toString()),
|
|
63
|
+
refund: new BN(args.extData.refund.toString()),
|
|
64
|
+
claimant: args.extData.claimant,
|
|
65
|
+
},
|
|
66
|
+
proof: {
|
|
67
|
+
proof_a: args.proof.proofA,
|
|
68
|
+
proof_b: args.proof.proofB,
|
|
69
|
+
proof_c: args.proof.proofC,
|
|
70
|
+
},
|
|
71
|
+
note_ciphers: args.noteCiphers
|
|
72
|
+
? {
|
|
73
|
+
note0_ephemeral_key: Array.from(args.noteCiphers.note0EphemeralKey),
|
|
74
|
+
note0_encrypted: Array.from(args.noteCiphers.note0Encrypted),
|
|
75
|
+
note0_view_tag: args.noteCiphers.note0ViewTag,
|
|
76
|
+
note1_ephemeral_key: Array.from(args.noteCiphers.note1EphemeralKey),
|
|
77
|
+
note1_encrypted: Array.from(args.noteCiphers.note1Encrypted),
|
|
78
|
+
note1_view_tag: args.noteCiphers.note1ViewTag,
|
|
79
|
+
}
|
|
80
|
+
: null,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import type { ShieldOwner } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a shield recipient into the pair of keys that must belong to the same
|
|
5
|
+
* account.
|
|
6
|
+
*
|
|
7
|
+
* This is the only mechanism that makes the owner invariant safe. A note's
|
|
8
|
+
* *spend* authority is a Poseidon field element and its *detection* authority is
|
|
9
|
+
* an Ed25519 wallet key; nothing on-chain relates them, and if an integrator
|
|
10
|
+
* sources them separately and gets them wrong, the note is spendable but
|
|
11
|
+
* permanently invisible — the funds are gone from the owner's view with no error
|
|
12
|
+
* raised anywhere in the stack.
|
|
13
|
+
*
|
|
14
|
+
* `GET /auth/veiloPublicKey` returns both halves in a single response, so
|
|
15
|
+
* routing through this function makes the pairing structural rather than a
|
|
16
|
+
* convention integrators are asked to remember.
|
|
17
|
+
*
|
|
18
|
+
* Prefer this over hand-building a {@link ShieldOwner} in all cases.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveShieldOwner(target: {
|
|
21
|
+
username: string;
|
|
22
|
+
} | {
|
|
23
|
+
publicKey: string | PublicKey;
|
|
24
|
+
}): Promise<ShieldOwner>;
|
|
25
|
+
/**
|
|
26
|
+
* Build a {@link ShieldOwner} from keys the caller already holds.
|
|
27
|
+
*
|
|
28
|
+
* Only correct when both keys provably belong to the same account. The explicit
|
|
29
|
+
* flag is not ceremony — it is the last checkpoint before a class of bug whose
|
|
30
|
+
* only symptom is a user's money quietly disappearing from their balance.
|
|
31
|
+
*/
|
|
32
|
+
export declare function unsafeShieldOwner(params: {
|
|
33
|
+
veiloPublicKey: bigint;
|
|
34
|
+
noteViewingKey: PublicKey;
|
|
35
|
+
acknowledgeOwnerInvariant: true;
|
|
36
|
+
}): ShieldOwner;
|