Skip to content

Commit

Permalink
Merge pull request #8 from traderjoe-xyz/launch-event-phase-one-testing
Browse files Browse the repository at this point in the history
Launch event phase one testing
  • Loading branch information
LouisMeMyself authored Jan 5, 2022
2 parents 574b695 + 10e8761 commit 35ca634
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 31 deletions.
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
compile:
yarn run hardhat compile

.PHONY: test
test:
yarn run hardhat test

clean:
yarn run hardhat clean

coverage:
yarn run hardhat coverage

console:
yarn run hardhat console
10 changes: 8 additions & 2 deletions contracts/LaunchEvent.sol
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ contract LaunchEvent is Ownable {
);

issuer = _issuer;

transferOwnership(issuer);
/// Different time phases
phaseOneStartTime = _phaseOneStartTime;
phaseOneLengthSeconds = 3 days;
Expand Down Expand Up @@ -246,9 +246,14 @@ contract LaunchEvent is Ownable {
WAVAX.withdraw(amount);

safeTransferAVAX(msg.sender, amountMinusFee);
safeTransferAVAX(penaltyCollector, feeAmount);
if (feeAmount > 0) {
safeTransferAVAX(penaltyCollector, feeAmount);
}
}

/// @dev Needed for withdrawing from WAVAX contract.
receive() external payable {}

/// @dev Returns the current penalty
function getPenalty() public view returns (uint256) {
uint256 startedSince = block.timestamp - phaseOneStartTime;
Expand Down Expand Up @@ -381,6 +386,7 @@ contract LaunchEvent is Ownable {

/// @dev Transfers and burns all the rJoe.
function burnRJoe(address from, uint256 rJoeAmount) internal {
// TODO: Should we use SafeERC20
rJoe.transferFrom(from, address(this), rJoeAmount);
rJoe.burn(rJoeAmount);
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/RocketJoeFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ contract RocketJoeFactory is IRocketJoeFactory, Ownable {

IERC20(_token).transferFrom(msg.sender, launchEvent, _tokenAmount); // msg.sender needs to approve RocketJoeFactory

LaunchEvent(launchEvent).initialize(
LaunchEvent(payable(launchEvent)).initialize(
_issuer,
_phaseOneStartTime,
_token,
Expand Down
2 changes: 2 additions & 0 deletions contracts/interfaces/IWAVAX.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ interface IWAVAX {
function transfer(address to, uint256 value) external returns (bool);

function withdraw(uint256) external;

function balanceOf(address account) external returns (uint256);
}
31 changes: 3 additions & 28 deletions test/LaunchEvent.test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
const { ethers, network } = require("hardhat");
const { expect } = require("chai");

describe("Launch Event Contract", function () {
describe("Launch event contract initialisation", function () {
before(async function () {
this.signers = await ethers.getSigners();
this.dev = this.signers[0];
this.alice = this.signers[1];
this.bob = this.signers[2];
this.carol = this.signers[3];
// I think if we deploy WAVAX contract we can skip the forking.
// To get faster tests.
await network.provider.request({
method: "hardhat_reset",
params: [
Expand Down Expand Up @@ -259,33 +261,6 @@ describe("Launch Event Contract", function () {
});
});

describe("Interacting with phase one", function () {
it("should revert if cant transfer rJOE", async function () {});
it("should revert if AVAX sent less than min allocation", async function () {});
it("should revert if AVAX sent more than max allocation", async function () {});
it("should burn rJOE on succesful deposit", async function () {});
it("should revert if second deposit is above max allocation", async function () {});
it("should revert if we withdraw during phase one", async function () {});
it("should revert try to create pool during phase one", async function () {});
});

describe("Interacting with phase two", function () {
it("should revert try to create pool during phase two", async function () {});
});

describe("Interacting with phase three", function () {
it("should revert if users withdraws before timelock", async function () {});
it("should revert if issuer withdraws before timelock", async function () {});
it("should revert when timelock finishes", async function () {});
it("should create the pair", async function () {});
it("should revert if the pair is already created", async function () {});
});

describe("The penalty structure", function () {
it("should be static for the first day", function () {});
it("should be linear for second day", function () {});
});

after(async function () {
await network.provider.request({
method: "hardhat_reset",
Expand Down
245 changes: 245 additions & 0 deletions test/LaunchEventPhaseOne.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
const { ethers, network } = require("hardhat");
const { expect } = require("chai");

describe("Launch event contract phase one", function () {
before(async function () {
this.signers = await ethers.getSigners();
this.dev = this.signers[0];
this.alice = this.signers[1];
this.bob = this.signers[2];
this.carol = this.signers[3];

await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: "https://api.avax.network/ext/bc/C/rpc",
// blockNumber: 8465376,
},
live: false,
saveDeployments: true,
tags: ["test", "local"],
},
],
});
});

beforeEach(async function () {
// We want to setup
// The Rocket factory contract
// A new ERC20 for the auction
// rocket-joe token
this.WAVAX = "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7";
this.wavax = ethers.getContractAt("IWAVAX", this.WAVAX);
this.PENALTY_COLLECTOR = this.carol.address;
this.ROUTER = "0x60aE616a2155Ee3d9A68541Ba4544862310933d4";
this.FACTORY = "0x9Ad6C38BE94206cA50bb0d90783181662f0Cfa10";

this.RocketJoeTokenCF = await ethers.getContractFactory("RocketJoeToken");
this.rJOE = await this.RocketJoeTokenCF.deploy();
this.AUCTOK = await this.RocketJoeTokenCF.deploy();
// Send rJOE to dev address
await this.rJOE
.connect(this.dev)
.mint(this.dev.address, "1000000000000000000000000");

await this.rJOE
.connect(this.dev)
.mint(this.bob.address, ethers.utils.parseEther("10.0"));

// Send auction token to the dev.
await this.AUCTOK.connect(this.dev).mint(
this.dev.address,
"1000000000000000000000000"
);

this.LaunchEventCF = await ethers.getContractFactory("LaunchEvent");
this.RocketFactoryCF = await ethers.getContractFactory("RocketJoeFactory");
this.RocketFactory = await this.RocketFactoryCF.deploy(
this.rJOE.address,
this.WAVAX,
this.PENALTY_COLLECTOR,
this.ROUTER,
this.FACTORY
);
await this.AUCTOK.connect(this.dev).approve(
this.RocketFactory.address,
"1000000000000000000000000"
);

// Deploy the launch event contract
block = await ethers.provider.getBlock();
await this.RocketFactory.createRJLaunchEvent(
this.alice.address, // Issuer
block.timestamp + 60, // Start time (60 seconds from now)
this.AUCTOK.address, // Address of the token being auctioned
100, // Floor price (100 Wei)
1000, // Amount of tokens for auction
2893517, // Withdraw penalty gradient
4e11, // Fixed withdraw penalty
5000, // min allocation
ethers.utils.parseEther("5.0"), // max allocation
60 * 60 * 24 * 7 - 1, // User timelock
60 * 60 * 24 * 8 // Issuer timelock
);

// Get a reference to the acutal launch event contract.
this.LaunchEvent = await ethers.getContractAt(
"LaunchEvent",
this.RocketFactory.getRJLaunchEvent(this.AUCTOK.address)
);
});

describe("Interacting with phase one", function () {
it("It should revert if sale has not started yet", async function () {
expect(
this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
})
).to.be.revertedWith("LaunchEvent: Not in phase one");
});

it("It should revert if rJOE not approved", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
expect(
this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
})
).to.be.revertedWith("ERC20: transfer amount exceeds allowance");
});

it("should be payable with AVAX", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE
.connect(this.bob)
.approve(this.LaunchEvent.address, ethers.utils.parseEther("1.0"));
await this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
});
expect(this.LaunchEvent.users(this.bob.address).amount).to.equal(
ethers.utils.parseEther("1.0").number
);
});

it("should revert if AVAX sent less than min allocation", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE.connect(this.bob).approve(this.LaunchEvent.address, 4999);
expect(
this.LaunchEvent.connect(this.bob).depositAVAX({ value: 4999 })
).to.be.revertedWith(
"LaunchEvent: Not enough AVAX sent to meet the min allocation"
);
});

it("Should only be pausable by owner", async function () {
expect(this.LaunchEvent.connect(this.dev).pause()).to.be.revertedWith(
"Ownable: caller is not the owner"
);
});

it("should revert if paused", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE.connect(this.bob).approve(this.LaunchEvent.address, 4999);
await this.LaunchEvent.connect(this.alice).pause();
expect(
this.LaunchEvent.connect(this.bob).depositAVAX({ value: 4999 })
).to.be.revertedWith("LaunchEvent: Contract is paused");
});

it("should revert if AVAX sent more than max allocation", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE
.connect(this.bob)
.approve(this.LaunchEvent.address, ethers.utils.parseEther("6"));
expect(
this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("6"),
})
).to.be.revertedWith(
"LaunchEvent: Too much AVAX sent to meet the max allocation"
);
});

it("should burn rJOE on succesful deposit", async function () {
let rJOEBefore = await this.rJOE.totalSupply();

await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE
.connect(this.bob)
.approve(this.LaunchEvent.address, ethers.utils.parseEther("1.0"));

await this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
});

expect(await this.rJOE.totalSupply()).to.be.equal(
rJOEBefore.sub(ethers.utils.parseEther("1.0"))
);
});

it("should apply no fee if withdraw in first day", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE
.connect(this.bob)
.approve(this.LaunchEvent.address, ethers.utils.parseEther("1.0"));

await this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
});

// Test the amount received
const balanceBefore = await this.bob.getBalance();
await this.LaunchEvent.connect(this.bob).withdrawWAVAX(
ethers.utils.parseEther("1.0")
);
expect(await this.bob.getBalance()).to.be.above(balanceBefore);
// Check the balance of penalty collecter.
expect(await this.carol.getBalance()).to.equal("10000000000000000000000");
});

it("should apply gradient fee if withdraw in second day", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
await this.rJOE
.connect(this.bob)
.approve(this.LaunchEvent.address, ethers.utils.parseEther("1.0"));

await this.LaunchEvent.connect(this.bob).depositAVAX({
value: ethers.utils.parseEther("1.0"),
});
await network.provider.send("evm_increaseTime", [60 * 60 * 36]); // 1.5 days
await network.provider.send("evm_mine");
await this.LaunchEvent.connect(this.bob).withdrawWAVAX(
ethers.utils.parseEther("1.0")
);

// Check the balance of penalty collecter.
expect(await this.carol.getBalance()).to.be.above(
"10000000000000000000000"
);
});

it("should revert try to create pool during phase one", async function () {
await network.provider.send("evm_increaseTime", [120]);
await network.provider.send("evm_mine");
expect(
this.LaunchEvent.connect(this.dev).createPair()
).to.be.revertedWith("LaunchEvent: Not in phase three");
});
});

after(async function () {
await network.provider.request({
method: "hardhat_reset",
params: [],
});
});
});

0 comments on commit 35ca634

Please sign in to comment.