stake-tokens
Stake tokens to earn yield by locking assets in a staking contract (EVM) or delegating SOL to a validator (Solana).
evmsolana
Dependencies
viem@solana/web3.js
stake-tokens/evm.tsx
/**
* stake-tokens/evm.tsx
* Generic EVM staking pattern: approve token → call stake(amount) on staking contract.
* Replace STAKING_ADDRESS and STAKING_ABI with your target protocol.
*/
import { useState } from "react";
import {
useAccount,
useWriteContract,
useReadContract,
useWaitForTransactionReceipt,
} from "wagmi";
import { parseUnits, formatUnits } from "viem";
const TOKEN_ADDRESS = "0xTOKEN" as `0x${string}`;
const STAKING_ADDRESS = "0xSTAKING" as `0x${string}`;
const DECIMALS = 18;
const ERC20_ABI = [
{ name: "approve", type: "function", stateMutability: "nonpayable",
inputs: [{ name: "spender", type: "address" }, { name: "amount", type: "uint256" }],
outputs: [{ type: "bool" }] },
] as const;
const STAKING_ABI = [
{ name: "stake", type: "function", stateMutability: "nonpayable",
inputs: [{ name: "amount", type: "uint256" }], outputs: [] },
{ name: "stakedBalance", type: "function", stateMutability: "view",
inputs: [{ name: "account", type: "address" }],
outputs: [{ type: "uint256" }] },
] as const;
export function useStakeTokens() {
const { address } = useAccount();
const [amount, setAmount] = useState("");
const { data: stakedBalance } = useReadContract({
address: STAKING_ADDRESS,
abi: STAKING_ABI,
functionName: "stakedBalance",
args: address ? [address] : undefined,
query: { enabled: !!address },
});
const { writeContract: approve, data: approveTxHash } = useWriteContract();
const { isSuccess: approved } = useWaitForTransactionReceipt({ hash: approveTxHash });
const { writeContract: stake, data: stakeTxHash } = useWriteContract();
const { isSuccess: staked, isLoading: staking } =
useWaitForTransactionReceipt({ hash: stakeTxHash });
function handleApprove() {
approve({ address: TOKEN_ADDRESS, abi: ERC20_ABI, functionName: "approve",
args: [STAKING_ADDRESS, parseUnits(amount, DECIMALS)] });
}
function handleStake() {
stake({ address: STAKING_ADDRESS, abi: STAKING_ABI, functionName: "stake",
args: [parseUnits(amount, DECIMALS)] });
}
return {
amount, setAmount,
stakedBalance: stakedBalance ? formatUnits(stakedBalance, DECIMALS) : "0",
handleApprove, approved,
handleStake, staking, staked,
};
}Learn: Staking
Proof-of-Stake basics
PoS networks (Ethereum, Solana) select validators proportional to their stake. Validators earn block rewards and fees; delegators share in those rewards.
Native vs liquid vs DeFi staking
| Type | Example | Tradeoff |
|---|---|---|
| Native | SOL delegation, ETH solo validator | Full rewards, illiquid |
| Liquid | stSOL (Marinade), stETH (Lido) | Tradeable LST, small fee |
| DeFi | Synthetix SNX, Curve CRV | Token emissions, smart contract risk |
APY vs APR
- APR (Annual Percentage Rate): simple interest, no compounding.
- APY (Annual Percentage Yield): includes compounding effect.
- Most DeFi UIs show APY. Native staking usually shows APR.
- Formula:
APY = (1 + APR/n)^n − 1where n = compounding periods/year.
Epoch-based vs continuous rewards
- Solana: rewards distributed once per epoch (~2 days). Stake must be active (not in warmup) to earn for that epoch.
- EVM protocols: vary — some accrue per block, others require manual
claim.
Slashing risks
- EVM: protocol-specific; some have no slashing, others slash for inactivity or double-signing.
- Solana native: validators can be slashed for double-voting; rare in practice.
- Liquid staking: slashing risk is socialised across all LST holders.
Unbonding / cooldown
Always read the protocol docs for cooldown periods before staking. Some EVM protocols have multi-day withdrawal queues. Solana native stake takes ~1 epoch to deactivate before funds can be withdrawn.
Key takeaway
Staking is not risk-free. Understand lock-up, slashing exposure, and whether you're earning in a volatile token before committing capital.