Skip to content

Commit

Permalink
Add basic unit tests for staking
Browse files Browse the repository at this point in the history
  • Loading branch information
r-czajkowski committed Nov 27, 2023
1 parent 14c14e1 commit 02c2b3b
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 3 deletions.
2 changes: 1 addition & 1 deletion core/contracts/Acre.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ contract Acre is ERC4626, IReceiveApproval {
) external override {
require(_token == super.asset(), "Unrecognized token");
// TODO: Decide on the format of the `extradata` variable.
require(extraData.length >= 32, "Corrupted stake data");
require(extraData.length == 32, "Corrupted stake data");

this.stake(amount, from, bytes32(extraData));
}
Expand Down
117 changes: 115 additions & 2 deletions core/test/Acre.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,118 @@
import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers"
import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"
import { ethers } from "hardhat"
import { expect } from "chai"
import { WeiPerEther } from "ethers"
import type { TestToken, Acre } from "../typechain"

async function acreFixture() {
const [_, tokenHolder] = await ethers.getSigners()
const Token = await ethers.getContractFactory("TestToken")
const token = await Token.deploy()

const amountToMint = WeiPerEther * 10000n

token.mint(tokenHolder, amountToMint)

const Acre = await ethers.getContractFactory("Acre")
const acre = await Acre.deploy(await token.getAddress())

return { acre, token, tokenHolder }
}

describe("Acre", () => {
describe("Add your tests", () => {
it("Should validate something", async () => {})
let acre: Acre
let token: TestToken
let tokenHolder: HardhatEthersSigner

beforeEach(async () => {
;({ acre, token, tokenHolder } = await loadFixture(acreFixture))
})

describe("Staking", () => {
const referrer = ethers.encodeBytes32String("referrer")

context("when staking via Acre contract", () => {
beforeEach(async () => {
// Infinite approval for staking contract.
await token
.connect(tokenHolder)
.approve(await acre.getAddress(), ethers.MaxUint256)
})

it("should stake tokens and receive shares", async () => {
const tokenHolderAddress = tokenHolder.address
const amountToStake = await token.balanceOf(tokenHolderAddress)

await expect(
acre
.connect(tokenHolder)
.stake(amountToStake, tokenHolderAddress, referrer),
)
.to.emit(acre, "Deposit")
.withArgs(
// Caller.
tokenHolderAddress,
// Receiver.
tokenHolderAddress,
// Staked tokens.
amountToStake,
// Received shares. In this test case there is only one staker and
// the token vault has not earned anythig yet so received shares are
// equal to staked tokens amount.
amountToStake,
)
expect(await acre.balanceOf(tokenHolderAddress)).to.be.eq(amountToStake)
expect(await token.balanceOf(tokenHolderAddress)).to.be.eq(0)
})

it("should revert if the referrer is zero valu", async () => {
const emptyReferrer = ethers.encodeBytes32String("")

await expect(
acre
.connect(tokenHolder)
.stake(1, tokenHolder.address, emptyReferrer),
).to.be.revertedWith("Referrer can not be empty")
})
})

context(
"when staking via staking token using approve and call pattern",
() => {
it("should stake tokens", () => {
// TODO: The `ERC4626.deposit` sets the owner as `msg.sender` under
// the hood. Using the approve and call pattern the `msg.sender` is
// token address, so we are actually trying to send tokens from the
// token contract to the receiver, which is impossible. We need to
// decide if we want to override the `deposit` function to allow
// staking via approve and call pattern.
})

it("should revert when called not for linked token", async () => {
const FakeToken = await ethers.getContractFactory("TestToken")
const fakeToken = await FakeToken.deploy()
const acreAddress = await acre.getAddress()

await expect(
fakeToken.connect(tokenHolder).approveAndCall(acreAddress, 1, "0x"),
).to.be.revertedWith("Unrecognized token")
})

it("should revert when extra data is invalid", async () => {
const acreAddress = await acre.getAddress()
const invalidExtraData = ethers.AbiCoder.defaultAbiCoder().encode(
["bytes32", "address"],
[referrer, tokenHolder.address],
)

await expect(
token
.connect(tokenHolder)
.approveAndCall(acreAddress, 1, invalidExtraData),
).to.be.revertedWith("Corrupted stake data")
})
},
)
})
})

0 comments on commit 02c2b3b

Please sign in to comment.