Merge pull request #93 from eccheung4/pooltogether-connector-polygon

Pooltogether Polygon connector
This commit is contained in:
Thrilok kumar 2021-10-21 00:02:57 +05:30 committed by GitHub
commit 2d186feb6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 716 additions and 2 deletions

View File

@ -9,12 +9,12 @@ abstract contract Helpers is DSMath, Basic {
/**
* @dev Aave Lending Pool Provider
*/
AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5);
AaveLendingPoolProviderInterface constant internal aaveProvider = AaveLendingPoolProviderInterface(0xd05e3E715d945B59290df0ae8eF85c1BdB684744);
/**
* @dev Aave Protocol Data Provider
*/
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x057835Ad21a177dbdd3090bB1CAE03EaCF78Fc6d);
AaveDataProviderInterface constant internal aaveData = AaveDataProviderInterface(0x7551b5D2763519d4e37e8B81929D336De671d46d);
/**
* @dev Aave Referral Code

View File

@ -0,0 +1,10 @@
pragma solidity ^0.7.0;
import { TokenFaucetInterface } from "./interface.sol";
contract Events {
event LogDepositTo(address prizePool, address to, uint256 amount, address controlledToken, uint256 getId, uint256 setId);
event LogWithdrawInstantlyFrom(address prizePool, address from, uint256 amount, address controlledToken, uint256 maximumExitFee, uint256 exitFee, uint256 getId, uint256 setId);
event LogClaim(address tokenFaucet, address user, uint256 claimed, uint256 setId);
event LogClaimAll(address tokenFaucetProxyFactory, address user, TokenFaucetInterface[] tokenFaucets);
}

View File

@ -0,0 +1,15 @@
pragma solidity ^0.7.0;
interface PrizePoolInterface {
function token() external view returns (address);
function depositTo( address to, uint256 amount, address controlledToken, address referrer) external;
function withdrawInstantlyFrom( address from, uint256 amount, address controlledToken, uint256 maximumExitFee) external returns (uint256);
}
interface TokenFaucetInterface {
function claim( address user) external returns (uint256);
}
interface TokenFaucetProxyFactoryInterface {
function claimAll(address user, TokenFaucetInterface[] calldata tokenFaucets) external;
}

View File

@ -0,0 +1,145 @@
pragma solidity ^0.7.0;
/**
* @title PoolTogether
* @dev Deposit & Withdraw from PoolTogether
*/
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { PrizePoolInterface, TokenFaucetInterface, TokenFaucetProxyFactoryInterface } from "./interface.sol";
import { TokenInterface } from "../../common/interfaces.sol";
import { Stores } from "../../common/stores.sol";
import { Events } from "./events.sol";
import { DSMath } from "../../common/math.sol";
import { Basic } from "../../common/basic.sol";
abstract contract PoolTogetherResolver is Events, DSMath, Basic {
using SafeERC20 for IERC20;
/**
* @dev Deposit into Prize Pool
* @notice Deposit assets into the Prize Pool in exchange for tokens
* @param prizePool PrizePool address to deposit to
* @param amount The amount of the underlying asset the user wishes to deposit. The Prize Pool contract should have been pre-approved by the caller to transfer the underlying ERC20 tokens.
* @param controlledToken The address of the token that they wish to mint. For our default Prize Strategy this will either be the Ticket address or the Sponsorship address. Those addresses can be looked up on the Prize Strategy.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function depositTo(
address prizePool,
uint256 amount,
address controlledToken,
uint256 getId,
uint256 setId
) external payable returns ( string memory _eventName, bytes memory _eventParam) {
uint _amount = getUint(getId, amount);
PrizePoolInterface prizePoolContract = PrizePoolInterface(prizePool);
address prizePoolToken = prizePoolContract.token();
bool isMatic = prizePoolToken == wmaticAddr;
TokenInterface tokenContract = TokenInterface(prizePoolToken);
if (isMatic) {
_amount = _amount == uint256(-1) ? address(this).balance : _amount;
convertMaticToWmatic(isMatic, tokenContract, _amount);
} else {
_amount = _amount == uint256(-1) ? tokenContract.balanceOf(address(this)) : _amount;
}
// Approve prizePool
approve(tokenContract, prizePool, _amount);
prizePoolContract.depositTo(address(this), _amount, controlledToken, address(0));
setUint(setId, _amount);
_eventName = "LogDepositTo(address,address,uint256,address,uint256,uint256)";
_eventParam = abi.encode(address(prizePool), address(this), _amount, address(controlledToken), getId, setId);
}
/**
* @dev Withdraw from Prize Pool
* @notice Withdraw assets from the Prize Pool instantly. A fairness fee may be charged for an early exit.
* @param prizePool PrizePool address to withdraw from
* @param amount The amount of tokens to redeem for assets.
* @param controlledToken The address of the token to redeem (i.e. ticket or sponsorship)
* @param maximumExitFee The maximum early exit fee the caller is willing to pay. This prevents the Prize Strategy from changing the fee on the fly. This should be pre-calculated by the calculateExitFee() fxn.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function withdrawInstantlyFrom (
address prizePool,
uint256 amount,
address controlledToken,
uint256 maximumExitFee,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amount = getUint(getId, amount);
PrizePoolInterface prizePoolContract = PrizePoolInterface(prizePool);
address prizePoolToken = prizePoolContract.token();
TokenInterface tokenContract = TokenInterface(prizePoolToken);
TokenInterface ticketToken = TokenInterface(controlledToken);
_amount = _amount == uint256(-1) ? ticketToken.balanceOf(address(this)) : _amount;
uint exitFee = prizePoolContract.withdrawInstantlyFrom(address(this), _amount, controlledToken, maximumExitFee);
_amount = _amount - exitFee;
convertWmaticToMatic(prizePoolToken == wmaticAddr, tokenContract, _amount);
setUint(setId, _amount);
_eventName = "LogWithdrawInstantlyFrom(address,address,uint256,address,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(address(prizePool), address(this), _amount, address(controlledToken), maximumExitFee, exitFee, getId, setId);
}
/**
* @dev Claim token from a Token Faucet
* @notice Claim token from a Token Faucet
* @param tokenFaucet TokenFaucet address
* @param setId Set claimed amount at this ID in `InstaMemory` Contract.
*/
function claim (
address tokenFaucet,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
TokenFaucetInterface tokenFaucetContract = TokenFaucetInterface(tokenFaucet);
uint256 claimed = tokenFaucetContract.claim(address(this));
setUint(setId, claimed);
_eventName = "LogClaim(address,address, uint256, uint256)";
_eventParam = abi.encode(address(tokenFaucet), address(this), claimed, setId);
}
/**
* @dev Runs claim on all passed comptrollers for a user.
* @notice Runs claim on all passed comptrollers for a user.
* @param tokenFaucetProxyFactory The TokenFaucetProxyFactory address
* @param tokenFaucets The tokenFaucets to call claim on.
*/
function claimAll (
address tokenFaucetProxyFactory,
TokenFaucetInterface[] calldata tokenFaucets
) external payable returns (string memory _eventName, bytes memory _eventParam) {
TokenFaucetProxyFactoryInterface tokenFaucetProxyFactoryContract = TokenFaucetProxyFactoryInterface(tokenFaucetProxyFactory);
tokenFaucetProxyFactoryContract.claimAll(address(this), tokenFaucets);
_eventName = "LogClaimAll(address,address,TokenFaucetInterface[])";
_eventParam = abi.encode(address(tokenFaucetProxyFactory), address(this), tokenFaucets);
}
}
contract ConnectV2PoolTogetherPolygon is PoolTogetherResolver {
string public constant name = "PoolTogether-v1";
}

View File

@ -0,0 +1,15 @@
const hre = require("hardhat");
const { ethers } = hre;
const addresses = require("./constant/addresses");
const abis = require("../constant/abis");
const instaImplementations_m1 = require("../../deployements/mainnet/Implementation_m1.sol/InstaImplementationM1.json")
module.exports = async function (owner) {
const instaIndex = await ethers.getContractAt(abis.core.instaIndex, addresses.core.instaIndex)
const tx = await instaIndex.build(owner, 2, owner);
const receipt = await tx.wait()
const event = receipt.events.find(a => a.event === "LogAccountCreated")
return await ethers.getContractAt(instaImplementations_m1.abi, event.args.account)
};

View File

@ -0,0 +1,10 @@
module.exports = {
connectors: {
basic: "0x1cAF5EC802ca602E98139AD96A8f2B7BC524264E",
auth: "0xf6474aD0dA75A0dE15D2c915e601D9f754B9e6fe",
},
core: {
connectorsV2: "0x2A00684bFAb9717C21271E0751BCcb7d2D763c88",
instaIndex: "0xA9B99766E6C676Cf1975c0D3166F96C0848fF5ad",
},
};

View File

@ -0,0 +1,7 @@
module.exports = {
address_zero: "0x0000000000000000000000000000000000000000",
eth_addr: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
matic_addr: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
max_value: "115792089237316195423570985008687907853269984665640564039457584007913129639935"
};

View File

@ -0,0 +1,30 @@
module.exports = {
"matic": {
"type": "token",
"symbol": "MATIC",
"name": "Matic",
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"decimals": 18
},
"eth": {
"type": "token",
"symbol": "ETH",
"name": "Ethereum",
"address": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"decimals": 18
},
"dai": {
"type": "token",
"symbol": "DAI",
"name": "DAI Stable",
"address": "0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063",
"decimals": 18
},
"usdc": {
"type": "token",
"symbol": "USDC",
"name": "USD Coin",
"address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
"decimals": 6
}
}

View File

@ -0,0 +1,19 @@
const abis = require("../constant/abis");
const addresses = require("./constant/addresses");
const hre = require("hardhat");
const { ethers, waffle } = hre;
const { deployContract } = waffle;
const fs = require("fs")
module.exports = async function ({connectorName, contractArtifact, signer, connectors}) {
const connectorInstanace = await deployContract(signer, contractArtifact, []);
await connectors.connect(signer).addConnectors([connectorName], [connectorInstanace.address])
addresses.connectors[connectorName] = connectorInstanace.address
abis.connectors[connectorName] = contractArtifact.abi;
return connectorInstanace;
};

View File

@ -0,0 +1,18 @@
const abis = require("../constant/abis");
const addresses = require("./constant/addresses");
const { web3 } = hre;
module.exports = function (spells) {
const targets = spells.map(a => a.connector)
const calldatas = spells.map(a => {
const functionName = a.method;
// console.log(functionName)
const abi = abis.connectors[a.connector].find(b => {
return b.name === functionName
});
// console.log(functionName)
if (!abi) throw new Error("Couldn't find function")
return web3.eth.abi.encodeFunctionCall(abi, a.args)
})
return [targets, calldatas]
};

View File

@ -0,0 +1,25 @@
const hre = require("hardhat");
const { ethers } = hre;
const addresses = require("./constant/addresses");
const abis = require("../constant/abis");
module.exports = async function() {
const [_, __, ___, wallet3] = await ethers.getSigners();
const instaIndex = new ethers.Contract(
addresses.core.instaIndex,
abis.core.instaIndex,
wallet3
);
const masterAddress = await instaIndex.master(); // TODO: make it constant?
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [masterAddress],
});
await wallet3.sendTransaction({
to: masterAddress,
value: ethers.utils.parseEther("10"),
});
return await ethers.getSigner(masterAddress);
};

View File

@ -0,0 +1,420 @@
const { expect } = require("chai");
const hre = require("hardhat");
const { web3, deployments, waffle, ethers } = hre;
const { provider, deployContract } = waffle
const ALCHEMY_ID = process.env.ALCHEMY_ID;
const deployAndEnableConnector = require("../../scripts/polygon/deployAndEnableConnector.js")
const buildDSAv2 = require("../../scripts/polygon/buildDSAv2")
const encodeSpells = require("../../scripts/polygon/encodeSpells.js")
const getMasterSigner = require("../../scripts/polygon/getMasterSigner")
const addresses = require("../../scripts/polygon/constant/addresses");
const abis = require("../../scripts/constant/abis");
const constants = require("../../scripts/polygon/constant/constant");
const tokens = require("../../scripts/polygon/constant/tokens");
const connectV2AaveV2Artifacts = require("../../artifacts/contracts/polygon/connectors/aave/v2/main.sol/ConnectV2AaveV2Polygon.json")
const connectV2PoolTogetherArtifacts = require("../../artifacts/contracts/polygon/connectors/pooltogether/main.sol/ConnectV2PoolTogetherPolygon.json")
const DAI_TOKEN_ADDR = tokens.dai.address // DAI Token
// PoolTogether Address: https://docs.pooltogether.com/resources/networks/matic
const USDC_PRIZE_POOL_ADDR = "0xEE06AbE9e2Af61cabcb13170e01266Af2DEFa946" // USDC Prize Pool
const PT_USDC_TICKET_ADDR = "0x473E484c722EF9ec6f63B509b07Bb9cfB258820b" // PT USDC Ticket
const PT_USDC_SPONGSOR_TICKET_ADDR = "0x19c0e557ee5a9b456f613ba3d025a4dc45b52c35" // PT USDC Sponsor Ticket
const USDC_POOL_FAUCET_ADDR = "0x6cbc003fE015D753180f072d904bA841b2415498" // USDC POOL Faucet
const POOL_TOKEN_ADDRESS = "0x25788a1a171ec66Da6502f9975a15B609fF54CF6" // POOL Tocken
const TOKEN_FAUCET_PROXY_FACTORY_ADDR = "0xeaa636304a7C8853324B6b603dCdE55F92dfbab1" // TokenFaucetProxyFactory for claimAll
// Community WETH Prize Pool (Rari): https://reference-app.pooltogether.com/pools/mainnet/0xa88ca010b32a54d446fc38091ddbca55750cbfc3/manage#stats
const WETH_PRIZE_POOL_ADDR = "0xa88ca010b32a54d446fc38091ddbca55750cbfc3" // Community WETH Prize Pool (Rari)
const WETH_POOL_TICKET_ADDR = "0x9b5c30aeb9ce2a6a121cea9a85bc0d662f6d9b40" // Community WETH Prize Pool Ticket (Rari)
const prizePoolABI = [
"function calculateEarlyExitFee( address from, address controlledToken, uint256 amount) external returns ( uint256 exitFee, uint256 burnedCredit)",
"function creditPlanOf( address controlledToken) external view returns ( uint128 creditLimitMantissa, uint128 creditRateMantissa)"
]
const connectorsABI = [
"function isConnectors(string[] calldata connectorNames) external view returns (bool, address[] memory)"
]
describe("PoolTogether", function () {
const connectorName = "AAVEV2-TEST-A"
const ptConnectorName = "POOLTOGETHER-TEST-A"
let dsaWallet0
let masterSigner;
let instaConnectorsV2;
let connector;
let ptConnector;
const wallets = provider.getWallets()
const [wallet0, wallet1, wallet2, wallet3] = wallets
before(async () => {
await hre.network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: `https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_ID}`,
blockNumber: 18717337,
},
},
],
});
masterSigner = await getMasterSigner()
instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2);
// Deploy and enable Compound Connector
connector = await deployAndEnableConnector({
connectorName,
contractArtifact: connectV2AaveV2Artifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
// Deploy and enable Pool Together Connector
ptConnector = await deployAndEnableConnector({
connectorName: ptConnectorName,
contractArtifact: connectV2PoolTogetherArtifacts,
signer: masterSigner,
connectors: instaConnectorsV2
})
})
it("Should have contracts deployed.", async function () {
expect(!!instaConnectorsV2.address).to.be.true;
expect(!!connector.address).to.be.true;
expect(!!ptConnector.address).to.be.true;
expect(!!masterSigner.address).to.be.true;
});
describe("DSA wallet setup", function () {
it("Should build DSA v2", async function () {
dsaWallet0 = await buildDSAv2(wallet0.address)
expect(!!dsaWallet0.address).to.be.true;
});
it("Deposit 1000 MATIC into DSA wallet", async function () {
await wallet0.sendTransaction({
to: dsaWallet0.address,
value: ethers.utils.parseEther("1000")
});
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("1000"));
});
});
describe("Main - USDC Prize Pool Test", function () {
it("Should deposit 100 MATIC in AAVE V2", async function () {
const amount = ethers.utils.parseEther("100") // 100 MATIC
const spells = [
{
connector: connectorName,
method: "deposit",
args: [tokens.matic.address, amount, 0, 0]
}
]
const tx = await dsaWallet0.cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("900"));
});
it("Should borrow 10 USDC from AAVE V2 and deposit USDC into USDC Prize Pool", async function () {
const amount = ethers.utils.parseUnits("10", 6) // 10 USDC
const setId = "83478237"
const spells = [
{
connector: connectorName,
method: "borrow",
args: [tokens.usdc.address, amount, 2, 0, setId]
},
{
connector: ptConnectorName,
method: "depositTo",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_SPONGSOR_TICKET_ADDR, setId, 0]
}
]
// Before Spell
let usdcToken = await ethers.getContractAt(abis.basic.erc20, tokens.usdc.address)
let usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `USDC balance is 0`).to.be.eq(ethers.utils.parseUnits("0", 6));
let cToken = await ethers.getContractAt(abis.basic.erc20, PT_USDC_SPONGSOR_TICKET_ADDR)
const balance = await cToken.balanceOf(dsaWallet0.address)
expect(balance,`PoolTogether USDC Ticket balance is 0`).to.be.eq(0);
// Run spell transaction
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
// After spell
usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `Expect USDC balance to still equal 0 since it was deposited into Prize Pool`).to.be.eq(0);
const balanceAfter = await cToken.balanceOf(dsaWallet0.address)
expect(balanceAfter, `PoolTogether USDC Ticket balance equals 10`).to.be.eq(ethers.utils.parseUnits("10", 6));
// ETH used for transaction
expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("900"));
});
it("Should wait 11 days, withdraw all PrizePool, get back 10 USDC, and claim POOL", async function () {
const amount = ethers.utils.parseUnits("10", 6) // 10 USDC
let prizePoolContract = new ethers.Contract(USDC_PRIZE_POOL_ADDR, prizePoolABI, ethers.provider);
// const { creditLimitMantissa, creditRateMantissa } = await prizePoolContract.creditPlanOf(PT_USDC_TICKET_ADDR);
// console.log("CreditLimitMantiss: ", creditLimitMantissa.toString());
// console.log("CreditRateMantiss: ", creditRateMantissa.toString());
let earlyExitFee = await prizePoolContract.callStatic["calculateEarlyExitFee"](dsaWallet0.address, PT_USDC_SPONGSOR_TICKET_ADDR, amount);
expect(earlyExitFee.exitFee, "Exit Fee equal to 0 USDC because 0% fee for sponsorship ticket").to.be.eq(ethers.utils.parseUnits("0", 6));
const spells = [
{
connector: ptConnectorName,
method: "claim",
args: [USDC_POOL_FAUCET_ADDR, 0]
},
{
connector: ptConnectorName,
method: "withdrawInstantlyFrom",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_SPONGSOR_TICKET_ADDR, earlyExitFee.exitFee, 0, 0]
}
]
// Before spell
let usdcToken = await ethers.getContractAt(abis.basic.erc20, tokens.usdc.address)
let usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `USDC balance equals 0`).to.be.eq(ethers.utils.parseEther("0"));
let cToken = await ethers.getContractAt(abis.basic.erc20, PT_USDC_SPONGSOR_TICKET_ADDR)
const balance = await cToken.balanceOf(dsaWallet0.address)
expect(balance, `PoolTogether USDC Ticket is 10`).to.be.eq(ethers.utils.parseUnits("10", 6));
let poolToken = await ethers.getContractAt(abis.basic.erc20, POOL_TOKEN_ADDRESS)
const poolBalance = await poolToken.balanceOf(dsaWallet0.address)
expect(poolBalance, `POOL Token equals 0`).to.be.eq(ethers.utils.parseEther("0"));
// Increase time by 11 days so we get back all USDC without early withdrawal fee
await ethers.provider.send("evm_increaseTime", [15*24*60*60]);
await ethers.provider.send("evm_mine");
earlyExitFee = await prizePoolContract.callStatic["calculateEarlyExitFee"](dsaWallet0.address, PT_USDC_SPONGSOR_TICKET_ADDR, amount);
expect(earlyExitFee.exitFee, "Exit Fee equal to 0 DAI because past 14 days").to.be.eq(0);
// Run spell transaction
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
// After spell
usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
console.log("USDC BALANCE: ", usdcBalance.toString());
console.log("USDC BALANCE: ", ethers.utils.parseUnits("10", 6).toString());
expect(usdcBalance,
`USDC balance to be equal to 10, because of no early withdrawal fee`
).to.be.eq(ethers.utils.parseUnits("10", 6));
const balanceAfter = await cToken.balanceOf(dsaWallet0.address)
expect(balanceAfter, `PoolTogether USDC Ticket to equal 0`).to.be.eq(0);
const poolBalanceAfter = await poolToken.balanceOf(dsaWallet0.address)
console.log("POOL BALANCE AFTER:" ,poolBalanceAfter.toString());
expect(poolBalanceAfter, `POOL Token Balance to be greater than 0`).to.be.gt(ethers.utils.parseEther("0"));
});
it("Should deposit and withdraw all PrizePool, get back less than 10 USDC", async function() {
const amount = ethers.utils.parseUnits("10", 6) // 10 USDC
const exitFee = ethers.utils.parseUnits(".1", 6) // 1 USDC is 1% of 100 USDC
const spells = [
{
connector: ptConnectorName,
method: "depositTo",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_TICKET_ADDR, 0, 0]
},
{
connector: ptConnectorName,
method: "withdrawInstantlyFrom",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_TICKET_ADDR, exitFee, 0, 0]
}
]
// Before spell
let usdcToken = await ethers.getContractAt(abis.basic.erc20, tokens.usdc.address)
let usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `USDC Balance equals 100`).to.be.eq(ethers.utils.parseUnits("10", 6));
let cToken = await ethers.getContractAt(abis.basic.erc20, PT_USDC_TICKET_ADDR)
const balance = await cToken.balanceOf(dsaWallet0.address)
expect(balance, `PoolTogether USDC Ticket equals 0`).to.be.eq(0);
let poolToken = await ethers.getContractAt(abis.basic.erc20, POOL_TOKEN_ADDRESS)
const poolBalance = await poolToken.balanceOf(dsaWallet0.address)
expect(poolBalance, `PoolTogether Token greater than 0`).to.be.gt(0);
// Run spell transaction
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
const receipt = await tx.wait()
// After spell
usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance,
`USDC balance to be less than 10, because of early withdrawal fee`
).to.be.lt(ethers.utils.parseUnits("10",6));
console.log("USDC BALANCE AFTER:", usdcBalance.toString());
const balanceAfter = await cToken.balanceOf(dsaWallet0.address)
expect(balanceAfter, `PoolTogether USDC Ticket to equal 0`).to.be.eq(0);
const poolBalanceAfter = await poolToken.balanceOf(dsaWallet0.address)
expect(poolBalanceAfter, `POOL Token Balance to greater than 0`).to.be.gt(ethers.utils.parseEther("0"));
});
it("Should deposit, wait 11 days, and withdraw all PrizePool, get 10 USDC, and claim all POOL using claimAll", async function() {
const amount = ethers.utils.parseUnits("9.9", 6) // 9 USDC
const depositSpells = [
{
connector: ptConnectorName,
method: "depositTo",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_SPONGSOR_TICKET_ADDR, 0, 0]
}
]
// Before spell
let usdcToken = await ethers.getContractAt(abis.basic.erc20, tokens.usdc.address)
let usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `USDC balance less than 10`).to.be.lt(ethers.utils.parseUnits("10", 6));
let cToken = await ethers.getContractAt(abis.basic.erc20, PT_USDC_SPONGSOR_TICKET_ADDR)
const balance = await cToken.balanceOf(dsaWallet0.address)
expect(balance, `PoolTogether USDC Ticket equal 0`).to.be.eq(0);
let poolToken = await ethers.getContractAt(abis.basic.erc20, POOL_TOKEN_ADDRESS)
const poolBalance = await poolToken.balanceOf(dsaWallet0.address)
expect(poolBalance, `POOL Token is greater than 0`).to.be.gt(ethers.utils.parseEther("0"));
// Run spell transaction
const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(depositSpells), wallet1.address)
const receipt = await tx.wait()
const prizePoolContract = new ethers.Contract(USDC_PRIZE_POOL_ADDR, prizePoolABI, ethers.provider);
let earlyExitFee = await prizePoolContract.callStatic["calculateEarlyExitFee"](dsaWallet0.address, PT_USDC_SPONGSOR_TICKET_ADDR, amount);
expect(earlyExitFee.exitFee, "Exit Fee equal to 0 USDC because fee 0%").to.be.eq(0);
// Increase time by 11 days so we get back all DAI without early withdrawal fee
await ethers.provider.send("evm_increaseTime", [11*24*60*60]);
await ethers.provider.send("evm_mine");
const withdrawSpells = [
{
connector: ptConnectorName,
method: "withdrawInstantlyFrom",
args: [USDC_PRIZE_POOL_ADDR, amount, PT_USDC_SPONGSOR_TICKET_ADDR, earlyExitFee.exitFee, 0, 0]
},
{
connector: ptConnectorName,
method: "claimAll",
args: [TOKEN_FAUCET_PROXY_FACTORY_ADDR, [USDC_POOL_FAUCET_ADDR]]
}
]
// Run spell transaction
const tx2 = await dsaWallet0.connect(wallet0).cast(...encodeSpells(withdrawSpells), wallet1.address)
const receipt2 = await tx2.wait()
// After spell
usdcBalance = await usdcToken.balanceOf(dsaWallet0.address);
expect(usdcBalance, `USDC balance equals 9.9`).to.be.eq(ethers.utils.parseUnits("9.9", 6));
const balanceAfter = await cToken.balanceOf(dsaWallet0.address)
expect(balanceAfter, `PoolTogether USDC Ticket equal 0`).to.be.eq(0);
// Expect
const poolBalanceAfter = await poolToken.balanceOf(dsaWallet0.address)
console.log("POOL BALANCE AFTER:" ,poolBalanceAfter.toString());
expect(poolBalanceAfter, `Pool Token to be greater than before`).to.be.gt(poolBalance);
});
// })
// NO WMATIC POOLS: https://reference-app.pooltogether.com/pools/polygon
// describe("Main - WETH Prize Pool Test", function () {
// it("Deposit 1 ETH into WETH Prize Pool and withdraw immediately", async function () {
// const amount = ethers.utils.parseEther("1") // 1 ETH
// const setId = "83478237"
// const spells = [
// {
// connector: ptConnectorName,
// method: "depositTo",
// args: [WETH_PRIZE_POOL_ADDR, amount, WETH_POOL_TICKET_ADDR, 0, setId]
// },
// {
// connector: ptConnectorName,
// method: "withdrawInstantlyFrom",
// args: [WETH_PRIZE_POOL_ADDR, amount, WETH_POOL_TICKET_ADDR, amount, setId, 0]
// },
// ]
// // Before Spell
// const ethBalanceBefore = await ethers.provider.getBalance(dsaWallet0.address);
// // Run spell transaction
// const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address)
// const receipt = await tx.wait()
// // After spell
// const ethBalanceAfter = await ethers.provider.getBalance(dsaWallet0.address);
// // ETH used for transaction
// expect(ethBalanceAfter, `ETH Balance less than before spell because of early withdrawal fee`).to.be.lte(ethBalanceBefore);
// });
// it("Deposit 1 ETH into WETH Prize Pool, wait 14 days, then withdraw", async function () {
// const amount = ethers.utils.parseEther("1") // 1 ETH
// const depositSpell = [
// {
// connector: ptConnectorName,
// method: "depositTo",
// args: [WETH_PRIZE_POOL_ADDR, amount, WETH_POOL_TICKET_ADDR, 0, 0]
// }
// ]
// const withdrawSpell = [
// {
// connector: ptConnectorName,
// method: "withdrawInstantlyFrom",
// args: [WETH_PRIZE_POOL_ADDR, amount, WETH_POOL_TICKET_ADDR, amount, 0, 0]
// }
// ]
// // Before Deposit Spell
// let ethBalanceBefore = await ethers.provider.getBalance(dsaWallet0.address);
// // Run deposit spell transaction
// const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(depositSpell), wallet1.address)
// const receipt = await tx.wait()
// // After Deposit spell
// let ethBalanceAfter = await ethers.provider.getBalance(dsaWallet0.address);
// expect(ethBalanceAfter, `ETH Balance less than before spell`).to.be.lte(ethBalanceBefore);
// // Increase time by 11 days so we get back all ETH without early withdrawal fee
// await ethers.provider.send("evm_increaseTime", [14*24*60*60]);
// await ethers.provider.send("evm_mine");
// // Run withdraw spell transaction
// const tx2 = await dsaWallet0.connect(wallet0).cast(...encodeSpells(withdrawSpell), wallet1.address)
// const receipt2 = await tx.wait()
// // After Deposit spell
// ethBalanceAfter = await ethers.provider.getBalance(dsaWallet0.address);
// expect(ethBalanceAfter, `ETH Balance equal to before spell because no early exit fee`).to.be.eq(ethBalanceBefore);
// });
});
})