import { expect } from "chai"; import hre from "hardhat"; const { waffle, ethers } = hre; const { provider } = waffle; const { BigNumber, utils } = ethers; import {deployAndEnableConnector} from "../../../scripts/tests/deployAndEnableConnector"; import {buildDSAv2} from "../../../scripts/tests/buildDSAv2"; import {encodeSpells} from "../../../scripts/tests/encodeSpells"; import {addresses} from "../../../scripts/tests/mainnet/addresses"; import {abis} from "../../../scripts/constant/abis"; import {impersonateAccounts} from "../../../scripts/tests/impersonate"; import type { Signer, Contract, BigNumberish } from "ethers"; import {forkReset, sendEth, mineNBlock} from "./utils"; import { ConnectV2Ubiquity__factory } from "../../../typechain"; import { abi as implementationsABI } from "../../../scripts/constant/abi/core/InstaImplementations.json"; const implementationsMappingAddr = "0xCBA828153d3a85b30B5b912e1f2daCac5816aE9D"; describe("Ubiquity", function () { const ubiquityTest = "UBIQUITY-TEST-A"; const BOND = "0x2dA07859613C14F6f05c97eFE37B9B4F212b5eF5"; const UAD = "0x0F644658510c95CB46955e55D7BA9DDa9E9fBEc6"; const DAI = "0x6B175474E89094C44Da98b954EedeAC495271d0F"; const USDC = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"; const USDT = "0xdAC17F958D2ee523a2206206994597C13D831ec7"; const CRV3 = "0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490"; const POOL3 = "0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7"; const UAD3CRVF = "0x20955CB69Ae1515962177D164dfC9522feef567E"; const ethWhaleAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; const uadWhaleAddress = "0xefC0e701A824943b469a694aC564Aa1efF7Ab7dd"; const blockFork = 13097100; const one = BigNumber.from(10).pow(18); const onep = BigNumber.from(10).pow(6); const ABI = [ "function balanceOf(address owner) view returns (uint256)", "function allowance(address owner, address spender) external view returns (uint256)", "function transfer(address to, uint amount) returns (boolean)", "function remove_liquidity_one_coin(uint256 _burn_amount, int128 i, uint256 _min_received) external returns (uint256)", "function add_liquidity(uint256[3],uint256) returns (uint256)", "function approve(address, uint256) external", "function holderTokens(address) view returns (uint256[])", "function getBond(uint256) view returns (tuple(address,uint256,uint256,uint256,uint256,uint256))" ]; let dsa: Contract; let POOL3Contract: Contract; let CRV3Contract: Contract; let uAD3CRVfContract: Contract; let uADContract: Contract; let DAIContract: Contract; let USDCContract: Contract; let USDTContract: Contract; let BONDContract: Contract; let instaIndex: Contract; let instaConnectorsV2: Contract; let connector: Contract; let instaImplementationsMapping; let InstaAccountV2DefaultImpl; let uadWhale; const bondingShare = async function (address: any) { let lpAmount = BigNumber.from(0); let lpAmountTotal = BigNumber.from(0); let bondId = -1; const bondIds = await BONDContract.holderTokens(address); const bondN = bondIds?.length || 0; if (bondN) { for await (bondId of bondIds) { lpAmountTotal = lpAmountTotal.add((await BONDContract.getBond(bondId))[5]); } bondId = Number(bondIds[bondN - 1]); lpAmount = (await BONDContract.getBond(bondId))[5]; } return { bondId, bondN, lpAmount, lpAmountTotal }; }; const depositAndGetOneBond = async function () { await dsaDepositUAD3CRVf(100); dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [UAD3CRVF, one.mul(100), 1, 0, 0] } ]), uadWhaleAddress ); }; before(async () => { // await forkReset(blockFork); await hre.network.provider.request({ method: "hardhat_reset", params: [ { forking: { // @ts-ignore jsonRpcUrl: hre.config.networks.hardhat.forking.url, blockNumber: 13097100, }, }, ], }); [uadWhale] = await impersonateAccounts([uadWhaleAddress]); const [ethWhale] = await impersonateAccounts([ethWhaleAddress]); await sendEth(ethWhale, uadWhaleAddress, 100); POOL3Contract = new ethers.Contract(POOL3, ABI, uadWhale); CRV3Contract = new ethers.Contract(CRV3, ABI, uadWhale); uAD3CRVfContract = new ethers.Contract(UAD3CRVF, ABI, uadWhale); uADContract = new ethers.Contract(UAD, ABI, uadWhale); DAIContract = new ethers.Contract(DAI, ABI, uadWhale); USDCContract = new ethers.Contract(USDC, ABI, uadWhale); USDTContract = new ethers.Contract(USDT, ABI, uadWhale); BONDContract = new ethers.Contract(BOND, ABI, uadWhale); dsa = (await buildDSAv2(uadWhaleAddress)).connect(uadWhale); await sendEth(ethWhale, dsa.address, 100); await sendEth(ethWhale, uadWhaleAddress, 100); instaIndex = new ethers.Contract(addresses.core.instaIndex, abis.core.instaIndex, ethWhale); const masterAddress = await instaIndex.master(); const [master] = await impersonateAccounts([masterAddress]); await sendEth(ethWhale, masterAddress, 100); instaConnectorsV2 = new ethers.Contract(addresses.core.connectorsV2, abis.core.connectorsV2); instaImplementationsMapping = await ethers.getContractAt(implementationsABI, implementationsMappingAddr); InstaAccountV2DefaultImpl = await ethers.getContractFactory("InstaDefaultImplementation"); InstaAccountV2DefaultImpl = await InstaAccountV2DefaultImpl.deploy(addresses.core.instaIndex); await InstaAccountV2DefaultImpl.deployed(); await ( await instaImplementationsMapping.connect(master).setDefaultImplementation(InstaAccountV2DefaultImpl.address) ).wait(); connector = await deployAndEnableConnector({ connectorName: ubiquityTest, contractArtifact: ConnectV2Ubiquity__factory, signer: master, connectors: instaConnectorsV2 }); }); const logAll = async function () { console.log("dsa eth", utils.formatEther(await ethers.provider.getBalance(dsa.address))); console.log("dsa dai", utils.formatEther(await DAIContract.balanceOf(dsa.address))); console.log("dsa usdc", utils.formatUnits(await USDCContract.balanceOf(dsa.address), 6)); console.log("dsa usdt", utils.formatUnits(await USDTContract.balanceOf(dsa.address), 6)); console.log("dsa uad", utils.formatEther(await uADContract.balanceOf(dsa.address))); console.log("dsa 3CRV", utils.formatEther(await CRV3Contract.balanceOf(dsa.address))); console.log("dsa uad3CRV-f", utils.formatEther(await uAD3CRVfContract.balanceOf(dsa.address))); const { bondId, bondN, lpAmount, lpAmountTotal } = await bondingShare(dsa.address); console.log("dsa n bonds", utils.formatEther(lpAmountTotal), bondN); console.log("dsa last bond", utils.formatEther(lpAmount), bondId); }; afterEach(logAll); const dsaDepositUAD3CRVf = async (amount: BigNumberish) => { await uAD3CRVfContract.transfer(dsa.address, one.mul(amount)); }; const dsaDepositUAD = async (amount: BigNumberish) => { await uAD3CRVfContract.remove_liquidity_one_coin(one.mul(amount).mul(110).div(100), 0, one.mul(amount)); await uADContract.transfer(dsa.address, one.mul(amount)); }; const dsaDepositCRV3 = async (amount: BigNumberish) => { await uAD3CRVfContract.remove_liquidity_one_coin(one.mul(amount).mul(110).div(100), 1, one.mul(amount)); await CRV3Contract.transfer(dsa.address, one.mul(amount)); }; const dsaDepositDAI = async (amount: BigNumberish) => { await uAD3CRVfContract.remove_liquidity_one_coin( one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100) ); await POOL3Contract.remove_liquidity_one_coin(one.mul(amount).mul(110).div(100), 0, one.mul(amount)); await DAIContract.transfer(dsa.address, one.mul(amount)); }; const dsaDepositUSDC = async (amount: BigNumberish) => { await uAD3CRVfContract.remove_liquidity_one_coin( one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100) ); await POOL3Contract.remove_liquidity_one_coin(one.mul(amount).mul(110).div(100), 1, onep.mul(amount)); await USDCContract.transfer(dsa.address, onep.mul(amount)); }; const dsaDepositUSDT = async (amount: BigNumberish) => { await uAD3CRVfContract.remove_liquidity_one_coin( one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100) ); await POOL3Contract.remove_liquidity_one_coin(one.mul(amount).mul(110).div(100), 2, onep.mul(amount)); await USDTContract.transfer(dsa.address, onep.mul(amount)); }; describe("Deposit", function () { it("should deposit uAD3CRVf to get Ubiquity Bonding Shares", async function () { await logAll(); await dsaDepositUAD3CRVf(100); expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [UAD3CRVF, one.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit uAD to get Ubiquity Bonding Shares", async function () { await dsaDepositUAD(100); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [UAD, one.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit 3CRV to get Ubiquity Bonding Shares", async function () { await dsaDepositCRV3(100); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [CRV3, one.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit DAI to get Ubiquity Bonding Shares", async function () { await dsaDepositDAI(100); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [DAI, one.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit USDC to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDC(100); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [USDC, onep.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit USDT to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDT(100); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", args: [USDT, onep.mul(100), 4, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); }); describe("Withdraw", function () { let bondId = -1; before(async () => { await depositAndGetOneBond(); await depositAndGetOneBond(); await depositAndGetOneBond(); await depositAndGetOneBond(); await depositAndGetOneBond(); await depositAndGetOneBond(); ({ bondId } = await bondingShare(dsa.address)); await logAll(); console.log("Mining 50 000 blocks for more than one week, please wait..."); await mineNBlock(50000, 1); }); it("Should deposit and withdraw DAI", async function () { await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId, DAI, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; }); it("Should deposit and withdraw USDC", async function () { // await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId - 1, USDC, 0, 0] } ]), uadWhaleAddress ); // ).to.be.not.reverted; }); it("Should deposit and withdraw USDT", async function () { await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId - 2, USDT, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; }); it("Should deposit and withdraw UAD", async function () { await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId - 3, UAD, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; }); it("Should deposit and withdraw CRV3", async function () { await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId - 4, CRV3, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; }); it("Should deposit and withdraw UAD3CRVF", async function () { await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "withdraw", args: [bondId - 5, UAD3CRVF, 0, 0] } ]), uadWhaleAddress ) ).to.be.not.reverted; }); }); describe("DSA wallet setup", function () { it("Should have contracts deployed.", async function () { expect(POOL3Contract.address).to.be.properAddress; expect(CRV3Contract.address).to.be.properAddress; expect(uADContract.address).to.be.properAddress; expect(uAD3CRVfContract.address).to.be.properAddress; expect(DAIContract.address).to.be.properAddress; expect(USDCContract.address).to.be.properAddress; expect(USDTContract.address).to.be.properAddress; expect(BONDContract.address).to.be.properAddress; expect(instaIndex.address).to.be.properAddress; expect(instaConnectorsV2.address).to.be.properAddress; expect(connector.address).to.be.properAddress; expect(dsa.address).to.be.properAddress; }); it("Should deposit uAD3CRVf into DSA wallet", async function () { await dsaDepositUAD3CRVf(100); expect(await uAD3CRVfContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); it("Should deposit uAD into DSA wallet", async function () { await dsaDepositUAD(100); expect(await uADContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); it("Should deposit 3CRV into DSA wallet", async function () { await dsaDepositCRV3(100); expect(await CRV3Contract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); it("Should deposit DAI into DSA wallet", async function () { await dsaDepositDAI(100); expect(await DAIContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); it("Should deposit USDC into DSA wallet", async function () { await dsaDepositUSDC(100); expect(await USDCContract.balanceOf(dsa.address)).to.be.gte(onep.mul(100)); }); it("Should deposit USDT into DSA wallet", async function () { await dsaDepositUSDT(100); expect(await USDTContract.balanceOf(dsa.address)).to.be.gte(onep.mul(100)); }); }); });