Omnipair is a next-generation DeFi primitive on Solana that unifies liquidity provision and lending into a single capital-efficient protocol.
Omnipair GAMM (Generalized Automated Market Maker) combines a UniV2-style CPMM (constant-product market maker) with an integrated lending market, allowing liquidity providers to earn both swap fees and lending interest on their deposited assets. Borrowers can use one side of the pair as collateral to borrow the other. Price uses a built-in symmetric EMA (smooths both up and down over a half-life); dynamic LTV and collateral factors use a double-EMA (symmetric + directional), taking the more conservative of the two to protect against volatility and front-running.
Lending is isolated per pair (each pool’s risk is contained), and bad debt is socialized on LPs (insolvent positions are written off against the pool so the protocol avoids bank runs; LPs bear the loss via the constant-product curve). The protocol is oracless (no external oracle dependency) and permissionless (anyone can create pairs, add liquidity, borrow, or liquidate).
Beyond the AMM invariant xy = k, Omnipair enforces a lending solvency invariant: virtual reserves = cash + debt (R_virtual = R_cash + R_debt) with R_cash ≥ 0, and every state change obeys ΔR_virtual = ΔR_cash + ΔR_debt. See the Docs for reserve types, Impact-aware collateral factor and how liquidation works.
- Unified Liquidity - LP deposits serve as both AMM reserves and lending supply, maximizing capital efficiency
- Isolated Lending - Risk is isolated per pair; each pool’s borrows and collateral are independent of other pairs
- Bad debt socialized on LPs - Insolvent positions are written off against the pool; LPs absorb the loss (via the AMM curve) to protect the protocol from bank runs
- Lending EMA price - Built-in price uses a symmetric EMA that smooths both up and down movements over a configurable half-life
- Dynamic LTV / collateral factors: double-EMA - Two EMAs (symmetric and directional) feed dynamic LTV and collateral ratios; the more conservative of the two is used for borrow and liquidation limits to protect LPs and borrowers
- Flash Loans - Uncollateralized loans within a single transaction (0.05% fee)
- Interest Rate Model - Adaptive rates based on utilization with configurable target ranges
- Liquidation Engine - Partial liquidations with 3% penalty (0.5% to liquidator, 2.5% to LPs)
┌─────────────────────────────────────────────────────────────────┐
│ OMNIPAIR │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Liquidity Providers Traders │
│ ┌───────────────────┐ ┌─────────────────┐ │
│ │ Deposit Token A │ │ Swap A ↔ B │ │
│ │ Deposit Token B │ │ (pay swap fee) │ │
│ │ Receive LP Tokens │ └─────────────────┘ │
│ └───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Unified Reserve Pool │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ Token A Reserve │ │ Token B Reserve │ │ │
│ │ │ (Cash + Debt) │ │ (Cash + Debt) │ │ │
│ │ └──────────────────┘ └──────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Borrowers │
│ ┌─────────────────┐ │
│ │ Deposit Token A │ → Borrow Token B │
│ │ as Collateral │ ← (pay interest) │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
| Parameter | Value | Description |
|---|---|---|
| Swap Fee | Configurable | Per-pair swap fee in basis points |
| Flash Loan Fee | 0.05% | Fee for uncollateralized flash loans |
| Max Collateral Factor | 85% | Maximum LTV before liquidation risk |
| LTV Buffer | 5% | Gap between borrow limit and liquidation |
| Liquidation Penalty | 3% | Total penalty on liquidated collateral |
| Liquidation Incentive | 0.5% | Reward for liquidators |
| LP Withdrawal Fee | 1% | Fee to remaining LPs on withdrawal |
Omnipair has been audited by:
- Offside Labs
- Ackee
See security policy for details.
| Network | Program ID |
|---|---|
| Mainnet | omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE |
| Devnet | omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE |
# Install dependencies
yarn install
# Build for devnet
anchor build
# Run tests
anchor testCreate a .env file based on .env.example:
cp .env.example .envKey variables:
ANCHOR_CLUSTER: Network cluster (devnet/mainnet)ANCHOR_WALLET: Path to wallet keypair fileTOKEN0_MINT/TOKEN1_MINT: Token mint addresses for the pair
-
Deploy Test Tokens (devnet only):
yarn deploy-tokens
Update
.envwith the new token mint addresses. -
Initialize Futarchy Authority:
yarn init-futarchy
-
Mint Test Tokens:
yarn faucet-mint
-
Initialize the Pair:
yarn initialize
-
Publish IDL:
anchor idl init --filepath target/idl/omnipair.json <PROGRAM_ID>
This project uses automated CI/CD with GitHub Actions for releases and program upgrades.
┌─────────────────────────────────────────────────────────────────────┐
│ AUTOMATIC (PR Merge) │
├─────────────────────────────────────────────────────────────────────┤
│ 1. Version Bump → Based on conventional commits │
│ 2. Verifiable Build → anchor build --verifiable --features prod │
│ 3. Create Release → GitHub release with .so and IDL artifacts │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ MANUAL: Deploy Buffer (~8 SOL) │
├─────────────────────────────────────────────────────────────────────┤
│ 4. Download from Release → Gets omnipair.so from GitHub │
│ 5. Deploy Buffer → solana program write-buffer │
│ 6. Transfer to Squads → Buffer authority → multisig │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ MANUAL: Squads Approval │
├─────────────────────────────────────────────────────────────────────┤
│ Team signs upgrade transaction on Squads UI │
│ https://app.squads.so/squads/<MULTISIG>/developer/programs/<ID> │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ MANUAL: Verify & Publish Packages │
├─────────────────────────────────────────────────────────────────────┤
│ 7. Verify Release → solana-verify + OtterSec submission │
│ 8. Publish npm → @omnipair/program-interface │
│ 9. Publish crate → omnipair-decoder on crates.io │
└─────────────────────────────────────────────────────────────────────┘
Version bumps are automatic based on commit messages:
| Commit Prefix | Version Bump | Example |
|---|---|---|
fix: |
PATCH (0.0.X) | fix: correct swap calculation |
feat: |
MINOR (0.X.0) | feat: add flash loan support |
feat!: or BREAKING CHANGE: |
MAJOR (X.0.0) | feat!: new account structure |
chore:, docs:, test: |
No release | chore: update dependencies |
| Workflow | Trigger | Purpose |
|---|---|---|
release-build.yaml |
PR merge / Manual | Build, release, deploy, verify, publish |
anchor-buffer.yaml |
Manual | Standalone buffer deployment (edge cases) |
verify-build.yaml |
Manual | Verify on-chain program against source |
All manual triggers: Actions → release-build → Run workflow
| Input | Purpose |
|---|---|
version |
Explicit version (e.g., 1.0.0) |
bump_type |
Auto/patch/minor/major bump |
deploy_buffer ✅ |
Deploy buffer to Solana mainnet (~8 SOL) |
verify_only ✅ |
Only verify on-chain program |
publish_packages ✅ |
Verify + publish npm/crates.io |
Typical Upgrade Flow:
1. Merge PR → Auto creates release v0.4.0
2. deploy_buffer ✅ → Deploys buffer, transfers to Squads
3. Team signs → Approve on Squads UI
4. publish_packages ✅ → Verify + publish packages
Deploy Buffer Only (edge cases):
Actions → Manual Buffer Deploy → Run workflow
├── source: release (from GitHub release)
└── release_tag: v0.4.0 (optional, defaults to latest)
All releases are built using Anchor's verifiable build system for reproducibility.
# Set environment variables for security.txt
export GIT_REV=$(git rev-parse HEAD)
export GIT_RELEASE=$(git describe --tags --abbrev=0 2>/dev/null || echo "dev")
# Build verifiable
anchor build --verifiable -p omnipair \
-e GIT_REV=$GIT_REV \
-e GIT_RELEASE=$GIT_RELEASE \
-- --features "production"# Install solana-verify
cargo install solana-verify
# Verify from repository
solana-verify verify-from-repo \
--remote \
--program-id omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE \
https://github.com/omnipair/omnipair-rs \
--commit-hash <COMMIT_SHA> \
--library-name omnipair \
--bpf-flag "features=production"solana-verify remote submit-job \
--program-id omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE \
https://github.com/omnipair/omnipair-rs \
--commit-hash <COMMIT_SHA> \
--library-name omnipair \
--bpf-flag "features=production"The program upgrade authority is a Squads multisig. Upgrades require team approval.
- Merge PR to
mainwithfeat:orfix:commit - CI builds verifiable binary and creates GitHub release
- Manual: Run workflow with
deploy_buffer✅ to deploy buffer - Manual: Team signs upgrade transaction on Squads UI
- Manual: Run workflow with
publish_packages✅ to verify + publish
If you need to upgrade manually:
# 1. Build verifiable binary
export GIT_REV=$(git rev-parse HEAD)
export GIT_RELEASE=$(git describe --tags)
anchor build --verifiable -p omnipair \
-e GIT_REV=$GIT_REV \
-e GIT_RELEASE=$GIT_RELEASE \
-- --features "production"
# 2. Deploy buffer
solana program write-buffer \
--keypair deployer-keypair.json \
target/verifiable/omnipair.so \
-u mainnet-beta
# 3. Transfer authority to Squads vault
solana program set-buffer-authority <BUFFER_ADDRESS> \
--new-buffer-authority <SQUADS_VAULT_ADDRESS> \
--keypair deployer-keypair.json \
-u mainnet-beta
# 4. Create upgrade proposal on Squads UI
# https://app.squads.so/squads/<MULTISIG_ADDRESS>/developer/programs/<PROGRAM_ID>
# 5. Team signs and executes
# 6. Verify
solana-verify verify-from-repo \
--remote \
-um \
--program-id <PROGRAM_ID> \
https://github.com/omnipair/omnipair-rs \
--library-name omnipair \
--bpf-flag "features=production"If the new binary is larger than allocated space:
# Check current size
solana program show omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE
# Extend (requires upgrade authority - do via Squads)
solana program extend omnixgS8fnqHfCcTGKWj6JtKjzpJZ1Y5y9pyFkQDkYE <ADDITIONAL_BYTES>| Secret | Description |
|---|---|
DEPLOYER_KEYPAIR |
JSON array of funded deployer wallet (~8 SOL for buffer) |
NPM_TOKEN |
npm access token for publishing |
CRATES_IO_TOKEN |
crates.io API token for publishing decoder |
GH_PAT |
GitHub PAT with repo write access (for version bump commits) |
| Variable | Description |
|---|---|
SQUADS_MULTISIG_ADDRESS |
Squads multisig address |
SQUADS_VAULT_ADDRESS |
Squads vault PDA (buffer authority recipient) |
MAINNET_RPC_URL |
(Optional) Custom RPC URL |
Note:
PROGRAM_IDis automatically extracted fromprograms/omnipair/src/lib.rs(declare_id!macro).
import { getVaultPda } from "@sqds/multisig";
const [vault] = getVaultPda({
multisigPda: new PublicKey("YOUR_MULTISIG_ADDRESS"),
index: 0,
});
console.log("Vault:", vault.toBase58());omnipair-rs/
├── programs/
│ └── omnipair/ # Main program
│ ├── src/
│ │ ├── lib.rs
│ │ ├── instructions/
│ │ ├── state/
│ │ └── utils/
│ └── Cargo.toml
├── scripts/ # TypeScript helper scripts
├── tests/ # Integration tests
├── packages/
│ └── program-interface/ # npm package with IDL
└── .github/workflows/ # CI/CD workflows
See LICENSE for details.