@veilo/sdk-core 0.5.0 → 0.7.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 +282 -18
- package/accounts.d.ts +2 -0
- package/accounts.js +3 -0
- package/cloak.d.ts +2 -0
- package/cloak.js +3 -0
- package/config.d.ts +2 -0
- package/config.js +3 -0
- package/dist/cjs/events/index.d.ts +6 -0
- package/dist/cjs/events/index.js +22 -0
- package/dist/cjs/events/parsing.d.ts +25 -0
- package/dist/cjs/events/parsing.js +158 -0
- package/dist/cjs/events/position.d.ts +26 -0
- package/dist/cjs/events/position.js +53 -0
- package/dist/cjs/events/recovery.d.ts +87 -0
- package/dist/cjs/events/recovery.js +281 -0
- package/dist/cjs/events/scanning.d.ts +35 -0
- package/dist/cjs/events/scanning.js +98 -0
- package/dist/cjs/events/tree.d.ts +27 -0
- package/dist/cjs/events/tree.js +63 -0
- package/dist/cjs/events/types.d.ts +39 -0
- package/dist/cjs/events/types.js +2 -0
- package/dist/cjs/events.d.ts +1 -77
- package/dist/cjs/events.js +6 -154
- package/dist/cjs/identity/encoding.d.ts +9 -0
- package/dist/cjs/identity/encoding.js +85 -0
- package/dist/cjs/identity/index.d.ts +4 -0
- package/dist/cjs/identity/index.js +20 -0
- package/dist/cjs/identity/noteKey.d.ts +33 -0
- package/dist/cjs/identity/noteKey.js +97 -0
- package/dist/cjs/identity/spending.d.ts +18 -0
- package/dist/cjs/identity/spending.js +46 -0
- package/dist/cjs/identity/viewKey.d.ts +38 -0
- package/dist/cjs/identity/viewKey.js +105 -0
- package/dist/cjs/idl/index.d.ts +18 -0
- package/dist/cjs/idl/index.js +24 -0
- package/dist/cjs/idl/privacy_pool.json +9907 -9907
- package/dist/cjs/idl/privacy_pool_legacy.d.ts +5 -0
- package/dist/cjs/idl/privacy_pool_legacy.js +3307 -0
- package/dist/cjs/idl/privacy_pool_legacy.json +2302 -0
- package/dist/cjs/idl/privacy_pool_legacy2.d.ts +5 -0
- package/dist/cjs/idl/privacy_pool_legacy2.js +3397 -0
- package/dist/cjs/idl/privacy_pool_legacy2.json +2376 -0
- package/dist/cjs/index.d.ts +8 -3
- package/dist/cjs/index.js +12 -2
- package/dist/cjs/notes/amount.d.ts +2 -0
- package/dist/cjs/notes/amount.js +21 -0
- package/dist/cjs/notes/index.d.ts +4 -0
- package/dist/cjs/notes/index.js +4 -0
- package/dist/cjs/notes/recovery.d.ts +16 -6
- package/dist/cjs/notes/recovery.js +33 -16
- package/dist/cjs/notes/scan.d.ts +74 -0
- package/dist/cjs/notes/scan.js +110 -0
- package/dist/cjs/notes/selection.d.ts +133 -0
- package/dist/cjs/notes/selection.js +260 -0
- package/dist/cjs/notes/spent.d.ts +60 -0
- package/dist/cjs/notes/spent.js +101 -0
- package/dist/cjs/perps/constants.d.ts +16 -0
- package/dist/cjs/perps/constants.js +52 -0
- package/dist/cjs/perps/index.d.ts +5 -0
- package/dist/cjs/perps/index.js +21 -0
- package/dist/cjs/perps/keys.d.ts +16 -0
- package/dist/cjs/perps/keys.js +43 -0
- package/dist/cjs/perps/pdas.d.ts +29 -0
- package/dist/cjs/perps/pdas.js +55 -0
- package/dist/cjs/perps/relayer.d.ts +9 -0
- package/dist/cjs/perps/relayer.js +35 -0
- package/dist/cjs/perps/types.d.ts +126 -0
- package/dist/cjs/perps/types.js +2 -0
- package/dist/cjs/positions/index.d.ts +4 -0
- package/dist/cjs/positions/index.js +20 -0
- package/dist/cjs/positions/keys.d.ts +29 -0
- package/dist/cjs/positions/keys.js +71 -0
- package/dist/cjs/positions/pdas.d.ts +15 -0
- package/dist/cjs/positions/pdas.js +54 -0
- package/dist/cjs/positions/relayer.d.ts +4 -0
- package/dist/cjs/positions/relayer.js +15 -0
- package/dist/cjs/positions/types.d.ts +97 -0
- package/dist/cjs/positions/types.js +2 -0
- package/dist/cjs/predictions/client.d.ts +41 -0
- package/dist/cjs/predictions/client.js +147 -0
- package/dist/cjs/predictions/index.d.ts +5 -0
- package/dist/cjs/predictions/index.js +21 -0
- package/dist/cjs/predictions/keys.d.ts +14 -0
- package/dist/cjs/predictions/keys.js +40 -0
- package/dist/cjs/predictions/pdas.d.ts +6 -0
- package/dist/cjs/predictions/pdas.js +13 -0
- package/dist/cjs/predictions/relayer.d.ts +3 -0
- package/dist/cjs/predictions/relayer.js +11 -0
- package/dist/cjs/predictions/types.d.ts +178 -0
- package/dist/cjs/predictions/types.js +2 -0
- package/dist/cjs/program.d.ts +2 -0
- package/dist/cjs/program.js +8 -7
- package/dist/cjs/prover.d.ts +27 -4
- package/dist/cjs/prover.js +107 -48
- package/dist/cjs/relayer/api.d.ts +41 -0
- package/dist/cjs/relayer/api.js +99 -0
- package/dist/cjs/relayer/client.d.ts +42 -17
- package/dist/cjs/relayer/client.js +94 -17
- package/dist/cjs/relayer/errors.d.ts +1 -1
- package/dist/cjs/relayer/errors.js +1 -1
- package/dist/cjs/relayer/index.d.ts +4 -1
- package/dist/cjs/relayer/index.js +1 -1
- package/dist/cjs/relayer/internal-config.d.ts +36 -0
- package/dist/cjs/relayer/internal-config.js +9 -0
- package/dist/cjs/relayer/internal.d.ts +6 -0
- package/dist/cjs/relayer/internal.js +14 -0
- package/dist/cjs/relayer/transport.d.ts +4 -2
- package/dist/cjs/relayer/transport.js +10 -5
- package/dist/cjs/relayer/types.d.ts +40 -10
- package/dist/cjs/relayer/types.js +1 -1
- package/dist/cjs/shield/owner.js +1 -4
- package/dist/esm/events/index.d.ts +6 -0
- package/dist/esm/events/index.js +6 -0
- package/dist/esm/events/parsing.d.ts +25 -0
- package/dist/esm/events/parsing.js +120 -0
- package/dist/esm/events/position.d.ts +26 -0
- package/dist/esm/events/position.js +48 -0
- package/dist/esm/events/recovery.d.ts +87 -0
- package/dist/esm/events/recovery.js +237 -0
- package/dist/esm/events/scanning.d.ts +35 -0
- package/dist/esm/events/scanning.js +92 -0
- package/dist/esm/events/tree.d.ts +27 -0
- package/dist/esm/events/tree.js +58 -0
- package/dist/esm/events/types.d.ts +39 -0
- package/dist/esm/events/types.js +1 -0
- package/dist/esm/events.d.ts +1 -77
- package/dist/esm/events.js +3 -129
- package/dist/esm/identity/encoding.d.ts +9 -0
- package/dist/esm/identity/encoding.js +75 -0
- package/dist/esm/identity/index.d.ts +4 -0
- package/dist/esm/identity/index.js +4 -0
- package/dist/esm/identity/noteKey.d.ts +33 -0
- package/dist/esm/identity/noteKey.js +91 -0
- package/dist/esm/identity/spending.d.ts +18 -0
- package/dist/esm/identity/spending.js +35 -0
- package/dist/esm/identity/viewKey.d.ts +38 -0
- package/dist/esm/identity/viewKey.js +96 -0
- package/dist/esm/idl/index.d.ts +18 -0
- package/dist/esm/idl/index.js +18 -0
- package/dist/esm/idl/privacy_pool.json +9907 -9907
- package/dist/esm/idl/privacy_pool_legacy.d.ts +5 -0
- package/dist/esm/idl/privacy_pool_legacy.js +3305 -0
- package/dist/esm/idl/privacy_pool_legacy.json +2302 -0
- package/dist/esm/idl/privacy_pool_legacy2.d.ts +5 -0
- package/dist/esm/idl/privacy_pool_legacy2.js +3395 -0
- package/dist/esm/idl/privacy_pool_legacy2.json +2376 -0
- package/dist/esm/index.d.ts +8 -3
- package/dist/esm/index.js +8 -3
- package/dist/esm/notes/amount.d.ts +2 -0
- package/dist/esm/notes/amount.js +18 -0
- package/dist/esm/notes/index.d.ts +4 -0
- package/dist/esm/notes/index.js +4 -0
- package/dist/esm/notes/recovery.d.ts +16 -6
- package/dist/esm/notes/recovery.js +33 -16
- package/dist/esm/notes/scan.d.ts +74 -0
- package/dist/esm/notes/scan.js +105 -0
- package/dist/esm/notes/selection.d.ts +133 -0
- package/dist/esm/notes/selection.js +254 -0
- package/dist/esm/notes/spent.d.ts +60 -0
- package/dist/esm/notes/spent.js +96 -0
- package/dist/esm/perps/constants.d.ts +16 -0
- package/dist/esm/perps/constants.js +48 -0
- package/dist/esm/perps/index.d.ts +5 -0
- package/dist/esm/perps/index.js +5 -0
- package/dist/esm/perps/keys.d.ts +16 -0
- package/dist/esm/perps/keys.js +35 -0
- package/dist/esm/perps/pdas.d.ts +29 -0
- package/dist/esm/perps/pdas.js +47 -0
- package/dist/esm/perps/relayer.d.ts +9 -0
- package/dist/esm/perps/relayer.js +25 -0
- package/dist/esm/perps/types.d.ts +126 -0
- package/dist/esm/perps/types.js +1 -0
- package/dist/esm/positions/index.d.ts +4 -0
- package/dist/esm/positions/index.js +4 -0
- package/dist/esm/positions/keys.d.ts +29 -0
- package/dist/esm/positions/keys.js +65 -0
- package/dist/esm/positions/pdas.d.ts +15 -0
- package/dist/esm/positions/pdas.js +44 -0
- package/dist/esm/positions/relayer.d.ts +4 -0
- package/dist/esm/positions/relayer.js +10 -0
- package/dist/esm/positions/types.d.ts +97 -0
- package/dist/esm/positions/types.js +1 -0
- package/dist/esm/predictions/client.d.ts +41 -0
- package/dist/esm/predictions/client.js +141 -0
- package/dist/esm/predictions/index.d.ts +5 -0
- package/dist/esm/predictions/index.js +5 -0
- package/dist/esm/predictions/keys.d.ts +14 -0
- package/dist/esm/predictions/keys.js +33 -0
- package/dist/esm/predictions/pdas.d.ts +6 -0
- package/dist/esm/predictions/pdas.js +10 -0
- package/dist/esm/predictions/relayer.d.ts +3 -0
- package/dist/esm/predictions/relayer.js +7 -0
- package/dist/esm/predictions/types.d.ts +178 -0
- package/dist/esm/predictions/types.js +1 -0
- package/dist/esm/program.d.ts +2 -0
- package/dist/esm/program.js +4 -3
- package/dist/esm/prover.d.ts +27 -4
- package/dist/esm/prover.js +106 -15
- package/dist/esm/relayer/api.d.ts +41 -0
- package/dist/esm/relayer/api.js +66 -0
- package/dist/esm/relayer/client.d.ts +42 -17
- package/dist/esm/relayer/client.js +94 -17
- package/dist/esm/relayer/errors.d.ts +1 -1
- package/dist/esm/relayer/errors.js +1 -1
- package/dist/esm/relayer/index.d.ts +4 -1
- package/dist/esm/relayer/index.js +1 -1
- package/dist/esm/relayer/internal-config.d.ts +36 -0
- package/dist/esm/relayer/internal-config.js +6 -0
- package/dist/esm/relayer/internal.d.ts +6 -0
- package/dist/esm/relayer/internal.js +10 -0
- package/dist/esm/relayer/transport.d.ts +4 -2
- package/dist/esm/relayer/transport.js +10 -5
- package/dist/esm/relayer/types.d.ts +40 -10
- package/dist/esm/relayer/types.js +1 -1
- package/dist/esm/shield/owner.js +1 -4
- package/identity.d.ts +2 -0
- package/identity.js +3 -0
- package/idl.d.ts +2 -0
- package/idl.js +3 -0
- package/notes.d.ts +2 -0
- package/notes.js +3 -0
- package/package.json +85 -3
- package/perps.d.ts +2 -0
- package/perps.js +3 -0
- package/poseidon.d.ts +2 -0
- package/poseidon.js +3 -0
- package/positions.d.ts +2 -0
- package/positions.js +3 -0
- package/predictions.d.ts +2 -0
- package/predictions.js +3 -0
- package/proof.d.ts +2 -0
- package/proof.js +3 -0
- package/prover.d.ts +2 -0
- package/prover.js +3 -0
- package/relayer.d.ts +2 -0
- package/relayer.js +3 -0
- package/shield.d.ts +2 -0
- package/shield.js +3 -0
- package/transactions.d.ts +2 -0
- package/transactions.js +3 -0
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ The SDK gives TypeScript applications a safe, typed way to:
|
|
|
6
6
|
|
|
7
7
|
- shield SOL or SPL tokens into Veilo;
|
|
8
8
|
- withdraw, privately transfer, or privately swap shielded funds;
|
|
9
|
+
- open and manage private positions, Jupiter perps, and predictions;
|
|
9
10
|
- work with Veilo's relayer without handling its encryption protocol yourself;
|
|
10
11
|
- add partner-powered private sends and swaps through the Cloak API.
|
|
11
12
|
|
|
@@ -31,7 +32,7 @@ You will also need:
|
|
|
31
32
|
- a Solana RPC connection;
|
|
32
33
|
- a connected wallet when a user must sign;
|
|
33
34
|
- the Veilo circuit `.wasm` and `.zkey` files for local proof generation;
|
|
34
|
-
-
|
|
35
|
+
- an API key only for partner services such as Cloak or Jupiter Predictions.
|
|
35
36
|
|
|
36
37
|
## Choose an integration
|
|
37
38
|
|
|
@@ -39,7 +40,7 @@ You will also need:
|
|
|
39
40
|
| --- | --- | --- |
|
|
40
41
|
| Let any wallet shield funds into Veilo | `shield()` | The user's wallet |
|
|
41
42
|
| Add private transfers or swaps to a partner app | `VeiloCloakClient` | The user's wallet |
|
|
42
|
-
| Build a full Veilo wallet experience |
|
|
43
|
+
| Build a full Veilo wallet experience | Managed relayer helpers | The relayer for private spends |
|
|
43
44
|
| Manage proofs, notes, trees, and transactions yourself | Transaction helpers | Your application or relayer |
|
|
44
45
|
|
|
45
46
|
For most third-party deposit integrations, `shield()` is the best starting
|
|
@@ -231,31 +232,240 @@ that fits your application:
|
|
|
231
232
|
| Private transfer | `submitPrivateTransfer()` | `privateTransfer()` |
|
|
232
233
|
| Private swap | `submitPrivateSwap()` | `buildPrivateSwapInstructions()` or `transactSwap()` |
|
|
233
234
|
|
|
234
|
-
### Use the relayer
|
|
235
|
+
### Use the managed relayer helpers
|
|
235
236
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
The SDK owns Veilo's production relayer URL, encryption key, request encryption,
|
|
238
|
+
and safe retry behavior. Applications call typed functions directly; there is
|
|
239
|
+
no relayer client or URL to configure.
|
|
239
240
|
|
|
240
241
|
```ts
|
|
241
242
|
import {
|
|
242
|
-
|
|
243
|
+
submitWithdraw,
|
|
243
244
|
type WithdrawRequest,
|
|
244
245
|
} from "@veilo/sdk-core/relayer";
|
|
245
246
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
247
|
+
async function submitWithdrawal(request: WithdrawRequest) {
|
|
248
|
+
return submitWithdraw(request);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The same focused entry point provides account authentication, encrypted note
|
|
253
|
+
storage, Merkle tree reads, private transfers, private swaps, and these product
|
|
254
|
+
flows:
|
|
255
|
+
|
|
256
|
+
| Product | Relayer helpers |
|
|
257
|
+
| --- | --- |
|
|
258
|
+
| Private positions | `submitOpenPosition()`, `submitClosePosition()`, `submitMergePositions()` |
|
|
259
|
+
| Jupiter perps | `submitJperpOpen()`, `submitJperpClose()`, TP/SL, cancellation, recovery, and reissue helpers |
|
|
260
|
+
| Jupiter predictions | `submitPredictionOpen()` and `submitPredictionReissue()` |
|
|
261
|
+
|
|
262
|
+
#### Submission always targets Veilo's relayer
|
|
263
|
+
|
|
264
|
+
Every helper above submits to Veilo's relayer. There is no `baseUrl` option, no
|
|
265
|
+
client to construct, and no supported way to redirect submission. That is
|
|
266
|
+
deliberate, for two independent reasons:
|
|
267
|
+
|
|
268
|
+
1. **The program requires it.** The privacy pool checks the submitting relayer
|
|
269
|
+
against an on-chain allowlist on every spend. Deposits (`public_amount > 0`)
|
|
270
|
+
are permissionless — which is why `shield()` and `deposit()` work with any
|
|
271
|
+
wallet — but withdrawals, transfers, swaps, positions, perps, and predictions
|
|
272
|
+
all fail with `RelayerNotAllowed` unless the transaction is signed by a
|
|
273
|
+
whitelisted relayer. Pointing the SDK at a different host would produce a
|
|
274
|
+
well-formed request that cannot land on chain.
|
|
275
|
+
2. **These requests carry spending keys.** `TransactNote.privateKey`, and the
|
|
276
|
+
`claimantSecretKey` on position close and merge, *are* the spend authority for
|
|
277
|
+
the funds involved (see [A private note is valuable secret
|
|
278
|
+
data](#a-private-note-is-valuable-secret-data)). A configurable submission
|
|
279
|
+
target would be a configurable destination for user funds.
|
|
280
|
+
|
|
281
|
+
Running your own relayer is a whitelisting conversation rather than a
|
|
282
|
+
configuration flag — see [Support](#support). Reaching past the package's
|
|
283
|
+
`exports` map to import internal modules is unsupported and not covered by
|
|
284
|
+
semver.
|
|
285
|
+
|
|
286
|
+
### Finding your notes on the public feed
|
|
287
|
+
|
|
288
|
+
Every row in the compact feed is ciphertext plus a one-byte view tag; nothing on
|
|
289
|
+
it says who a note belongs to. You find yours by trial decryption, and the view
|
|
290
|
+
tag makes that cheap — it rejects roughly 255 of every 256 foreign rows with a
|
|
291
|
+
single hash instead of a full decrypt.
|
|
292
|
+
|
|
293
|
+
```ts
|
|
294
|
+
import { scanCompactNotes, fetchNotesByCommitment } from "@veilo/sdk-core";
|
|
295
|
+
|
|
296
|
+
const { notes, scanned, nextCursor } = await scanCompactNotes(walletSecretKey, {
|
|
297
|
+
onPage: ({ matched }) => console.log(`${matched} found so far`),
|
|
250
298
|
});
|
|
299
|
+
```
|
|
251
300
|
|
|
252
|
-
|
|
253
|
-
|
|
301
|
+
It paginates to exhaustion by default and derives the X25519 key once for the
|
|
302
|
+
whole scan. Stop early with `maxPages` or by returning `false` from `onPage`;
|
|
303
|
+
`nextCursor` is then non-null and can be passed back later to resume. The feed
|
|
304
|
+
carries only unspent, unclaimed notes, and it needs no auth token — scanning
|
|
305
|
+
reveals nothing without your key.
|
|
306
|
+
|
|
307
|
+
`fetchNotesByCommitment(commitments)` looks up known commitments instead,
|
|
308
|
+
chunked at the server's 50-per-request cap and issued concurrently. Commitments
|
|
309
|
+
the relayer does not know are simply absent from the result.
|
|
310
|
+
|
|
311
|
+
### Consolidating notes before a large spend
|
|
312
|
+
|
|
313
|
+
When no one or two notes cover an amount, `selectNotesForAmount` reports
|
|
314
|
+
`requiresMerge`. `planNoteConsolidation` says what to do about it:
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
const plan = planNoteConsolidation(unspentNotes, amountRaw, { mint });
|
|
318
|
+
if (plan.ok) {
|
|
319
|
+
for (const { inputs, outputAmount } of plan.steps) {
|
|
320
|
+
// one 2-in-1-out privateTransfer to yourself per step
|
|
321
|
+
}
|
|
254
322
|
}
|
|
255
323
|
```
|
|
256
324
|
|
|
257
|
-
|
|
258
|
-
|
|
325
|
+
Each step is a self-transfer combining two inputs into one, so k notes need k-2
|
|
326
|
+
steps before a final two-input spend. Steps chain — a later step can consume an
|
|
327
|
+
earlier step's output, and inputs are tagged `{ kind: "note" }` or
|
|
328
|
+
`{ kind: "step", step }` so you always know which. The two smallest are merged
|
|
329
|
+
each round, which retires dust first and leaves large notes intact. The plan is
|
|
330
|
+
pure: it computes, it does not execute.
|
|
331
|
+
|
|
332
|
+
### Spend status and private balance
|
|
333
|
+
|
|
334
|
+
Nothing in a note says whether it has been spent — a note is yours until its
|
|
335
|
+
nullifier is published. So a balance is always two steps, and the SDK gives you
|
|
336
|
+
both:
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
import { getPrivateBalance, checkNullifiersSpent } from "@veilo/sdk-core";
|
|
340
|
+
|
|
341
|
+
const { total, byMint, unspent, spent } = await getPrivateBalance(myNotes);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Each note needs an `amount`, a 64-character hex `nullifier`, and optionally a
|
|
345
|
+
`mint` to group by. `getPrivateBalance` asks the relayer which nullifiers are
|
|
346
|
+
spent, then sums what is left; `unspent` and `spent` hand back your own note
|
|
347
|
+
objects, so you can render from them directly.
|
|
348
|
+
|
|
349
|
+
`checkNullifiersSpent(nullifiers)` is the same question on its own. It
|
|
350
|
+
deduplicates, splits into the server's 200-per-request batches, issues them
|
|
351
|
+
concurrently, and returns a `Set` for membership testing. It also lower-cases
|
|
352
|
+
input: the endpoint validates case-insensitively but answers in lower case, so
|
|
353
|
+
upper-case hex would otherwise never match and every note would read as unspent.
|
|
354
|
+
|
|
355
|
+
To compute a balance without the relayer — from a chain scan of nullifier
|
|
356
|
+
events, or a local cache — supply the answer yourself:
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
await getPrivateBalance(myNotes, { resolveSpent: async (ns) => mySpentSet(ns) });
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Amounts stay `bigint` end to end. A `number` amount above `Number.MAX_SAFE_INTEGER`
|
|
363
|
+
is rejected rather than silently rounded, and a malformed nullifier throws
|
|
364
|
+
instead of counting as unspent — either would overstate a balance.
|
|
365
|
+
|
|
366
|
+
### Choosing notes to spend
|
|
367
|
+
|
|
368
|
+
Two rules govern this, and both are easy to get wrong:
|
|
369
|
+
|
|
370
|
+
- the transaction circuit is **2-in-2-out**, so one transaction spends at most
|
|
371
|
+
two notes;
|
|
372
|
+
- notes are only co-spendable inside the **same Merkle tree**, and the tree is
|
|
373
|
+
derived from the mint.
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
import { selectNotesForAmount, canonicalTreeId } from "@veilo/sdk-core";
|
|
377
|
+
|
|
378
|
+
const selection = selectNotesForAmount(unspentNotes, amountRaw, { mint });
|
|
379
|
+
if (!selection.ok) throw new Error(selection.message); // NO_NOTES | INSUFFICIENT_FUNDS
|
|
380
|
+
if (selection.requiresMerge) {
|
|
381
|
+
// more than two inputs — combine them before proving
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
It searches each tree independently and returns the best result: the smallest
|
|
386
|
+
single note that covers the amount, else the pair with the least change (found
|
|
387
|
+
by a two-pointer scan, not an all-pairs search), else the largest notes greedily
|
|
388
|
+
with `requiresMerge` set. A failure reports `available`, the largest total
|
|
389
|
+
reachable within one tree.
|
|
390
|
+
|
|
391
|
+
`canonicalTreeId(mint)` derives a note's tree the way the relayer does. **Derive
|
|
392
|
+
it; never trust a stored `treeId`.** Change notes are written with the on-chain
|
|
393
|
+
shard index while deposits and synced notes carry the mint-derived id — for
|
|
394
|
+
native SOL both are 0 so the difference hides, but for SPL tokens they diverge
|
|
395
|
+
and co-spending across the two fails at proof time as a commitment mismatch.
|
|
396
|
+
|
|
397
|
+
### Private product keys and recovery
|
|
398
|
+
|
|
399
|
+
Private positions, perps, and predictions use deterministic client-held keys.
|
|
400
|
+
The SDK provides the exact derivations used by Veilo's wallet, extension,
|
|
401
|
+
relayer, and program tests. Keep the spending key and claimant secret on the
|
|
402
|
+
user's device; send claimant secrets only inside the SDK's encrypted relayer
|
|
403
|
+
requests.
|
|
404
|
+
|
|
405
|
+
```ts
|
|
406
|
+
import {
|
|
407
|
+
derivePositionKeyBundle,
|
|
408
|
+
deriveSpendingKeyWithSigner,
|
|
409
|
+
encodeClaimantSecretKey,
|
|
410
|
+
initPoseidon,
|
|
411
|
+
submitOpenPosition,
|
|
412
|
+
} from "@veilo/sdk-core";
|
|
413
|
+
|
|
414
|
+
await initPoseidon();
|
|
415
|
+
const spendingKey = await deriveSpendingKeyWithSigner(
|
|
416
|
+
(message) => wallet.signMessage(message),
|
|
417
|
+
);
|
|
418
|
+
const positionKeys = derivePositionKeyBundle(spendingKey, nextPositionIndex);
|
|
419
|
+
|
|
420
|
+
await submitOpenPosition({
|
|
421
|
+
// Select private source notes in your wallet before calling the relayer.
|
|
422
|
+
notes,
|
|
423
|
+
sourceMintAddress,
|
|
424
|
+
destMintAddress,
|
|
425
|
+
swapAmountRaw,
|
|
426
|
+
slippageBps: 50,
|
|
427
|
+
userPublicKey: wallet.publicKey.toBase58(),
|
|
428
|
+
veiloPublicKey,
|
|
429
|
+
position: positionKeys.position,
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
// Persist the returned position data and `nextPositionIndex`. Re-derive the
|
|
433
|
+
// same claimant later when closing or merging the position.
|
|
434
|
+
const claimantSecretKey = encodeClaimantSecretKey(positionKeys.claimant);
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Use `deriveJperpKeyBundle()` and `getJperpMarketPayload()` for private perps.
|
|
438
|
+
Use `derivePredictionKeyBundle()` for private predictions. Lower-level key
|
|
439
|
+
derivations are also exported when an application needs them individually. The
|
|
440
|
+
PDA helpers in each focused entry point support on-chain recovery scans on a
|
|
441
|
+
fresh device.
|
|
442
|
+
|
|
443
|
+
Predictions have one additional step: Jupiter returns an unsigned order,
|
|
444
|
+
close, or claim transaction. The SDK exposes that API without taking custody
|
|
445
|
+
of signing:
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
import {
|
|
449
|
+
JupiterPredictionClient,
|
|
450
|
+
deserializePredictionTransaction,
|
|
451
|
+
} from "@veilo/sdk-core/predictions";
|
|
452
|
+
|
|
453
|
+
const predictions = new JupiterPredictionClient({ apiKey: jupiterApiKey });
|
|
454
|
+
const order = await predictions.placeOrder({
|
|
455
|
+
ownerPubkey: ephemeral.publicKey.toBase58(),
|
|
456
|
+
marketId,
|
|
457
|
+
isYes: true,
|
|
458
|
+
isBuy: true,
|
|
459
|
+
depositAmount: "5000000",
|
|
460
|
+
depositMint: usdcMint,
|
|
461
|
+
});
|
|
462
|
+
const transaction = deserializePredictionTransaction(order);
|
|
463
|
+
// Ask the deterministic ephemeral wallet to sign, then submit and confirm it.
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
The SDK deliberately does not own application storage or choose which notes to
|
|
467
|
+
spend. Persist indexes and returned product records only after the corresponding
|
|
468
|
+
transaction is confirmed.
|
|
259
469
|
|
|
260
470
|
### Use the direct helpers
|
|
261
471
|
|
|
@@ -347,8 +557,28 @@ for shields and call a deposit's `commit()` callback only after confirmation.
|
|
|
347
557
|
### Proof files are separate
|
|
348
558
|
|
|
349
559
|
Circuit `.wasm` and `.zkey` files are intentionally not bundled with the npm
|
|
350
|
-
package because they are large
|
|
351
|
-
to `createTransactionProver()` and
|
|
560
|
+
package because they are large — `files` ships `dist/` only. Provide local
|
|
561
|
+
paths, byte arrays, or hosted URLs to `createTransactionProver()` and
|
|
562
|
+
`createSwapProver()`.
|
|
563
|
+
|
|
564
|
+
Both arguments are optional. Omit them and the prover resolves artifacts from
|
|
565
|
+
disk on first use, first hit wins:
|
|
566
|
+
|
|
567
|
+
1. `$VEILO_CIRCUITS_DIR`
|
|
568
|
+
2. `<package>/circuits` — populated by `npm run copy:circuits`
|
|
569
|
+
3. `<cwd>/circuits`
|
|
570
|
+
4. `<cwd>/node_modules/@veilo/sdk-core/circuits`
|
|
571
|
+
|
|
572
|
+
```ts
|
|
573
|
+
const prover = createTransactionProver(); // resolved from disk
|
|
574
|
+
const prover = createTransactionProver({ wasmPath, zkeyPath }); // explicit
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
`resolveCircuitArtifacts("transaction" | "swap")` performs that lookup on its
|
|
578
|
+
own if you want the paths. Resolution is **Node-only and lazy** — it imports
|
|
579
|
+
`node:fs` inside the call so browser bundles can still import this module, and
|
|
580
|
+
there is nothing to resolve in a browser anyway. Browser builds must pass
|
|
581
|
+
`CircuitArtifacts` explicitly. A miss throws with every path it tried.
|
|
352
582
|
|
|
353
583
|
## Error handling
|
|
354
584
|
|
|
@@ -388,8 +618,11 @@ import { shield } from "@veilo/sdk-core";
|
|
|
388
618
|
import { getPoolPdas } from "@veilo/sdk-core/accounts";
|
|
389
619
|
import { createUTXO } from "@veilo/sdk-core/notes";
|
|
390
620
|
import { deposit, withdraw } from "@veilo/sdk-core/transactions";
|
|
391
|
-
import {
|
|
621
|
+
import { submitWithdraw } from "@veilo/sdk-core/relayer";
|
|
392
622
|
import { VeiloCloakClient } from "@veilo/sdk-core/cloak";
|
|
623
|
+
import { derivePositionKeyBundle } from "@veilo/sdk-core/positions";
|
|
624
|
+
import { getJperpMarketPayload } from "@veilo/sdk-core/perps";
|
|
625
|
+
import { JupiterPredictionClient } from "@veilo/sdk-core/predictions";
|
|
393
626
|
```
|
|
394
627
|
|
|
395
628
|
Available focused entry points:
|
|
@@ -397,7 +630,12 @@ Available focused entry points:
|
|
|
397
630
|
- `@veilo/sdk-core/accounts`
|
|
398
631
|
- `@veilo/sdk-core/cloak`
|
|
399
632
|
- `@veilo/sdk-core/config`
|
|
633
|
+
- `@veilo/sdk-core/idl`
|
|
634
|
+
- `@veilo/sdk-core/identity`
|
|
400
635
|
- `@veilo/sdk-core/notes`
|
|
636
|
+
- `@veilo/sdk-core/perps`
|
|
637
|
+
- `@veilo/sdk-core/positions`
|
|
638
|
+
- `@veilo/sdk-core/predictions`
|
|
401
639
|
- `@veilo/sdk-core/poseidon`
|
|
402
640
|
- `@veilo/sdk-core/proof`
|
|
403
641
|
- `@veilo/sdk-core/prover`
|
|
@@ -421,6 +659,32 @@ or relayer:
|
|
|
421
659
|
These APIs are fully typed. Use their TypeScript definitions as the source of
|
|
422
660
|
truth for required inputs.
|
|
423
661
|
|
|
662
|
+
### Historical IDLs and commitment recovery
|
|
663
|
+
|
|
664
|
+
The SDK includes the current, legacy, and legacy-2 privacy-pool IDLs used by the
|
|
665
|
+
relayer. Event scans automatically try the historical layouts, so applications
|
|
666
|
+
can rebuild trees across program upgrades.
|
|
667
|
+
|
|
668
|
+
```ts
|
|
669
|
+
import {
|
|
670
|
+
PRIVACY_POOL_IDLS,
|
|
671
|
+
buildTreeFromEvents,
|
|
672
|
+
resolveCommitmentEvents,
|
|
673
|
+
} from "@veilo/sdk-core";
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
`buildTreeFromEvents()` includes Veilo's protected historical repairs by
|
|
677
|
+
default and rejects gaps that would produce an incorrect root. When a confirmed
|
|
678
|
+
instruction appended commitments without emitting `CommitmentEvent`, use
|
|
679
|
+
`resolveCommitmentEvents()` with the expected commitments and current local
|
|
680
|
+
tree. It prefers emitted metadata and computes only the missing entries.
|
|
681
|
+
|
|
682
|
+
For the deployed eventless `open_position` path, use
|
|
683
|
+
`recoverEventlessOpenPositionEvents()`. It decodes both commitments from the
|
|
684
|
+
instruction and reads the authoritative global position-tree leaf index from
|
|
685
|
+
the program-owned PositionPDA. `buildGlobalPositionTreeFromEvents()` mirrors
|
|
686
|
+
the relayer's all-mint position-tree reconstruction.
|
|
687
|
+
|
|
424
688
|
## Development
|
|
425
689
|
|
|
426
690
|
```bash
|
package/accounts.d.ts
ADDED
package/accounts.js
ADDED
package/cloak.d.ts
ADDED
package/cloak.js
ADDED
package/config.d.ts
ADDED
package/config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./types.js"), exports);
|
|
18
|
+
__exportStar(require("./parsing.js"), exports);
|
|
19
|
+
__exportStar(require("./position.js"), exports);
|
|
20
|
+
__exportStar(require("./recovery.js"), exports);
|
|
21
|
+
__exportStar(require("./scanning.js"), exports);
|
|
22
|
+
__exportStar(require("./tree.js"), exports);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import { type VersionedPrivacyPoolIdl } from "../idl/index.js";
|
|
3
|
+
import type { CommitmentEvent, NullifierSpentEvent, ParsedVeiloEvent } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Decode logs using the current, legacy, and legacy-2 IDLs.
|
|
6
|
+
*
|
|
7
|
+
* IDLs are evaluated in the relayer's current/legacy/legacy-2 order. Anchor's
|
|
8
|
+
* Borsh decoder accepts trailing bytes, however, so every successful parse is
|
|
9
|
+
* considered and the richest result wins. That preserves the compact fields
|
|
10
|
+
* in legacy-2 events instead of misclassifying them as the shorter legacy form.
|
|
11
|
+
* Ties retain the relayer's order.
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseVeiloEventsWithFallback(logMessages: readonly string[] | null | undefined, programId: PublicKey, idls?: readonly VersionedPrivacyPoolIdl[]): ParsedVeiloEvent[];
|
|
14
|
+
export declare function parseCommitmentEventsFromLogs(params: {
|
|
15
|
+
logMessages: readonly string[] | null | undefined;
|
|
16
|
+
programId: PublicKey;
|
|
17
|
+
txSignature: string;
|
|
18
|
+
slot: number;
|
|
19
|
+
}): CommitmentEvent[];
|
|
20
|
+
export declare function parseNullifierEventsFromLogs(params: {
|
|
21
|
+
logMessages: readonly string[] | null | undefined;
|
|
22
|
+
programId: PublicKey;
|
|
23
|
+
txSignature: string;
|
|
24
|
+
slot: number;
|
|
25
|
+
}): NullifierSpentEvent[];
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.parseVeiloEventsWithFallback = parseVeiloEventsWithFallback;
|
|
37
|
+
exports.parseCommitmentEventsFromLogs = parseCommitmentEventsFromLogs;
|
|
38
|
+
exports.parseNullifierEventsFromLogs = parseNullifierEventsFromLogs;
|
|
39
|
+
const anchor = __importStar(require("@coral-xyz/anchor"));
|
|
40
|
+
const web3_js_1 = require("@solana/web3.js");
|
|
41
|
+
const index_js_1 = require("../idl/index.js");
|
|
42
|
+
/**
|
|
43
|
+
* Decode logs using the current, legacy, and legacy-2 IDLs.
|
|
44
|
+
*
|
|
45
|
+
* IDLs are evaluated in the relayer's current/legacy/legacy-2 order. Anchor's
|
|
46
|
+
* Borsh decoder accepts trailing bytes, however, so every successful parse is
|
|
47
|
+
* considered and the richest result wins. That preserves the compact fields
|
|
48
|
+
* in legacy-2 events instead of misclassifying them as the shorter legacy form.
|
|
49
|
+
* Ties retain the relayer's order.
|
|
50
|
+
*/
|
|
51
|
+
function parseVeiloEventsWithFallback(logMessages, programId, idls = index_js_1.PRIVACY_POOL_IDLS) {
|
|
52
|
+
if (!logMessages?.length)
|
|
53
|
+
return [];
|
|
54
|
+
let best = [];
|
|
55
|
+
let bestScore = -1;
|
|
56
|
+
for (const candidate of idls) {
|
|
57
|
+
try {
|
|
58
|
+
const parser = new anchor.EventParser(programId, new anchor.BorshCoder(candidate.idl));
|
|
59
|
+
const parsed = Array.from(parser.parseLogs([...logMessages])).map((event) => ({
|
|
60
|
+
name: event.name,
|
|
61
|
+
data: event.data,
|
|
62
|
+
idlVersion: candidate.version,
|
|
63
|
+
}));
|
|
64
|
+
const score = parsed.reduce((total, event) => total + decodedFieldCount(event.data), 0);
|
|
65
|
+
if (score > bestScore) {
|
|
66
|
+
best = parsed;
|
|
67
|
+
bestScore = score;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// The discriminator is shared while historical payload lengths differ.
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return best;
|
|
75
|
+
}
|
|
76
|
+
function parseCommitmentEventsFromLogs(params) {
|
|
77
|
+
const { logMessages, programId, txSignature, slot } = params;
|
|
78
|
+
const out = [];
|
|
79
|
+
for (const event of parseVeiloEventsWithFallback(logMessages, programId)) {
|
|
80
|
+
if (event.name.toLowerCase() !== "commitmentevent")
|
|
81
|
+
continue;
|
|
82
|
+
const data = event.data;
|
|
83
|
+
const mintAddress = toPublicKey(field(data, "mintAddress", "mint_address"));
|
|
84
|
+
const ephemeralPublicKey = optionalBytes(field(data, "ephemeralPublicKey", "ephemeral_public_key"));
|
|
85
|
+
const encryptedBlob = optionalBytes(field(data, "encryptedBlob", "encrypted_blob"));
|
|
86
|
+
const rawViewTag = field(data, "viewTag", "view_tag");
|
|
87
|
+
out.push({
|
|
88
|
+
commitment: toBytes(field(data, "commitment"), 32, "commitment"),
|
|
89
|
+
leafIndex: toSafeNumber(field(data, "leafIndex", "leaf_index"), "leafIndex"),
|
|
90
|
+
newRoot: toBytes(field(data, "newRoot", "new_root"), 32, "newRoot"),
|
|
91
|
+
timestamp: toSafeNumber(field(data, "timestamp"), "timestamp"),
|
|
92
|
+
mintAddress,
|
|
93
|
+
treeId: toSafeNumber(field(data, "treeId", "tree_id"), "treeId"),
|
|
94
|
+
txSignature,
|
|
95
|
+
slot,
|
|
96
|
+
...(ephemeralPublicKey ? { ephemeralPublicKey } : {}),
|
|
97
|
+
...(encryptedBlob ? { encryptedBlob } : {}),
|
|
98
|
+
...(rawViewTag !== undefined
|
|
99
|
+
? { viewTag: toSafeNumber(rawViewTag, "viewTag") }
|
|
100
|
+
: {}),
|
|
101
|
+
source: "emitted",
|
|
102
|
+
idlVersion: event.idlVersion,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
function parseNullifierEventsFromLogs(params) {
|
|
108
|
+
const { logMessages, programId, txSignature, slot } = params;
|
|
109
|
+
const out = [];
|
|
110
|
+
for (const event of parseVeiloEventsWithFallback(logMessages, programId)) {
|
|
111
|
+
if (event.name.toLowerCase() !== "nullifierspent")
|
|
112
|
+
continue;
|
|
113
|
+
const data = event.data;
|
|
114
|
+
out.push({
|
|
115
|
+
nullifier: toBytes(field(data, "nullifier"), 32, "nullifier"),
|
|
116
|
+
timestamp: toSafeNumber(field(data, "timestamp"), "timestamp"),
|
|
117
|
+
mintAddress: toPublicKey(field(data, "mintAddress", "mint_address")),
|
|
118
|
+
treeId: toSafeNumber(field(data, "treeId", "tree_id"), "treeId"),
|
|
119
|
+
txSignature,
|
|
120
|
+
slot,
|
|
121
|
+
idlVersion: event.idlVersion,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return out;
|
|
125
|
+
}
|
|
126
|
+
function field(data, camel, snake) {
|
|
127
|
+
return data[camel] ?? (snake ? data[snake] : undefined);
|
|
128
|
+
}
|
|
129
|
+
function optionalBytes(value) {
|
|
130
|
+
return value === undefined || value === null
|
|
131
|
+
? undefined
|
|
132
|
+
: new Uint8Array(value);
|
|
133
|
+
}
|
|
134
|
+
function decodedFieldCount(value) {
|
|
135
|
+
return value && typeof value === "object" ? Object.keys(value).length : 0;
|
|
136
|
+
}
|
|
137
|
+
function toBytes(value, length, label) {
|
|
138
|
+
const bytes = new Uint8Array(value);
|
|
139
|
+
if (bytes.length !== length) {
|
|
140
|
+
throw new Error(`${label} must be ${length} bytes, got ${bytes.length}`);
|
|
141
|
+
}
|
|
142
|
+
return bytes;
|
|
143
|
+
}
|
|
144
|
+
function toPublicKey(value) {
|
|
145
|
+
if (value instanceof web3_js_1.PublicKey)
|
|
146
|
+
return value;
|
|
147
|
+
return new web3_js_1.PublicKey(value);
|
|
148
|
+
}
|
|
149
|
+
function toSafeNumber(value, label) {
|
|
150
|
+
if (value === undefined || value === null) {
|
|
151
|
+
throw new Error(`Missing ${label} in decoded event`);
|
|
152
|
+
}
|
|
153
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
154
|
+
if (!Number.isSafeInteger(numeric)) {
|
|
155
|
+
throw new Error(`${label} is outside JavaScript's safe integer range`);
|
|
156
|
+
}
|
|
157
|
+
return numeric;
|
|
158
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Idl, Program } from "@coral-xyz/anchor";
|
|
2
|
+
import { PublicKey } from "@solana/web3.js";
|
|
3
|
+
import type { CommitmentEvent } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Privacy-pool mints copied from the relayer's global position-tree classifier.
|
|
6
|
+
* Position commitments use non-pool destination mints at the same tree ID.
|
|
7
|
+
*/
|
|
8
|
+
export declare const POSITION_TREE_POOL_MINTS: readonly PublicKey[];
|
|
9
|
+
export declare function isGlobalPositionCommitment(event: CommitmentEvent): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Rebuild the one global position tree shared across every position mint.
|
|
12
|
+
* This mirrors the relayer: scan all mints for the position tree ID, then drop
|
|
13
|
+
* normal privacy-pool mint events before sorting by the global leaf index.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildGlobalPositionTreeFromEvents<T extends Idl>(params: {
|
|
16
|
+
program: Program<T>;
|
|
17
|
+
positionTreeId?: number;
|
|
18
|
+
depth?: number;
|
|
19
|
+
additionalEvents?: readonly CommitmentEvent[];
|
|
20
|
+
includeProtectedEvents?: boolean;
|
|
21
|
+
strictLeafIndices?: boolean;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
tree: import("../merkle.js").MerkleTree;
|
|
24
|
+
events: CommitmentEvent[];
|
|
25
|
+
latestSignature: string;
|
|
26
|
+
}>;
|