Skip to content

Assignment

Add emissions so users can get back ERC-20 in leiu of staking.

  • Initialize a new forge contract
forge init --template https://github.com/foundry-rs/forge-template staking-contract
  • Add openzeplin contracts
npm init -y
npm install @openzeppelin/contracts
  • Add remapping.txt
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
  • Create your own token (ERC20.sol)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "forge-std/Test.sol";
contract KiratCoin is ERC20 {
address stakingContract;
constructor(address _stakingContract) ERC20("KiratCoin", "KIRA") {
stakingContract = _stakingContract;
}
modifier onlyContract() {
require(msg.sender == stakingContract);
_;
}
function mint(address to, uint256 amount) public onlyContract {
_mint(to, amount);
}
function updateContract(address newContract) public onlyContract {
stakingContract = newContract;
}
}
  • Write tests for your own token (ERC20.t.sol)
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "src/ERC20.sol";
contract ERC20ContractTest is Test {
KiratCoin c;
function setUp() public {
c = new KiratCoin(address(this));
}
function testMint() public {
uint value = 10;
c.mint(address(this), value);
assert(c.balanceOf(address(this)) == value);
}
function testFailMint() public {
vm.startPrank(0x587EFaEe4f308aB2795ca35A27Dff8c1dfAF9e3f);
c.mint(address(this), value);
}
}
  • Create the staking contract (StakingWithEmissions.sol)
// SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "src/StakingWithEmissions.sol";
import "src/ERC20.sol";
contract StakingWithEmissionsTest is Test {
StakingWithEmissions stakingContract;
KiratCoin kiratToken;
function setUp() public {
kiratToken = new KiratCoin(address(this)); // address doesnt matter
stakingContract = new StakingWithEmissions(IKiratToken(address(kiratToken)));
kiratToken.updateContract(address(stakingContract));
}
function testStake() public {
uint value = 10 ether;
stakingContract.stake{value: value}(value);
assert(stakingContract.totalStake() == value);
}
function testFailStake() public {
uint value = 10 ether;
stakingContract.stake(value);
stakingContract.unstake(value + 1 ether);
}
function testGetRewards() public {
uint value = 1 ether;
stakingContract.stake{value: value}(value);
vm.warp(block.timestamp + 1);
uint rewards = stakingContract.getRewards();
assert(rewards == 1 ether);
}
function testComplexGetRewards() public {
uint value = 1 ether;
stakingContract.stake{value: value}(value);
vm.warp(block.timestamp + 1);
console.log(block.timestamp);
stakingContract.stake{value: value}(value);
vm.warp(block.timestamp + 1);
uint rewards = stakingContract.getRewards();
assert(rewards == 3 ether);
}
function testRedeemRewards() public {
uint value = 1 ether;
stakingContract.stake{value: value}(value);
vm.warp(block.timestamp + 1);
stakingContract.claimEmissions();
console.log("balance of");
console.log(kiratToken.balanceOf(address(this)));
assert(kiratToken.balanceOf(address(this)) == 1 ether);
}
}