
Build SVG NFT dApp by Scaffold-Eth | Web3.0 dApp Dev 0x07
国内用户如需交流,可加微信:197626581.Authors: qiwihui, msfewHistory Articles List:Quickstart | Web3.0 dApp Dev 0x01Web3.0 dApp Developer Growth Path | Web3.0 dApp Dev 0x02Scaffold-Eth Quickstart | Web3.0 dApp Dev 0x03Get & Set Value 1.0 | Web3.0 dApp Dev 0x04Get & Set Value 2.0 | Web3.0 dApp Dev 0x05Get & Set Value 3.0 | Web3.0 dApp Dev 0x06loogies-svg-nft is a simple NFT minting and displaying project provided by scaffold-eth. In this tutorial, we will walk you through a step-by-step analysis and impleme...

RSS in Crypto@NonceGeekLab
Supported by NonceGeekLab <> PlayerLinkAttention: All articles by NonceGeekLab do not constitute any investment advice.PlayerLink: A Trustless Decentralized Web3-Oriented Service Aggregation Protocol. Through reliable, secure, and scalable technology, PlayerLink empowers billions to create and get a new service experience.NonceGeekLab: Focus on Crypto, the most interesting track in the world! https://github.com/WeLightProject/NonceGeekLabAuthors: msfew、leeduckgo、Erqi0x00 Key questionsGood que...

Get & Set Value 3.0 | Web3.0 dApp Dev 0x06
In PurposeHandler version 2.0, we learned to add permission control to functions via the require statement. Now we can add a real economy mechanism to it, so that the value of purpose is controlled by a real bidding auction mechanism!0x01 Add OwnerTo get the owner of a contract owner is a must-learn operation for newbies. The easiest way is to set a public owner variable and pass the _owner parameter in the constructor.pragma solidity >=0.8.0 <0.9.0; //SPDX-License-Identifier: MIT contra...
the Online Camp focusing on Web3.0 dApp Development.

Build SVG NFT dApp by Scaffold-Eth | Web3.0 dApp Dev 0x07
国内用户如需交流,可加微信:197626581.Authors: qiwihui, msfewHistory Articles List:Quickstart | Web3.0 dApp Dev 0x01Web3.0 dApp Developer Growth Path | Web3.0 dApp Dev 0x02Scaffold-Eth Quickstart | Web3.0 dApp Dev 0x03Get & Set Value 1.0 | Web3.0 dApp Dev 0x04Get & Set Value 2.0 | Web3.0 dApp Dev 0x05Get & Set Value 3.0 | Web3.0 dApp Dev 0x06loogies-svg-nft is a simple NFT minting and displaying project provided by scaffold-eth. In this tutorial, we will walk you through a step-by-step analysis and impleme...

RSS in Crypto@NonceGeekLab
Supported by NonceGeekLab <> PlayerLinkAttention: All articles by NonceGeekLab do not constitute any investment advice.PlayerLink: A Trustless Decentralized Web3-Oriented Service Aggregation Protocol. Through reliable, secure, and scalable technology, PlayerLink empowers billions to create and get a new service experience.NonceGeekLab: Focus on Crypto, the most interesting track in the world! https://github.com/WeLightProject/NonceGeekLabAuthors: msfew、leeduckgo、Erqi0x00 Key questionsGood que...

Get & Set Value 3.0 | Web3.0 dApp Dev 0x06
In PurposeHandler version 2.0, we learned to add permission control to functions via the require statement. Now we can add a real economy mechanism to it, so that the value of purpose is controlled by a real bidding auction mechanism!0x01 Add OwnerTo get the owner of a contract owner is a must-learn operation for newbies. The easiest way is to set a public owner variable and pass the _owner parameter in the constructor.pragma solidity >=0.8.0 <0.9.0; //SPDX-License-Identifier: MIT contra...
the Online Camp focusing on Web3.0 dApp Development.

Subscribe to Web3dAppDevCamp

Subscribe to Web3dAppDevCamp
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers


国内用户请加微信:19726581
Buidl a decentralized Staking dApp.
This example also corresponds to Challenge 0x01 in SpeedrunEthereum (an official Ethereum developer challenge):
https://speedrunethereum.com/challenge/decentralized-staking
An example of one of these completions can be found at:
Contract: https://rinkeby.etherscan.io/address/0x4707468C95558E9B2F339c2A41DAEF483Ce11104 dApp: https://duckgo_staking.surge.sh/
Staking, which translates to pledge, staking mining, or staking of interest, is the algorithm used to generate new blocks, and is derived from Proof of Stake.
If you're familiar with how Bitcoin works, you're probably familiar with Proof of Work (PoW). This mechanism allows transactions to be collected into blocks. These blocks are then linked together to create a blockchain.
国内用户请加微信:19726581
Buidl a decentralized Staking dApp.
This example also corresponds to Challenge 0x01 in SpeedrunEthereum (an official Ethereum developer challenge):
https://speedrunethereum.com/challenge/decentralized-staking
An example of one of these completions can be found at:
Contract: https://rinkeby.etherscan.io/address/0x4707468C95558E9B2F339c2A41DAEF483Ce11104 dApp: https://duckgo_staking.surge.sh/
Staking, which translates to pledge, staking mining, or staking of interest, is the algorithm used to generate new blocks, and is derived from Proof of Stake.
If you're familiar with how Bitcoin works, you're probably familiar with Proof of Work (PoW). This mechanism allows transactions to be collected into blocks. These blocks are then linked together to create a blockchain.
Specifically, miners compete to solve complex mathematical puzzles, and whoever solves the puzzle first is entitled to add the next block to the blockchain. Proof of workload has proven to be a very powerful mechanism to facilitate consensus in a decentralized manner. The problem is that this mechanism involves a lot of arbitrary computation. Miners are scrambling to solve the puzzle just to maintain network security and nothing else.
Moving on to proof of stake, the main idea is that participants can lock in tokens (their "pledged interest") and the protocol will randomly assign rights to one of them for verification of the next block at a given time interval. Usually, the probability of being selected is proportional to the number of tokens: the more tokens locked, the better the chances.

In the cryptocurrency market, mining has been gradually replaced by staking in recent years, with the benefit of lower power consumption and passive income than the former.
Some students may not have experience with web3 related development, so here is a speed run on your behalf to facilitate a quick introduction to the development on Ether.
Prerequisites
metamask Wallet
Environment
nodejs
yarn
git
vscode
Tech Stack
Framework: scaffold-eth
Frontend: react
Contract Development: hardhat
Step 1: Scaffolding
git clone https://github.com/scaffold-eth/scaffold-eth.git
cd scaffold-eth
yarn install
Step 2: Start a local network
cd scaffold-eth
yarn chain
Step 3: Deploy Smart Contracts
cd scaffold-eth
yarn deploy
Step 4: Open the front-end page
cd scaffold-eth
yarn start
Technology Stack
Top Level Technology Stack
solidity contract programming language
hardhat local development test chain
react front-end
etherseth api sdk
antd front-end components ui
Libraries & Components & Services
Eth-components
Eth-services
Command Line
Underlying Foundation
the graph
tenderly
etherscan
rpc
blocknative
L2/Sidechain Services
Arbitrum
Optimism
Graph Node
Examples
General
simple dao
Diamond Standard
Meta-Multi-Sig Wallet
Minimal Proxy
Minimum Viable Payment Channel
Push The Button - Multi-player Turn Based Game
Simple Stream
Token Allocator
Streaming Meta Multi Sig
DeFi
Bonding Curve
rTokens
Quadratic Funding
Uniswapper
Lender
Aave Flash Loans Intro
Aave Ape
DeFi Subgraphs
NFT
Simple NFT
Simple ERC-1155 NFT
Chainlink VRF NFT
Merkle Mint NFT
Nifty Viewer
NFT Auction
NFT Signature Based Auction
Security
Honeypot
Re-entrancy Attack
Denial of Service
Infrastructure
ChainLink
Layer2
Optimism Starter Pack
Optimism NFT
We all know that the most important part of dApp development is writing smart contracts, so let's analyze the basic format of a Staking contract.
Pledge (stake) a certain amount of tokens (threshold) within a certain time (deadline). After the expiration date, you can transfer (execute) the tokens to another contract, or withdraw (withdraw) the tokens.
So we abstracted out three key functions.
stake()
execute()
withdraw()
scaffold-eth also provides us with such a scaffold, just pull down the code and we will build on it step by step this time.
git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git
cd scaffold-eth-challenges
git checkout challenge-1-decentralized-staking
yarn install
Then open three terminal windows and execute the following three commands:
yarn start
yarn deploy --reset
Key point 1: Stake a certain amount of eth at a time.
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
mapping(address => uint256) public balances;
event Stake(address indexed staker, uint256 amount);
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
}
Key point 2, deploy the script to remove the constructor's parameters
// deploy/01_deploy_staker.js
// ....
await deploy('Staker', {
// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
from: deployer,
// args: [exampleExternalContract.address],
log: true,
});
//...
Key Point 3, Deployment
yarn deploy --reset
Key point 4, airdrop some test coins
Key point 5, test staking
The funds raised are transferred to another contract after certain conditions are met.
Key point 1, another contract
contract ExampleExternalContract {
bool public completed;
function complete() public payable {
completed = true;
}
}
It's simple, there is a flag to indicate whether it is finished or not.
Key point 2, the constructor
In the stake contract, to bring in this contract, there is a constructor.
ExampleExternalContract public exampleExternalContract;
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
Key point 3, initialize when deploying
// deploy/01_deploy_staker.js
// ....
await deploy('Staker', {
// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
from: deployer,
args: [exampleExternalContract.address],
log: true,
});
//...
Key Point 4, Staking Limit
uint256 public constant threshold = 1 ether;
Key point 5, transfer to the second contract.
function execute() public {
uint256 contractBalance = address(this).balance;
// check the contract has enough ETH to reach the treshold
require(contractBalance >= threshold, "Threshold not reached");
// Execute the external contract, transfer all the balance to the contract
// (bool sent, bytes memory data) = exampleExternalContract.complete{value: contractBalance}();
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete failed");
}
The final code is as follows
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
event Stake(address indexed staker, uint256 amount);
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
}
Deployment
yarn deploy --reset
Airdrop test coins
stake some coins reach the limit
test execute
Withdrawing the staked money is relatively simple - just transfer the money out.
function withdraw() public {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
The complete code is as follows
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
uint256 public deadline = block.timestamp + 30 seconds;
event Stake(address indexed sender, uint256 amount);
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete failed");
}
function withdraw() public {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
}
Deployment
yarn deploy --reset
Airdrop test coins
stake some coins
test withdraw
There are two criteria to judge here
The first is whether the time has been reached, and the other is whether the pledge has been completed.
Whether the first one is completed or not, just go directly to the mark of the other contract
modifier stakeNotCompleted() {
bool completed = exampleExternalContract.completed();
require(!completed, "staking process is already completed");
_;
}
Is the second one up to time?
The first is to have a deadline variable
uint256 public deadline = block.timestamp + 60 seconds;
Then there is also a timeLeft function
function timeLeft() public view returns (uint256 timeleft) {
if (block.timestamp >= deadline) {
return 0;
} else {
return deadline - block.timestamp;
}
}
Next is the deadlineReached function
modifier deadlineReached(bool requireReached) {
uint256 timeRemaining = timeLeft();
if (requireReached) {
require(timeRemaining == 0, "deadline is not reached yet");
} else {
require(timeRemaining > 0, "deadline has already reached");
}
_;
}
How to modify these functions
stake
function stake() public payable deadlineReached(false) stakeNotCompleted {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
execute function
function execute() public stakeNotCompleted deadlineReached(false) {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
Functions that can be called by external contracts
receive() external payable {
stake();
}
The final code is as follows:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
event Stake(address indexed staker, uint256 amount);
uint256 public deadline = block.timestamp + 60 seconds;
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
modifier stakeNotCompleted() {
bool completed = exampleExternalContract.completed();
require(!completed, "staking process is already completed");
_;
}
modifier deadlineReached(bool requireReached) {
uint256 timeRemaining = timeLeft();
if (requireReached) {
require(timeRemaining == 0, "deadline is not reached yet");
} else {
require(timeRemaining > 0, "deadline has already reached");
}
_;
}
function timeLeft() public view returns (uint256 timeleft) {
if (block.timestamp >= deadline) {
return 0;
} else {
return deadline - block.timestamp;
}
}
function stake() public payable deadlineReached(false) stakeNotCompleted {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public stakeNotCompleted deadlineReached(false) {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
function withdraw() public deadlineReached(true) stakeNotCompleted {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
receive() external payable {
stake();
}
}
Deployment
yarn deploy --reset
Testing
Specifically, miners compete to solve complex mathematical puzzles, and whoever solves the puzzle first is entitled to add the next block to the blockchain. Proof of workload has proven to be a very powerful mechanism to facilitate consensus in a decentralized manner. The problem is that this mechanism involves a lot of arbitrary computation. Miners are scrambling to solve the puzzle just to maintain network security and nothing else.
Moving on to proof of stake, the main idea is that participants can lock in tokens (their "pledged interest") and the protocol will randomly assign rights to one of them for verification of the next block at a given time interval. Usually, the probability of being selected is proportional to the number of tokens: the more tokens locked, the better the chances.

In the cryptocurrency market, mining has been gradually replaced by staking in recent years, with the benefit of lower power consumption and passive income than the former.
Some students may not have experience with web3 related development, so here is a speed run on your behalf to facilitate a quick introduction to the development on Ether.
Prerequisites
metamask Wallet
Environment
nodejs
yarn
git
vscode
Tech Stack
Framework: scaffold-eth
Frontend: react
Contract Development: hardhat
Step 1: Scaffolding
git clone https://github.com/scaffold-eth/scaffold-eth.git
cd scaffold-eth
yarn install
Step 2: Start a local network
cd scaffold-eth
yarn chain
Step 3: Deploy Smart Contracts
cd scaffold-eth
yarn deploy
Step 4: Open the front-end page
cd scaffold-eth
yarn start
Technology Stack
Top Level Technology Stack
solidity contract programming language
hardhat local development test chain
react front-end
etherseth api sdk
antd front-end components ui
Libraries & Components & Services
Eth-components
Eth-services
Command Line
Underlying Foundation
the graph
tenderly
etherscan
rpc
blocknative
L2/Sidechain Services
Arbitrum
Optimism
Graph Node
Examples
General
simple dao
Diamond Standard
Meta-Multi-Sig Wallet
Minimal Proxy
Minimum Viable Payment Channel
Push The Button - Multi-player Turn Based Game
Simple Stream
Token Allocator
Streaming Meta Multi Sig
DeFi
Bonding Curve
rTokens
Quadratic Funding
Uniswapper
Lender
Aave Flash Loans Intro
Aave Ape
DeFi Subgraphs
NFT
Simple NFT
Simple ERC-1155 NFT
Chainlink VRF NFT
Merkle Mint NFT
Nifty Viewer
NFT Auction
NFT Signature Based Auction
Security
Honeypot
Re-entrancy Attack
Denial of Service
Infrastructure
ChainLink
Layer2
Optimism Starter Pack
Optimism NFT
We all know that the most important part of dApp development is writing smart contracts, so let's analyze the basic format of a Staking contract.
Pledge (stake) a certain amount of tokens (threshold) within a certain time (deadline). After the expiration date, you can transfer (execute) the tokens to another contract, or withdraw (withdraw) the tokens.
So we abstracted out three key functions.
stake()
execute()
withdraw()
scaffold-eth also provides us with such a scaffold, just pull down the code and we will build on it step by step this time.
git clone https://github.com/scaffold-eth/scaffold-eth-challenges.git
cd scaffold-eth-challenges
git checkout challenge-1-decentralized-staking
yarn install
Then open three terminal windows and execute the following three commands:
yarn start
yarn deploy --reset
Key point 1: Stake a certain amount of eth at a time.
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
mapping(address => uint256) public balances;
event Stake(address indexed staker, uint256 amount);
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
}
Key point 2, deploy the script to remove the constructor's parameters
// deploy/01_deploy_staker.js
// ....
await deploy('Staker', {
// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
from: deployer,
// args: [exampleExternalContract.address],
log: true,
});
//...
Key Point 3, Deployment
yarn deploy --reset
Key point 4, airdrop some test coins
Key point 5, test staking
The funds raised are transferred to another contract after certain conditions are met.
Key point 1, another contract
contract ExampleExternalContract {
bool public completed;
function complete() public payable {
completed = true;
}
}
It's simple, there is a flag to indicate whether it is finished or not.
Key point 2, the constructor
In the stake contract, to bring in this contract, there is a constructor.
ExampleExternalContract public exampleExternalContract;
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
Key point 3, initialize when deploying
// deploy/01_deploy_staker.js
// ....
await deploy('Staker', {
// Learn more about args here: https://www.npmjs.com/package/hardhat-deploy#deploymentsdeploy
from: deployer,
args: [exampleExternalContract.address],
log: true,
});
//...
Key Point 4, Staking Limit
uint256 public constant threshold = 1 ether;
Key point 5, transfer to the second contract.
function execute() public {
uint256 contractBalance = address(this).balance;
// check the contract has enough ETH to reach the treshold
require(contractBalance >= threshold, "Threshold not reached");
// Execute the external contract, transfer all the balance to the contract
// (bool sent, bytes memory data) = exampleExternalContract.complete{value: contractBalance}();
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete failed");
}
The final code is as follows
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
event Stake(address indexed staker, uint256 amount);
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
}
Deployment
yarn deploy --reset
Airdrop test coins
stake some coins reach the limit
test execute
Withdrawing the staked money is relatively simple - just transfer the money out.
function withdraw() public {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
The complete code is as follows
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
uint256 public deadline = block.timestamp + 30 seconds;
event Stake(address indexed sender, uint256 amount);
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
function stake() public payable {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete failed");
}
function withdraw() public {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
}
Deployment
yarn deploy --reset
Airdrop test coins
stake some coins
test withdraw
There are two criteria to judge here
The first is whether the time has been reached, and the other is whether the pledge has been completed.
Whether the first one is completed or not, just go directly to the mark of the other contract
modifier stakeNotCompleted() {
bool completed = exampleExternalContract.completed();
require(!completed, "staking process is already completed");
_;
}
Is the second one up to time?
The first is to have a deadline variable
uint256 public deadline = block.timestamp + 60 seconds;
Then there is also a timeLeft function
function timeLeft() public view returns (uint256 timeleft) {
if (block.timestamp >= deadline) {
return 0;
} else {
return deadline - block.timestamp;
}
}
Next is the deadlineReached function
modifier deadlineReached(bool requireReached) {
uint256 timeRemaining = timeLeft();
if (requireReached) {
require(timeRemaining == 0, "deadline is not reached yet");
} else {
require(timeRemaining > 0, "deadline has already reached");
}
_;
}
How to modify these functions
stake
function stake() public payable deadlineReached(false) stakeNotCompleted {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
execute function
function execute() public stakeNotCompleted deadlineReached(false) {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
Functions that can be called by external contracts
receive() external payable {
stake();
}
The final code is as follows:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "hardhat/console.sol";
import "./ExampleExternalContract.sol";
contract Staker {
ExampleExternalContract public exampleExternalContract;
mapping(address => uint256) public balances;
uint256 public constant threshold = 1 ether;
event Stake(address indexed staker, uint256 amount);
uint256 public deadline = block.timestamp + 60 seconds;
constructor(address exampleExternalContractAddress) public {
exampleExternalContract = ExampleExternalContract(
exampleExternalContractAddress
);
}
modifier stakeNotCompleted() {
bool completed = exampleExternalContract.completed();
require(!completed, "staking process is already completed");
_;
}
modifier deadlineReached(bool requireReached) {
uint256 timeRemaining = timeLeft();
if (requireReached) {
require(timeRemaining == 0, "deadline is not reached yet");
} else {
require(timeRemaining > 0, "deadline has already reached");
}
_;
}
function timeLeft() public view returns (uint256 timeleft) {
if (block.timestamp >= deadline) {
return 0;
} else {
return deadline - block.timestamp;
}
}
function stake() public payable deadlineReached(false) stakeNotCompleted {
balances[msg.sender] += msg.value;
emit Stake(msg.sender, msg.value);
}
function execute() public stakeNotCompleted deadlineReached(false) {
uint256 contractBalance = address(this).balance;
require(contractBalance >= threshold, "Threshold not reached");
(bool sent, ) = address(exampleExternalContract).call{
value: contractBalance
}(abi.encodeWithSignature("complete()"));
require(sent, "exampleExternalContract.complete() failed");
}
function withdraw() public deadlineReached(true) stakeNotCompleted {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
receive() external payable {
stake();
}
}
Deployment
yarn deploy --reset
Testing
withdraw function
function withdraw() public deadlineReached(true) stakeNotCompleted {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
withdraw function
function withdraw() public deadlineReached(true) stakeNotCompleted {
uint256 userBalance = balances[msg.sender];
require(userBalance > 0, "You don't have balance to withdraw");
balances[msg.sender] = 0;
(bool sent, ) = msg.sender.call{value: userBalance}("");
require(sent, "Failed to send user balance back to the user");
}
No activity yet