⚠️ DISCLAIMER: FOR EDUCATIONAL PURPOSES ONLYThis code has NOT been audited. Do NOT use in production or with real funds. This is experimental software provided for learning and testing purposes only. Use at your own risk.
Passive LP matcher for Percolator.
A Solana program that provides passive market making by quoting ±50 basis points off the oracle price. Called via CPI from Percolator's TradeCpi instruction.
- Passive quoting: Bid/ask spread of 50 bps (0.5%) around oracle price
- Integer-only math: Deterministic, no floating point
- Rounding: Bid rounds down, ask rounds up (both passive-favorable)
- LP PDA binding: Context account stores expected LP PDA, verified on each call
- ABI compatible: Implements Percolator's matcher context account interface
bid = floor(oracle_price × 9950 / 10000)
ask = ceil(oracle_price × 10050 / 10000)
Example with oracle price of 100,000:
- Bid: 99,500
- Ask: 100,500
# Build for Solana
cargo-build-sbf
# Run tests
cargo testThe compiled program is output to target/deploy/percolator_match.so.
- Deploy the matcher program
- Create a context account owned by the matcher program (minimum 96 bytes, recommended 320 bytes)
- Initialize the context with the LP PDA (Tag 1 instruction)
- Register the LP with Percolator via
InitLP, setting:matcher_program: This program's deployed addressmatcher_context: The initialized context account
| Offset | Field | Size | Description |
|---|---|---|---|
| 0-63 | return | 64 | Matcher return data (written on each call) - ABI required |
| 64-95 | lp_pda | 32 | Stored LP PDA (set on init, verified on calls) |
Minimum size: 96 bytes (percolator requires 320 bytes)
Executes passive matching logic. Requires LP PDA to be a signer and match the stored PDA.
| Index | Name | Type | Description |
|---|---|---|---|
| 0 | lp_pda | Signer | LP PDA (must match stored PDA) |
| 1 | matcher_ctx | Writable | Context account owned by this program |
| Offset | Field | Type | Description |
|---|---|---|---|
| 0 | tag | u8 | Always 0 |
| 1-9 | req_id | u64 | Request ID (echoed) |
| 9-11 | lp_idx | u16 | LP account index |
| 11-19 | lp_account_id | u64 | LP account ID (echoed) |
| 19-27 | oracle_price_e6 | u64 | Oracle price (1e6 scaled) |
| 27-43 | req_size | i128 | Requested size (+buy/-sell) |
| 43-67 | reserved | [u8;24] | Must be zero |
| Offset | Field | Type | Description |
|---|---|---|---|
| 0-4 | abi_version | u32 | Always 1 |
| 4-8 | flags | u32 | VALID=1, PARTIAL_OK=2, REJECTED=4 |
| 8-16 | exec_price_e6 | u64 | Execution price |
| 16-32 | exec_size | i128 | Executed size |
| 32-40 | req_id | u64 | Echo of req_id |
| 40-48 | lp_account_id | u64 | Echo of lp_account_id |
| 48-56 | oracle_price_e6 | u64 | Echo of oracle_price_e6 |
| 56-64 | reserved | u64 | Always 0 |
Stores the LP PDA in the context account. Does not require PDA signature (passive init). Can only be called once.
| Index | Name | Type | Description |
|---|---|---|---|
| 0 | lp_pda | - | LP PDA to store (no signature required) |
| 1 | matcher_ctx | Writable | Context account owned by this program |
| Offset | Field | Type | Description |
|---|---|---|---|
| 0 | tag | u8 | Always 1 |
- LP PDA binding: The matcher verifies that the LP PDA signer matches the PDA stored during initialization
- One-time init: Context can only be initialized once (prevents rebinding)
- Program ownership: Context account must be owned by this program
Apache 2.0