Skip to content

Instantly share code, notes, and snippets.

@Falilah
Last active February 16, 2023 13:16
Show Gist options
  • Save Falilah/8bfc9f34ecea56ad7bc4d0e8673c274c to your computer and use it in GitHub Desktop.
Save Falilah/8bfc9f34ecea56ad7bc4d0e8673c274c to your computer and use it in GitHub Desktop.
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
interface IUSDT {
function approve(address _spender, uint256 _value) external;
function balanceOf(address who) external view returns (uint256);
function allowance(address _owner, address _spender)
external
returns (uint256 remaining);
}
import { ethers, network } from "hardhat";
import { time } from "@nomicfoundation/hardhat-network-helpers";
import hre from "hardhat";
import { BigNumber } from "ethers";
async function main() {
const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F";
const DAIHolder = "0x748dE14197922c4Ae258c7939C7739f3ff1db573";
// const [owner, holder1, holder2, holder3] = await ethers.getSigners();
//deploy reward token
const Token = await ethers.getContractFactory("CVIII");
const token = await Token.deploy("web3Bridge", "VIII");
await token.deployed();
const tokenaddress = token.address;
console.log(`Reward Token deployed to ${tokenaddress}`);
///deploy Staking contract
const Staking = await ethers.getContractFactory("StakERC20");
const staking = await Staking.deploy(tokenaddress);
await staking.deployed();
console.log(`Staking contract deployed to ${staking.address}`);
/// connect dai
const dai = await ethers.getContractAt("IDAI", DAI);
const daiAdress = dai.address;
console.log(`staking Token deployed to ${daiAdress}`);
const balance = await dai.balanceOf(DAIHolder);
console.log(`balnce is ${balance}`);
const helpers = require("@nomicfoundation/hardhat-network-helpers");
const address = DAIHolder;
await helpers.impersonateAccount(address);
const impersonatedSigner = await ethers.getSigner(address);
const tokenSet = await staking.setStakeToken(daiAdress);
// console.log(await tokenSet.wait());
console.log(`staked Token ${await staking.stakeToken()}`);
const stakeDai = await ethers.utils.parseEther("50");
await dai.connect(impersonatedSigner).approve(staking.address, stakeDai);
const allowance = await dai.allowance(DAIHolder, staking.address);
// console.log(`allowance ${allowance.wait()}`);
const staker1 = await staking.connect(impersonatedSigner).stake(stakeDai);
const userInfo1 = await staking.userInfo(impersonatedSigner.address);
console.log(`holder1 infornation ${userInfo1}`);
await ethers.provider.send("evm_mine", [1708037999]);
await staking.connect(impersonatedSigner).updateReward();
const userInfo = await staking.userInfo(impersonatedSigner.address);
console.log(`holder1 infornation ${userInfo}`);
let a = BigNumber.from("10000000000000000000");
// let b = BigNumber.from("10000000000000000000");
await token.transfer(staking.address, a);
await staking.connect(impersonatedSigner).claimReward(a);
const userInfoAfter = await staking.userInfo(impersonatedSigner.address);
console.log(`holder1 infornation ${userInfoAfter}`);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
//users stake usdt
//user get 20% APY CVIII as reward;
// tken ratio 1: 1
contract StakERC20 is Ownable {
IERC20 public rewardToken;
IERC20 public stakeToken;
uint256 constant SECONDS_PER_YEAR = 31536000;
struct User {
uint256 stakedAmount;
uint256 startTime;
uint256 rewardAccrued;
}
mapping(address => User) user;
error tryAgain();
constructor(address _rewardToken) {
rewardToken = IERC20(_rewardToken);
}
function setStakeToken(address _token)
external
onlyOwner
returns (address _newToken)
{
require(IERC20(_token) != stakeToken, "Token already set");
require(IERC20(_token) != rewardToken, "canot stake reward");
require(_token != address(0), "cannot set address zero");
stakeToken = IERC20(_token);
_newToken = address(stakeToken);
}
function stake(uint256 amount) external {
User storage _user = user[msg.sender];
uint256 _amount = _user.stakedAmount;
stakeToken.transferFrom(msg.sender, address(this), amount);
if (_amount == 0) {
_user.stakedAmount = amount;
_user.startTime = block.timestamp;
} else {
updateReward();
_user.stakedAmount += amount;
}
}
function calcReward() public view returns (uint256 _reward) {
User storage _user = user[msg.sender];
uint256 _amount = _user.stakedAmount;
uint256 _startTime = _user.startTime;
uint256 duration = block.timestamp - _startTime;
_reward = (duration * 20 * _amount) / (SECONDS_PER_YEAR * 100);
}
function claimReward(uint256 amount) public {
User storage _user = user[msg.sender];
updateReward();
uint256 _claimableReward = _user.rewardAccrued;
require(_claimableReward >= amount, "insufficient funds");
_user.rewardAccrued -= amount;
if (amount > rewardToken.balanceOf(address(this))) revert tryAgain();
rewardToken.transfer(msg.sender, amount);
}
function updateReward() public {
User storage _user = user[msg.sender];
uint256 _reward = calcReward();
_user.rewardAccrued += _reward;
_user.startTime = block.timestamp;
}
function withdrawStaked(uint256 amount) public {
User storage _user = user[msg.sender];
uint256 staked = _user.stakedAmount;
require(staked >= amount, "insufficient fund");
updateReward();
_user.stakedAmount -= amount;
stakeToken.transfer(msg.sender, amount);
}
function closeAccount() external {
User storage _user = user[msg.sender];
uint256 staked = _user.stakedAmount;
withdrawStaked(staked);
uint256 reward = _user.rewardAccrued;
claimReward(reward);
}
function userInfo(address _user) external view returns (User memory) {
return user[_user];
}
}
import { ethers, network } from "hardhat";
import { time } from "@nomicfoundation/hardhat-network-helpers";
async function main() {
const [owner, holder1, holder2, holder3] = await ethers.getSigners();
//deploy reward token
const Token = await ethers.getContractFactory("CVIII");
const token = await Token.deploy("web3Bridge", "VIII");
await token.deployed();
const tokenaddress = token.address;
console.log(`Reward Token deployed to ${tokenaddress}`);
///deploy Staking contract
const Staking = await ethers.getContractFactory("StakERC20");
const staking = await Staking.deploy(tokenaddress);
await staking.deployed();
console.log(`Staking contract deployed to ${staking.address}`);
// Mock usdt
const USDT = await ethers.getContractFactory("USDT");
const usdt = await USDT.deploy("Tether", "USDT");
await usdt.deployed();
const usdtAdress = usdt.address;
console.log(`staking Token deployed to ${usdtAdress}`);
const tokenSet = await staking.setStakeToken(usdtAdress);
// console.log(await tokenSet.wait());
console.log(`staked Token ${await staking.stakeToken()}`);
const staker1Minting = await usdt.connect(holder1).mint(100);
await usdt.connect(holder1).approve(staking.address, 100000000);
const staker1 = await staking.connect(holder1).stake(50000000);
const userInfo1 = await staking.userInfo(holder1.address);
console.log(`holder1 infornation ${userInfo1}`);
await ethers.provider.send("evm_mine", [1708037999]);
await staking.connect(holder1).updateReward();
const userInfo = await staking.userInfo(holder1.address);
console.log(`holder1 infornation ${userInfo}`);
await token.transfer(staking.address, 100000000);
await staking.connect(holder1).claimReward(10000000);
const userInfoAfter = await staking.userInfo(holder1.address);
console.log(`holder1 infornation ${userInfoAfter}`);
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
//18 772 231
// 18 772 216
// 10 005 054
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment