@dexterai/vault 0.4.2 → 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/README.md CHANGED
@@ -21,11 +21,53 @@
21
21
 
22
22
  ---
23
23
 
24
- ## What is `@dexterai/vault`?
24
+ <!-- GTM-DRAFT: product framing/wording pending GTM agent review before publish -->
25
25
 
26
- The `dexter-vault` Solana program is a non-custodial passkey-rooted vault: WebAuthn signs every spend, a programmatic Swig role makes the unruggable streaming channel possible, and the entire spend path goes through the vault program — no master key, no escrow, no trust.
26
+ ## Open a tab for your agent
27
27
 
28
- This package is the TypeScript that talks to it. Every byte the on-chain program checks instruction discriminators, the 180-byte session-registration message, the 128-byte revocation message, the 44-byte voucher payload, the vault account layout lives here, in exactly one file each. Three repos used to hand-roll these primitives and one of them missed a role; that bug is now structurally impossible.
28
+ You open a tab with a hard limit. Your agent spends against it, charge by charge, with no signature prompt per charge. When the work is done you settle and the tab closes. The spending limit is enforced by the Solana program at consensus, not by this SDK and not by Dexter. The SDK never holds a key that can overspend it, and you can verify the cap on-chain yourself.
29
+
30
+ ```ts
31
+ import { openTab, settleTab, readTabMeter } from '@dexterai/vault/tab';
32
+
33
+ // arm a tab with a chain-enforced cap
34
+ const open = await openTab({ vaultPda, amount: 5_000_000n, dexterAuthority });
35
+
36
+ // settle a streamed micro-charge (composes precompile + settle + transfer)
37
+ const settle = await settleTab({
38
+ connection, vaultPda, swigAddress, channelId,
39
+ cumulativeAmount, sequenceNumber, sessionSigner, sellerAta, feePayer, dexterAuthority,
40
+ });
41
+
42
+ // read remaining headroom (the chain is the real guard)
43
+ const meter = await readTabMeter(connection, vaultPda);
44
+ ```
45
+
46
+ That is the whole product loop: `openTab` arms a capped tab, `settleTab` records each streamed charge against it, `readTabMeter` reports the headroom left. The buyer's USDC never leaves their wallet while the tab runs; the program gates their exit until the tab settles. The closest familiar shape is an auth-and-capture credit-card hold, except the hold is enforced on-chain instead of by a processor.
47
+
48
+ A tab can also spend **past** the user's balance, backed by a financier's standby capital: non-custodial, and structured so the buyer cannot rug the financier and the financier cannot seize more than the agreed bound. Every guard in that path is proven on Solana mainnet, including a real draw, a real repayment, a real default-and-seize, and every anti-rug rejection. Same import, three more verbs:
49
+
50
+ ```ts
51
+ import { drawCredit, repayCredit, seizeCollateral } from '@dexterai/vault/tab';
52
+ ```
53
+
54
+ Credit is not a separate product bolted onto a tab. It is a tab that can spend past its balance. That is why it lives in the same import.
55
+
56
+ > **Two sides.** This package is the buyer side. The seller side (verify vouchers, meter consumption, accept payment in about ten lines) lives in `@dexterai/x402`. Together they cover both halves of agent payments on Solana.
57
+
58
+ Every `./tab` verb returns `TransactionInstruction[]`, so you own signing, fees, and sending.
59
+
60
+ ---
61
+
62
+ ## Under the hood: the primitives
63
+
64
+ If the four `./tab` verbs are all you need, you can stop reading here. The rest of this package is the low-level surface those verbs are built from, exposed for the servers that assemble their own transactions.
65
+
66
+ The `dexter-vault` Solana program is a non-custodial passkey-rooted vault: WebAuthn signs every spend, a programmatic Swig role makes the unruggable streaming channel possible, and the entire spend path goes through the vault program, with no master key, no escrow, and no trust.
67
+
68
+ This package is the TypeScript that talks to it. Every byte the on-chain program checks lives here, in exactly one file each: instruction discriminators, the 188-byte V2 session-registration message, the 128-byte revocation message, the 44-byte voucher payload, and the vault account layout. Three repos used to hand-roll these primitives and one of them missed a role; that bug is now structurally impossible.
69
+
70
+ The `./tab` verbs above compose these primitives. The tiers stack on top of the same building blocks: the streaming tab (`settle_tab_voucher`), the credit tab (`draw_credit` / `repay_credit` / `seize_collateral`), the LockedClaim crystallized tier (`@dexterai/vault/instructions`), and factoring / instant payout (`@dexterai/vault/factoring`).
29
71
 
30
72
  If you are about to hand-roll a vault instruction builder, a precompile message, a Swig role list, or a vault account decoder, **stop and import from here instead**.
31
73
 
@@ -37,7 +79,7 @@ If you are about to hand-roll a vault instruction builder, a precompile message,
37
79
  npm install @dexterai/vault
38
80
  ```
39
81
 
40
- Compatible with `dexter-vault` program version 2 (12 Anchor discriminators including `prove_passkey`, `settle_tab_voucher`, and the session-key register/revoke pair).
82
+ Targets the `dexter-vault` V5 program (21 Anchor discriminators including `prove_passkey`, `settle_tab_voucher`, the session-key register/revoke pair, the LockedClaim set, and the credit set `open_standby` / `draw_credit` / `repay_credit` / `seize_collateral`).
41
83
 
42
84
  ---
43
85
 
@@ -63,7 +105,7 @@ const bundle = await buildSwigCreationBundle({
63
105
  const tx = new Transaction().add(...bundle.instructions);
64
106
  ```
65
107
 
66
- The 4-role design role 0 bootstrap, role 1 `ProgramExec(finalize_withdrawal)`, role 2 session master, role 3 `ProgramExec(settle_tab_voucher)` lives in exactly one function. Tests in this repo lock the role list against the on-chain Anchor discriminators.
108
+ The 4-role design (role 0 bootstrap, role 1 `ProgramExec(finalize_withdrawal)`, role 2 session master, role 3 `ProgramExec(settle_tab_voucher)`) lives in exactly one function. Tests in this repo lock the role list against the on-chain Anchor discriminators.
67
109
 
68
110
  ### Settle a Tab voucher on chain (facilitator-side)
69
111
 
@@ -141,14 +183,18 @@ Each subpath is a tree-shakeable entry point. Pull only what you need.
141
183
  |---|---|
142
184
  | `@dexterai/vault` | Re-exports `types` + `counterfactual` for convenience |
143
185
  | `@dexterai/vault/types` | `VaultState`, `VaultStateFull`, `ActiveSession`, `PendingWithdrawal`, `SessionKey`, `SessionScope`, `SignedVoucher`, `VoucherPayload`, `AtomicAmount`, `HumanAmount`, `TabNetworkId` |
144
- | `@dexterai/vault/constants` | `DEXTER_VAULT_PROGRAM_ID`, `SWIG_PROGRAM_ID`, `USDC_MAINNET`/`USDC_DEVNET`, all 12 `DISCRIMINATORS`, `OTS_SESSION_REGISTER_V1_DOMAIN`, `OTS_SESSION_REVOKE_V1_DOMAIN` |
186
+ | `@dexterai/vault/constants` | `DEXTER_VAULT_PROGRAM_ID`, `SWIG_PROGRAM_ID`, `USDC_MAINNET`/`USDC_DEVNET`, all 21 `DISCRIMINATORS`, `LOCKED_CLAIM_SEED`, `OTS_SESSION_REGISTER_V1_DOMAIN`, `OTS_SESSION_REGISTER_V2_DOMAIN`, `OTS_SESSION_REVOKE_V1_DOMAIN` |
145
187
  | `@dexterai/vault/instructions` | Every builder: `buildInitializeVaultInstruction`, `buildSetSwigInstruction`, `buildRegisterSessionKeyInstruction`, `buildRevokeSessionKeyInstruction`, `buildSettleVoucherInstruction`, `buildSettleTabVoucherInstruction`, `buildRequestWithdrawalInstruction`, `buildFinalizeWithdrawalInstruction`, `buildForceReleaseInstruction`, `buildRotatePasskeyInstruction`, `buildRotateDexterAuthorityInstruction`, `buildProvePasskeyInstruction`, and the canonical `buildSwigCreationBundle` + `expectedSwigAddressFor` + `verifySwigIsOurs` |
146
- | `@dexterai/vault/messages` | `sessionRegisterMessage` (180 bytes), `sessionRevokeMessage` (128 bytes), `voucherPayloadMessage` / `buildVoucherMessage` (44 bytes), `buildSetSwigOperationMessage` |
188
+ | `@dexterai/vault/messages` | `sessionRegisterMessage` (188 bytes, V2), `sessionRevokeMessage` (128 bytes), `voucherPayloadMessage` / `buildVoucherMessage` (44 bytes), `buildSetSwigOperationMessage` |
147
189
  | `@dexterai/vault/reader` | `readVaultOnchain` (slim), `readVaultFull` (with active session) |
148
190
  | `@dexterai/vault/precompile` | `buildSecp256r1VerifyInstruction`, `buildPrecompileMessage`, `buildEd25519VerifyInstruction` |
149
191
  | `@dexterai/vault/counterfactual` | `deriveCounterfactualAddresses` |
150
192
  | `@dexterai/vault/signers` | `Ed25519Signer`, `PasskeySigner` interfaces |
151
193
  | `@dexterai/vault/signers/node` | `NodeEd25519Signer` (tweetnacl-backed) |
194
+ | `@dexterai/vault/signers/browser` | `WebAuthnAssertion` (pure-browser P-256 passkey ceremony, shipped 0.2.0), `derSignatureToCompactLowS` |
195
+ | `@dexterai/vault/tab` | Product layer: `openTab`, `settleTab`, `readTabMeter`, `drawCredit`, `repayCredit`, `seizeCollateral`, `defaultAssembleSignV2` |
196
+ | `@dexterai/vault/factoring` | `computeFactoringSplit`, `buildInstantPayoutInstructions` (settle a LockedClaim and split the payout) |
197
+ | `@dexterai/vault/kit` | `kitInstructionsToWeb3`, `getRpc` (Swig-kit↔web3 bridge) |
152
198
 
153
199
  ---
154
200
 
@@ -156,7 +202,7 @@ Each subpath is a tree-shakeable entry point. Pull only what you need.
156
202
 
157
203
  Three places used to hand-roll the same protocol: `dexter-api/src/vault/`, `dexter-facilitator/src/vault/`, and `dexter-vault/tests/`. One of them added role 3 (`ProgramExec` for `settle_tab_voucher`); two didn't. The end-to-end Tab settle smoke kept failing with `Role not found for ID: 3` and it ate hours of debugging on 2026-06-02 before anyone noticed the drift.
158
204
 
159
- This package is the structural fix. The canonical 4-role Swig provisioner, every instruction builder, every byte-precise message encoder, the vault account decoder, the precompile helpers they live in exactly one file each. Consumers (`dexter-api`, `dexter-facilitator`, `dexter-vault` tests, `@dexterai/x402/tab`) import from here. The drift bug class is gone.
205
+ This package is the structural fix. The canonical 4-role Swig provisioner, every instruction builder, every byte-precise message encoder, the vault account decoder, and the precompile helpers each live in exactly one file. Consumers (`dexter-api`, `dexter-facilitator`, `dexter-vault` tests, `@dexterai/x402/tab`) import from here. The drift bug class is gone.
160
206
 
161
207
  ---
162
208
 
@@ -164,10 +210,10 @@ This package is the structural fix. The canonical 4-role Swig provisioner, every
164
210
 
165
211
  `tests/byte-parity.test.ts`, `tests/precompile.test.ts`, `tests/swigBundle.test.ts`, `tests/counterfactual.test.ts`, and `tests/reader.test.ts` together snapshot:
166
212
 
167
- - All **12 instruction discriminators** (10 vault + 2 session-key) as exact byte arrays.
168
- - All **3 message layouts** 180-byte session registration, 128-byte revocation, 44-byte voucher payload — byte-by-byte.
169
- - Both **precompile builders** secp256r1 (SIMD-0075) and Ed25519 including the 14-byte offsets table.
170
- - The **vault account decoder** for every Anchor v2 layout combination (with/without pending withdrawal, with/without active session).
213
+ - All **21 instruction discriminators**, derived from `sha256("global:<name>")` and checked against the pinned bytes, covering the vault core, the session-key pair, the LockedClaim set, and the credit set.
214
+ - All **3 message layouts**, byte-by-byte: 188-byte V2 session registration, 128-byte revocation, 44-byte voucher payload.
215
+ - Both **precompile builders**, secp256r1 (SIMD-0075) and Ed25519, including the 14-byte offsets table.
216
+ - The **vault account decoder** for every V5 layout combination (with/without pending withdrawal, with/without active session).
171
217
  - The **`buildSwigCreationBundle` structural lock**: ≥4 instructions, idempotent for the same `(identitySeed, hmacKey)`, distinct outputs for different inputs, the `settle_tab_voucher` Swig exec marker bytes match the on-chain discriminator.
172
218
  - The **counterfactual derivation** for a known seed.
173
219
 
@@ -184,7 +230,7 @@ npm test
184
230
  ```
185
231
  ┌─────────────────────────────────┐
186
232
  │ dexter-vault (Anchor program) │ ← source of truth
187
- 12 discriminators, 3 layouts
233
+ V5: 21 discriminators, 3 layouts│
188
234
  └────────────────┬────────────────┘
189
235
  │ defines bytes
190
236
 
@@ -229,15 +275,15 @@ interface PasskeySigner {
229
275
  }
230
276
  ```
231
277
 
232
- `NodeEd25519Signer` ships at `@dexterai/vault/signers/node`. `BrowserPasskeySigner` is the v0.2 work lifted from `dexter-fe`'s existing WebAuthn ceremony, it unlocks browser-buyer flows on dexter.cash and anywhere else a user pays through their passkey vault.
278
+ `NodeEd25519Signer` ships at `@dexterai/vault/signers/node`. The browser passkey signer shipped in 0.2.0 as `WebAuthnAssertion` at `@dexterai/vault/signers/browser`: a pure-browser P-256 ceremony that runs `navigator.credentials.get()` and returns the three on-chain-ready buffers (64-byte compact lowS signature, raw `clientDataJSON`, raw `authenticatorData`), zero `fetch` calls. It implements the `PasskeySigner` interface; consumers compose it with their own server-policy adapter. This unlocks browser-buyer flows on dexter.cash and anywhere else a user pays through their passkey vault.
233
279
 
234
280
  ---
235
281
 
236
282
  ## Versioning
237
283
 
238
- `@dexterai/vault@0.1.x` is compatible with `dexter-vault` program version 2 (12 Anchor instructions; role 3 `ProgramExec` for `settle_tab_voucher` registered on every new Swig).
284
+ The current SDK targets the `dexter-vault` V5 program (21 Anchor instructions; role 3 `ProgramExec` for `settle_tab_voucher` registered on every new Swig).
239
285
 
240
- Future program versions will bump the SDK major or document the delta in the CHANGELOG. The byte-parity tests are the structural lock any layout change requires an explicit snapshot update.
286
+ Future program versions will bump the SDK major or document the delta in the CHANGELOG. The byte-parity tests are the structural lock: any layout change requires an explicit snapshot update.
241
287
 
242
288
  ---
243
289
 
@@ -24,6 +24,7 @@ __export(constants_exports, {
24
24
  DISCRIMINATORS: () => DISCRIMINATORS,
25
25
  ED25519_PROGRAM_ID: () => ED25519_PROGRAM_ID,
26
26
  INSTRUCTIONS_SYSVAR_ID: () => INSTRUCTIONS_SYSVAR_ID,
27
+ LOCKED_CLAIM_SEED: () => LOCKED_CLAIM_SEED,
27
28
  OTS_SESSION_REGISTER_V1_DOMAIN: () => OTS_SESSION_REGISTER_V1_DOMAIN,
28
29
  OTS_SESSION_REGISTER_V2_DOMAIN: () => OTS_SESSION_REGISTER_V2_DOMAIN,
29
30
  OTS_SESSION_REVOKE_V1_DOMAIN: () => OTS_SESSION_REVOKE_V1_DOMAIN,
@@ -53,6 +54,7 @@ var INSTRUCTIONS_SYSVAR_ID = new import_web3.PublicKey(
53
54
  var USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
54
55
  var USDC_DEVNET = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
55
56
  var VAULT_SEED_PREFIX = Buffer.from("vault");
57
+ var LOCKED_CLAIM_SEED = Buffer.from("locked-claim");
56
58
  var DISCRIMINATORS = Object.freeze({
57
59
  initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
58
60
  set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
@@ -65,7 +67,16 @@ var DISCRIMINATORS = Object.freeze({
65
67
  prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
66
68
  settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
67
69
  register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
68
- revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151])
70
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151]),
71
+ lock_voucher: Uint8Array.from([91, 138, 5, 227, 119, 239, 48, 254]),
72
+ settle_locked_voucher: Uint8Array.from([44, 80, 216, 43, 247, 253, 101, 45]),
73
+ transfer_lock_ownership: Uint8Array.from([193, 13, 131, 134, 95, 25, 229, 157]),
74
+ recover_abandoned_lock: Uint8Array.from([169, 213, 107, 64, 229, 49, 43, 234]),
75
+ open_standby: Uint8Array.from([234, 184, 232, 135, 246, 191, 90, 250]),
76
+ draw_credit: Uint8Array.from([20, 84, 47, 211, 78, 117, 195, 210]),
77
+ repay_credit: Uint8Array.from([38, 113, 240, 182, 109, 179, 154, 245]),
78
+ seize_collateral: Uint8Array.from([40, 250, 7, 243, 168, 184, 116, 154]),
79
+ migrate_v4_to_v5: Uint8Array.from([226, 105, 140, 184, 101, 39, 235, 116])
69
80
  });
70
81
  var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
71
82
  const buf = new Uint8Array(32);
@@ -88,6 +99,7 @@ var OTS_SESSION_REVOKE_V1_DOMAIN = (() => {
88
99
  DISCRIMINATORS,
89
100
  ED25519_PROGRAM_ID,
90
101
  INSTRUCTIONS_SYSVAR_ID,
102
+ LOCKED_CLAIM_SEED,
91
103
  OTS_SESSION_REGISTER_V1_DOMAIN,
92
104
  OTS_SESSION_REGISTER_V2_DOMAIN,
93
105
  OTS_SESSION_REVOKE_V1_DOMAIN,
@@ -14,6 +14,7 @@ declare const INSTRUCTIONS_SYSVAR_ID: PublicKey;
14
14
  declare const USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
15
15
  declare const USDC_DEVNET = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
16
16
  declare const VAULT_SEED_PREFIX: Buffer<ArrayBuffer>;
17
+ declare const LOCKED_CLAIM_SEED: Buffer<ArrayBuffer>;
17
18
  declare const DISCRIMINATORS: Readonly<{
18
19
  initialize_vault: Uint8Array<ArrayBuffer>;
19
20
  set_swig: Uint8Array<ArrayBuffer>;
@@ -27,9 +28,18 @@ declare const DISCRIMINATORS: Readonly<{
27
28
  settle_tab_voucher: Uint8Array<ArrayBuffer>;
28
29
  register_session_key: Uint8Array<ArrayBuffer>;
29
30
  revoke_session_key: Uint8Array<ArrayBuffer>;
31
+ lock_voucher: Uint8Array<ArrayBuffer>;
32
+ settle_locked_voucher: Uint8Array<ArrayBuffer>;
33
+ transfer_lock_ownership: Uint8Array<ArrayBuffer>;
34
+ recover_abandoned_lock: Uint8Array<ArrayBuffer>;
35
+ open_standby: Uint8Array<ArrayBuffer>;
36
+ draw_credit: Uint8Array<ArrayBuffer>;
37
+ repay_credit: Uint8Array<ArrayBuffer>;
38
+ seize_collateral: Uint8Array<ArrayBuffer>;
39
+ migrate_v4_to_v5: Uint8Array<ArrayBuffer>;
30
40
  }>;
31
41
  declare const OTS_SESSION_REGISTER_V1_DOMAIN: Uint8Array;
32
42
  declare const OTS_SESSION_REGISTER_V2_DOMAIN: Uint8Array;
33
43
  declare const OTS_SESSION_REVOKE_V1_DOMAIN: Uint8Array;
34
44
 
35
- export { DEXTER_VAULT_PROGRAM_ID, DISCRIMINATORS, ED25519_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, OTS_SESSION_REGISTER_V1_DOMAIN, OTS_SESSION_REGISTER_V2_DOMAIN, OTS_SESSION_REVOKE_V1_DOMAIN, SECP256R1_PROGRAM_ID, SWIG_PROGRAM_ID, USDC_DEVNET, USDC_MAINNET, VAULT_SEED_PREFIX };
45
+ export { DEXTER_VAULT_PROGRAM_ID, DISCRIMINATORS, ED25519_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, LOCKED_CLAIM_SEED, OTS_SESSION_REGISTER_V1_DOMAIN, OTS_SESSION_REGISTER_V2_DOMAIN, OTS_SESSION_REVOKE_V1_DOMAIN, SECP256R1_PROGRAM_ID, SWIG_PROGRAM_ID, USDC_DEVNET, USDC_MAINNET, VAULT_SEED_PREFIX };
@@ -14,6 +14,7 @@ declare const INSTRUCTIONS_SYSVAR_ID: PublicKey;
14
14
  declare const USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
15
15
  declare const USDC_DEVNET = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
16
16
  declare const VAULT_SEED_PREFIX: Buffer<ArrayBuffer>;
17
+ declare const LOCKED_CLAIM_SEED: Buffer<ArrayBuffer>;
17
18
  declare const DISCRIMINATORS: Readonly<{
18
19
  initialize_vault: Uint8Array<ArrayBuffer>;
19
20
  set_swig: Uint8Array<ArrayBuffer>;
@@ -27,9 +28,18 @@ declare const DISCRIMINATORS: Readonly<{
27
28
  settle_tab_voucher: Uint8Array<ArrayBuffer>;
28
29
  register_session_key: Uint8Array<ArrayBuffer>;
29
30
  revoke_session_key: Uint8Array<ArrayBuffer>;
31
+ lock_voucher: Uint8Array<ArrayBuffer>;
32
+ settle_locked_voucher: Uint8Array<ArrayBuffer>;
33
+ transfer_lock_ownership: Uint8Array<ArrayBuffer>;
34
+ recover_abandoned_lock: Uint8Array<ArrayBuffer>;
35
+ open_standby: Uint8Array<ArrayBuffer>;
36
+ draw_credit: Uint8Array<ArrayBuffer>;
37
+ repay_credit: Uint8Array<ArrayBuffer>;
38
+ seize_collateral: Uint8Array<ArrayBuffer>;
39
+ migrate_v4_to_v5: Uint8Array<ArrayBuffer>;
30
40
  }>;
31
41
  declare const OTS_SESSION_REGISTER_V1_DOMAIN: Uint8Array;
32
42
  declare const OTS_SESSION_REGISTER_V2_DOMAIN: Uint8Array;
33
43
  declare const OTS_SESSION_REVOKE_V1_DOMAIN: Uint8Array;
34
44
 
35
- export { DEXTER_VAULT_PROGRAM_ID, DISCRIMINATORS, ED25519_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, OTS_SESSION_REGISTER_V1_DOMAIN, OTS_SESSION_REGISTER_V2_DOMAIN, OTS_SESSION_REVOKE_V1_DOMAIN, SECP256R1_PROGRAM_ID, SWIG_PROGRAM_ID, USDC_DEVNET, USDC_MAINNET, VAULT_SEED_PREFIX };
45
+ export { DEXTER_VAULT_PROGRAM_ID, DISCRIMINATORS, ED25519_PROGRAM_ID, INSTRUCTIONS_SYSVAR_ID, LOCKED_CLAIM_SEED, OTS_SESSION_REGISTER_V1_DOMAIN, OTS_SESSION_REGISTER_V2_DOMAIN, OTS_SESSION_REVOKE_V1_DOMAIN, SECP256R1_PROGRAM_ID, SWIG_PROGRAM_ID, USDC_DEVNET, USDC_MAINNET, VAULT_SEED_PREFIX };
@@ -18,6 +18,7 @@ var INSTRUCTIONS_SYSVAR_ID = new PublicKey(
18
18
  var USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
19
19
  var USDC_DEVNET = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU";
20
20
  var VAULT_SEED_PREFIX = Buffer.from("vault");
21
+ var LOCKED_CLAIM_SEED = Buffer.from("locked-claim");
21
22
  var DISCRIMINATORS = Object.freeze({
22
23
  initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
23
24
  set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
@@ -30,7 +31,16 @@ var DISCRIMINATORS = Object.freeze({
30
31
  prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
31
32
  settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
32
33
  register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
33
- revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151])
34
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151]),
35
+ lock_voucher: Uint8Array.from([91, 138, 5, 227, 119, 239, 48, 254]),
36
+ settle_locked_voucher: Uint8Array.from([44, 80, 216, 43, 247, 253, 101, 45]),
37
+ transfer_lock_ownership: Uint8Array.from([193, 13, 131, 134, 95, 25, 229, 157]),
38
+ recover_abandoned_lock: Uint8Array.from([169, 213, 107, 64, 229, 49, 43, 234]),
39
+ open_standby: Uint8Array.from([234, 184, 232, 135, 246, 191, 90, 250]),
40
+ draw_credit: Uint8Array.from([20, 84, 47, 211, 78, 117, 195, 210]),
41
+ repay_credit: Uint8Array.from([38, 113, 240, 182, 109, 179, 154, 245]),
42
+ seize_collateral: Uint8Array.from([40, 250, 7, 243, 168, 184, 116, 154]),
43
+ migrate_v4_to_v5: Uint8Array.from([226, 105, 140, 184, 101, 39, 235, 116])
34
44
  });
35
45
  var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
36
46
  const buf = new Uint8Array(32);
@@ -52,6 +62,7 @@ export {
52
62
  DISCRIMINATORS,
53
63
  ED25519_PROGRAM_ID,
54
64
  INSTRUCTIONS_SYSVAR_ID,
65
+ LOCKED_CLAIM_SEED,
55
66
  OTS_SESSION_REGISTER_V1_DOMAIN,
56
67
  OTS_SESSION_REGISTER_V2_DOMAIN,
57
68
  OTS_SESSION_REVOKE_V1_DOMAIN,
@@ -39,6 +39,7 @@ var import_lib2 = require("@swig-wallet/lib");
39
39
  var import_node_crypto = require("crypto");
40
40
  var import_kit = require("@swig-wallet/kit");
41
41
  var import_lib = require("@swig-wallet/lib");
42
+ var import_kit2 = require("@solana/kit");
42
43
  var bs58Module = __toESM(require("bs58"), 1);
43
44
  var import_web32 = require("@solana/web3.js");
44
45
 
@@ -60,6 +61,7 @@ var INSTRUCTIONS_SYSVAR_ID = new import_web3.PublicKey(
60
61
  "Sysvar1nstructions1111111111111111111111111"
61
62
  );
62
63
  var VAULT_SEED_PREFIX = Buffer.from("vault");
64
+ var LOCKED_CLAIM_SEED = Buffer.from("locked-claim");
63
65
  var DISCRIMINATORS = Object.freeze({
64
66
  initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
65
67
  set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
@@ -72,7 +74,16 @@ var DISCRIMINATORS = Object.freeze({
72
74
  prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
73
75
  settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
74
76
  register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
75
- revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151])
77
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151]),
78
+ lock_voucher: Uint8Array.from([91, 138, 5, 227, 119, 239, 48, 254]),
79
+ settle_locked_voucher: Uint8Array.from([44, 80, 216, 43, 247, 253, 101, 45]),
80
+ transfer_lock_ownership: Uint8Array.from([193, 13, 131, 134, 95, 25, 229, 157]),
81
+ recover_abandoned_lock: Uint8Array.from([169, 213, 107, 64, 229, 49, 43, 234]),
82
+ open_standby: Uint8Array.from([234, 184, 232, 135, 246, 191, 90, 250]),
83
+ draw_credit: Uint8Array.from([20, 84, 47, 211, 78, 117, 195, 210]),
84
+ repay_credit: Uint8Array.from([38, 113, 240, 182, 109, 179, 154, 245]),
85
+ seize_collateral: Uint8Array.from([40, 250, 7, 243, 168, 184, 116, 154]),
86
+ migrate_v4_to_v5: Uint8Array.from([226, 105, 140, 184, 101, 39, 235, 116])
76
87
  });
77
88
  var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
78
89
  const buf = new Uint8Array(32);
@@ -15,6 +15,7 @@ import {
15
15
  createEd25519SessionAuthorityInfo,
16
16
  getCreateSwigWithMultipleAuthoritiesInstructionContextBuilder
17
17
  } from "@swig-wallet/lib";
18
+ import { address, createSolanaRpc } from "@solana/kit";
18
19
  import * as bs58Module from "bs58";
19
20
  import { PublicKey as PublicKey2 } from "@solana/web3.js";
20
21
 
@@ -36,6 +37,7 @@ var INSTRUCTIONS_SYSVAR_ID = new PublicKey(
36
37
  "Sysvar1nstructions1111111111111111111111111"
37
38
  );
38
39
  var VAULT_SEED_PREFIX = Buffer.from("vault");
40
+ var LOCKED_CLAIM_SEED = Buffer.from("locked-claim");
39
41
  var DISCRIMINATORS = Object.freeze({
40
42
  initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
41
43
  set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
@@ -48,7 +50,16 @@ var DISCRIMINATORS = Object.freeze({
48
50
  prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
49
51
  settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
50
52
  register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
51
- revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151])
53
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151]),
54
+ lock_voucher: Uint8Array.from([91, 138, 5, 227, 119, 239, 48, 254]),
55
+ settle_locked_voucher: Uint8Array.from([44, 80, 216, 43, 247, 253, 101, 45]),
56
+ transfer_lock_ownership: Uint8Array.from([193, 13, 131, 134, 95, 25, 229, 157]),
57
+ recover_abandoned_lock: Uint8Array.from([169, 213, 107, 64, 229, 49, 43, 234]),
58
+ open_standby: Uint8Array.from([234, 184, 232, 135, 246, 191, 90, 250]),
59
+ draw_credit: Uint8Array.from([20, 84, 47, 211, 78, 117, 195, 210]),
60
+ repay_credit: Uint8Array.from([38, 113, 240, 182, 109, 179, 154, 245]),
61
+ seize_collateral: Uint8Array.from([40, 250, 7, 243, 168, 184, 116, 154]),
62
+ migrate_v4_to_v5: Uint8Array.from([226, 105, 140, 184, 101, 39, 235, 116])
52
63
  });
53
64
  var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
54
65
  const buf = new Uint8Array(32);
@@ -0,0 +1,246 @@
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/factoring/index.ts
21
+ var factoring_exports = {};
22
+ __export(factoring_exports, {
23
+ buildInstantPayoutInstructions: () => buildInstantPayoutInstructions,
24
+ computeFactoringSplit: () => computeFactoringSplit,
25
+ getRpc: () => getRpc,
26
+ kitInstructionsToWeb3: () => kitInstructionsToWeb3
27
+ });
28
+ module.exports = __toCommonJS(factoring_exports);
29
+
30
+ // src/factoring/split.ts
31
+ function computeFactoringSplit(p) {
32
+ if (p.claimAmount <= 0n) {
33
+ throw new Error(`factoring: claim amount must be positive, got ${p.claimAmount}`);
34
+ }
35
+ if (p.financierSpread < 0n) {
36
+ throw new Error(`factoring: spread must not be negative, got ${p.financierSpread}`);
37
+ }
38
+ if (p.financierSpread > p.claimAmount) {
39
+ throw new Error(`factoring: spread exceeds claim (${p.financierSpread} > ${p.claimAmount})`);
40
+ }
41
+ return {
42
+ sellerReceives: p.claimAmount - p.financierSpread,
43
+ financierSpread: p.financierSpread
44
+ };
45
+ }
46
+
47
+ // src/factoring/instantPayout.ts
48
+ var import_web35 = require("@solana/web3.js");
49
+ var import_kit3 = require("@swig-wallet/kit");
50
+ var import_kit4 = require("@solana/kit");
51
+ var import_token = require("@solana-program/token");
52
+ var import_spl_token = require("@solana/spl-token");
53
+
54
+ // src/instructions/lockedClaim.ts
55
+ var import_web33 = require("@solana/web3.js");
56
+
57
+ // src/constants/index.ts
58
+ var import_web3 = require("@solana/web3.js");
59
+ var DEXTER_VAULT_PROGRAM_ID = new import_web3.PublicKey(
60
+ "Hg3wRaydFtJhYrdvYrKECacpJYDsC9Px7yKmpncj2fhc"
61
+ );
62
+ var SWIG_PROGRAM_ID = new import_web3.PublicKey(
63
+ "swigypWHEksbC64pWKwah1WTeh9JXwx8H1rJHLdbQMB"
64
+ );
65
+ var SECP256R1_PROGRAM_ID = new import_web3.PublicKey(
66
+ "Secp256r1SigVerify1111111111111111111111111"
67
+ );
68
+ var ED25519_PROGRAM_ID = new import_web3.PublicKey(
69
+ "Ed25519SigVerify111111111111111111111111111"
70
+ );
71
+ var INSTRUCTIONS_SYSVAR_ID = new import_web3.PublicKey(
72
+ "Sysvar1nstructions1111111111111111111111111"
73
+ );
74
+ var USDC_MAINNET = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
75
+ var VAULT_SEED_PREFIX = Buffer.from("vault");
76
+ var LOCKED_CLAIM_SEED = Buffer.from("locked-claim");
77
+ var DISCRIMINATORS = Object.freeze({
78
+ initialize_vault: Uint8Array.from([48, 191, 163, 44, 71, 129, 63, 164]),
79
+ set_swig: Uint8Array.from([253, 229, 89, 206, 192, 118, 137, 165]),
80
+ settle_voucher: Uint8Array.from([144, 176, 128, 220, 156, 79, 41, 54]),
81
+ request_withdrawal: Uint8Array.from([251, 85, 121, 205, 56, 201, 12, 177]),
82
+ finalize_withdrawal: Uint8Array.from([178, 87, 206, 68, 201, 186, 164, 232]),
83
+ force_release: Uint8Array.from([122, 190, 243, 252, 54, 202, 208, 234]),
84
+ rotate_passkey: Uint8Array.from([28, 134, 49, 89, 196, 34, 58, 174]),
85
+ rotate_dexter_authority: Uint8Array.from([145, 60, 4, 119, 180, 205, 236, 134]),
86
+ prove_passkey: Uint8Array.from([35, 175, 41, 143, 201, 118, 49, 184]),
87
+ settle_tab_voucher: Uint8Array.from([173, 22, 98, 31, 110, 129, 59, 161]),
88
+ register_session_key: Uint8Array.from([69, 94, 60, 44, 49, 199, 183, 233]),
89
+ revoke_session_key: Uint8Array.from([81, 192, 32, 110, 104, 116, 144, 151]),
90
+ lock_voucher: Uint8Array.from([91, 138, 5, 227, 119, 239, 48, 254]),
91
+ settle_locked_voucher: Uint8Array.from([44, 80, 216, 43, 247, 253, 101, 45]),
92
+ transfer_lock_ownership: Uint8Array.from([193, 13, 131, 134, 95, 25, 229, 157]),
93
+ recover_abandoned_lock: Uint8Array.from([169, 213, 107, 64, 229, 49, 43, 234]),
94
+ open_standby: Uint8Array.from([234, 184, 232, 135, 246, 191, 90, 250]),
95
+ draw_credit: Uint8Array.from([20, 84, 47, 211, 78, 117, 195, 210]),
96
+ repay_credit: Uint8Array.from([38, 113, 240, 182, 109, 179, 154, 245]),
97
+ seize_collateral: Uint8Array.from([40, 250, 7, 243, 168, 184, 116, 154]),
98
+ migrate_v4_to_v5: Uint8Array.from([226, 105, 140, 184, 101, 39, 235, 116])
99
+ });
100
+ var OTS_SESSION_REGISTER_V1_DOMAIN = (() => {
101
+ const buf = new Uint8Array(32);
102
+ buf.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V1"), 0);
103
+ return buf;
104
+ })();
105
+ var OTS_SESSION_REGISTER_V2_DOMAIN = (() => {
106
+ const buf = new Uint8Array(32);
107
+ buf.set(new TextEncoder().encode("OTS_SESSION_REGISTER_V2"), 0);
108
+ return buf;
109
+ })();
110
+ var OTS_SESSION_REVOKE_V1_DOMAIN = (() => {
111
+ const buf = new Uint8Array(32);
112
+ buf.set(new TextEncoder().encode("OTS_SESSION_REVOKE_V1"), 0);
113
+ return buf;
114
+ })();
115
+
116
+ // src/instructions/withdraw.ts
117
+ var import_web32 = require("@solana/web3.js");
118
+ function deriveSwigWalletAddress(swigAddress) {
119
+ const [pda] = import_web32.PublicKey.findProgramAddressSync(
120
+ [Buffer.from("swig-wallet-address"), swigAddress.toBuffer()],
121
+ SWIG_PROGRAM_ID
122
+ );
123
+ return pda;
124
+ }
125
+
126
+ // src/instructions/lockedClaim.ts
127
+ function buildSettleLockedVoucherInstruction(p) {
128
+ const data = Buffer.from(DISCRIMINATORS.settle_locked_voucher);
129
+ const swigWalletAddress = deriveSwigWalletAddress(p.swigAddress);
130
+ return new import_web33.TransactionInstruction({
131
+ programId: DEXTER_VAULT_PROGRAM_ID,
132
+ keys: [
133
+ { pubkey: p.swigAddress, isSigner: false, isWritable: false },
134
+ { pubkey: swigWalletAddress, isSigner: false, isWritable: false },
135
+ { pubkey: p.claimPda, isSigner: false, isWritable: true },
136
+ { pubkey: p.vaultPda, isSigner: false, isWritable: true },
137
+ { pubkey: p.holder, isSigner: true, isWritable: false },
138
+ { pubkey: p.dexterAuthority, isSigner: true, isWritable: false }
139
+ ],
140
+ data
141
+ });
142
+ }
143
+
144
+ // src/kit/index.ts
145
+ var import_web34 = require("@solana/web3.js");
146
+ var import_kit = require("@solana/kit");
147
+ function kitInstructionsToWeb3(kitInstructions) {
148
+ return kitInstructions.map((ix) => {
149
+ const accounts = (ix.accounts ?? []).map((acc) => {
150
+ const role = acc.role;
151
+ const hasBooleanShape = typeof acc.signer === "boolean" || typeof acc.writable === "boolean";
152
+ let isSigner = false;
153
+ let isWritable = false;
154
+ if (hasBooleanShape) {
155
+ isSigner = Boolean(acc.signer);
156
+ isWritable = Boolean(acc.writable);
157
+ } else if (typeof role === "number") {
158
+ isSigner = role >= 2;
159
+ isWritable = role % 2 === 1;
160
+ } else if (typeof role === "string") {
161
+ const r = role.toLowerCase();
162
+ isSigner = r.endsWith("signer");
163
+ isWritable = r.startsWith("writable");
164
+ }
165
+ const addressSource = acc.address ?? acc.publicKey;
166
+ const pubkey = addressSource instanceof import_web34.PublicKey ? addressSource : typeof addressSource === "string" ? new import_web34.PublicKey(addressSource) : new import_web34.PublicKey(String(addressSource));
167
+ return { pubkey, isSigner, isWritable };
168
+ });
169
+ return new import_web34.TransactionInstruction({
170
+ programId: new import_web34.PublicKey(ix.programAddress ?? ix.programId),
171
+ keys: accounts,
172
+ data: Buffer.from(ix.data ?? [])
173
+ });
174
+ });
175
+ }
176
+ function getRpc(connection) {
177
+ const endpoint = connection._rpcEndpoint ?? connection.rpcEndpoint;
178
+ if (!endpoint) throw new Error("kit: cannot extract RPC endpoint from connection");
179
+ return (0, import_kit.createSolanaRpc)(endpoint);
180
+ }
181
+
182
+ // src/factoring/instantPayout.ts
183
+ var VAULT_PROGRAM_EXEC_ROLE_ID = 1;
184
+ var USDC_DECIMALS = 6;
185
+ async function buildInstantPayoutInstructions(p) {
186
+ const split = computeFactoringSplit({
187
+ claimAmount: p.claimAmount,
188
+ financierSpread: p.financierSpread
189
+ });
190
+ const settleIx = buildSettleLockedVoucherInstruction({
191
+ swigAddress: p.swigAddress,
192
+ claimPda: p.claimPda,
193
+ vaultPda: p.vaultPda,
194
+ holder: p.financier,
195
+ dexterAuthority: p.dexterAuthority
196
+ });
197
+ const transfers = [
198
+ { destinationAta: p.sellerAta, amount: split.sellerReceives }
199
+ ];
200
+ if (split.financierSpread > 0n) {
201
+ transfers.push({ destinationAta: p.financierAta, amount: split.financierSpread });
202
+ }
203
+ const assemble = p.assembleSignV2 ?? defaultAssembleSignV2;
204
+ const signV2Ixs = await assemble({
205
+ connection: p.connection,
206
+ swigAddress: p.swigAddress,
207
+ feePayer: p.feePayer,
208
+ settleIx,
209
+ transfers
210
+ });
211
+ return [settleIx, ...signV2Ixs];
212
+ }
213
+ var defaultAssembleSignV2 = async (a) => {
214
+ const rpc = getRpc(a.connection);
215
+ const swig = await (0, import_kit3.fetchSwig)(rpc, (0, import_kit4.address)(a.swigAddress.toBase58()));
216
+ if (!swig) throw new Error(`factoring: swig not found on-chain: ${a.swigAddress.toBase58()}`);
217
+ const swigWalletKitAddr = await (0, import_kit3.getSwigWalletAddress)(swig);
218
+ const swigWalletPda = new import_web35.PublicKey(String(swigWalletKitAddr));
219
+ const usdcMint = new import_web35.PublicKey(USDC_MAINNET);
220
+ const sourceAta = (0, import_spl_token.getAssociatedTokenAddressSync)(usdcMint, swigWalletPda, true);
221
+ const transferIxs = a.transfers.map(
222
+ (t) => (0, import_token.getTransferCheckedInstruction)({
223
+ source: (0, import_kit4.address)(sourceAta.toBase58()),
224
+ mint: (0, import_kit4.address)(usdcMint.toBase58()),
225
+ destination: (0, import_kit4.address)(t.destinationAta.toBase58()),
226
+ authority: swigWalletKitAddr,
227
+ amount: t.amount,
228
+ decimals: USDC_DECIMALS
229
+ })
230
+ );
231
+ const signIx = await (0, import_kit3.getSignInstructions)(
232
+ swig,
233
+ VAULT_PROGRAM_EXEC_ROLE_ID,
234
+ transferIxs,
235
+ false,
236
+ { payer: (0, import_kit4.address)(a.feePayer.toBase58()), preInstructions: [a.settleIx] }
237
+ );
238
+ return kitInstructionsToWeb3(signIx);
239
+ };
240
+ // Annotate the CommonJS export names for ESM import in node:
241
+ 0 && (module.exports = {
242
+ buildInstantPayoutInstructions,
243
+ computeFactoringSplit,
244
+ getRpc,
245
+ kitInstructionsToWeb3
246
+ });