feat(tokens/hackathon): Anchor 1.0 hackathon prize program with Squads multisig committee#21
Closed
mikemaccana wants to merge 2 commits into
Closed
feat(tokens/hackathon): Anchor 1.0 hackathon prize program with Squads multisig committee#21mikemaccana wants to merge 2 commits into
mikemaccana wants to merge 2 commits into
Conversation
added 2 commits
May 13, 2026 21:43
A new Anchor 1.0 example: a hackathon prize program whose authority is an external Squads multisig vault PDA. The on-chain program is multisig-agnostic - it stores an opaque `authority` pubkey and checks `signer == authority` on each privileged handler. Squads handles propose/vote/execute off-program. Instruction handlers: - create_hackathon: open a hackathon under `authority` - add_prize: register a prize with its own mint and vault ATA - set_winner: record the winning pubkey for a prize (multisig) - pay_winner: transfer exactly `prize.amount` to the recorded winner. Unpermissioned: anyone can call once the winner is set and the vault is funded. - cancel_prize: drain the vault back to a refund target and lock the prize (multisig) - close_hackathon: refund Hackathon rent once every prize is paid or cancelled (multisig) Uses the SPL Token Interface throughout so the same compiled program works for both classic SPL Token and Token-2022 mints. Per-prize mint and per-prize vault PDA so one hackathon can mix denominations and surface a clean PDA-derivation pattern. This commit is program code + smoke build only; LiteSVM tests with a real Squads 2-of-3 (Alice/Bob/Carol) committee follow in the next commit.
Integration tests build a real Squads v4 multisig (Alice/Bob/Carol,
threshold 2-of-3) inside LiteSVM and drive the hackathon program end-to-end
through the propose / vote / execute flow.
Coverage (9 tests total):
- happy path: create_hackathon -> add_prize -> fund -> set_winner (via
multisig vote) -> pay_winner (signed by an unrelated bystander wallet).
Asserts the winner's token balance equals prize.amount.
- pay_winner failure cases: no winner set, vault under-funded, already
paid.
- set_winner failure case: non-multisig signer rejected by Anchor's
has_one = authority constraint.
- cancel_prize: drains a funded vault to a refund target, closes the
vault, locks the prize against future pay_winner.
- close_hackathon: succeeds once every prize is paid or cancelled; fails
while any prize is still active.
Implementation notes:
- Squads on-chain program is vendored as a 1.5 MB .so fixture dumped from
mainnet (SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf). The README has
the refresh command.
- The Squads SDK crates (squads-multisig, squads-multisig-program) pull
in solana-client 1.17, which conflicts with the Anchor 1.0 / Solana 3.x
stack on zeroize. Instead, instruction builders are hand-rolled in
tests/common/squads.rs: Anchor 8-byte discriminators (sha256("global:
<name>")[..8]), Borsh args, plus the SmallVec<u8, T> wire format used
by the compiled-message TransactionMessage struct.
- The Squads ProgramConfig account (which would normally be initialised
by a Squads admin instruction we cannot run) is forged directly into
LiteSVM via set_account with multisig_creation_fee = 0.
Also adds the README and bumps Cargo.toml with the sha2 dev-dependency
used by the Squads helper module.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
tokens/hackathon/anchor/— an Anchor 1.0 program for running ahackathon prize pool where a Squads multisig committee controls prize
creation and award decisions, but anyone can trigger the actual on-chain
payment once a winner is recorded.
The program is multisig-agnostic: it stores a single
authority: Pubkeyper hackathon and checks
signer == authorityon privileged handlers. Inpractice that pubkey is a Squads v4 vault PDA, but you could swap in any
other multisig without touching the program.
Instruction handlers
create_hackathonHackathonunderauthority.add_prizePrizewith its own mint and a new vault ATA.set_winnerpay_winnerprize.amountto the winner's token account.cancel_prizeclose_hackathonHackathonrent once every prize is paid or cancelled.pay_winnerbeing permissionless is deliberate. Once the committee hasvoted, anyone — the winner, a bot, an organiser's intern — can submit the
payout transaction.
Tests
LiteSVM-based Rust integration tests build a real Squads v4 2-of-3
multisig (Alice / Bob / Carol) and drive the program end-to-end through
Squads' propose / vote / execute flow. 9 tests, all green:
multisig vote) → pay_winner (signed by an unrelated bystander wallet).
Asserts winner balance equals
prize.amount.pay_winnerrejects when no winner is set,vault is under-funded, or prize is already paid.
set_winnerrejects anon-multisig signer.
cancel_prizedrains a funded vault and locks theprize.
close_hackathonsucceeds once every prize is resolved, failswhile any prize is still active.
Squads integration notes
.sofixture atprograms/hackathon/tests/fixtures/squads_multisig.so, dumped frommainnet (
SQDS4ep65T869zMMBKyuUq6aD6EgTu8psMjkvj52pCf). The README hasthe refresh command. The repo's top-level
.gitignorealreadywhitelists
**/tests/fixtures/*.so.squads-multisigSDK crate — it pulls insolana-client 1.17, which conflicts with the Anchor 1.0 / Solana 3.xstack on
zeroize. Instead, instruction builders are hand-rolled intests/common/squads.rs(Anchor 8-byte discriminators + Borsh args +the
SmallVec<u8, T>wire format used by the compiled-messageTransactionMessagestruct).ProgramConfigaccount (normally written by a Squads admininstruction we cannot run from a test fixture) is forged directly into
LiteSVM with
multisig_creation_fee = 0.Files
Build & run
cargo build-sbfmust run first because the integration tests load thecompiled program
.soviainclude_bytes!.Stack
anchor-lang = "1.0.0",anchor-spl = "1.0.0"litesvm = "0.11.0",solana-kite = "0.3.0"Token-2022 mints; the choice is per-prize at
add_prizetime.Compiled program is 336 KB.