From 6ebede48cb05604b5eb4a7678949618d3037ff45 Mon Sep 17 00:00:00 2001 From: Damian Date: Tue, 3 Dec 2024 19:25:39 -0300 Subject: [PATCH 1/5] Challenge 1 extension --- README.md | 245 ++++++++++++++++++ extension/README.md.args.mjs | 233 +++++++++++++++++ .../contracts/ExampleExternalContract.sol | 10 + .../packages/hardhat/contracts/Staker.sol | 27 ++ .../00_deploy_example_external_contract.ts | 35 +++ .../hardhat/deploy/01_deploy_staker.ts | 38 +++ extension/packages/hardhat/test/Challenge1.ts | 149 +++++++++++ .../packages/nextjs/app/layout.tsx.args.mjs | 4 + .../packages/nextjs/app/page.tsx.args.mjs | 40 +++ .../app/staker-ui/_components/EthToPrice.tsx | 53 ++++ .../_components/StakeContractInteraction.tsx | 139 ++++++++++ .../app/staker-ui/_components/index.tsx | 2 + .../packages/nextjs/app/staker-ui/page.tsx | 12 + .../packages/nextjs/app/stakings/page.tsx | 62 +++++ .../nextjs/components/Header.tsx.args.mjs | 15 ++ .../ScaffoldEthAppWithProviders.tsx.args.mjs | 1 + extension/packages/nextjs/package.json | 5 + extension/packages/nextjs/public/hero.png | Bin 0 -> 32724 bytes .../nextjs/public/thumbnail-challenge-1.png | Bin 0 -> 35950 bytes .../nextjs/styles/globals.css.args.mjs | 1 + .../nextjs/tailwind.config.js.args.mjs | 68 +++++ .../scaffold-eth/getMetadata.ts.args.mjs | 2 + 22 files changed, 1141 insertions(+) create mode 100644 README.md create mode 100644 extension/README.md.args.mjs create mode 100644 extension/packages/hardhat/contracts/ExampleExternalContract.sol create mode 100644 extension/packages/hardhat/contracts/Staker.sol create mode 100644 extension/packages/hardhat/deploy/00_deploy_example_external_contract.ts create mode 100644 extension/packages/hardhat/deploy/01_deploy_staker.ts create mode 100644 extension/packages/hardhat/test/Challenge1.ts create mode 100644 extension/packages/nextjs/app/layout.tsx.args.mjs create mode 100644 extension/packages/nextjs/app/page.tsx.args.mjs create mode 100644 extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx create mode 100644 extension/packages/nextjs/app/staker-ui/_components/StakeContractInteraction.tsx create mode 100644 extension/packages/nextjs/app/staker-ui/_components/index.tsx create mode 100644 extension/packages/nextjs/app/staker-ui/page.tsx create mode 100644 extension/packages/nextjs/app/stakings/page.tsx create mode 100644 extension/packages/nextjs/components/Header.tsx.args.mjs create mode 100644 extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs create mode 100644 extension/packages/nextjs/package.json create mode 100644 extension/packages/nextjs/public/hero.png create mode 100644 extension/packages/nextjs/public/thumbnail-challenge-1.png create mode 100644 extension/packages/nextjs/styles/globals.css.args.mjs create mode 100644 extension/packages/nextjs/tailwind.config.js.args.mjs create mode 100644 extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs diff --git a/README.md b/README.md new file mode 100644 index 00000000..74ece3d0 --- /dev/null +++ b/README.md @@ -0,0 +1,245 @@ +# 🚩 Challenge 1: πŸ” Decentralized Staking App + +![readme-1](https://github.com/scaffold-eth/se-2-challenges/assets/80153681/a620999a-a1ff-462d-9ae3-5b49ab0e023a) + +🦸 A superpower of Ethereum is allowing you, the builder, to create a simple set of rules that an adversarial group of players can use to work together. In this challenge, you create a decentralized application where users can coordinate a group funding effort. If the users cooperate, the money is collected in a second smart contract. If they defect, the worst that can happen is everyone gets their money back. The users only have to trust the code. + +🏦 Build a `Staker.sol` contract that collects **ETH** from numerous addresses using a payable `stake()` function and keeps track of `balances`. After some `deadline` if it has at least some `threshold` of ETH, it sends it to an `ExampleExternalContract` and triggers the `complete()` action sending the full balance. If not enough **ETH** is collected, allow users to `withdraw()`. + +πŸŽ› Building the frontend to display the information and UI is just as important as writing the contract. The goal is to deploy the contract and the app to allow anyone to stake using your app. Use a `Stake(address,uint256)` event to list all stakes. + +🌟 The final deliverable is deploying a Dapp that lets users send ether to a contract and stake if the conditions are met, then `yarn vercel` your app to a public webserver. Submit the url on [SpeedRunEthereum.com](https://speedrunethereum.com)! + +> πŸ’¬ Meet other builders working on this challenge and get help in the [Challenge 1 Telegram](https://t.me/joinchat/E6r91UFt4oMJlt01)! + +--- + +## Checkpoint 0: πŸ“¦ Environment πŸ“š + +Before you begin, you need to install the following tools: + +- [Node (v18 LTS)](https://nodejs.org/en/download/) +- Yarn ([v1](https://classic.yarnpkg.com/en/docs/install/) or [v2+](https://yarnpkg.com/getting-started/install)) +- [Git](https://git-scm.com/downloads) + +Then download the challenge to your computer and install dependencies by running: + +```sh +git clone https://github.com/scaffold-eth/se-2-challenges.git challenge-1-decentralized-staking +cd challenge-1-decentralized-staking +git checkout challenge-1-decentralized-staking +yarn install +``` + +> in the same terminal, start your local network (a blockchain emulator in your computer): + +```sh +yarn chain +``` + +> in a second terminal window, πŸ›° deploy your contract (locally): + +```sh +cd challenge-1-decentralized-staking +yarn deploy +``` + +> in a third terminal window, start your πŸ“± frontend: + +```sh +cd challenge-1-decentralized-staking +yarn start +``` + +πŸ“± Open http://localhost:3000 to see the app. + +> πŸ‘©β€πŸ’» Rerun `yarn deploy` whenever you want to deploy new contracts to the frontend. If you haven't made any contract changes, you can run `yarn deploy --reset` for a completely fresh deploy. + +πŸ” Now you are ready to edit your smart contract `Staker.sol` in `packages/hardhat/contracts` + +--- + +βš—οΈ At this point you will need to know basic Solidity syntax. If not, you can pick it up quickly by tinkering with concepts from [πŸ“‘ Solidity By Example](https://solidity-by-example.org/) using [πŸ—οΈ Scaffold-ETH-2](https://scaffoldeth.io). (In particular: global units,Β primitive data types,Β mappings, sending ether, and payable functions.) + +--- + +## Checkpoint 1: πŸ” Staking πŸ’΅ + +You'll need to track individual `balances` using a mapping: + +```solidity +mapping ( address => uint256 ) public balances; +``` + +And also track a constant `threshold` at `1 ether` + +```solidity +uint256 public constant threshold = 1 ether; +``` + +> πŸ‘©β€πŸ’» Write your `stake()` function and test it with the `Debug Contracts` tab in the frontend. + +![debugContracts](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/1a888e31-a79b-49ef-9848-357c5cee445a) + +> πŸ’Έ Need more funds from the faucet? Click on _"Grab funds from faucet"_, or use the Faucet feature at the bottom left of the page to get as much as you need! + +![Faucet](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/e82e3100-20fb-4886-a6bf-4113c3729f53) + +> ✏ Need to troubleshoot your code? If you import `hardhat/console.sol` to your contract, you can call `console.log()` right in your Solidity code. The output will appear in your `yarn chain` terminal. + +### πŸ₯… Goals + +- [ ] Do you see the balance of the `Staker` contract go up when you `stake()`? +- [ ] Is your `balance` correctly tracked? +- [ ] Do you see the events in the `Stake Events` tab? + + ![allStakings](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/80bcc843-034c-4547-8535-129ed494a204) + +--- + +## Checkpoint 2: πŸ”¬ State Machine / Timing ⏱ + +### State Machine + +> βš™οΈ Think of your smart contract like a _state machine_. First, there is a **stake** period. Then, if you have gathered the `threshold` worth of ETH, there is a **success** state. Or, we go into a **withdraw** state to let users withdraw their funds. + +Set a `deadline` of `block.timestamp + 30 seconds` + +```solidity +uint256 public deadline = block.timestamp + 30 seconds; +``` + +πŸ‘¨β€πŸ« Smart contracts can't execute automatically, you always need to have a transaction execute to change state. Because of this, you will need to have an `execute()` function that _anyone_ can call, just once, after the `deadline` has expired. + +> πŸ‘©β€πŸ’» Write your `execute()` function and test it with the `Debug Contracts` tab + +> Check the `ExampleExternalContract.sol` for the bool you can use to test if it has been completed or not. But do not edit the `ExampleExternalContract.sol` as it can slow the auto grading. + +If the `address(this).balance` of the contract is over the `threshold` by the `deadline`, you will want to call: `exampleExternalContract.complete{value: address(this).balance}()` + +If the balance is less than the `threshold`, you want to set a `openForWithdraw` bool to `true` which will allow users to `withdraw()` their funds. + +### Timing + +You'll have 30 seconds after deploying until the deadline is reached, you can adjust this in the contract. + +> πŸ‘©β€πŸ’» Create a `timeLeft()` function including `public view returns (uint256)` that returns how much time is left. + +⚠️ Be careful! If `block.timestamp >= deadline` you want to `return 0;` + +⏳ _"Time Left"_ will only update if a transaction occurs. You can see the time update by getting funds from the faucet button in navbar just to trigger a new block. + +![stakerUI](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/7d85badb-3ea3-4f3c-b5f8-43d5b64f6714) + +> πŸ‘©β€πŸ’» You can call `yarn deploy --reset` any time you want a fresh contract, it will get re-deployed even if there are no changes on it. +> You may need it when you want to reload the _"Time Left"_ of your tests. + +Your `Staker UI` tab should be almost done and working at this point. + +--- + +### πŸ₯… Goals + +- [ ] Can you see `timeLeft` counting down in the `Staker UI` tab when you trigger a transaction with the faucet button? +- [ ] If enough ETH is staked by the deadline, does your `execute()` function correctly call `complete()` and stake the ETH? +- [ ] If the threshold isn't met by the deadline, are you able to `withdraw()` your funds? + +--- + +## Checkpoint 3: πŸ’΅ Receive Function / UX πŸ™Ž + +πŸŽ€ To improve the user experience, set your contract up so it accepts ETH sent to it and calls `stake()`. You will use what is called the `receive()` function. + +> Use the [receive()](https://docs.soliditylang.org/en/v0.8.9/contracts.html?highlight=receive#receive-ether-function) function in solidity to "catch" ETH sent to the contract and call `stake()` to update `balances`. + +--- + +### πŸ₯… Goals + +- [ ] If you send ETH directly to the contract address does it update your `balance` and the `balance` of the contract? + +--- + +### βš”οΈ Side Quests + +- [ ] Can `execute()` get called more than once, and is that okay? +- [ ] Can you stake and withdraw freely after the `deadline`, and is that okay? +- [ ] What are other implications of _anyone_ being able to withdraw for someone? + +--- + +### 🐸 It's a trap! + +- [ ] Make sure funds can't get trapped in the contract! **Try sending funds after you have executed! What happens?** +- [ ] Try to create a [modifier](https://solidity-by-example.org/function-modifier/) called `notCompleted`. It will check that `ExampleExternalContract` is not completed yet. Use it to protect your `execute` and `withdraw` functions. + +### ⚠️ Test it! + +- Now is a good time to run `yarn test` to run the automated testing function. It will test that you hit the core checkpoints. You are looking for all green checkmarks and passing tests! + +--- + +## Checkpoint 4: πŸ’Ύ Deploy your contract! πŸ›° + +πŸ“‘ Edit the `defaultNetwork` to [your choice of public EVM networks](https://ethereum.org/en/developers/docs/networks/) in `packages/hardhat/hardhat.config.ts` + +πŸ” You will need to generate a **deployer address** using `yarn generate` This creates a mnemonic and saves it locally. + +πŸ‘©β€πŸš€ Use `yarn account` to view your deployer account balances. + +⛽️ You will need to send ETH to your deployer address with your wallet, or get it from a public faucet of your chosen network. + +> πŸ“ If you plan on submitting this challenge, be sure to set your `deadline` to at least `block.timestamp + 72 hours` + +πŸš€ Run `yarn deploy` to deploy your smart contract to a public network (selected in `hardhat.config.ts`) + +> πŸ’¬ Hint: You can set the `defaultNetwork` in `hardhat.config.ts` to `sepolia` or `optimismSepolia` **OR** you can `yarn deploy --network sepolia` or `yarn deploy --network optimismSepolia`. + +![allStakings-blockFrom](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/04725dc8-4a8d-4089-ba82-90f9b94bfbda) + +> πŸ’¬ Hint: For faster loading of your _"Stake Events"_ page, consider updating the `fromBlock` passed to `useScaffoldEventHistory` in [`packages/nextjs/app/stakings/page.tsx`](https://github.com/scaffold-eth/se-2-challenges/blob/challenge-1-decentralized-staking/packages/nextjs/app/stakings/page.tsx) to `blocknumber - 10` at which your contract was deployed. Example: `fromBlock: 3750241n` (where `n` represents its a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)). To find this blocknumber, search your contract's address on Etherscan and find the `Contract Creation` transaction line. + +--- + +## Checkpoint 5: 🚒 Ship your frontend! 🚁 + +✏️ Edit your frontend config in `packages/nextjs/scaffold.config.ts` to change the `targetNetwork` to `chains.sepolia` (or `chains.optimismSepolia` if you deployed to OP Sepolia) + +πŸ’» View your frontend at http://localhost:3000/staker-ui and verify you see the correct network. + +πŸ“‘ When you are ready to ship the frontend app... + +πŸ“¦ Run `yarn vercel` to package up your frontend and deploy. + +> Follow the steps to deploy to Vercel. Once you log in (email, github, etc), the default options should work. It'll give you a public URL. + +> If you want to redeploy to the same production URL you can run `yarn vercel --prod`. If you omit the `--prod` flag it will deploy it to a preview/test URL. + +> 🦊 Since we have deployed to a public testnet, you will now need to connect using a wallet you own or use a burner wallet. By default πŸ”₯ `burner wallets` are only available on `hardhat` . You can enable them on every chain by setting `onlyLocalBurnerWallet: false` in your frontend config (`scaffold.config.ts` in `packages/nextjs/`) + +#### Configuration of Third-Party Services for Production-Grade Apps. + +By default, πŸ— Scaffold-ETH 2 provides predefined API keys for popular services such as Alchemy and Etherscan. This allows you to begin developing and testing your applications more easily, avoiding the need to register for these services. +This is great to complete your **SpeedRunEthereum**. + +For production-grade applications, it's recommended to obtain your own API keys (to prevent rate limiting issues). You can configure these at: + +- πŸ”·`ALCHEMY_API_KEY` variable in `packages/hardhat/.env` and `packages/nextjs/.env.local`. You can create API keys from the [Alchemy dashboard](https://dashboard.alchemy.com/). + +- πŸ“ƒ`ETHERSCAN_API_KEY` variable in `packages/hardhat/.env` with your generated API key. You can get your key [here](https://etherscan.io/myapikey). + +> πŸ’¬ Hint: It's recommended to store env's for nextjs in Vercel/system env config for live apps and use .env.local for local testing. + +--- + +## Checkpoint 6: πŸ“œ Contract Verification + +Run the `yarn verify --network your_network` command to verify your contracts on etherscan πŸ›° + +πŸ‘‰ Search this address on [Sepolia Etherscan](https://sepolia.etherscan.io/) (or [Optimism Sepolia Etherscan](https://sepolia-optimism.etherscan.io/) if you deployed to OP Sepolia) to get the URL you submit to πŸƒβ€β™€οΈ[SpeedRunEthereum.com](https://speedrunethereum.com). + +--- + +> πŸƒ Head to your next challenge [here](https://speedrunethereum.com). + +> πŸ’¬ Problems, questions, comments on the stack? Post them to the [πŸ— scaffold-eth developers chat](https://t.me/joinchat/F7nCRK3kI93PoCOk) diff --git a/extension/README.md.args.mjs b/extension/README.md.args.mjs new file mode 100644 index 00000000..60bdd1f6 --- /dev/null +++ b/extension/README.md.args.mjs @@ -0,0 +1,233 @@ +export const skipQuickStart = true; + +export const extraContents = `# 🚩 Challenge 1: πŸ” Decentralized Staking App + +![readme-1](https://github.com/scaffold-eth/se-2-challenges/assets/80153681/a620999a-a1ff-462d-9ae3-5b49ab0e023a) + +🦸 A superpower of Ethereum is allowing you, the builder, to create a simple set of rules that an adversarial group of players can use to work together. In this challenge, you create a decentralized application where users can coordinate a group funding effort. If the users cooperate, the money is collected in a second smart contract. If they defect, the worst that can happen is everyone gets their money back. The users only have to trust the code. + +🏦 Build a \`Staker.sol\` contract that collects **ETH** from numerous addresses using a payable \`stake()\` function and keeps track of \`balances\`. After some \`deadline\` if it has at least some \`threshold\` of ETH, it sends it to an \`ExampleExternalContract\` and triggers the \`complete()\` action sending the full balance. If not enough **ETH** is collected, allow users to \`withdraw()\`. + +πŸŽ› Building the frontend to display the information and UI is just as important as writing the contract. The goal is to deploy the contract and the app to allow anyone to stake using your app. Use a \`Stake(address,uint256)\` event to list all stakes. + +🌟 The final deliverable is deploying a Dapp that lets users send ether to a contract and stake if the conditions are met, then \`yarn vercel\` your app to a public webserver. Submit the url on [SpeedRunEthereum.com](https://speedrunethereum.com)! + +> πŸ’¬ Meet other builders working on this challenge and get help in the [Challenge 1 Telegram](https://t.me/joinchat/E6r91UFt4oMJlt01)! + +--- + +## Checkpoint 0: πŸ“¦ Environment πŸ“š + +> Start your local network (a local instance of a blockchain): + +\`\`\`sh +yarn chain +\`\`\` + +> in a second terminal window, πŸ›° deploy your contract (locally): + +\`\`\`sh +cd challenge-1-decentralized-staking +yarn deploy +\`\`\` + +> in a third terminal window, start your πŸ“± frontend: + +\`\`\`sh +cd challenge-1-decentralized-staking +yarn start +\`\`\` + +πŸ“± Open http://localhost:3000 to see the app. + +> πŸ‘©β€πŸ’» Rerun \`yarn deploy\` whenever you want to deploy new contracts to the frontend. If you haven't made any contract changes, you can run \`yarn deploy --reset\` for a completely fresh deploy. + +πŸ” Now you are ready to edit your smart contract \`Staker.sol\` in \`packages/hardhat/contracts\` + +--- + +βš—οΈ At this point you will need to know basic Solidity syntax. If not, you can pick it up quickly by tinkering with concepts from [πŸ“‘ Solidity By Example](https://solidity-by-example.org/) using [πŸ—οΈ Scaffold-ETH-2](https://scaffoldeth.io). (In particular: global units,Β primitive data types,Β mappings, sending ether, and payable functions.) + +--- + +## Checkpoint 1: πŸ” Staking πŸ’΅ + +You'll need to track individual \`balances\` using a mapping: + +\`\`\`solidity +mapping ( address => uint256 ) public balances; +\`\`\` + +And also track a constant \`threshold\` at \`1 ether\` + +\`\`\`solidity +uint256 public constant threshold = 1 ether; +\`\`\` + +> πŸ‘©β€πŸ’» Write your \`stake()\` function and test it with the \`Debug Contracts\` tab in the frontend. + +![debugContracts](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/1a888e31-a79b-49ef-9848-357c5cee445a) + +> πŸ’Έ Need more funds from the faucet? Click on _"Grab funds from faucet"_, or use the Faucet feature at the bottom left of the page to get as much as you need! + +![Faucet](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/e82e3100-20fb-4886-a6bf-4113c3729f53) + +> ✏ Need to troubleshoot your code? If you import \`hardhat/console.sol\` to your contract, you can call \`console.log()\` right in your Solidity code. The output will appear in your \`yarn chain\` terminal. + +### πŸ₯… Goals + +- [ ] Do you see the balance of the \`Staker\` contract go up when you \`stake()\`? +- [ ] Is your \`balance\` correctly tracked? +- [ ] Do you see the events in the \`Stake Events\` tab? + + ![allStakings](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/80bcc843-034c-4547-8535-129ed494a204) + +--- + +## Checkpoint 2: πŸ”¬ State Machine / Timing ⏱ + +### State Machine + +> βš™οΈ Think of your smart contract like a _state machine_. First, there is a **stake** period. Then, if you have gathered the \`threshold\` worth of ETH, there is a **success** state. Or, we go into a **withdraw** state to let users withdraw their funds. + +Set a \`deadline\` of \`block.timestamp + 30 seconds\` + +\`\`\`solidity +uint256 public deadline = block.timestamp + 30 seconds; +\`\`\` + +πŸ‘¨β€πŸ« Smart contracts can't execute automatically, you always need to have a transaction execute to change state. Because of this, you will need to have an \`execute()\` function that _anyone_ can call, just once, after the \`deadline\` has expired. + +> πŸ‘©β€πŸ’» Write your \`execute()\` function and test it with the \`Debug Contracts\` tab + +> Check the \`ExampleExternalContract.sol\` for the bool you can use to test if it has been completed or not. But do not edit the \`ExampleExternalContract.sol\` as it can slow the auto grading. + +If the \`address(this).balance\` of the contract is over the \`threshold\` by the \`deadline\`, you will want to call: \`exampleExternalContract.complete{value: address(this).balance}()\` + +If the balance is less than the \`threshold\`, you want to set a \`openForWithdraw\` bool to \`true\` which will allow users to \`withdraw()\` their funds. + +### Timing + +You'll have 30 seconds after deploying until the deadline is reached, you can adjust this in the contract. + +> πŸ‘©β€πŸ’» Create a \`timeLeft()\` function including \`public view returns (uint256)\` that returns how much time is left. + +⚠️ Be careful! If \`block.timestamp >= deadline\` you want to \`return 0;\` + +⏳ _"Time Left"_ will only update if a transaction occurs. You can see the time update by getting funds from the faucet button in navbar just to trigger a new block. + +![stakerUI](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/7d85badb-3ea3-4f3c-b5f8-43d5b64f6714) + +> πŸ‘©β€πŸ’» You can call \`yarn deploy --reset\` any time you want a fresh contract, it will get re-deployed even if there are no changes on it. +> You may need it when you want to reload the _"Time Left"_ of your tests. + +Your \`Staker UI\` tab should be almost done and working at this point. + +--- + +### πŸ₯… Goals + +- [ ] Can you see \`timeLeft\` counting down in the \`Staker UI\` tab when you trigger a transaction with the faucet button? +- [ ] If enough ETH is staked by the deadline, does your \`execute()\` function correctly call \`complete()\` and stake the ETH? +- [ ] If the threshold isn't met by the deadline, are you able to \`withdraw()\` your funds? + +--- + +## Checkpoint 3: πŸ’΅ Receive Function / UX πŸ™Ž + +πŸŽ€ To improve the user experience, set your contract up so it accepts ETH sent to it and calls \`stake()\`. You will use what is called the \`receive()\` function. + +> Use the [receive()](https://docs.soliditylang.org/en/v0.8.9/contracts.html?highlight=receive#receive-ether-function) function in solidity to "catch" ETH sent to the contract and call \`stake()\` to update \`balances\`. + +--- + +### πŸ₯… Goals + +- [ ] If you send ETH directly to the contract address does it update your \`balance\` and the \`balance\` of the contract? + +--- + +### βš”οΈ Side Quests + +- [ ] Can \`execute()\` get called more than once, and is that okay? +- [ ] Can you stake and withdraw freely after the \`deadline\`, and is that okay? +- [ ] What are other implications of _anyone_ being able to withdraw for someone? + +--- + +### 🐸 It's a trap! + +- [ ] Make sure funds can't get trapped in the contract! **Try sending funds after you have executed! What happens?** +- [ ] Try to create a [modifier](https://solidity-by-example.org/function-modifier/) called \`notCompleted\`. It will check that \`ExampleExternalContract\` is not completed yet. Use it to protect your \`execute\` and \`withdraw\` functions. + +### ⚠️ Test it! + +- Now is a good time to run \`yarn test\` to run the automated testing function. It will test that you hit the core checkpoints. You are looking for all green checkmarks and passing tests! + +--- + +## Checkpoint 4: πŸ’Ύ Deploy your contract! πŸ›° + +πŸ“‘ Edit the \`defaultNetwork\` to [your choice of public EVM networks](https://ethereum.org/en/developers/docs/networks/) in \`packages/hardhat/hardhat.config.ts\` + +πŸ” You will need to generate a **deployer address** using \`yarn generate\` This creates a mnemonic and saves it locally. + +πŸ‘©β€πŸš€ Use \`yarn account\` to view your deployer account balances. + +⛽️ You will need to send ETH to your deployer address with your wallet, or get it from a public faucet of your chosen network. + +> πŸ“ If you plan on submitting this challenge, be sure to set your \`deadline\` to at least \`block.timestamp + 72 hours\` + +πŸš€ Run \`yarn deploy\` to deploy your smart contract to a public network (selected in \`hardhat.config.ts\`) + +> πŸ’¬ Hint: You can set the \`defaultNetwork\` in \`hardhat.config.ts\` to \`sepolia\` or \`optimismSepolia\` **OR** you can \`yarn deploy --network sepolia\` or \`yarn deploy --network optimismSepolia\`. + +![allStakings-blockFrom](https://github.com/scaffold-eth/se-2-challenges/assets/55535804/04725dc8-4a8d-4089-ba82-90f9b94bfbda) + +> πŸ’¬ Hint: For faster loading of your _"Stake Events"_ page, consider updating the \`fromBlock\` passed to \`useScaffoldEventHistory\` in [\`packages/nextjs/app/stakings/page.tsx\`](https://github.com/scaffold-eth/se-2-challenges/blob/challenge-1-decentralized-staking/packages/nextjs/app/stakings/page.tsx) to \`blocknumber - 10\` at which your contract was deployed. Example: \`fromBlock: 3750241n\` (where \`n\` represents its a [BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt)). To find this blocknumber, search your contract's address on Etherscan and find the \`Contract Creation\` transaction line. + +--- + +## Checkpoint 5: 🚒 Ship your frontend! 🚁 + +✏️ Edit your frontend config in \`packages/nextjs/scaffold.config.ts\` to change the \`targetNetwork\` to \`chains.sepolia\` (or \`chains.optimismSepolia\` if you deployed to OP Sepolia) + +πŸ’» View your frontend at http://localhost:3000/staker-ui and verify you see the correct network. + +πŸ“‘ When you are ready to ship the frontend app... + +πŸ“¦ Run \`yarn vercel\` to package up your frontend and deploy. + +> Follow the steps to deploy to Vercel. Once you log in (email, github, etc), the default options should work. It'll give you a public URL. + +> If you want to redeploy to the same production URL you can run \`yarn vercel --prod\`. If you omit the \`--prod\` flag it will deploy it to a preview/test URL. + +> 🦊 Since we have deployed to a public testnet, you will now need to connect using a wallet you own or use a burner wallet. By default πŸ”₯ \`burner wallets\` are only available on \`hardhat\` . You can enable them on every chain by setting \`onlyLocalBurnerWallet: false\` in your frontend config (\`scaffold.config.ts\` in \`packages/nextjs/\`) + +#### Configuration of Third-Party Services for Production-Grade Apps. + +By default, πŸ— Scaffold-ETH 2 provides predefined API keys for popular services such as Alchemy and Etherscan. This allows you to begin developing and testing your applications more easily, avoiding the need to register for these services. +This is great to complete your **SpeedRunEthereum**. + +For production-grade applications, it's recommended to obtain your own API keys (to prevent rate limiting issues). You can configure these at: + +- πŸ”·\`ALCHEMY_API_KEY\` variable in \`packages/hardhat/.env\` and \`packages/nextjs/.env.local\`. You can create API keys from the [Alchemy dashboard](https://dashboard.alchemy.com/). + +- πŸ“ƒ\`ETHERSCAN_API_KEY\` variable in \`packages/hardhat/.env\` with your generated API key. You can get your key [here](https://etherscan.io/myapikey). + +> πŸ’¬ Hint: It's recommended to store env's for nextjs in Vercel/system env config for live apps and use .env.local for local testing. + +--- + +## Checkpoint 6: πŸ“œ Contract Verification + +Run the \`yarn verify --network your_network\` command to verify your contracts on etherscan πŸ›° + +πŸ‘‰ Search this address on [Sepolia Etherscan](https://sepolia.etherscan.io/) (or [Optimism Sepolia Etherscan](https://sepolia-optimism.etherscan.io/) if you deployed to OP Sepolia) to get the URL you submit to πŸƒβ€β™€οΈ[SpeedRunEthereum.com](https://speedrunethereum.com). + +--- + +> πŸƒ Head to your next challenge [here](https://speedrunethereum.com). + +> πŸ’¬ Problems, questions, comments on the stack? Post them to the [πŸ— scaffold-eth developers chat](https://t.me/joinchat/F7nCRK3kI93PoCOk) +`; \ No newline at end of file diff --git a/extension/packages/hardhat/contracts/ExampleExternalContract.sol b/extension/packages/hardhat/contracts/ExampleExternalContract.sol new file mode 100644 index 00000000..e37b3f15 --- /dev/null +++ b/extension/packages/hardhat/contracts/ExampleExternalContract.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; //Do not change the solidity version as it negativly impacts submission grading + +contract ExampleExternalContract { + bool public completed; + + function complete() public payable { + completed = true; + } +} diff --git a/extension/packages/hardhat/contracts/Staker.sol b/extension/packages/hardhat/contracts/Staker.sol new file mode 100644 index 00000000..932145d6 --- /dev/null +++ b/extension/packages/hardhat/contracts/Staker.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.20; //Do not change the solidity version as it negativly impacts submission grading + +import "hardhat/console.sol"; +import "./ExampleExternalContract.sol"; + +contract Staker { + ExampleExternalContract public exampleExternalContract; + + constructor(address exampleExternalContractAddress) { + exampleExternalContract = ExampleExternalContract( + exampleExternalContractAddress + ); + } + + // Collect funds in a payable `stake()` function and track individual `balances` with a mapping: + // (Make sure to add a `Stake(address,uint256)` event and emit it for the frontend `All Stakings` tab to display) + + // After some `deadline` allow anyone to call an `execute()` function + // If the deadline has passed and the threshold is met, it should call `exampleExternalContract.complete{value: address(this).balance}()` + + // If the `threshold` was not met, allow everyone to call a `withdraw()` function to withdraw their balance + + // Add a `timeLeft()` view function that returns the time left before the deadline for the frontend + + // Add the `receive()` special function that receives eth and calls stake() +} diff --git a/extension/packages/hardhat/deploy/00_deploy_example_external_contract.ts b/extension/packages/hardhat/deploy/00_deploy_example_external_contract.ts new file mode 100644 index 00000000..e6ecec90 --- /dev/null +++ b/extension/packages/hardhat/deploy/00_deploy_example_external_contract.ts @@ -0,0 +1,35 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; + +/** + * Deploys a contract named "YourContract" using the deployer account and + * constructor arguments set to the deployer address + * + * @param hre HardhatRuntimeEnvironment object. + */ +const deployExampleExternalContract: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + /* + On localhost, the deployer account is the one that comes with Hardhat, which is already funded. + + When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account + should have sufficient balance to pay for the gas fees for contract creation. + + You can generate a random account with `yarn generate` which will fill DEPLOYER_PRIVATE_KEY + with a random private key in the .env file (then used on hardhat.config.ts) + You can run the `yarn account` command to check your balance in every network. + */ + const { deployer } = await hre.getNamedAccounts(); + const { deploy } = hre.deployments; + + await deploy("ExampleExternalContract", { + from: deployer, + log: true, + // autoMine: can be passed to the deploy function to make the deployment process faster on local networks by + // automatically mining the contract deployment transaction. There is no effect on live networks. + autoMine: true, + }); +}; + +export default deployExampleExternalContract; + +deployExampleExternalContract.tags = ["ExampleExternalContract"]; diff --git a/extension/packages/hardhat/deploy/01_deploy_staker.ts b/extension/packages/hardhat/deploy/01_deploy_staker.ts new file mode 100644 index 00000000..8ff607b5 --- /dev/null +++ b/extension/packages/hardhat/deploy/01_deploy_staker.ts @@ -0,0 +1,38 @@ +import { HardhatRuntimeEnvironment } from "hardhat/types"; +import { DeployFunction } from "hardhat-deploy/types"; + +/** + * Deploys a contract named "Staker" using the deployer account and + * constructor arguments set to the deployer address + * + * @param hre HardhatRuntimeEnvironment object. + */ +const deployStaker: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + /* + On localhost, the deployer account is the one that comes with Hardhat, which is already funded. + + When deploying to live networks (e.g `yarn deploy --network goerli`), the deployer account + should have sufficient balance to pay for the gas fees for contract creation. + + You can generate a random account with `yarn generate` which will fill DEPLOYER_PRIVATE_KEY + with a random private key in the .env file (then used on hardhat.config.ts) + You can run the `yarn account` command to check your balance in every network. + */ + const { deployer } = await hre.getNamedAccounts(); + const { deploy, get } = hre.deployments; + const exampleExternalContract = await get("ExampleExternalContract"); + + await deploy("Staker", { + from: deployer, + // Contract constructor arguments + args: [exampleExternalContract.address], + log: true, + // autoMine: can be passed to the deploy function to make the deployment process faster on local networks by + // automatically mining the contract deployment transaction. There is no effect on live networks. + autoMine: true, + }); +}; + +export default deployStaker; + +deployStaker.tags = ["Staker"]; diff --git a/extension/packages/hardhat/test/Challenge1.ts b/extension/packages/hardhat/test/Challenge1.ts new file mode 100644 index 00000000..0569a41d --- /dev/null +++ b/extension/packages/hardhat/test/Challenge1.ts @@ -0,0 +1,149 @@ +// +// This script executes when you run 'yarn test' +// +import { ethers, network } from "hardhat"; +import { expect } from "chai"; +import { ExampleExternalContract, Staker } from "../typechain-types"; + +describe("🚩 Challenge 1: πŸ” Decentralized Staking App", function () { + let exampleExternalContract: ExampleExternalContract; + let stakerContract: Staker; + + describe("Staker", function () { + const contractAddress = process.env.CONTRACT_ADDRESS; + + let contractArtifact: string; + if (contractAddress) { + // For the autograder. + contractArtifact = `contracts/download-${contractAddress}.sol:Staker`; + } else { + contractArtifact = "contracts/Staker.sol:Staker"; + } + + it("Should deploy ExampleExternalContract", async function () { + const ExampleExternalContract = await ethers.getContractFactory("ExampleExternalContract"); + exampleExternalContract = await ExampleExternalContract.deploy(); + }); + it("Should deploy Staker", async function () { + const Staker = await ethers.getContractFactory(contractArtifact); + stakerContract = (await Staker.deploy(await exampleExternalContract.getAddress())) as Staker; + console.log("\t", "πŸ›° Staker contract deployed on", await stakerContract.getAddress()); + }); + describe("stake()", function () { + it("Balance should go up when you stake()", async function () { + const [owner] = await ethers.getSigners(); + + console.log("\t", " πŸ§‘β€πŸ« Tester Address: ", owner.address); + + const startingBalance = await stakerContract.balances(owner.address); + console.log("\t", " βš–οΈ Starting balance: ", Number(startingBalance)); + + console.log("\t", " πŸ”¨ Staking..."); + const stakeResult = await stakerContract.stake({ value: ethers.parseEther("0.001") }); + console.log("\t", " 🏷 stakeResult: ", stakeResult.hash); + + console.log("\t", " ⏳ Waiting for confirmation..."); + const txResult = await stakeResult.wait(); + expect(txResult?.status).to.equal(1); + + const newBalance = await stakerContract.balances(owner.address); + console.log("\t", " πŸ”Ž New balance: ", ethers.formatEther(newBalance)); + expect(newBalance).to.equal(startingBalance + ethers.parseEther("0.001")); + }); + + if (process.env.CONTRACT_ADDRESS) { + console.log( + " 🀷 since we will run this test on a live contract this is as far as the automated tests will go...", + ); + } else { + it("If enough is staked and time has passed, you should be able to complete", async function () { + const timeLeft1 = await stakerContract.timeLeft(); + console.log("\t", "⏱ There should be some time left: ", Number(timeLeft1)); + expect(Number(timeLeft1)).to.greaterThan(0); + + console.log("\t", " πŸš€ Staking a full eth!"); + const stakeResult = await stakerContract.stake({ value: ethers.parseEther("1") }); + console.log("\t", " 🏷 stakeResult: ", stakeResult.hash); + + console.log("\t", " βŒ›οΈ fast forward time..."); + await network.provider.send("evm_increaseTime", [72 * 3600]); + await network.provider.send("evm_mine"); + + const timeLeft2 = await stakerContract.timeLeft(); + console.log("\t", "⏱ Time should be up now: ", Number(timeLeft2)); + expect(Number(timeLeft2)).to.equal(0); + + console.log("\t", " πŸŽ‰ calling execute"); + const execResult = await stakerContract.execute(); + console.log("\t", " 🏷 execResult: ", execResult.hash); + + const result = await exampleExternalContract.completed(); + console.log("\t", " πŸ₯ complete: ", result); + expect(result).to.equal(true); + }); + + it("Should redeploy Staker, stake, not get enough, and withdraw", async function () { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [owner, secondAccount] = await ethers.getSigners(); + + const ExampleExternalContract = await ethers.getContractFactory("ExampleExternalContract"); + exampleExternalContract = await ExampleExternalContract.deploy(); + const exampleExternalContractAddress = await exampleExternalContract.getAddress(); + + const Staker = await ethers.getContractFactory("Staker"); + + stakerContract = await Staker.deploy(exampleExternalContractAddress); + + console.log("\t", " πŸ”¨ Staking..."); + const stakeResult = await stakerContract.connect(secondAccount).stake({ + value: ethers.parseEther("0.001"), + }); + console.log("\t", " 🏷 stakeResult: ", stakeResult.hash); + + console.log("\t", " ⏳ Waiting for confirmation..."); + const txResult = await stakeResult.wait(); + expect(txResult?.status).to.equal(1); + + console.log("\t", " βŒ›οΈ fast forward time..."); + await network.provider.send("evm_increaseTime", [72 * 3600]); + await network.provider.send("evm_mine"); + + console.log("\t", " πŸŽ‰ calling execute"); + const execResult = await stakerContract.execute(); + console.log("\t", " 🏷 execResult: ", execResult.hash); + + const result = await exampleExternalContract.completed(); + console.log("\t", " πŸ₯ complete should be false: ", result); + expect(result).to.equal(false); + + const startingBalance = await ethers.provider.getBalance(secondAccount.address); + //console.log("startingBalance before withdraw", ethers.formatEther(startingBalance)) + + console.log("\t", " πŸ’΅ calling withdraw"); + const withdrawResult = await stakerContract.connect(secondAccount).withdraw(); + console.log("\t", " 🏷 withdrawResult: ", withdrawResult.hash); + + // need to account for the gas cost from calling withdraw + const tx = await ethers.provider.getTransaction(withdrawResult.hash); + + if (!tx) { + throw new Error("Cannot resolve transaction"); + } + + const receipt = await ethers.provider.getTransactionReceipt(withdrawResult.hash); + + if (!receipt) { + throw new Error("Cannot resolve receipt"); + } + + const gasCost = tx.gasPrice * receipt.gasUsed; + + const endingBalance = await ethers.provider.getBalance(secondAccount.address); + //console.log("endingBalance after withdraw", ethers.formatEther(endingBalance)) + + expect(endingBalance).to.equal(startingBalance + ethers.parseEther("0.001") - gasCost); + }); + } + }); + }); +}); diff --git a/extension/packages/nextjs/app/layout.tsx.args.mjs b/extension/packages/nextjs/app/layout.tsx.args.mjs new file mode 100644 index 00000000..32608a72 --- /dev/null +++ b/extension/packages/nextjs/app/layout.tsx.args.mjs @@ -0,0 +1,4 @@ +export const metadata = { + title: "Challenge #1 | SpeedRunEthereum", + description: "Built with πŸ— Scaffold-ETH 2", +}; \ No newline at end of file diff --git a/extension/packages/nextjs/app/page.tsx.args.mjs b/extension/packages/nextjs/app/page.tsx.args.mjs new file mode 100644 index 00000000..c0227500 --- /dev/null +++ b/extension/packages/nextjs/app/page.tsx.args.mjs @@ -0,0 +1,40 @@ +export const imports = `import Image from "next/image";`; + +export const description = ` +
+
+

+ SpeedRunEthereum + Challenge #1: πŸ” Decentralized Staking App +

+
+ challenge banner +
+

+ 🦸 A superpower of Ethereum is allowing you, the builder, to create a simple set of rules that an + adversarial group of players can use to work together. In this challenge, you create a decentralized + application where users can coordinate a group funding effort. If the users cooperate, the money is + collected in a second smart contract. If they defect, the worst that can happen is everyone gets their + money back. The users only have to trust the code. +

+

+ 🌟 The final deliverable is deploying a Dapp that lets users send ether to a contract and stake if the + conditions are met, then deploy your app to a public webserver. Submit the url on{" "} + + SpeedRunEthereum.com + {" "} + ! +

+
+
+
+
+`; + +export const externalExtensionName = "SpeedRunEthereum Challenge #1"; \ No newline at end of file diff --git a/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx b/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx new file mode 100644 index 00000000..b1c52605 --- /dev/null +++ b/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx @@ -0,0 +1,53 @@ +import { useCallback, useState } from "react"; +import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; +import { useGlobalState } from "~~/services/store/store"; + +type TBalanceProps = { + value?: string; + className?: string; +}; + +/** + * Display (ETH & USD) value for the input value provided. + */ +export const ETHToPrice = ({ value, className = "" }: TBalanceProps) => { + const [isEthBalance, setIsEthBalance] = useState(true); + const { targetNetwork } = useTargetNetwork(); + const price = useGlobalState(state => state.nativeCurrencyPrice); + + const onToggleBalance = useCallback(() => { + if (price > 0) { + setIsEthBalance(!isEthBalance); + } + }, [isEthBalance, price]); + + if (!value) { + return ( +
+
+
+
+
+ ); + } + return ( + + ); +}; diff --git a/extension/packages/nextjs/app/staker-ui/_components/StakeContractInteraction.tsx b/extension/packages/nextjs/app/staker-ui/_components/StakeContractInteraction.tsx new file mode 100644 index 00000000..217b6452 --- /dev/null +++ b/extension/packages/nextjs/app/staker-ui/_components/StakeContractInteraction.tsx @@ -0,0 +1,139 @@ +"use client"; + +import { ETHToPrice } from "./EthToPrice"; +import humanizeDuration from "humanize-duration"; +import { formatEther, parseEther } from "viem"; +import { useAccount } from "wagmi"; +import { Address } from "~~/components/scaffold-eth"; +import { useDeployedContractInfo, useScaffoldReadContract, useScaffoldWriteContract } from "~~/hooks/scaffold-eth"; +import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; +import { useWatchBalance } from "~~/hooks/scaffold-eth/useWatchBalance"; + +export const StakeContractInteraction = ({ address }: { address?: string }) => { + const { address: connectedAddress } = useAccount(); + const { data: StakerContract } = useDeployedContractInfo("Staker"); + const { data: ExampleExternalContact } = useDeployedContractInfo("ExampleExternalContract"); + const { data: stakerContractBalance } = useWatchBalance({ + address: StakerContract?.address, + }); + const { data: exampleExternalContractBalance } = useWatchBalance({ + address: ExampleExternalContact?.address, + }); + + const { targetNetwork } = useTargetNetwork(); + + // Contract Read Actions + const { data: threshold } = useScaffoldReadContract({ + contractName: "Staker", + functionName: "threshold", + watch: true, + }); + const { data: timeLeft } = useScaffoldReadContract({ + contractName: "Staker", + functionName: "timeLeft", + watch: true, + }); + const { data: myStake } = useScaffoldReadContract({ + contractName: "Staker", + functionName: "balances", + args: [connectedAddress], + watch: true, + }); + const { data: isStakingCompleted } = useScaffoldReadContract({ + contractName: "ExampleExternalContract", + functionName: "completed", + watch: true, + }); + + const { writeContractAsync } = useScaffoldWriteContract("Staker"); + + return ( +
+ {isStakingCompleted && ( +
+

+ {" "} + πŸŽ‰   Staking App triggered `ExampleExternalContract`   πŸŽ‰{" "} +

+
+ +

staked !!

+
+
+ )} +
+
+

Staker Contract

+
+
+
+
+

Time Left

+

{timeLeft ? `${humanizeDuration(Number(timeLeft) * 1000)}` : 0}

+
+
+

You Staked

+ + {myStake ? formatEther(myStake) : 0} {targetNetwork.nativeCurrency.symbol} + +
+
+
+

Total Staked

+
+ {} + / + {} +
+
+
+
+ + +
+ +
+
+
+ ); +}; diff --git a/extension/packages/nextjs/app/staker-ui/_components/index.tsx b/extension/packages/nextjs/app/staker-ui/_components/index.tsx new file mode 100644 index 00000000..98585a37 --- /dev/null +++ b/extension/packages/nextjs/app/staker-ui/_components/index.tsx @@ -0,0 +1,2 @@ +export * from "./EthToPrice"; +export * from "./StakeContractInteraction"; diff --git a/extension/packages/nextjs/app/staker-ui/page.tsx b/extension/packages/nextjs/app/staker-ui/page.tsx new file mode 100644 index 00000000..44c4c87f --- /dev/null +++ b/extension/packages/nextjs/app/staker-ui/page.tsx @@ -0,0 +1,12 @@ +"use client"; + +import { StakeContractInteraction } from "./_components"; +import type { NextPage } from "next"; +import { useDeployedContractInfo } from "~~/hooks/scaffold-eth"; + +const StakerUI: NextPage = () => { + const { data: StakerContract } = useDeployedContractInfo("Staker"); + return ; +}; + +export default StakerUI; diff --git a/extension/packages/nextjs/app/stakings/page.tsx b/extension/packages/nextjs/app/stakings/page.tsx new file mode 100644 index 00000000..3c2c3f10 --- /dev/null +++ b/extension/packages/nextjs/app/stakings/page.tsx @@ -0,0 +1,62 @@ +"use client"; + +import type { NextPage } from "next"; +import { formatEther } from "viem"; +import { Address } from "~~/components/scaffold-eth"; +import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth"; + +const Stakings: NextPage = () => { + const { data: stakeEvents, isLoading } = useScaffoldEventHistory({ + contractName: "Staker", + eventName: "Stake", + fromBlock: 0n, + }); + + if (isLoading) + return ( +
+ +
+ ); + return ( +
+
+

+ All Staking Events +

+
+
+ + + + + + + + + {!stakeEvents || stakeEvents.length === 0 ? ( + + + + ) : ( + stakeEvents?.map((event, index) => { + return ( + + + + + ); + }) + )} + +
FromValue
+ No events found +
+
+
{formatEther(event.args?.[1] || 0n)} ETH
+
+
+ ); +}; + +export default Stakings; diff --git a/extension/packages/nextjs/components/Header.tsx.args.mjs b/extension/packages/nextjs/components/Header.tsx.args.mjs new file mode 100644 index 00000000..375417d9 --- /dev/null +++ b/extension/packages/nextjs/components/Header.tsx.args.mjs @@ -0,0 +1,15 @@ +export const menuIconImports = `import { CircleStackIcon, InboxStackIcon} from "@heroicons/react/24/outline";`; + +export const menuObjects = `{ + label: "Staker UI", + href: "/staker-ui", + icon: , + }, + { + label: "Stake Events", + href: "/stakings", + icon: , + }`; + +export const logoTitle = "SRE Challenges"; +export const logoSubtitle = "#1 Decentralized Staking App"; \ No newline at end of file diff --git a/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs b/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs new file mode 100644 index 00000000..d33bccd8 --- /dev/null +++ b/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs @@ -0,0 +1 @@ +export const globalClassNames = "font-space-grotesk"; \ No newline at end of file diff --git a/extension/packages/nextjs/package.json b/extension/packages/nextjs/package.json new file mode 100644 index 00000000..c94b30c8 --- /dev/null +++ b/extension/packages/nextjs/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "humanize-duration": "^3.28.0" + } +} \ No newline at end of file diff --git a/extension/packages/nextjs/public/hero.png b/extension/packages/nextjs/public/hero.png new file mode 100644 index 0000000000000000000000000000000000000000..80b0ea453cf0c6db9198555c4c9def58e3edd91e GIT binary patch literal 32724 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 Jvd$@?2>``MmLmWF literal 0 HcmV?d00001 diff --git a/extension/packages/nextjs/styles/globals.css.args.mjs b/extension/packages/nextjs/styles/globals.css.args.mjs new file mode 100644 index 00000000..8c93b701 --- /dev/null +++ b/extension/packages/nextjs/styles/globals.css.args.mjs @@ -0,0 +1 @@ +export const globalImports = '@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");'; \ No newline at end of file diff --git a/extension/packages/nextjs/tailwind.config.js.args.mjs b/extension/packages/nextjs/tailwind.config.js.args.mjs new file mode 100644 index 00000000..b3c0628a --- /dev/null +++ b/extension/packages/nextjs/tailwind.config.js.args.mjs @@ -0,0 +1,68 @@ +export const lightTheme = { + primary: "#C8F5FF", + "primary-content": "#026262", + secondary: "#89d7e9", + "secondary-content": "#088484", + accent: "#026262", + "accent-content": "#E9FBFF", + neutral: "#088484", + "neutral-content": "#F0FCFF", + "base-100": "#F0FCFF", + "base-200": "#E1FAFF", + "base-300": "#C8F5FF", + "base-content": "#088484", + info: "#026262", + success: "#34EEB6", + warning: "#FFCF72", + error: "#FF8863", + + "--rounded-btn": "9999rem", + + ".tooltip": { + "--tooltip-tail": "6px" + }, + ".link": { + textUnderlineOffset: "2px" + }, + ".link:hover": { + opacity: "80%" + } +}; + +export const darkTheme = { + primary: "#026262", + "primary-content": "#C8F5FF", + secondary: "#107575", + "secondary-content": "#E9FBFF", + accent: "#C8F5FF", + "accent-content": "#088484", + neutral: "#E9FBFF", + "neutral-content": "#11ACAC", + "base-100": "#11ACAC", + "base-200": "#088484", + "base-300": "#026262", + "base-content": "#E9FBFF", + info: "#C8F5FF", + success: "#34EEB6", + warning: "#FFCF72", + error: "#FF8863", + + "--rounded-btn": "9999rem", + + ".tooltip": { + "--tooltip-tail": "6px", + "--tooltip-color": "oklch(var(--p))" + }, + ".link": { + textUnderlineOffset: "2px" + }, + ".link:hover": { + opacity: "80%" + } +}; + +export const extendTheme = { + fontFamily: { + "space-grotesk": ["Space Grotesk", "sans-serif"] + } +}; \ No newline at end of file diff --git a/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs b/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs new file mode 100644 index 00000000..5b045fca --- /dev/null +++ b/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs @@ -0,0 +1,2 @@ +export const titleTemplate = "%s | SpeedRunEthereum"; +export const thumbnailPath = "/thumbnail-challenge-1.png"; \ No newline at end of file From ecb26259c2739754cb1af4712e6e6ae11bf2e3f1 Mon Sep 17 00:00:00 2001 From: Damian Date: Wed, 4 Dec 2024 19:17:30 -0300 Subject: [PATCH 2/5] Change git clone to npx create-eth on README --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 74ece3d0..445347d2 100644 --- a/README.md +++ b/README.md @@ -25,10 +25,8 @@ Before you begin, you need to install the following tools: Then download the challenge to your computer and install dependencies by running: ```sh -git clone https://github.com/scaffold-eth/se-2-challenges.git challenge-1-decentralized-staking +npx create-eth@latest -e sre-challenge-1 challenge-1-decentralized-staking cd challenge-1-decentralized-staking -git checkout challenge-1-decentralized-staking -yarn install ``` > in the same terminal, start your local network (a blockchain emulator in your computer): From 5754043ec469ffc53e0bf96ef84382ad1bff3eb4 Mon Sep 17 00:00:00 2001 From: Damian Date: Wed, 4 Dec 2024 19:18:21 -0300 Subject: [PATCH 3/5] Add blank line at end of files --- extension/README.md.args.mjs | 4 +--- extension/packages/nextjs/app/layout.tsx.args.mjs | 2 +- extension/packages/nextjs/app/page.tsx.args.mjs | 2 +- extension/packages/nextjs/components/Header.tsx.args.mjs | 2 +- .../components/ScaffoldEthAppWithProviders.tsx.args.mjs | 2 +- extension/packages/nextjs/package.json | 2 +- extension/packages/nextjs/styles/globals.css.args.mjs | 2 +- extension/packages/nextjs/tailwind.config.js.args.mjs | 2 +- .../nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs | 2 +- 9 files changed, 9 insertions(+), 11 deletions(-) diff --git a/extension/README.md.args.mjs b/extension/README.md.args.mjs index 60bdd1f6..c29447b0 100644 --- a/extension/README.md.args.mjs +++ b/extension/README.md.args.mjs @@ -27,14 +27,12 @@ yarn chain > in a second terminal window, πŸ›° deploy your contract (locally): \`\`\`sh -cd challenge-1-decentralized-staking yarn deploy \`\`\` > in a third terminal window, start your πŸ“± frontend: \`\`\`sh -cd challenge-1-decentralized-staking yarn start \`\`\` @@ -230,4 +228,4 @@ Run the \`yarn verify --network your_network\` command to verify your contracts > πŸƒ Head to your next challenge [here](https://speedrunethereum.com). > πŸ’¬ Problems, questions, comments on the stack? Post them to the [πŸ— scaffold-eth developers chat](https://t.me/joinchat/F7nCRK3kI93PoCOk) -`; \ No newline at end of file +`; diff --git a/extension/packages/nextjs/app/layout.tsx.args.mjs b/extension/packages/nextjs/app/layout.tsx.args.mjs index 32608a72..d66c0094 100644 --- a/extension/packages/nextjs/app/layout.tsx.args.mjs +++ b/extension/packages/nextjs/app/layout.tsx.args.mjs @@ -1,4 +1,4 @@ export const metadata = { title: "Challenge #1 | SpeedRunEthereum", description: "Built with πŸ— Scaffold-ETH 2", -}; \ No newline at end of file +}; diff --git a/extension/packages/nextjs/app/page.tsx.args.mjs b/extension/packages/nextjs/app/page.tsx.args.mjs index c0227500..92b66c26 100644 --- a/extension/packages/nextjs/app/page.tsx.args.mjs +++ b/extension/packages/nextjs/app/page.tsx.args.mjs @@ -37,4 +37,4 @@ export const description = ` `; -export const externalExtensionName = "SpeedRunEthereum Challenge #1"; \ No newline at end of file +export const externalExtensionName = "SpeedRunEthereum Challenge #1"; diff --git a/extension/packages/nextjs/components/Header.tsx.args.mjs b/extension/packages/nextjs/components/Header.tsx.args.mjs index 375417d9..eb68be7e 100644 --- a/extension/packages/nextjs/components/Header.tsx.args.mjs +++ b/extension/packages/nextjs/components/Header.tsx.args.mjs @@ -12,4 +12,4 @@ export const menuObjects = `{ }`; export const logoTitle = "SRE Challenges"; -export const logoSubtitle = "#1 Decentralized Staking App"; \ No newline at end of file +export const logoSubtitle = "#1 Decentralized Staking App"; diff --git a/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs b/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs index d33bccd8..fca30389 100644 --- a/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs +++ b/extension/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx.args.mjs @@ -1 +1 @@ -export const globalClassNames = "font-space-grotesk"; \ No newline at end of file +export const globalClassNames = "font-space-grotesk"; diff --git a/extension/packages/nextjs/package.json b/extension/packages/nextjs/package.json index c94b30c8..a49265f6 100644 --- a/extension/packages/nextjs/package.json +++ b/extension/packages/nextjs/package.json @@ -2,4 +2,4 @@ "dependencies": { "humanize-duration": "^3.28.0" } -} \ No newline at end of file +} diff --git a/extension/packages/nextjs/styles/globals.css.args.mjs b/extension/packages/nextjs/styles/globals.css.args.mjs index 8c93b701..340ea399 100644 --- a/extension/packages/nextjs/styles/globals.css.args.mjs +++ b/extension/packages/nextjs/styles/globals.css.args.mjs @@ -1 +1 @@ -export const globalImports = '@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");'; \ No newline at end of file +export const globalImports = '@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&display=swap");'; diff --git a/extension/packages/nextjs/tailwind.config.js.args.mjs b/extension/packages/nextjs/tailwind.config.js.args.mjs index b3c0628a..912bcc9d 100644 --- a/extension/packages/nextjs/tailwind.config.js.args.mjs +++ b/extension/packages/nextjs/tailwind.config.js.args.mjs @@ -65,4 +65,4 @@ export const extendTheme = { fontFamily: { "space-grotesk": ["Space Grotesk", "sans-serif"] } -}; \ No newline at end of file +}; diff --git a/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs b/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs index 5b045fca..73699206 100644 --- a/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs +++ b/extension/packages/nextjs/utils/scaffold-eth/getMetadata.ts.args.mjs @@ -1,2 +1,2 @@ export const titleTemplate = "%s | SpeedRunEthereum"; -export const thumbnailPath = "/thumbnail-challenge-1.png"; \ No newline at end of file +export const thumbnailPath = "/thumbnail-challenge-1.png"; From b1c48d671cf74202bdc28b1e1ee01acfbbadde72 Mon Sep 17 00:00:00 2001 From: Damian Date: Thu, 5 Dec 2024 11:44:01 -0300 Subject: [PATCH 4/5] Fix native currency price --- .../packages/nextjs/app/staker-ui/_components/EthToPrice.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx b/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx index b1c52605..768b6660 100644 --- a/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx +++ b/extension/packages/nextjs/app/staker-ui/_components/EthToPrice.tsx @@ -13,7 +13,7 @@ type TBalanceProps = { export const ETHToPrice = ({ value, className = "" }: TBalanceProps) => { const [isEthBalance, setIsEthBalance] = useState(true); const { targetNetwork } = useTargetNetwork(); - const price = useGlobalState(state => state.nativeCurrencyPrice); + const price = useGlobalState(state => state.nativeCurrency.price); const onToggleBalance = useCallback(() => { if (price > 0) { From a95dcd7bad1c85f5af66e78787c4133f7019c364 Mon Sep 17 00:00:00 2001 From: Damian Date: Thu, 5 Dec 2024 11:44:26 -0300 Subject: [PATCH 5/5] Add missing @types/humanize-duration dev dependency --- extension/packages/nextjs/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extension/packages/nextjs/package.json b/extension/packages/nextjs/package.json index a49265f6..5102b066 100644 --- a/extension/packages/nextjs/package.json +++ b/extension/packages/nextjs/package.json @@ -1,5 +1,8 @@ { "dependencies": { "humanize-duration": "^3.28.0" + }, + "devDependencies": { + "@types/humanize-duration": "^3" } }