Skip to content

Commit dedcb1e

Browse files
committed
docs(finance): add CHANGELOG.md to the finance programs
Only lending (both twins) and vault-strategy/anchor had a CHANGELOG. Add an initial 0.1.0 entry to the remaining finance programs and Quasar twins (escrow, token-swap, perpetual-futures, token-fundraiser, order-book, betting-market, and vault-strategy/quasar), matching the existing house format. Each entry is derived from the program's README and source: handler, account, seed, and error names were verified against the code, and Quasar twins note their port-specific differences. betting-market is described as admin-trusted for resolution, not trustless.
1 parent 841adab commit dedcb1e

13 files changed

Lines changed: 305 additions & 0 deletions

File tree

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial betting-market program: a parimutuel (pooled) prediction market where an admin opens events and bettors stake a token on outcomes.
6+
7+
- A single `Config` PDA (`["config"]`) holding the `admin`, the accepted `token_mint`, the `fee_recipient`, and `fee_bps`.
8+
- Per-market `Event` PDAs (`["event", event_id]`) tracking `total_pool`, `status` (`Open` / `Settled` / `Cancelled`), and the winning figures written at settlement, with `fee_bps` snapshotted at creation so later Config changes can't alter a joined market.
9+
- Per-result `Outcome` PDAs (`["outcome", event, index]`) whose `total_amount` is the pro-rata denominator, and per-`(outcome, bettor)` `Bet` PDAs holding one staker's total position.
10+
- A per-wallet `User` index PDA (`["user", wallet]`) listing a bettor's open `Bet` addresses, capped at `MAX_BETS_PER_USER` concurrent open positions (rejected with `TooManyBets`).
11+
- Nine instruction handlers: `initialize_config`, `create_event`, `add_outcome`, `place_bet`, `settle_event`, `claim_winnings`, `close_losing_bet`, `cancel_event`, and `claim_refund`.
12+
- Each event owns a single vault (the associated token account of the Event PDA); `place_bet` moves stakes in, and settlement and claims move tokens out with the program signing as the Event PDA (`["event", event_id, bump]`).
13+
- Parimutuel payout formula: the fee is charged only on `losing_pool`, and each winner claims `stake + stake * distributable_losing / winning_pool`, so a winner never receives less than they staked.
14+
- Integer division floors each share, leaving at most a few minor units of dust in the vault rather than ever overpaying.
15+
- Outcome resolution is admin-trusted: `settle_event` and `cancel_event` are admin-only and the admin chooses the winning outcome; the custody guarantee is that the admin's only powers are creating events/outcomes and settling or cancelling, never withdrawing stakes.
16+
- `add_outcome` is locked once the first bet is placed, so the field of choices can't change under existing bettors.
17+
- `settle_event` rejects a winning outcome with no bets; an event that can't be resolved fairly is unwound with `cancel_event`, after which every bettor reclaims their exact stake with `claim_refund` and no fee is taken.
18+
- Closing the `Bet` account (via `claim_winnings`, `claim_refund`, or `close_losing_bet`) is what ends a position and makes a second claim impossible, and it removes the entry from the user's index.
19+
- Ships Rust + LiteSVM integration tests (with solana-kite helpers) covering the bet/settle/claim lifecycle with exact payout and fee assertions, admin authorization, the bet-after-settle and double-claim guards, no-bet settlement, the cancel/refund path, and the User index bookkeeping.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial Quasar port of the betting-market program: a parimutuel (pooled) prediction market where an admin opens events and bettors stake a token on outcomes.
6+
7+
- Port of the Anchor example, sharing the same program ID (`7LyqAeLR3mK9dfj9LqxWzfKH61VVHzuNpkgW5Y32De74`), so clients and PDA derivations work against either build unchanged.
8+
- A single `Config` PDA (`["config"]`) holding the `admin`, accepted `token_mint`, `fee_recipient`, and `fee_bps`; per-market `Event` PDAs (`["event", event_id]`) tracking `total_pool`, status, a fee snapshot, and the winning figures.
9+
- Per-result `Outcome` PDAs (`["outcome", event, index]`), per-`(outcome, bettor)` `Bet` PDAs, and a per-wallet `User` index PDA (`["user", bettor]`) capped at 32 concurrent open positions.
10+
- Instruction handlers covering the lifecycle: `initialize_config`, `create_event`, `add_outcome`, `place_bet`, `settle_event`, `claim_winnings`, `close_losing_bet`, `cancel_event`, and `claim_refund`.
11+
- Each event's stakes sit in a single pool vault from `place_bet` until a claim or refund; every transfer out is signed by the Event PDA via `invoke_signed`, so only the deployed program can move pooled funds.
12+
- Parimutuel payout: the fee is charged only on the losing pool so a winner never receives less than they staked, and integer division floors in the pool's favor, leaving at most a few minor units of dust.
13+
- Outcome resolution is admin-trusted: admin-gated instructions bind the signer to `config.admin` with `has_one`, there is no admin path to withdraw stakes (only to settle or cancel), and the winning outcome is tied to its index through PDA derivation so a mismatched outcome can't be settled to.
14+
- `add_outcome` is locked once the first bet is placed, and payouts credit and close before transferring (effects before interactions).
15+
- Closing the `Bet` account on claim, refund, or loser-close is what ends a position and prevents a double claim.
16+
- Quasar-specific: the port stores `Event.description`, `Outcome.label`, and the `User` position index as fixed byte buffers plus a length (`[u8; 200]`, `[u8; 64]`, and a packed `[u8; 1024]` of up to 32 addresses) instead of borsh `String` / `Vec<Pubkey>`, making each mutation an in-place write.
17+
- Quasar-specific: the pool vault is a program-derived token account (`["vault", event]`) rather than an associated token account, matching the other Quasar finance examples, and enum values (`side`, status) are stored as `u8` matching the Anchor build's byte encodings.
18+
- Ships QuasarSVM integration tests (`src/tests.rs`) driving the full lifecycle (open a market, add outcomes, place opposing bets, settle, claim, close the losing bet) and the cancel/refund path with onchain state, token balance, and fee assertions, plus an admin-authorization rejection.

finance/escrow/anchor/CHANGELOG.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
An atomic two-party token escrow: a maker swaps a fixed amount of one token for
6+
a wanted amount of another with a taker, without either party trusting the other
7+
and with no spread or middleman fee.
8+
9+
- `Offer` PDA seeded `["offer", maker, id]` storing the `id`, `maker`, both
10+
mints (`token_mint_a` offered, `token_mint_b` wanted), the
11+
`token_b_wanted_amount`, and the `bump`; the `id` lets one maker keep several
12+
offers open at once.
13+
- The vault is the offer PDA's associated token account for token A; it holds
14+
the maker's offered tokens while the offer is open, and only the offer PDA can
15+
sign transfers out of it.
16+
- `make_offer` creates the offer PDA and vault, moves the offered token A into
17+
the vault with `transfer_checked`, and records the offer state; the maker
18+
signs and pays all rent.
19+
- `make_offer` also creates the maker's token-B associated token account if
20+
needed, paid by the maker, so the eventual taker never funds a maker-owned
21+
account.
22+
- `take_offer` sends the wanted token B from the taker to the maker, releases
23+
the vault's token A to the taker signed by the offer PDA, and closes both the
24+
vault and the offer account back to the maker.
25+
- `cancel_offer` returns the vault's token A to the maker and closes both
26+
accounts; only the maker can call it, so an abandoned offer never locks the
27+
maker's tokens forever.
28+
- Anchor constraints bind every account to the stored offer state (`has_one` on
29+
the maker and both mints, associated-token constraints on the vault and every
30+
token account, and the PDA seeds on the offer itself).
31+
- Every path that closes the offer and vault (`take_offer`, `cancel_offer`)
32+
refunds both rents to the maker, who paid them.
33+
- Settlement is atomic in a single transaction: neither party can take the
34+
other's tokens and run.
35+
- Ships Rust + LiteSVM integration tests (with solana-kite helpers) covering the
36+
make/take flow, the make/cancel flow, rejection of a non-maker cancel, token
37+
balances on every leg, and the maker's rent refunds after both take and
38+
cancel.
39+
- Based on Dean Little's Anchor Escrow, restructured for teaching.

finance/escrow/quasar/CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial Quasar port of the escrow program: an atomic token swap between a maker
6+
and a taker.
7+
8+
- `Offer` PDA seeded `["offer", maker, id]` - the same seeds as the Anchor
9+
variant, so clients work against either build.
10+
- The `Offer` account stores the `maker`, both mints, the maker's token B
11+
account (`maker_token_account_b`), the `vault` address, the wanted `receive`
12+
amount, and the `bump`.
13+
- The vault is a token account owned by the offer PDA holding the maker's
14+
offered token A while the offer is open.
15+
- `make_offer` (discriminator 0) takes `id`, `deposit`, and `receive`; it saves
16+
the offer state and then deposits the offered token A into the vault, with the
17+
maker paying rent for both the offer account and the vault.
18+
- `take_offer` (discriminator 1) transfers the wanted token B to the maker, then
19+
withdraws the vault's token A to the taker and closes the accounts back to the
20+
maker.
21+
- `cancel_offer` (discriminator 2) withdraws token A back to the maker and
22+
closes the vault and offer accounts; the maker-only path prevents funds being
23+
locked forever.
24+
- `has_one` bindings validate every passed account against the stored offer
25+
state.
26+
- The program is `no_std` and its instructions carry explicit discriminators
27+
(0/1/2).
28+
- Ships QuasarSVM in-process tests that invoke the instruction handlers and
29+
assert onchain state, with no local validator.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial order-book program: an onchain central limit order book (CLOB) for a single base/quote token pair.
6+
7+
- One `Market` PDA per base/quote pair, seeded `["market", base_mint, quote_mint]`, holding fee rate, tick size, minimum order size, the vault and order-book addresses, and the authority allowed to withdraw fees.
8+
- An `OrderBook` account (a client-allocated keypair account, not a PDA, since ~180 KB exceeds the inner-CPI allocation limit) with two critbit trees, bids highest-first and asks lowest-first, up to 1024 leaves each.
9+
- Per-`(market, wallet)` `MarketUser` PDAs tracking `open_orders` (capped at 20) plus `unsettled_base` / `unsettled_quote` counters, and per-order `Order` PDAs seeded `["order", market, order_id]`.
10+
- Six instruction handlers: `initialize_market`, `create_market_user`, `place_order`, `cancel_order`, `settle_funds`, and `withdraw_fees`.
11+
- `place_order` locks funds up front, plans then applies fills against the maker pairs passed in remaining accounts, matches in price-time priority, and rests any remainder on the book.
12+
- Fills clear at the resting maker's price, so a taker whose limit is better is refunded the difference as price improvement into `unsettled_quote`.
13+
- Matching and settlement are split: fills only credit `unsettled_*` counters, and users later call `settle_funds` to withdraw, so a taker crossing many makers avoids a token CPI per maker.
14+
- Taker fees are `ceil(gross * fee_bps / 10_000)` per fill, batched into `fee_vault` in one CPI and rounded in the protocol's favor.
15+
- Money math throughout uses `checked_mul` / `checked_add` with `u64` products computed in `u128` and narrowed via `try_into`, erroring `NumericalOverflow`; a per-fill invariant enforces `fee_quote <= gross_quote`.
16+
- The three token vaults are authority = Market PDA, so only the program can move funds out; `place_order` and `withdraw_fees` bind the vaults and mints to the market's stored addresses with `has_one`.
17+
- The market authority can only drain `fee_vault` via `withdraw_fees` (`NotMarketAuthority`); there is no path for any signer to withdraw user balances.
18+
- `settle_funds` zeroes the `unsettled_*` counters before the transfer CPIs (checks-effects-interactions), so no transfer hook can observe stale balances and double-withdraw.
19+
- `cancel_order` is accounting-only: it credits the locked remainder back to `unsettled_*` and removes the order from the book, with tokens moving on the next `settle_funds`.
20+
- Ships Rust + LiteSVM integration tests covering placement, matching, price improvement, partial fills, cancel/settle round trips, fee accounting, and authorization.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial Quasar port of the order-book program: an onchain central limit order book (CLOB) for a single base/quote token pair.
6+
7+
- Port of the Anchor example, sharing the same program ID (`C69UJ8irfmHq5ysyLek7FKApHR86FBeupiz4JnoyPzzx`), so offchain tooling and PDA derivations work against either build unchanged.
8+
- One `Market` PDA per base/quote pair whose PDA is the token authority of the `base_vault`, `quote_vault`, and `fee_vault`; a keypair-account `OrderBook` holding two critbit slabs; per-user `MarketUser` PDAs and per-order `Order` PDAs.
9+
- Six instruction handlers: `initialize_market`, `create_market_user`, `place_order`, `cancel_order`, `settle_funds`, and `withdraw_fees`.
10+
- `place_order` locks funds, crosses the opposing side in price-time priority against the `(maker_order, maker_market_user)` pairs passed as remaining accounts, credits fills to maker/taker `unsettled_*`, routes the taker fee, and rests any remainder.
11+
- Fills clear at the maker's price with taker price improvement, and matching and settlement are split so fills only credit counters that users later drain via `settle_funds`, keeping no maker ATAs in the fill path.
12+
- A two-lot pricing model (`base_lot_size`, `quote_lot_size`) denominates both sides in lots so `price` and `quantity` read as human numbers regardless of each mint's decimals.
13+
- Taker fees use ceiling division rounding in the protocol's favor, batched into `fee_vault`.
14+
- The critbit matching engine, packing a 128-bit `[price][seq_num]` key for best-price-first in-order walks with time priority, is ported near-verbatim from openbook-v2.
15+
- Quasar-specific: the order book is accessed by casting raw account bytes to `&mut OrderBook` with `bytemuck` (guarded by an 8-byte discriminator) rather than Anchor's `AccountLoader`.
16+
- Quasar-specific: `MarketUser.open_orders` is a fixed `[u8; 160]` (20 packed u64s) plus a length instead of a borsh `Vec<u64>`, keeping every mutation an in-place write.
17+
- Quasar-specific: the slab is heap-free with a fixed traversal stack, a single `place_order` crosses at most `MAX_FILLS` (16) resting orders, and `side` and order status/side enums are stored as `u8` whose encodings match the Anchor build's borsh discriminants.
18+
- Every vault transfer out is signed by the market PDA via `invoke_signed`; `place_order` binds every market-owned account with `has_one`, and `settle_funds` zeroes `unsettled_*` before transferring (checks-effects-interactions).
19+
- Ships QuasarSVM integration tests (`src/tests.rs`) driving the full lifecycle (initialize, create users, rest an ask, cross with a bid, settle both sides, withdraw the fee) plus an authorization rejection, loading the compiled `.so`.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial perpetual-futures exchange: an oracle-priced, pool-collateralized venue for leveraged long/short bets, modelled on Jupiter Perpetuals and GMX.
6+
7+
- One shared liquidity pool is the counterparty to every trade: providers fund it with `add_liquidity` for shares and redeem with `remove_liquidity`, and the pool pays trader profits and keeps their losses.
8+
- Single-collateral USDC pool tracking one oracle price feed, created by `initialize_pool` with a `Pool` PDA, a `pool_authority` signer PDA, a `custody_vault` token account, and an `lp_mint` share mint.
9+
- Provider shares are priced against mark-to-market assets-under-management derived from running per-side accumulators, so no handler's cost grows with the number of open positions; the first deposit mints `deposit - MINIMUM_LIQUIDITY` shares (Uniswap V2 convention).
10+
- `open_position` takes a side, collateral, and size up to the pool's max leverage; profit/loss is notional times the percentage price change.
11+
- Reserved liquidity backs each open position's maximum recoverable profit: an open is allowed only while `reserved + size <= liquidity` (which doubles as an open-interest cap), and provider withdrawals can pull only the free remainder.
12+
- `close_position` caps a winner's payout at the reserved `size` and fails closed (reverts) rather than pay out more than the pool can cover.
13+
- Funding accrues from the heavier side of open interest via a cumulative funding index advancing `funding_rate_per_slot` each slot; a position records the index at open and settles the change at close.
14+
- Permissionless `liquidate_position` closes a position once equity falls to or below the `maintenance_margin_bps` maintenance margin, paying the cranker the liquidation fee from remaining equity.
15+
- Oracle prices are validated for staleness by slot, positivity, scale, and a confidence band within `max_confidence_bps`; every position and liquidity action reads a fresh oracle and rejects stale or wide-confidence prices.
16+
- Open/close fees are charged in basis points of notional and accrue to `protocol_fees`, which the admin sweeps with `collect_fees`; every state-changing handler takes a slippage bound and reverts if breached.
17+
- All money math is integer `u128` with `checked_*` operations, multiplying before dividing and rounding in the pool's favour: no floats and no fixed-point library.
18+
- Ships a test-only `mock-switchboard` program storing a price, scale, last-update slot, and confidence band, standing in for a real Switchboard On-Demand feed.
19+
- Rust + LiteSVM integration tests deploy both programs and cover liquidity round-trips, longs and shorts in profit and loss, leverage and slippage rejection, stale-price and wide-confidence rejection, funding accrual, liquidation (and refusal to liquidate a healthy position), reserved-liquidity behaviour, and fee collection.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Changelog
2+
3+
## 0.1.0
4+
5+
Initial Quasar port of the perpetual-futures exchange, matching the Anchor version's oracle-priced, pool-collateralized design, math, and behaviour.
6+
7+
- One shared liquidity pool as counterparty to every trade, with provider shares priced against mark-to-market assets-under-management from per-side accumulators, reserved-liquidity payout backing, slot-indexed funding, permissionless liquidation, and oracle staleness/positivity/confidence validation, all carried over from the Anchor implementation.
8+
- All money math is integer `u128` with `checked_*` operations, multiplying before dividing and rounding in the pool's favour.
9+
- One position per trader per pool: Quasar's `address` constraint can only reference account inputs, not instruction arguments, so the side cannot be a seed; the position PDA is `[b"position", pool, owner]` and the side is stored in the account (the Anchor version seeds by side, `[b"position", pool, owner, side]`, allowing a simultaneous long and short).
10+
- No separate mock-oracle program: tests write the feed account's bytes directly (price, scale, last-update slot) and the program reads them the same way it would read a real Switchboard feed.
11+
- State writes use Quasar's zero-copy field accessors (`field.get()` / `field.set()`) and `set_inner` rather than Anchor's `Account` mutation.
12+
- Ships in-process QuasarSVM (`quasar-svm`) tests covering pool initialization, liquidity add/remove, opening and closing a long in profit, leverage rejection, liquidation, and fee collection.

0 commit comments

Comments
 (0)