From a12320f8fde9cfa62efee61e31012ba252c8c8a1 Mon Sep 17 00:00:00 2001 From: "zapaz.eth" Date: Mon, 11 Oct 2021 18:47:51 +0200 Subject: [PATCH 1/5] ubiquity connector after rebase main --- .../mainnet/connectors/ubiquity/events.sol | 15 + .../mainnet/connectors/ubiquity/helpers.sol | 40 +++ .../connectors/ubiquity/interfaces.sol | 31 ++ .../mainnet/connectors/ubiquity/main.sol | 137 ++++++++ hardhat.config.js | 4 + test/ubiquity/ubiquity.test.js | 316 ++++++++++++++++++ test/ubiquity/utils.js | 24 ++ 7 files changed, 567 insertions(+) create mode 100644 contracts/mainnet/connectors/ubiquity/events.sol create mode 100644 contracts/mainnet/connectors/ubiquity/helpers.sol create mode 100644 contracts/mainnet/connectors/ubiquity/interfaces.sol create mode 100644 contracts/mainnet/connectors/ubiquity/main.sol create mode 100644 test/ubiquity/ubiquity.test.js create mode 100644 test/ubiquity/utils.js diff --git a/contracts/mainnet/connectors/ubiquity/events.sol b/contracts/mainnet/connectors/ubiquity/events.sol new file mode 100644 index 00000000..acdc679b --- /dev/null +++ b/contracts/mainnet/connectors/ubiquity/events.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; + +contract Events { + event Deposit( + address indexed userAddress, + address indexed token, + uint256 amount, + uint256 lpAmount, + uint256 durationWeeks, + uint256 indexed bondingShareId, + uint256 getId, + uint256 setId + ); +} diff --git a/contracts/mainnet/connectors/ubiquity/helpers.sol b/contracts/mainnet/connectors/ubiquity/helpers.sol new file mode 100644 index 00000000..c1fb4e34 --- /dev/null +++ b/contracts/mainnet/connectors/ubiquity/helpers.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; + +import {TokenInterface} from "../../common/interfaces.sol"; +import {DSMath} from "../../common/math.sol"; +import {Basic} from "../../common/basic.sol"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Ubiquity Algorithmic Dollar Manager Address + */ + address internal constant UbiquityAlgorithmicDollarManager = + 0x4DA97a8b831C345dBe6d16FF7432DF2b7b776d98; + + /** + * @dev DAI Address + */ + address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + + /** + * @dev USDC Address + */ + address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + /** + * @dev USDT Address + */ + address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + + /** + * @dev Curve 3CRV Token Address + */ + address internal constant CRV3 = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490; + + /** + * @dev Curve 3Pool Address + */ + address internal constant Pool3 = + 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; +} diff --git a/contracts/mainnet/connectors/ubiquity/interfaces.sol b/contracts/mainnet/connectors/ubiquity/interfaces.sol new file mode 100644 index 00000000..dad4f1ea --- /dev/null +++ b/contracts/mainnet/connectors/ubiquity/interfaces.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.7.6; + +import {TokenInterface} from "../../common/interfaces.sol"; + +interface IUbiquityBondingV2 { + function deposit(uint256 lpAmount, uint256 durationWeeks) + external + returns (uint256 bondingShareId); +} + +interface IUbiquityMetaPool { + function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) + external + returns (uint256); +} + +interface IUbiquity3Pool { + function add_liquidity( + uint256[3] calldata _amounts, + uint256 _min_mint_amount + ) external; +} + +interface IUbiquityAlgorithmicDollarManager { + function dollarTokenAddress() external returns (address); + + function stableSwapMetaPoolAddress() external returns (address); + + function bondingContractAddress() external returns (address); +} diff --git a/contracts/mainnet/connectors/ubiquity/main.sol b/contracts/mainnet/connectors/ubiquity/main.sol new file mode 100644 index 00000000..6b2840a3 --- /dev/null +++ b/contracts/mainnet/connectors/ubiquity/main.sol @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.7.6; +pragma abicoder v2; + +/** + * @title Ubiquity. + * @dev Ubiquity Dollar (uAD). + */ + +import {TokenInterface, MemoryInterface} from "../../common/interfaces.sol"; +import {Stores} from "../../common/stores.sol"; +import {SafeMath} from "../../common/math.sol"; +import {IUbiquityBondingV2, IUbiquityMetaPool, IUbiquity3Pool, IUbiquityAlgorithmicDollarManager} from "./interfaces.sol"; +import {Helpers} from "./helpers.sol"; +import {Events} from "./events.sol"; + +contract ConnectV2Ubiquity is Helpers, Events { + string public constant name = "Ubiquity-v1"; + + /** + * @dev Deposit into Ubiquity protocol + * @notice 3POOL (DAI / USDC / USDT) => METAPOOL (3CRV / uAD) => uAD3CRV-f => Ubiquity BondingShare + * @notice STEP 1 : 3POOL (DAI / USDC / USDT) => 3CRV + * @notice STEP 2 : METAPOOL(3CRV / UAD) => uAD3CRV-f + * @notice STEP 3 : uAD3CRV-f => Ubiquity BondingShare + * @param token Token deposited : DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f + * @param amount Amount of tokens to deposit (For max: `uint256(-1)`) + * @param durationWeeks Duration in weeks tokens will be locked (4-208) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + address token, + uint256 amount, + uint256 durationWeeks, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + address UAD = IUbiquityAlgorithmicDollarManager( + UbiquityAlgorithmicDollarManager + ).dollarTokenAddress(); + address UAD3CRVf = IUbiquityAlgorithmicDollarManager( + UbiquityAlgorithmicDollarManager + ).stableSwapMetaPoolAddress(); + + require( + token == DAI || + token == USDC || + token == USDT || + token == UAD || + token == CRV3 || + token == UAD3CRVf, + "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" + ); + + uint256 _amount = getUint(getId, amount); + uint256 _lpAmount; + + // Full balance if amount = -1 + if (_amount == uint256(-1)) { + _amount = getTokenBal(TokenInterface(token)); + } + + // STEP 1 : SwapTo3CRV : Deposit DAI, USDC or USDT into 3Pool to get 3Crv LPs + if (token == DAI || token == USDC || token == USDT) { + uint256[3] memory amounts1; + + if (token == DAI) amounts1[0] = _amount; + else if (token == USDC) amounts1[1] = _amount; + else if (token == USDT) amounts1[2] = _amount; + + approve(TokenInterface(token), Pool3, _amount); + IUbiquity3Pool(Pool3).add_liquidity(amounts1, 0); + } + + // STEP 2 : ProvideLiquidityToMetapool : Deposit in uAD3CRV pool to get uAD3CRV-f LPs + if ( + token == DAI || + token == USDC || + token == USDT || + token == UAD || + token == CRV3 + ) { + uint256[2] memory amounts2; + address token2 = token; + uint256 _amount2; + + if (token == UAD) { + _amount2 = _amount; + amounts2[0] = _amount2; + } else { + if (token == CRV3) { + _amount2 = _amount; + } else { + token2 = CRV3; + _amount2 = getTokenBal(TokenInterface(token2)); + } + amounts2[1] = _amount2; + } + + approve(TokenInterface(token2), UAD3CRVf, _amount2); + _lpAmount = IUbiquityMetaPool(UAD3CRVf).add_liquidity(amounts2, 0); + } + + // STEP 3 : Farm/ApeIn : Deposit uAD3CRV-f LPs into UbiquityBondingV2 and get Ubiquity Bonding Shares + if (token == UAD3CRVf) { + _lpAmount = _amount; + } + + address Bonding = IUbiquityAlgorithmicDollarManager( + UbiquityAlgorithmicDollarManager + ).bondingContractAddress(); + approve(TokenInterface(UAD3CRVf), Bonding, _lpAmount); + uint256 bondingShareId = IUbiquityBondingV2(Bonding).deposit( + _lpAmount, + durationWeeks + ); + + setUint(setId, bondingShareId); + + _eventName = "Deposit(address,address,uint256,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode( + address(this), + token, + amount, + _lpAmount, + durationWeeks, + bondingShareId, + getId, + setId + ); + } +} diff --git a/hardhat.config.js b/hardhat.config.js index 04300869..9c2b5b86 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -65,6 +65,10 @@ module.exports = { blockNumber: 12696000, }, blockGasLimit: 12000000, + gasPrice: parseInt(utils.parseUnits("300", "gwei")), + }, + local: { + url: "http://127.0.0.1:8545", }, matic: { url: "https://rpc-mainnet.maticvigil.com/", diff --git a/test/ubiquity/ubiquity.test.js b/test/ubiquity/ubiquity.test.js new file mode 100644 index 00000000..e4b661ee --- /dev/null +++ b/test/ubiquity/ubiquity.test.js @@ -0,0 +1,316 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); +const { waffle, ethers } = hre; +const { provider } = waffle; +const { BigNumber } = ethers; + +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js"); +const buildDSAv2 = require("../../scripts/buildDSAv2"); +const encodeSpells = require("../../scripts/encodeSpells"); +const addresses = require("../../scripts/constant/addresses"); +const abis = require("../../scripts/constant/abis"); +const impersonate = require("../../scripts/impersonate"); +const { forkReset, sendEth } = require("./utils"); + +const connectV2UbiquityArtifacts = require("../../artifacts/contracts/mainnet/connectors/ubiquity/main.sol/ConnectV2Ubiquity.json"); + +const { abi: implementationsABI } = require("../../scripts/constant/abi/core/InstaImplementations.json") +const implementationsMappingAddr = "0xCBA828153d3a85b30B5b912e1f2daCac5816aE9D" + +describe.only("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; + let POOL3Contract; + let CRV3Contract; + let uAD3CRVfContract; + let uADContract; + let DAIContract; + let USDCContract; + let USDTContract; + let BONDContract; + let instaIndex; + let instaConnectorsV2; + let connector; + let instaImplementationsMapping; + let InstaAccountV2DefaultImpl; + + let uadWhale; + + const bondingShareLpAmount = async function (address) { + let LP = 0; + const bondId = await BONDContract.holderTokens(address); + if (bondId.length){ + const bond = await BONDContract.getBond(bondId[0]); + LP = bond[5]; + } + // console.log("LP", ethers.utils.formatEther(LP.toString())); + return LP; + } + + beforeEach(async () => { + await forkReset(blockFork); + + [uadWhale] = await impersonate([uadWhaleAddress]); + const [ethWhale] = await impersonate([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); + + instaIndex = new ethers.Contract(addresses.core.instaIndex, abis.core.instaIndex, ethWhale); + + const masterAddress = await instaIndex.master(); + const [master] = await impersonate([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: connectV2UbiquityArtifacts, + signer: master, + connectors: instaConnectorsV2, + }); + }); + + const dsaDepositUAD3CRVf = async (amount) => { + await uAD3CRVfContract.transfer(dsa.address, one.mul(amount)); + }; + + const dsaDepositUAD = async (amount) => { + 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) => { + 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) => { + 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) => { + 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) => { + 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("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)); + }); + }); + + describe("Main", function () { + it("should deposit uAD3CRVf to get Ubiquity Bonding Shares", async function () { + await dsaDepositUAD3CRVf(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [UAD3CRVF, one, 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + + it("should deposit uAD to get Ubiquity Bonding Shares", async function () { + await dsaDepositUAD(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [UAD, one, 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + + it("should deposit 3CRV to get Ubiquity Bonding Shares", async function () { + await dsaDepositCRV3(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [CRV3, one, 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + + it("should deposit DAI to get Ubiquity Bonding Shares", async function () { + await dsaDepositDAI(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [DAI, one.mul(100), 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + + it("should deposit USDC to get Ubiquity Bonding Shares", async function () { + await dsaDepositUSDC(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [USDC, onep.mul(100), 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + + it("should deposit USDT to get Ubiquity Bonding Shares", async function () { + await dsaDepositUSDT(100); + expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + await expect( + dsa.cast( + ...encodeSpells([ + { + connector: ubiquityTest, + method: "deposit", + args: [USDT, onep.mul(100), 4, 0, 0], + }, + ]), + uadWhaleAddress + ) + ).to.be.not.reverted; + expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + }); + }); + + describe("3Pool test", function () { + it("Should add DAI liquidity to 3Pool", async function () { + const n = 100; + await dsaDepositDAI(n); + const amount = one.mul(n); + const [dsaSigner] = await impersonate([dsa.address]); + + expect(await DAIContract.balanceOf(dsa.address)).to.be.equal(amount); + expect(await CRV3Contract.balanceOf(dsa.address)).to.be.equal(0); + + await (await DAIContract.connect(dsaSigner).approve(POOL3, amount)).wait(); + await (await POOL3Contract.connect(dsaSigner).add_liquidity([amount, 0, 0], amount.mul(98).div(100))).wait(); + + expect(await DAIContract.balanceOf(dsa.address)).to.be.equal(0); + expect(await CRV3Contract.balanceOf(dsa.address)) + .to.be.gte(amount.mul(98).div(100)) + .to.be.lte(amount.mul(102).div(100)); + }); + }); +}); diff --git a/test/ubiquity/utils.js b/test/ubiquity/utils.js new file mode 100644 index 00000000..0b79a4ae --- /dev/null +++ b/test/ubiquity/utils.js @@ -0,0 +1,24 @@ +const hre = require("hardhat"); +const hardhatConfig = require("../../hardhat.config"); + +async function forkReset(blockNumber) { + await hre.network.provider.request({ + method: "hardhat_reset", + params: [ + { + forking: { + jsonRpcUrl: hardhatConfig.networks.hardhat.forking.url, + blockNumber, + }, + }, + ], + }); +} +async function sendEth(from, to, amount) { + await from.sendTransaction({ + to: to, + value: ethers.BigNumber.from(10).pow(18).mul(amount), + }); +} + +module.exports = { forkReset, sendEth }; From dffd14c2fee4a444360df8558a201507a9e8e301 Mon Sep 17 00:00:00 2001 From: "zapaz.eth" Date: Sat, 16 Oct 2021 11:21:41 +0200 Subject: [PATCH 2/5] add withdraw functionnality --- .prettierrc | 22 ++ .../mainnet/connectors/ubiquity/events.sol | 10 + .../mainnet/connectors/ubiquity/helpers.sol | 75 +++-- .../connectors/ubiquity/interfaces.sol | 64 +++- .../mainnet/connectors/ubiquity/main.sol | 305 +++++++++++------- hardhat.config.js | 43 +-- package.json | 29 +- test/ubiquity/ubiquity.test.js | 259 ++++++++++++--- test/ubiquity/utils.js | 54 +++- 9 files changed, 609 insertions(+), 252 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..91da568e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,22 @@ +{ + "printWidth": 120, + "singleQuote": false, + "useTabs": false, + "tabWidth": 2, + "trailingComma": "none", + "semi": true, + "plugins": ["./node_modules/prettier-plugin-solidity"], + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 80, + "tabWidth": 4, + "useTabs": true, + "singleQuote": false, + "bracketSpacing": true, + "explicitTypes": "always" + } + } + ] +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/ubiquity/events.sol b/contracts/mainnet/connectors/ubiquity/events.sol index acdc679b..c00372e2 100644 --- a/contracts/mainnet/connectors/ubiquity/events.sol +++ b/contracts/mainnet/connectors/ubiquity/events.sol @@ -6,9 +6,19 @@ contract Events { address indexed userAddress, address indexed token, uint256 amount, + uint256 indexed bondingShareId, uint256 lpAmount, uint256 durationWeeks, + uint256 getId, + uint256 setId + ); + event Withdraw( + address indexed userAddress, uint256 indexed bondingShareId, + uint256 lpAmount, + uint256 endBlock, + address indexed token, + uint256 amount, uint256 getId, uint256 setId ); diff --git a/contracts/mainnet/connectors/ubiquity/helpers.sol b/contracts/mainnet/connectors/ubiquity/helpers.sol index c1fb4e34..d134b654 100644 --- a/contracts/mainnet/connectors/ubiquity/helpers.sol +++ b/contracts/mainnet/connectors/ubiquity/helpers.sol @@ -1,40 +1,55 @@ // SPDX-License-Identifier: MIT pragma solidity 0.7.6; -import {TokenInterface} from "../../common/interfaces.sol"; -import {DSMath} from "../../common/math.sol"; -import {Basic} from "../../common/basic.sol"; +import { Basic } from "../../common/basic.sol"; +import { IUbiquityAlgorithmicDollarManager } from "./interfaces.sol"; -abstract contract Helpers is DSMath, Basic { - /** - * @dev Ubiquity Algorithmic Dollar Manager Address - */ - address internal constant UbiquityAlgorithmicDollarManager = - 0x4DA97a8b831C345dBe6d16FF7432DF2b7b776d98; +abstract contract Helpers is Basic { + /** + * @dev Ubiquity Algorithmic Dollar Manager + */ + IUbiquityAlgorithmicDollarManager internal constant ubiquityManager = + IUbiquityAlgorithmicDollarManager( + 0x4DA97a8b831C345dBe6d16FF7432DF2b7b776d98 + ); - /** - * @dev DAI Address - */ - address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; + /** + * @dev DAI Address + */ + address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; - /** - * @dev USDC Address - */ - address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + /** + * @dev USDC Address + */ + address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; - /** - * @dev USDT Address - */ - address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; + /** + * @dev USDT Address + */ + address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; - /** - * @dev Curve 3CRV Token Address - */ - address internal constant CRV3 = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490; + /** + * @dev Curve 3CRV Token Address + */ + address internal constant CRV3 = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490; - /** - * @dev Curve 3Pool Address - */ - address internal constant Pool3 = - 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; + /** + * @dev Curve 3Pool Address + */ + address internal constant Pool3 = + 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; + + /** + * @dev Ubiquity Algorithmic Dollar Address + */ + function getUAD() internal returns (address) { + return ubiquityManager.dollarTokenAddress(); + } + + /** + * @dev Ubiquity Metapool uAD / 3CRV Address + */ + function getUADCRV3() internal returns (address) { + return ubiquityManager.stableSwapMetaPoolAddress(); + } } diff --git a/contracts/mainnet/connectors/ubiquity/interfaces.sol b/contracts/mainnet/connectors/ubiquity/interfaces.sol index dad4f1ea..4bcefcd0 100644 --- a/contracts/mainnet/connectors/ubiquity/interfaces.sol +++ b/contracts/mainnet/connectors/ubiquity/interfaces.sol @@ -1,31 +1,63 @@ // SPDX-License-Identifier: MIT pragma solidity 0.7.6; - -import {TokenInterface} from "../../common/interfaces.sol"; +pragma abicoder v2; interface IUbiquityBondingV2 { - function deposit(uint256 lpAmount, uint256 durationWeeks) - external - returns (uint256 bondingShareId); + struct Bond { + address minter; + uint256 lpFirstDeposited; + uint256 creationBlock; + uint256 lpRewardDebt; + uint256 endBlock; + uint256 lpAmount; + } + + function deposit(uint256 lpAmount, uint256 durationWeeks) + external + returns (uint256 bondingShareId); + + function removeLiquidity(uint256 lpAmount, uint256 bondId) external; + + function holderTokens(address) external view returns (uint256[] memory); + + function totalLP() external view returns (uint256); + + function totalSupply() external view returns (uint256); + + function getBond(uint256 bondId) external returns (Bond memory bond); } interface IUbiquityMetaPool { - function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) - external - returns (uint256); + function add_liquidity(uint256[2] memory _amounts, uint256 _min_mint_amount) + external + returns (uint256); + + function remove_liquidity_one_coin( + uint256 lpAmount, + int128 i, + uint256 min_amount + ) external returns (uint256); } -interface IUbiquity3Pool { - function add_liquidity( - uint256[3] calldata _amounts, - uint256 _min_mint_amount - ) external; +interface I3Pool { + function add_liquidity( + uint256[3] calldata _amounts, + uint256 _min_mint_amount + ) external; + + function remove_liquidity_one_coin( + uint256 lpAmount, + int128 i, + uint256 min_amount + ) external; } interface IUbiquityAlgorithmicDollarManager { - function dollarTokenAddress() external returns (address); + function dollarTokenAddress() external returns (address); - function stableSwapMetaPoolAddress() external returns (address); + function stableSwapMetaPoolAddress() external returns (address); - function bondingContractAddress() external returns (address); + function bondingContractAddress() external returns (address); + + function bondingShareAddress() external returns (address); } diff --git a/contracts/mainnet/connectors/ubiquity/main.sol b/contracts/mainnet/connectors/ubiquity/main.sol index 6b2840a3..3031c3d5 100644 --- a/contracts/mainnet/connectors/ubiquity/main.sol +++ b/contracts/mainnet/connectors/ubiquity/main.sol @@ -7,131 +7,214 @@ pragma abicoder v2; * @dev Ubiquity Dollar (uAD). */ -import {TokenInterface, MemoryInterface} from "../../common/interfaces.sol"; -import {Stores} from "../../common/stores.sol"; -import {SafeMath} from "../../common/math.sol"; -import {IUbiquityBondingV2, IUbiquityMetaPool, IUbiquity3Pool, IUbiquityAlgorithmicDollarManager} from "./interfaces.sol"; -import {Helpers} from "./helpers.sol"; -import {Events} from "./events.sol"; +import { TokenInterface } from "../../common/interfaces.sol"; +import { IUbiquityBondingV2, IUbiquityMetaPool, I3Pool } from "./interfaces.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; contract ConnectV2Ubiquity is Helpers, Events { - string public constant name = "Ubiquity-v1"; + string public constant name = "Ubiquity-v1"; - /** - * @dev Deposit into Ubiquity protocol - * @notice 3POOL (DAI / USDC / USDT) => METAPOOL (3CRV / uAD) => uAD3CRV-f => Ubiquity BondingShare - * @notice STEP 1 : 3POOL (DAI / USDC / USDT) => 3CRV - * @notice STEP 2 : METAPOOL(3CRV / UAD) => uAD3CRV-f - * @notice STEP 3 : uAD3CRV-f => Ubiquity BondingShare - * @param token Token deposited : DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f - * @param amount Amount of tokens to deposit (For max: `uint256(-1)`) - * @param durationWeeks Duration in weeks tokens will be locked (4-208) - * @param getId ID to retrieve amt. - * @param setId ID stores the amount of tokens deposited. - */ - function deposit( - address token, - uint256 amount, - uint256 durationWeeks, - uint256 getId, - uint256 setId - ) - external - payable - returns (string memory _eventName, bytes memory _eventParam) - { - address UAD = IUbiquityAlgorithmicDollarManager( - UbiquityAlgorithmicDollarManager - ).dollarTokenAddress(); - address UAD3CRVf = IUbiquityAlgorithmicDollarManager( - UbiquityAlgorithmicDollarManager - ).stableSwapMetaPoolAddress(); + /** + * @dev Deposit into Ubiquity protocol + * @notice 3POOL (DAI / USDC / USDT) => METAPOOL (3CRV / uAD) => uAD3CRV-f => Ubiquity BondingShare + * @notice STEP 1 : 3POOL (DAI / USDC / USDT) => 3CRV + * @notice STEP 2 : METAPOOL(3CRV / UAD) => uAD3CRV-f + * @notice STEP 3 : uAD3CRV-f => Ubiquity BondingShare + * @param token Token deposited : DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f + * @param amount Amount of tokens to deposit (For max: `uint256(-1)`) + * @param durationWeeks Duration in weeks tokens will be locked (4-208) + * @param getId ID to retrieve amt. + * @param setId ID stores the bonding share id of tokens deposited. + */ + function deposit( + address token, + uint256 amount, + uint256 durationWeeks, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + address UAD = getUAD(); + address UAD3CRVf = getUADCRV3(); - require( - token == DAI || - token == USDC || - token == USDT || - token == UAD || - token == CRV3 || - token == UAD3CRVf, - "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" - ); + require( + token == DAI || + token == USDC || + token == USDT || + token == UAD || + token == CRV3 || + token == UAD3CRVf, + "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" + ); - uint256 _amount = getUint(getId, amount); - uint256 _lpAmount; + uint256 _amount = getUint(getId, amount); + uint256 lpAmount; - // Full balance if amount = -1 - if (_amount == uint256(-1)) { - _amount = getTokenBal(TokenInterface(token)); - } + // Full balance if amount = -1 + if (_amount == uint256(-1)) { + _amount = getTokenBal(TokenInterface(token)); + } - // STEP 1 : SwapTo3CRV : Deposit DAI, USDC or USDT into 3Pool to get 3Crv LPs - if (token == DAI || token == USDC || token == USDT) { - uint256[3] memory amounts1; + // STEP 1 : SwapTo3CRV : Deposit DAI, USDC or USDT into 3Pool to get 3Crv LPs + if (token == DAI || token == USDC || token == USDT) { + uint256[3] memory amounts1; - if (token == DAI) amounts1[0] = _amount; - else if (token == USDC) amounts1[1] = _amount; - else if (token == USDT) amounts1[2] = _amount; + if (token == DAI) amounts1[0] = _amount; + else if (token == USDC) amounts1[1] = _amount; + else if (token == USDT) amounts1[2] = _amount; - approve(TokenInterface(token), Pool3, _amount); - IUbiquity3Pool(Pool3).add_liquidity(amounts1, 0); - } + approve(TokenInterface(token), Pool3, _amount); + I3Pool(Pool3).add_liquidity(amounts1, 0); + } - // STEP 2 : ProvideLiquidityToMetapool : Deposit in uAD3CRV pool to get uAD3CRV-f LPs - if ( - token == DAI || - token == USDC || - token == USDT || - token == UAD || - token == CRV3 - ) { - uint256[2] memory amounts2; - address token2 = token; - uint256 _amount2; + // STEP 2 : ProvideLiquidityToMetapool : Deposit in uAD3CRV pool to get uAD3CRV-f LPs + if ( + token == DAI || + token == USDC || + token == USDT || + token == UAD || + token == CRV3 + ) { + uint256[2] memory amounts2; + address token2 = token; + uint256 _amount2; - if (token == UAD) { - _amount2 = _amount; - amounts2[0] = _amount2; - } else { - if (token == CRV3) { - _amount2 = _amount; - } else { - token2 = CRV3; - _amount2 = getTokenBal(TokenInterface(token2)); - } - amounts2[1] = _amount2; - } + if (token == UAD) { + _amount2 = _amount; + amounts2[0] = _amount2; + } else { + if (token == CRV3) { + _amount2 = _amount; + } else { + token2 = CRV3; + _amount2 = getTokenBal(TokenInterface(token2)); + } + amounts2[1] = _amount2; + } - approve(TokenInterface(token2), UAD3CRVf, _amount2); - _lpAmount = IUbiquityMetaPool(UAD3CRVf).add_liquidity(amounts2, 0); - } + approve(TokenInterface(token2), UAD3CRVf, _amount2); + lpAmount = IUbiquityMetaPool(UAD3CRVf).add_liquidity(amounts2, 0); + } - // STEP 3 : Farm/ApeIn : Deposit uAD3CRV-f LPs into UbiquityBondingV2 and get Ubiquity Bonding Shares - if (token == UAD3CRVf) { - _lpAmount = _amount; - } + // STEP 3 : Farm/ApeIn : Deposit uAD3CRV-f LPs into UbiquityBondingV2 and get Ubiquity Bonding Shares + if (token == UAD3CRVf) { + lpAmount = _amount; + } - address Bonding = IUbiquityAlgorithmicDollarManager( - UbiquityAlgorithmicDollarManager - ).bondingContractAddress(); - approve(TokenInterface(UAD3CRVf), Bonding, _lpAmount); - uint256 bondingShareId = IUbiquityBondingV2(Bonding).deposit( - _lpAmount, - durationWeeks - ); + address bonding = ubiquityManager.bondingContractAddress(); + approve(TokenInterface(UAD3CRVf), bonding, lpAmount); + uint256 bondingShareId = IUbiquityBondingV2(bonding).deposit( + lpAmount, + durationWeeks + ); - setUint(setId, bondingShareId); + setUint(setId, bondingShareId); - _eventName = "Deposit(address,address,uint256,uint256,uint256,uint256,uint256,uint256)"; - _eventParam = abi.encode( - address(this), - token, - amount, - _lpAmount, - durationWeeks, - bondingShareId, - getId, - setId - ); - } + _eventName = "Deposit(address,address,uint256,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode( + address(this), + token, + amount, + bondingShareId, + lpAmount, + durationWeeks, + getId, + setId + ); + } + + /** + * @dev Withdraw from Ubiquity protocol + * @notice Ubiquity BondingShare => uAD3CRV-f => METAPOOL (3CRV / uAD) => 3POOL (DAI / USDC / USDT) + * @notice STEP 1 : Ubiquity BondingShare => uAD3CRV-f + * @notice STEP 2 : uAD3CRV-f => METAPOOL(3CRV / UAD) + * @notice STEP 3 : 3CRV => 3POOL (DAI / USDC / USDT) + * @param bondingShareId Bonding Share Id to withdraw + * @param token Token to withdraw to : DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f + * @param getId ID + * @param setId ID + */ + function withdraw( + uint256 bondingShareId, + address token, + uint256 getId, + uint256 setId + ) + external + payable + returns (string memory _eventName, bytes memory _eventParam) + { + address UAD3CRVf = getUADCRV3(); + bool[6] memory tok = [ + token == DAI, // 0 + token == USDC, // 1 + token == USDT, // 2 + token == CRV3, // 3 + token == getUAD(), // 4 + token == UAD3CRVf // 5 + ]; + + require( + // DAI / USDC / USDT / CRV3 / UAD / UAD3CRVF + tok[0] || tok[1] || tok[2] || tok[3] || tok[4] || tok[5], + "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" + ); + + uint256 _bondingShareId = getUint(getId, bondingShareId); + + // Get Bond + IUbiquityBondingV2.Bond memory bond = IUbiquityBondingV2( + ubiquityManager.bondingShareAddress() + ).getBond(_bondingShareId); + + require(address(this) == bond.minter, "Not bond owner"); + + // STEP 1 : Withdraw Ubiquity Bonding Shares to get back uAD3CRV-f LPs + address bonding = ubiquityManager.bondingContractAddress(); + IUbiquityBondingV2(bonding).removeLiquidity( + bond.lpAmount, + _bondingShareId + ); + + // STEP 2 : Withdraw uAD3CRV-f LPs to get back uAD or 3Crv + // DAI / USDC / USDT / CRV3 / UAD + if (tok[0] || tok[1] || tok[2] || tok[3] || tok[4]) { + uint256 amount2 = getTokenBal(TokenInterface(UAD3CRVf)); + IUbiquityMetaPool(UAD3CRVf).remove_liquidity_one_coin( + amount2, + tok[4] ? 0 : 1, + 0 + ); + } + + // STEP 3 : Withdraw 3Crv LPs from 3Pool to get back DAI, USDC or USDT + // DAI / USDC / USDT + if (tok[0] || tok[1] || tok[2]) { + uint256 amount1 = getTokenBal(TokenInterface(CRV3)); + I3Pool(Pool3).remove_liquidity_one_coin( + amount1, + tok[0] ? 0 : (tok[1] ? 1 : 2), + 0 + ); + } + + uint256 amount = getTokenBal(TokenInterface(token)); + + setUint(setId, amount); + _eventName = "Withdraw(address,uint256,uint256,uint256,address,uint256,uint256,uint256)"; + _eventParam = abi.encode( + address(this), + _bondingShareId, + bond.lpAmount, + bond.endBlock, + token, + amount, + getId, + setId + ); + } } diff --git a/hardhat.config.js b/hardhat.config.js index 9c2b5b86..fcaa2a67 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -28,63 +28,63 @@ module.exports = { settings: { optimizer: { enabled: true, - runs: 200, - }, - }, + runs: 200 + } + } }, { - version: "0.6.0", + version: "0.6.0" }, { - version: "0.6.2", + version: "0.6.2" }, { - version: "0.6.5", - }, - ], + version: "0.6.5" + } + ] }, networks: { kovan: { url: `https://eth-kovan.alchemyapi.io/v2/${ALCHEMY_ID}`, - accounts: [`0x${PRIVATE_KEY}`], + accounts: [`0x${PRIVATE_KEY}`] }, mainnet: { url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, accounts: [`0x${PRIVATE_KEY}`], timeout: 150000, - gasPrice: parseInt(utils.parseUnits("30", "gwei")), + gasPrice: parseInt(utils.parseUnits("30", "gwei")) }, rinkeby: { url: `https://eth-rinkeby.alchemyapi.io/v2/${ALCHEMY_ID}`, accounts: [`0x${PRIVATE_KEY}`], - timeout: 150000, + timeout: 150000 }, hardhat: { forking: { url: `https://eth-mainnet.alchemyapi.io/v2/${ALCHEMY_ID}`, - blockNumber: 12696000, + blockNumber: 13097100 }, blockGasLimit: 12000000, - gasPrice: parseInt(utils.parseUnits("300", "gwei")), + gasPrice: parseInt(utils.parseUnits("300", "gwei")) }, local: { - url: "http://127.0.0.1:8545", + url: "http://127.0.0.1:8545" }, matic: { url: "https://rpc-mainnet.maticvigil.com/", accounts: [`0x${PRIVATE_KEY}`], timeout: 150000, - gasPrice: parseInt(utils.parseUnits("1", "gwei")), + gasPrice: parseInt(utils.parseUnits("1", "gwei")) }, arbitrum: { chainId: 42161, url: `https://arb-mainnet.g.alchemy.com/v2/${ALCHEMY_ID}`, accounts: [`0x${PRIVATE_KEY}`], timeout: 150000, - gasPrice: parseInt(utils.parseUnits("2", "gwei")), + gasPrice: parseInt(utils.parseUnits("2", "gwei")) }, avax: { - url: 'https://api.avax.network/ext/bc/C/rpc', + url: "https://api.avax.network/ext/bc/C/rpc", chainId: 43114, accounts: [`0x${PRIVATE_KEY}`], timeout: 150000, @@ -92,13 +92,14 @@ module.exports = { } }, etherscan: { - apiKey: ETHERSCAN_API_KEY, + apiKey: ETHERSCAN_API_KEY }, tenderly: { project: process.env.TENDERLY_PROJECT, - username: process.env.TENDERLY_USERNAME, + username: process.env.TENDERLY_USERNAME }, mocha: { timeout: 100 * 1000, - }, -}; \ No newline at end of file + bail: true + } +}; diff --git a/package.json b/package.json index dd1ac07c..5e3a976c 100644 --- a/package.json +++ b/package.json @@ -22,33 +22,36 @@ }, "homepage": "https://github.com/InstaDApp/dsa-connectors-new#readme", "dependencies": { - "@openzeppelin/contracts": "^3.4.0-solc-0.7", + "@openzeppelin/contracts": "^3.4.2", "@uniswap/v3-core": "^1.0.0", - "@uniswap/v3-periphery": "^1.1.1", - "chalk": "^4.0.0", - "commander": "^7.1.0", + "@uniswap/v3-periphery": "^1.2.1", + "chalk": "^4.1.2", + "commander": "^7.2.0", "dotenv": "^7.0.0", - "hardhat-docgen": "^1.1.1", + "hardhat-docgen": "^1.1.2", "minimist": "^1.2.5", - "solc": "^0.7.0" + "solc": "^0.7.6" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.2", "@nomiclabs/hardhat-etherscan": "^2.1.6", "@nomiclabs/hardhat-waffle": "^2.0.1", "@nomiclabs/hardhat-web3": "^2.0.0", - "@openzeppelin/test-helpers": "^0.5.12", - "@studydefi/money-legos": "^2.3.7", + "@openzeppelin/test-helpers": "^0.5.15", + "@studydefi/money-legos": "^2.4.2", "@tenderly/hardhat-tenderly": "^1.0.12", "chai-as-promised": "^7.1.1", "ethereum-waffle": "^3.4.0", - "ethers": "^5.4.4", - "hardhat": "^2.6.4", - "hardhat-deploy": "^0.9.1", - "hardhat-deploy-ethers": "^0.3.0-beta.10", + "ethers": "^5.4.7", + "hardhat": "^2.6.6", + "hardhat-deploy": "^0.9.3", + "hardhat-deploy-ethers": "^0.3.0-beta.11", "husky": "^6.0.0", + "prettier": "^2.4.1", + "prettier-plugin-solidity": "^1.0.0-beta.18", "sol-merger": "^2.0.1", + "solhint": "^3.3.6", "solidity-coverage": "0.5.11", - "web3": "^1.3.6" + "web3": "^1.6.0" } } diff --git a/test/ubiquity/ubiquity.test.js b/test/ubiquity/ubiquity.test.js index e4b661ee..3df3feb9 100644 --- a/test/ubiquity/ubiquity.test.js +++ b/test/ubiquity/ubiquity.test.js @@ -2,7 +2,7 @@ const { expect } = require("chai"); const hre = require("hardhat"); const { waffle, ethers } = hre; const { provider } = waffle; -const { BigNumber } = ethers; +const { BigNumber, utils } = ethers; const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js"); const buildDSAv2 = require("../../scripts/buildDSAv2"); @@ -10,14 +10,14 @@ const encodeSpells = require("../../scripts/encodeSpells"); const addresses = require("../../scripts/constant/addresses"); const abis = require("../../scripts/constant/abis"); const impersonate = require("../../scripts/impersonate"); -const { forkReset, sendEth } = require("./utils"); +const { forkReset, sendEth, mineNBlock } = require("./utils"); const connectV2UbiquityArtifacts = require("../../artifacts/contracts/mainnet/connectors/ubiquity/main.sol/ConnectV2Ubiquity.json"); -const { abi: implementationsABI } = require("../../scripts/constant/abi/core/InstaImplementations.json") -const implementationsMappingAddr = "0xCBA828153d3a85b30B5b912e1f2daCac5816aE9D" +const { abi: implementationsABI } = require("../../scripts/constant/abi/core/InstaImplementations.json"); +const implementationsMappingAddr = "0xCBA828153d3a85b30B5b912e1f2daCac5816aE9D"; -describe.only("Ubiquity", function () { +describe("Ubiquity", function () { const ubiquityTest = "UBIQUITY-TEST-A"; const BOND = "0x2dA07859613C14F6f05c97eFE37B9B4F212b5eF5"; @@ -43,7 +43,7 @@ describe.only("Ubiquity", function () { "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))", + "function getBond(uint256) view returns (tuple(address,uint256,uint256,uint256,uint256,uint256))" ]; let dsa; let POOL3Contract; @@ -62,19 +62,40 @@ describe.only("Ubiquity", function () { let uadWhale; - const bondingShareLpAmount = async function (address) { - let LP = 0; - const bondId = await BONDContract.holderTokens(address); - if (bondId.length){ - const bond = await BONDContract.getBond(bondId[0]); - LP = bond[5]; - } - // console.log("LP", ethers.utils.formatEther(LP.toString())); - return LP; - } + const bondingShare = async function (address) { + let lpAmount = BigNumber.from(0); + let lpAmountTotal = BigNumber.from(0); + let bondId = -1; - beforeEach(async () => { - await forkReset(blockFork); + 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); [uadWhale] = await impersonate([uadWhaleAddress]); const [ethWhale] = await impersonate([ethWhaleAddress]); @@ -90,6 +111,7 @@ describe.only("Ubiquity", function () { 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); @@ -100,19 +122,36 @@ describe.only("Ubiquity", function () { instaConnectorsV2 = new ethers.Contract(addresses.core.connectorsV2, abis.core.connectorsV2); instaImplementationsMapping = await ethers.getContractAt(implementationsABI, implementationsMappingAddr); - InstaAccountV2DefaultImpl = await ethers.getContractFactory("InstaDefaultImplementation") + InstaAccountV2DefaultImpl = await ethers.getContractFactory("InstaDefaultImplementation"); instaAccountV2DefaultImpl = await InstaAccountV2DefaultImpl.deploy(addresses.core.instaIndex); - await instaAccountV2DefaultImpl.deployed() - await (await instaImplementationsMapping.connect(master).setDefaultImplementation(instaAccountV2DefaultImpl.address)).wait(); + await instaAccountV2DefaultImpl.deployed(); + await ( + await instaImplementationsMapping.connect(master).setDefaultImplementation(instaAccountV2DefaultImpl.address) + ).wait(); connector = await deployAndEnableConnector({ connectorName: ubiquityTest, contractArtifact: connectV2UbiquityArtifacts, signer: master, - connectors: instaConnectorsV2, + 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) => { await uAD3CRVfContract.transfer(dsa.address, one.mul(amount)); }; @@ -128,17 +167,29 @@ describe.only("Ubiquity", function () { }; const dsaDepositDAI = async (amount) => { - await uAD3CRVfContract.remove_liquidity_one_coin(one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100)); + 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) => { - await uAD3CRVfContract.remove_liquidity_one_coin(one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100)); + 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) => { - await uAD3CRVfContract.remove_liquidity_one_coin(one.mul(amount).mul(120).div(100), 1, one.mul(amount).mul(110).div(100)); + 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)); }; @@ -184,113 +235,221 @@ describe.only("Ubiquity", function () { }); }); - describe("Main", function () { + describe.only("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); + }); + + 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("Deposit", function () { it("should deposit uAD3CRVf to get Ubiquity Bonding Shares", async function () { await dsaDepositUAD3CRVf(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [UAD3CRVF, one, 4, 0, 0], - }, + args: [UAD3CRVF, one, 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit uAD to get Ubiquity Bonding Shares", async function () { await dsaDepositUAD(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [UAD, one, 4, 0, 0], - }, + args: [UAD, one, 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit 3CRV to get Ubiquity Bonding Shares", async function () { await dsaDepositCRV3(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [CRV3, one, 4, 0, 0], - }, + args: [CRV3, one, 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit DAI to get Ubiquity Bonding Shares", async function () { await dsaDepositDAI(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [DAI, one.mul(100), 4, 0, 0], - }, + args: [DAI, one.mul(100), 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit USDC to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDC(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [USDC, onep.mul(100), 4, 0, 0], - }, + args: [USDC, onep.mul(100), 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); it("should deposit USDT to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDT(100); - expect(await bondingShareLpAmount(dsa.address)).to.be.equal(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); await expect( dsa.cast( ...encodeSpells([ { connector: ubiquityTest, method: "deposit", - args: [USDT, onep.mul(100), 4, 0, 0], - }, + args: [USDT, onep.mul(100), 4, 0, 0] + } ]), uadWhaleAddress ) ).to.be.not.reverted; - expect(await bondingShareLpAmount(dsa.address)).to.be.gt(0); + expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); }); }); diff --git a/test/ubiquity/utils.js b/test/ubiquity/utils.js index 0b79a4ae..7f9537ff 100644 --- a/test/ubiquity/utils.js +++ b/test/ubiquity/utils.js @@ -8,17 +8,49 @@ async function forkReset(blockNumber) { { forking: { jsonRpcUrl: hardhatConfig.networks.hardhat.forking.url, - blockNumber, - }, - }, - ], - }); -} -async function sendEth(from, to, amount) { - await from.sendTransaction({ - to: to, - value: ethers.BigNumber.from(10).pow(18).mul(amount), + blockNumber + } + } + ] }); } -module.exports = { forkReset, sendEth }; +async function mineBlock(timestamp) { + await network.provider.request({ + method: "evm_mine", + params: [timestamp] + }); +} + +async function sendEth(from, to, amount) { + await from.sendTransaction({ + to: to, + value: ethers.BigNumber.from(10).pow(18).mul(amount) + }); +} + +async function mineNBlock(blockCount, secondsBetweenBlock) { + const blockBefore = await ethers.provider.getBlock("latest"); + const maxMinedBlockPerBatch = 1000; + let blockToMine = blockCount; + let blockTime = blockBefore.timestamp; + while (blockToMine > maxMinedBlockPerBatch) { + // eslint-disable-next-line @typescript-eslint/no-loop-func + const minings = [...Array(maxMinedBlockPerBatch).keys()].map((_v, i) => { + const newTs = blockTime + i + (secondsBetweenBlock || 1); + return mineBlock(newTs); + }); + // eslint-disable-next-line no-await-in-loop + await Promise.all(minings); + blockToMine -= maxMinedBlockPerBatch; + blockTime = blockTime + maxMinedBlockPerBatch - 1 + maxMinedBlockPerBatch * (secondsBetweenBlock || 1); + } + const minings = [...Array(blockToMine).keys()].map((_v, i) => { + const newTs = blockTime + i + (secondsBetweenBlock || 1); + return mineBlock(newTs); + }); + // eslint-disable-next-line no-await-in-loop + await Promise.all(minings); +} + +module.exports = { forkReset, sendEth, mineNBlock }; From a7ef817d956d0646bce139ffd0c666f9a9599b96 Mon Sep 17 00:00:00 2001 From: "zapaz.eth" Date: Sat, 16 Oct 2021 11:40:18 +0200 Subject: [PATCH 3/5] improvments --- .../mainnet/connectors/ubiquity/main.sol | 46 +-- test/ubiquity/ubiquity.test.js | 264 ++++++++---------- 2 files changed, 143 insertions(+), 167 deletions(-) diff --git a/contracts/mainnet/connectors/ubiquity/main.sol b/contracts/mainnet/connectors/ubiquity/main.sol index 3031c3d5..88067259 100644 --- a/contracts/mainnet/connectors/ubiquity/main.sol +++ b/contracts/mainnet/connectors/ubiquity/main.sol @@ -38,17 +38,20 @@ contract ConnectV2Ubiquity is Helpers, Events { payable returns (string memory _eventName, bytes memory _eventParam) { - address UAD = getUAD(); address UAD3CRVf = getUADCRV3(); + bool[6] memory tok = [ + token == DAI, // 0 + token == USDC, // 1 + token == USDT, // 2 + token == CRV3, // 3 + token == getUAD(), // 4 + token == UAD3CRVf // 5 + ]; require( - token == DAI || - token == USDC || - token == USDT || - token == UAD || - token == CRV3 || - token == UAD3CRVf, - "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" + // DAI / USDC / USDT / CRV3 / UAD / UAD3CRVF + tok[0] || tok[1] || tok[2] || tok[3] || tok[4] || tok[5], + "Invalid token: must be DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f" ); uint256 _amount = getUint(getId, amount); @@ -60,34 +63,30 @@ contract ConnectV2Ubiquity is Helpers, Events { } // STEP 1 : SwapTo3CRV : Deposit DAI, USDC or USDT into 3Pool to get 3Crv LPs - if (token == DAI || token == USDC || token == USDT) { + // DAI / USDC / USDT + if (tok[0] || tok[1] || tok[2]) { uint256[3] memory amounts1; - if (token == DAI) amounts1[0] = _amount; - else if (token == USDC) amounts1[1] = _amount; - else if (token == USDT) amounts1[2] = _amount; + if (tok[0]) amounts1[0] = _amount; + else if (tok[1]) amounts1[1] = _amount; + else if (tok[2]) amounts1[2] = _amount; approve(TokenInterface(token), Pool3, _amount); I3Pool(Pool3).add_liquidity(amounts1, 0); } // STEP 2 : ProvideLiquidityToMetapool : Deposit in uAD3CRV pool to get uAD3CRV-f LPs - if ( - token == DAI || - token == USDC || - token == USDT || - token == UAD || - token == CRV3 - ) { + // DAI / USDC / USDT / CRV3 / UAD + if (tok[0] || tok[1] || tok[2] || tok[3] || tok[4]) { uint256[2] memory amounts2; address token2 = token; uint256 _amount2; - if (token == UAD) { + if (tok[4]) { _amount2 = _amount; amounts2[0] = _amount2; } else { - if (token == CRV3) { + if (tok[3]) { _amount2 = _amount; } else { token2 = CRV3; @@ -101,7 +100,8 @@ contract ConnectV2Ubiquity is Helpers, Events { } // STEP 3 : Farm/ApeIn : Deposit uAD3CRV-f LPs into UbiquityBondingV2 and get Ubiquity Bonding Shares - if (token == UAD3CRVf) { + // UAD3CRVF + if (tok[5]) { lpAmount = _amount; } @@ -161,7 +161,7 @@ contract ConnectV2Ubiquity is Helpers, Events { require( // DAI / USDC / USDT / CRV3 / UAD / UAD3CRVF tok[0] || tok[1] || tok[2] || tok[3] || tok[4] || tok[5], - "Invalid token: must be DAI, USDC, USDT, uAD, 3CRV or uAD3CRV-f" + "Invalid token: must be DAI, USDC, USDT, 3CRV, uAD or uAD3CRV-f" ); uint256 _bondingShareId = getUint(getId, bondingShareId); diff --git a/test/ubiquity/ubiquity.test.js b/test/ubiquity/ubiquity.test.js index 3df3feb9..723946d2 100644 --- a/test/ubiquity/ubiquity.test.js +++ b/test/ubiquity/ubiquity.test.js @@ -194,48 +194,113 @@ describe("Ubiquity", function () { await USDTContract.transfer(dsa.address, onep.mul(amount)); }; - 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 () { + describe("Deposit", function () { + it("should deposit uAD3CRVf to get Ubiquity Bonding Shares", async function () { + await logAll(); await dsaDepositUAD3CRVf(100); - expect(await uAD3CRVfContract.balanceOf(dsa.address)).to.be.gte(one.mul(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 into DSA wallet", async function () { + + it("should deposit uAD to get Ubiquity Bonding Shares", async function () { await dsaDepositUAD(100); - expect(await uADContract.balanceOf(dsa.address)).to.be.gte(one.mul(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 into DSA wallet", async function () { + + it("should deposit 3CRV to get Ubiquity Bonding Shares", async function () { await dsaDepositCRV3(100); - expect(await CRV3Contract.balanceOf(dsa.address)).to.be.gte(one.mul(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 into DSA wallet", async function () { + + it("should deposit DAI to get Ubiquity Bonding Shares", async function () { await dsaDepositDAI(100); - expect(await DAIContract.balanceOf(dsa.address)).to.be.gte(one.mul(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 into DSA wallet", async function () { + + it("should deposit USDC to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDC(100); - expect(await USDCContract.balanceOf(dsa.address)).to.be.gte(onep.mul(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 into DSA wallet", async function () { + + it("should deposit USDT to get Ubiquity Bonding Shares", async function () { await dsaDepositUSDT(100); - expect(await USDTContract.balanceOf(dsa.address)).to.be.gte(onep.mul(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.only("Withdraw", function () { + describe("Withdraw", function () { let bondId = -1; before(async () => { @@ -343,133 +408,44 @@ describe("Ubiquity", function () { }); }); - describe("Deposit", function () { - it("should deposit uAD3CRVf to get Ubiquity Bonding Shares", async function () { + 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 bondingShare(dsa.address)).lpAmount).to.be.equal(0); - await expect( - dsa.cast( - ...encodeSpells([ - { - connector: ubiquityTest, - method: "deposit", - args: [UAD3CRVF, one, 4, 0, 0] - } - ]), - uadWhaleAddress - ) - ).to.be.not.reverted; - expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); + expect(await uAD3CRVfContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); - - it("should deposit uAD to get Ubiquity Bonding Shares", async function () { + it("Should deposit uAD into DSA wallet", async function () { await dsaDepositUAD(100); - expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); - await expect( - dsa.cast( - ...encodeSpells([ - { - connector: ubiquityTest, - method: "deposit", - args: [UAD, one, 4, 0, 0] - } - ]), - uadWhaleAddress - ) - ).to.be.not.reverted; - expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); + expect(await uADContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); - - it("should deposit 3CRV to get Ubiquity Bonding Shares", async function () { + it("Should deposit 3CRV into DSA wallet", async function () { await dsaDepositCRV3(100); - expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); - await expect( - dsa.cast( - ...encodeSpells([ - { - connector: ubiquityTest, - method: "deposit", - args: [CRV3, one, 4, 0, 0] - } - ]), - uadWhaleAddress - ) - ).to.be.not.reverted; - expect((await bondingShare(dsa.address)).lpAmount).to.be.gt(0); + expect(await CRV3Contract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); - - it("should deposit DAI to get Ubiquity Bonding Shares", async function () { + it("Should deposit DAI into DSA wallet", async function () { await dsaDepositDAI(100); - expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); - 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); + expect(await DAIContract.balanceOf(dsa.address)).to.be.gte(one.mul(100)); }); - - it("should deposit USDC to get Ubiquity Bonding Shares", async function () { + it("Should deposit USDC into DSA wallet", async function () { await dsaDepositUSDC(100); - expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); - 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); + expect(await USDCContract.balanceOf(dsa.address)).to.be.gte(onep.mul(100)); }); - - it("should deposit USDT to get Ubiquity Bonding Shares", async function () { + it("Should deposit USDT into DSA wallet", async function () { await dsaDepositUSDT(100); - expect((await bondingShare(dsa.address)).lpAmount).to.be.equal(0); - 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("3Pool test", function () { - it("Should add DAI liquidity to 3Pool", async function () { - const n = 100; - await dsaDepositDAI(n); - const amount = one.mul(n); - const [dsaSigner] = await impersonate([dsa.address]); - - expect(await DAIContract.balanceOf(dsa.address)).to.be.equal(amount); - expect(await CRV3Contract.balanceOf(dsa.address)).to.be.equal(0); - - await (await DAIContract.connect(dsaSigner).approve(POOL3, amount)).wait(); - await (await POOL3Contract.connect(dsaSigner).add_liquidity([amount, 0, 0], amount.mul(98).div(100))).wait(); - - expect(await DAIContract.balanceOf(dsa.address)).to.be.equal(0); - expect(await CRV3Contract.balanceOf(dsa.address)) - .to.be.gte(amount.mul(98).div(100)) - .to.be.lte(amount.mul(102).div(100)); + expect(await USDTContract.balanceOf(dsa.address)).to.be.gte(onep.mul(100)); }); }); }); From b4ce55ad6a988eb16c9563a439f71f356bd8e59a Mon Sep 17 00:00:00 2001 From: "zapaz.eth" Date: Fri, 22 Oct 2021 14:06:29 +0200 Subject: [PATCH 4/5] PR remarks --- .../mainnet/connectors/ubiquity/events.sol | 40 +++++++++---------- .../mainnet/connectors/ubiquity/main.sol | 12 +++--- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/contracts/mainnet/connectors/ubiquity/events.sol b/contracts/mainnet/connectors/ubiquity/events.sol index c00372e2..f39947e9 100644 --- a/contracts/mainnet/connectors/ubiquity/events.sol +++ b/contracts/mainnet/connectors/ubiquity/events.sol @@ -2,24 +2,24 @@ pragma solidity 0.7.6; contract Events { - event Deposit( - address indexed userAddress, - address indexed token, - uint256 amount, - uint256 indexed bondingShareId, - uint256 lpAmount, - uint256 durationWeeks, - uint256 getId, - uint256 setId - ); - event Withdraw( - address indexed userAddress, - uint256 indexed bondingShareId, - uint256 lpAmount, - uint256 endBlock, - address indexed token, - uint256 amount, - uint256 getId, - uint256 setId - ); + event LogDeposit( + address indexed userAddress, + address indexed token, + uint256 amount, + uint256 indexed bondingShareId, + uint256 lpAmount, + uint256 durationWeeks, + uint256 getId, + uint256 setId + ); + event LogWithdraw( + address indexed userAddress, + uint256 indexed bondingShareId, + uint256 lpAmount, + uint256 endBlock, + address indexed token, + uint256 amount, + uint256 getId, + uint256 setId + ); } diff --git a/contracts/mainnet/connectors/ubiquity/main.sol b/contracts/mainnet/connectors/ubiquity/main.sol index 88067259..8e3c1758 100644 --- a/contracts/mainnet/connectors/ubiquity/main.sol +++ b/contracts/mainnet/connectors/ubiquity/main.sol @@ -12,9 +12,7 @@ import { IUbiquityBondingV2, IUbiquityMetaPool, I3Pool } from "./interfaces.sol" import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; -contract ConnectV2Ubiquity is Helpers, Events { - string public constant name = "Ubiquity-v1"; - +abstract contract UbiquityResolver is Helpers, Events { /** * @dev Deposit into Ubiquity protocol * @notice 3POOL (DAI / USDC / USDT) => METAPOOL (3CRV / uAD) => uAD3CRV-f => Ubiquity BondingShare @@ -114,7 +112,7 @@ contract ConnectV2Ubiquity is Helpers, Events { setUint(setId, bondingShareId); - _eventName = "Deposit(address,address,uint256,uint256,uint256,uint256,uint256,uint256)"; + _eventName = "LogDeposit(address,address,uint256,uint256,uint256,uint256,uint256,uint256)"; _eventParam = abi.encode( address(this), token, @@ -205,7 +203,7 @@ contract ConnectV2Ubiquity is Helpers, Events { uint256 amount = getTokenBal(TokenInterface(token)); setUint(setId, amount); - _eventName = "Withdraw(address,uint256,uint256,uint256,address,uint256,uint256,uint256)"; + _eventName = "LogWithdraw(address,uint256,uint256,uint256,address,uint256,uint256,uint256)"; _eventParam = abi.encode( address(this), _bondingShareId, @@ -218,3 +216,7 @@ contract ConnectV2Ubiquity is Helpers, Events { ); } } + +contract ConnectV2Ubiquity is UbiquityResolver { + string public constant name = "Ubiquity-v1"; +} From 0b11e2240ce945f609b904a000d05c2d59a57df4 Mon Sep 17 00:00:00 2001 From: "zapaz.eth" Date: Tue, 2 Nov 2021 09:26:16 +0100 Subject: [PATCH 5/5] resolve conflict with main package.json --- package.json | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 5e3a976c..fe395f34 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,7 @@ "coverage": "./node_modules/.bin/solidity-coverage", "check": "node status-checks/huskyCheck.js", "check-husky": "node status-checks/huskyCheck.js", - "deploy": "node scripts/deployConnectorsFromCmd.js", - "build-contracts": "sol-merger \"./contracts/connectors/mock.sol\" ./contracts/build" + "deploy": "node scripts/deployConnectorsFromCmd.js" }, "repository": { "type": "git", @@ -22,19 +21,18 @@ }, "homepage": "https://github.com/InstaDApp/dsa-connectors-new#readme", "dependencies": { - "@openzeppelin/contracts": "^3.4.2", + "@openzeppelin/contracts": "^3.4.0-solc-0.7", "@uniswap/v3-core": "^1.0.0", "@uniswap/v3-periphery": "^1.2.1", "chalk": "^4.1.2", - "commander": "^7.2.0", - "dotenv": "^7.0.0", + "dotenv": "^10.0.0", "hardhat-docgen": "^1.1.2", "minimist": "^1.2.5", "solc": "^0.7.6" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.0.2", - "@nomiclabs/hardhat-etherscan": "^2.1.6", + "@nomiclabs/hardhat-etherscan": "^2.1.7", "@nomiclabs/hardhat-waffle": "^2.0.1", "@nomiclabs/hardhat-web3": "^2.0.0", "@openzeppelin/test-helpers": "^0.5.15", @@ -42,15 +40,14 @@ "@tenderly/hardhat-tenderly": "^1.0.12", "chai-as-promised": "^7.1.1", "ethereum-waffle": "^3.4.0", - "ethers": "^5.4.7", - "hardhat": "^2.6.6", - "hardhat-deploy": "^0.9.3", + "ethers": "^5.5.1", + "hardhat": "^2.6.7", + "hardhat-deploy": "^0.9.4", "hardhat-deploy-ethers": "^0.3.0-beta.11", - "husky": "^6.0.0", "prettier": "^2.4.1", "prettier-plugin-solidity": "^1.0.0-beta.18", - "sol-merger": "^2.0.1", "solhint": "^3.3.6", + "husky": "^7.0.4", "solidity-coverage": "0.5.11", "web3": "^1.6.0" }