├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── components ├── Header.js ├── StakeDetails.js └── StakeForm.js ├── constants ├── index.js ├── rewardTokenAbi.json └── stakingAbi.json ├── next.config.js ├── package.json ├── pages ├── _app.js ├── api │ └── hello.js └── index.js ├── postcss.config.js ├── public ├── favicon.ico └── vercel.svg ├── styles ├── Home.module.css └── globals.css ├── tailwind.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | artifacts 3 | cache 4 | coverage* 5 | gasReporterOutput.json 6 | package.json 7 | img 8 | .env 9 | .* 10 | README.md 11 | coverage.json 12 | deployments 13 | .next -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "useTabs": false, 4 | "semi": false, 5 | "singleQuote": false, 6 | "printWidth": 99 7 | } 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | ## Learn More 22 | 23 | To learn more about Next.js, take a look at the following resources: 24 | 25 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 26 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 27 | 28 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 29 | 30 | ## Deploy on Vercel 31 | 32 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 33 | 34 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 35 | -------------------------------------------------------------------------------- /components/Header.js: -------------------------------------------------------------------------------- 1 | import { ConnectButton } from "web3uikit" 2 | 3 | export default function Header() { 4 | return ( 5 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /components/StakeDetails.js: -------------------------------------------------------------------------------- 1 | // how many tokens are in our wallet 2 | // how many tokens are staked 3 | // how many tokens we have earned 4 | import { useMoralis, useWeb3Contract } from "react-moralis" 5 | import { stakingAddress, stakingAbi, rewardTokenAbi, rewardTokenAddress } from "../constants" 6 | import { useState, useEffect } from "react" 7 | import { ethers } from "ethers" 8 | 9 | export default function StakeDetails() { 10 | const { account, isWeb3Enabled } = useMoralis() 11 | const [rtBalance, setRtBalance] = useState("0") 12 | const [stakedBalance, setStakedBalance] = useState("0") 13 | const [earnedBalance, setEarned] = useState("0") 14 | 15 | const { runContractFunction: getRtBalance } = useWeb3Contract({ 16 | abi: rewardTokenAbi, 17 | contractAddress: rewardTokenAddress, 18 | functionName: "balanceOf", 19 | params: { 20 | account: account, 21 | }, 22 | }) 23 | 24 | const { runContractFunction: getStakedBalance } = useWeb3Contract({ 25 | abi: stakingAbi, 26 | contractAddress: stakingAddress, 27 | functionName: "getStaked", 28 | params: { 29 | account: account, 30 | }, 31 | }) 32 | 33 | const { runContractFunction: getEarned } = useWeb3Contract({ 34 | abi: stakingAbi, 35 | contractAddress: stakingAddress, 36 | functionName: "earned", 37 | params: { 38 | account: account, 39 | }, 40 | }) 41 | 42 | useEffect(() => { 43 | // update the UI and get balances 44 | if (isWeb3Enabled && account) { 45 | updateUiValues() 46 | } 47 | }, [account, isWeb3Enabled]) 48 | 49 | async function updateUiValues() { 50 | const rtBalanceFromContract = ( 51 | await getRtBalance({ onError: (error) => console.log(error) }) 52 | ).toString() 53 | const formatttedRtBalanceFromContract = ethers.utils.formatUnits( 54 | rtBalanceFromContract, 55 | "ether" 56 | ) 57 | setRtBalance(formatttedRtBalanceFromContract) 58 | 59 | const stakedFromContract = ( 60 | await getStakedBalance({ onError: (error) => console.log(error) }) 61 | ).toString() 62 | const formatttedstakedFromContract = ethers.utils.formatUnits(stakedFromContract, "ether") 63 | setStakedBalance(formatttedstakedFromContract) 64 | 65 | const earnedFromContract = ( 66 | await getEarned({ onError: (error) => console.log(error) }) 67 | ).toString() 68 | 69 | console.log(`Earned: ${earnedFromContract}`) 70 | 71 | const formatttedEarnedFromContract = ethers.utils.formatUnits(earnedFromContract, "ether") 72 | setEarned(formatttedEarnedFromContract) 73 | } 74 | 75 | return ( 76 |
77 |
RT Balance is: {rtBalance}
78 |
Earned Balance is: {earnedBalance}
79 |
Staked Balance is: {stakedBalance}
80 |
81 | ) 82 | } 83 | -------------------------------------------------------------------------------- /components/StakeForm.js: -------------------------------------------------------------------------------- 1 | // staking abi 2 | // staking address 3 | // how much they want to stake 4 | // approve our reward token 5 | import { useWeb3Contract } from "react-moralis" 6 | import { rewardTokenAbi, rewardTokenAddress, stakingAbi, stakingAddress } from "../constants" 7 | import { Form } from "web3uikit" 8 | import { ethers } from "ethers" 9 | 10 | export default function StakeForm() { 11 | const { runContractFunction } = useWeb3Contract() 12 | let approveOptions = { 13 | abi: rewardTokenAbi, 14 | contractAddress: rewardTokenAddress, 15 | functionName: "approve", 16 | } 17 | let stakeOptions = { 18 | abi: stakingAbi, 19 | contractAddress: stakingAddress, 20 | functionName: "stake", 21 | } 22 | 23 | async function handleStakeSubmit(data) { 24 | const amountToApprove = data.data[0].inputResult 25 | approveOptions.params = { 26 | amount: ethers.utils.parseUnits(amountToApprove, "ether").toString(), 27 | spender: stakingAddress, 28 | } 29 | console.log("Approving...") 30 | const tx = await runContractFunction({ 31 | params: approveOptions, 32 | onError: (error) => console.log(error), 33 | onSuccess: () => { 34 | handleApproveSuccess(approveOptions.params.amount) 35 | }, 36 | }) 37 | } 38 | 39 | async function handleApproveSuccess(amountToStakeFormatted) { 40 | stakeOptions.params = { 41 | amount: amountToStakeFormatted, 42 | } 43 | console.log(`Staking ${stakeOptions.params.amount} RT Token...`) 44 | const tx = await runContractFunction({ 45 | params: stakeOptions, 46 | onError: (error) => console.log(error), 47 | }) 48 | await tx.wait(1) 49 | console.log("Transaction has been confirmed by 1 block") 50 | } 51 | 52 | return ( 53 |
54 |
67 |
68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /constants/index.js: -------------------------------------------------------------------------------- 1 | const stakingAddress = "0x0165878A594ca255338adfa4d48449f69242Eb8F" 2 | const rewardTokenAddress = "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" 3 | 4 | const stakingAbi = require("./stakingAbi.json") 5 | const rewardTokenAbi = require("./rewardTokenAbi.json") 6 | 7 | module.exports = { 8 | stakingAbi, 9 | rewardTokenAbi, 10 | stakingAddress, 11 | rewardTokenAddress, 12 | } 13 | -------------------------------------------------------------------------------- /constants/rewardTokenAbi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [], 4 | "stateMutability": "nonpayable", 5 | "type": "constructor" 6 | }, 7 | { 8 | "anonymous": false, 9 | "inputs": [ 10 | { 11 | "indexed": true, 12 | "internalType": "address", 13 | "name": "owner", 14 | "type": "address" 15 | }, 16 | { 17 | "indexed": true, 18 | "internalType": "address", 19 | "name": "spender", 20 | "type": "address" 21 | }, 22 | { 23 | "indexed": false, 24 | "internalType": "uint256", 25 | "name": "value", 26 | "type": "uint256" 27 | } 28 | ], 29 | "name": "Approval", 30 | "type": "event" 31 | }, 32 | { 33 | "anonymous": false, 34 | "inputs": [ 35 | { 36 | "indexed": true, 37 | "internalType": "address", 38 | "name": "from", 39 | "type": "address" 40 | }, 41 | { 42 | "indexed": true, 43 | "internalType": "address", 44 | "name": "to", 45 | "type": "address" 46 | }, 47 | { 48 | "indexed": false, 49 | "internalType": "uint256", 50 | "name": "value", 51 | "type": "uint256" 52 | } 53 | ], 54 | "name": "Transfer", 55 | "type": "event" 56 | }, 57 | { 58 | "inputs": [ 59 | { 60 | "internalType": "address", 61 | "name": "owner", 62 | "type": "address" 63 | }, 64 | { 65 | "internalType": "address", 66 | "name": "spender", 67 | "type": "address" 68 | } 69 | ], 70 | "name": "allowance", 71 | "outputs": [ 72 | { 73 | "internalType": "uint256", 74 | "name": "", 75 | "type": "uint256" 76 | } 77 | ], 78 | "stateMutability": "view", 79 | "type": "function" 80 | }, 81 | { 82 | "inputs": [ 83 | { 84 | "internalType": "address", 85 | "name": "spender", 86 | "type": "address" 87 | }, 88 | { 89 | "internalType": "uint256", 90 | "name": "amount", 91 | "type": "uint256" 92 | } 93 | ], 94 | "name": "approve", 95 | "outputs": [ 96 | { 97 | "internalType": "bool", 98 | "name": "", 99 | "type": "bool" 100 | } 101 | ], 102 | "stateMutability": "nonpayable", 103 | "type": "function" 104 | }, 105 | { 106 | "inputs": [ 107 | { 108 | "internalType": "address", 109 | "name": "account", 110 | "type": "address" 111 | } 112 | ], 113 | "name": "balanceOf", 114 | "outputs": [ 115 | { 116 | "internalType": "uint256", 117 | "name": "", 118 | "type": "uint256" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [], 126 | "name": "decimals", 127 | "outputs": [ 128 | { 129 | "internalType": "uint8", 130 | "name": "", 131 | "type": "uint8" 132 | } 133 | ], 134 | "stateMutability": "view", 135 | "type": "function" 136 | }, 137 | { 138 | "inputs": [ 139 | { 140 | "internalType": "address", 141 | "name": "spender", 142 | "type": "address" 143 | }, 144 | { 145 | "internalType": "uint256", 146 | "name": "subtractedValue", 147 | "type": "uint256" 148 | } 149 | ], 150 | "name": "decreaseAllowance", 151 | "outputs": [ 152 | { 153 | "internalType": "bool", 154 | "name": "", 155 | "type": "bool" 156 | } 157 | ], 158 | "stateMutability": "nonpayable", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [ 163 | { 164 | "internalType": "address", 165 | "name": "spender", 166 | "type": "address" 167 | }, 168 | { 169 | "internalType": "uint256", 170 | "name": "addedValue", 171 | "type": "uint256" 172 | } 173 | ], 174 | "name": "increaseAllowance", 175 | "outputs": [ 176 | { 177 | "internalType": "bool", 178 | "name": "", 179 | "type": "bool" 180 | } 181 | ], 182 | "stateMutability": "nonpayable", 183 | "type": "function" 184 | }, 185 | { 186 | "inputs": [], 187 | "name": "name", 188 | "outputs": [ 189 | { 190 | "internalType": "string", 191 | "name": "", 192 | "type": "string" 193 | } 194 | ], 195 | "stateMutability": "view", 196 | "type": "function" 197 | }, 198 | { 199 | "inputs": [], 200 | "name": "symbol", 201 | "outputs": [ 202 | { 203 | "internalType": "string", 204 | "name": "", 205 | "type": "string" 206 | } 207 | ], 208 | "stateMutability": "view", 209 | "type": "function" 210 | }, 211 | { 212 | "inputs": [], 213 | "name": "totalSupply", 214 | "outputs": [ 215 | { 216 | "internalType": "uint256", 217 | "name": "", 218 | "type": "uint256" 219 | } 220 | ], 221 | "stateMutability": "view", 222 | "type": "function" 223 | }, 224 | { 225 | "inputs": [ 226 | { 227 | "internalType": "address", 228 | "name": "to", 229 | "type": "address" 230 | }, 231 | { 232 | "internalType": "uint256", 233 | "name": "amount", 234 | "type": "uint256" 235 | } 236 | ], 237 | "name": "transfer", 238 | "outputs": [ 239 | { 240 | "internalType": "bool", 241 | "name": "", 242 | "type": "bool" 243 | } 244 | ], 245 | "stateMutability": "nonpayable", 246 | "type": "function" 247 | }, 248 | { 249 | "inputs": [ 250 | { 251 | "internalType": "address", 252 | "name": "from", 253 | "type": "address" 254 | }, 255 | { 256 | "internalType": "address", 257 | "name": "to", 258 | "type": "address" 259 | }, 260 | { 261 | "internalType": "uint256", 262 | "name": "amount", 263 | "type": "uint256" 264 | } 265 | ], 266 | "name": "transferFrom", 267 | "outputs": [ 268 | { 269 | "internalType": "bool", 270 | "name": "", 271 | "type": "bool" 272 | } 273 | ], 274 | "stateMutability": "nonpayable", 275 | "type": "function" 276 | } 277 | ] -------------------------------------------------------------------------------- /constants/stakingAbi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "inputs": [ 4 | { 5 | "internalType": "address", 6 | "name": "stakingToken", 7 | "type": "address" 8 | }, 9 | { 10 | "internalType": "address", 11 | "name": "rewardsToken", 12 | "type": "address" 13 | } 14 | ], 15 | "stateMutability": "nonpayable", 16 | "type": "constructor" 17 | }, 18 | { 19 | "inputs": [], 20 | "name": "NeedsMoreThanZero", 21 | "type": "error" 22 | }, 23 | { 24 | "inputs": [], 25 | "name": "TransferFailed", 26 | "type": "error" 27 | }, 28 | { 29 | "anonymous": false, 30 | "inputs": [ 31 | { 32 | "indexed": true, 33 | "internalType": "address", 34 | "name": "user", 35 | "type": "address" 36 | }, 37 | { 38 | "indexed": true, 39 | "internalType": "uint256", 40 | "name": "amount", 41 | "type": "uint256" 42 | } 43 | ], 44 | "name": "RewardsClaimed", 45 | "type": "event" 46 | }, 47 | { 48 | "anonymous": false, 49 | "inputs": [ 50 | { 51 | "indexed": true, 52 | "internalType": "address", 53 | "name": "user", 54 | "type": "address" 55 | }, 56 | { 57 | "indexed": true, 58 | "internalType": "uint256", 59 | "name": "amount", 60 | "type": "uint256" 61 | } 62 | ], 63 | "name": "Staked", 64 | "type": "event" 65 | }, 66 | { 67 | "anonymous": false, 68 | "inputs": [ 69 | { 70 | "indexed": true, 71 | "internalType": "address", 72 | "name": "user", 73 | "type": "address" 74 | }, 75 | { 76 | "indexed": true, 77 | "internalType": "uint256", 78 | "name": "amount", 79 | "type": "uint256" 80 | } 81 | ], 82 | "name": "WithdrewStake", 83 | "type": "event" 84 | }, 85 | { 86 | "inputs": [], 87 | "name": "REWARD_RATE", 88 | "outputs": [ 89 | { 90 | "internalType": "uint256", 91 | "name": "", 92 | "type": "uint256" 93 | } 94 | ], 95 | "stateMutability": "view", 96 | "type": "function" 97 | }, 98 | { 99 | "inputs": [], 100 | "name": "claimReward", 101 | "outputs": [], 102 | "stateMutability": "nonpayable", 103 | "type": "function" 104 | }, 105 | { 106 | "inputs": [ 107 | { 108 | "internalType": "address", 109 | "name": "account", 110 | "type": "address" 111 | } 112 | ], 113 | "name": "earned", 114 | "outputs": [ 115 | { 116 | "internalType": "uint256", 117 | "name": "", 118 | "type": "uint256" 119 | } 120 | ], 121 | "stateMutability": "view", 122 | "type": "function" 123 | }, 124 | { 125 | "inputs": [ 126 | { 127 | "internalType": "address", 128 | "name": "account", 129 | "type": "address" 130 | } 131 | ], 132 | "name": "getStaked", 133 | "outputs": [ 134 | { 135 | "internalType": "uint256", 136 | "name": "", 137 | "type": "uint256" 138 | } 139 | ], 140 | "stateMutability": "view", 141 | "type": "function" 142 | }, 143 | { 144 | "inputs": [], 145 | "name": "rewardPerToken", 146 | "outputs": [ 147 | { 148 | "internalType": "uint256", 149 | "name": "", 150 | "type": "uint256" 151 | } 152 | ], 153 | "stateMutability": "view", 154 | "type": "function" 155 | }, 156 | { 157 | "inputs": [ 158 | { 159 | "internalType": "address", 160 | "name": "", 161 | "type": "address" 162 | } 163 | ], 164 | "name": "s_balances", 165 | "outputs": [ 166 | { 167 | "internalType": "uint256", 168 | "name": "", 169 | "type": "uint256" 170 | } 171 | ], 172 | "stateMutability": "view", 173 | "type": "function" 174 | }, 175 | { 176 | "inputs": [], 177 | "name": "s_lastUpdateTime", 178 | "outputs": [ 179 | { 180 | "internalType": "uint256", 181 | "name": "", 182 | "type": "uint256" 183 | } 184 | ], 185 | "stateMutability": "view", 186 | "type": "function" 187 | }, 188 | { 189 | "inputs": [], 190 | "name": "s_rewardPerTokenStored", 191 | "outputs": [ 192 | { 193 | "internalType": "uint256", 194 | "name": "", 195 | "type": "uint256" 196 | } 197 | ], 198 | "stateMutability": "view", 199 | "type": "function" 200 | }, 201 | { 202 | "inputs": [ 203 | { 204 | "internalType": "address", 205 | "name": "", 206 | "type": "address" 207 | } 208 | ], 209 | "name": "s_rewards", 210 | "outputs": [ 211 | { 212 | "internalType": "uint256", 213 | "name": "", 214 | "type": "uint256" 215 | } 216 | ], 217 | "stateMutability": "view", 218 | "type": "function" 219 | }, 220 | { 221 | "inputs": [], 222 | "name": "s_rewardsToken", 223 | "outputs": [ 224 | { 225 | "internalType": "contract IERC20", 226 | "name": "", 227 | "type": "address" 228 | } 229 | ], 230 | "stateMutability": "view", 231 | "type": "function" 232 | }, 233 | { 234 | "inputs": [], 235 | "name": "s_stakingToken", 236 | "outputs": [ 237 | { 238 | "internalType": "contract IERC20", 239 | "name": "", 240 | "type": "address" 241 | } 242 | ], 243 | "stateMutability": "view", 244 | "type": "function" 245 | }, 246 | { 247 | "inputs": [ 248 | { 249 | "internalType": "address", 250 | "name": "", 251 | "type": "address" 252 | } 253 | ], 254 | "name": "s_userRewardPerTokenPaid", 255 | "outputs": [ 256 | { 257 | "internalType": "uint256", 258 | "name": "", 259 | "type": "uint256" 260 | } 261 | ], 262 | "stateMutability": "view", 263 | "type": "function" 264 | }, 265 | { 266 | "inputs": [ 267 | { 268 | "internalType": "uint256", 269 | "name": "amount", 270 | "type": "uint256" 271 | } 272 | ], 273 | "name": "stake", 274 | "outputs": [], 275 | "stateMutability": "nonpayable", 276 | "type": "function" 277 | }, 278 | { 279 | "inputs": [ 280 | { 281 | "internalType": "uint256", 282 | "name": "amount", 283 | "type": "uint256" 284 | } 285 | ], 286 | "name": "withdraw", 287 | "outputs": [], 288 | "stateMutability": "nonpayable", 289 | "type": "function" 290 | } 291 | ] -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "staking-ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "moralis": "^1.6.0", 13 | "next": "12.1.6", 14 | "react": "18.1.0", 15 | "react-dom": "18.1.0", 16 | "react-moralis": "^1.3.5", 17 | "web3uikit": "^0.1.140" 18 | }, 19 | "devDependencies": { 20 | "autoprefixer": "^10.4.7", 21 | "eslint": "8.14.0", 22 | "eslint-config-next": "12.1.6", 23 | "postcss": "^8.4.13", 24 | "prettier": "^2.6.2", 25 | "tailwindcss": "^3.0.24" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /pages/_app.js: -------------------------------------------------------------------------------- 1 | import "../styles/globals.css" 2 | import { MoralisProvider } from "react-moralis" 3 | 4 | function MyApp({ Component, pageProps }) { 5 | return ( 6 | 7 | 8 | 9 | ) 10 | } 11 | 12 | export default MyApp 13 | -------------------------------------------------------------------------------- /pages/api/hello.js: -------------------------------------------------------------------------------- 1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction 2 | 3 | export default function handler(req, res) { 4 | res.status(200).json({ name: "John Doe" }) 5 | } 6 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import styles from "../styles/Home.module.css" 2 | import Header from "../components/Header" 3 | import StakeDetails from "../components/StakeDetails" 4 | import StakeForm from "../components/StakeForm" 5 | import { useChain } from "react-moralis" 6 | 7 | export default function Home() { 8 | const { switchNetwork, chainId, chain, account } = useChain() 9 | return ( 10 |
11 |
12 | 13 | 14 |
15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatrickAlphaC/staking-ui-demo/f49bb5917c4469b03994762219a0f2b29f342607/public/favicon.ico -------------------------------------------------------------------------------- /public/vercel.svg: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /styles/Home.module.css: -------------------------------------------------------------------------------- 1 | .container { 2 | padding: 0 2rem; 3 | } 4 | 5 | .main { 6 | min-height: 100vh; 7 | padding: 4rem 0; 8 | flex: 1; 9 | display: flex; 10 | flex-direction: column; 11 | justify-content: center; 12 | align-items: center; 13 | } 14 | 15 | .footer { 16 | display: flex; 17 | flex: 1; 18 | padding: 2rem 0; 19 | border-top: 1px solid #eaeaea; 20 | justify-content: center; 21 | align-items: center; 22 | } 23 | 24 | .footer a { 25 | display: flex; 26 | justify-content: center; 27 | align-items: center; 28 | flex-grow: 1; 29 | } 30 | 31 | .title a { 32 | color: #0070f3; 33 | text-decoration: none; 34 | } 35 | 36 | .title a:hover, 37 | .title a:focus, 38 | .title a:active { 39 | text-decoration: underline; 40 | } 41 | 42 | .title { 43 | margin: 0; 44 | line-height: 1.15; 45 | font-size: 4rem; 46 | } 47 | 48 | .title, 49 | .description { 50 | text-align: center; 51 | } 52 | 53 | .description { 54 | margin: 4rem 0; 55 | line-height: 1.5; 56 | font-size: 1.5rem; 57 | } 58 | 59 | .code { 60 | background: #fafafa; 61 | border-radius: 5px; 62 | padding: 0.75rem; 63 | font-size: 1.1rem; 64 | font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, 65 | Bitstream Vera Sans Mono, Courier New, monospace; 66 | } 67 | 68 | .grid { 69 | display: flex; 70 | align-items: center; 71 | justify-content: center; 72 | flex-wrap: wrap; 73 | max-width: 800px; 74 | } 75 | 76 | .card { 77 | margin: 1rem; 78 | padding: 1.5rem; 79 | text-align: left; 80 | color: inherit; 81 | text-decoration: none; 82 | border: 1px solid #eaeaea; 83 | border-radius: 10px; 84 | transition: color 0.15s ease, border-color 0.15s ease; 85 | max-width: 300px; 86 | } 87 | 88 | .card:hover, 89 | .card:focus, 90 | .card:active { 91 | color: #0070f3; 92 | border-color: #0070f3; 93 | } 94 | 95 | .card h2 { 96 | margin: 0 0 1rem 0; 97 | font-size: 1.5rem; 98 | } 99 | 100 | .card p { 101 | margin: 0; 102 | font-size: 1.25rem; 103 | line-height: 1.5; 104 | } 105 | 106 | .logo { 107 | height: 1em; 108 | margin-left: 0.5rem; 109 | } 110 | 111 | @media (max-width: 600px) { 112 | .grid { 113 | width: 100%; 114 | flex-direction: column; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /styles/globals.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | content: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"], 3 | theme: { 4 | extend: {}, 5 | }, 6 | plugins: [], 7 | } 8 | --------------------------------------------------------------------------------