@dexterai/vault 0.1.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 (43) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +61 -0
  3. package/dist/constants/index.cjs +92 -0
  4. package/dist/constants/index.d.cts +34 -0
  5. package/dist/constants/index.d.ts +34 -0
  6. package/dist/constants/index.js +57 -0
  7. package/dist/counterfactual.cjs +138 -0
  8. package/dist/counterfactual.d.cts +17 -0
  9. package/dist/counterfactual.d.ts +17 -0
  10. package/dist/counterfactual.js +113 -0
  11. package/dist/index.cjs +140 -0
  12. package/dist/index.d.cts +2 -0
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +113 -0
  15. package/dist/instructions/index.cjs +5016 -0
  16. package/dist/instructions/index.d.cts +290 -0
  17. package/dist/instructions/index.d.ts +290 -0
  18. package/dist/instructions/index.js +4989 -0
  19. package/dist/messages/index.cjs +156 -0
  20. package/dist/messages/index.d.cts +89 -0
  21. package/dist/messages/index.d.ts +89 -0
  22. package/dist/messages/index.js +125 -0
  23. package/dist/precompile/index.cjs +192 -0
  24. package/dist/precompile/index.d.cts +45 -0
  25. package/dist/precompile/index.d.ts +45 -0
  26. package/dist/precompile/index.js +149 -0
  27. package/dist/reader/index.cjs +121 -0
  28. package/dist/reader/index.d.cts +41 -0
  29. package/dist/reader/index.d.ts +41 -0
  30. package/dist/reader/index.js +93 -0
  31. package/dist/signers/node/index.cjs +62 -0
  32. package/dist/signers/node/index.d.cts +21 -0
  33. package/dist/signers/node/index.d.ts +21 -0
  34. package/dist/signers/node/index.js +27 -0
  35. package/dist/signers/types.cjs +18 -0
  36. package/dist/signers/types.d.cts +34 -0
  37. package/dist/signers/types.d.ts +34 -0
  38. package/dist/signers/types.js +0 -0
  39. package/dist/types.cjs +18 -0
  40. package/dist/types.d.cts +104 -0
  41. package/dist/types.d.ts +104 -0
  42. package/dist/types.js +0 -0
  43. package/package.json +53 -0
@@ -0,0 +1,45 @@
1
+ import { TransactionInstruction } from '@solana/web3.js';
2
+
3
+ /**
4
+ * SIMD-0075 secp256r1 precompile builder + WebAuthn precompile message
5
+ * assembler.
6
+ *
7
+ * Place a secp256r1 verify instruction IMMEDIATELY before any vault
8
+ * instruction that takes a passkey-signed op (set_swig, register_session_key,
9
+ * revoke_session_key, request_withdrawal, finalize_withdrawal, force_release,
10
+ * rotate_passkey, prove_passkey). The vault program reads
11
+ * SYSVAR_INSTRUCTIONS to introspect the sibling and rejects unless it
12
+ * verifies.
13
+ */
14
+
15
+ declare const SIGNATURE_OFFSETS_SERIALIZED_SIZE = 14;
16
+ declare const SIGNATURE_SERIALIZED_SIZE = 64;
17
+ declare const COMPRESSED_PUBKEY_SERIALIZED_SIZE = 33;
18
+ declare const PRECOMPILE_DATA_START = 2;
19
+ declare function buildSecp256r1VerifyInstruction(publicKey: Uint8Array, // 33-byte compressed P-256
20
+ signature: Uint8Array, // 64-byte (r||s)
21
+ message: Uint8Array): TransactionInstruction;
22
+ /**
23
+ * Build the bytes the precompile verifies against the WebAuthn signature:
24
+ * authenticatorData || SHA-256(clientDataJSON)
25
+ *
26
+ * Works in Node (via `node:crypto`) and the browser (via SubtleCrypto).
27
+ */
28
+ declare function buildPrecompileMessage(clientDataJSON: Uint8Array, authenticatorData: Uint8Array): Promise<Uint8Array>;
29
+
30
+ /**
31
+ * Solana Ed25519 sigverify precompile builder.
32
+ *
33
+ * Layout matches solana-sdk/sdk/src/ed25519_instruction.rs byte-for-byte:
34
+ * u8 numSigs + u8 padding + 14-byte SignatureOffsets +
35
+ * contiguous pubkey(32) || signature(64) || message
36
+ *
37
+ * Place this BEFORE vault::settle_tab_voucher (or any future ix needing
38
+ * session-key verification) in the same tx.
39
+ */
40
+
41
+ declare function buildEd25519VerifyInstruction(pubkey: Uint8Array, // 32 bytes
42
+ signature: Uint8Array, // 64 bytes
43
+ message: Uint8Array): TransactionInstruction;
44
+
45
+ export { COMPRESSED_PUBKEY_SERIALIZED_SIZE, PRECOMPILE_DATA_START, SIGNATURE_OFFSETS_SERIALIZED_SIZE, SIGNATURE_SERIALIZED_SIZE, buildEd25519VerifyInstruction, buildPrecompileMessage, buildSecp256r1VerifyInstruction };
@@ -0,0 +1,149 @@
1
+ // src/precompile/secp256r1.ts
2
+ import { TransactionInstruction } from "@solana/web3.js";
3
+
4
+ // src/constants/index.ts
5
+ import { PublicKey } from "@solana/web3.js";
6
+ var DEXTER_VAULT_PROGRAM_ID = new PublicKey(
7
+ "Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"
8
+ );
9
+ var SWIG_PROGRAM_ID = new PublicKey(
10
+ "swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB"
11
+ );
12
+ var SECP256R1_PROGRAM_ID = new PublicKey(
13
+ "Secp256r1SigVerify1111111111111111111111111"
14
+ );
15
+ var ED25519_PROGRAM_ID = new PublicKey(
16
+ "Ed25519SigVerify111111111111111111111111111"
17
+ );
18
+ var INSTRUCTIONS_SYSVAR_ID = new PublicKey(
19
+ "Sysvar1nstructions1111111111111111111111111"
20
+ );
21
+ var VAULT_SEED_PREFIX = Buffer.from("vault");
22
+ var DISCRIMINATORS = Object.freeze({
23
+ initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
24
+ set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
25
+ settle_voucher: Uint8Array.from([144, 176, 128, 220, 156, 79, 41, 54]),
26
+ request_withdrawal: Uint8Array.from([251, 85, 121, 205, 56, 201, 12, 177]),
27
+ finalize_withdrawal: Uint8Array.from([178, 87, 206, 68, 201, 186, 164, 232]),
28
+ force_release: Uint8Array.from([122, 190, 243, 252, 54, 202, 208, 234]),
29
+ rotate_passkey: Uint8Array.from([28, 134, 49, 89, 196, 34, 58, 174]),
30
+ rotate_dexter_authority: Uint8Array.from([145, 60, 4, 119, 180, 205, 236, 134]),
31
+ prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
32
+ settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
33
+ register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
34
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151])
35
+ });
36
+ var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
37
+ const buf = new Uint8Array(32);
38
+ buf.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"), 0);
39
+ return buf;
40
+ })();
41
+ var OTS_SESSION_REVOKE_V1_DOMAIN = (() => {
42
+ const buf = new Uint8Array(32);
43
+ buf.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"), 0);
44
+ return buf;
45
+ })();
46
+
47
+ // src/precompile/secp256r1.ts
48
+ var SIGNATURE_OFFSETS_SERIALIZED_SIZE = 14;
49
+ var SIGNATURE_SERIALIZED_SIZE = 64;
50
+ var COMPRESSED_PUBKEY_SERIALIZED_SIZE = 33;
51
+ var PRECOMPILE_DATA_START = 2;
52
+ function buildSecp256r1VerifyInstruction(publicKey, signature, message) {
53
+ if (publicKey.length !== COMPRESSED_PUBKEY_SERIALIZED_SIZE) {
54
+ throw new Error(`expected ${COMPRESSED_PUBKEY_SERIALIZED_SIZE}-byte pubkey`);
55
+ }
56
+ if (signature.length !== SIGNATURE_SERIALIZED_SIZE) {
57
+ throw new Error(`expected ${SIGNATURE_SERIALIZED_SIZE}-byte signature`);
58
+ }
59
+ const signatureOffset = PRECOMPILE_DATA_START + SIGNATURE_OFFSETS_SERIALIZED_SIZE;
60
+ const publicKeyOffset = signatureOffset + SIGNATURE_SERIALIZED_SIZE;
61
+ const messageOffset = publicKeyOffset + COMPRESSED_PUBKEY_SERIALIZED_SIZE;
62
+ const messageSize = message.length;
63
+ const totalLen = messageOffset + messageSize;
64
+ const data = Buffer.alloc(totalLen);
65
+ data[0] = 1;
66
+ data[1] = 0;
67
+ data.writeUInt16LE(signatureOffset, PRECOMPILE_DATA_START + 0);
68
+ data.writeUInt16LE(65535, PRECOMPILE_DATA_START + 2);
69
+ data.writeUInt16LE(publicKeyOffset, PRECOMPILE_DATA_START + 4);
70
+ data.writeUInt16LE(65535, PRECOMPILE_DATA_START + 6);
71
+ data.writeUInt16LE(messageOffset, PRECOMPILE_DATA_START + 8);
72
+ data.writeUInt16LE(messageSize, PRECOMPILE_DATA_START + 10);
73
+ data.writeUInt16LE(65535, PRECOMPILE_DATA_START + 12);
74
+ Buffer.from(signature).copy(data, signatureOffset);
75
+ Buffer.from(publicKey).copy(data, publicKeyOffset);
76
+ Buffer.from(message).copy(data, messageOffset);
77
+ return new TransactionInstruction({
78
+ keys: [],
79
+ programId: SECP256R1_PROGRAM_ID,
80
+ data
81
+ });
82
+ }
83
+ async function buildPrecompileMessage(clientDataJSON, authenticatorData) {
84
+ const subtle = globalThis.crypto?.subtle;
85
+ let clientDataHash;
86
+ if (subtle) {
87
+ const buf = await subtle.digest("SHA-256", clientDataJSON);
88
+ clientDataHash = new Uint8Array(buf);
89
+ } else {
90
+ const { createHash } = await import("crypto");
91
+ clientDataHash = createHash("sha256").update(clientDataJSON).digest();
92
+ }
93
+ const out = new Uint8Array(authenticatorData.length + 32);
94
+ out.set(authenticatorData, 0);
95
+ out.set(clientDataHash, authenticatorData.length);
96
+ return out;
97
+ }
98
+
99
+ // src/precompile/ed25519.ts
100
+ import { TransactionInstruction as TransactionInstruction2 } from "@solana/web3.js";
101
+ function buildEd25519VerifyInstruction(pubkey, signature, message) {
102
+ if (pubkey.length !== 32) throw new Error("pubkey must be 32 bytes");
103
+ if (signature.length !== 64) throw new Error("signature must be 64 bytes");
104
+ const NUM_SIG = 1;
105
+ const PADDING = 0;
106
+ const HEADER_LEN = 2;
107
+ const OFFSETS_LEN = 14;
108
+ const DATA_START = HEADER_LEN + OFFSETS_LEN;
109
+ const data = Buffer.alloc(DATA_START + pubkey.length + signature.length + message.length);
110
+ let off = 0;
111
+ data.writeUInt8(NUM_SIG, off);
112
+ off += 1;
113
+ data.writeUInt8(PADDING, off);
114
+ off += 1;
115
+ const pubkeyOffset = DATA_START;
116
+ const signatureOffset = pubkeyOffset + pubkey.length;
117
+ const messageOffset = signatureOffset + signature.length;
118
+ data.writeUInt16LE(signatureOffset, off);
119
+ off += 2;
120
+ data.writeUInt16LE(65535, off);
121
+ off += 2;
122
+ data.writeUInt16LE(pubkeyOffset, off);
123
+ off += 2;
124
+ data.writeUInt16LE(65535, off);
125
+ off += 2;
126
+ data.writeUInt16LE(messageOffset, off);
127
+ off += 2;
128
+ data.writeUInt16LE(message.length, off);
129
+ off += 2;
130
+ data.writeUInt16LE(65535, off);
131
+ off += 2;
132
+ Buffer.from(pubkey).copy(data, pubkeyOffset);
133
+ Buffer.from(signature).copy(data, signatureOffset);
134
+ Buffer.from(message).copy(data, messageOffset);
135
+ return new TransactionInstruction2({
136
+ programId: ED25519_PROGRAM_ID,
137
+ keys: [],
138
+ data
139
+ });
140
+ }
141
+ export {
142
+ COMPRESSED_PUBKEY_SERIALIZED_SIZE,
143
+ PRECOMPILE_DATA_START,
144
+ SIGNATURE_OFFSETS_SERIALIZED_SIZE,
145
+ SIGNATURE_SERIALIZED_SIZE,
146
+ buildEd25519VerifyInstruction,
147
+ buildPrecompileMessage,
148
+ buildSecp256r1VerifyInstruction
149
+ };
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/reader/index.ts
21
+ var reader_exports = {};
22
+ __export(reader_exports, {
23
+ readVaultFull: () => readVaultFull,
24
+ readVaultOnchain: () => readVaultOnchain
25
+ });
26
+ module.exports = __toCommonJS(reader_exports);
27
+
28
+ // src/reader/accountReader.ts
29
+ var import_web3 = require("@solana/web3.js");
30
+ var VERSION_OFFSET = 8;
31
+ var SWIG_ADDRESS_OFFSET = 43;
32
+ var PENDING_VOUCHER_COUNT_OFFSET = 79;
33
+ var PENDING_WITHDRAWAL_TAG_OFFSET = 83;
34
+ var PENDING_WITHDRAWAL_AMOUNT_OFFSET = 84;
35
+ var PENDING_WITHDRAWAL_DESTINATION_OFFSET = 92;
36
+ var PENDING_WITHDRAWAL_REQUESTED_AT_OFFSET = 124;
37
+ var PENDING_WITHDRAWAL_BODY_LEN = 48;
38
+ var PENDING_WITHDRAWAL_BODY_START = PENDING_WITHDRAWAL_TAG_OFFSET + 1;
39
+ var IDENTITY_CLAIM_LEN = 32;
40
+ var PUBKEY_LEN = 32;
41
+ var ACTIVE_SESSION_BODY_LEN = 92;
42
+ var EMPTY_FULL = {
43
+ exists: false,
44
+ version: 0,
45
+ swigAddress: null,
46
+ dexterAuthority: null,
47
+ pendingVoucherCount: 0,
48
+ activeSession: null
49
+ };
50
+ async function readVaultOnchain(conn, vaultPda) {
51
+ const account = await conn.getAccountInfo(vaultPda, "confirmed");
52
+ if (!account) {
53
+ return { exists: false, pendingVoucherCount: 0, pendingWithdrawal: null };
54
+ }
55
+ const data = account.data;
56
+ const pendingVoucherCount = data.readUInt32LE(PENDING_VOUCHER_COUNT_OFFSET);
57
+ let pendingWithdrawal = null;
58
+ if (data[PENDING_WITHDRAWAL_TAG_OFFSET] === 1) {
59
+ pendingWithdrawal = {
60
+ amount: data.readBigUInt64LE(PENDING_WITHDRAWAL_AMOUNT_OFFSET).toString(),
61
+ destination: new import_web3.PublicKey(
62
+ data.subarray(
63
+ PENDING_WITHDRAWAL_DESTINATION_OFFSET,
64
+ PENDING_WITHDRAWAL_DESTINATION_OFFSET + 32
65
+ )
66
+ ).toBase58(),
67
+ requestedAt: Number(data.readBigInt64LE(PENDING_WITHDRAWAL_REQUESTED_AT_OFFSET))
68
+ };
69
+ }
70
+ return { exists: true, pendingVoucherCount, pendingWithdrawal };
71
+ }
72
+ async function readVaultFull(conn, vaultPda) {
73
+ const account = await conn.getAccountInfo(vaultPda, "confirmed");
74
+ if (!account) return EMPTY_FULL;
75
+ const data = account.data;
76
+ if (data.length < SWIG_ADDRESS_OFFSET + PUBKEY_LEN) return EMPTY_FULL;
77
+ const version = data.readUInt8(VERSION_OFFSET);
78
+ const swigAddress = new import_web3.PublicKey(
79
+ data.subarray(SWIG_ADDRESS_OFFSET, SWIG_ADDRESS_OFFSET + PUBKEY_LEN)
80
+ ).toBase58();
81
+ const pendingVoucherCount = data.readUInt32LE(PENDING_VOUCHER_COUNT_OFFSET);
82
+ const withdrawalTag = data[PENDING_WITHDRAWAL_TAG_OFFSET];
83
+ const afterWithdrawal = PENDING_WITHDRAWAL_BODY_START + (withdrawalTag === 1 ? PENDING_WITHDRAWAL_BODY_LEN : 0);
84
+ const dexterAuthorityOffset = afterWithdrawal + IDENTITY_CLAIM_LEN;
85
+ if (data.length < dexterAuthorityOffset + PUBKEY_LEN) {
86
+ return { ...EMPTY_FULL, exists: true, version, swigAddress, pendingVoucherCount };
87
+ }
88
+ const dexterAuthority = new import_web3.PublicKey(
89
+ data.subarray(dexterAuthorityOffset, dexterAuthorityOffset + PUBKEY_LEN)
90
+ ).toBase58();
91
+ const activeSessionTagOffset = dexterAuthorityOffset + PUBKEY_LEN;
92
+ let activeSession = null;
93
+ if (data.length > activeSessionTagOffset && data[activeSessionTagOffset] === 1) {
94
+ const bodyStart = activeSessionTagOffset + 1;
95
+ if (data.length >= bodyStart + ACTIVE_SESSION_BODY_LEN) {
96
+ activeSession = {
97
+ sessionPubkey: new Uint8Array(data.subarray(bodyStart, bodyStart + 32)),
98
+ maxAmount: data.readBigUInt64LE(bodyStart + 32),
99
+ expiresAt: Number(data.readBigInt64LE(bodyStart + 40)),
100
+ allowedCounterparty: new import_web3.PublicKey(
101
+ data.subarray(bodyStart + 48, bodyStart + 80)
102
+ ).toBase58(),
103
+ nonce: data.readUInt32LE(bodyStart + 80),
104
+ spent: data.readBigUInt64LE(bodyStart + 84)
105
+ };
106
+ }
107
+ }
108
+ return {
109
+ exists: true,
110
+ version,
111
+ swigAddress,
112
+ dexterAuthority,
113
+ pendingVoucherCount,
114
+ activeSession
115
+ };
116
+ }
117
+ // Annotate the CommonJS export names for ESM import in node:
118
+ 0 && (module.exports = {
119
+ readVaultFull,
120
+ readVaultOnchain
121
+ });
@@ -0,0 +1,41 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { VaultStateFull, VaultOnchainState } from '../types.cjs';
3
+
4
+ /**
5
+ * Vault account decoders (Anchor v2 layout).
6
+ *
7
+ * Two entry points sharing one byte layout:
8
+ * - readVaultOnchain → slim {exists, pendingVoucherCount, pendingWithdrawal}
9
+ * - readVaultFull → full incl. swigAddress + dexterAuthority + activeSession
10
+ *
11
+ * v2 layout (programs/dexter-vault/src/state.rs::Vault):
12
+ * 0 8 discriminator
13
+ * 8 1 version u8 (= 2)
14
+ * 9 1 bump u8
15
+ * 10 33 passkey_pubkey
16
+ * 43 32 swig_address
17
+ * 75 4 cooling_off_seconds u32
18
+ * 79 4 pending_voucher_count u32
19
+ * 83 1 pending_withdrawal Option tag
20
+ * 48 pending_withdrawal body (if tag==1):
21
+ * 8 amount u64
22
+ * 32 destination
23
+ * 8 requested_at i64
24
+ * 132/84 32 identity_claim (132 if withdrawal present, else 84)
25
+ * 164/116 32 dexter_authority (164 if withdrawal present, else 116)
26
+ * 196/148 1 active_session Option tag
27
+ * 92 session body (if tag==1):
28
+ * 32 session_pubkey
29
+ * 8 max_amount u64
30
+ * 8 expires_at i64
31
+ * 32 allowed_counterparty
32
+ * 4 nonce u32
33
+ * 8 spent u64
34
+ */
35
+
36
+ /** Slim read — the shape dexter-api's existing /status routes return. */
37
+ declare function readVaultOnchain(conn: Connection, vaultPda: PublicKey): Promise<VaultOnchainState>;
38
+ /** Full read — adds swigAddress, dexterAuthority, activeSession. The /tab/settle path. */
39
+ declare function readVaultFull(conn: Connection, vaultPda: PublicKey): Promise<VaultStateFull>;
40
+
41
+ export { readVaultFull, readVaultOnchain };
@@ -0,0 +1,41 @@
1
+ import { Connection, PublicKey } from '@solana/web3.js';
2
+ import { VaultStateFull, VaultOnchainState } from '../types.js';
3
+
4
+ /**
5
+ * Vault account decoders (Anchor v2 layout).
6
+ *
7
+ * Two entry points sharing one byte layout:
8
+ * - readVaultOnchain → slim {exists, pendingVoucherCount, pendingWithdrawal}
9
+ * - readVaultFull → full incl. swigAddress + dexterAuthority + activeSession
10
+ *
11
+ * v2 layout (programs/dexter-vault/src/state.rs::Vault):
12
+ * 0 8 discriminator
13
+ * 8 1 version u8 (= 2)
14
+ * 9 1 bump u8
15
+ * 10 33 passkey_pubkey
16
+ * 43 32 swig_address
17
+ * 75 4 cooling_off_seconds u32
18
+ * 79 4 pending_voucher_count u32
19
+ * 83 1 pending_withdrawal Option tag
20
+ * 48 pending_withdrawal body (if tag==1):
21
+ * 8 amount u64
22
+ * 32 destination
23
+ * 8 requested_at i64
24
+ * 132/84 32 identity_claim (132 if withdrawal present, else 84)
25
+ * 164/116 32 dexter_authority (164 if withdrawal present, else 116)
26
+ * 196/148 1 active_session Option tag
27
+ * 92 session body (if tag==1):
28
+ * 32 session_pubkey
29
+ * 8 max_amount u64
30
+ * 8 expires_at i64
31
+ * 32 allowed_counterparty
32
+ * 4 nonce u32
33
+ * 8 spent u64
34
+ */
35
+
36
+ /** Slim read — the shape dexter-api's existing /status routes return. */
37
+ declare function readVaultOnchain(conn: Connection, vaultPda: PublicKey): Promise<VaultOnchainState>;
38
+ /** Full read — adds swigAddress, dexterAuthority, activeSession. The /tab/settle path. */
39
+ declare function readVaultFull(conn: Connection, vaultPda: PublicKey): Promise<VaultStateFull>;
40
+
41
+ export { readVaultFull, readVaultOnchain };
@@ -0,0 +1,93 @@
1
+ // src/reader/accountReader.ts
2
+ import { PublicKey } from "@solana/web3.js";
3
+ var VERSION_OFFSET = 8;
4
+ var SWIG_ADDRESS_OFFSET = 43;
5
+ var PENDING_VOUCHER_COUNT_OFFSET = 79;
6
+ var PENDING_WITHDRAWAL_TAG_OFFSET = 83;
7
+ var PENDING_WITHDRAWAL_AMOUNT_OFFSET = 84;
8
+ var PENDING_WITHDRAWAL_DESTINATION_OFFSET = 92;
9
+ var PENDING_WITHDRAWAL_REQUESTED_AT_OFFSET = 124;
10
+ var PENDING_WITHDRAWAL_BODY_LEN = 48;
11
+ var PENDING_WITHDRAWAL_BODY_START = PENDING_WITHDRAWAL_TAG_OFFSET + 1;
12
+ var IDENTITY_CLAIM_LEN = 32;
13
+ var PUBKEY_LEN = 32;
14
+ var ACTIVE_SESSION_BODY_LEN = 92;
15
+ var EMPTY_FULL = {
16
+ exists: false,
17
+ version: 0,
18
+ swigAddress: null,
19
+ dexterAuthority: null,
20
+ pendingVoucherCount: 0,
21
+ activeSession: null
22
+ };
23
+ async function readVaultOnchain(conn, vaultPda) {
24
+ const account = await conn.getAccountInfo(vaultPda, "confirmed");
25
+ if (!account) {
26
+ return { exists: false, pendingVoucherCount: 0, pendingWithdrawal: null };
27
+ }
28
+ const data = account.data;
29
+ const pendingVoucherCount = data.readUInt32LE(PENDING_VOUCHER_COUNT_OFFSET);
30
+ let pendingWithdrawal = null;
31
+ if (data[PENDING_WITHDRAWAL_TAG_OFFSET] === 1) {
32
+ pendingWithdrawal = {
33
+ amount: data.readBigUInt64LE(PENDING_WITHDRAWAL_AMOUNT_OFFSET).toString(),
34
+ destination: new PublicKey(
35
+ data.subarray(
36
+ PENDING_WITHDRAWAL_DESTINATION_OFFSET,
37
+ PENDING_WITHDRAWAL_DESTINATION_OFFSET + 32
38
+ )
39
+ ).toBase58(),
40
+ requestedAt: Number(data.readBigInt64LE(PENDING_WITHDRAWAL_REQUESTED_AT_OFFSET))
41
+ };
42
+ }
43
+ return { exists: true, pendingVoucherCount, pendingWithdrawal };
44
+ }
45
+ async function readVaultFull(conn, vaultPda) {
46
+ const account = await conn.getAccountInfo(vaultPda, "confirmed");
47
+ if (!account) return EMPTY_FULL;
48
+ const data = account.data;
49
+ if (data.length < SWIG_ADDRESS_OFFSET + PUBKEY_LEN) return EMPTY_FULL;
50
+ const version = data.readUInt8(VERSION_OFFSET);
51
+ const swigAddress = new PublicKey(
52
+ data.subarray(SWIG_ADDRESS_OFFSET, SWIG_ADDRESS_OFFSET + PUBKEY_LEN)
53
+ ).toBase58();
54
+ const pendingVoucherCount = data.readUInt32LE(PENDING_VOUCHER_COUNT_OFFSET);
55
+ const withdrawalTag = data[PENDING_WITHDRAWAL_TAG_OFFSET];
56
+ const afterWithdrawal = PENDING_WITHDRAWAL_BODY_START + (withdrawalTag === 1 ? PENDING_WITHDRAWAL_BODY_LEN : 0);
57
+ const dexterAuthorityOffset = afterWithdrawal + IDENTITY_CLAIM_LEN;
58
+ if (data.length < dexterAuthorityOffset + PUBKEY_LEN) {
59
+ return { ...EMPTY_FULL, exists: true, version, swigAddress, pendingVoucherCount };
60
+ }
61
+ const dexterAuthority = new PublicKey(
62
+ data.subarray(dexterAuthorityOffset, dexterAuthorityOffset + PUBKEY_LEN)
63
+ ).toBase58();
64
+ const activeSessionTagOffset = dexterAuthorityOffset + PUBKEY_LEN;
65
+ let activeSession = null;
66
+ if (data.length > activeSessionTagOffset && data[activeSessionTagOffset] === 1) {
67
+ const bodyStart = activeSessionTagOffset + 1;
68
+ if (data.length >= bodyStart + ACTIVE_SESSION_BODY_LEN) {
69
+ activeSession = {
70
+ sessionPubkey: new Uint8Array(data.subarray(bodyStart, bodyStart + 32)),
71
+ maxAmount: data.readBigUInt64LE(bodyStart + 32),
72
+ expiresAt: Number(data.readBigInt64LE(bodyStart + 40)),
73
+ allowedCounterparty: new PublicKey(
74
+ data.subarray(bodyStart + 48, bodyStart + 80)
75
+ ).toBase58(),
76
+ nonce: data.readUInt32LE(bodyStart + 80),
77
+ spent: data.readBigUInt64LE(bodyStart + 84)
78
+ };
79
+ }
80
+ }
81
+ return {
82
+ exists: true,
83
+ version,
84
+ swigAddress,
85
+ dexterAuthority,
86
+ pendingVoucherCount,
87
+ activeSession
88
+ };
89
+ }
90
+ export {
91
+ readVaultFull,
92
+ readVaultOnchain
93
+ };
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/signers/node/index.ts
31
+ var node_exports = {};
32
+ __export(node_exports, {
33
+ NodeEd25519Signer: () => NodeEd25519Signer
34
+ });
35
+ module.exports = __toCommonJS(node_exports);
36
+ var import_tweetnacl = __toESM(require("tweetnacl"), 1);
37
+ var NodeEd25519Signer = class {
38
+ keypair;
39
+ /**
40
+ * @param secretKey 32-byte seed OR 64-byte nacl secret-key buffer
41
+ * (seed || pubkey). Both shapes are accepted.
42
+ */
43
+ constructor(secretKey) {
44
+ if (secretKey.length === 32) {
45
+ this.keypair = import_tweetnacl.default.sign.keyPair.fromSeed(secretKey);
46
+ } else if (secretKey.length === 64) {
47
+ this.keypair = import_tweetnacl.default.sign.keyPair.fromSecretKey(secretKey);
48
+ } else {
49
+ throw new Error(`NodeEd25519Signer: secretKey must be 32 or 64 bytes, got ${secretKey.length}`);
50
+ }
51
+ }
52
+ get publicKey() {
53
+ return this.keypair.publicKey;
54
+ }
55
+ async sign(message) {
56
+ return import_tweetnacl.default.sign.detached(message, this.keypair.secretKey);
57
+ }
58
+ };
59
+ // Annotate the CommonJS export names for ESM import in node:
60
+ 0 && (module.exports = {
61
+ NodeEd25519Signer
62
+ });
@@ -0,0 +1,21 @@
1
+ import { Ed25519Signer } from '../types.cjs';
2
+
3
+ /**
4
+ * Node Ed25519 signer — wraps a secret-key seed with tweetnacl.
5
+ *
6
+ * Used by dexter-api as its dexter-authority signer (the server-held
7
+ * session master) and by dexter-vault tests as a deterministic stand-in.
8
+ */
9
+
10
+ declare class NodeEd25519Signer implements Ed25519Signer {
11
+ private readonly keypair;
12
+ /**
13
+ * @param secretKey 32-byte seed OR 64-byte nacl secret-key buffer
14
+ * (seed || pubkey). Both shapes are accepted.
15
+ */
16
+ constructor(secretKey: Uint8Array);
17
+ get publicKey(): Uint8Array;
18
+ sign(message: Uint8Array): Promise<Uint8Array>;
19
+ }
20
+
21
+ export { NodeEd25519Signer };
@@ -0,0 +1,21 @@
1
+ import { Ed25519Signer } from '../types.js';
2
+
3
+ /**
4
+ * Node Ed25519 signer — wraps a secret-key seed with tweetnacl.
5
+ *
6
+ * Used by dexter-api as its dexter-authority signer (the server-held
7
+ * session master) and by dexter-vault tests as a deterministic stand-in.
8
+ */
9
+
10
+ declare class NodeEd25519Signer implements Ed25519Signer {
11
+ private readonly keypair;
12
+ /**
13
+ * @param secretKey 32-byte seed OR 64-byte nacl secret-key buffer
14
+ * (seed || pubkey). Both shapes are accepted.
15
+ */
16
+ constructor(secretKey: Uint8Array);
17
+ get publicKey(): Uint8Array;
18
+ sign(message: Uint8Array): Promise<Uint8Array>;
19
+ }
20
+
21
+ export { NodeEd25519Signer };
@@ -0,0 +1,27 @@
1
+ // src/signers/node/index.ts
2
+ import nacl from "tweetnacl";
3
+ var NodeEd25519Signer = class {
4
+ keypair;
5
+ /**
6
+ * @param secretKey 32-byte seed OR 64-byte nacl secret-key buffer
7
+ * (seed || pubkey). Both shapes are accepted.
8
+ */
9
+ constructor(secretKey) {
10
+ if (secretKey.length === 32) {
11
+ this.keypair = nacl.sign.keyPair.fromSeed(secretKey);
12
+ } else if (secretKey.length === 64) {
13
+ this.keypair = nacl.sign.keyPair.fromSecretKey(secretKey);
14
+ } else {
15
+ throw new Error(`NodeEd25519Signer: secretKey must be 32 or 64 bytes, got ${secretKey.length}`);
16
+ }
17
+ }
18
+ get publicKey() {
19
+ return this.keypair.publicKey;
20
+ }
21
+ async sign(message) {
22
+ return nacl.sign.detached(message, this.keypair.secretKey);
23
+ }
24
+ };
25
+ export {
26
+ NodeEd25519Signer
27
+ };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/signers/types.ts
17
+ var types_exports = {};
18
+ module.exports = __toCommonJS(types_exports);
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Signer abstractions.
3
+ *
4
+ * Ed25519Signer is shipped with a Node implementation in v0.1.
5
+ * PasskeySigner is shipped as INTERFACE ONLY in v0.1 — the WebAuthn
6
+ * implementation is tracked as task #235 ("@dexterai/vault v0.2 —
7
+ * BrowserPasskeySigner") and must lift from dexter-fe/app/lib/passkey.ts +
8
+ * dexter-fe/app/lib/passkey-anon.ts. Until v0.2 ships, dexter-fe stays on
9
+ * its hand-rolled passkey ceremony.
10
+ */
11
+ interface Ed25519Signer {
12
+ /** 32-byte public key. */
13
+ readonly publicKey: Uint8Array;
14
+ /** Produce a 64-byte detached signature over `message`. */
15
+ sign(message: Uint8Array): Promise<Uint8Array>;
16
+ }
17
+ interface PasskeySigner {
18
+ /** Opaque credential ID handed back to the platform authenticator. */
19
+ readonly credentialId: Uint8Array;
20
+ /**
21
+ * Run the WebAuthn assertion ceremony over `challenge` and return the
22
+ * three things the precompile needs.
23
+ *
24
+ * Implementation: TASK #235. dexter-fe currently ships an equivalent
25
+ * function in app/lib/passkey.ts (`signOperation`) — the lift target.
26
+ */
27
+ sign(challenge: Uint8Array): Promise<{
28
+ signature: Uint8Array;
29
+ clientDataJSON: Uint8Array;
30
+ authenticatorData: Uint8Array;
31
+ }>;
32
+ }
33
+
34
+ export type { Ed25519Signer, PasskeySigner };