diff --git a/package.json b/package.json index 213f3a1..46cfcda 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "prettier": "prettier --config .prettierrc --write \"**/*.{js,json,md,sol,ts}\"", "prettier:list-different": "prettier --config .prettierrc --list-different \"**/*.{js,json,md,sol,ts}\"", "profile": "REPORT_GAS=true yarn hardhat test test/*.ts test/**/*.ts", - "test": "yarn hardhat test test/*.ts test/**/*.ts" + "test": "yarn hardhat test test/*.ts" }, "dependencies": { "@openzeppelin/contracts": "5.1.0", diff --git a/test/token_pool.js b/test/token_pool.js deleted file mode 100644 index 687d0b0..0000000 --- a/test/token_pool.js +++ /dev/null @@ -1,120 +0,0 @@ -const { contract, web3 } = require("@openzeppelin/test-environment"); -const { expectRevert, expectEvent } = require("@openzeppelin/test-helpers"); -const { expect } = require("chai"); - -const _require = require("app-root-path").require; -const BlockchainCaller = _require("/util/blockchain_caller"); -const chain = new BlockchainCaller(web3); - -const MockERC20 = contract.fromArtifact("MockERC20"); -const TokenPool = contract.fromArtifact("TokenPool"); - -let token, otherToken, tokenPool, owner, anotherAccount; -describe("tokenPool", function () { - beforeEach("setup contracts", async function () { - const accounts = await chain.getUserAccounts(); - owner = web3.utils.toChecksumAddress(accounts[0]); - anotherAccount = web3.utils.toChecksumAddress(accounts[8]); - - token = await MockERC20.new(1000); - otherToken = await MockERC20.new(2000); - - tokenPool = await TokenPool.new(token.address); - }); - - describe("balance", function () { - it("should return the balance of the token pool", async function () { - await token.transfer(tokenPool.address, 123); - expect(await tokenPool.balance.call()).to.be.bignumber.equal("123"); - await tokenPool.transfer(owner, 99); - expect(await tokenPool.balance.call()).to.be.bignumber.equal("24"); - await tokenPool.transfer(owner, 24); - expect(await tokenPool.balance.call()).to.be.bignumber.equal("0"); - }); - }); - - describe("transfer", function () { - it("should let the owner transfer funds out", async function () { - await token.transfer(tokenPool.address, 1000); - - expect(await tokenPool.balance.call()).to.be.bignumber.equal("1000"); - expect(await token.balanceOf.call(anotherAccount)).to.be.bignumber.equal("0"); - - await tokenPool.transfer(anotherAccount, 1000); - - expect(await tokenPool.balance.call()).to.be.bignumber.equal("0"); - expect(await token.balanceOf.call(anotherAccount)).to.be.bignumber.equal("1000"); - }); - - it("should NOT let other users transfer funds out", async function () { - await token.transfer(tokenPool.address, 1000); - await expectRevert( - tokenPool.transfer(anotherAccount, 1000, { from: anotherAccount }), - "Ownable: caller is not the owner", - ); - }); - }); - - describe("rescueFunds", function () { - beforeEach(async function () { - await token.transfer(tokenPool.address, 1000); - await otherToken.transfer(tokenPool.address, 2000); - - expect(await tokenPool.balance.call()).to.be.bignumber.equal("1000"); - expect(await token.balanceOf.call(anotherAccount)).to.be.bignumber.equal("0"); - expect(await otherToken.balanceOf.call(tokenPool.address)).to.be.bignumber.equal( - "2000", - ); - expect(await otherToken.balanceOf.call(anotherAccount)).to.be.bignumber.equal("0"); - }); - - it("should let owner users claim excess funds completely", async function () { - await tokenPool.rescueFunds(otherToken.address, anotherAccount, 2000); - - expect(await tokenPool.balance.call()).to.be.bignumber.equal("1000"); - expect(await token.balanceOf.call(anotherAccount)).to.be.bignumber.equal("0"); - expect(await otherToken.balanceOf.call(tokenPool.address)).to.be.bignumber.equal( - "0", - ); - expect(await otherToken.balanceOf.call(anotherAccount)).to.be.bignumber.equal( - "2000", - ); - }); - - it("should let owner users claim excess funds partially", async function () { - await tokenPool.rescueFunds(otherToken.address, anotherAccount, 777); - - expect(await tokenPool.balance.call()).to.be.bignumber.equal("1000"); - expect(await token.balanceOf.call(anotherAccount)).to.be.bignumber.equal("0"); - expect(await otherToken.balanceOf.call(tokenPool.address)).to.be.bignumber.equal( - "1223", - ); - expect(await otherToken.balanceOf.call(anotherAccount)).to.be.bignumber.equal( - "777", - ); - }); - - it("should NOT let owner claim more than available excess funds", async function () { - await expectRevert( - tokenPool.rescueFunds(otherToken.address, anotherAccount, 2001), - "ERC20: transfer amount exceeds balance", - ); - }); - - it("should NOT let owner users claim held funds", async function () { - await expectRevert( - tokenPool.rescueFunds(token.address, anotherAccount, 1000), - "TokenPool: Cannot claim token held by the contract", - ); - }); - - it("should NOT let other users users claim excess funds", async function () { - await expectRevert( - tokenPool.rescueFunds(otherToken.address, anotherAccount, 2000, { - from: anotherAccount, - }), - "Ownable: caller is not the owner", - ); - }); - }); -}); diff --git a/test/token_pool.ts b/test/token_pool.ts new file mode 100644 index 0000000..e8e9fe3 --- /dev/null +++ b/test/token_pool.ts @@ -0,0 +1,137 @@ +import { ethers, waffle } from "hardhat"; +import { expect } from "chai"; +import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; + +let owner: SignerWithAddress, anotherAccount: SignerWithAddress; + +describe.only("TokenPool", function () { + async function setupContracts() { + [owner, anotherAccount] = await ethers.getSigners(); + + const MockERC20 = await ethers.getContractFactory("MockERC20"); + const token = await MockERC20.deploy(1000); + const otherToken = await MockERC20.deploy(2000); + + const TokenPool = await ethers.getContractFactory("TokenPool"); + const tokenPool = await TokenPool.deploy(token.target); + + return { token, otherToken, tokenPool, owner, anotherAccount }; + } + + describe("balance", function () { + it("should return the balance of the token pool", async function () { + const { token, tokenPool, owner } = await loadFixture(setupContracts); + + await token.transfer(tokenPool.target, 123); + expect(await tokenPool.balance()).to.equal(123); + await tokenPool.transfer(await owner.getAddress(), 99); + expect(await tokenPool.balance()).to.equal(24); + await tokenPool.transfer(await owner.getAddress(), 24); + expect(await tokenPool.balance()).to.equal(0); + }); + }); + + describe("transfer", function () { + it("should let the owner transfer funds out", async function () { + const { token, tokenPool, anotherAccount } = await loadFixture(setupContracts); + + await token.transfer(tokenPool.target, 1000); + + expect(await tokenPool.balance()).to.equal(1000); + expect(await token.balanceOf(await anotherAccount.getAddress())).to.equal(0); + + await tokenPool.transfer(await anotherAccount.getAddress(), 1000); + + expect(await tokenPool.balance()).to.equal(0); + expect(await token.balanceOf(await anotherAccount.getAddress())).to.equal(1000); + }); + + it("should NOT let other users transfer funds out", async function () { + const { token, tokenPool, anotherAccount } = await loadFixture(setupContracts); + + await token.transfer(tokenPool.target, 1000); + await expect( + tokenPool + .connect(anotherAccount) + .transfer(await anotherAccount.getAddress(), 1000), + ).to.be.revertedWithCustomError(tokenPool, "OwnableUnauthorizedAccount"); + }); + }); + + describe("rescueFunds", function () { + it("should let owner users claim excess funds completely", async function () { + const { token, otherToken, tokenPool, anotherAccount } = await loadFixture( + setupContracts, + ); + + await token.transfer(tokenPool.target, 1000); + await otherToken.transfer(tokenPool.target, 2000); + + await tokenPool.rescueFunds( + otherToken.target, + await anotherAccount.getAddress(), + 2000, + ); + + expect(await tokenPool.balance()).to.equal(1000); + expect(await token.balanceOf(await anotherAccount.getAddress())).to.equal(0); + expect(await otherToken.balanceOf(tokenPool.target)).to.equal(0); + expect(await otherToken.balanceOf(await anotherAccount.getAddress())).to.equal( + 2000, + ); + }); + + it("should let owner users claim excess funds partially", async function () { + const { token, otherToken, tokenPool, anotherAccount } = await loadFixture( + setupContracts, + ); + + await token.transfer(tokenPool.target, 1000); + await otherToken.transfer(tokenPool.target, 2000); + + await tokenPool.rescueFunds( + otherToken.target, + await anotherAccount.getAddress(), + 777, + ); + + expect(await tokenPool.balance()).to.equal(1000); + expect(await token.balanceOf(await anotherAccount.getAddress())).to.equal(0); + expect(await otherToken.balanceOf(tokenPool.target)).to.equal(1223); + expect(await otherToken.balanceOf(await anotherAccount.getAddress())).to.equal(777); + }); + + it("should NOT let owner claim more than available excess funds", async function () { + const { otherToken, tokenPool, anotherAccount } = await loadFixture(setupContracts); + + await otherToken.transfer(tokenPool.target, 2000); + + await expect( + tokenPool.rescueFunds(otherToken.target, await anotherAccount.getAddress(), 2001), + ).to.be.revertedWithCustomError(otherToken, "ERC20InsufficientBalance"); + }); + + it("should NOT let owner users claim held funds", async function () { + const { token, tokenPool, anotherAccount } = await loadFixture(setupContracts); + + await token.transfer(tokenPool.target, 1000); + + await expect( + tokenPool.rescueFunds(token.target, await anotherAccount.getAddress(), 1000), + ).to.be.revertedWith("TokenPool: Cannot claim token held by the contract"); + }); + + it("should NOT let other users claim excess funds", async function () { + const { otherToken, tokenPool, anotherAccount } = await loadFixture(setupContracts); + + await otherToken.transfer(tokenPool.target, 2000); + + await expect( + tokenPool + .connect(anotherAccount) + .rescueFunds(otherToken.target, await anotherAccount.getAddress(), 2000), + ).to.be.revertedWithCustomError(tokenPool, "OwnableUnauthorizedAccount"); + }); + }); +});