Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/staking and reward tokens #1

Merged
merged 6 commits into from
Jan 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/test-contracts.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
name: Test Contracts

on: workflow_dispatch
on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited

env:
FOUNDRY_PROFILE: ci
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "contracts/lib/forge-std"]
path = contracts/lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "contracts/lib/openzeppelin-contracts"]
path = contracts/lib/openzeppelin-contracts
url = https://github.com/OpenZeppelin/openzeppelin-contracts
1 change: 1 addition & 0 deletions contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
src = "src"
out = "out"
libs = ["lib"]
remappings = ['@openzeppelin/contracts=lib/openzeppelin-contracts/contracts']

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1 change: 1 addition & 0 deletions contracts/lib/openzeppelin-contracts
Submodule openzeppelin-contracts added at 01ef44
28 changes: 28 additions & 0 deletions contracts/src/FinthetixRewardToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.23;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

/**
* @title FinthetixRewardtoken
* @author sayandcode
* @notice This token is paid out by the Finthetix Staking Contract as a reward
* @dev This contract needs to be deployed by the Staking Contract in order for it to be able to
* generate rewards periodically. This is because only the owner of this Token Contract can mint
* more tokens
*/
contract FinthetixRewardToken is ERC20, Ownable {
constructor() ERC20("FinthetixRewardToken", "FRT") Ownable(msg.sender) {}

/**
*
* @param to The address of the recipient of the funds
* @param amtToMint The amount of tokens to allocate to the recipient
* @notice This function will be called by the staking contract when it is time to generate rewards for stakers
* @dev This is intended to be only used by the Staking Contract
*/
function mint(address to, uint256 amtToMint) external onlyOwner {
_mint(to, amtToMint);
}
}
32 changes: 32 additions & 0 deletions contracts/src/FinthetixStakingToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.23;

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

interface FSTEvents {
/**
*
* @param requesterAddr The address of the user requesting a sample of FST tokens
* @dev This event is emitted when the user requests a sample of FST tokens
*/
event SampleTokenRequested(address requesterAddr);
}

/**
* @title FinthetixStakingToken
* @author sayandcode
* @notice This is the staking token used by the Finthetix Staking Contract. Users lock up this token
* to gain rewards in the token chosen by the staking contract.
*/
contract FinthetixStakingToken is ERC20, FSTEvents {
constructor() ERC20("FinthetixStakingToken", "FST") {}

/**
* @notice Users can call this function to get a few sample tokens, in order to try out the
* staking contract
*/
function requestSampleTokens() public {
_mint(msg.sender, 5 ether);
emit SampleTokenRequested(msg.sender);
}
}
47 changes: 47 additions & 0 deletions contracts/test/FinthetixRewardToken.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.23;

import {FinthetixRewardToken} from "src/FinthetixRewardToken.sol";
import {Test} from "forge-std/Test.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

contract RewardToken_UnitTest is Test {
string private constant TOKEN_SYMBOL = "FRT";
string private constant TOKEN_NAME = "FinthetixRewardToken";
address private immutable contractOwnerAddr = vm.addr(0xB0b);

FinthetixRewardToken private tokenContract;

function setUp() public {
vm.prank(contractOwnerAddr);
tokenContract = new FinthetixRewardToken();
}

function test_HasCorrectLabels() public {
assertEq(tokenContract.symbol(), TOKEN_SYMBOL, "Incorrect Token Symbol");
assertEq(tokenContract.name(), TOKEN_NAME, "Incorrect Token Name");
}

function test_CanMintToken(uint256 amtToMint) public {
address receiverAddr = address(1);

uint256 balanceBefore = tokenContract.balanceOf(receiverAddr);
assertEq(balanceBefore, 0);

vm.prank(contractOwnerAddr);
tokenContract.mint(receiverAddr, amtToMint);

uint256 balanceAfter = tokenContract.balanceOf(receiverAddr);
assertEq(balanceAfter, amtToMint);
}

function test_NonOwnersCannotMint(address senderAddr) public {
vm.assume(senderAddr != contractOwnerAddr);

uint8 amtToMint = 2;

vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, senderAddr));
vm.prank(senderAddr);
tokenContract.mint(senderAddr, amtToMint);
}
}
33 changes: 33 additions & 0 deletions contracts/test/FinthetixStakingToken.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: SEE LICENSE IN LICENSE
pragma solidity 0.8.23;

import {FinthetixStakingToken, FSTEvents} from "src/FinthetixStakingToken.sol";
import {Test} from "forge-std/Test.sol";

contract StakingToken_UnitTest is Test {
string private constant TOKEN_NAME = "FinthetixStakingToken";
string private constant TOKEN_SYMBOL = "FST";
uint256 private constant SAMPLE_TOKEN_QTY = 5 ether;
FinthetixStakingToken private tokenContract;

function setUp() public {
tokenContract = new FinthetixStakingToken();
}

function test_HasCorrectLabels() public {
assertEq(tokenContract.name(), TOKEN_NAME);
assertEq(tokenContract.symbol(), TOKEN_SYMBOL);
}

function test_RequestSampleTokensFn() public {
uint256 tokensBefore = tokenContract.balanceOf(address(this));
assertEq(tokensBefore, 0);

vm.expectEmit(address(tokenContract));
emit FSTEvents.SampleTokenRequested(address(this));
tokenContract.requestSampleTokens();

uint256 tokensAfter = tokenContract.balanceOf(address(this));
assertEq(tokensAfter, SAMPLE_TOKEN_QTY);
}
}