βββββββ ββββββ βββββββ βββ ββββββββββ βββββββ βββββββ βββ
βββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββββ
βββ ββββββββββββββββββββββββββ βββββββββββ ββββββ ββββββ
βββ ββββββββββββββββββββββββββ βββββββ βββ ββββββ ββββββ
βββββββββββ ββββββ ββββββ ββββββ ββββββββββββββββββββββββββ
βββββββ βββ ββββββ ββββββ ββββββ βββββββ βββββββ ββββββββ
On-chain coordination for DarkPool drops
Nullifier-verified SOL drops with rate limits, vaults, and authority controls.
DarkPool Program is an Anchor-based Solana program that manages SOL vaults, drop metadata, and nullifier state for DarkDrop's pool-like flows. It enforces double-spend prevention, expiration windows, fee routing, and authority-guarded drop creation.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β DARKPOOL PROGRAM β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ create_drop ββββββββββββββββββββββ β
β β AUTHORITY ββββββββββββββββββββΊβ DROP PDA β β
β β (SERVICE) β β (metadata only) β β
β ββββββββ¬βββββββ ββββββββββββ¬ββββββββββ β
β β β β
β βΌ βΌ β
β βββββββββββββββ ββββββββββββββββββ β
β β NULLIFIER βββββββββββββββββββββββΊβ NULLIFIER PDA β β
β β DERIVE β claim_drop β (spent flags) β β
β βββββββββββββββ ββββββββββββββββββ β
β β
β Notes: Funds are held in vault PDAs. Privacy rails remain off-chain and β
β integrate with this program for deposit/claim orchestration. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββ
β NONE β
βββββββ¬βββββββ
β create_drop
βΌ
ββββββββββββββ
β ACTIVE β
βββββββ¬βββββββ
claim β expire
βΌ
ββββββββββββββ΄βββββββββββββ
β β
βββββββββββββ βββββββββββββ
β CLAIMED β β EXPIRED β
βββββββββββββ βββββββββββββ
ββββββββββββββββ ββββββββββββββββ
β UNUSED ββββββββββΊβ USED β
ββββββββββββββββ claim ββββββββββββββββ
ββββββββββββββ propose ββββββββββββββββ accept ββββββββββββββ
β AUTHORITY ββββββββββββΊβ PENDING ββββββββββΊβ AUTHORITY β
ββββββββββββββ ββββββββββββββββ ββββββββββββββ
β cancel
βΌ
ββββββββββββββ
β AUTHORITY β
ββββββββββββββ
Devnet: EPpgM9ogD8wTVESMmin8kwemTmkVPQhPq9w1Mpz8Gxb7
poseidon: Canonical hashing path for local + mainnet.devnet-fast-hash: Devnet-only hash shortcut for Phase 1 demo wiring. Not for mainnet.
Devnet build example:
$env:DARKPOOL_FEATURES="poseidon,devnet-fast-hash,no-log-ix-name"
$env:GROTH16_FEATURES="devnet-fast-hash"
.\build-with-docker.ps1
Devnet proof/VK generation:
docker run --rm -v "${PWD}:/workspace" -w /workspace/tools/proofgen darkpool-builder \
bash -lc "cargo run --release --features devnet-fast-hash -- input.devnet.json"
Phase 1 is frozen unless a critical bug is found.
Initializes program configuration. Must be called once before any drops can be created.
Accounts
config(PDA) - seeds:["config"]authority- signer, payersystem_program
Creates a new drop record and nullifier entry (authority-only flow).
Params
nullifier: [u8; 32]recipient: Pubkeyamount: u64asset_type: u8(0=SOL, 1=USDC)expires_at: i64
Accounts
drop(PDA) - seeds:["drop", nullifier]nullifier_account(PDA) - seeds:["nullifier", nullifier]config(PDA)rate_limit_account(PDA) - seeds:["rate_limit", payer]payer- signersystem_program
Validations
- Authority matches config
- Amount > 0
- Asset type supported
- Recipient differs from payer
- Expiration 1 minute to 30 days in future
- 10s rate limit per payer
Deposits SOL into the vault and creates a drop record.
Params
nullifier: [u8; 32]amount: u64asset_type: u8(0=SOL)expires_at: i64(0 disables expiry)
Transfers from vaults to the claimer, applies fees, and marks the nullifier used.
Params
nullifier: [u8; 32]
Accounts
drop(PDA)nullifier_account(PDA)claimer- signer
Validations
- Drop is Active
- Not expired
- Nullifier unused
- Nullifier matches drop
Expires an active drop that has passed its expiration window.
Params
nullifier: [u8; 32]
Accounts
drop(PDA, close)nullifier_account(PDA, close)config(PDA)authority- signerrent_collector
propose_authoritycancel_authority_proposalaccept_authorityupdate_authority_delay
authority: Pubkey
is_initialized: bool
pending_authority: Pubkey
pending_authority_set_at: i64
authority_delay_seconds: i64
usdc_mint: Pubkey
treasury: Pubkey
fee_bps: u16
sol_vault_bump: u8
usdc_vault_bump: u8
vault_authority_bump: u8
nullifier: [u8; 32]
recipient: Pubkey
amount: u64
asset_type: u8
status: DropStatus
expires_at: i64
created_at: i64
claimed_at: i64
claimer: Pubkey
bump: u8
nullifier: [u8; 32]
is_used: bool
claimer: Pubkey
used_at: i64
bump: u8
last_drop_at: i64
bump: u8
import * as anchor from "@coral-xyz/anchor";
import { PublicKey, SystemProgram } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
const program = anchor.workspace.Darkpool;
const [configPDA] = PublicKey.findProgramAddressSync(
[Buffer.from("config")],
program.programId
);
await program.methods
.depositPool(
Array.from(nullifier),
new BN(amount),
assetType,
expiresAt
)
.accounts({
drop: dropPDA,
nullifierAccount: nullifierPDA,
config: configPDA,
rateLimitAccount: rateLimitPDA,
payer: authority.publicKey,
payerToken: authority.publicKey,
solVault: solVaultPDA,
usdcVault: usdcVaultPDA,
usdcMint,
systemProgram: SystemProgram.programId,
tokenProgram: anchor.utils.token.TOKEN_PROGRAM_ID,
})
.rpc();anchor testTests cover:
- Initialization
- Drop creation
- Double-claim prevention
- Rate limit enforcement
- Input validation
- Expiration handling
See tests/darkpool.ts for implementation.
.\build-with-docker.ps1.\build-program.ps1- Use
anchor build --no-idlfor local builds. IDL generation is deferred to a separate tooling phase. - Account validation is implemented manually (not
#[derive(Accounts)]) to avoid macro path-resolution issues and keep the on-chain logic explicit and auditable.
.\deploy-devnet.ps1- This program enforces SOL vault transfers and nullifier state.
- Privacy rails remain off-chain; vault flows do not hide amounts on-chain.
- No security audit has been completed. Do not deploy to mainnet without a professional review.
MIT License - see LICENSE for details.