Inspiration
Every semester, universities allocate funds to student clubs, and FSO (funded student organizations) money comes with strings attached. It can go toward event supplies, venue rentals, food for meetings, or travel, but not toward personal expenses or anything off the approved list.
Today those rules are enforced by trust and paperwork: purchase requests, receipts, reimbursements, and after-the-fact review. Treasurers spend hours on forms, administrators spend hours checking them, and a misuse is only caught once the money is already gone.
We asked: what if the funds themselves only worked where the rules allow? Instead of checking a receipt after the fact, the money simply refuses to go to the wrong place.
What it does
CashRules is a token that carries its own spending rules. A university (the issuer) allocates funds to a club (the grantee), and the club can only spend them at approved vendors, in approved categories, within per-payment and daily limits.
For example, a club receives 500 CashRules for the semester:
- Pizza for a general meeting, an approved food vendor: goes through
- Printing posters at the campus print shop, an approved vendor: goes through
- A payment to a casino or a personal wallet: blocked on-chain
Every CashRules is backed 1:1 by USDC in a vault. Every transfer is checked against four rules:
- The recipient is an approved, active merchant.
- The merchant's category is allowed by the grant.
- The amount is within that merchant's per-payment cap.
- The club's spending today stays within the daily cap (resets at midnight UTC).
In short, a payment succeeds only if all four of these hold:
vendor is active AND category is allowed AND amount <= vendor cap AND spent today + amount <= daily cap
The vault rule is just as simple: the total CashRules supply always equals the USDC held in the vault, and anyone can check it on the dashboard.
Clubs also have needs that don't fit a policy perfectly, so we built exception requests. A club treasurer can ask for an out-of-policy payment and explain why. The funds move into the university's escrow, and the administrator approves (the vendor is paid) or rejects (the club is charged). That replaces the email thread with something transparent and on-chain.
The web app has four pages:
- Dashboard: total supply, vault backing, approved vendors, and a live feed of paid, blocked and funded transactions
- Pay: a club pays an approved vendor and sees its daily cap left
- Merchant: vendors see their approval status and redeem CashRules for USDC
- Issuer: the university approves or pauses vendors, sets categories and caps, funds clubs, and decides exception requests
How we built it
- On-chain program: Anchor (Rust) on Solana devnet. It stores the grant (the policy), the approved vendors, and per-club daily spend counters.
- Token-2022 transfer hook: runs on every transfer and reverts it if a rule fails. The CashRules mint authority is the grant itself, so no one can mint outside the vault.
- Vault:
deposit_and_mintlocks USDC and mints CashRules 1:1.redeemlets an approved vendor burn CashRules and take USDC back. - Web app: four static pages, no server, deployed to GitHub Pages with a GitHub Actions workflow.
- Scripts and tests: a seed script builds the demo state, a demo-activity script sends one good payment and three rejected ones, and a smoke test runs every write path end to end. The Anchor suite has 15 passing test cases.
Challenges we ran into
- Wallets protect users from failing transactions. Phantom simulates each transaction before you approve it, so a payment that will be blocked (like one to the casino) can trigger a "likely to fail" warning, and Phantom may refuse to sign it. We built a fallback script that sends the same blocked transactions without a wallet so the feed still shows them.
- Testing without leaking keys. We wrote a local signer that holds the demo keys on
127.0.0.1and a browser stand-in for Phantom that asks it to sign, so no key ever goes into the page. - Public RPC limits. Devnet's public endpoint rate-limits bursts, and the dashboard can go blank under load. A dedicated RPC fixes this.
- Designing exceptions fairly. Clubs sometimes have legitimate needs the policy didn't anticipate. Escrow lets an administrator review them, but the administrator controls those funds, and a rejection means the club is charged. We had to be honest about the trust that implies.
Accomplishments that we're proud of
- The rule is enforced by the token itself. A transfer to a non-approved wallet fails the same way as a transfer to the casino.
- Every payment, every block (with a reason such as
CategoryBlockedorOverTxCap) and every administrator decision is public, so a university sees misuse attempts as they happen instead of at audit time. - The full flow works end to end in the browser: pay, get blocked, request an exception, approve it.
What we learned
- How Token-2022 transfer hooks work and how to design rules that run inside a token transfer.
- How to model a funding policy on-chain with grants, vendor records and per-day counters.
- That wallet UX matters: a correct on-chain rejection can still look like a failure to the user unless you plan for it.
- How to be upfront about trust. The issuer key is powerful, so a real deployment needs a multisig or a governance process.
Beyond clubs
The same design fits other restricted funds: grants and DAO treasuries, company per-diems and expense budgets, allowances, and vendor payments with guardrails. Student clubs are our starting point because the problem is so familiar to anyone who has been a club treasurer.
Honest limits
- Devnet only, no real money.
- The demo uses a Token-2022 mock standing in for USDC. Real USDC is a classic-token mint, and that path isn't tested.
- Not audited.
- A single issuer key can change policy, so real use needs a multisig or governance.
- There are no identity checks. KYC is outside this project.
What's next for CashRules
- Solana Pay QR codes so clubs can pay vendors by scanning
- Blinks, so administrators can approve exceptions from a chat link
- A dedicated RPC
- A stats page
- A multisig or governance for the issuer role
- A security audit
Built With
- anchor
- html
- javascript
- next.js
- react
- rust
- solana
- solanacli
- token-2022
- typescript