Skip to content

Commit

Permalink
Add stake function to TokenStaking contract
Browse files Browse the repository at this point in the history
Add function that stakes owner's tokens in the staking contract - tracks
user's staked funds and emit `Staked` event. The minimum amount is
required.
  • Loading branch information
r-czajkowski committed Oct 30, 2023
1 parent 3448952 commit ad7fd74
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 1 deletion.
17 changes: 16 additions & 1 deletion core/contracts/staking/TokenStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// and recover the stake after undelegation period is over.
contract TokenStaking {
using SafeERC20 for IERC20;


event Staked(address indexed account, uint256 amount);

IERC20 internal immutable token;

mapping(address => uint256) public balanceOf;

constructor(IERC20 _token) {
require(
address(_token) != address(0),
Expand All @@ -22,4 +26,15 @@ contract TokenStaking {

token = _token;
}

/// @notice Stakes the owner's tokens in the staking contract.
/// @param amount Approved amount for the transfer and stake.
function stake(uint256 amount) external {
require(amount > 0, "Amount is less than minimum");

balanceOf[msg.sender] += amount;

emit Staked(msg.sender, amount);
token.safeTransferFrom(msg.sender, address(this), amount);
}
}
13 changes: 13 additions & 0 deletions core/contracts/test/TestToken.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity 0.8.20;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
constructor() ERC20("Test Token", "TEST") {}

function mint(address account, uint256 value) external {
_mint(account, value);
}
}
67 changes: 67 additions & 0 deletions core/test/staking/TokenStaking.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
import { ethers } from "hardhat"
import { expect } from "chai"
import { Token, TokenStaking } from "../../typechain"
import { WeiPerEther } from "ethers"
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"
import { before } from "mocha"

async function tokenStakingFixture() {
const [deployer, tokenHolder] = await ethers.getSigners()
const StakingToken = await ethers.getContractFactory("Token")
const token = await StakingToken.deploy()

const amountToMint = WeiPerEther * 10000n

token.mint(tokenHolder, amountToMint)

const TokenStaking = await ethers.getContractFactory("TokenStaking")
const tokenStaking = await TokenStaking.deploy(await token.getAddress())

return { tokenStaking, token, tokenHolder }
}

describe("TokenStaking", () => {
let tokenStaking: TokenStaking
let token: Token
let tokenHolder: HardhatEthersSigner

beforeEach(async () => {
const {
tokenStaking: _tokenStaking,
token: _token,
tokenHolder: _tokenHolder,
} = await loadFixture(tokenStakingFixture)

tokenStaking = _tokenStaking
token = _token
tokenHolder = _tokenHolder
})

describe("staking", () => {
beforeEach(async () => {
// Infinite approval for staking contract.
await token
.connect(tokenHolder)
.approve(await tokenStaking.getAddress(), ethers.MaxUint256)
})

it("should stake tokens", async () => {
const tokenHolderAddress = await tokenHolder.getAddress()
const tokenBalance = await token.balanceOf(tokenHolderAddress)

await expect(tokenStaking.connect(tokenHolder).stake(tokenBalance))
.to.emit(tokenStaking, "Staked")
.withArgs(tokenHolderAddress, tokenBalance)
expect(await tokenStaking.balanceOf(tokenHolderAddress)).to.be.eq(
tokenBalance,
)
expect(await token.balanceOf(tokenHolderAddress)).to.be.eq(0)
})

it("should revert if the staked amount is less than required minimum", async () => {
await expect(tokenStaking.connect(tokenHolder).stake(0))
.to.be.revertedWith("Amount is less than minimum")
})
})
})

0 comments on commit ad7fd74

Please sign in to comment.