SkillStake is a Solana commitment staking dApp built with Anchor and React. A user escrows SOL into a stake PDA together with a goal, deadline, and validator wallet. The validator can resolve the commitment on or before the deadline:
complete_stake: returns the locked SOL to the creatorfail_stake: sends the locked SOL to the configured treasury wallet
The repo includes:
- an Anchor program in
programs/commitment-stake/src/lib.rs - Anchor integration tests in
tests/commitment-stake.ts - a Vite + React frontend in
app - GitHub Actions for CI and GitHub Pages deployment in
.github/workflows
See CONTRIBUTING.md for local setup and INTERVIEW.md for talking points to discuss in interviews.
Each stake is a PDA derived from:
["stake", creator_pubkey, stake_id_le_bytes]
The stake_id is generated in the frontend, which lets the same wallet create multiple commitments without collisions.
StakeAccount stores:
goaldeadlinevalidatortreasuryamountcreatorcreated_atstatus
When a stake is created, the program initializes the PDA and transfers the staked SOL from the creator into that PDA. When the validator resolves the stake, the locked amount is moved to the creator or treasury, and the PDA closes back to the creator.
.
├── Anchor.toml
├── Cargo.toml
├── programs/commitment-stake
├── tests
├── app
└── .github/workflows
- Rust stable
- Solana CLI
- Anchor CLI
- Node.js 20+
- A wallet at
~/.config/solana/id.jsonfor local Anchor commands
Helpful installs:
cargo install --git https://github.com/coral-xyz/anchor avm --locked --force
avm install latest
avm use latest
sh -c "$(curl -sSfL https://release.solana.com/stable/install)"- Install JavaScript dependencies:
npm install- Build the program:
npm run anchor:build- If you are deploying with a new program key, sync the generated program ID:
anchor keys list
anchor keys sync- Start a local validator in a separate terminal:
solana-test-validator- Run the test suite:
npm run anchor:testCopy the example env file and fill in your network values:
cp app/.env.example app/.envRecommended app/.env for devnet:
VITE_SOLANA_RPC_URL=https://api.devnet.solana.com
VITE_PROGRAM_ID=YOUR_DEPLOYED_PROGRAM_ID
VITE_TREASURY_WALLET=YOUR_DEVNET_TREASURY_PUBKEY
VITE_NETWORK=devnet
VITE_BASE_PATH=/Run the frontend locally:
npm run app:devBuild the frontend:
npm run app:buildBuild and serve the frontend in a container:
docker build --tag skillstake-frontend ./appRun the container on port 8080:
docker run --rm -p 8080:80 skillstake-frontendOpen http://localhost:8080 in your browser.
If you want to build with custom env values, pass build args:
docker build \
--build-arg VITE_PROGRAM_ID=YOUR_PROGRAM_ID \
--build-arg VITE_SOLANA_RPC_URL=https://api.devnet.solana.com \
--build-arg VITE_TREASURY_WALLET=YOUR_TREASURY_PUBKEY \
--build-arg VITE_NETWORK=devnet \
--build-arg VITE_BASE_PATH=/ \
--tag skillstake-frontend ./appUse Docker Compose to build and run the app with a single command:
docker compose up --buildThen open http://localhost:8080.
anchor deploy- Switch Solana CLI:
solana config set --url devnet- Fund your deployer:
solana airdrop 2- Update
Anchor.tomlprovider cluster if needed, then deploy:
anchor deploy --provider.cluster devnet- Put the deployed program ID into
app/.env.
This repo is set up for GitHub Pages deployment of the React app.
git init
git add .
git commit -m "Initial SkillStake dApp"
git branch -M main
git remote add origin <your-repo-url>
git push -u origin main- In GitHub, open
Settings -> Pages - Set the source to
GitHub Actions
In Settings -> Secrets and variables -> Actions -> Variables, add:
VITE_PROGRAM_IDVITE_SOLANA_RPC_URLVITE_TREASURY_WALLETVITE_NETWORK
The workflow automatically sets:
VITE_BASE_PATH=/<repo-name>/
The workflow in .github/workflows/deploy-pages.yml builds app/dist and deploys it to GitHub Pages.
- creator enters goal, validator pubkey, deadline, and SOL amount
- frontend generates a
stake_idand derives the stake PDA - Anchor creates the stake account and transfers SOL into it
- validator signs
complete_stake - program checks that the signer matches the stake validator
- locked SOL is returned to creator
- validator signs
fail_stake - program checks the validator and treasury
- locked SOL is moved to treasury
- validators can only resolve a stake while it is still pending
- resolution must happen on or before the stored deadline
- a failed stake can only send funds to the treasury originally stored on creation
- rent is returned to the creator when the stake PDA closes
- add an admin-owned global config PDA for treasury management
- add index filtering by creator and validator on-chain
- emit events for easier analytics and notification services
- add support for automatic failure after deadline through an external crank service
- The placeholder program ID in this repo is the standard Anchor default until you deploy your own program.
- The frontend uses the checked-in IDL at
app/src/idl/commitment_stake.json. After changing program interfaces, rebuild and update the frontend copy.