@gooddollar/goodprotocol
Version:
GoodDollar Protocol
339 lines (316 loc) • 11.7 kB
text/typescript
import { default as hre, ethers, upgrades } from "hardhat";
import { loadFixture } from "@nomicfoundation/hardhat-network-helpers";
import { BigNumber, Contract } from "ethers";
import { expect } from "chai";
import { GoodMarketMaker } from "../../types";
import IUniswapV2Pair from "@uniswap/v2-core/build/IUniswapV2Pair.json";
import { createDAO, deployUniswap, getStakingFactory } from "../helpers";
const BN = ethers.BigNumber;
export const NULL_ADDRESS = ethers.constants.AddressZero;
describe("UsdcAaveStakingV2 - staking with USDC mocks to AAVE interface", () => {
let dai: Contract;
let usdc: Contract;
let pair: Contract, uniswapRouter: Contract;
let comp: Contract, aave: Contract;
let daiUsdOracle: Contract, aaveUsdOracle: Contract;
let goodAaveStaking: Contract;
let goodFundManager: Contract;
let avatar,
goodDollar,
marketMaker: GoodMarketMaker,
controller,
founder,
staker,
schemeMock,
signers,
nameService,
incentiveController,
lendingPool,
setDAOAddress,
genericCall,
goodAaveStakingFactory,
runAsAvatarOnly,
deployStaking;
before(async () => {
[founder, staker, ...signers] = await ethers.getSigners();
schemeMock = signers.pop();
let {
controller: ctrl,
avatar: av,
gd,
identity,
nameService: ns,
setDAOAddress: sda,
marketMaker: mm,
daiAddress,
genericCall: gc,
COMP,
runAsAvatarOnly: raao
} = await loadFixture(createDAO);
const cUsdcFactory = await ethers.getContractFactory("cUSDCMock");
const goodFundManagerFactory = await ethers.getContractFactory(
"GoodFundManager"
);
goodAaveStakingFactory = await getStakingFactory("GoodAaveStakingV2");
const lendingPoolFactory = await ethers.getContractFactory(
"LendingPoolMock"
);
const usdcFactory = await ethers.getContractFactory("USDCMock");
dai = await ethers.getContractAt("DAIMock", daiAddress);
avatar = av;
controller = ctrl;
setDAOAddress = sda;
nameService = ns;
genericCall = gc;
runAsAvatarOnly = raao;
console.log("deployed dao", {
founder: founder.address,
gd,
identity,
controller,
avatar
});
goodFundManager = await upgrades.deployProxy(
goodFundManagerFactory,
[nameService.address],
{ kind: "uups" }
);
await setDAOAddress("FUND_MANAGER", goodFundManager.address);
console.log("Deployed goodfund manager", {
manager: goodFundManager.address
});
goodDollar = await ethers.getContractAt("IGoodDollar", gd);
marketMaker = mm;
const tokenUsdOracleFactory = await ethers.getContractFactory(
"BatUSDMockOracle"
);
daiUsdOracle = await tokenUsdOracleFactory.deploy();
comp = COMP;
usdc = await usdcFactory.deploy(); // Another erc20 token for uniswap router test
const uniswap = await deployUniswap(comp, dai);
uniswapRouter = uniswap.router;
const { factory, weth } = uniswap;
await setDAOAddress("UNISWAP_ROUTER", uniswapRouter.address);
await factory.createPair(usdc.address, dai.address); // Create tokenA and dai pair
const pairAddress = factory.getPair(usdc.address, dai.address);
pair = new Contract(
pairAddress,
JSON.stringify(IUniswapV2Pair.abi),
staker
).connect(founder);
aave = await (await ethers.getContractFactory("AaveMock")).deploy();
await factory.createPair(aave.address, dai.address);
const aavePairAddress = factory.getPair(aave.address, dai.address);
const aavePair = new Contract(
aavePairAddress,
JSON.stringify(IUniswapV2Pair.abi),
staker
).connect(founder);
await dai["mint(address,uint256)"](
founder.address,
ethers.utils.parseEther("500000000000000")
);
await aave["mint(address,uint256)"](
founder.address,
ethers.utils.parseEther("20000")
);
await addLiquidity(
dai,
aave,
aavePair,
ethers.utils.parseEther("2000000"),
ethers.utils.parseEther("2000")
);
await setDAOAddress("COMP", comp.address);
lendingPool = await lendingPoolFactory.deploy(usdc.address);
incentiveController = await (
await ethers.getContractFactory("IncentiveControllerMock")
).deploy(aave.address);
aaveUsdOracle = await (
await ethers.getContractFactory("AaveUSDMockOracle")
).deploy();
await setDAOAddress("AAVE", aave.address);
deployStaking = async () => {
return await goodAaveStakingFactory.deploy().then(async contract => {
await contract.init(
usdc.address,
lendingPool.address,
nameService.address,
"Good USDC",
"gUSDC",
"172800",
daiUsdOracle.address,
incentiveController.address,
aaveUsdOracle.address,
[usdc.address, dai.address]
);
return contract;
});
};
goodAaveStaking = await deployStaking();
await usdc["mint(address,uint256)"](
founder.address,
ethers.utils.parseUnits("500000000000000", 6)
);
await usdc["mint(address,uint256)"](
staker.address,
ethers.utils.parseUnits("10000", 6)
);
await usdc["mint(address,uint256)"](
lendingPool.address,
ethers.utils.parseEther("100000000")
); // We should put extra USDC to LendingPool/Atoken contract in order to provide interest
await addLiquidity(
usdc,
dai,
pair,
ethers.utils.parseUnits("200000000000000", 6),
ethers.utils.parseEther("200000000000000")
);
await usdc.approve(goodAaveStaking.address, ethers.constants.MaxUint256);
await usdc
.connect(staker)
.approve(goodAaveStaking.address, ethers.constants.MaxUint256);
const currentBlockNumber = await ethers.provider.getBlockNumber();
const encodedData = goodFundManagerFactory.interface.encodeFunctionData(
"setStakingReward",
[
"1000",
goodAaveStaking.address,
currentBlockNumber - 5,
currentBlockNumber + 500,
false
] // set 10 gd per block
);
await genericCall(goodFundManager.address, encodedData, avatar, 0);
await setDAOAddress("MARKET_MAKER", marketMaker.address);
});
it("it should stake usdc to lendingPool and withdraw", async () => {
const stakingAmount = ethers.utils.parseUnits("100", 6);
await goodAaveStaking.stake(stakingAmount, 0, false);
const aTokenBalanceAfterStake = await lendingPool.balanceOf(
goodAaveStaking.address
);
await goodAaveStaking.withdrawStake(stakingAmount, false);
const aTokenBalanceAfterWithdraw = await lendingPool.balanceOf(
goodAaveStaking.address
);
expect(aTokenBalanceAfterWithdraw).to.be.equal(0);
expect(aTokenBalanceAfterStake).to.be.gt(0);
expect(aTokenBalanceAfterStake).to.be.equal(stakingAmount);
});
it("stake should generate some interest and should be used to generate UBI", async () => {
const stakingAmount = ethers.utils.parseUnits("100", 6);
await goodAaveStaking.connect(staker).stake(stakingAmount, 0, false);
await lendingPool.giveInterestToUser("1500", goodAaveStaking.address); // increase interest by calling giveInterestToUser
const currentUBIInterestBeforeWithdraw = await goodAaveStaking.currentGains(
false,
true
);
await goodAaveStaking.connect(staker).withdrawStake(stakingAmount, false);
const gdBalanceBeforeCollectInterest = await goodDollar.balanceOf(
staker.address
);
const contractAddressesToBeCollected =
await goodFundManager.calcSortedContracts();
console.log(contractAddressesToBeCollected.toString());
const addressesToCollect = contractAddressesToBeCollected.map(x => x[0]);
await goodFundManager
.connect(staker)
.collectInterest(addressesToCollect, false);
const gdBalanceAfterCollectInterest = await goodDollar.balanceOf(
staker.address
);
const currentUBIInterestAfterWithdraw = await goodAaveStaking.currentGains(
false,
true
);
expect(currentUBIInterestBeforeWithdraw[0].toString()).to.not.be.equal("0");
expect(currentUBIInterestAfterWithdraw[0].toString()).to.be.equal("0");
expect(gdBalanceAfterCollectInterest.gt(gdBalanceBeforeCollectInterest));
});
it("it should collect stkAAVE to Avatar when collecting interest", async () => {
const stakingAmount = ethers.utils.parseUnits("100", 6);
const avatarBalance = await aave.balanceOf(avatar);
await goodAaveStaking.stake(stakingAmount, "0", false);
const currentGainsAfterStake = await goodAaveStaking.currentGains(
false,
true
);
await incentiveController.increaseRewardsBalance(
goodAaveStaking.address,
ethers.utils.parseEther("10")
);
const currentGainsAfterEarnRewards = await goodAaveStaking.currentGains(
false,
true
);
await lendingPool.giveInterestToUser(2000, goodAaveStaking.address);
const currentGainsAfterGetInterest = await goodAaveStaking.currentGains(
false,
true
);
const contractAddressesToBeCollected = await goodFundManager
.connect(staker)
.calcSortedContracts();
const addressesToCollect = contractAddressesToBeCollected.map(x => x[0]);
await goodFundManager.collectInterest(addressesToCollect, false, {
gasLimit: 1200000
});
const currentGainsAfterCollectInterest = await goodAaveStaking.currentGains(
false,
true
);
await goodAaveStaking.withdrawStake(stakingAmount, false);
expect(currentGainsAfterStake[4]).to.be.equal("0");
expect(currentGainsAfterGetInterest[4]).to.be.gt(
currentGainsAfterEarnRewards[4]
);
expect(currentGainsAfterEarnRewards[4]).to.be.equal(0); // stkAAVE rewards shouldnt count as gain
expect(currentGainsAfterCollectInterest[4]).to.be.equal("0");
expect(await aave.balanceOf(avatar)).gt(avatarBalance);
});
it("should be able to transfer staked tokens", async () => {
const stakingAmount = ethers.utils.parseUnits("100", 6);
await goodAaveStaking.connect(staker).stake(stakingAmount, 0, false);
await lendingPool.giveInterestToUser("1500", goodAaveStaking.address); // increase interest by calling giveInterestToUser
await expect(
goodAaveStaking
.connect(staker)
.transfer(signers[0].address, stakingAmount)
).not.reverted;
expect(await goodAaveStaking.balanceOf(signers[0].address)).to.eq(
stakingAmount
);
});
async function addLiquidity(
token0: Contract,
token1: Contract,
pair: Contract,
token0Amount: BigNumber,
token1Amount: BigNumber
) {
await token0.transfer(pair.address, token0Amount);
await token1.transfer(pair.address, token1Amount);
await pair.mint(founder.address);
}
it("should set gas cost to interest collection parameters", async () => {
const stakingContract = await deployStaking();
const collectGasCostBefore = await stakingContract.collectInterestGasCost();
const claimStakeGasCostBefore =
await stakingContract.collectInterestGasCost();
await runAsAvatarOnly(
stakingContract,
"setcollectInterestGasCostParams(uint32,uint32)",
999,
999
);
const collectGasCostAfter = await stakingContract.collectInterestGasCost();
const claimStakeGasCostAfter =
await stakingContract.collectInterestGasCost();
expect(collectGasCostAfter).to.not.equal(collectGasCostBefore);
expect(collectGasCostAfter).to.equal(999);
expect(claimStakeGasCostAfter).to.not.equal(claimStakeGasCostBefore);
expect(claimStakeGasCostAfter).to.equal(999);
});
});