@veilo/sdk-core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +449 -1243
- 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 -2
- package/config.js +2 -3
- package/dist/cjs/accounts/admin.d.ts +84 -0
- package/dist/cjs/accounts/admin.js +208 -0
- package/dist/cjs/accounts/errors.d.ts +6 -0
- package/dist/cjs/accounts/errors.js +98 -0
- package/dist/cjs/accounts/index.d.ts +4 -0
- package/dist/cjs/accounts/index.js +20 -0
- package/dist/cjs/accounts/pdas.d.ts +23 -0
- package/dist/cjs/accounts/pdas.js +44 -0
- package/dist/cjs/accounts/queries.d.ts +41 -0
- package/dist/cjs/accounts/queries.js +95 -0
- package/dist/cjs/client.d.ts +2 -407
- package/dist/cjs/client.js +6 -938
- package/dist/cjs/cloak/client.d.ts +28 -0
- package/dist/cjs/cloak/client.js +68 -0
- package/dist/cjs/cloak/errors.d.ts +13 -0
- package/dist/cjs/cloak/errors.js +25 -0
- package/dist/cjs/cloak/helpers.d.ts +6 -0
- package/dist/cjs/cloak/helpers.js +35 -0
- package/dist/cjs/cloak/index.d.ts +6 -0
- package/dist/cjs/cloak/index.js +24 -0
- package/dist/cjs/cloak/polling.d.ts +7 -0
- package/dist/cjs/cloak/polling.js +66 -0
- package/dist/cjs/cloak/transport.d.ts +15 -0
- package/dist/cjs/cloak/transport.js +119 -0
- package/dist/cjs/cloak/types.d.ts +188 -0
- package/dist/cjs/cloak/types.js +5 -0
- package/dist/cjs/cloak.d.ts +1 -0
- package/dist/cjs/cloak.js +18 -0
- package/dist/cjs/compactNote.d.ts +21 -0
- package/dist/cjs/compactNote.js +31 -7
- 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.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.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 +9 -3
- package/dist/cjs/index.js +15 -2
- package/dist/cjs/notes/amount.d.ts +2 -0
- package/dist/cjs/notes/amount.js +21 -0
- package/dist/cjs/notes/encryption.d.ts +41 -0
- package/dist/cjs/notes/encryption.js +75 -0
- package/dist/cjs/notes/index.d.ts +8 -0
- package/dist/cjs/notes/index.js +24 -0
- package/dist/cjs/notes/mailbox.d.ts +70 -0
- package/dist/cjs/notes/mailbox.js +164 -0
- package/dist/cjs/notes/model.d.ts +91 -0
- package/dist/cjs/notes/model.js +109 -0
- package/dist/cjs/notes/nullifier.d.ts +27 -0
- package/dist/cjs/notes/nullifier.js +45 -0
- package/dist/cjs/notes/recovery.d.ts +20 -0
- package/dist/cjs/notes/recovery.js +48 -0
- package/dist/cjs/notes/selection.d.ts +77 -0
- package/dist/cjs/notes/selection.js +193 -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/proof.d.ts +1 -183
- package/dist/cjs/proof.js +16 -290
- package/dist/cjs/proofs/encoding.d.ts +17 -0
- package/dist/cjs/proofs/encoding.js +72 -0
- package/dist/cjs/proofs/formatting.d.ts +6 -0
- package/dist/cjs/proofs/formatting.js +34 -0
- package/dist/cjs/proofs/index.d.ts +5 -0
- package/dist/cjs/proofs/index.js +21 -0
- package/dist/cjs/proofs/swap.d.ts +87 -0
- package/dist/cjs/proofs/swap.js +144 -0
- package/dist/cjs/proofs/transaction.d.ts +28 -0
- package/dist/cjs/proofs/transaction.js +110 -0
- package/dist/cjs/proofs/types.d.ts +70 -0
- package/dist/cjs/proofs/types.js +2 -0
- package/dist/cjs/prover.d.ts +30 -4
- package/dist/cjs/prover.js +118 -49
- package/dist/cjs/relayer/api.d.ts +31 -0
- package/dist/cjs/relayer/api.js +86 -0
- package/dist/cjs/relayer/client.d.ts +73 -0
- package/dist/cjs/relayer/client.js +206 -0
- package/dist/cjs/relayer/crypto.d.ts +5 -0
- package/dist/cjs/relayer/crypto.js +26 -0
- package/dist/cjs/relayer/encoding.d.ts +2 -0
- package/dist/cjs/relayer/encoding.js +23 -0
- package/dist/cjs/relayer/errors.d.ts +7 -0
- package/dist/cjs/relayer/errors.js +17 -0
- package/dist/cjs/relayer/index.d.ts +6 -0
- package/dist/cjs/relayer/index.js +19 -0
- 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 +19 -0
- package/dist/cjs/relayer/transport.js +68 -0
- package/dist/{src/relayer.d.ts → cjs/relayer/types.d.ts} +53 -96
- package/dist/cjs/relayer/types.js +5 -0
- package/dist/cjs/relayer.d.ts +1 -318
- package/dist/cjs/relayer.js +15 -254
- package/dist/cjs/shield/alt.js +8 -8
- package/dist/cjs/shield/errors.js +2 -2
- package/dist/cjs/shield/finalize.js +2 -2
- package/dist/cjs/shield/ix.d.ts +1 -1
- package/dist/cjs/shield/owner.js +9 -11
- package/dist/cjs/shield/ports.js +3 -3
- package/dist/cjs/shield/preflight.js +3 -3
- package/dist/cjs/shield/shield.js +20 -19
- package/dist/cjs/shield/types.d.ts +1 -1
- package/dist/cjs/transactions/deposit.d.ts +94 -0
- package/dist/cjs/transactions/deposit.js +234 -0
- package/dist/cjs/transactions/index.d.ts +7 -0
- package/dist/cjs/transactions/index.js +26 -0
- package/dist/cjs/transactions/swap.d.ts +71 -0
- package/dist/cjs/transactions/swap.js +184 -0
- package/dist/cjs/transactions/transact.d.ts +34 -0
- package/dist/cjs/transactions/transact.js +146 -0
- package/dist/cjs/transactions/transfer.d.ts +51 -0
- package/dist/cjs/transactions/transfer.js +106 -0
- package/dist/cjs/transactions/withdraw.d.ts +52 -0
- package/dist/cjs/transactions/withdraw.js +104 -0
- package/dist/cjs/utxo.d.ts +1 -235
- package/dist/cjs/utxo.js +15 -404
- package/dist/esm/accounts/admin.d.ts +84 -0
- package/dist/esm/accounts/admin.js +165 -0
- package/dist/esm/accounts/errors.d.ts +6 -0
- package/dist/esm/accounts/errors.js +95 -0
- package/dist/esm/accounts/index.d.ts +4 -0
- package/dist/esm/accounts/index.js +4 -0
- package/dist/esm/accounts/pdas.d.ts +23 -0
- package/dist/esm/accounts/pdas.js +38 -0
- package/dist/esm/accounts/queries.d.ts +41 -0
- package/dist/esm/accounts/queries.js +88 -0
- package/dist/esm/client.d.ts +2 -407
- package/dist/esm/client.js +3 -891
- package/dist/esm/cloak/client.d.ts +28 -0
- package/dist/esm/cloak/client.js +64 -0
- package/dist/esm/cloak/errors.d.ts +13 -0
- package/dist/esm/cloak/errors.js +21 -0
- package/dist/esm/cloak/helpers.d.ts +6 -0
- package/dist/esm/cloak/helpers.js +31 -0
- package/dist/esm/cloak/index.d.ts +6 -0
- package/dist/esm/cloak/index.js +6 -0
- package/dist/esm/cloak/polling.d.ts +7 -0
- package/dist/esm/cloak/polling.js +63 -0
- package/dist/esm/cloak/transport.d.ts +15 -0
- package/dist/esm/cloak/transport.js +115 -0
- package/dist/esm/cloak/types.d.ts +188 -0
- package/dist/esm/cloak/types.js +4 -0
- package/dist/esm/cloak.d.ts +1 -0
- package/dist/esm/cloak.js +2 -0
- package/dist/esm/compactNote.d.ts +21 -0
- package/dist/esm/compactNote.js +24 -1
- 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 +9 -3
- package/dist/esm/index.js +10 -3
- package/dist/esm/notes/amount.d.ts +2 -0
- package/dist/esm/notes/amount.js +18 -0
- package/dist/esm/notes/encryption.d.ts +41 -0
- package/dist/esm/notes/encryption.js +67 -0
- package/dist/esm/notes/index.d.ts +8 -0
- package/dist/esm/notes/index.js +8 -0
- package/dist/esm/notes/mailbox.d.ts +70 -0
- package/dist/esm/notes/mailbox.js +154 -0
- package/dist/esm/notes/model.d.ts +91 -0
- package/dist/esm/notes/model.js +99 -0
- package/dist/esm/notes/nullifier.d.ts +27 -0
- package/dist/esm/notes/nullifier.js +40 -0
- package/dist/esm/notes/recovery.d.ts +20 -0
- package/dist/esm/notes/recovery.js +45 -0
- package/dist/esm/notes/selection.d.ts +77 -0
- package/dist/esm/notes/selection.js +188 -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/proof.d.ts +1 -183
- package/dist/esm/proof.js +2 -281
- package/dist/esm/proofs/encoding.d.ts +17 -0
- package/dist/esm/proofs/encoding.js +68 -0
- package/dist/esm/proofs/formatting.d.ts +6 -0
- package/dist/esm/proofs/formatting.js +31 -0
- package/dist/esm/proofs/index.d.ts +5 -0
- package/dist/esm/proofs/index.js +5 -0
- package/dist/esm/proofs/swap.d.ts +87 -0
- package/dist/esm/proofs/swap.js +138 -0
- package/dist/esm/proofs/transaction.d.ts +28 -0
- package/dist/esm/proofs/transaction.js +105 -0
- package/dist/esm/proofs/types.d.ts +70 -0
- package/dist/esm/proofs/types.js +1 -0
- package/dist/esm/prover.d.ts +30 -4
- package/dist/esm/prover.js +115 -15
- package/dist/esm/relayer/api.d.ts +31 -0
- package/dist/esm/relayer/api.js +55 -0
- package/dist/esm/relayer/client.d.ts +73 -0
- package/dist/esm/relayer/client.js +199 -0
- package/dist/esm/relayer/crypto.d.ts +5 -0
- package/dist/esm/relayer/crypto.js +20 -0
- package/dist/esm/relayer/encoding.d.ts +2 -0
- package/dist/esm/relayer/encoding.js +19 -0
- package/dist/esm/relayer/errors.d.ts +7 -0
- package/dist/esm/relayer/errors.js +13 -0
- package/dist/esm/relayer/index.d.ts +6 -0
- package/dist/esm/relayer/index.js +3 -0
- 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 +19 -0
- package/dist/esm/relayer/transport.js +64 -0
- package/dist/esm/relayer/types.d.ts +275 -0
- package/dist/esm/relayer/types.js +4 -0
- package/dist/esm/relayer.d.ts +1 -318
- package/dist/esm/relayer.js +2 -249
- package/dist/esm/shield/alt.js +1 -1
- package/dist/esm/shield/errors.js +1 -1
- package/dist/esm/shield/finalize.js +1 -1
- package/dist/esm/shield/ix.d.ts +1 -1
- package/dist/esm/shield/owner.js +3 -5
- package/dist/esm/shield/ports.js +1 -1
- package/dist/esm/shield/preflight.js +1 -1
- package/dist/esm/shield/shield.js +4 -3
- package/dist/esm/shield/types.d.ts +1 -1
- package/dist/esm/transactions/deposit.d.ts +94 -0
- package/dist/esm/transactions/deposit.js +198 -0
- package/dist/esm/transactions/index.d.ts +7 -0
- package/dist/esm/transactions/index.js +7 -0
- package/dist/esm/transactions/swap.d.ts +71 -0
- package/dist/esm/transactions/swap.js +144 -0
- package/dist/esm/transactions/transact.d.ts +34 -0
- package/dist/esm/transactions/transact.js +110 -0
- package/dist/esm/transactions/transfer.d.ts +51 -0
- package/dist/esm/transactions/transfer.js +103 -0
- package/dist/esm/transactions/withdraw.d.ts +52 -0
- package/dist/esm/transactions/withdraw.js +101 -0
- package/dist/esm/utxo.d.ts +1 -235
- package/dist/esm/utxo.js +2 -382
- 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 +131 -11
- package/perps.d.ts +2 -0
- package/perps.js +3 -0
- package/poseidon.d.ts +2 -2
- package/poseidon.js +2 -3
- 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 -2
- package/proof.js +2 -3
- package/prover.d.ts +2 -2
- package/prover.js +2 -3
- package/relayer.d.ts +2 -0
- package/relayer.js +3 -0
- package/shield.d.ts +2 -2
- package/shield.js +2 -3
- package/transactions.d.ts +2 -0
- package/transactions.js +3 -0
- package/SHIELD_INTEGRATION.md +0 -143
- package/dist/src/client.d.ts +0 -407
- package/dist/src/client.js +0 -951
- package/dist/src/compactNote.d.ts +0 -107
- package/dist/src/compactNote.js +0 -167
- package/dist/src/config.d.ts +0 -82
- package/dist/src/config.js +0 -57
- package/dist/src/events.d.ts +0 -77
- package/dist/src/events.js +0 -167
- package/dist/src/idl/privacy_pool.js +0 -15218
- package/dist/src/index.d.ts +0 -16
- package/dist/src/index.js +0 -67
- package/dist/src/merkle.d.ts +0 -77
- package/dist/src/merkle.js +0 -156
- package/dist/src/poseidon.d.ts +0 -29
- package/dist/src/poseidon.js +0 -100
- package/dist/src/program.d.ts +0 -37
- package/dist/src/program.js +0 -61
- package/dist/src/proof.d.ts +0 -183
- package/dist/src/proof.js +0 -292
- package/dist/src/prover.d.ts +0 -54
- package/dist/src/prover.js +0 -112
- package/dist/src/random.d.ts +0 -16
- package/dist/src/random.js +0 -28
- package/dist/src/relayer.js +0 -257
- package/dist/src/retry.d.ts +0 -32
- package/dist/src/retry.js +0 -75
- package/dist/src/shield/alt.d.ts +0 -87
- package/dist/src/shield/alt.js +0 -194
- package/dist/src/shield/computeBudget.d.ts +0 -61
- package/dist/src/shield/computeBudget.js +0 -64
- package/dist/src/shield/errors.d.ts +0 -58
- package/dist/src/shield/errors.js +0 -121
- package/dist/src/shield/finalize.d.ts +0 -45
- package/dist/src/shield/finalize.js +0 -119
- package/dist/src/shield/index.d.ts +0 -35
- package/dist/src/shield/index.js +0 -68
- package/dist/src/shield/ix.d.ts +0 -54
- package/dist/src/shield/ix.js +0 -119
- package/dist/src/shield/owner.d.ts +0 -36
- package/dist/src/shield/owner.js +0 -126
- package/dist/src/shield/ports.d.ts +0 -43
- package/dist/src/shield/ports.js +0 -153
- package/dist/src/shield/preflight.d.ts +0 -30
- package/dist/src/shield/preflight.js +0 -154
- package/dist/src/shield/shield.d.ts +0 -68
- package/dist/src/shield/shield.js +0 -499
- package/dist/src/shield/types.d.ts +0 -202
- package/dist/src/utxo.d.ts +0 -235
- package/dist/src/utxo.js +0 -407
- package/dist/tests/compact-note.test.d.ts +0 -1
- package/dist/tests/compact-note.test.js +0 -173
- package/dist/tests/config.test.d.ts +0 -1
- package/dist/tests/config.test.js +0 -102
- package/dist/tests/edge-cases.test.d.ts +0 -1
- package/dist/tests/edge-cases.test.js +0 -220
- package/dist/tests/encryption.test.d.ts +0 -1
- package/dist/tests/encryption.test.js +0 -215
- package/dist/tests/events.test.d.ts +0 -1
- package/dist/tests/events.test.js +0 -78
- package/dist/tests/multi-tree.test.d.ts +0 -1
- package/dist/tests/multi-tree.test.js +0 -405
- package/dist/tests/pda.test.d.ts +0 -1
- package/dist/tests/pda.test.js +0 -229
- package/dist/tests/poseidon-builder-parity.test.d.ts +0 -1
- package/dist/tests/poseidon-builder-parity.test.js +0 -72
- package/dist/tests/poseidon.test.d.ts +0 -1
- package/dist/tests/poseidon.test.js +0 -142
- package/dist/tests/proof.test.d.ts +0 -1
- package/dist/tests/proof.test.js +0 -296
- package/dist/tests/relayer.test.d.ts +0 -1
- package/dist/tests/relayer.test.js +0 -271
- package/dist/tests/sdk.integration.test.d.ts +0 -1
- package/dist/tests/sdk.integration.test.js +0 -330
- package/dist/tests/shield-owner.test.d.ts +0 -1
- package/dist/tests/shield-owner.test.js +0 -89
- package/dist/tests/shield-preflight.test.d.ts +0 -1
- package/dist/tests/shield-preflight.test.js +0 -87
- package/dist/tests/shield-realproof.test.d.ts +0 -1
- package/dist/tests/shield-realproof.test.js +0 -272
- package/dist/tests/shield.test.d.ts +0 -1
- package/dist/tests/shield.test.js +0 -403
- package/dist/tests/utxo.test.d.ts +0 -1
- package/dist/tests/utxo.test.js +0 -140
- /package/dist/{src/shield → cjs/events}/types.js +0 -0
- /package/dist/{src/idl/privacy_pool.d.ts → cjs/idl/privacy_pool_legacy.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,1463 +1,669 @@
|
|
|
1
1
|
# @veilo/sdk-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Build private payments and swaps on Solana with Veilo.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
The SDK gives TypeScript applications a safe, typed way to:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- **Event Scanning**: Reconstruct Merkle trees from on-chain events
|
|
13
|
-
- **Poseidon Hashing**: BN254-curve compatible hashing using circomlibjs
|
|
14
|
-
- **Relayer Support**: Built-in relayer infrastructure for private withdrawals and swaps
|
|
7
|
+
- shield SOL or SPL tokens into Veilo;
|
|
8
|
+
- withdraw, privately transfer, or privately swap shielded funds;
|
|
9
|
+
- open and manage private positions, Jupiter perps, and predictions;
|
|
10
|
+
- work with Veilo's relayer without handling its encryption protocol yourself;
|
|
11
|
+
- add partner-powered private sends and swaps through the Cloak API.
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
> Proofs are generated off-chain and verified on-chain using Groth16.
|
|
13
|
+
It works with both ESM and CommonJS and includes TypeScript declarations.
|
|
18
14
|
|
|
19
|
-
|
|
15
|
+
> **Project status:** Active development. Test integrations on Devnet before using
|
|
16
|
+
> them with real funds.
|
|
20
17
|
|
|
21
|
-
##
|
|
18
|
+
## Install
|
|
22
19
|
|
|
23
20
|
```bash
|
|
24
21
|
npm install @veilo/sdk-core
|
|
25
22
|
```
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
## 2. Prerequisites
|
|
30
|
-
|
|
31
|
-
- A running Solana validator (localnet/devnet/mainnet)
|
|
32
|
-
- The `privacy-pool` program deployed to the network
|
|
33
|
-
- A funded keypair
|
|
24
|
+
Install `snarkjs` only if your application generates proofs locally:
|
|
34
25
|
|
|
35
26
|
```bash
|
|
36
|
-
|
|
37
|
-
export ANCHOR_WALLET=$HOME/.config/solana/id.json
|
|
27
|
+
npm install snarkjs
|
|
38
28
|
```
|
|
39
29
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## 3. Build
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
npm run build
|
|
46
|
-
```
|
|
30
|
+
You will also need:
|
|
47
31
|
|
|
48
|
-
|
|
32
|
+
- a Solana RPC connection;
|
|
33
|
+
- a connected wallet when a user must sign;
|
|
34
|
+
- the Veilo circuit `.wasm` and `.zkey` files for local proof generation;
|
|
35
|
+
- an API key only for partner services such as Cloak or Jupiter Predictions.
|
|
49
36
|
|
|
50
|
-
##
|
|
37
|
+
## Choose an integration
|
|
51
38
|
|
|
52
|
-
|
|
39
|
+
| What you want to build | Start with | Who signs? |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| Let any wallet shield funds into Veilo | `shield()` | The user's wallet |
|
|
42
|
+
| Add private transfers or swaps to a partner app | `VeiloCloakClient` | The user's wallet |
|
|
43
|
+
| Build a full Veilo wallet experience | Managed relayer helpers | The relayer for private spends |
|
|
44
|
+
| Manage proofs, notes, trees, and transactions yourself | Transaction helpers | Your application or relayer |
|
|
53
45
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
getPoolPdas,
|
|
57
|
-
getNoteTreePda,
|
|
58
|
-
getGlobalConfigPda,
|
|
59
|
-
getNullifierMarkerPda,
|
|
60
|
-
getSwapExecutorPda,
|
|
61
|
-
} from "@veilo/sdk-core";
|
|
62
|
-
import { PublicKey } from "@solana/web3.js";
|
|
63
|
-
|
|
64
|
-
const programId = new PublicKey(
|
|
65
|
-
"YourProgram1111111111111111111111111111111111",
|
|
66
|
-
);
|
|
67
|
-
const mintAddress = new PublicKey(
|
|
68
|
-
"So11111111111111111111111111111111111111112",
|
|
69
|
-
);
|
|
46
|
+
For most third-party deposit integrations, `shield()` is the best starting
|
|
47
|
+
point. For a managed private send or swap flow, use Cloak.
|
|
70
48
|
|
|
71
|
-
|
|
72
|
-
const { config, vault, nullifiers } = getPoolPdas(programId, mintAddress);
|
|
49
|
+
## Quick start: shield funds
|
|
73
50
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Global config PDA (one per program)
|
|
78
|
-
const globalConfig = getGlobalConfigPda(programId);
|
|
79
|
-
|
|
80
|
-
// Nullifier marker PDA (prevents double-spend)
|
|
81
|
-
const nullifier = new Uint8Array(32);
|
|
82
|
-
const marker = getNullifierMarkerPda(programId, mintAddress, nullifier);
|
|
83
|
-
|
|
84
|
-
// Swap executor PDA (for cross-pool swaps)
|
|
85
|
-
const relayerPubkey = new PublicKey("...");
|
|
86
|
-
const executor = getSwapExecutorPda(
|
|
87
|
-
programId,
|
|
88
|
-
sourceMint,
|
|
89
|
-
destMint,
|
|
90
|
-
inputNullifier0, // Uint8Array[32]
|
|
91
|
-
relayerPubkey,
|
|
92
|
-
);
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
**PDA seeds (v3):**
|
|
96
|
-
|
|
97
|
-
| Account | Seeds |
|
|
98
|
-
| ---------------- | ------------------------------------------------------------------- |
|
|
99
|
-
| Config | `["privacy_config_v3", mint]` |
|
|
100
|
-
| Vault | `["privacy_vault_v3", mint]` |
|
|
101
|
-
| Note Tree | `["privacy_note_tree_v3", mint, tree_id]` |
|
|
102
|
-
| Nullifiers | `["privacy_nullifiers_v3", mint]` |
|
|
103
|
-
| Nullifier Marker | `["nullifier_v3", mint, nullifier]` |
|
|
104
|
-
| Global Config | `["global_config_v1"]` |
|
|
105
|
-
| Swap Executor | `["swap_executor_v1", source_mint, dest_mint, nullifier0, relayer]` |
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
### 4.2 Pool Initialization
|
|
51
|
+
`shield()` creates an unsigned transaction. Your application asks the user's
|
|
52
|
+
wallet to sign it, submits it, and then finalizes the new private note.
|
|
110
53
|
|
|
111
54
|
```ts
|
|
55
|
+
import { Connection } from "@solana/web3.js";
|
|
112
56
|
import {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
getPoolConfig,
|
|
118
|
-
updateGlobalConfig,
|
|
57
|
+
createTransactionProver,
|
|
58
|
+
finalizeShield,
|
|
59
|
+
resolveShieldOwner,
|
|
60
|
+
shield,
|
|
119
61
|
} from "@veilo/sdk-core";
|
|
120
|
-
import { NATIVE_SOL_MINT, sol } from "@veilo/sdk-core/config";
|
|
121
62
|
|
|
122
|
-
|
|
123
|
-
await initializeGlobalConfig({ program, admin: adminKeypair });
|
|
63
|
+
const connection = new Connection(process.env.SOLANA_RPC_URL!, "confirmed");
|
|
124
64
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
// Initialize a pool for native SOL
|
|
134
|
-
await initializePool({
|
|
135
|
-
program,
|
|
136
|
-
payer: adminKeypair,
|
|
137
|
-
admin: adminKeypair,
|
|
138
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
139
|
-
minDepositAmount: sol(0.1),
|
|
140
|
-
maxDepositAmount: sol(100),
|
|
141
|
-
minWithdrawAmount: sol(0.1),
|
|
142
|
-
maxWithdrawAmount: sol(100),
|
|
143
|
-
feeBps: 50, // 0.5%
|
|
144
|
-
feeErrorMarginBps: 10, // 0.1% margin
|
|
145
|
-
minWithdrawalFee: 1_000_000n,
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Add Merkle tree (tree ID 0)
|
|
149
|
-
await addMerkleTree({
|
|
150
|
-
program,
|
|
151
|
-
payer: adminKeypair,
|
|
152
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
153
|
-
treeId: 0,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// Update pool fee
|
|
157
|
-
await updatePoolConfig({
|
|
158
|
-
program,
|
|
159
|
-
admin: adminKeypair,
|
|
160
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
161
|
-
feeBps: 30,
|
|
65
|
+
// `wallet` is any connected Solana wallet with `publicKey` and
|
|
66
|
+
// `signTransaction` methods.
|
|
67
|
+
const owner = await resolveShieldOwner({ username: "alice" });
|
|
68
|
+
const prover = createTransactionProver({
|
|
69
|
+
wasmPath: "/circuits/transaction.wasm",
|
|
70
|
+
zkeyPath: "/circuits/transaction_final.zkey",
|
|
162
71
|
});
|
|
163
72
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
### 4.3 On-Chain Account Queries
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
import {
|
|
175
|
-
fetchPoolConfig,
|
|
176
|
-
checkNullifierSpent,
|
|
177
|
-
getTreeInfo,
|
|
178
|
-
getAllTreeInfo,
|
|
179
|
-
getBestTreeForDeposit,
|
|
180
|
-
} from "@veilo/sdk-core";
|
|
181
|
-
|
|
182
|
-
// Fetch decoded PrivacyConfig account
|
|
183
|
-
const config = await fetchPoolConfig(program, NATIVE_SOL_MINT);
|
|
184
|
-
|
|
185
|
-
// Check if a nullifier has been spent
|
|
186
|
-
const spent = await checkNullifierSpent(program, NATIVE_SOL_MINT, nullifier);
|
|
187
|
-
|
|
188
|
-
// Info for a single tree
|
|
189
|
-
const info = await getTreeInfo(program, NATIVE_SOL_MINT, 0);
|
|
190
|
-
// info = { treeId, leafCount, root, isFull }
|
|
191
|
-
|
|
192
|
-
// Info for all trees in a pool
|
|
193
|
-
const allInfo = await getAllTreeInfo(program, NATIVE_SOL_MINT);
|
|
194
|
-
|
|
195
|
-
// Pick the best tree for depositing (least full with capacity)
|
|
196
|
-
const best = await getBestTreeForDeposit(program, NATIVE_SOL_MINT);
|
|
197
|
-
// best = { treeId, leafCount, root }
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
### 4.4 UTXO Management
|
|
203
|
-
|
|
204
|
-
```ts
|
|
205
|
-
import {
|
|
206
|
-
generateKeypair,
|
|
207
|
-
keypairFromPrivateKey,
|
|
208
|
-
createUTXO,
|
|
209
|
-
createOwnedUTXO,
|
|
210
|
-
createOwnedZeroUTXO,
|
|
211
|
-
deriveNullifier,
|
|
212
|
-
type Keypair,
|
|
213
|
-
type UTXO,
|
|
214
|
-
type SerializedUTXO,
|
|
215
|
-
type InputUTXO,
|
|
216
|
-
} from "@veilo/sdk-core";
|
|
217
|
-
import { NATIVE_SOL_MINT } from "@veilo/sdk-core/config";
|
|
218
|
-
import { pubkeyToField } from "@veilo/sdk-core";
|
|
219
|
-
|
|
220
|
-
// Generate a random UTXO keypair
|
|
221
|
-
const keypair: Keypair = generateKeypair();
|
|
222
|
-
// keypair = { privateKey: bigint, publicKey: bigint }
|
|
223
|
-
|
|
224
|
-
// Restore from private key
|
|
225
|
-
const restored = keypairFromPrivateKey(privateKeyBigInt);
|
|
226
|
-
|
|
227
|
-
// Create an owned UTXO (includes private key)
|
|
228
|
-
const ownedUtxo: SerializedUTXO = createOwnedUTXO({
|
|
229
|
-
amount: 1_000_000_000n,
|
|
230
|
-
privateKey: keypair.privateKey,
|
|
231
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
73
|
+
const result = await shield({
|
|
74
|
+
connection,
|
|
75
|
+
amount: 1_000_000_000n, // 1 SOL in lamports
|
|
76
|
+
owner,
|
|
77
|
+
signer: { publicKey: wallet.publicKey },
|
|
78
|
+
prover,
|
|
232
79
|
});
|
|
233
80
|
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
// Derive nullifier for spending
|
|
238
|
-
const pathIndex = 0; // leaf index in Merkle tree
|
|
239
|
-
const treeId = 0;
|
|
240
|
-
const nullifier = deriveNullifier(
|
|
241
|
-
ownedUtxo.privateKey,
|
|
242
|
-
ownedUtxo.commitment,
|
|
243
|
-
pathIndex,
|
|
244
|
-
treeId,
|
|
245
|
-
);
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
**UTXO commitment:** `Poseidon(amount, pubkey, blinding, mintAddress)`
|
|
249
|
-
|
|
250
|
-
**Nullifier:** `Poseidon(privateKey, commitment, pathIndex, treeId)`
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
### 4.5 UTXO Encryption
|
|
255
|
-
|
|
256
|
-
The SDK provides NaCl-based encryption for UTXO notes (relayer storage) and blind mailbox delivery (wallet-to-wallet).
|
|
257
|
-
|
|
258
|
-
```ts
|
|
259
|
-
import {
|
|
260
|
-
deriveEncryptionKeypair,
|
|
261
|
-
encryptUTXONote,
|
|
262
|
-
decryptUTXONote,
|
|
263
|
-
encryptBlindMailboxNote,
|
|
264
|
-
decryptBlindMailboxNote,
|
|
265
|
-
fetchAndDecryptNotes,
|
|
266
|
-
computeSignature,
|
|
267
|
-
inputUTXOToCircuitFormat,
|
|
268
|
-
type EncryptedNote,
|
|
269
|
-
type BlindMailboxNote,
|
|
270
|
-
type BlindMailboxNoteData,
|
|
271
|
-
type DecryptedNote,
|
|
272
|
-
} from "@veilo/sdk-core";
|
|
273
|
-
import { Keypair as SolanaKeypair } from "@solana/web3.js";
|
|
274
|
-
|
|
275
|
-
// Derive a NaCl encryption keypair from a UTXO private key
|
|
276
|
-
const encKeypair = deriveEncryptionKeypair(utxoKeypair.privateKey);
|
|
277
|
-
// encKeypair = { publicKey: Uint8Array[32], secretKey: Uint8Array[32] }
|
|
278
|
-
|
|
279
|
-
// Encrypt a UTXO note for relay storage
|
|
280
|
-
const encryptedNote: EncryptedNote = encryptUTXONote(
|
|
281
|
-
serializedUtxo, // SerializedUTXO
|
|
282
|
-
encKeypair.publicKey, // NaCl public key (Uint8Array[32])
|
|
283
|
-
);
|
|
284
|
-
|
|
285
|
-
// Decrypt a UTXO note
|
|
286
|
-
const decrypted: SerializedUTXO | null = decryptUTXONote(
|
|
287
|
-
encryptedNote,
|
|
288
|
-
encKeypair.secretKey, // NaCl secret key (Uint8Array[32])
|
|
289
|
-
);
|
|
290
|
-
|
|
291
|
-
// Blind mailbox: encrypt for a Solana wallet keypair
|
|
292
|
-
const recipientKeypair = SolanaKeypair.generate();
|
|
293
|
-
|
|
294
|
-
const mailboxNote: BlindMailboxNote = encryptBlindMailboxNote(
|
|
295
|
-
serializedUtxo,
|
|
296
|
-
recipientKeypair.publicKey.toBytes(), // ed25519 public key → X25519 DH
|
|
297
|
-
);
|
|
81
|
+
const signed = await wallet.signTransaction(result.transaction);
|
|
82
|
+
const signature = await connection.sendRawTransaction(signed.serialize());
|
|
298
83
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
84
|
+
const confirmation = await connection.confirmTransaction(
|
|
85
|
+
{
|
|
86
|
+
signature,
|
|
87
|
+
blockhash: result.blockhash,
|
|
88
|
+
lastValidBlockHeight: result.lastValidBlockHeight,
|
|
89
|
+
},
|
|
90
|
+
"confirmed",
|
|
303
91
|
);
|
|
304
92
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
// Format an InputUTXO for snarkjs circuit
|
|
309
|
-
const circuitFormat = inputUTXOToCircuitFormat(inputUtxo);
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
---
|
|
313
|
-
|
|
314
|
-
### 4.6 Merkle Tree Operations
|
|
315
|
-
|
|
316
|
-
```ts
|
|
317
|
-
import { MerkleTree } from "@veilo/sdk-core";
|
|
318
|
-
|
|
319
|
-
// Create a new Merkle tree (default depth: 22)
|
|
320
|
-
const tree = new MerkleTree();
|
|
321
|
-
|
|
322
|
-
// Insert commitments
|
|
323
|
-
const index = tree.insert(ownedUtxo.commitment);
|
|
324
|
-
|
|
325
|
-
// Current root
|
|
326
|
-
const root = tree.root();
|
|
327
|
-
|
|
328
|
-
// Merkle path for proof generation
|
|
329
|
-
const path = tree.path(index);
|
|
330
|
-
// path = { pathElements: Uint8Array[], pathIndices: number[] }
|
|
331
|
-
|
|
332
|
-
// Total leaves inserted
|
|
333
|
-
const count = tree.totalLeaves;
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
---
|
|
337
|
-
|
|
338
|
-
### 4.7 Transaction Operations
|
|
339
|
-
|
|
340
|
-
All transaction functions return `Promise<string>` (the transaction signature).
|
|
341
|
-
|
|
342
|
-
#### Deposits
|
|
343
|
-
|
|
344
|
-
```ts
|
|
345
|
-
import { deposit, type DepositResult } from "@veilo/sdk-core";
|
|
346
|
-
|
|
347
|
-
const result: DepositResult = await deposit({
|
|
348
|
-
program,
|
|
349
|
-
depositor: depositorKeypair,
|
|
350
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
351
|
-
amount: 1_000_000_000n, // 1 SOL
|
|
352
|
-
recipientPubkey: pubkeyToField(depositorKeypair.publicKey), // bigint
|
|
353
|
-
tree,
|
|
354
|
-
proofBuilder,
|
|
355
|
-
treeId: 0,
|
|
356
|
-
});
|
|
357
|
-
// result = { outputUTXOs, leafIndices, root }
|
|
358
|
-
```
|
|
359
|
-
|
|
360
|
-
#### Withdrawals
|
|
361
|
-
|
|
362
|
-
```ts
|
|
363
|
-
import { withdraw, type WithdrawResult } from "@veilo/sdk-core";
|
|
364
|
-
|
|
365
|
-
const result: WithdrawResult = await withdraw({
|
|
366
|
-
program,
|
|
367
|
-
relayer: relayerKeypair,
|
|
368
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
369
|
-
amount: 900_000_000n, // 0.9 SOL
|
|
370
|
-
fee: 100_000_000n, // 0.1 SOL to relayer
|
|
371
|
-
inputs: [inputUtxo1, zeroInputUtxo],
|
|
372
|
-
outputs: [changeUtxo, zeroOutputUtxo],
|
|
373
|
-
recipient: recipientKeypair.publicKey,
|
|
374
|
-
tree,
|
|
375
|
-
proofBuilder,
|
|
376
|
-
treeId: 0,
|
|
377
|
-
});
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
#### Private Transfers
|
|
381
|
-
|
|
382
|
-
```ts
|
|
383
|
-
import { privateTransfer, type TransferResult } from "@veilo/sdk-core";
|
|
93
|
+
if (confirmation.value.err) {
|
|
94
|
+
throw new Error("Shield transaction failed");
|
|
95
|
+
}
|
|
384
96
|
|
|
385
|
-
const
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
outputs: [recipientUtxo, changeUtxo],
|
|
391
|
-
recipient: relayerKeypair.publicKey,
|
|
392
|
-
tree,
|
|
393
|
-
proofBuilder,
|
|
394
|
-
treeId: 0,
|
|
97
|
+
const finalized = await finalizeShield({
|
|
98
|
+
connection,
|
|
99
|
+
signature,
|
|
100
|
+
note: result.note,
|
|
101
|
+
owner,
|
|
395
102
|
});
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
#### Low-Level `transact`
|
|
399
|
-
|
|
400
|
-
```ts
|
|
401
|
-
import { transact } from "@veilo/sdk-core";
|
|
402
103
|
|
|
403
|
-
|
|
404
|
-
program,
|
|
405
|
-
relayer: relayerKeypair,
|
|
406
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
407
|
-
inputTreeId: 0,
|
|
408
|
-
outputTreeId: 0,
|
|
409
|
-
root: tree.root(),
|
|
410
|
-
publicAmount: 0n,
|
|
411
|
-
inputNullifiers: [nullifier1, nullifier2],
|
|
412
|
-
outputCommitments: [output1.commitment, output2.commitment],
|
|
413
|
-
extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
|
|
414
|
-
proof,
|
|
415
|
-
});
|
|
104
|
+
console.log("Private note created at leaf", finalized.leafIndex);
|
|
416
105
|
```
|
|
417
106
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
#### Wallet-agnostic shielding
|
|
421
|
-
|
|
422
|
-
`shield()` builds an unsigned v0 deposit transaction for any Solana wallet to
|
|
423
|
-
sign. The signer funds the deposit, while the resulting private note can belong
|
|
424
|
-
to a different Veilo user. The SDK never receives a wallet secret key and never
|
|
425
|
-
broadcasts on the caller's behalf.
|
|
107
|
+
To shield an SPL token, pass its mint:
|
|
426
108
|
|
|
427
109
|
```ts
|
|
428
|
-
import {
|
|
429
|
-
createTransactionProver,
|
|
430
|
-
resolveShieldOwner,
|
|
431
|
-
shield,
|
|
432
|
-
} from "@veilo/sdk-core";
|
|
433
|
-
|
|
434
|
-
const owner = await resolveShieldOwner({ username: "alice" });
|
|
435
110
|
const result = await shield({
|
|
436
111
|
connection,
|
|
437
|
-
|
|
438
|
-
|
|
112
|
+
mint: usdcMint,
|
|
113
|
+
amount: 5_000_000n, // 5 USDC when the mint has 6 decimals
|
|
439
114
|
owner,
|
|
440
115
|
signer: { publicKey: wallet.publicKey },
|
|
441
|
-
prover
|
|
116
|
+
prover,
|
|
442
117
|
});
|
|
443
|
-
|
|
444
|
-
const signed = await wallet.signTransaction(result.transaction);
|
|
445
|
-
const signature = await connection.sendRawTransaction(signed.serialize());
|
|
446
118
|
```
|
|
447
119
|
|
|
448
|
-
|
|
449
|
-
`finalizeShield()`
|
|
450
|
-
|
|
451
|
-
build → sign → submit → finalize flow, retry rules, owner-key invariant, and
|
|
452
|
-
fee/rent requirements.
|
|
453
|
-
|
|
454
|
-
---
|
|
120
|
+
Keep `result.note` private. It contains the information needed to recover the
|
|
121
|
+
shielded funds. `finalizeShield()` gives you the authoritative leaf index after
|
|
122
|
+
the transaction lands.
|
|
455
123
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
Cross-pool private swaps via Jupiter/Raydium. For native SOL source pools the SDK automatically composes the required `fund_native_source` + `transact_swap` instructions into a single atomic transaction.
|
|
124
|
+
If the blockhash expires before submission, reuse the proof with `rebuild()`:
|
|
459
125
|
|
|
460
126
|
```ts
|
|
461
|
-
import {
|
|
462
|
-
transactSwap,
|
|
463
|
-
getSwapExecutorPda,
|
|
464
|
-
fundNativeSource,
|
|
465
|
-
type SwapParams,
|
|
466
|
-
type SwapProofStruct,
|
|
467
|
-
} from "@veilo/sdk-core";
|
|
127
|
+
import { rebuild } from "@veilo/sdk-core";
|
|
468
128
|
|
|
469
|
-
|
|
470
|
-
const signature: string = await transactSwap({
|
|
471
|
-
program,
|
|
472
|
-
relayer: relayerKeypair,
|
|
473
|
-
sourceMint, // NATIVE_SOL_MINT or SPL token mint
|
|
474
|
-
destMint,
|
|
475
|
-
sourceRoot: tree.root(),
|
|
476
|
-
sourceTreeId: 0,
|
|
477
|
-
destTreeId: 0,
|
|
478
|
-
inputNullifiers: [nullifier0, nullifier1],
|
|
479
|
-
outputCommitments: [changeCommitment, destCommitment],
|
|
480
|
-
proof, // SwapProofStruct
|
|
481
|
-
swapParams: {
|
|
482
|
-
minAmountOut: 950_000_000n,
|
|
483
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 60),
|
|
484
|
-
sourceMint,
|
|
485
|
-
destMint,
|
|
486
|
-
destAmount: 950_000_000n,
|
|
487
|
-
swapDataHash: new Uint8Array(32), // SHA-256 of DEX ix bytes, or zeros
|
|
488
|
-
},
|
|
489
|
-
swapAmount: 1_000_000_000n,
|
|
490
|
-
swapData: jupiterInstructionBytes, // Buffer
|
|
491
|
-
extData: { recipient, relayer: relayerPubkey, fee, refund: 0n, claimant },
|
|
492
|
-
sourceVaultTokenAccount,
|
|
493
|
-
sourceMintAccount,
|
|
494
|
-
destVaultTokenAccount,
|
|
495
|
-
destMintAccount,
|
|
496
|
-
relayerTokenAccount,
|
|
497
|
-
swapProgram: JUPITER_PROGRAM_ID,
|
|
498
|
-
jupiterEventAuthority,
|
|
499
|
-
});
|
|
500
|
-
|
|
501
|
-
// Build the fund_native_source instruction standalone (advanced)
|
|
502
|
-
const fundIx = await fundNativeSource({
|
|
503
|
-
program,
|
|
504
|
-
relayer: relayerKeypair,
|
|
505
|
-
sourceMint: NATIVE_SOL_MINT,
|
|
506
|
-
destMint,
|
|
507
|
-
inputNullifier0: nullifier0,
|
|
508
|
-
swapAmount: 1_000_000_000n,
|
|
509
|
-
});
|
|
510
|
-
// Returns TransactionInstruction — must be first ix in same tx as transact_swap
|
|
129
|
+
const refreshed = await rebuild(result, { connection });
|
|
511
130
|
```
|
|
512
131
|
|
|
513
|
-
|
|
132
|
+
A stale Merkle root needs a new call to `shield()` because it requires a new
|
|
133
|
+
proof.
|
|
514
134
|
|
|
515
|
-
|
|
135
|
+
## Cloak Partner API
|
|
516
136
|
|
|
517
|
-
|
|
137
|
+
Cloak is the simplest route for partner applications that want a private send
|
|
138
|
+
or cross-asset private swap. The SDK handles request types, API authentication,
|
|
139
|
+
transaction decoding, polling, and structured errors. It never signs for the
|
|
140
|
+
user.
|
|
141
|
+
|
|
142
|
+
Keep your Cloak API key on a trusted server. Do not include it in a browser or
|
|
143
|
+
mobile bundle.
|
|
144
|
+
|
|
145
|
+
### Create an order on your server
|
|
518
146
|
|
|
519
147
|
```ts
|
|
520
|
-
import {
|
|
521
|
-
scanCommitmentEvents,
|
|
522
|
-
scanNullifierEvents,
|
|
523
|
-
buildTreeFromEvents,
|
|
524
|
-
type CommitmentEvent,
|
|
525
|
-
type NullifierSpentEvent,
|
|
526
|
-
} from "@veilo/sdk-core";
|
|
148
|
+
import { VeiloCloakClient } from "@veilo/sdk-core/cloak";
|
|
527
149
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
program,
|
|
531
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
532
|
-
treeId: 0,
|
|
533
|
-
beforeSignature: undefined, // or last known signature for pagination
|
|
534
|
-
limit: 1000,
|
|
150
|
+
const cloak = new VeiloCloakClient({
|
|
151
|
+
apiKey: process.env.VEILO_CLOAK_KEY!,
|
|
535
152
|
});
|
|
536
|
-
// events: CommitmentEvent[]
|
|
537
|
-
// CommitmentEvent = { commitment, leafIndex, newRoot, timestamp, mintAddress, treeId }
|
|
538
153
|
|
|
539
|
-
//
|
|
540
|
-
const {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
154
|
+
// The production API defaults to https://api.veilo.network/.
|
|
155
|
+
const { quote } = await cloak.getQuote({
|
|
156
|
+
amount: "100000000", // raw token units
|
|
157
|
+
sourceAssetId: "veilo-usdc",
|
|
158
|
+
destinationAssetId: "veilo-usdc",
|
|
159
|
+
senderAddress,
|
|
160
|
+
recipientAddress,
|
|
161
|
+
mode: "exact_in",
|
|
545
162
|
});
|
|
546
|
-
// NullifierSpentEvent = { nullifier, mintAddress, treeId }
|
|
547
163
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
treeId: 0,
|
|
557
|
-
});
|
|
164
|
+
const { order } = await cloak.createOrder(
|
|
165
|
+
{
|
|
166
|
+
quote, // return the complete quote without changing it
|
|
167
|
+
senderAddress,
|
|
168
|
+
recipientAddress,
|
|
169
|
+
},
|
|
170
|
+
{ idempotencyKey: crypto.randomUUID() },
|
|
171
|
+
);
|
|
558
172
|
```
|
|
559
173
|
|
|
560
|
-
|
|
174
|
+
For a cross-asset swap, use a different `destinationAssetId` and optionally add
|
|
175
|
+
`slippageBps` to the quote request. Use `listTokens()` to discover supported
|
|
176
|
+
asset IDs and their current limits.
|
|
561
177
|
|
|
562
|
-
|
|
178
|
+
You can override the API address for another environment. Both the origin and
|
|
179
|
+
the full Cloak path are accepted:
|
|
563
180
|
|
|
564
181
|
```ts
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
computeExtDataHash,
|
|
569
|
-
encodeSnarkjsProofToTransactionProof,
|
|
570
|
-
packProofToBytes,
|
|
571
|
-
computeSwapParamsHash,
|
|
572
|
-
computeSwapDataHash,
|
|
573
|
-
type ExtData,
|
|
574
|
-
type TransactionCircuitInputs,
|
|
575
|
-
} from "@veilo/sdk-core";
|
|
576
|
-
|
|
577
|
-
// Prepare inputs for the transaction circuit
|
|
578
|
-
const circuitInputs: TransactionCircuitInputs = prepareTransactionInputs({
|
|
579
|
-
root: tree.root(),
|
|
580
|
-
publicAmount: 1_000_000_000n,
|
|
581
|
-
extData: { recipient, relayer: relayerPubkey, fee: 0n, refund: 0n, claimant },
|
|
582
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
583
|
-
inputs: [input1, input2],
|
|
584
|
-
outputs: [output1, output2],
|
|
585
|
-
inputTreeId: 0,
|
|
586
|
-
outputTreeId: 0,
|
|
587
|
-
});
|
|
588
|
-
|
|
589
|
-
// Format for snarkjs (converts bigints / Uint8Arrays to strings)
|
|
590
|
-
const snarkjsInputs = formatInputsForSnarkjs(circuitInputs);
|
|
591
|
-
|
|
592
|
-
// After proof generation:
|
|
593
|
-
// const { proof } = await snarkjs.groth16.fullProve(snarkjsInputs, wasmPath, zkeyPath);
|
|
594
|
-
// const transactionProof = encodeSnarkjsProofToTransactionProof(proof);
|
|
595
|
-
|
|
596
|
-
// Compute ext data hash (matches on-chain computation)
|
|
597
|
-
const extDataHash = computeExtDataHash({
|
|
598
|
-
recipient,
|
|
599
|
-
relayer,
|
|
600
|
-
fee: 0n,
|
|
601
|
-
refund: 0n,
|
|
602
|
-
claimant,
|
|
182
|
+
new VeiloCloakClient({
|
|
183
|
+
baseUrl: "https://api.veilo.network/", // `/cloak/v1` also works here
|
|
184
|
+
apiKey: process.env.VEILO_CLOAK_KEY!,
|
|
603
185
|
});
|
|
604
|
-
|
|
605
|
-
// Compute swap param/data hashes (for swap circuit inputs)
|
|
606
|
-
const swapParamsHash = computeSwapParamsHash(swapParams);
|
|
607
|
-
const swapDataHash = computeSwapDataHash(jupiterInstructionBytes);
|
|
608
186
|
```
|
|
609
187
|
|
|
610
|
-
|
|
188
|
+
### Sign in the user's application
|
|
611
189
|
|
|
612
|
-
|
|
190
|
+
Send the returned `order` to the user's application, then deserialize and sign
|
|
191
|
+
its transaction:
|
|
613
192
|
|
|
614
193
|
```ts
|
|
615
|
-
import {
|
|
616
|
-
computeWithdrawalFee,
|
|
617
|
-
computeSwapFee,
|
|
618
|
-
DEFAULT_FEE_BPS,
|
|
619
|
-
} from "@veilo/sdk-core/config";
|
|
194
|
+
import { deserializeCloakTransaction } from "@veilo/sdk-core/cloak";
|
|
620
195
|
|
|
621
|
-
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
const swapFee = computeSwapFee(swapAmount, feeBps);
|
|
196
|
+
const transaction = deserializeCloakTransaction(order);
|
|
197
|
+
const signed = await wallet.signTransaction(transaction);
|
|
198
|
+
const signature = await connection.sendRawTransaction(signed.serialize());
|
|
199
|
+
await connection.confirmTransaction(signature, "confirmed");
|
|
626
200
|
```
|
|
627
201
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
### 4.12 Relayer & Admin Management
|
|
202
|
+
Send the signature back to your server. The deposit notification is optional,
|
|
203
|
+
but it can reduce processing latency:
|
|
631
204
|
|
|
632
205
|
```ts
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
await addRelayer({
|
|
637
|
-
program,
|
|
638
|
-
admin: adminKeypair,
|
|
639
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
640
|
-
newRelayer: relayerPubkey,
|
|
206
|
+
await cloak.notifyDeposit({
|
|
207
|
+
trackingId: order.trackingId,
|
|
208
|
+
txSignature: signature,
|
|
641
209
|
});
|
|
642
210
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
admin: adminKeypair,
|
|
647
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
648
|
-
paused: true,
|
|
211
|
+
const finalStatus = await cloak.waitForFinalStatus(order.trackingId, {
|
|
212
|
+
intervalMs: 3_000,
|
|
213
|
+
timeoutMs: 20 * 60_000,
|
|
649
214
|
});
|
|
215
|
+
|
|
216
|
+
console.log(finalStatus.status);
|
|
650
217
|
```
|
|
651
218
|
|
|
652
|
-
|
|
219
|
+
If an unfunded order's transaction expires, call
|
|
220
|
+
`refreshTransaction(order.trackingId)` and ask the user to sign the refreshed
|
|
221
|
+
transaction.
|
|
653
222
|
|
|
654
|
-
|
|
223
|
+
## Full private wallet flows
|
|
655
224
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
initPoseidon,
|
|
659
|
-
poseidon1,
|
|
660
|
-
poseidon2,
|
|
661
|
-
poseidon3,
|
|
662
|
-
poseidon4,
|
|
663
|
-
pubkeyToField,
|
|
664
|
-
bytesToBigIntBE,
|
|
665
|
-
bigIntToBytesBE,
|
|
666
|
-
BN254_FR_MODULUS,
|
|
667
|
-
} from "@veilo/sdk-core";
|
|
225
|
+
The SDK supports all Veilo privacy-pool operations. Pick the highest-level API
|
|
226
|
+
that fits your application:
|
|
668
227
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
const h4 = poseidon4(12345n, 67890n, 11111n, 22222n);
|
|
228
|
+
| Operation | Managed relayer call | Direct SDK helper |
|
|
229
|
+
| --- | --- | --- |
|
|
230
|
+
| Deposit | Not required | `shield()` or `deposit()` |
|
|
231
|
+
| Withdraw | `submitWithdraw()` | `withdraw()` |
|
|
232
|
+
| Private transfer | `submitPrivateTransfer()` | `privateTransfer()` |
|
|
233
|
+
| Private swap | `submitPrivateSwap()` | `buildPrivateSwapInstructions()` or `transactSwap()` |
|
|
676
234
|
|
|
677
|
-
|
|
678
|
-
const field = pubkeyToField(NATIVE_SOL_MINT);
|
|
235
|
+
### Use the managed relayer helpers
|
|
679
236
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
```
|
|
684
|
-
|
|
685
|
-
---
|
|
686
|
-
|
|
687
|
-
### 4.14 Error Utilities
|
|
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.
|
|
688
240
|
|
|
689
241
|
```ts
|
|
690
|
-
import {
|
|
242
|
+
import {
|
|
243
|
+
submitWithdraw,
|
|
244
|
+
type WithdrawRequest,
|
|
245
|
+
} from "@veilo/sdk-core/relayer";
|
|
691
246
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
} catch (err) {
|
|
695
|
-
// Returns a human-readable error string from Anchor/program errors
|
|
696
|
-
const msg = parseOnChainError(err);
|
|
697
|
-
console.error("Swap failed:", msg);
|
|
247
|
+
async function submitWithdrawal(request: WithdrawRequest) {
|
|
248
|
+
return submitWithdraw(request);
|
|
698
249
|
}
|
|
699
250
|
```
|
|
700
251
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
### Transaction Model
|
|
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:
|
|
706
255
|
|
|
707
|
-
|
|
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()` |
|
|
708
261
|
|
|
709
|
-
|
|
710
|
-
- **Outputs**: 2 UTXOs (zero-value for withdrawals)
|
|
711
|
-
- **Public Amount**: net pool change — positive = deposit, negative = withdrawal, zero = private transfer or swap
|
|
262
|
+
#### Submission always targets Veilo's relayer
|
|
712
263
|
|
|
713
|
-
|
|
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:
|
|
714
267
|
|
|
715
|
-
|
|
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.
|
|
716
280
|
|
|
717
|
-
|
|
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.
|
|
718
285
|
|
|
719
|
-
|
|
720
|
-
2. `transact_swap` — verifies the ZK proof, spends input UTXOs, creates output UTXOs, and executes the DEX swap
|
|
721
|
-
|
|
722
|
-
`transactSwap()` handles this automatically. The on-chain program validates atomicity via the instructions sysvar.
|
|
723
|
-
|
|
724
|
-
### Privacy Guarantees
|
|
725
|
-
|
|
726
|
-
- **Commitment hiding**: amount, owner, blinding are hidden via Poseidon
|
|
727
|
-
- **Nullifier uniqueness**: each UTXO can only be spent once
|
|
728
|
-
- **Unlinkability**: no public link between inputs and outputs
|
|
729
|
-
- **ZK proofs**: Groth16 verified on-chain
|
|
730
|
-
|
|
731
|
-
### Constants
|
|
732
|
-
|
|
733
|
-
```ts
|
|
734
|
-
import {
|
|
735
|
-
NATIVE_SOL_MINT, // PublicKey.default — native SOL pools
|
|
736
|
-
MERKLE_TREE_DEPTH, // 22
|
|
737
|
-
ROOT_HISTORY_SIZE, // 256
|
|
738
|
-
DEFAULT_FEE_BPS, // 50 (0.5%)
|
|
739
|
-
sol, // sol(1) === 1_000_000_000n
|
|
740
|
-
} from "@veilo/sdk-core/config";
|
|
741
|
-
```
|
|
286
|
+
### Spend status and private balance
|
|
742
287
|
|
|
743
|
-
|
|
288
|
+
Nothing in a note says whether it has been spent — a note is yours until its
|
|
289
|
+
nullifier is published. So a balance is always two steps, and the SDK gives you
|
|
290
|
+
both:
|
|
744
291
|
|
|
745
292
|
```ts
|
|
746
|
-
import
|
|
747
|
-
// UTXO
|
|
748
|
-
Keypair,
|
|
749
|
-
UTXO,
|
|
750
|
-
SerializedUTXO,
|
|
751
|
-
InputUTXO,
|
|
752
|
-
// Encryption
|
|
753
|
-
EncryptedNote,
|
|
754
|
-
BlindMailboxNote,
|
|
755
|
-
BlindMailboxNoteData,
|
|
756
|
-
DecryptedNote,
|
|
757
|
-
// Proof
|
|
758
|
-
ExtData,
|
|
759
|
-
TransactionCircuitInputs,
|
|
760
|
-
TransactionProofStruct,
|
|
761
|
-
RawProof,
|
|
762
|
-
TransactionProofBuilder,
|
|
763
|
-
// Swap
|
|
764
|
-
SwapProofStruct,
|
|
765
|
-
SwapParams,
|
|
766
|
-
// Tree / events
|
|
767
|
-
MerklePath,
|
|
768
|
-
CircuitMerklePath,
|
|
769
|
-
TreeInfo,
|
|
770
|
-
CommitmentEvent,
|
|
771
|
-
NullifierSpentEvent,
|
|
772
|
-
// Results
|
|
773
|
-
DepositResult,
|
|
774
|
-
WithdrawResult,
|
|
775
|
-
TransferResult,
|
|
776
|
-
// Config
|
|
777
|
-
PoolInitConfig,
|
|
778
|
-
PrivacyConfigAccount,
|
|
779
|
-
GlobalConfigAccount,
|
|
780
|
-
} from "@veilo/sdk-core";
|
|
781
|
-
```
|
|
293
|
+
import { getPrivateBalance, checkNullifiersSpent } from "@veilo/sdk-core";
|
|
782
294
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
## 6. Development
|
|
786
|
-
|
|
787
|
-
```bash
|
|
788
|
-
# Run tests (requires devnet or local validator)
|
|
789
|
-
npm test
|
|
295
|
+
const { total, byMint, unspent, spent } = await getPrivateBalance(myNotes);
|
|
790
296
|
```
|
|
791
297
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
- **Repository**: https://github.com/VeiloSolana/veilo-sdk
|
|
797
|
-
- **Circomlibjs**: https://github.com/iden3/circomlibjs
|
|
798
|
-
- **Poseidon Hash**: https://www.poseidon-hash.info/
|
|
799
|
-
|
|
800
|
-
---
|
|
801
|
-
|
|
802
|
-
## License
|
|
298
|
+
Each note needs an `amount`, a 64-character hex `nullifier`, and optionally a
|
|
299
|
+
`mint` to group by. `getPrivateBalance` asks the relayer which nullifiers are
|
|
300
|
+
spent, then sums what is left; `unspent` and `spent` hand back your own note
|
|
301
|
+
objects, so you can render from them directly.
|
|
803
302
|
|
|
804
|
-
|
|
303
|
+
`checkNullifiersSpent(nullifiers)` is the same question on its own. It
|
|
304
|
+
deduplicates, splits into the server's 200-per-request batches, issues them
|
|
305
|
+
concurrently, and returns a `Set` for membership testing. It also lower-cases
|
|
306
|
+
input: the endpoint validates case-insensitively but answers in lower case, so
|
|
307
|
+
upper-case hex would otherwise never match and every note would read as unspent.
|
|
805
308
|
|
|
806
|
-
|
|
309
|
+
To compute a balance without the relayer — from a chain scan of nullifier
|
|
310
|
+
events, or a local cache — supply the answer yourself:
|
|
807
311
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
- **ZK Proofs**: Integration with Circom circuits for private transactions
|
|
811
|
-
- **Flexible Operations**: Deposits, withdrawals, and private transfers
|
|
812
|
-
- **Poseidon Hashing**: BN254-curve compatible hashing using circomlibjs
|
|
813
|
-
- **Merkle Trees**: Off-chain Merkle tree management with proof generation
|
|
814
|
-
- **Relayer Support**: Built-in relayer infrastructure for private withdrawals
|
|
815
|
-
|
|
816
|
-
> **Status:** Active development. The SDK supports full transaction privacy with ZK-SNARK proofs.
|
|
817
|
-
> Proofs are generated off-chain and verified on-chain using Groth16.
|
|
818
|
-
|
|
819
|
-
---
|
|
820
|
-
|
|
821
|
-
## 1. Installation
|
|
822
|
-
|
|
823
|
-
```bash
|
|
824
|
-
npm install @veilo/sdk-core
|
|
825
|
-
```
|
|
826
|
-
|
|
827
|
-
Or from source:
|
|
828
|
-
|
|
829
|
-
```bash
|
|
830
|
-
cd core-sdk
|
|
831
|
-
npm install
|
|
312
|
+
```ts
|
|
313
|
+
await getPrivateBalance(myNotes, { resolveSpent: async (ns) => mySpentSet(ns) });
|
|
832
314
|
```
|
|
833
315
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
316
|
+
Amounts stay `bigint` end to end. A `number` amount above `Number.MAX_SAFE_INTEGER`
|
|
317
|
+
is rejected rather than silently rounded, and a malformed nullifier throws
|
|
318
|
+
instead of counting as unspent — either would overstate a balance.
|
|
837
319
|
|
|
838
|
-
|
|
320
|
+
### Choosing notes to spend
|
|
839
321
|
|
|
840
|
-
|
|
322
|
+
Two rules govern this, and both are easy to get wrong:
|
|
841
323
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
324
|
+
- the transaction circuit is **2-in-2-out**, so one transaction spends at most
|
|
325
|
+
two notes;
|
|
326
|
+
- notes are only co-spendable inside the **same Merkle tree**, and the tree is
|
|
327
|
+
derived from the mint.
|
|
845
328
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
```text
|
|
850
|
-
idl/idl/privacy_pool.json
|
|
851
|
-
```
|
|
852
|
-
|
|
853
|
-
- A funded keypair:
|
|
854
|
-
|
|
855
|
-
```bash
|
|
856
|
-
solana config set --url http://127.0.0.1:8899
|
|
857
|
-
solana-keygen new --outfile ~/.config/solana/id.json
|
|
858
|
-
solana airdrop 10
|
|
859
|
-
```
|
|
860
|
-
|
|
861
|
-
Environment variables:
|
|
329
|
+
```ts
|
|
330
|
+
import { selectNotesForAmount, canonicalTreeId } from "@veilo/sdk-core";
|
|
862
331
|
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
332
|
+
const selection = selectNotesForAmount(unspentNotes, amountRaw, { mint });
|
|
333
|
+
if (!selection.ok) throw new Error(selection.message); // NO_NOTES | INSUFFICIENT_FUNDS
|
|
334
|
+
if (selection.requiresMerge) {
|
|
335
|
+
// more than two inputs — combine them before proving
|
|
336
|
+
}
|
|
866
337
|
```
|
|
867
338
|
|
|
868
|
-
|
|
339
|
+
It searches each tree independently and returns the best result: the smallest
|
|
340
|
+
single note that covers the amount, else the pair with the least change (found
|
|
341
|
+
by a two-pointer scan, not an all-pairs search), else the largest notes greedily
|
|
342
|
+
with `requiresMerge` set. A failure reports `available`, the largest total
|
|
343
|
+
reachable within one tree.
|
|
869
344
|
|
|
870
|
-
|
|
345
|
+
`canonicalTreeId(mint)` derives a note's tree the way the relayer does. **Derive
|
|
346
|
+
it; never trust a stored `treeId`.** Change notes are written with the on-chain
|
|
347
|
+
shard index while deposits and synced notes carry the mint-derived id — for
|
|
348
|
+
native SOL both are 0 so the difference hides, but for SPL tokens they diverge
|
|
349
|
+
and co-spending across the two fails at proof time as a commitment mismatch.
|
|
871
350
|
|
|
872
|
-
|
|
873
|
-
npm run build
|
|
874
|
-
```
|
|
351
|
+
### Private product keys and recovery
|
|
875
352
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
353
|
+
Private positions, perps, and predictions use deterministic client-held keys.
|
|
354
|
+
The SDK provides the exact derivations used by Veilo's wallet, extension,
|
|
355
|
+
relayer, and program tests. Keep the spending key and claimant secret on the
|
|
356
|
+
user's device; send claimant secrets only inside the SDK's encrypted relayer
|
|
357
|
+
requests.
|
|
881
358
|
|
|
882
359
|
```ts
|
|
883
360
|
import {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
361
|
+
derivePositionKeyBundle,
|
|
362
|
+
deriveSpendingKeyWithSigner,
|
|
363
|
+
encodeClaimantSecretKey,
|
|
364
|
+
initPoseidon,
|
|
365
|
+
submitOpenPosition,
|
|
888
366
|
} from "@veilo/sdk-core";
|
|
889
|
-
import { PublicKey } from "@solana/web3.js";
|
|
890
367
|
|
|
891
|
-
|
|
892
|
-
|
|
368
|
+
await initPoseidon();
|
|
369
|
+
const spendingKey = await deriveSpendingKeyWithSigner(
|
|
370
|
+
(message) => wallet.signMessage(message),
|
|
893
371
|
);
|
|
894
|
-
const
|
|
895
|
-
"So11111111111111111111111111111111111111112",
|
|
896
|
-
); // Native SOL
|
|
897
|
-
|
|
898
|
-
// Get pool PDAs
|
|
899
|
-
const { config, vault, nullifiers } = getPoolPdas(programId, mintAddress);
|
|
900
|
-
|
|
901
|
-
// Get note tree PDA for tree ID 0
|
|
902
|
-
const noteTree = getNoteTreePda(programId, mintAddress, 0);
|
|
372
|
+
const positionKeys = derivePositionKeyBundle(spendingKey, nextPositionIndex);
|
|
903
373
|
|
|
904
|
-
|
|
905
|
-
|
|
374
|
+
await submitOpenPosition({
|
|
375
|
+
// Select private source notes in your wallet before calling the relayer.
|
|
376
|
+
notes,
|
|
377
|
+
sourceMintAddress,
|
|
378
|
+
destMintAddress,
|
|
379
|
+
swapAmountRaw,
|
|
380
|
+
slippageBps: 50,
|
|
381
|
+
userPublicKey: wallet.publicKey.toBase58(),
|
|
382
|
+
veiloPublicKey,
|
|
383
|
+
position: positionKeys.position,
|
|
384
|
+
});
|
|
906
385
|
|
|
907
|
-
//
|
|
908
|
-
|
|
909
|
-
const
|
|
386
|
+
// Persist the returned position data and `nextPositionIndex`. Re-derive the
|
|
387
|
+
// same claimant later when closing or merging the position.
|
|
388
|
+
const claimantSecretKey = encodeClaimantSecretKey(positionKeys.claimant);
|
|
910
389
|
```
|
|
911
390
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
-
|
|
916
|
-
|
|
917
|
-
- Nullifiers: `["privacy_nullifiers_v3", mint_address]`
|
|
918
|
-
- Nullifier Marker: `["privacy_nullifier_v3", mint_address, tree_id, nullifier]`
|
|
919
|
-
- Global Config: `["global_config_v1"]`
|
|
920
|
-
|
|
921
|
-
---
|
|
391
|
+
Use `deriveJperpKeyBundle()` and `getJperpMarketPayload()` for private perps.
|
|
392
|
+
Use `derivePredictionKeyBundle()` for private predictions. Lower-level key
|
|
393
|
+
derivations are also exported when an application needs them individually. The
|
|
394
|
+
PDA helpers in each focused entry point support on-chain recovery scans on a
|
|
395
|
+
fresh device.
|
|
922
396
|
|
|
923
|
-
|
|
397
|
+
Predictions have one additional step: Jupiter returns an unsigned order,
|
|
398
|
+
close, or claim transaction. The SDK exposes that API without taking custody
|
|
399
|
+
of signing:
|
|
924
400
|
|
|
925
401
|
```ts
|
|
926
|
-
import * as anchor from "@coral-xyz/anchor";
|
|
927
402
|
import {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
addMerkleTree,
|
|
932
|
-
getPoolConfig,
|
|
933
|
-
} from "@veilo/sdk-core";
|
|
934
|
-
import { NATIVE_SOL_MINT, sol } from "@veilo/sdk-core/config";
|
|
935
|
-
|
|
936
|
-
// Initialize global config (once per program)
|
|
937
|
-
await initializeGlobalConfig({
|
|
938
|
-
program,
|
|
939
|
-
admin: adminKeypair,
|
|
940
|
-
});
|
|
403
|
+
JupiterPredictionClient,
|
|
404
|
+
deserializePredictionTransaction,
|
|
405
|
+
} from "@veilo/sdk-core/predictions";
|
|
941
406
|
|
|
942
|
-
|
|
943
|
-
await
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
minWithdrawAmount: sol(0.1),
|
|
951
|
-
maxWithdrawAmount: sol(100),
|
|
952
|
-
feeBps: 50, // 0.5%
|
|
953
|
-
feeErrorMarginBps: 10, // 0.1% margin
|
|
954
|
-
minWithdrawalFee: 1_000_000n, // 0.001 SOL minimum
|
|
407
|
+
const predictions = new JupiterPredictionClient({ apiKey: jupiterApiKey });
|
|
408
|
+
const order = await predictions.placeOrder({
|
|
409
|
+
ownerPubkey: ephemeral.publicKey.toBase58(),
|
|
410
|
+
marketId,
|
|
411
|
+
isYes: true,
|
|
412
|
+
isBuy: true,
|
|
413
|
+
depositAmount: "5000000",
|
|
414
|
+
depositMint: usdcMint,
|
|
955
415
|
});
|
|
956
|
-
|
|
957
|
-
//
|
|
958
|
-
await addMerkleTree({
|
|
959
|
-
program,
|
|
960
|
-
payer: adminKeypair,
|
|
961
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
962
|
-
treeId: 0,
|
|
963
|
-
});
|
|
964
|
-
|
|
965
|
-
// Update pool configuration
|
|
966
|
-
await updatePoolConfig({
|
|
967
|
-
program,
|
|
968
|
-
admin: adminKeypair,
|
|
969
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
970
|
-
feeBps: 30, // Change to 0.3%
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
// Read pool configuration
|
|
974
|
-
const poolConfig = await getPoolConfig(program, NATIVE_SOL_MINT);
|
|
975
|
-
console.log("TVL:", poolConfig.totalTvl);
|
|
976
|
-
console.log("Fee:", poolConfig.feeBps, "bps");
|
|
977
|
-
console.log("Num Trees:", poolConfig.numTrees);
|
|
416
|
+
const transaction = deserializePredictionTransaction(order);
|
|
417
|
+
// Ask the deterministic ephemeral wallet to sign, then submit and confirm it.
|
|
978
418
|
```
|
|
979
419
|
|
|
980
|
-
|
|
420
|
+
The SDK deliberately does not own application storage or choose which notes to
|
|
421
|
+
spend. Persist indexes and returned product records only after the corresponding
|
|
422
|
+
transaction is confirmed.
|
|
981
423
|
|
|
982
|
-
###
|
|
424
|
+
### Use the direct helpers
|
|
983
425
|
|
|
984
|
-
|
|
426
|
+
Direct helpers are intended for applications that already maintain Veilo note
|
|
427
|
+
and Merkle tree state and can generate proofs.
|
|
985
428
|
|
|
986
429
|
```ts
|
|
987
430
|
import {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
createOwnedZeroUTXO,
|
|
993
|
-
deriveNullifier,
|
|
994
|
-
type Keypair,
|
|
995
|
-
type UTXO,
|
|
996
|
-
type SerializedUTXO,
|
|
997
|
-
type InputUTXO,
|
|
431
|
+
NATIVE_SOL_MINT,
|
|
432
|
+
createTransactionProver,
|
|
433
|
+
createVeiloProgram,
|
|
434
|
+
deposit,
|
|
998
435
|
} from "@veilo/sdk-core";
|
|
999
|
-
import { NATIVE_SOL_MINT } from "@veilo/sdk-core/config";
|
|
1000
|
-
import { pubkeyToField } from "@veilo/sdk-core";
|
|
1001
|
-
|
|
1002
|
-
// Generate a random keypair
|
|
1003
|
-
const keypair: Keypair = generateKeypair();
|
|
1004
|
-
// keypair = { privateKey: bigint, publicKey: bigint }
|
|
1005
436
|
|
|
1006
|
-
|
|
1007
|
-
const
|
|
437
|
+
const program = createVeiloProgram(connection, anchorWallet);
|
|
438
|
+
const proofBuilder = createTransactionProver({
|
|
439
|
+
wasmPath: "/circuits/transaction.wasm",
|
|
440
|
+
zkeyPath: "/circuits/transaction_final.zkey",
|
|
441
|
+
});
|
|
1008
442
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
privateKey: keypair.privateKey,
|
|
443
|
+
const built = await deposit({
|
|
444
|
+
program,
|
|
445
|
+
depositor: { publicKey: wallet.publicKey },
|
|
1013
446
|
mintAddress: NATIVE_SOL_MINT,
|
|
447
|
+
amount: 1_000_000_000n,
|
|
448
|
+
recipientPubkey: veiloOwnerPublicKey,
|
|
449
|
+
noteRecipientWallet: wallet.publicKey,
|
|
450
|
+
tree,
|
|
451
|
+
proofBuilder,
|
|
452
|
+
treeId: 0,
|
|
1014
453
|
});
|
|
1015
454
|
|
|
1016
|
-
|
|
1017
|
-
const
|
|
1018
|
-
|
|
1019
|
-
// Derive nullifier for spending
|
|
1020
|
-
const nullifier = deriveNullifier(
|
|
1021
|
-
ownedUtxo.privateKey,
|
|
1022
|
-
ownedUtxo.commitment,
|
|
1023
|
-
0, // pathIndex in Merkle tree
|
|
1024
|
-
0, // treeId
|
|
1025
|
-
);
|
|
1026
|
-
```
|
|
1027
|
-
|
|
1028
|
-
**UTXO commitment formula:**
|
|
1029
|
-
|
|
1030
|
-
```
|
|
1031
|
-
commitment = Poseidon(amount, pubkey, blinding, mintAddress)
|
|
1032
|
-
```
|
|
1033
|
-
|
|
1034
|
-
**Nullifier formula:**
|
|
455
|
+
const signed = await wallet.signTransaction(built.transaction);
|
|
456
|
+
const signature = await connection.sendRawTransaction(signed.serialize());
|
|
457
|
+
await connection.confirmTransaction(signature, "confirmed");
|
|
1035
458
|
|
|
459
|
+
// Update the local tree only after on-chain confirmation.
|
|
460
|
+
const receipt = built.commit();
|
|
1036
461
|
```
|
|
1037
|
-
nullifier = Poseidon(privateKey, commitment, pathIndex, treeId)
|
|
1038
|
-
```
|
|
1039
|
-
|
|
1040
|
-
---
|
|
1041
462
|
|
|
1042
|
-
|
|
463
|
+
`withdraw()` and `privateTransfer()` accept two spendable input notes, build the
|
|
464
|
+
proof, submit through the supplied relayer signer, and return the resulting
|
|
465
|
+
change or output notes. Important rules are enforced by the SDK:
|
|
1043
466
|
|
|
1044
|
-
|
|
1045
|
-
|
|
467
|
+
- withdrawal amounts must be positive and fit within the selected notes;
|
|
468
|
+
- private-transfer outputs must equal the total input amount;
|
|
469
|
+
- direct private transfers use a zero public fee;
|
|
470
|
+
- note-recipient wallet keys should be supplied so new notes remain recoverable.
|
|
1046
471
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
const index1 = tree.insert(ownedUtxo1.commitment);
|
|
1052
|
-
const index2 = tree.insert(ownedUtxo2.commitment);
|
|
1053
|
-
|
|
1054
|
-
// Get current root
|
|
1055
|
-
const root = tree.root();
|
|
1056
|
-
|
|
1057
|
-
// Get Merkle path for proof generation
|
|
1058
|
-
const path = tree.path(index1);
|
|
1059
|
-
// path = { pathElements: Uint8Array[], pathIndices: number[] }
|
|
1060
|
-
|
|
1061
|
-
// Get number of leaves
|
|
1062
|
-
const numLeaves = tree.totalLeaves;
|
|
1063
|
-
|
|
1064
|
-
// Custom tree depth
|
|
1065
|
-
const deepTree = new MerkleTree(25); // 25 levels
|
|
1066
|
-
```
|
|
472
|
+
Private swaps normally use Jupiter versioned transactions and address lookup
|
|
473
|
+
tables. Use `buildPrivateSwapInstructions()` to add Veilo's atomic instructions
|
|
474
|
+
to the exact Jupiter route. Preserve Jupiter's account order and duplicate
|
|
475
|
+
accounts. `transactSwap()` is available when a legacy transaction is sufficient.
|
|
1067
476
|
|
|
1068
|
-
The
|
|
477
|
+
The low-level `transact()` and `buildRawTransactInstruction()` exports are for
|
|
478
|
+
custom transaction composition. Most applications should use the helpers above.
|
|
1069
479
|
|
|
1070
|
-
|
|
480
|
+
## Important concepts
|
|
1071
481
|
|
|
1072
|
-
###
|
|
482
|
+
### Amounts use base units
|
|
1073
483
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
#### Deposits (publicAmount > 0)
|
|
484
|
+
Amounts are `bigint` values or decimal strings in the token's smallest unit:
|
|
1077
485
|
|
|
1078
486
|
```ts
|
|
1079
|
-
import {
|
|
1080
|
-
|
|
1081
|
-
// Create output UTXO
|
|
1082
|
-
const outputUtxo = createOwnedUTXO({
|
|
1083
|
-
amount: 1_000_000_000n, // 1 SOL
|
|
1084
|
-
mintAddress: pubkeyToField(NATIVE_SOL_MINT),
|
|
1085
|
-
keypair: utxoKeypair,
|
|
1086
|
-
});
|
|
1087
|
-
|
|
1088
|
-
// Zero inputs for deposit
|
|
1089
|
-
const input1 = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair);
|
|
1090
|
-
const input2 = createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair);
|
|
1091
|
-
const output2 = createOwnedZeroUTXO(
|
|
1092
|
-
pubkeyToField(NATIVE_SOL_MINT),
|
|
1093
|
-
utxoKeypair,
|
|
1094
|
-
);
|
|
1095
|
-
|
|
1096
|
-
await deposit({
|
|
1097
|
-
program,
|
|
1098
|
-
depositor: depositorKeypair,
|
|
1099
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1100
|
-
inputTreeId: 0,
|
|
1101
|
-
outputTreeId: 0,
|
|
1102
|
-
root: tree.root(),
|
|
1103
|
-
publicAmount: 1_000_000_000n, // Positive = deposit
|
|
1104
|
-
inputs: [input1, input2],
|
|
1105
|
-
outputs: [outputUtxo, output2],
|
|
1106
|
-
recipient: depositorKeypair.publicKey,
|
|
1107
|
-
fee: 0n,
|
|
1108
|
-
refund: 0n,
|
|
1109
|
-
proof: mockProof,
|
|
1110
|
-
});
|
|
487
|
+
import { sol } from "@veilo/sdk-core/config";
|
|
1111
488
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
tree.insert(output2.commitment);
|
|
489
|
+
const oneSol = sol(1); // 1_000_000_000n lamports
|
|
490
|
+
const fiveUsdc = 5_000_000n; // 5 USDC for a 6-decimal mint
|
|
1115
491
|
```
|
|
1116
492
|
|
|
1117
|
-
|
|
493
|
+
Avoid JavaScript floating-point values for token arithmetic.
|
|
1118
494
|
|
|
1119
|
-
|
|
1120
|
-
import { withdraw } from "@veilo/sdk-core";
|
|
1121
|
-
|
|
1122
|
-
// Prepare input with Merkle path
|
|
1123
|
-
const input1: InputUTXO = {
|
|
1124
|
-
...ownedUtxo1,
|
|
1125
|
-
pathIndex: 0,
|
|
1126
|
-
pathElements: tree.path(0).pathElements,
|
|
1127
|
-
};
|
|
1128
|
-
|
|
1129
|
-
const zeroInput2: InputUTXO = {
|
|
1130
|
-
...createOwnedZeroUTXO(pubkeyToField(NATIVE_SOL_MINT), utxoKeypair),
|
|
1131
|
-
pathIndex: 0,
|
|
1132
|
-
pathElements: tree.path(0).pathElements,
|
|
1133
|
-
};
|
|
1134
|
-
|
|
1135
|
-
// Zero outputs
|
|
1136
|
-
const output1 = createOwnedZeroUTXO(
|
|
1137
|
-
pubkeyToField(NATIVE_SOL_MINT),
|
|
1138
|
-
utxoKeypair,
|
|
1139
|
-
);
|
|
1140
|
-
const output2 = createOwnedZeroUTXO(
|
|
1141
|
-
pubkeyToField(NATIVE_SOL_MINT),
|
|
1142
|
-
utxoKeypair,
|
|
1143
|
-
);
|
|
495
|
+
### A private note is valuable secret data
|
|
1144
496
|
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1149
|
-
inputTreeId: 0,
|
|
1150
|
-
outputTreeId: 0,
|
|
1151
|
-
root: tree.root(),
|
|
1152
|
-
publicAmount: -900_000_000n, // Negative = withdrawal (0.9 SOL)
|
|
1153
|
-
inputs: [input1, zeroInput2],
|
|
1154
|
-
outputs: [output1, output2],
|
|
1155
|
-
recipient: recipientKeypair.publicKey,
|
|
1156
|
-
fee: 100_000_000n, // 0.1 SOL to relayer
|
|
1157
|
-
refund: 0n,
|
|
1158
|
-
proof,
|
|
1159
|
-
});
|
|
1160
|
-
```
|
|
497
|
+
A note contains the information needed to locate and spend private funds. Store
|
|
498
|
+
it encrypted, never log it, and never send its unencrypted contents to an
|
|
499
|
+
analytics or application server.
|
|
1161
500
|
|
|
1162
|
-
|
|
501
|
+
For shielding, prefer `resolveShieldOwner()`. It obtains the spending and note
|
|
502
|
+
viewing keys as a matched pair. Supplying unrelated keys can create a note that
|
|
503
|
+
the recipient cannot discover.
|
|
1163
504
|
|
|
1164
|
-
|
|
1165
|
-
import {
|
|
1166
|
-
privateTransfer,
|
|
1167
|
-
generateKeypair,
|
|
1168
|
-
createOwnedUTXO,
|
|
1169
|
-
} from "@veilo/sdk-core";
|
|
505
|
+
### Confirmation comes before local state updates
|
|
1170
506
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
amount: 1_000_000_000n,
|
|
1175
|
-
privateKey: recipientKeypair.privateKey,
|
|
1176
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1177
|
-
});
|
|
507
|
+
Do not mark notes as spent, insert commitments into a local tree, or persist a
|
|
508
|
+
predicted leaf index until the transaction is confirmed. Use `finalizeShield()`
|
|
509
|
+
for shields and call a deposit's `commit()` callback only after confirmation.
|
|
1178
510
|
|
|
1179
|
-
|
|
1180
|
-
program,
|
|
1181
|
-
relayer: relayerKeypair,
|
|
1182
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1183
|
-
inputTreeId: 0,
|
|
1184
|
-
outputTreeId: 0,
|
|
1185
|
-
root: tree.root(),
|
|
1186
|
-
publicAmount: 0n, // Zero = private transfer
|
|
1187
|
-
inputs: [input1, zeroInput2],
|
|
1188
|
-
outputs: [output1, output2],
|
|
1189
|
-
recipient: relayerKeypair.publicKey,
|
|
1190
|
-
fee: 0n,
|
|
1191
|
-
refund: 0n,
|
|
1192
|
-
proof,
|
|
1193
|
-
});
|
|
511
|
+
### Proof files are separate
|
|
1194
512
|
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
513
|
+
Circuit `.wasm` and `.zkey` files are intentionally not bundled with the npm
|
|
514
|
+
package because they are large — `files` ships `dist/` only. Provide local
|
|
515
|
+
paths, byte arrays, or hosted URLs to `createTransactionProver()` and
|
|
516
|
+
`createSwapProver()`.
|
|
1199
517
|
|
|
1200
|
-
|
|
518
|
+
Both arguments are optional. Omit them and the prover resolves artifacts from
|
|
519
|
+
disk on first use, first hit wins:
|
|
1201
520
|
|
|
1202
|
-
|
|
521
|
+
1. `$VEILO_CIRCUITS_DIR`
|
|
522
|
+
2. `<package>/circuits` — populated by `npm run copy:circuits`
|
|
523
|
+
3. `<cwd>/circuits`
|
|
524
|
+
4. `<cwd>/node_modules/@veilo/sdk-core/circuits`
|
|
1203
525
|
|
|
1204
526
|
```ts
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
await transact({
|
|
1208
|
-
program,
|
|
1209
|
-
relayer: relayerKeypair,
|
|
1210
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1211
|
-
inputTreeId: 0,
|
|
1212
|
-
outputTreeId: 0,
|
|
1213
|
-
root: tree.root(),
|
|
1214
|
-
publicAmount: 0n,
|
|
1215
|
-
inputNullifiers: [nullifier1, nullifier2],
|
|
1216
|
-
outputCommitments: [output1.commitment, output2.commitment],
|
|
1217
|
-
extData: {
|
|
1218
|
-
recipient: recipientPubkey,
|
|
1219
|
-
relayer: relayerPubkey,
|
|
1220
|
-
fee: 0n,
|
|
1221
|
-
refund: 0n,
|
|
1222
|
-
claimant: claimantPubkey,
|
|
1223
|
-
},
|
|
1224
|
-
proof,
|
|
1225
|
-
});
|
|
527
|
+
const prover = createTransactionProver(); // resolved from disk
|
|
528
|
+
const prover = createTransactionProver({ wasmPath, zkeyPath }); // explicit
|
|
1226
529
|
```
|
|
1227
530
|
|
|
1228
|
-
|
|
531
|
+
`resolveCircuitArtifacts("transaction" | "swap")` performs that lookup on its
|
|
532
|
+
own if you want the paths. Resolution is **Node-only and lazy** — it imports
|
|
533
|
+
`node:fs` inside the call so browser bundles can still import this module, and
|
|
534
|
+
there is nothing to resolve in a browser anyway. Browser builds must pass
|
|
535
|
+
`CircuitArtifacts` explicitly. A miss throws with every path it tried.
|
|
1229
536
|
|
|
1230
|
-
|
|
537
|
+
## Error handling
|
|
1231
538
|
|
|
1232
|
-
|
|
539
|
+
Shield and Cloak errors include stable fields that applications can use to show
|
|
540
|
+
useful recovery actions.
|
|
1233
541
|
|
|
1234
542
|
```ts
|
|
1235
543
|
import {
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
computeExtDataHash,
|
|
1239
|
-
encodeSnarkjsProofToTransactionProof,
|
|
1240
|
-
packProofToBytes,
|
|
1241
|
-
type ExtData,
|
|
1242
|
-
type TransactionCircuitInputs,
|
|
544
|
+
CloakApiError,
|
|
545
|
+
mapShieldError,
|
|
1243
546
|
} from "@veilo/sdk-core";
|
|
1244
547
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
inputs: [input1, input2],
|
|
1258
|
-
outputs: [output1, output2],
|
|
1259
|
-
inputTreeId: 0,
|
|
1260
|
-
outputTreeId: 0,
|
|
1261
|
-
});
|
|
1262
|
-
|
|
1263
|
-
// Format for snarkjs (converts Uint8Array to string representations)
|
|
1264
|
-
const snarkjsInputs = formatInputsForSnarkjs(circuitInputs);
|
|
1265
|
-
|
|
1266
|
-
// Use with snarkjs to generate proof
|
|
1267
|
-
// const { proof, publicSignals } = await snarkjs.groth16.fullProve(
|
|
1268
|
-
// snarkjsInputs,
|
|
1269
|
-
// wasmPath,
|
|
1270
|
-
// zkeyPath
|
|
1271
|
-
// );
|
|
1272
|
-
|
|
1273
|
-
// Convert snarkjs proof to on-chain format
|
|
1274
|
-
// const transactionProof = encodeSnarkjsProofToTransactionProof(proof);
|
|
548
|
+
try {
|
|
549
|
+
// Build or submit a Veilo operation.
|
|
550
|
+
} catch (error) {
|
|
551
|
+
if (error instanceof CloakApiError) {
|
|
552
|
+
console.error(error.code, error.status, error.message);
|
|
553
|
+
} else {
|
|
554
|
+
const shieldError = mapShieldError(error);
|
|
555
|
+
console.error(shieldError.code, shieldError.message);
|
|
556
|
+
// retryable is `rebuild`, `reshield`, or `none`.
|
|
557
|
+
console.log(shieldError.retryable);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
1275
560
|
```
|
|
1276
561
|
|
|
1277
|
-
|
|
562
|
+
When handling Cloak separately, `CloakApiError` also exposes actionable values
|
|
563
|
+
such as `min`, `max`, `field`, `maxBps`, and `retryAfter` when the API returns
|
|
564
|
+
them.
|
|
1278
565
|
|
|
1279
|
-
|
|
566
|
+
## Package entry points
|
|
1280
567
|
|
|
1281
|
-
|
|
1282
|
-
import { addRelayer, setPaused } from "@veilo/sdk-core";
|
|
1283
|
-
|
|
1284
|
-
// Add a relayer
|
|
1285
|
-
await addRelayer({
|
|
1286
|
-
program,
|
|
1287
|
-
admin: adminKeypair,
|
|
1288
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1289
|
-
newRelayer: relayerPubkey,
|
|
1290
|
-
});
|
|
1291
|
-
|
|
1292
|
-
// Pause/unpause the pool
|
|
1293
|
-
await setPaused({
|
|
1294
|
-
program,
|
|
1295
|
-
admin: adminKeypair,
|
|
1296
|
-
mintAddress: NATIVE_SOL_MINT,
|
|
1297
|
-
paused: true,
|
|
1298
|
-
});
|
|
1299
|
-
```
|
|
1300
|
-
|
|
1301
|
-
---
|
|
1302
|
-
|
|
1303
|
-
### 4.8 Poseidon Utilities
|
|
568
|
+
Import from the package root for convenience or use a focused entry point:
|
|
1304
569
|
|
|
1305
570
|
```ts
|
|
1306
|
-
import {
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
} from "@veilo/sdk-core";
|
|
1314
|
-
|
|
1315
|
-
// Initialize Poseidon (required once before using hash functions)
|
|
1316
|
-
await initPoseidon();
|
|
1317
|
-
|
|
1318
|
-
// Hash functions
|
|
1319
|
-
const hash1 = poseidon1(12345n);
|
|
1320
|
-
const hash2 = poseidon2(12345n, 67890n);
|
|
1321
|
-
const hash3 = poseidon3(12345n, 67890n, 11111n);
|
|
1322
|
-
const hash4 = poseidon4(12345n, 67890n, 11111n, 22222n);
|
|
1323
|
-
|
|
1324
|
-
// Convert Solana PublicKey to field element
|
|
1325
|
-
const fieldElement = pubkeyToField(NATIVE_SOL_MINT);
|
|
571
|
+
import { shield } from "@veilo/sdk-core";
|
|
572
|
+
import { getPoolPdas } from "@veilo/sdk-core/accounts";
|
|
573
|
+
import { createUTXO } from "@veilo/sdk-core/notes";
|
|
574
|
+
import { deposit, withdraw } from "@veilo/sdk-core/transactions";
|
|
575
|
+
import { submitWithdraw } from "@veilo/sdk-core/relayer";
|
|
576
|
+
import { VeiloCloakClient } from "@veilo/sdk-core/cloak";
|
|
577
|
+
import { derivePositionKeyBundle } from "@veilo/sdk-core/positions";
|
|
578
|
+
import { getJperpMarketPayload } from "@veilo/sdk-core/perps";
|
|
579
|
+
import { JupiterPredictionClient } from "@veilo/sdk-core/predictions";
|
|
1326
580
|
```
|
|
1327
581
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
## 5. Architecture
|
|
1331
|
-
|
|
1332
|
-
### Transaction Model
|
|
1333
|
-
|
|
1334
|
-
Veilo uses a UTXO-based privacy model inspired by Zcash and Tornado Cash Nova:
|
|
582
|
+
Available focused entry points:
|
|
1335
583
|
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
584
|
+
- `@veilo/sdk-core/accounts`
|
|
585
|
+
- `@veilo/sdk-core/cloak`
|
|
586
|
+
- `@veilo/sdk-core/config`
|
|
587
|
+
- `@veilo/sdk-core/idl`
|
|
588
|
+
- `@veilo/sdk-core/identity`
|
|
589
|
+
- `@veilo/sdk-core/notes`
|
|
590
|
+
- `@veilo/sdk-core/perps`
|
|
591
|
+
- `@veilo/sdk-core/positions`
|
|
592
|
+
- `@veilo/sdk-core/predictions`
|
|
593
|
+
- `@veilo/sdk-core/poseidon`
|
|
594
|
+
- `@veilo/sdk-core/proof`
|
|
595
|
+
- `@veilo/sdk-core/prover`
|
|
596
|
+
- `@veilo/sdk-core/relayer`
|
|
597
|
+
- `@veilo/sdk-core/shield`
|
|
598
|
+
- `@veilo/sdk-core/transactions`
|
|
1339
599
|
|
|
1340
|
-
|
|
600
|
+
## Advanced building blocks
|
|
1341
601
|
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
- Generates 2 nullifiers (prevents double-spending)
|
|
1345
|
-
- Optionally transfers funds in/out of the pool
|
|
602
|
+
The root package also exports tools for teams building their own Veilo wallet
|
|
603
|
+
or relayer:
|
|
1346
604
|
|
|
1347
|
-
|
|
605
|
+
- account and PDA queries;
|
|
606
|
+
- UTXO creation, ownership, encryption, and recovery;
|
|
607
|
+
- Merkle tree reconstruction from on-chain events;
|
|
608
|
+
- transaction and swap witness preparation;
|
|
609
|
+
- Poseidon hashing helpers;
|
|
610
|
+
- pool initialization and administration;
|
|
611
|
+
- raw IDL-correct transaction instruction builders.
|
|
1348
612
|
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
- **Unlinkability**: No public link between inputs and outputs
|
|
1352
|
-
- **Zero-knowledge proofs**: Transactions proven valid without revealing private data
|
|
613
|
+
These APIs are fully typed. Use their TypeScript definitions as the source of
|
|
614
|
+
truth for required inputs.
|
|
1353
615
|
|
|
1354
|
-
###
|
|
616
|
+
### Historical IDLs and commitment recovery
|
|
1355
617
|
|
|
1356
|
-
The
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
- Allows parallel insertions
|
|
1360
|
-
- Each tree has independent state
|
|
1361
|
-
|
|
1362
|
-
### Constants
|
|
618
|
+
The SDK includes the current, legacy, and legacy-2 privacy-pool IDLs used by the
|
|
619
|
+
relayer. Event scans automatically try the historical layouts, so applications
|
|
620
|
+
can rebuild trees across program upgrades.
|
|
1363
621
|
|
|
1364
622
|
```ts
|
|
1365
623
|
import {
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
DEFAULT_FEE_BPS, // 50 (0.5%)
|
|
1370
|
-
sol, // Helper: sol(1) = 1_000_000_000n lamports
|
|
1371
|
-
} from "@veilo/sdk-core/config";
|
|
1372
|
-
|
|
1373
|
-
import { BN254_FR_MODULUS } from "@veilo/sdk-core";
|
|
1374
|
-
```
|
|
1375
|
-
|
|
1376
|
-
### Type Exports
|
|
1377
|
-
|
|
1378
|
-
The SDK exports the following types for TypeScript users:
|
|
1379
|
-
|
|
1380
|
-
```ts
|
|
1381
|
-
import type {
|
|
1382
|
-
// UTXO types
|
|
1383
|
-
Keypair,
|
|
1384
|
-
UTXO,
|
|
1385
|
-
SerializedUTXO,
|
|
1386
|
-
InputUTXO,
|
|
1387
|
-
|
|
1388
|
-
// Proof types
|
|
1389
|
-
ExtData,
|
|
1390
|
-
TransactionCircuitInputs,
|
|
1391
|
-
TransactionProofStruct,
|
|
1392
|
-
RawProof,
|
|
1393
|
-
TransactionProofBuilder,
|
|
1394
|
-
|
|
1395
|
-
// Merkle types
|
|
1396
|
-
MerklePath,
|
|
1397
|
-
CircuitMerklePath,
|
|
1398
|
-
|
|
1399
|
-
// Config types
|
|
1400
|
-
PoolInitConfig,
|
|
1401
|
-
PrivacyConfigAccount,
|
|
1402
|
-
GlobalConfigAccount,
|
|
624
|
+
PRIVACY_POOL_IDLS,
|
|
625
|
+
buildTreeFromEvents,
|
|
626
|
+
resolveCommitmentEvents,
|
|
1403
627
|
} from "@veilo/sdk-core";
|
|
1404
628
|
```
|
|
1405
629
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
import { PublicKey } from "@solana/web3.js";
|
|
1412
|
-
|
|
1413
|
-
// For native SOL
|
|
1414
|
-
const solMint = NATIVE_SOL_MINT; // PublicKey.default
|
|
1415
|
-
|
|
1416
|
-
// For SPL tokens
|
|
1417
|
-
const usdcMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
|
|
1418
|
-
|
|
1419
|
-
// Initialize pool for SPL token
|
|
1420
|
-
await initializePool({
|
|
1421
|
-
program,
|
|
1422
|
-
payer: adminKeypair,
|
|
1423
|
-
admin: adminKeypair,
|
|
1424
|
-
mintAddress: usdcMint, // Use SPL token mint
|
|
1425
|
-
minDepositAmount: 1_000_000n, // 1 USDC (6 decimals)
|
|
1426
|
-
// ... other params
|
|
1427
|
-
});
|
|
1428
|
-
```
|
|
1429
|
-
|
|
1430
|
-
When using SPL tokens, the SDK automatically handles associated token accounts.
|
|
630
|
+
`buildTreeFromEvents()` includes Veilo's protected historical repairs by
|
|
631
|
+
default and rejects gaps that would produce an incorrect root. When a confirmed
|
|
632
|
+
instruction appended commitments without emitting `CommitmentEvent`, use
|
|
633
|
+
`resolveCommitmentEvents()` with the expected commitments and current local
|
|
634
|
+
tree. It prefers emitted metadata and computes only the missing entries.
|
|
1431
635
|
|
|
1432
|
-
|
|
636
|
+
For the deployed eventless `open_position` path, use
|
|
637
|
+
`recoverEventlessOpenPositionEvents()`. It decodes both commitments from the
|
|
638
|
+
instruction and reads the authoritative global position-tree leaf index from
|
|
639
|
+
the program-owned PositionPDA. `buildGlobalPositionTreeFromEvents()` mirrors
|
|
640
|
+
the relayer's all-mint position-tree reconstruction.
|
|
1433
641
|
|
|
1434
|
-
##
|
|
1435
|
-
|
|
1436
|
-
### Environment Variables
|
|
642
|
+
## Development
|
|
1437
643
|
|
|
1438
644
|
```bash
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
```
|
|
1442
|
-
|
|
1443
|
-
---
|
|
645
|
+
# Build CommonJS, ESM, and declaration outputs
|
|
646
|
+
npm run build
|
|
1444
647
|
|
|
1445
|
-
|
|
648
|
+
# Run deterministic unit and proof tests
|
|
649
|
+
npm test
|
|
1446
650
|
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
- **Development status**: Active development, APIs may change
|
|
651
|
+
# Run opt-in live Devnet integration tests
|
|
652
|
+
npm run test:integration
|
|
1450
653
|
|
|
1451
|
-
|
|
654
|
+
# Check module boundaries for dependency cycles
|
|
655
|
+
npm run check:cycles
|
|
656
|
+
```
|
|
1452
657
|
|
|
1453
|
-
##
|
|
658
|
+
## Support
|
|
1454
659
|
|
|
1455
|
-
-
|
|
1456
|
-
-
|
|
1457
|
-
- **Poseidon Hash**: https://www.poseidon-hash.info/
|
|
660
|
+
- [Repository](https://github.com/VeiloSolana/veilo-sdk)
|
|
661
|
+
- [Issue tracker](https://github.com/VeiloSolana/veilo-sdk/issues)
|
|
1458
662
|
|
|
1459
|
-
|
|
663
|
+
When reporting a problem, include the SDK version, runtime, Solana cluster, and
|
|
664
|
+
the error's `code` and `status` or `programCode` where available. Never include
|
|
665
|
+
private notes, wallet secret keys, API keys, or authentication tokens.
|
|
1460
666
|
|
|
1461
667
|
## License
|
|
1462
668
|
|
|
1463
|
-
ISC
|
|
669
|
+
[ISC](./LICENSE)
|