Verifiable builds
The exact same Docker container and locked dependencies produce the exact same binary every time. CI publishes the SHA-256 hash — you can reproduce it yourself.
On-chain comparison
Dump the deployed program from Solana, hash it, and compare. If the hashes match, the code you read is the code that runs.
SDK audit
The TypeScript SDK that builds your transactions has been verified byte-for-byte against the Rust source — every instruction tag, every account ordering, every encoding.
What is an SBF Build?
Solana programs compile to SBF (Solana Bytecode Format) — a variant of eBPF designed for the Solana runtime. The compiled.so file is what gets deployed on-chain and executed by validators.
The problem: Rust builds are not deterministic across machines. Different OS versions, toolchains, or dependency resolution can produce different binaries from the same source code. This means you can’t just cargo build on your laptop and compare.
The solution: verifiable builds use a pinned Docker image with an exact Rust version, exact Solana tools, and a locked Cargo.lock to guarantee the same source always produces the same bytes.
If the hashes match, the deployed program is byte-for-byte identical to the open-source code.
Verified Builds
Percolator Program
Latest CI run — click to see build logs and artifact hash
Matcher Program
Latest CI run — click to see build logs and artifact hash
Percolator Program
| Repository | purpletrade/percolator-prog |
| Docker image | solanafoundation/solana-verifiable-build:1.18.9 |
| Rust | 1.75.0 |
| Branch | verifiable-build |
| Artifact | percolator-prog-sbf-1.18.9 (72.5 KB) |
| SHA-256 | bf68c6359fd0ecb2cf245c19ee0ccf10fcdb42b54f4c81d6772d10e1586b5cad |
Matcher Program
| Repository | purpletrade/percolator-match |
| Docker image | solanafoundation/solana-verifiable-build:2.3.0 |
| Branch | verifiable-build |
| Artifact | percolator-match-sbf-2.3.0 (12.6 KB) |
| SHA-256 | a2d5aef57b91b6895079a138f849471bd58b9fd0ae4a643f1ce069c794dba073 |
What the CI Does
Each verified build workflow runs these steps inside GitHub Actions:- Checkout — Clone the
verifiable-buildbranch with full history - Docker build — Spin up
solanafoundation/solana-verifiable-build(pinned version), install the exact Rust toolchain - Compile —
cargo-build-sbf --force-tools-install --sbf-out-dir target/deploy -- --lockedensures theCargo.lockis respected exactly - Hash —
shasum -a 256produces the deterministic SHA-256 of the.sobinary - Upload — The artifact (
.so+.sha256) is published to GitHub Actions for anyone to download
--locked flag is critical — it prevents Cargo from resolving newer dependency versions that could change the output.
Verify It Yourself
scripts/verify.sh helper in the repo does this in one command.
Upstream Transparency
Both repositories include anupstream-sync.yml CI workflow that checks for divergence from Anatoly Yakovenko’s original source. Every change we make is visible in the commit history:
- percolator-prog commits — security.txt, vendored dependencies, CI, threat model
- percolator-match commits — vAMM matcher, LP PDA validation, context initialization
Security Metadata
Both programs embedsolana-security-txt in the on-chain binary — contact info, source repo, and security policy discoverable directly from explorers. Programs are verified on OtterSec and display green verification badges on Solscan:
- Matcher on Solscan — click the Security tab to see
security.txtdetails
Formal Verification
The risk engine (purpletrade/percolator) is verified using Kani model checking — 143 proofs that mathematically verify safety invariants:
Conservation
No value created from nothing. Deposits + insurance = withdrawable capital + positions.
Isolation
No cross-account contagion. One account’s state cannot corrupt another’s.
No Over-Withdrawal
Users cannot extract more than deposited capital plus earned PnL.
| Category | Proofs | What it verifies |
|---|---|---|
| Matcher ABI validation | 13 | Rejects malformed matcher responses |
| Owner/signer enforcement | 5 | Only account owner can act, admin burn disables ops |
| CPI identity binding | 2 | LP matcher program/context must match registration |
| Edge cases & boundaries | 100+ | Overflow, sign, i128::MIN, reserved field checks |
SDK Source Audit
The TypeScript SDK atsrc/lib/percolator/ has been verified instruction-by-instruction against the Rust source at aeyakovenko/percolator-prog.
| Category | Verified | Status |
|---|---|---|
| Instruction tags | 21/21 | Verified |
| Data encoding | 21/21 | Verified |
| Account orderings | 21/21 | Verified |
| PDA derivation | 2/2 | Verified |
| Error codes | 25/25 | Verified |
| Slab layout | 4/4 structs | Verified |
Instruction tags — all 21 match
Instruction tags — all 21 match
Data encoding — field-by-field match
Data encoding — field-by-field match
Every instruction’s data payload verified against the Rust
decode functions. All little-endian with exact byte offsets:u8,u16,u32,u64: Standard LE integersi64,i128: Signed integers (twos complement, LE)u128: 16-byte LE (prices inPushOraclePrice)[u8; 32]: Raw pubkey bytes (UpdateAdmin,SetOracleAuthority)
Account orderings — TradeCpi example
Account orderings — TradeCpi example
Each instruction’s accounts verified against All 21 instruction account orderings match.
process_instruction in percolator.rs. Example for TradeCpi:PDA derivation — both patterns verified
PDA derivation — both patterns verified
Vault authority:LP PDA:
Error codes — 25/27 mapped
Error codes — 25/27 mapped
| Code | Error | Mapped |
|---|---|---|
| 0 | InvalidInstruction | Yes |
| 1 | InvalidSlabMagic | Yes |
| 2 | InvalidSlabVersion | Yes |
| 3 | InvalidSlabBump | Yes |
| 4 | InvalidSlabLen | Yes |
| 5 | SlabFull | Yes |
| 6 | AccountNotFound | Yes |
| 7 | AccountAlreadyExists | Yes |
| 8 | InsufficientCollateral | Yes |
| 9 | InsufficientMargin | Yes |
| 10 | MaxLeverageExceeded | Yes |
| 11 | InvalidOraclePrice | Yes |
| 12 | OracleStale | Yes |
| 13 | TradingPaused | Yes |
| 14 | Unauthorized | Yes |
| 15 | EngineUnauthorized | Yes |
| 16–25 | (various) | Yes |
| 26 | InvalidConfigParam | Omitted (admin-only) |
| 27 | HyperpTradeNoCpiDisabled | Omitted (internal) |
Slab layout — struct offsets verified
Slab layout — struct offsets verified
| Struct | Offset | Size | Match |
|---|---|---|---|
| SlabHeader | 0 | 72 bytes | Yes |
| MarketConfig | 72 | 320 bytes | Yes |
| EngineState | 392 | Variable | Yes |
| Account slots | After engine | 240 bytes each | Yes |
#[repr(C)] layout rules with alignment and padding.Methodology
- Read the complete Rust source (
percolator.rs, ~4,400 lines) - Extract every instruction’s decode logic, account ordering, and data format
- Compare line-by-line against the TypeScript SDK (
instructions.ts,accounts.ts,slab.ts,pda.ts,errors.ts) - Confirm byte-level compatibility for all encoded data
Source References
percolator-prog
Core program — verified builds, security.txt, formal proofs
percolator-match
LP matcher — verified builds, vAMM implementation
Original source
Canonical source by Anatoly Yakovenko
Risk engine
Formally verified library — 143 Kani proofs