
Cause Pots sample
MobileA sample collaborative savings app with time-locked, multi-signature pots, built with Expo, React Native, Solana Kit, Anchor, and Uniwind.
Get started
npx solana-mobile create --template gh:solana-mobile/templates/mobile/sample-expo-kit-cause-potssample-expo-kit-cause-pots
Cause Pots is a sample, not a template: a complete reference app to read, run, and copy the parts you need. Templates in this repository are starting points; this app shows what a finished feature set looks like on the expo-kit-anchor stack — collaborative savings pots on Solana, where contributors pool SOL into a shared vault that stays time-locked until enough of them sign off on releasing it.
Features
- Time-locked collaborative savings pots with an on-chain vault per pot
- Multi-signature release approval (M-of-N contributors)
- SOL amounts with an optional USD display currency (chain transfers are always SOL)
- Friend management by wallet address or
.skrdomain, resolved on mainnet with@solana-mobile/skr-domain - Activity feed derived entirely from on-chain transaction history — no backend anywhere
Technologies
- Anchor (Solana program framework)
- Expo
- Uniwind (Tailwind CSS for React Native)
- @solana/kit
- @wallet-ui/react-native-kit
Get started
Install dependencies
npm installStart the app
This step builds the dependencies for the development client.
npm run android
The app connects to devnet by default, where the program is already deployed — you don't need the Rust toolchain to run it. Your wallet needs a small amount of devnet SOL for pot accounts and transaction fees; get some at faucet.solana.com.
The Anchor program
The anchor directory contains the cause_pots program, deployed on devnet at EvUrRjL2ZowK58ai87ztHmVXyTRNvGb6HCWQ2Feo9bNN. Five instructions cover the whole lifecycle:
| Instruction | Behavior |
|---|---|
create_pot |
Creates the pot and its vault PDA; sets the target amount, unlock time, and signature threshold |
add_contributor |
Adds a wallet to the pot's contributor list (pot authority only) |
contribute |
Transfers SOL into the vault and tracks totals in a per-contributor account |
sign_release |
Records one contributor's approval for release, once the unlock time has passed |
release_funds |
Transfers the vault balance to a recipient once the signature threshold is met (pot authority only) |
PDA seeds:
- Pot:
["pot", authority, name] - Vault:
["vault", pot] - Contributor:
["contributor", pot, contributor]
Rules enforced on-chain:
- The unlock time derives from
Clock::get(), never from a client-supplied timestamp sign_releaserejects non-contributors, double-signing, and signing before the unlock timerelease_fundsrejects until the unlock time has passed and the signature count meets the threshold- Signatures approve the release itself, not a destination: the pot authority picks the recipient at release time, so contributors trust the authority with the payout — the same model as the original app
Working on the program requires the Rust, Solana, and Anchor toolchains.
Generate a program keypair and sync the program ID
This generates your own keypair, syncs it into
Anchor.tomlanddeclare_id!, rebuilds the program so the IDL carries the new address, and regenerates the TypeScript client from it:npm run anchor:setupBuild and test the program
npm run anchor:testThis builds the program, spins up a local validator, deploys, and runs the Vitest tests in
anchor/tests, including the rejection paths: releasing before the unlock time, releasing below the signature threshold, and signing twice.Deploy your own instance to devnet
npm run anchor:deploy:devnet
The generated TypeScript client
The app talks to the program through a fully typed client generated by Codama from the program's IDL. It lives in anchor/src/client/js/generated and only depends on @solana/kit. Import it anywhere in the app via the @project/anchor alias:
import { fetchPot, findPotPda, getContributeInstructionAsync } from '@project/anchor'
After changing the program, rebuild the IDL and regenerate the client:
npm run anchor:build
npm run codama:js
Add hand-written wrappers around the generated code in anchor/src/client/js/index.ts — the generated directory is overwritten on every run.
How the app is put together
Everything the original three-tier version of this app kept on a server lives on chain or on the device here:
- Pots (
src/features/pots) are read straight from the chain: the list is agetProgramAccountsscan decoded with the generated client (use-pots-query.ts), and every write is a generated instruction builder sent through Mobile Wallet Adapter (use-pot-program.ts). Pot metadata like the category and display currency are fields on the pot account. - Friends (
src/features/friends) are a local address book inexpo-sqlite's key-value store. Adding a friend by.skrdomain resolves it on mainnet with@solana-mobile/skr-domain(src/features/domains/resolve-address-or-domain.ts), and friends and pot contributors show a wallet's primary.skrname in place of its address when it has one. - Activity (
src/features/activity) is reconstructed from each pot's transaction history:getSignaturesForAddressgives the timeline and the generatedidentifyCausePotsInstructionand instruction data decoders identify what happened in each transaction. - USD display (
src/features/price) converts at the current CoinGecko rate. Contributions always move SOL on chain; a pot created in USD only renders its amounts differently.
Develop against localnet
For a faster loop you can run everything against a local validator, forwarded to your device over adb:
- Start the localnet and keep it running:
npx solana-mobile localnet - Deploy the program to it:
npm run anchor:deploy:localnet - Switch the network to Localnet with the selector in the app
- Connect your wallet and tap Request Airdrop to fund it
Two things to know: localnet needs a debug build — npm run android makes one, and Android debug builds allow the cleartext http://localhost endpoint while release builds only talk HTTPS. And the regular Seeker wallet only signs for public clusters, so signing on localnet requires a localnet-capable wallet such as fakewallet.
Learn more
To learn more about developing your project with Expo, look at the following resources:
- Expo documentation: Learn fundamentals, or go into advanced topics with our guides.
- Uniwind documentation: Learn how to style your app with Tailwind CSS.
- Anchor documentation: Learn how to build Solana programs with Anchor.
- Solana documentation: Learn how to build on Solana.