From e892d52c51c77e8ee3176fab34916a2a930f9d41 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Mon, 5 Jul 2021 21:58:51 +0300 Subject: [PATCH 01/38] b.compound --- .../connectors/b.protocol/compound/events.sol | 62 ++++ .../b.protocol/compound/helpers.sol | 26 ++ .../b.protocol/compound/interface.sol | 40 ++ .../connectors/b.protocol/compound/main.sol | 347 ++++++++++++++++++ test/b.protocol/b.compound.test.js | 128 +++++++ 5 files changed, 603 insertions(+) create mode 100644 contracts/mainnet/connectors/b.protocol/compound/events.sol create mode 100644 contracts/mainnet/connectors/b.protocol/compound/helpers.sol create mode 100644 contracts/mainnet/connectors/b.protocol/compound/interface.sol create mode 100644 contracts/mainnet/connectors/b.protocol/compound/main.sol create mode 100644 test/b.protocol/b.compound.test.js diff --git a/contracts/mainnet/connectors/b.protocol/compound/events.sol b/contracts/mainnet/connectors/b.protocol/compound/events.sol new file mode 100644 index 00000000..4e4b5033 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/compound/events.sol @@ -0,0 +1,62 @@ +pragma solidity ^0.7.0; + +contract Events { + event LogDeposit( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogWithdraw( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogBorrow( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogPayback( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogDepositCToken( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 cTokenAmt, + uint256 getId, + uint256 setId + ); + + event LogWithdrawCToken( + address indexed token, + address cToken, + uint256 tokenAmt, + uint256 cTokenAmt, + uint256 getId, + uint256 setId + ); + + event LogLiquidate( + address indexed borrower, + address indexed tokenToPay, + address indexed tokenInReturn, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); +} diff --git a/contracts/mainnet/connectors/b.protocol/compound/helpers.sol b/contracts/mainnet/connectors/b.protocol/compound/helpers.sol new file mode 100644 index 00000000..74e149b1 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/compound/helpers.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "./../../../common/math.sol"; +import { Basic } from "./../../../common/basic.sol"; +import { ComptrollerInterface, CompoundMappingInterface, BComptrollerInterface } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Compound Comptroller + */ + ComptrollerInterface internal constant troller = ComptrollerInterface(0x9dB10B9429989cC13408d7368644D4A1CB704ea3); + + /** + * @dev Compound Mapping + */ + CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082); + + /** + * @dev B.Compound Mapping + */ + function getMapping(string calldata tokenId) public returns(address token, address btoken) { + address ctoken; + (token, ctoken) = compMapping.getMapping(tokenId); + btoken = BComptrollerInterface(address(troller)).c2b(ctoken); + } +} diff --git a/contracts/mainnet/connectors/b.protocol/compound/interface.sol b/contracts/mainnet/connectors/b.protocol/compound/interface.sol new file mode 100644 index 00000000..4788e448 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/compound/interface.sol @@ -0,0 +1,40 @@ +pragma solidity ^0.7.0; + +interface CTokenInterface { + function mint(uint mintAmount) external returns (uint); + function redeem(uint redeemTokens) external returns (uint); + function borrow(uint borrowAmount) external returns (uint); + function repayBorrow(uint repayAmount) external returns (uint); + function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint); // For ERC20 + function liquidateBorrow(address borrower, uint repayAmount, address cTokenCollateral) external returns (uint); + + function borrowBalanceCurrent(address account) external returns (uint); + function redeemUnderlying(uint redeemAmount) external returns (uint); + function exchangeRateCurrent() external returns (uint); + + function balanceOf(address owner) external view returns (uint256 balance); +} + +interface CETHInterface { + function mint() external payable; + function repayBorrow() external payable; + function repayBorrowBehalf(address borrower) external payable; + function liquidateBorrow(address borrower, address cTokenCollateral) external payable; +} + +interface ComptrollerInterface { + function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); + function exitMarket(address cTokenAddress) external returns (uint); + function getAssetsIn(address account) external view returns (address[] memory); + function getAccountLiquidity(address account) external view returns (uint, uint, uint); + function claimComp(address) external; +} + +interface CompoundMappingInterface { + function cTokenMapping(string calldata tokenId) external view returns (address); + function getMapping(string calldata tokenId) external view returns (address, address); +} + +interface BComptrollerInterface { + function c2b(address ctoken) external view returns(address); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/compound/main.sol b/contracts/mainnet/connectors/b.protocol/compound/main.sol new file mode 100644 index 00000000..ecc062ad --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/compound/main.sol @@ -0,0 +1,347 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +/** + * @title B.Compound. + * @dev Lending & Borrowing. + */ + +import { TokenInterface } from "../../../common/interfaces.sol"; +import { Stores } from "../../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; +import { CETHInterface, CTokenInterface } from "./interface.sol"; + +abstract contract BCompoundResolver is Events, Helpers { + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Deposit a token to Compound for lending / collaterization. + * @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function depositRaw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + if (token == ethAddr) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + CETHInterface(cToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + approve(tokenContract, cToken, _amt); + require(CTokenInterface(cToken).mint(_amt) == 0, "deposit-failed"); + } + setUint(setId, _amt); + + _eventName = "LogDeposit(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, getId, setId); + } + + /** + * @dev Deposit ETH/ERC20_Token using the Mapping. + * @notice Deposit a token to Compound for lending / collaterization. + * @param tokenId The token id of the token to deposit.(For eg: ETH-A) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = depositRaw(token, cToken, amt, getId, setId); + } + + /** + * @dev Withdraw ETH/ERC20_Token. + * @notice Withdraw deposited token from Compound + * @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawRaw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + if (_amt == uint(-1)) { + TokenInterface tokenContract = TokenInterface(token); + uint initialBal = token == ethAddr ? address(this).balance : tokenContract.balanceOf(address(this)); + require(cTokenContract.redeem(cTokenContract.balanceOf(address(this))) == 0, "full-withdraw-failed"); + uint finalBal = token == ethAddr ? address(this).balance : tokenContract.balanceOf(address(this)); + _amt = finalBal - initialBal; + } else { + require(cTokenContract.redeemUnderlying(_amt) == 0, "withdraw-failed"); + } + setUint(setId, _amt); + + _eventName = "LogWithdraw(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, getId, setId); + } + + /** + * @dev Withdraw ETH/ERC20_Token using the Mapping. + * @notice Withdraw deposited token from Compound + * @param tokenId The token id of the token to withdraw.(For eg: ETH-A) + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdraw( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = withdrawRaw(token, cToken, amt, getId, setId); + } + + /** + * @dev Borrow ETH/ERC20_Token. + * @notice Borrow a token using Compound + * @param token The address of the token to borrow. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrowRaw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + require(CTokenInterface(cToken).borrow(_amt) == 0, "borrow-failed"); + setUint(setId, _amt); + + _eventName = "LogBorrow(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, getId, setId); + } + + /** + * @dev Borrow ETH/ERC20_Token using the Mapping. + * @notice Borrow a token using Compound + * @param tokenId The token id of the token to borrow.(For eg: DAI-A) + * @param amt The amount of the token to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrow( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = borrowRaw(token, cToken, amt, getId, setId); + } + + /** + * @dev Payback borrowed ETH/ERC20_Token. + * @notice Payback debt owed. + * @param token The address of the token to payback. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackRaw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + _amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(address(this)) : _amt; + + if (token == ethAddr) { + require(address(this).balance >= _amt, "not-enough-eth"); + CETHInterface(cToken).repayBorrow{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); + approve(tokenContract, cToken, _amt); + require(cTokenContract.repayBorrow(_amt) == 0, "repay-failed."); + } + setUint(setId, _amt); + + _eventName = "LogPayback(address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, getId, setId); + } + + /** + * @dev Payback borrowed ETH/ERC20_Token using the Mapping. + * @notice Payback debt owed. + * @param tokenId The token id of the token to payback.(For eg: COMP-A) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function payback( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = paybackRaw(token, cToken, amt, getId, setId); + } + + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Same as depositRaw. The only difference is this method stores cToken amount in set ID. + * @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of cTokens received. + */ + function depositCTokenRaw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + CTokenInterface ctokenContract = CTokenInterface(cToken); + uint initialBal = ctokenContract.balanceOf(address(this)); + + if (token == ethAddr) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + CETHInterface(cToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + approve(tokenContract, cToken, _amt); + require(ctokenContract.mint(_amt) == 0, "deposit-ctoken-failed."); + } + + uint _cAmt; + + { + uint finalBal = ctokenContract.balanceOf(address(this)); + _cAmt = sub(finalBal, initialBal); + + setUint(setId, _cAmt); + } + + _eventName = "LogDepositCToken(address,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, _cAmt, getId, setId); + } + + /** + * @dev Deposit ETH/ERC20_Token using the Mapping. + * @notice Same as deposit. The only difference is this method stores cToken amount in set ID. + * @param tokenId The token id of the token to depositCToken.(For eg: DAI-A) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of cTokens received. + */ + function depositCToken( + string calldata tokenId, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = depositCTokenRaw(token, cToken, amt, getId, setId); + } + + /** + * @dev Withdraw CETH/CERC20_Token using cToken Amt. + * @notice Same as withdrawRaw. The only difference is this method fetch cToken amount in get ID. + * @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param cTokenAmt The amount of cTokens to withdraw + * @param getId ID to retrieve cTokenAmt + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawCTokenRaw( + address token, + address cToken, + uint cTokenAmt, + uint getId, + uint setId + ) public payable returns (string memory _eventName, bytes memory _eventParam) { + uint _cAmt = getUint(getId, cTokenAmt); + require(token != address(0) && cToken != address(0), "invalid token/ctoken address"); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + TokenInterface tokenContract = TokenInterface(token); + _cAmt = _cAmt == uint(-1) ? cTokenContract.balanceOf(address(this)) : _cAmt; + + uint withdrawAmt; + { + uint initialBal = token != ethAddr ? tokenContract.balanceOf(address(this)) : address(this).balance; + require(cTokenContract.redeem(_cAmt) == 0, "redeem-failed"); + uint finalBal = token != ethAddr ? tokenContract.balanceOf(address(this)) : address(this).balance; + + withdrawAmt = sub(finalBal, initialBal); + } + + setUint(setId, withdrawAmt); + + _eventName = "LogWithdrawCToken(address,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, withdrawAmt, _cAmt, getId, setId); + } + + /** + * @dev Withdraw CETH/CERC20_Token using cToken Amt & the Mapping. + * @notice Same as withdraw. The only difference is this method fetch cToken amount in get ID. + * @param tokenId The token id of the token to withdraw CToken.(For eg: ETH-A) + * @param cTokenAmt The amount of cTokens to withdraw + * @param getId ID to retrieve cTokenAmt + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawCToken( + string calldata tokenId, + uint cTokenAmt, + uint getId, + uint setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = getMapping(tokenId); + (_eventName, _eventParam) = withdrawCTokenRaw(token, cToken, cTokenAmt, getId, setId); + } +} + +contract ConnectV1BCompound is BCompoundResolver { + string public name = "B.Compound-v1.0"; +} diff --git a/test/b.protocol/b.compound.test.js b/test/b.protocol/b.compound.test.js new file mode 100644 index 00000000..5d08235d --- /dev/null +++ b/test/b.protocol/b.compound.test.js @@ -0,0 +1,128 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); +const { web3, deployments, waffle, ethers } = hre; +const { provider, deployContract } = waffle + +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js") +const buildDSAv2 = require("../../scripts/buildDSAv2") +const encodeSpells = require("../../scripts/encodeSpells.js") +const getMasterSigner = require("../../scripts/getMasterSigner") + +const addresses = require("../../scripts/constant/addresses"); +const abis = require("../../scripts/constant/abis"); +const constants = require("../../scripts/constant/constant"); +const tokens = require("../../scripts/constant/tokens"); + +const connectV2CompoundArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/compound/main.sol/ConnectV1BCompound.json") + +describe("B.Compound", function () { + const connectorName = "B.COMPOUND-TEST-A" + + let dsaWallet0 + let masterSigner; + let instaConnectorsV2; + let connector; + + const wallets = provider.getWallets() + const [wallet0, wallet1, wallet2, wallet3] = wallets + before(async () => { + masterSigner = await getMasterSigner(wallet3) + instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2); + connector = await deployAndEnableConnector({ + connectorName, + contractArtifact: connectV2CompoundArtifacts, + signer: masterSigner, + connectors: instaConnectorsV2 + }) + console.log("Connector address", connector.address) + }) + + it("Should have contracts deployed.", async function () { + expect(!!instaConnectorsV2.address).to.be.true; + expect(!!connector.address).to.be.true; + expect(!!masterSigner.address).to.be.true; + expect(await connector.name()).to.be.equal("B.Compound-v1.0"); + }); + + 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 ETH into DSA wallet", async function () { + await wallet0.sendTransaction({ + to: dsaWallet0.address, + value: ethers.utils.parseEther("10") + }); + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); + }); + }); + + describe("Main", function () { + + it("Should deposit ETH in Compound", async function () { + const amount = ethers.utils.parseEther("1") // 1 ETH + const spells = [ + { + connector: connectorName, + method: "deposit", + args: ["ETH-A", amount, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("9")); + }); + + it("Should borrow and payback DAI from Compound", async function () { + const amount = ethers.utils.parseEther("100") // 100 DAI + const setId = "83478237" + const spells = [ + { + connector: connectorName, + method: "borrow", + args: ["DAI-A", amount, 0, setId] + }, + { + connector: connectorName, + method: "payback", + args: ["DAI-A", 0, setId, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("9")); + }); + + it("Should deposit all ETH in Compound", async function () { + const spells = [ + { + connector: connectorName, + method: "deposit", + args: ["ETH-A", constants.max_value, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.lte(ethers.utils.parseEther("0")); + }); + + it("Should withdraw all ETH from Compound", async function () { + const spells = [ + { + connector: connectorName, + method: "withdraw", + args: ["ETH-A", constants.max_value, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); + }); + }) +}) From f448d4eaa411154d141e762fcedfe6a681375202 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Mon, 5 Jul 2021 22:34:11 +0300 Subject: [PATCH 02/38] makerdao before tests --- .../connectors/b.protocol/makerdao/events.sol | 26 + .../b.protocol/makerdao/helpers.sol | 130 +++++ .../b.protocol/makerdao/interface.sol | 65 +++ .../connectors/b.protocol/makerdao/main.sol | 524 ++++++++++++++++++ 4 files changed, 745 insertions(+) create mode 100644 contracts/mainnet/connectors/b.protocol/makerdao/events.sol create mode 100644 contracts/mainnet/connectors/b.protocol/makerdao/helpers.sol create mode 100644 contracts/mainnet/connectors/b.protocol/makerdao/interface.sol create mode 100644 contracts/mainnet/connectors/b.protocol/makerdao/main.sol diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/events.sol b/contracts/mainnet/connectors/b.protocol/makerdao/events.sol new file mode 100644 index 00000000..702a70f3 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/makerdao/events.sol @@ -0,0 +1,26 @@ +pragma solidity ^0.7.0; + +contract Events { + event LogOpen(uint256 indexed vault, bytes32 indexed ilk); + event LogClose(uint256 indexed vault, bytes32 indexed ilk); + event LogTransfer(uint256 indexed vault, bytes32 indexed ilk, address newOwner); + event LogDeposit(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogWithdraw(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogBorrow(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogPayback(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogWithdrawLiquidated(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogExitDai(uint256 indexed vault, bytes32 indexed ilk, uint256 tokenAmt, uint256 getId, uint256 setId); + event LogDepositDai(uint256 tokenAmt, uint256 getId, uint256 setId); + event LogWithdrawDai(uint256 tokenAmt, uint256 getId, uint256 setId); + + event LogDepositAndBorrow( + uint256 indexed vault, + bytes32 indexed ilk, + uint256 depositAmt, + uint256 borrowAmt, + uint256 getIdDeposit, + uint256 getIdBorrow, + uint256 setIdDeposit, + uint256 setIdBorrow + ); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/helpers.sol b/contracts/mainnet/connectors/b.protocol/makerdao/helpers.sol new file mode 100644 index 00000000..37d0388d --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/makerdao/helpers.sol @@ -0,0 +1,130 @@ +pragma solidity ^0.7.0; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; +import { TokenInterface } from "./../../../common/interfaces.sol"; +import { BManagerLike, DaiJoinInterface, PotLike, VatLike, JugLike } from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + /** + * @dev Manager Interface + */ + BManagerLike internal constant managerContract = BManagerLike(0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed); + + /** + * @dev DAI Join + */ + DaiJoinInterface internal constant daiJoinContract = DaiJoinInterface(0x9759A6Ac90977b93B58547b4A71c78317f391A28); + + /** + * @dev Pot + */ + PotLike internal constant potContract = PotLike(0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7); + + /** + * @dev Maker MCD Jug Address. + */ + JugLike internal constant mcdJug = JugLike(0x19c0976f590D67707E62397C87829d896Dc0f1F1); + + /** + * @dev Return Close Vault Address. + */ + address internal constant giveAddr = 0x4dD58550eb15190a5B3DfAE28BB14EeC181fC267; + + /** + * @dev Get Vault's ilk. + */ + function getVaultData(uint vault) internal view returns (bytes32 ilk, address urn) { + ilk = managerContract.ilks(vault); + urn = managerContract.urns(vault); + } + + /** + * @dev Gem Join address is ETH type collateral. + */ + function isEth(address tknAddr) internal pure returns (bool) { + return tknAddr == wethAddr ? true : false; + } + + /** + * @dev Get Vault Debt Amount. + */ + function _getVaultDebt( + address vat, + bytes32 ilk, + address urn, + uint vault + ) internal view returns (uint wad) { + (, uint rate,,,) = VatLike(vat).ilks(ilk); + (, uint art) = VatLike(vat).urns(ilk, urn); + uint cushion = managerContract.cushion(vault); + art = add(art, cushion); + uint dai = VatLike(vat).dai(urn); + + uint rad = sub(mul(art, rate), dai); + wad = rad / RAY; + + wad = mul(wad, RAY) < rad ? wad + 1 : wad; + } + + /** + * @dev Get Borrow Amount. + */ + function _getBorrowAmt( + address vat, + address urn, + bytes32 ilk, + uint amt + ) internal returns (int dart) + { + uint rate = mcdJug.drip(ilk); + uint dai = VatLike(vat).dai(urn); + if (dai < mul(amt, RAY)) { + dart = toInt(sub(mul(amt, RAY), dai) / rate); + dart = mul(uint(dart), rate) < mul(amt, RAY) ? dart + 1 : dart; + } + } + + /** + * @dev Get Payback Amount. + */ + function _getWipeAmt( + address vat, + uint amt, + address urn, + bytes32 ilk, + uint vault + ) internal view returns (int dart) + { + (, uint rate,,,) = VatLike(vat).ilks(ilk); + (, uint art) = VatLike(vat).urns(ilk, urn); + uint cushion = managerContract.cushion(vault); + art = add(art, cushion); + dart = toInt(amt / rate); + dart = uint(dart) <= art ? - dart : - toInt(art); + } + + /** + * @dev Convert String to bytes32. + */ + function stringToBytes32(string memory str) internal pure returns (bytes32 result) { + require(bytes(str).length != 0, "string-empty"); + // solium-disable-next-line security/no-inline-assembly + assembly { + result := mload(add(str, 32)) + } + } + + /** + * @dev Get vault ID. If `vault` is 0, get last opened vault. + */ + function getVault(uint vault) internal view returns (uint _vault) { + if (vault == 0) { + require(managerContract.count(address(this)) > 0, "no-vault-opened"); + _vault = managerContract.last(address(this)); + } else { + _vault = vault; + } + } + +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol b/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol new file mode 100644 index 00000000..7a8c4ca8 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol @@ -0,0 +1,65 @@ +pragma solidity ^0.7.0; + +import { TokenInterface } from "../../../common/interfaces.sol"; + +interface ManagerLike { + function cdpCan(address, uint, address) external view returns (uint); + function ilks(uint) external view returns (bytes32); + function last(address) external view returns (uint); + function count(address) external view returns (uint); + function owns(uint) external view returns (address); + function urns(uint) external view returns (address); + function vat() external view returns (address); + function open(bytes32, address) external returns (uint); + function give(uint, address) external; + function frob(uint, int, int) external; + function flux(uint, address, uint) external; + function move(uint, address, uint) external; +} + +interface BManagerLike is ManagerLike { + function cushion(uint) external view returns(uint); +} + +interface VatLike { + function can(address, address) external view returns (uint); + function ilks(bytes32) external view returns (uint, uint, uint, uint, uint); + function dai(address) external view returns (uint); + function urns(bytes32, address) external view returns (uint, uint); + function frob( + bytes32, + address, + address, + address, + int, + int + ) external; + function hope(address) external; + function move(address, address, uint) external; + function gem(bytes32, address) external view returns (uint); +} + +interface TokenJoinInterface { + function dec() external returns (uint); + function gem() external returns (TokenInterface); + function join(address, uint) external payable; + function exit(address, uint) external; +} + +interface DaiJoinInterface { + function vat() external returns (VatLike); + function dai() external returns (TokenInterface); + function join(address, uint) external payable; + function exit(address, uint) external; +} + +interface JugLike { + function drip(bytes32) external returns (uint); +} + +interface PotLike { + function pie(address) external view returns (uint); + function drip() external returns (uint); + function join(uint) external; + function exit(uint) external; +} diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/main.sol b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol new file mode 100644 index 00000000..2f94c1e4 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol @@ -0,0 +1,524 @@ +pragma solidity ^0.7.0; + +/** + * @title MakerDAO. + * @dev Collateralized Borrowing. + */ + +import { TokenInterface, AccountInterface } from "./../../../common/interfaces.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; +import { VatLike, TokenJoinInterface } from "./interface.sol"; + +abstract contract BMakerResolver is Helpers, Events { + /** + * @dev Open Vault + * @notice Open a MakerDAO Vault + * @param colType Type of Collateral.(eg: 'ETH-A') + */ + function open(string calldata colType) external payable returns (string memory _eventName, bytes memory _eventParam) { + bytes32 ilk = stringToBytes32(colType); + require(instaMapping.gemJoinMapping(ilk) != address(0), "wrong-col-type"); + uint256 vault = managerContract.open(ilk, address(this)); + + _eventName = "LogOpen(uint256,bytes32)"; + _eventParam = abi.encode(vault, ilk); + } + + /** + * @dev Close Vault + * @notice Close a MakerDAO Vault + * @param vault Vault ID to close. + */ + function close(uint256 vault) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + (uint ink, uint art) = VatLike(managerContract.vat()).urns(ilk, urn); + + require(ink == 0 && art == 0, "vault-has-assets"); + require(managerContract.owns(_vault) == address(this), "not-owner"); + + managerContract.give(_vault, giveAddr); + + _eventName = "LogClose(uint256,bytes32)"; + _eventParam = abi.encode(_vault, ilk); + } + + /** + * @dev Transfer Vault + * @notice Transfer a MakerDAO Vault to "nextOwner" + * @param vault Vault ID to close. + * @param nextOwner Address of the next owner of the vault. + */ + function transfer( + uint vault, + address nextOwner + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + require(AccountInterface(address(this)).isAuth(nextOwner), "nextOwner-is-not-auth"); + + uint256 _vault = getVault(vault); + (bytes32 ilk,) = getVaultData(_vault); + + require(managerContract.owns(_vault) == address(this), "not-owner"); + + managerContract.give(_vault, nextOwner); + + _eventName = "LogTransfer(uint256,bytes32,address)"; + _eventParam = abi.encode(_vault, ilk, nextOwner); + } + + /** + * @dev Deposit ETH/ERC20_Token Collateral. + * @notice Deposit collateral to a MakerDAO vault + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt The amount of tokens to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + + address colAddr = instaMapping.gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + TokenInterface tokenContract = tokenJoinContract.gem(); + + if (isEth(address(tokenContract))) { + _amt = _amt == uint(-1) ? address(this).balance : _amt; + tokenContract.deposit{value: _amt}(); + } else { + _amt = _amt == uint(-1) ? tokenContract.balanceOf(address(this)) : _amt; + } + + approve(tokenContract, address(colAddr), _amt); + tokenJoinContract.join(address(this), _amt); + + VatLike(managerContract.vat()).frob( // TODO zelda - make manager.frob + ilk, + urn, + address(this), + address(this), + toInt(convertTo18(tokenJoinContract.dec(), _amt)), + 0 + ); + + setUint(setId, _amt); + + _eventName = "LogDeposit(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Withdraw ETH/ERC20_Token Collateral. + * @notice Withdraw collateral from a MakerDAO vault + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt The amount of tokens to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdraw( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + + address colAddr = instaMapping.gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + + uint _amt18; + if (_amt == uint(-1)) { + (_amt18,) = VatLike(managerContract.vat()).urns(ilk, urn); + _amt = convert18ToDec(tokenJoinContract.dec(), _amt18); + } else { + _amt18 = convertTo18(tokenJoinContract.dec(), _amt); + } + + managerContract.frob( + _vault, + -toInt(_amt18), + 0 + ); + + managerContract.flux( + _vault, + address(this), + _amt18 + ); + + TokenInterface tokenContract = tokenJoinContract.gem(); + + if (isEth(address(tokenContract))) { + tokenJoinContract.exit(address(this), _amt); + tokenContract.withdraw(_amt); + } else { + tokenJoinContract.exit(address(this), _amt); + } + + setUint(setId, _amt); + + _eventName = "LogWithdraw(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Borrow DAI. + * @notice Borrow DAI using a MakerDAO vault + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt The amount of DAI to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of DAI borrowed. + */ + function borrow( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + + VatLike vatContract = VatLike(managerContract.vat()); + + managerContract.frob( + _vault, + 0, + _getBorrowAmt( + address(vatContract), + urn, + ilk, + _amt + ) + ); + + managerContract.move( + _vault, + address(this), + toRad(_amt) + ); + + if (vatContract.can(address(this), address(daiJoinContract)) == 0) { + vatContract.hope(address(daiJoinContract)); + } + + daiJoinContract.exit(address(this), _amt); + + setUint(setId, _amt); + + _eventName = "LogBorrow(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Payback borrowed DAI. + * @notice Payback DAI debt owed by a MakerDAO vault + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt The amount of DAI to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of DAI paid back. + */ + function payback( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + + address vat = managerContract.vat(); + + uint _maxDebt = _getVaultDebt(vat, ilk, urn, vault); + + _amt = _amt == uint(-1) ? _maxDebt : _amt; + + require(_maxDebt >= _amt, "paying-excess-debt"); + + approve(daiJoinContract.dai(), address(daiJoinContract), _amt); + daiJoinContract.join(urn, _amt); + + managerContract.frob( + _vault, + 0, + _getWipeAmt( + vat, + VatLike(vat).dai(urn), + urn, + ilk, + _vault + ) + ); + + setUint(setId, _amt); + + _eventName = "LogPayback(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Withdraw leftover ETH/ERC20_Token after Liquidation. + * @notice Withdraw leftover collateral after Liquidation. + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt token amount to Withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of collateral withdrawn. + */ + function withdrawLiquidated( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + (bytes32 ilk, address urn) = getVaultData(vault); + + address colAddr = instaMapping.gemJoinMapping(ilk); + TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr); + + uint _amt18; + if (_amt == uint(-1)) { + _amt18 = VatLike(managerContract.vat()).gem(ilk, urn); + _amt = convert18ToDec(tokenJoinContract.dec(), _amt18); + } else { + _amt18 = convertTo18(tokenJoinContract.dec(), _amt); + } + + managerContract.flux( + vault, + address(this), + _amt18 + ); + + TokenInterface tokenContract = tokenJoinContract.gem(); + tokenJoinContract.exit(address(this), _amt); + if (isEth(address(tokenContract))) { + tokenContract.withdraw(_amt); + } + + setUint(setId, _amt); + + _eventName = "LogWithdrawLiquidated(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(vault, ilk, _amt, getId, setId); + } + + struct MakerData { + uint _vault; + address colAddr; + TokenJoinInterface tokenJoinContract; + VatLike vatContract; + TokenInterface tokenContract; + } + /** + * @dev Deposit ETH/ERC20_Token Collateral and Borrow DAI. + * @notice Deposit collateral and borrow DAI. + * @param vault Vault ID. (Use 0 for last opened vault) + * @param depositAmt The amount of tokens to deposit. (For max: `uint256(-1)`) + * @param borrowAmt The amount of DAI to borrow. + * @param getIdDeposit ID to retrieve depositAmt. + * @param getIdBorrow ID to retrieve borrowAmt. + * @param setIdDeposit ID stores the amount of tokens deposited. + * @param setIdBorrow ID stores the amount of DAI borrowed. + */ + function depositAndBorrow( + uint256 vault, + uint256 depositAmt, + uint256 borrowAmt, + uint256 getIdDeposit, + uint256 getIdBorrow, + uint256 setIdDeposit, + uint256 setIdBorrow + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + MakerData memory makerData; + uint _amtDeposit = getUint(getIdDeposit, depositAmt); + uint _amtBorrow = getUint(getIdBorrow, borrowAmt); + + makerData._vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(makerData._vault); + + makerData.colAddr = instaMapping.gemJoinMapping(ilk); + makerData.tokenJoinContract = TokenJoinInterface(makerData.colAddr); + makerData.vatContract = VatLike(managerContract.vat()); + makerData.tokenContract = makerData.tokenJoinContract.gem(); + + if (isEth(address(makerData.tokenContract))) { + _amtDeposit = _amtDeposit == uint(-1) ? address(this).balance : _amtDeposit; + makerData.tokenContract.deposit{value: _amtDeposit}(); + } else { + _amtDeposit = _amtDeposit == uint(-1) ? makerData.tokenContract.balanceOf(address(this)) : _amtDeposit; + } + + approve(makerData.tokenContract, address(makerData.colAddr), _amtDeposit); + makerData.tokenJoinContract.join(urn, _amtDeposit); + + managerContract.frob( + makerData._vault, + toInt(convertTo18(makerData.tokenJoinContract.dec(), _amtDeposit)), + _getBorrowAmt( + address(makerData.vatContract), + urn, + ilk, + _amtBorrow + ) + ); + + managerContract.move( + makerData._vault, + address(this), + toRad(_amtBorrow) + ); + + if (makerData.vatContract.can(address(this), address(daiJoinContract)) == 0) { + makerData.vatContract.hope(address(daiJoinContract)); + } + + daiJoinContract.exit(address(this), _amtBorrow); + + setUint(setIdDeposit, _amtDeposit); + setUint(setIdBorrow, _amtBorrow); + + _eventName = "LogDepositAndBorrow(uint256,bytes32,uint256,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode( + makerData._vault, + ilk, + _amtDeposit, + _amtBorrow, + getIdDeposit, + getIdBorrow, + setIdDeposit, + setIdBorrow + ); + } + + /** + * @dev Exit DAI from urn. + * @notice Exit DAI from urn. + * @param vault Vault ID. (Use 0 for last opened vault) + * @param amt The amount of DAI to exit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of DAI exited. + */ + function exitDai( + uint256 vault, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + uint _vault = getVault(vault); + (bytes32 ilk, address urn) = getVaultData(_vault); + + VatLike vatContract = VatLike(managerContract.vat()); + if(_amt == uint(-1)) { + _amt = vatContract.dai(urn); + _amt = _amt / 10 ** 27; + } + + managerContract.move( + _vault, + address(this), + toRad(_amt) + ); + + if (vatContract.can(address(this), address(daiJoinContract)) == 0) { + vatContract.hope(address(daiJoinContract)); + } + + daiJoinContract.exit(address(this), _amt); + + setUint(setId, _amt); + + _eventName = "LogExitDai(uint256,bytes32,uint256,uint256,uint256)"; + _eventParam = abi.encode(_vault, ilk, _amt, getId, setId); + } + + /** + * @dev Deposit DAI in DSR. + * @notice Deposit DAI in DSR. + * @param amt The amount of DAI to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of DAI deposited. + */ + function depositDai( + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + _amt = _amt == uint(-1) ? + daiJoinContract.dai().balanceOf(address(this)) : + _amt; + + VatLike vat = daiJoinContract.vat(); + uint chi = potContract.drip(); + + approve(daiJoinContract.dai(), address(daiJoinContract), _amt); + daiJoinContract.join(address(this), _amt); + if (vat.can(address(this), address(potContract)) == 0) { + vat.hope(address(potContract)); + } + + potContract.join(mul(_amt, RAY) / chi); + setUint(setId, _amt); + + _eventName = "LogDepositDai(uint256,uint256,uint256)"; + _eventParam = abi.encode(_amt, getId, setId); + } + + /** + * @dev Withdraw DAI from DSR. + * @notice Withdraw DAI from DSR. + * @param amt The amount of DAI to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of DAI withdrawn. + */ + function withdrawDai( + uint256 amt, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + uint _amt = getUint(getId, amt); + + VatLike vat = daiJoinContract.vat(); + + uint chi = potContract.drip(); + uint pie; + if (_amt == uint(-1)) { + pie = potContract.pie(address(this)); + _amt = mul(chi, pie) / RAY; + } else { + pie = mul(_amt, RAY) / chi; + } + + potContract.exit(pie); + + uint bal = vat.dai(address(this)); + if (vat.can(address(this), address(daiJoinContract)) == 0) { + vat.hope(address(daiJoinContract)); + } + daiJoinContract.exit( + address(this), + bal >= mul(_amt, RAY) ? _amt : bal / RAY + ); + + setUint(setId, _amt); + + _eventName = "LogWithdrawDai(uint256,uint256,uint256)"; + _eventParam = abi.encode(_amt, getId, setId); + } +} + +contract ConnectV1BMakerDAO is BMakerResolver { + string public constant name = "B.MakerDAO-v1.0"; +} From 07705981d62e080da9654f2db083456a833f2770 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Tue, 6 Jul 2021 00:08:32 +0300 Subject: [PATCH 03/38] basic b.makerdao tests --- .../b.protocol/makerdao/interface.sol | 3 +- test/b.protocol/b.maker.test.js | 198 ++++++++++++++++++ 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 test/b.protocol/b.maker.test.js diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol b/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol index 7a8c4ca8..d291e384 100644 --- a/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol +++ b/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol @@ -18,7 +18,8 @@ interface ManagerLike { } interface BManagerLike is ManagerLike { - function cushion(uint) external view returns(uint); + function cushion(uint) external view returns (uint); + function cdpi() external view returns (uint); } interface VatLike { diff --git a/test/b.protocol/b.maker.test.js b/test/b.protocol/b.maker.test.js new file mode 100644 index 00000000..3eff7d76 --- /dev/null +++ b/test/b.protocol/b.maker.test.js @@ -0,0 +1,198 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); +const { web3, deployments, waffle, ethers } = hre; +const { provider, deployContract } = waffle + +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js") +const buildDSAv2 = require("../../scripts/buildDSAv2") +const encodeSpells = require("../../scripts/encodeSpells.js") +const getMasterSigner = require("../../scripts/getMasterSigner") + +const addresses = require("../../scripts/constant/addresses"); +const abis = require("../../scripts/constant/abis"); +const constants = require("../../scripts/constant/constant"); +const tokens = require("../../scripts/constant/tokens"); + +const connectorMakerArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/main.sol/ConnectV1BMakerDAO.json") + +describe("B.Maker", function () { + const connectorName = "B.MAKER-TEST-A" + + let dsaWallet0 + let masterSigner; + let instaConnectorsV2; + let connector; + let managerWeb3Contract; + let vatWeb3Contract; + let daiWeb3Contract; + + const wallets = provider.getWallets() + const [wallet0, wallet1, wallet2, wallet3] = wallets + before(async () => { + masterSigner = await getMasterSigner(wallet3) + instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2); + connector = await deployAndEnableConnector({ + connectorName, + contractArtifact: connectorMakerArtifacts, + signer: masterSigner, + connectors: instaConnectorsV2 + }) + + const cdpManagerArtifact = await hre.artifacts.readArtifact("BManagerLike"); + const vatArtifact = await hre.artifacts.readArtifact("../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol:VatLike"); + + managerWeb3Contract = new web3.eth.Contract(cdpManagerArtifact.abi, "0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed") + vatWeb3Contract = new web3.eth.Contract(vatArtifact.abi, await managerWeb3Contract.methods.vat().call()) + daiWeb3Contract = new web3.eth.Contract(abis.basic.erc20, tokens.dai.address) + + console.log("Connector address", connector.address) + }) + + it("Should have contracts deployed.", async function () { + expect(!!instaConnectorsV2.address).to.be.true; + expect(!!connector.address).to.be.true; + expect(!!masterSigner.address).to.be.true; + expect(await connector.name()).to.be.equal("B.MakerDAO-v1.0"); + }); + + 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 ETH into DSA wallet", async function () { + await wallet0.sendTransaction({ + to: dsaWallet0.address, + value: ethers.utils.parseEther("10") + }); + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); + }); + }); + + describe("Main", function () { + let vault + let ilk + let urn + + it("Should open ETH-A vault Maker", async function () { + vault = Number(await managerWeb3Contract.methods.cdpi().call()) + 1 + const spells = [ + { + connector: connectorName, + method: "open", + args: ["ETH-A"] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + expect(await managerWeb3Contract.methods.owns(vault).call()).to.be.equal(dsaWallet0.address) + + ilk = await managerWeb3Contract.methods.ilks(vault).call() + expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000") + + urn = await managerWeb3Contract.methods.urns(vault).call() + }); + + it("Should deposit", async function () { + const amount = ethers.utils.parseEther("7") // 7 ETH + const setId = "83478237" + + const spells = [ + { + connector: connectorName, + method: "deposit", + args: [vault, amount, 0, setId] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("3")) + + const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + expect(urnData[0]).to.be.equal(amount) // ink + expect(urnData[1]).to.be.equal("0") // art + + }); + + it("Should withdraw", async function () { + const amount = ethers.utils.parseEther("1") // 1 ETH + const setId = "83478237" + + const spells = [ + { + connector: connectorName, + method: "withdraw", + args: [vault, amount, 0, setId] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("4")) + + const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink + expect(urnData[1]).to.be.equal("0") // art + + }); + + it("Should borrow", async function () { + const amount = ethers.utils.parseEther("6000") // 6000 dai + const setId = "83478237" + + const spells = [ + { + connector: connectorName, + method: "borrow", + args: [vault, amount, 0, setId] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink + expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, amount)) // art + + expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(amount) + }); + + it("Should repay", async function () { + const amount = ethers.utils.parseEther("500") // 500 dai + const setId = "83478237" + + const spells = [ + { + connector: connectorName, + method: "payback", + args: [vault, amount, 0, setId] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink + expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("5500"))) // art + expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(ethers.utils.parseEther("5500")) + }); + }) +}) + +async function daiToArt(vatWeb3Contract, ilk, dai) { + const ilks = await vatWeb3Contract.methods.ilks(ilk).call() + const rate = ilks[1] // second parameter + const _1e27 = ethers.utils.parseEther("1000000000") // 1e9 * 1e18 + const art = dai.mul(_1e27).div(rate) + + return art.add(1) +} + From 6fa171df235ad083a29f51a37f9fc5729d464b17 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Tue, 6 Jul 2021 09:17:12 +0300 Subject: [PATCH 04/38] deposit and borrow test --- test/b.protocol/b.maker.test.js | 45 +++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/b.protocol/b.maker.test.js b/test/b.protocol/b.maker.test.js index 3eff7d76..b14822bd 100644 --- a/test/b.protocol/b.maker.test.js +++ b/test/b.protocol/b.maker.test.js @@ -48,6 +48,13 @@ describe("B.Maker", function () { console.log("Connector address", connector.address) }) + it("test veryClose.", async function () { + expect(veryClose(1000001, 1000000)).to.be.true + expect(veryClose(1000000, 1000001)).to.be.true + expect(veryClose(1003000, 1000001)).to.be.false + expect(veryClose(1000001, 1000300)).to.be.false + }); + it("Should have contracts deployed.", async function () { expect(!!instaConnectorsV2.address).to.be.true; expect(!!connector.address).to.be.true; @@ -183,6 +190,32 @@ describe("B.Maker", function () { expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("5500"))) // art expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(ethers.utils.parseEther("5500")) + }); + + it("Should depositAndBorrow", async function () { + const borrowAmount = ethers.utils.parseEther("1000") // 500 dai + const depositAmount = ethers.utils.parseEther("1") // 1 dai + + const setId = "83478237" + + const spells = [ + { + connector: connectorName, + method: "depositAndBorrow", + args: [vault, depositAmount, borrowAmount, 0, 0, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + expect(urnData[0]).to.be.equal(ethers.utils.parseEther("7")) // ink + expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(ethers.utils.parseEther("6500")) + // calculation is not precise as the jug was dripped + expect(veryClose(urnData[1], await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500")))).to.be.true + //expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500"))) // art + expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("1")) }); }) }) @@ -196,3 +229,15 @@ async function daiToArt(vatWeb3Contract, ilk, dai) { return art.add(1) } +function veryClose(n1, n2) { + n1 = web3.utils.toBN(n1) + n2 = web3.utils.toBN(n2) + + _10000 = web3.utils.toBN(10000) + _9999 = web3.utils.toBN(9999) + + if(n1.mul(_10000).lt(n2.mul(_9999))) return false + if(n2.mul(_10000).lt(n1.mul(_9999))) return false + + return true +} From 2fac6a94ff0d4a6e4940488f7bea9c16712db3c6 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Tue, 6 Jul 2021 11:26:32 +0300 Subject: [PATCH 05/38] close test --- test/b.protocol/b.maker.test.js | 89 ++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/test/b.protocol/b.maker.test.js b/test/b.protocol/b.maker.test.js index b14822bd..0ed96cb4 100644 --- a/test/b.protocol/b.maker.test.js +++ b/test/b.protocol/b.maker.test.js @@ -19,6 +19,7 @@ describe("B.Maker", function () { const connectorName = "B.MAKER-TEST-A" let dsaWallet0 + let dsaWallet1 let masterSigner; let instaConnectorsV2; let connector; @@ -66,6 +67,9 @@ describe("B.Maker", function () { it("Should build DSA v2", async function () { dsaWallet0 = await buildDSAv2(wallet0.address) expect(!!dsaWallet0.address).to.be.true; + + dsaWallet1 = await buildDSAv2(wallet1.address) + expect(!!dsaWallet1.address).to.be.true; }); it("Deposit ETH into DSA wallet", async function () { @@ -74,6 +78,12 @@ describe("B.Maker", function () { value: ethers.utils.parseEther("10") }); expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("10")); + + await wallet1.sendTransaction({ + to: dsaWallet1.address, + value: ethers.utils.parseEther("10") + }); + expect(await ethers.provider.getBalance(dsaWallet1.address)).to.be.gte(ethers.utils.parseEther("10")); }); }); @@ -193,7 +203,7 @@ describe("B.Maker", function () { }); it("Should depositAndBorrow", async function () { - const borrowAmount = ethers.utils.parseEther("1000") // 500 dai + const borrowAmount = ethers.utils.parseEther("1000") // 1000 dai const depositAmount = ethers.utils.parseEther("1") // 1 dai const setId = "83478237" @@ -216,6 +226,83 @@ describe("B.Maker", function () { expect(veryClose(urnData[1], await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500")))).to.be.true //expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500"))) // art expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("1")) + }); + + it("Should close", async function () { + // open a new vault + const newVault = vault + 1 + let spells = [ + { + connector: connectorName, + method: "open", + args: ["ETH-A"] + } + ] + + let tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) + let receipt = await tx.wait() + + expect(await managerWeb3Contract.methods.owns(newVault).call()).to.be.equal(dsaWallet1.address) + + ilk = await managerWeb3Contract.methods.ilks(newVault).call() + expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000") + + urn = await managerWeb3Contract.methods.urns(newVault).call() + + // deposit and borrow + const borrowAmount = ethers.utils.parseEther("6000") // 6000 dai + const depositAmount = ethers.utils.parseEther("5") // 5 ETH + + spells = [ + { + connector: connectorName, + method: "depositAndBorrow", + args: [newVault, depositAmount, borrowAmount, 0, 0, 0, 0] + } + ] + + tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) + receipt = await tx.wait() + + const setId = 0 + + // repay borrow + spells = [ + { + connector: connectorName, + method: "payback", + args: [newVault, borrowAmount, 0, setId] + } + ] + + tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) + receipt = await tx.wait() + + // withdraw deposit + spells = [ + { + connector: connectorName, + method: "withdraw", + args: [newVault, depositAmount, 0, setId] + } + ] + + tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) + receipt = await tx.wait() + + // close + spells = [ + { + connector: connectorName, + method: "close", + args: [newVault] + } + ] + + tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) + receipt = await tx.wait() + + expect(await managerWeb3Contract.methods.owns(newVault).call()).not.to.be.equal(dsaWallet1.address) }); }) }) From 8a70ccddff81dd3d6bb959aad9c5d40460614843 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Tue, 6 Jul 2021 11:42:25 +0300 Subject: [PATCH 06/38] hardhat contracts instead of web3 contracts in test --- test/b.protocol/b.maker.test.js | 62 +++++++++++++++------------------ 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/test/b.protocol/b.maker.test.js b/test/b.protocol/b.maker.test.js index 0ed96cb4..57b687cd 100644 --- a/test/b.protocol/b.maker.test.js +++ b/test/b.protocol/b.maker.test.js @@ -18,14 +18,14 @@ const connectorMakerArtifacts = require("../../artifacts/contracts/mainnet/conne describe("B.Maker", function () { const connectorName = "B.MAKER-TEST-A" - let dsaWallet0 - let dsaWallet1 + let dsaWallet0; + let dsaWallet1; let masterSigner; let instaConnectorsV2; let connector; - let managerWeb3Contract; - let vatWeb3Contract; - let daiWeb3Contract; + let manager; + let vat; + let dai; const wallets = provider.getWallets() const [wallet0, wallet1, wallet2, wallet3] = wallets @@ -39,12 +39,9 @@ describe("B.Maker", function () { connectors: instaConnectorsV2 }) - const cdpManagerArtifact = await hre.artifacts.readArtifact("BManagerLike"); - const vatArtifact = await hre.artifacts.readArtifact("../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol:VatLike"); - - managerWeb3Contract = new web3.eth.Contract(cdpManagerArtifact.abi, "0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed") - vatWeb3Contract = new web3.eth.Contract(vatArtifact.abi, await managerWeb3Contract.methods.vat().call()) - daiWeb3Contract = new web3.eth.Contract(abis.basic.erc20, tokens.dai.address) + manager = await ethers.getContractAt("BManagerLike", "0x3f30c2381CD8B917Dd96EB2f1A4F96D91324BBed") + vat = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/makerdao/interface.sol:VatLike", await manager.vat()) + dai = await ethers.getContractAt("../artifacts/contracts/mainnet/common/interfaces.sol:TokenInterface", tokens.dai.address) console.log("Connector address", connector.address) }) @@ -93,7 +90,7 @@ describe("B.Maker", function () { let urn it("Should open ETH-A vault Maker", async function () { - vault = Number(await managerWeb3Contract.methods.cdpi().call()) + 1 + vault = Number(await manager.cdpi()) + 1 const spells = [ { connector: connectorName, @@ -105,12 +102,12 @@ describe("B.Maker", function () { const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) const receipt = await tx.wait() - expect(await managerWeb3Contract.methods.owns(vault).call()).to.be.equal(dsaWallet0.address) + expect(await manager.owns(vault)).to.be.equal(dsaWallet0.address) - ilk = await managerWeb3Contract.methods.ilks(vault).call() + ilk = await manager.ilks(vault) expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000") - urn = await managerWeb3Contract.methods.urns(vault).call() + urn = await manager.urns(vault) }); it("Should deposit", async function () { @@ -130,7 +127,7 @@ describe("B.Maker", function () { expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("3")) - const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + const urnData = await vat.urns(ilk, urn) expect(urnData[0]).to.be.equal(amount) // ink expect(urnData[1]).to.be.equal("0") // art @@ -153,7 +150,7 @@ describe("B.Maker", function () { expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("4")) - const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + const urnData = await vat.urns(ilk, urn) expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink expect(urnData[1]).to.be.equal("0") // art @@ -174,11 +171,11 @@ describe("B.Maker", function () { const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) const receipt = await tx.wait() - const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + const urnData = await vat.urns(ilk, urn) expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink - expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, amount)) // art + expect(urnData[1]).to.be.equal(await daiToArt(vat, ilk, amount)) // art - expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(amount) + expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(amount) }); it("Should repay", async function () { @@ -196,10 +193,10 @@ describe("B.Maker", function () { const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) const receipt = await tx.wait() - const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + const urnData = await vat.urns(ilk, urn) expect(urnData[0]).to.be.equal(ethers.utils.parseEther("6")) // ink - expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("5500"))) // art - expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(ethers.utils.parseEther("5500")) + expect(urnData[1]).to.be.equal(await daiToArt(vat, ilk, ethers.utils.parseEther("5500"))) // art + expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(ethers.utils.parseEther("5500")) }); it("Should depositAndBorrow", async function () { @@ -219,12 +216,11 @@ describe("B.Maker", function () { const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) const receipt = await tx.wait() - const urnData = await vatWeb3Contract.methods.urns(ilk, urn).call() + const urnData = await vat.urns(ilk, urn) expect(urnData[0]).to.be.equal(ethers.utils.parseEther("7")) // ink - expect(await daiWeb3Contract.methods.balanceOf(dsaWallet0.address).call()).to.be.equal(ethers.utils.parseEther("6500")) + expect(await dai.balanceOf(dsaWallet0.address)).to.be.equal(ethers.utils.parseEther("6500")) // calculation is not precise as the jug was dripped - expect(veryClose(urnData[1], await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500")))).to.be.true - //expect(urnData[1]).to.be.equal(await daiToArt(vatWeb3Contract, ilk, ethers.utils.parseEther("6500"))) // art + expect(veryClose(urnData[1], await daiToArt(vat, ilk, ethers.utils.parseEther("6500")))).to.be.true expect(await ethers.provider.getBalance(dsaWallet0.address)).to.be.gte(ethers.utils.parseEther("1")) }); @@ -242,12 +238,12 @@ describe("B.Maker", function () { let tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) let receipt = await tx.wait() - expect(await managerWeb3Contract.methods.owns(newVault).call()).to.be.equal(dsaWallet1.address) + expect(await manager.owns(newVault)).to.be.equal(dsaWallet1.address) - ilk = await managerWeb3Contract.methods.ilks(newVault).call() + ilk = await manager.ilks(newVault) expect(ilk).to.be.equal("0x4554482d41000000000000000000000000000000000000000000000000000000") - urn = await managerWeb3Contract.methods.urns(newVault).call() + urn = await manager.urns(newVault) // deposit and borrow const borrowAmount = ethers.utils.parseEther("6000") // 6000 dai @@ -302,13 +298,13 @@ describe("B.Maker", function () { tx = await dsaWallet1.connect(wallet1).cast(...encodeSpells(spells), wallet1.address) receipt = await tx.wait() - expect(await managerWeb3Contract.methods.owns(newVault).call()).not.to.be.equal(dsaWallet1.address) + expect(await manager.owns(newVault)).not.to.be.equal(dsaWallet1.address) }); }) }) -async function daiToArt(vatWeb3Contract, ilk, dai) { - const ilks = await vatWeb3Contract.methods.ilks(ilk).call() +async function daiToArt(vat, ilk, dai) { + const ilks = await vat.ilks(ilk) const rate = ilks[1] // second parameter const _1e27 = ethers.utils.parseEther("1000000000") // 1e9 * 1e18 const art = dai.mul(_1e27).div(rate) From 6f356a3a46b3a3646beebfb61f3cc93591078164 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Wed, 4 Aug 2021 00:44:18 +0300 Subject: [PATCH 07/38] b.protocol: deposit to cdp manager and not to vat directly --- .../mainnet/connectors/b.protocol/makerdao/main.sol | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/main.sol b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol index 2f94c1e4..a839fb3a 100644 --- a/contracts/mainnet/connectors/b.protocol/makerdao/main.sol +++ b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol @@ -97,13 +97,10 @@ abstract contract BMakerResolver is Helpers, Events { } approve(tokenContract, address(colAddr), _amt); - tokenJoinContract.join(address(this), _amt); + tokenJoinContract.join(urn, _amt); - VatLike(managerContract.vat()).frob( // TODO zelda - make manager.frob - ilk, - urn, - address(this), - address(this), + managerContract.frob( + _vault, toInt(convertTo18(tokenJoinContract.dec(), _amt)), 0 ); From 33b4b66bd7cab447ba5804fc29d8f044a4115530 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Thu, 5 Aug 2021 12:59:12 +0530 Subject: [PATCH 08/38] Deployed new compound mapping --- docs/connectors.json | 3 ++- scripts/deployCompoundMapping.js | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/connectors.json b/docs/connectors.json index 52b4877d..f4e79b0f 100644 --- a/docs/connectors.json +++ b/docs/connectors.json @@ -36,6 +36,7 @@ } }, "mappings": { - "InstaMappingController": "0xDdd075D5e1024901E4038461e1e4BbC3A48a08d4" + "InstaMappingController": "0xDdd075D5e1024901E4038461e1e4BbC3A48a08d4", + "InstaCompoundMapping": "0xe7a85d0adDB972A4f0A4e57B698B37f171519e88" } } diff --git a/scripts/deployCompoundMapping.js b/scripts/deployCompoundMapping.js index f61428f3..498b00d5 100644 --- a/scripts/deployCompoundMapping.js +++ b/scripts/deployCompoundMapping.js @@ -3,7 +3,7 @@ const { ethers } = hre; async function main() { - const CONNECTORS_V2 = "0xFE2390DAD597594439f218190fC2De40f9Cf1179"; + const CONNECTORS_V2 = "0x97b0B3A8bDeFE8cB9563a3c610019Ad10DB8aD11"; const ctokenMapping = { "ETH-A": "0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5", @@ -16,7 +16,13 @@ async function main() { "USDT-A": "0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9", "WBTC-A": "0xc11b1268c1a384e55c48c2391d8d480264a3a7f4", "WBTC-B": "0xccF4429DB6322D5C611ee964527D42E5d685DD6a", - "ZRX-A": "0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407" + "ZRX-A": "0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407", + "YFI-A": "0x80a2ae356fc9ef4305676f7a3e2ed04e12c33946", + "SUSHI-A": "0x4b0181102a0112a2ef11abee5563bb4a3176c9d7", + "MKR-A": "0x95b4ef2869ebd94beb4eee400a99824bf5dc325b", + "AAVE-A": "0xe65cdb6479bac1e22340e4e755fae7e509ecd06c", + "TUSD-A": "0x12392f67bdf24fae0af363c24ac620a2f67dad86", + "LINK-A": "0xface851a4921ce59e912d19329929ce6da6eb0c7", } const tokenMapping = { @@ -30,7 +36,13 @@ async function main() { "USDT-A": "0xdac17f958d2ee523a2206206994597c13d831ec7", "WBTC-A": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", "WBTC-B": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599", - "ZRX-A": "0xe41d2489571d322189246dafa5ebde1f4699f498" + "ZRX-A": "0xe41d2489571d322189246dafa5ebde1f4699f498", + "YFI-A": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e", + "SUSHI-A": "0x6B3595068778DD592e39A122f4f5a5cF09C90fE2", + "MKR-A": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", + "AAVE-A": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", + "TUSD-A": "0x0000000000085d4780B73119b644AE5ecd22b376", + "LINK-A": "0x514910771af9ca656af840dff83e8264ecf986ca", } const Mapping = await ethers.getContractFactory("InstaCompoundMapping"); From 9f576e3111a4b18d93ad32e6e39d6b730b6856e6 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Thu, 5 Aug 2021 13:00:04 +0530 Subject: [PATCH 09/38] Updated compound mapping address --- contracts/mainnet/connectors/compound/helpers.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/compound/helpers.sol b/contracts/mainnet/connectors/compound/helpers.sol index 08e05120..b78f7d26 100644 --- a/contracts/mainnet/connectors/compound/helpers.sol +++ b/contracts/mainnet/connectors/compound/helpers.sol @@ -13,7 +13,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Compound Mapping */ - CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082); + CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); /** * @dev enter compound market From c0e1b4a1fbd19631cef75a4e5e2569bf82e54886 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Mon, 9 Aug 2021 23:07:09 +0530 Subject: [PATCH 10/38] Updated compound mapping address --- contracts/mainnet/connectors/COMP/helpers.sol | 2 +- contracts/mainnet/connectors/refinance/helpers.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/mainnet/connectors/COMP/helpers.sol b/contracts/mainnet/connectors/COMP/helpers.sol index c793843e..a19242cb 100644 --- a/contracts/mainnet/connectors/COMP/helpers.sol +++ b/contracts/mainnet/connectors/COMP/helpers.sol @@ -19,7 +19,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Compound Mapping */ - CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082); + CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); function getMergedCTokens( string[] calldata supplyIds, diff --git a/contracts/mainnet/connectors/refinance/helpers.sol b/contracts/mainnet/connectors/refinance/helpers.sol index c3593d50..4ab86a00 100644 --- a/contracts/mainnet/connectors/refinance/helpers.sol +++ b/contracts/mainnet/connectors/refinance/helpers.sol @@ -35,7 +35,7 @@ contract Helpers is Basic { /** * @dev Return InstaDApp Mapping Address */ - address constant internal getMappingAddr = 0xA8F9D4aA7319C54C04404765117ddBf9448E2082; // CompoundMapping Address + address constant internal getMappingAddr = 0xe7a85d0adDB972A4f0A4e57B698B37f171519e88; // CompoundMapping Address /** * @dev Return Compound Comptroller Address From 8239368ea42231dad5be8b7907a3af11365aeb48 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Mon, 9 Aug 2021 23:29:18 +0530 Subject: [PATCH 11/38] Updated connector addresses doc --- contracts/mainnet/connectors/COMP/main.sol | 2 +- contracts/mainnet/connectors/refinance/main.sol | 2 +- docs/connectors.json | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contracts/mainnet/connectors/COMP/main.sol b/contracts/mainnet/connectors/COMP/main.sol index 840396bf..65d9b427 100644 --- a/contracts/mainnet/connectors/COMP/main.sol +++ b/contracts/mainnet/connectors/COMP/main.sol @@ -99,5 +99,5 @@ abstract contract CompResolver is Events, Helpers { } contract ConnectV2COMP is CompResolver { - string public constant name = "COMP-v1"; + string public constant name = "COMP-v1.1"; } diff --git a/contracts/mainnet/connectors/refinance/main.sol b/contracts/mainnet/connectors/refinance/main.sol index 2fa0eff6..5c875f1d 100644 --- a/contracts/mainnet/connectors/refinance/main.sol +++ b/contracts/mainnet/connectors/refinance/main.sol @@ -335,5 +335,5 @@ contract RefinanceResolver is CompoundHelpers, AaveV1Helpers, AaveV2Helpers { } contract ConnectV2Refinance is RefinanceResolver { - string public name = "Refinance-v1.0"; + string public name = "Refinance-v1.1"; } \ No newline at end of file diff --git a/docs/connectors.json b/docs/connectors.json index ad0eb37a..92efaa2c 100644 --- a/docs/connectors.json +++ b/docs/connectors.json @@ -5,12 +5,12 @@ "BASIC-A": "0x9926955e0Dd681Dc303370C52f4Ad0a4dd061687", "1INCH-A": "0x235fca310ac7be45c7ad45f111203468743e4b7c", "1INCH-B": "0xaBac3dCf164eD827EAfda8e05eCc8208D6bc5E04", - "COMPOUND-A": "0xbb153cf09a123746e0eb3b3a436c544a7eeb24b6", + "COMPOUND-A": "0x1B1EACaa31abbE544117073f6F8F658a56A3aE25", "AAVE-V1-A": "0x612c5CA43230D9F97a0ac87E4420F66b8DF97e9D", "AAVE-V2-A": "0x68b27A84101ac5120bBAb7Ce8d6b096C961df52C", "MAKERDAO-A": "0x4049db23c605b197f764072569b8db2464653ef6", "UNISWAP-V2-A": "0x1E5CE41BdB653734445FeC3553b61FebDdaFC43c", - "COMP-A": "0xB446e325D44C52b93eC122Bf76301f235f90B9c9", + "COMP-A": "0x907F0C8c99B08606eE0A51ec5Bc3dFdbFC2d92f3", "UNISWAP-A": "0xA4BF319968986D2352FA1c550D781bBFCCE3FcaB", "POLYGON-BRIDGE-A": "0x1b79B302132370B434fb7807b36CB72FB0510aD5", "AAVE-CLAIM-A": "0x611C1FA59Aa1d6352c4C8bD44882063c6aEE85E0", @@ -22,7 +22,7 @@ "INSTAPOOL-A": "0x5806Af7AB22E2916fA582Ff05731Bf7C682387B2", "MAKERDAO-CLAIM-A": "0x2f8cBE650af98602a215b6482F2aD60893C5A4E8", "WETH-A": "0x22075fa719eFb02Ca3cF298AFa9C974B7465E5D3", - "REFINANCE-A": "0x9eA34bE6dA51aa9F6408FeA79c946FDCFA424442", + "REFINANCE-A": "0x6f22931423e8ffC8d51f6E5aF73118fC64b27856", "INST-A": "0x52C2C4a0db049255fF345EB9D3Fb1f555b7a924A", "REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8" }, @@ -37,7 +37,7 @@ }, "mappings": { "InstaMappingController": "0xDdd075D5e1024901E4038461e1e4BbC3A48a08d4", - "InstaCompoundMapping": "0xe7a85d0adDB972A4f0A4e57B698B37f171519e88" + "InstaCompoundMapping": "0xe7a85d0adDB972A4f0A4e57B698B37f171519e88", "InstaReflexerGebMapping": "0x573e5132693C046D1A9F75Bac683889164bA41b4" } } From 56b101f2f95844c64c552effc0ffdd3b1dab2819 Mon Sep 17 00:00:00 2001 From: Edward Mulraney Date: Tue, 10 Aug 2021 11:18:32 +0100 Subject: [PATCH 12/38] handle repayments in adjust() and upate tests --- contracts/mainnet/connectors/liquity/helpers.sol | 3 +-- contracts/mainnet/connectors/liquity/main.sol | 14 +++++++------- test/liquity/liquity.test.js | 14 +++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/contracts/mainnet/connectors/liquity/helpers.sol b/contracts/mainnet/connectors/liquity/helpers.sol index 0fc9ef1c..3fdd35cb 100644 --- a/contracts/mainnet/connectors/liquity/helpers.sol +++ b/contracts/mainnet/connectors/liquity/helpers.sol @@ -29,8 +29,7 @@ abstract contract Helpers is DSMath, Basic { uint maxFeePercentage; uint withdrawAmount; uint depositAmount; - uint borrowAmount; - uint repayAmount; + uint lusdChange; bool isBorrow; } diff --git a/contracts/mainnet/connectors/liquity/main.sol b/contracts/mainnet/connectors/liquity/main.sol index 6bec9af8..ce574dd9 100644 --- a/contracts/mainnet/connectors/liquity/main.sol +++ b/contracts/mainnet/connectors/liquity/main.sol @@ -226,7 +226,7 @@ abstract contract LiquityResolver is Events, Helpers { withdrawAmount = getUint(getIds[1], withdrawAmount); adjustTrove.withdrawAmount = withdrawAmount == uint(-1) ? troveManager.getTroveColl(address(this)) : withdrawAmount; - adjustTrove.borrowAmount = getUint(getIds[2], borrowAmount); + borrowAmount = getUint(getIds[2], borrowAmount); repayAmount = getUint(getIds[3], repayAmount); if (repayAmount == uint(-1)) { @@ -234,14 +234,14 @@ abstract contract LiquityResolver is Events, Helpers { uint _totalDebt = troveManager.getTroveDebt(address(this)); repayAmount = _lusdBal > _totalDebt ? _totalDebt : _lusdBal; } - adjustTrove.repayAmount = repayAmount; adjustTrove.isBorrow = borrowAmount > 0; - + adjustTrove.lusdChange = adjustTrove.isBorrow ? borrowAmount : repayAmount; + borrowerOperations.adjustTrove{value: adjustTrove.depositAmount}( adjustTrove.maxFeePercentage, adjustTrove.withdrawAmount, - adjustTrove.borrowAmount, + adjustTrove.lusdChange, adjustTrove.isBorrow, upperHint, lowerHint @@ -249,11 +249,11 @@ abstract contract LiquityResolver is Events, Helpers { setUint(setIds[0], adjustTrove.depositAmount); setUint(setIds[1], adjustTrove.withdrawAmount); - setUint(setIds[2], adjustTrove.borrowAmount); - setUint(setIds[3], adjustTrove.repayAmount); + setUint(setIds[2], borrowAmount); + setUint(setIds[3], repayAmount); _eventName = "LogAdjust(address,uint256,uint256,uint256,uint256,uint256,uint256[],uint256[])"; - _eventParam = abi.encode(address(this), maxFeePercentage, adjustTrove.depositAmount, adjustTrove.withdrawAmount, adjustTrove.borrowAmount, adjustTrove.repayAmount, getIds, setIds); + _eventParam = abi.encode(address(this), maxFeePercentage, adjustTrove.depositAmount, adjustTrove.withdrawAmount, borrowAmount, repayAmount, getIds, setIds); } /** diff --git a/test/liquity/liquity.test.js b/test/liquity/liquity.test.js index 6b4ae743..7b8dce39 100644 --- a/test/liquity/liquity.test.js +++ b/test/liquity/liquity.test.js @@ -1208,7 +1208,7 @@ describe("Liquity", () => { const depositAmount = 0; const borrowAmount = 0; const withdrawAmount = ethers.utils.parseEther("1"); // 1 ETH; - const repayAmount = ethers.utils.parseUnits("500", 18); // 500 LUSD; + const repayAmount = ethers.utils.parseUnits("10", 18); // 10 LUSD; const { upperHint, lowerHint } = await helpers.getTroveInsertionHints( troveCollateralBefore.sub(withdrawAmount), troveDebtBefore.sub(repayAmount), @@ -1256,7 +1256,7 @@ describe("Liquity", () => { expect( troveDebt, - `Trove debt should have increased by at least ${borrowAmount} ETH` + `Trove debt should have decreased by at least ${repayAmount} LUSD` ).to.gte(expectedTroveDebt); }); @@ -1273,7 +1273,7 @@ describe("Liquity", () => { const depositAmount = ethers.utils.parseEther("1"); // 1 ETH const borrowAmount = 0; const withdrawAmount = 0; - const repayAmount = ethers.utils.parseUnits("100", 18); // 100 lUSD + const repayAmount = ethers.utils.parseUnits("10", 18); // 10 lUSD const upperHint = ethers.constants.AddressZero; const lowerHint = ethers.constants.AddressZero; const maxFeePercentage = ethers.utils.parseUnits("0.5", 18); // 0.5% max fee @@ -1304,7 +1304,7 @@ describe("Liquity", () => { 0, // Repay amount comes from a previous spell's storage slot upperHint, lowerHint, - [ethDepositId, 0, 0, 0], + [ethDepositId, 0, 0, lusdRepayId], [0, 0, 0, 0], ], }; @@ -1323,7 +1323,7 @@ describe("Liquity", () => { .connect(userWallet) .approve(dsa.address, repayAmount); - // Adjust Trove by depositing ETH and borrowing LUSD + // Adjust Trove by depositing ETH and repaying LUSD await dsa .connect(userWallet) .cast(...encodeSpells(spells), userWallet.address, { @@ -1338,7 +1338,7 @@ describe("Liquity", () => { dsa.address ); const expectedTroveColl = troveCollateralBefore.add(depositAmount); - const expectedTroveDebt = troveDebtBefore.add(borrowAmount); + const expectedTroveDebt = troveDebtBefore.sub(repayAmount); expect( troveCollateral, @@ -1347,7 +1347,7 @@ describe("Liquity", () => { expect( troveDebt, - `Trove debt should have increased by at least ${borrowAmount} ETH` + `Trove debt (${troveDebtBefore}) should have decreased by at least ${repayAmount} LUSD` ).to.eq(expectedTroveDebt); }); From ed791eba4766eade746252f2ba9e6c1acee32159 Mon Sep 17 00:00:00 2001 From: yaron velner Date: Mon, 23 Aug 2021 13:06:49 +0300 Subject: [PATCH 13/38] b.liquity --- .../connectors/b.protocol/liquity/events.sol | 22 +++ .../connectors/b.protocol/liquity/helpers.sol | 18 ++ .../b.protocol/liquity/interface.sol | 17 ++ .../connectors/b.protocol/liquity/main.sol | 86 +++++++++ test/b.protocol/b.liquity.test.js | 181 ++++++++++++++++++ 5 files changed, 324 insertions(+) create mode 100644 contracts/mainnet/connectors/b.protocol/liquity/events.sol create mode 100644 contracts/mainnet/connectors/b.protocol/liquity/helpers.sol create mode 100644 contracts/mainnet/connectors/b.protocol/liquity/interface.sol create mode 100644 contracts/mainnet/connectors/b.protocol/liquity/main.sol create mode 100644 test/b.protocol/b.liquity.test.js diff --git a/contracts/mainnet/connectors/b.protocol/liquity/events.sol b/contracts/mainnet/connectors/b.protocol/liquity/events.sol new file mode 100644 index 00000000..0590b125 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/liquity/events.sol @@ -0,0 +1,22 @@ +pragma solidity ^0.7.6; + +contract Events { + + /* Stability Pool */ + event LogStabilityDeposit( + address indexed borrower, + uint amount, + uint lqtyGain, + uint getDepositId, + uint setDepositId, + uint setLqtyGainId + ); + event LogStabilityWithdraw( + address indexed borrower, + uint numShares, + uint lqtyGain, + uint getWithdrawId, + uint setWithdrawId, + uint setLqtyGainId + ); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/liquity/helpers.sol b/contracts/mainnet/connectors/b.protocol/liquity/helpers.sol new file mode 100644 index 00000000..f9463de4 --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/liquity/helpers.sol @@ -0,0 +1,18 @@ +pragma solidity ^0.7.6; + +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; + +import { TokenInterface } from "../../../common/interfaces.sol"; + +import { + StabilityPoolLike, + BAMMLike +} from "./interface.sol"; + +abstract contract Helpers is DSMath, Basic { + StabilityPoolLike internal constant stabilityPool = StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb); + TokenInterface internal constant lqtyToken = TokenInterface(0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D); + TokenInterface internal constant lusdToken = TokenInterface(0x5f98805A4E8be255a32880FDeC7F6728C6568bA0); + BAMMLike internal constant BAMM = BAMMLike(0x0d3AbAA7E088C2c82f54B2f47613DA438ea8C598); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/liquity/interface.sol b/contracts/mainnet/connectors/b.protocol/liquity/interface.sol new file mode 100644 index 00000000..dd2ad2fd --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/liquity/interface.sol @@ -0,0 +1,17 @@ +pragma solidity ^0.7.6; + +interface StabilityPoolLike { + function provideToSP(uint _amount, address _frontEndTag) external; + function withdrawFromSP(uint _amount) external; + function withdrawETHGainToTrove(address _upperHint, address _lowerHint) external; + function getDepositorETHGain(address _depositor) external view returns (uint); + function getDepositorLQTYGain(address _depositor) external view returns (uint); + function getCompoundedLUSDDeposit(address _depositor) external view returns (uint); +} + +interface BAMMLike { + function deposit(uint lusdAmount) external; + function withdraw(uint numShares) external; + function balanceOf(address a) external view returns(uint); + function totalSupply() external view returns(uint); +} \ No newline at end of file diff --git a/contracts/mainnet/connectors/b.protocol/liquity/main.sol b/contracts/mainnet/connectors/b.protocol/liquity/main.sol new file mode 100644 index 00000000..3d19afef --- /dev/null +++ b/contracts/mainnet/connectors/b.protocol/liquity/main.sol @@ -0,0 +1,86 @@ +pragma solidity ^0.7.6; + +/** + * @title B.Liquity. + * @dev Lending & Borrowing. + */ +import { + StabilityPoolLike, + BAMMLike +} from "./interface.sol"; +import { Stores } from "../../../common/stores.sol"; +import { Helpers } from "./helpers.sol"; +import { Events } from "./events.sol"; + +abstract contract BLiquityResolver is Events, Helpers { + /* Begin: Stability Pool */ + + /** + * @dev Deposit LUSD into Stability Pool + * @notice Deposit LUSD into Stability Pool + * @param amount Amount of LUSD to deposit into Stability Pool + * @param getDepositId Optional storage slot to retrieve the amount of LUSD from + * @param setDepositId Optional storage slot to store the final amount of LUSD deposited + * @param setLqtyGainId Optional storage slot to store any LQTY gains in + */ + function deposit( + uint amount, + uint getDepositId, + uint setDepositId, + uint setLqtyGainId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + amount = getUint(getDepositId, amount); + + amount = amount == uint(-1) ? lusdToken.balanceOf(address(this)) : amount; + + uint lqtyBalanceBefore = lqtyToken.balanceOf(address(this)); + + lusdToken.approve(address(BAMM), amount); + BAMM.deposit(amount); + + uint lqtyBalanceAfter = lqtyToken.balanceOf(address(this)); + uint lqtyGain = sub(lqtyBalanceAfter, lqtyBalanceBefore); + + setUint(setDepositId, amount); + setUint(setLqtyGainId, lqtyGain); + + _eventName = "LogStabilityDeposit(address,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(this), amount,lqtyGain, getDepositId, setDepositId, setLqtyGainId); + } + + /** + * @dev Withdraw user deposited LUSD from Stability Pool + * @notice Withdraw LUSD from Stability Pool + * @param numShares amount of shares to withdraw from the BAMM + * @param getWithdrawId Optional storage slot to retrieve the amount of LUSD to withdraw from + * @param setWithdrawId Optional storage slot to store the withdrawn LUSD + * @param setLqtyGainId Optional storage slot to store any LQTY gains in + */ + function withdraw( + uint numShares, + uint getWithdrawId, + uint setWithdrawId, + uint setLqtyGainId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + numShares = getUint(getWithdrawId, numShares); + + numShares = numShares == uint(-1) ? BAMM.balanceOf(address(this)) : numShares; + + uint lqtyBalanceBefore = lqtyToken.balanceOf(address(this)); + + BAMM.withdraw(numShares); + + uint lqtyBalanceAfter = lqtyToken.balanceOf(address(this)); + uint lqtyGain = sub(lqtyBalanceAfter, lqtyBalanceBefore); + + setUint(setWithdrawId, numShares); + setUint(setLqtyGainId, lqtyGain); + + _eventName = "LogStabilityWithdraw(address,uint256,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(address(this), numShares, lqtyGain, getWithdrawId, setWithdrawId, setLqtyGainId); + } +} + +contract ConnectV2BLiquity is BLiquityResolver { + string public name = "B.Liquity-v1"; +} \ No newline at end of file diff --git a/test/b.protocol/b.liquity.test.js b/test/b.protocol/b.liquity.test.js new file mode 100644 index 00000000..8a180345 --- /dev/null +++ b/test/b.protocol/b.liquity.test.js @@ -0,0 +1,181 @@ +const { expect } = require("chai"); +const hre = require("hardhat"); +const { web3, deployments, waffle, ethers } = hre; +const { provider, deployContract } = waffle + +const deployAndEnableConnector = require("../../scripts/deployAndEnableConnector.js") +const buildDSAv2 = require("../../scripts/buildDSAv2") +const encodeSpells = require("../../scripts/encodeSpells.js") +const getMasterSigner = require("../../scripts/getMasterSigner") + +const addresses = require("../../scripts/constant/addresses"); +const abis = require("../../scripts/constant/abis"); +const constants = require("../../scripts/constant/constant"); +const tokens = require("../../scripts/constant/tokens"); + +const connectorLiquityArtifacts = require("../../artifacts/contracts/mainnet/connectors/b.protocol/liquity/main.sol/ConnectV2BLiquity.json") + +const LUSD_WHALE = "0x66017D22b0f8556afDd19FC67041899Eb65a21bb" // stability pool + +const BAMM_ADDRESS = "0x0d3AbAA7E088C2c82f54B2f47613DA438ea8C598" + +describe("B.Liquity", function () { + const connectorName = "B.LIQUITY-TEST-A" + + let dsaWallet0; + let dsaWallet1; + let masterSigner; + let instaConnectorsV2; + let connector; + let manager; + let vat; + let lusd; + let bammToken; + let stabilityPool; + + const wallets = provider.getWallets() + const [wallet0, wallet1, wallet2, wallet3] = wallets + before(async () => { + masterSigner = await getMasterSigner(wallet3) + instaConnectorsV2 = await ethers.getContractAt(abis.core.connectorsV2, addresses.core.connectorsV2); + connector = await deployAndEnableConnector({ + connectorName, + contractArtifact: connectorLiquityArtifacts, + signer: masterSigner, + connectors: instaConnectorsV2 + }) + + lusd = await ethers.getContractAt("../artifacts/contracts/mainnet/common/interfaces.sol:TokenInterface", "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0") + bammToken = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/liquity/interface.sol:BAMMLike", BAMM_ADDRESS) + stabilityPool = await ethers.getContractAt("../artifacts/contracts/mainnet/connectors/b.protocol/liquity/interface.sol:StabilityPoolLike", "0x66017D22b0f8556afDd19FC67041899Eb65a21bb") + + console.log("Connector address", connector.address) + }) + + it("test veryClose.", async function () { + expect(veryClose(1000001, 1000000)).to.be.true + expect(veryClose(1000000, 1000001)).to.be.true + expect(veryClose(1003000, 1000001)).to.be.false + expect(veryClose(1000001, 1000300)).to.be.false + }); + + it("Should have contracts deployed.", async function () { + expect(!!instaConnectorsV2.address).to.be.true; + expect(!!connector.address).to.be.true; + expect(!!masterSigner.address).to.be.true; + expect(await connector.name()).to.be.equal("B.Liquity-v1"); + }); + + describe("DSA wallet setup", function () { + it("Should build DSA v2", async function () { + dsaWallet0 = await buildDSAv2(wallet0.address) + expect(!!dsaWallet0.address).to.be.true; + + dsaWallet1 = await buildDSAv2(wallet1.address) + expect(!!dsaWallet1.address).to.be.true; + }); + + it("Deposit LUSD into DSA wallet", async function () { + await hre.network.provider.request({ + method: "hardhat_impersonateAccount", + params: [LUSD_WHALE], + }); + + const signer = await hre.ethers.provider.getSigner(LUSD_WHALE); + await lusd.connect(signer).transfer(dsaWallet0.address, ethers.utils.parseEther("100000")) + + expect(await lusd.balanceOf(dsaWallet0.address)).to.equal(ethers.utils.parseEther("100000")); + }); + }); + + describe("Main", function () { + it("should deposit 10k LUSD", async function () { + const totalSupplyBefore = await bammToken.totalSupply(); + const lusdBalanceBefore = await stabilityPool.getCompoundedLUSDDeposit(BAMM_ADDRESS); + const amount = ethers.utils.parseEther("10000"); + const spells = [ + { + connector: connectorName, + method: "deposit", + args: [amount, 0, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + const expectedBalance = totalSupplyBefore.mul(amount).div(lusdBalanceBefore) + expect(veryClose(expectedBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true + }); + + it("should deposit all LUSD", async function () { + const totalSupplyBefore = await bammToken.totalSupply(); + const lusdBalanceBefore = await stabilityPool.getCompoundedLUSDDeposit(BAMM_ADDRESS); + const amount = web3.utils.toBN("2").pow(web3.utils.toBN("256")).sub(web3.utils.toBN("1")); + const balanceBefore = await bammToken.balanceOf(dsaWallet0.address) + + const spells = [ + { + connector: connectorName, + method: "deposit", + args: [amount, 0, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + const expectedBalance = (totalSupplyBefore.mul(ethers.utils.parseEther("90000")).div(lusdBalanceBefore)).add(balanceBefore) + expect(veryClose(expectedBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true + }); + + it("should withdraw half of the shares", async function () { + const balanceBefore = await bammToken.balanceOf(dsaWallet0.address) + const halfBalance = balanceBefore.div("2") + + const spells = [ + { + connector: connectorName, + method: "withdraw", + args: [halfBalance, 0, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + expect(veryClose(halfBalance, await bammToken.balanceOf(dsaWallet0.address))).to.be.true + expect(veryClose(ethers.utils.parseEther("50000"), await lusd.balanceOf(dsaWallet0.address))).to.be.true + }); + + it("should withdraw all the shares", async function () { + const amount = web3.utils.toBN("2").pow(web3.utils.toBN("256")).sub(web3.utils.toBN("1")); + + const spells = [ + { + connector: connectorName, + method: "withdraw", + args: [amount, 0, 0, 0] + } + ] + + const tx = await dsaWallet0.connect(wallet0).cast(...encodeSpells(spells), wallet1.address) + const receipt = await tx.wait() + + expect(veryClose(ethers.utils.parseEther("100000"), await lusd.balanceOf(dsaWallet0.address))).to.be.true + }); + }) +}) + +function veryClose(n1, n2) { + n1 = web3.utils.toBN(n1) + n2 = web3.utils.toBN(n2) + + _10000 = web3.utils.toBN(10000) + _9999 = web3.utils.toBN(9999) + + if(n1.mul(_10000).lt(n2.mul(_9999))) return false + if(n2.mul(_10000).lt(n1.mul(_9999))) return false + + return true +} From 9a070412d5eccfdc9d8e9e25b543aabccfb242d8 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Tue, 24 Aug 2021 02:32:44 +0530 Subject: [PATCH 14/38] Added Liquity connector --- docs/connectors.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/connectors.json b/docs/connectors.json index 92efaa2c..28c96123 100644 --- a/docs/connectors.json +++ b/docs/connectors.json @@ -24,7 +24,8 @@ "WETH-A": "0x22075fa719eFb02Ca3cF298AFa9C974B7465E5D3", "REFINANCE-A": "0x6f22931423e8ffC8d51f6E5aF73118fC64b27856", "INST-A": "0x52C2C4a0db049255fF345EB9D3Fb1f555b7a924A", - "REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8" + "REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8", + "LIQUITY-A": "0x3643bA40B8e2bd8F77233BDB6abe38c218f31bFe" }, "137" : { "1INCH-A": "0xC0d9210496afE9763F5d8cEb8deFfBa817232A9e", From 563aada811bc0b23a6e2176267289bc4e96b81c3 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 01:06:59 +0530 Subject: [PATCH 15/38] Updated deposit comment --- contracts/mainnet/connectors/basic/main.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/mainnet/connectors/basic/main.sol b/contracts/mainnet/connectors/basic/main.sol index ace1c225..715fd1b3 100644 --- a/contracts/mainnet/connectors/basic/main.sol +++ b/contracts/mainnet/connectors/basic/main.sol @@ -17,8 +17,8 @@ abstract contract BasicResolver is Events, DSMath, Basic { /** * @dev Deposit Assets To Smart Account. - * @notice Deposit a token to DSA - * @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @notice Deposit a token to DSA. + * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```. For ERC20: Need to give allowance piror casting spells.) * @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for ETH)) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens deposited. From bbb01cd6bdef31200861a7d8f22cf9a38d2b68e2 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 01:10:10 +0530 Subject: [PATCH 16/38] Update main.sol --- contracts/mainnet/connectors/basic/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/basic/main.sol b/contracts/mainnet/connectors/basic/main.sol index 715fd1b3..3ab94455 100644 --- a/contracts/mainnet/connectors/basic/main.sol +++ b/contracts/mainnet/connectors/basic/main.sol @@ -18,7 +18,7 @@ abstract contract BasicResolver is Events, DSMath, Basic { /** * @dev Deposit Assets To Smart Account. * @notice Deposit a token to DSA. - * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```. For ERC20: Need to give allowance piror casting spells.) + * @param token The address of the token to deposit.\n(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.\nFor ERC20: Need to give allowance piror casting spells.) * @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for ETH)) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens deposited. From 4d1af0fe3efc1cc0a4a40053bf01b68787eead9a Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 01:23:12 +0530 Subject: [PATCH 17/38] Update main.sol --- contracts/mainnet/connectors/basic/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/basic/main.sol b/contracts/mainnet/connectors/basic/main.sol index 3ab94455..d98df0ee 100644 --- a/contracts/mainnet/connectors/basic/main.sol +++ b/contracts/mainnet/connectors/basic/main.sol @@ -18,7 +18,7 @@ abstract contract BasicResolver is Events, DSMath, Basic { /** * @dev Deposit Assets To Smart Account. * @notice Deposit a token to DSA. - * @param token The address of the token to deposit.\n(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.\nFor ERC20: Need to give allowance piror casting spells.) + * @param token The address of the token to deposit.
(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.
For ERC20: Need to give allowance piror casting spells.) * @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for ETH)) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens deposited. From cd337224b51e638794e7458ec217e8095d675a1e Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 01:25:29 +0530 Subject: [PATCH 18/38] Update main.sol --- contracts/mainnet/connectors/basic/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/basic/main.sol b/contracts/mainnet/connectors/basic/main.sol index d98df0ee..60c2470b 100644 --- a/contracts/mainnet/connectors/basic/main.sol +++ b/contracts/mainnet/connectors/basic/main.sol @@ -18,7 +18,7 @@ abstract contract BasicResolver is Events, DSMath, Basic { /** * @dev Deposit Assets To Smart Account. * @notice Deposit a token to DSA. - * @param token The address of the token to deposit.
(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.
For ERC20: Need to give allowance piror casting spells.) + * @param token The address of the token to deposit.
(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE and need to pass `value` parameter equal to `amt` in cast function ```dsa.cast({..., value: amt})```.
For ERC20: Need to give allowance prior casting spells.) * @param amt The amount of tokens to deposit. (For max: `uint256(-1)` (Not valid for ETH)) * @param getId ID to retrieve amt. * @param setId ID stores the amount of tokens deposited. From b0744e2797684ac0b1a8e44cc6c32ba05c1dbc18 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 03:00:30 +0530 Subject: [PATCH 19/38] Updated Compound Mapping address --- contracts/mainnet/connectors/b.protocol/compound/helpers.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/b.protocol/compound/helpers.sol b/contracts/mainnet/connectors/b.protocol/compound/helpers.sol index 74e149b1..9cd8ca30 100644 --- a/contracts/mainnet/connectors/b.protocol/compound/helpers.sol +++ b/contracts/mainnet/connectors/b.protocol/compound/helpers.sol @@ -13,7 +13,7 @@ abstract contract Helpers is DSMath, Basic { /** * @dev Compound Mapping */ - CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xA8F9D4aA7319C54C04404765117ddBf9448E2082); + CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe7a85d0adDB972A4f0A4e57B698B37f171519e88); /** * @dev B.Compound Mapping From a9897fe3721f39b83644d82806e08d22cbd4f3e4 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 03:00:41 +0530 Subject: [PATCH 20/38] Minor change --- contracts/mainnet/connectors/b.protocol/compound/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/b.protocol/compound/main.sol b/contracts/mainnet/connectors/b.protocol/compound/main.sol index ecc062ad..cfef8513 100644 --- a/contracts/mainnet/connectors/b.protocol/compound/main.sol +++ b/contracts/mainnet/connectors/b.protocol/compound/main.sol @@ -342,6 +342,6 @@ abstract contract BCompoundResolver is Events, Helpers { } } -contract ConnectV1BCompound is BCompoundResolver { +contract ConnectV2BCompound is BCompoundResolver { string public name = "B.Compound-v1.0"; } From fa0a22e49c6a708f48c4a3cd04d3fea4a83c1196 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 03:00:48 +0530 Subject: [PATCH 21/38] Minor change --- contracts/mainnet/connectors/b.protocol/makerdao/main.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/b.protocol/makerdao/main.sol b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol index a839fb3a..bc4e2deb 100644 --- a/contracts/mainnet/connectors/b.protocol/makerdao/main.sol +++ b/contracts/mainnet/connectors/b.protocol/makerdao/main.sol @@ -516,6 +516,6 @@ abstract contract BMakerResolver is Helpers, Events { } } -contract ConnectV1BMakerDAO is BMakerResolver { +contract ConnectV2BMakerDAO is BMakerResolver { string public constant name = "B.MakerDAO-v1.0"; } From fa4de09e1ddcc504b7e3dc21c6a3ab67d6079b09 Mon Sep 17 00:00:00 2001 From: Sowmay Jain Date: Thu, 26 Aug 2021 13:13:33 +0530 Subject: [PATCH 22/38] Update README.md --- README.md | 385 ------------------------------------------------------ 1 file changed, 385 deletions(-) diff --git a/README.md b/README.md index 5b0f1f4a..bfea269b 100644 --- a/README.md +++ b/README.md @@ -7,388 +7,3 @@ DSAs are powerful because they can easily be extended with connectors. Every new You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained [here](docs/how-to-add-new-connector.md). Following is the list of all the supported connectors. Following is the list of all the primary connectors used to cast spells: [Read this post to learn about getId and setId used in the connectors](https://discuss.instadapp.io/t/how-to-use-getid-setid/104) - -## Authority - -[Code](contracts/mainnet/connectors/authority/main.sol) - -### `add(authority)` - -**Add an address authority** - -`authority` - Address of the authority to add - -### `remove(authority)` - -**Remove an address authority** - -`authority` - Address of the authority to remove - -## Basic - -[Code](contracts/mainnet/connectors/basic/main.sol) - -### `deposit(erc20, amt, getId, setId)` - -**Deposit a token or ETH to DSA.** - -`erc20` - Address of the token to deposit. ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE - -`amt` - Amount of token to deposit - -In case of an ERC20 Token, allowance must be given to DSA before depositing - -### `withdraw(erc20, amt, getId, setId)` - -**Withdraw a token or ETH from DSA.** - -`erc20` - Address of the token to withdraw. ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE - -`amt` - Amount of token to withdraw - -`to` - Address to which token will be withdrawn - -## MakerDAO - -[Code](contracts/mainnet/connectors/makerdao/main.sol) - -### `open(collateralType)` - -**Open a Maker vault** of the `collateralType`. E.g. "ETH-A", "USDC-B", etc... - -### `close(vault)` - -**Close a Maker vault** - -`vault` - Vault ID (Use 0 for last opened vault) - -### `deposit(vault, amt, getId, setId)` - -**Deposit collateral to a Maker vault.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`amt` - Amount of collteral to deposit - -### `withdraw(vault, amt, getId, setId)` - -**Withdraw collateral from a Maker vault.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`amt` - Amount of collteral to withdraw - -### `borrow(vault, amt, getId, setId)` - -**Borrow DAI from a Maker vault.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`amt` - Amount of DAI to borrow - -### `payback(vault, amt, getId, setId)` - -**Payback DAI to a Maker vault.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`amt` - Amount of DAI to payback - -### `withdrawLiquidated(vault, amt, getId, setId)` - -**Withdraw leftover collateral after liquidation.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`amt` - Amount of collateral to withdraw - -### `depositAndBorrow(vault, depositAmt, borrowAmt, getIdDeposit, getIdBorrow, setIdDeposit, setIdBorrow)` - -**Deposit collateral & borrow DAI from a vault.** - -`vault` - Vault ID (Use 0 for last opened vault) - -`depositAmt` - Amount of collateral to deposit - -`borrowAmt` - Amount of DAI to borrow - -## Compound - -[Code](contracts/mainnet/connectors/compound/main.sol) - -### `deposit(token, amt, getId, setId)` - -**Deposit token to Compound.** - -`token` - Address of the token to deposit - -`amt` - Amount of token to deposit - -### `withdraw(token, amt, getId, setId)` - -**Withdraw token from Compound.** - -`token` - Address of the token to withdraw - -`amt` - Amount of token to withdraw - -### `borrow(token, amt, getId, setId)` - -**Borrow token from Compound.** - -`token` - Address of the token to borrow - -`amt` - Amount of token to borrow - -### `payback(token, amt, getId, setId)` - -**Payback debt to Compound.** - -`token` - Address of the token to payback - -`amt` - Amount of token to payback - -## COMP - -[Code](contracts/mainnet/connectors/COMP/main.sol) - -### `ClaimComp(setId)` - -**Claim unclaimed COMP** - -### `ClaimCompTwo(tokens, setId)` - -**Claim unclaimed COMP** - -`tokens` - List of tokens supplied or borrowed - -### `ClaimCompThree(supplyTokens, borrowTokens, setId)` - -**Claim unclaimed COMP** - -`supplyTokens` - List of tokens supplied - -`borrowTokens` - List of tokens borrowed - -### `delegate(delegatee)` - -**Delegate COMP votes** - -`delegatee` - Address of the delegatee - -## Aave v1 - -[Code](contracts/mainnet/connectors/aave/main.sol) - -### `deposit(token, amt, getId, setId)` - -**Deposit token to Aave.** - -`token` - Address of the token to deposit - -`amt` - Amount of token to deposit - -### `withdraw(token, amt, getId, setId)` - -**Withdraw token from Aave.** - -`token` - Address of the token to withdraw - -`amt` - Amount of token to withdraw - -### `borrow(token, amt, getId, setId)` - -**Borrow token from Aave.** - -`token` - Address of the token to borrow - -`amt` - Amount of token to borrow - -### `payback(token, amt, getId, setId)` - -**Payback debt to Aave.** - -`token` - Address of the token to payback - -`amt` - Amount of token to payback - -## Aave v2 - -[Code](contracts/mainnet/connectors/aave_v2/main.sol) - -### `deposit(token, amt, getId, setId)` - -**Deposit token to Aave.** - -`token` - Address of the token to deposit - -`amt` - Amount of token to deposit - -### `withdraw(token, amt, getId, setId)` - -**Withdraw token from Aave.** - -`token` - Address of the token to withdraw - -`amt` - Amount of token to withdraw - -### `borrow(token, amt, rateMode, getId, setId)` - -**Borrow token from Aave.** - -`token` - Address of the token to borrow - -`amt` - Amount of token to borrow - -`rateMode` - Borrow interest rate mode (1 = Stable & 2 = Variable) - -### `payback(token, amt, rateMode, getId, setId)` - -**Payback debt to Aave.** - -`token` - Address of the token to payback - -`amt` - Amount of token to payback - -`rateMode` - Borrow interest rate mode (1 = Stable & 2 = Variable) - -## dYdX - -[Code](contracts/mainnet/connectors/dydx/main.sol) - -### `deposit(token, amt, getId, setId)` - -**Deposit token to dYdX.** - -`token` - Address of the token to deposit - -`amt` - Amount of token to deposit - -### `withdraw(token, amt, getId, setId)` - -**Withdraw token from dYdX.** - -`token` - Address of the token to withdraw - -`amt` - Amount of token to withdraw - -### `borrow(token, amt, getId, setId)` - -**Borrow token from dYdX.** - -`token` - Address of the token to borrow - -`amt` - Amount of token to borrow - -### `payback(token, amt, getId, setId)` - -**Payback debt to dYdX.** - -`token` - Address of the token to payback - -`amt` - Amount of token to payback - -## Uniswap - -[Code](contracts/mainnet/connectors/uniswap/main.sol) - -### `deposit(tokenA, tokenB, amtA, unitAmt, slippage, getId, setId)` - -**Deposit liquidity to tokenA/tokenB pool** - -`tokenA` - Address of token A - -`tokenB` - Address of token B - -`amtA` - Amount of token A to deposit - -`unitAmt` - Unit amount of amtB/amtA with slippage. - -`slippage` - Slippage amount in wei - - -### `withdraw(tokenA, tokenB, uniAmt, unitAmtA, unitAmtB, getId, setId)` - -**Withdraw liquidity from tokenA/tokenB pool** - -`tokenA` - Address of token A - -`tokenB` - Address of token B - -`uniAmt` - Amount of LP tokens to withdraw - -`unitAmtA` - Unit amount of amtA/uniAmt with slippage. - -`unitAmtB` - Unit amount of amtB/uniAmt with slippage. - -### `buy(buyAddr, sellAddr, buyAmt, unitAmt, getId, setId)` - -**Buy a token/ETH** - -`buyAddr` - Address of the buying token - -`sellAddr` - Address of the selling token - -`buyAmt` - Amount of tokens to buy - -`unitAmt` - Unit amount of sellAmt/buyAmt with slippage - -### `sell(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)` - -**Sell a token/ETH** - -`buyAddr` - Address of the buying token - -`sellAddr` - Address of the selling token - -`sellAmt` - Amount of tokens to sell - -`unitAmt` - Unit amount of buyAmt/sellAmt with slippage - -## 1Inch - -[Code](contracts/mainnet/connectors/1inch/main.sol) - -### `sell(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)` - -**Sell ETH/ERC20 using 1proto** - -`buyAddr` - Address of the buying token - -`sellAddr` - Address of the selling token - -`sellAmt` - Amount of tokens to sell - -`unitAmt` - Unit amount of buyAmt/sellAmt with slippage - -### `sellTwo(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)` - -**Sell ETH/ERC20 using 1proto** - -`buyAddr` - Address of the buying token - -`sellAddr` - Address of the selling token - -`sellAmt` - Amount of tokens to sell - -`unitAmt` - Unit amount of buyAmt/sellAmt with slippage - -`[]distribution` - Distribution of swap across different dex. - -`disableDexes` - Disable a dex. (To disable none: 0) - -### `sellTwo(buyAddr, sellAddr, sellAmt, unitAmt, getId, setId)` - -**Sell ETH/ERC20 using 1inch** - -Use [1Inch API](https://docs.1inch.exchange/api/) for calldata - -`buyAddr` - Address of the buying token - -`sellAddr` - Address of the selling token - -`sellAmt` - Amount of tokens to sell - -`unitAmt` - Unit amount of buyAmt/sellAmt with slippage - -`callData` - Data from 1inch API From 92db8df3ece73e6337930b5cfee0c5754300bbb7 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Thu, 26 Aug 2021 16:21:11 +0530 Subject: [PATCH 23/38] Update how-to-add-new-connector.md --- docs/how-to-add-new-connector.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-to-add-new-connector.md b/docs/how-to-add-new-connector.md index 29207022..8d787696 100644 --- a/docs/how-to-add-new-connector.md +++ b/docs/how-to-add-new-connector.md @@ -31,7 +31,7 @@ Few things to consider while writing the connector: * `_eventParam` of `bytes` type: This will be the abi encoded event parameters * The contracts should not have `selfdestruct()` * The contracts should not have `delegatecall()` -* Use `uint(-1)` for maximum amount everywhere +* Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere * Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20) * Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc * Only `approve()` limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. From a9980a05e9861388743509504a93d7c06675c6c6 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Thu, 26 Aug 2021 16:33:14 +0530 Subject: [PATCH 24/38] Update README.md --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bfea269b..d8e21ead 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,49 @@ Connectors are standard proxy logics contract that let DeFi Smart Account (DSA) DSAs are powerful because they can easily be extended with connectors. Every new connector that is added is immediately usable by any developer building on top of DSAs. Connectors can either be base connectors to protocols, auth connectors, higher level connectors with more specific use cases like optimized lending, or connectors to native liquidity pools. -You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained [here](docs/how-to-add-new-connector.md). Following is the list of all the supported connectors. Following is the list of all the primary connectors used to cast spells: +You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained below. + +## How to add a new connector + +You can create a new PR to add a new connector. To get the PR merged, certain requirements needs to be met which will be explained here. + +### New connector should follow the current directory structure + +Common files for all connectors are in `contracts/common` directory. + +* `math.sol` has methods for mathematical operations (`DSMath`) +* `interfaces.sol` contains the common interfaces + * `TokenInterface` for ERC-20 interface including WETH +* `stores.sol` contains the global constants as well as methods `getId` & `setId` (`Stores`) +* `basic.sol` inherits `DSMath` & `Stores` contracts. This contains few details explained below + * Wrapping & unwrapping ETH (`convertEthToWeth` & `convertWethToEth`) + * Getting token & ETH balance of DSA + +Connectors are under `contracts/connectors` directory, and should be formatted as follows: + +* Connector events should be in a separate contract: `events.sol` +* Interfaces should be defined in a seperate file: `interface.sol` +* If the connector has helper methods & constants (including interface instances), this should be defined in a separate file: `helpers.sol` + * `Helpers` contract should inherit `Basic` contract from common directory + * If the connector doesn't have any helper methods, the main contract should inherit `Basic` contract +* The main logic of the contract should be under `main.sol`, and the contract should inherit `Helpers` (if exists, otherwise `Basic`) & `Events` + +Few things to consider while writing the connector: + +* Connector should have a public string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1` +* User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables: + * `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)` + * `_eventParam` of `bytes` type: This will be the abi encoded event parameters +* The contracts should not have `selfdestruct()` +* The contracts should not have `delegatecall()` +* Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere +* Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20) +* Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc +* Only `approve()` limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. +* Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell +* Use `setUint()` (declared in `Stores`) for setting value to save for the future spell + +### Support + +If you can't find something you're looking for or have any questions, ask them at our developers community on [Discord](https://discord.gg/83vvrnY) or simply send an [Email](mailto:info@instadapp.io). -[Read this post to learn about getId and setId used in the connectors](https://discuss.instadapp.io/t/how-to-use-getid-setid/104) From f23341d99fb1c30a8e89a96d2317b7450c05cee2 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Thu, 26 Aug 2021 16:34:46 +0530 Subject: [PATCH 25/38] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d8e21ead..2304f33c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ DSAs are powerful because they can easily be extended with connectors. Every new You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained below. +List of all the mainnet connector for referrence is (here)[https://github.com/Instadapp/dsa-connectors/tree/main/contracts/mainnet/connectors] + ## How to add a new connector You can create a new PR to add a new connector. To get the PR merged, certain requirements needs to be met which will be explained here. From e0de2ca44e49f32fd5fd1494b5184615602de061 Mon Sep 17 00:00:00 2001 From: Samyak Jain <34437877+KaymasJain@users.noreply.github.com> Date: Thu, 26 Aug 2021 16:35:16 +0530 Subject: [PATCH 26/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2304f33c..2f7daf34 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DSAs are powerful because they can easily be extended with connectors. Every new You can create a PR to request a support for specific protocol or external contracts. The process to add a new connector is explained below. -List of all the mainnet connector for referrence is (here)[https://github.com/Instadapp/dsa-connectors/tree/main/contracts/mainnet/connectors] +List of all the mainnet connector for referrence is [here](https://github.com/Instadapp/dsa-connectors/tree/main/contracts/mainnet/connectors) ## How to add a new connector From c6c0c825964f61524ab0efba3c398820338f9944 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 22:05:18 +0530 Subject: [PATCH 27/38] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f7daf34..24e978cb 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,8 @@ Few things to consider while writing the connector: * Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere * Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20) * Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc -* Only `approve()` limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. +* Only `approve()` (Use from `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. +* User interacting functions should have natspec comments(@dev, @notice, @param). * Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell * Use `setUint()` (declared in `Stores`) for setting value to save for the future spell From 1e380f7c2d67356309d4e0fb38f853d4d3ed6307 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 22:08:40 +0530 Subject: [PATCH 28/38] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24e978cb..1f88fb08 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Few things to consider while writing the connector: * Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere * Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20) * Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc -* Only `approve()` (Use from `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. +* Only `approve()` (Wrapper function to be used is declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. * User interacting functions should have natspec comments(@dev, @notice, @param). * Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell * Use `setUint()` (declared in `Stores`) for setting value to save for the future spell From b286025bc6c7d5c72c1a2eaa2a06b8dcc7b0f137 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 22:10:17 +0530 Subject: [PATCH 29/38] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1f88fb08..e3dc4bbb 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Connectors are under `contracts/connectors` directory, and should be formatted a Few things to consider while writing the connector: * Connector should have a public string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1` +* Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound` * User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables: * `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)` * `_eventParam` of `bytes` type: This will be the abi encoded event parameters From 541df8e551affea60d1c7977a7f5f7d932da3e19 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Thu, 26 Aug 2021 22:11:14 +0530 Subject: [PATCH 30/38] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e3dc4bbb..e9a60cd8 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ Connectors are under `contracts/connectors` directory, and should be formatted a Few things to consider while writing the connector: -* Connector should have a public string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1` +* Connector should have a public constant string declared `name`, which will be the name of the connector. This will be versioned. Ex: `Compound-v1` * Contract name should start with `ConnectV2` appended with protocol name. Eg: `ConnectV2Compound` * User interacting methods (`external` methods) will not be emitting events, rather the methods will be returning 2 variables: * `_eventName` of `string` type: This will be the event signture defined in the `Events` contract. Ex: `LogDeposit(address,address,uint256,uint256,uint256)` @@ -45,7 +45,7 @@ Few things to consider while writing the connector: * Use `uint(-1)` of `type(uint256).max` for maximum amount everywhere * Use `ethAddr` (declared in `Stores`) to denote Ethereum (non-ERC20) * Use `address(this)` instead of `msg.sender` for fetching balance on-chain, etc -* Only `approve()` (Wrapper function to be used is declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. +* Only `approve()` (declared in `Basic`) limited amount while giving ERC20 allowance, which strictly needs to be 0 by the end of the spell. * User interacting functions should have natspec comments(@dev, @notice, @param). * Use `getUint()` (declared in `Stores`) for getting value that saved from previous spell * Use `setUint()` (declared in `Stores`) for setting value to save for the future spell From 2da9eb49017e5d53d2486cbb984946341d7878dd Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Fri, 27 Aug 2021 17:12:17 +0530 Subject: [PATCH 31/38] Update main.sol --- contracts/mainnet/connectors/instapool_v2/main.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/mainnet/connectors/instapool_v2/main.sol b/contracts/mainnet/connectors/instapool_v2/main.sol index 7c436aa0..f97af8b3 100644 --- a/contracts/mainnet/connectors/instapool_v2/main.sol +++ b/contracts/mainnet/connectors/instapool_v2/main.sol @@ -23,6 +23,7 @@ contract LiquidityResolver is DSMath, Stores, Variables, Events { * @dev Borrow Flashloan and Cast spells. * @param token Token Address. * @param amt Token Amount. + * @param route Flashloan source route. (0: dYdX(ETH,DAI,USDC only), 1: MakerDAO(DAI only), 2: Compound(All borrowable tokens in Compound), 3: AaveV2(All borrowable tokens in AaveV2)) * @param data targets & data for cast. */ function flashBorrowAndCast( @@ -74,4 +75,4 @@ contract LiquidityResolver is DSMath, Stores, Variables, Events { contract ConnectV2InstaPool is LiquidityResolver { string public name = "Instapool-v1.1"; -} \ No newline at end of file +} From cce38fec6d8bd054ea11f1415d57f6d4316b4338 Mon Sep 17 00:00:00 2001 From: Thrilok kumar Date: Sun, 29 Aug 2021 23:03:05 +0530 Subject: [PATCH 32/38] Added new connectors Connector Name: "B-COMPOUND-A" Connector Address: 0xa3EeFDc2de9DFA59968bEcff3E15b53E6162460f Connector Name: "B-MAKERDAO-A" Connector Address: 0xB0A1f10FeEfECf25064CE7cdF0a65042F7dE7bF0 Connector Name: "B-LIQUITY-A" Connector Address: 0x19574E5Dfb40bbD63A4F3bdcF27ed662b329b2ff Connector Name: "UNISWAP-V3-A" Connector Address: 0x25B0c76dE86C3457b9B8b9ee3775F5a7b8D4c475 --- docs/connectors.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/connectors.json b/docs/connectors.json index 28c96123..75db30dc 100644 --- a/docs/connectors.json +++ b/docs/connectors.json @@ -25,7 +25,11 @@ "REFINANCE-A": "0x6f22931423e8ffC8d51f6E5aF73118fC64b27856", "INST-A": "0x52C2C4a0db049255fF345EB9D3Fb1f555b7a924A", "REFLEXER-A": "0xaC6dc28a6251F49Bbe5755E630107Dccde9ae2C8", - "LIQUITY-A": "0x3643bA40B8e2bd8F77233BDB6abe38c218f31bFe" + "LIQUITY-A": "0x3643bA40B8e2bd8F77233BDB6abe38c218f31bFe", + "UNISWAP-V3-A": "0x25B0c76dE86C3457b9B8b9ee3775F5a7b8D4c475", + "B-COMPOUND-A": "0xa3EeFDc2de9DFA59968bEcff3E15b53E6162460f", + "B-MAKERDAO-A": "0xB0A1f10FeEfECf25064CE7cdF0a65042F7dE7bF0", + "B-LIQUITY-A": "0x19574E5Dfb40bbD63A4F3bdcF27ed662b329b2ff" }, "137" : { "1INCH-A": "0xC0d9210496afE9763F5d8cEb8deFfBa817232A9e", From 7d45c6ad8fc2ae256bfcde30b9e1eb6f0d1f7e99 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Thu, 2 Sep 2021 13:00:48 +0530 Subject: [PATCH 33/38] Updated pr status check gh action config --- .github/workflows/status.yml | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index 9dd6986c..0470aa1e 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -9,18 +9,24 @@ jobs: matrix: node-version: [16.x] steps: - - uses: actions/checkout@v1 - with: - # Checkout the head ref instead of the PR branch that github creates. - ref: ${{ github.head_ref }} - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: Install and build - run: | - npm install - - name: Run status checks - run: node ./status-checks - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v2 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Use Cache + uses: actions/cache@v2 + with: + path: | + node_modules + */*/node_modules + key: ${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('**/package-lock.json') }} + - name: Install and build + run: | + npm install + - name: Run status checks + run: node ./status-checks + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 0da788cdb2f3d8ab8c4af2ab66fbe58b3a542673 Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Thu, 2 Sep 2021 22:56:29 +0530 Subject: [PATCH 34/38] auto check pr gh action: Add output of status checks as a comment in the thread --- .github/workflows/status.yml | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index 0470aa1e..fc6ede0a 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -27,6 +27,22 @@ jobs: run: | npm install - name: Run status checks - run: node ./status-checks + id: status_check + run: | + output=$(node ./status-checks) + # Escape newlines so _all_ the output is included in the set-output + output="${output//'%'/'%25'}" + output="${output//$'\n'/'%0A'}" + output="${output//$'\r'/'%0D'}" + echo "::set-output name=status_check_output::$output" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Auto Comment Status Check Result + # Use with caution + uses: bubkoo/auto-comment@v1 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + pullRequestSynchronize: "${{ steps.status_check.outputs.output }}" + pullRequestAssigned: "${{ steps.status_check.outputs.output }}" + pullRequestOpened: "${{ steps.status_check.outputs.output }}" + pullRequestReopened: "${{ steps.status_check.outputs.output }}" From cf504594be9a99e628dd1ba6a7ae8cae46830e9f Mon Sep 17 00:00:00 2001 From: Ishan Jain Date: Thu, 2 Sep 2021 23:31:58 +0530 Subject: [PATCH 35/38] Updated pull request check gh action --- .github/workflows/status.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/status.yml b/.github/workflows/status.yml index fc6ede0a..2e72f099 100644 --- a/.github/workflows/status.yml +++ b/.github/workflows/status.yml @@ -42,7 +42,7 @@ jobs: uses: bubkoo/auto-comment@v1 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - pullRequestSynchronize: "${{ steps.status_check.outputs.output }}" - pullRequestAssigned: "${{ steps.status_check.outputs.output }}" - pullRequestOpened: "${{ steps.status_check.outputs.output }}" - pullRequestReopened: "${{ steps.status_check.outputs.output }}" + pullRequestSynchronize: "${{ steps.status_check.outputs.status_check_output }}" + pullRequestAssigned: "${{ steps.status_check.outputs.status_check_output }}" + pullRequestOpened: "${{ steps.status_check.outputs.status_check_output }}" + pullRequestReopened: "${{ steps.status_check.outputs.status_check_output }}" From 3c800b82accee88a1888107b8c60c96107270651 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Tue, 7 Sep 2021 23:48:07 +0530 Subject: [PATCH 36/38] restructured uniswap folders --- contracts/mainnet/connectors/uniswap/{ => v2}/events.sol | 0 contracts/mainnet/connectors/uniswap/{ => v2}/helpers.sol | 0 contracts/mainnet/connectors/uniswap/{ => v2}/interface.sol | 0 contracts/mainnet/connectors/uniswap/{ => v2}/main.sol | 0 contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/events.sol | 0 .../mainnet/connectors/{uniswapV3 => uniswap/v3}/helpers.sol | 0 .../mainnet/connectors/{uniswapV3 => uniswap/v3}/interface.sol | 0 contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/main.sol | 0 .../connectors/{uniswapStaker => uniswap/v3_staker}/events.sol | 0 .../connectors/{uniswapStaker => uniswap/v3_staker}/helpers.sol | 0 .../connectors/{uniswapStaker => uniswap/v3_staker}/interface.sol | 0 .../connectors/{uniswapStaker => uniswap/v3_staker}/main.sol | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename contracts/mainnet/connectors/uniswap/{ => v2}/events.sol (100%) rename contracts/mainnet/connectors/uniswap/{ => v2}/helpers.sol (100%) rename contracts/mainnet/connectors/uniswap/{ => v2}/interface.sol (100%) rename contracts/mainnet/connectors/uniswap/{ => v2}/main.sol (100%) rename contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/events.sol (100%) rename contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/helpers.sol (100%) rename contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/interface.sol (100%) rename contracts/mainnet/connectors/{uniswapV3 => uniswap/v3}/main.sol (100%) rename contracts/mainnet/connectors/{uniswapStaker => uniswap/v3_staker}/events.sol (100%) rename contracts/mainnet/connectors/{uniswapStaker => uniswap/v3_staker}/helpers.sol (100%) rename contracts/mainnet/connectors/{uniswapStaker => uniswap/v3_staker}/interface.sol (100%) rename contracts/mainnet/connectors/{uniswapStaker => uniswap/v3_staker}/main.sol (100%) diff --git a/contracts/mainnet/connectors/uniswap/events.sol b/contracts/mainnet/connectors/uniswap/v2/events.sol similarity index 100% rename from contracts/mainnet/connectors/uniswap/events.sol rename to contracts/mainnet/connectors/uniswap/v2/events.sol diff --git a/contracts/mainnet/connectors/uniswap/helpers.sol b/contracts/mainnet/connectors/uniswap/v2/helpers.sol similarity index 100% rename from contracts/mainnet/connectors/uniswap/helpers.sol rename to contracts/mainnet/connectors/uniswap/v2/helpers.sol diff --git a/contracts/mainnet/connectors/uniswap/interface.sol b/contracts/mainnet/connectors/uniswap/v2/interface.sol similarity index 100% rename from contracts/mainnet/connectors/uniswap/interface.sol rename to contracts/mainnet/connectors/uniswap/v2/interface.sol diff --git a/contracts/mainnet/connectors/uniswap/main.sol b/contracts/mainnet/connectors/uniswap/v2/main.sol similarity index 100% rename from contracts/mainnet/connectors/uniswap/main.sol rename to contracts/mainnet/connectors/uniswap/v2/main.sol diff --git a/contracts/mainnet/connectors/uniswapV3/events.sol b/contracts/mainnet/connectors/uniswap/v3/events.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapV3/events.sol rename to contracts/mainnet/connectors/uniswap/v3/events.sol diff --git a/contracts/mainnet/connectors/uniswapV3/helpers.sol b/contracts/mainnet/connectors/uniswap/v3/helpers.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapV3/helpers.sol rename to contracts/mainnet/connectors/uniswap/v3/helpers.sol diff --git a/contracts/mainnet/connectors/uniswapV3/interface.sol b/contracts/mainnet/connectors/uniswap/v3/interface.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapV3/interface.sol rename to contracts/mainnet/connectors/uniswap/v3/interface.sol diff --git a/contracts/mainnet/connectors/uniswapV3/main.sol b/contracts/mainnet/connectors/uniswap/v3/main.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapV3/main.sol rename to contracts/mainnet/connectors/uniswap/v3/main.sol diff --git a/contracts/mainnet/connectors/uniswapStaker/events.sol b/contracts/mainnet/connectors/uniswap/v3_staker/events.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapStaker/events.sol rename to contracts/mainnet/connectors/uniswap/v3_staker/events.sol diff --git a/contracts/mainnet/connectors/uniswapStaker/helpers.sol b/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapStaker/helpers.sol rename to contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol diff --git a/contracts/mainnet/connectors/uniswapStaker/interface.sol b/contracts/mainnet/connectors/uniswap/v3_staker/interface.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapStaker/interface.sol rename to contracts/mainnet/connectors/uniswap/v3_staker/interface.sol diff --git a/contracts/mainnet/connectors/uniswapStaker/main.sol b/contracts/mainnet/connectors/uniswap/v3_staker/main.sol similarity index 100% rename from contracts/mainnet/connectors/uniswapStaker/main.sol rename to contracts/mainnet/connectors/uniswap/v3_staker/main.sol From 73969113c5a67d4bac2260354df5b7dfcc08bd48 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Tue, 7 Sep 2021 23:50:58 +0530 Subject: [PATCH 37/38] minor fixes --- contracts/mainnet/connectors/uniswap/v2/helpers.sol | 6 +++--- contracts/mainnet/connectors/uniswap/v2/main.sol | 2 +- contracts/mainnet/connectors/uniswap/v3/helpers.sol | 6 +++--- contracts/mainnet/connectors/uniswap/v3/main.sol | 2 +- contracts/mainnet/connectors/uniswap/v3_staker/events.sol | 1 + contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol | 6 +++--- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/contracts/mainnet/connectors/uniswap/v2/helpers.sol b/contracts/mainnet/connectors/uniswap/v2/helpers.sol index f435a78b..f0a8a6da 100644 --- a/contracts/mainnet/connectors/uniswap/v2/helpers.sol +++ b/contracts/mainnet/connectors/uniswap/v2/helpers.sol @@ -1,8 +1,8 @@ pragma solidity ^0.7.0; -import { TokenInterface } from "../../common/interfaces.sol"; -import { DSMath } from "../../common/math.sol"; -import { Basic } from "../../common/basic.sol"; +import { TokenInterface } from "../../../common/interfaces.sol"; +import { DSMath } from "../../../common/math.sol"; +import { Basic } from "../../../common/basic.sol"; import { IUniswapV2Router02, IUniswapV2Factory } from "./interface.sol"; abstract contract Helpers is DSMath, Basic { diff --git a/contracts/mainnet/connectors/uniswap/v2/main.sol b/contracts/mainnet/connectors/uniswap/v2/main.sol index a8ee9959..e0daa6a9 100644 --- a/contracts/mainnet/connectors/uniswap/v2/main.sol +++ b/contracts/mainnet/connectors/uniswap/v2/main.sol @@ -5,7 +5,7 @@ pragma solidity ^0.7.0; * @dev Decentralized Exchange. */ -import { TokenInterface } from "../../common/interfaces.sol"; +import { TokenInterface } from "../../../common/interfaces.sol"; import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; diff --git a/contracts/mainnet/connectors/uniswap/v3/helpers.sol b/contracts/mainnet/connectors/uniswap/v3/helpers.sol index 8585f84f..2fc42f8b 100644 --- a/contracts/mainnet/connectors/uniswap/v3/helpers.sol +++ b/contracts/mainnet/connectors/uniswap/v3/helpers.sol @@ -1,9 +1,9 @@ pragma solidity ^0.7.6; pragma abicoder v2; -import {TokenInterface} from "../../common/interfaces.sol"; -import {DSMath} from "../../common/math.sol"; -import {Basic} from "../../common/basic.sol"; +import {TokenInterface} from "../../../common/interfaces.sol"; +import {DSMath} from "../../../common/math.sol"; +import {Basic} from "../../../common/basic.sol"; import "./interface.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@uniswap/v3-core/contracts/libraries/TickMath.sol"; diff --git a/contracts/mainnet/connectors/uniswap/v3/main.sol b/contracts/mainnet/connectors/uniswap/v3/main.sol index 7fd058a6..c40f871f 100644 --- a/contracts/mainnet/connectors/uniswap/v3/main.sol +++ b/contracts/mainnet/connectors/uniswap/v3/main.sol @@ -6,7 +6,7 @@ pragma abicoder v2; * @dev Decentralized Exchange. */ -import {TokenInterface} from "../../common/interfaces.sol"; +import {TokenInterface} from "../../../common/interfaces.sol"; import {Helpers} from "./helpers.sol"; import {Events} from "./events.sol"; diff --git a/contracts/mainnet/connectors/uniswap/v3_staker/events.sol b/contracts/mainnet/connectors/uniswap/v3_staker/events.sol index 0406b33c..1582d7d2 100644 --- a/contracts/mainnet/connectors/uniswap/v3_staker/events.sol +++ b/contracts/mainnet/connectors/uniswap/v3_staker/events.sol @@ -19,6 +19,7 @@ contract Events { event LogIncentiveCreated( address poolAddr, + address refundee, uint256 startTime, uint256 endTime, uint256 reward diff --git a/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol b/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol index 71926302..f6ff4e16 100644 --- a/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol +++ b/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol @@ -1,9 +1,9 @@ pragma solidity ^0.7.6; pragma abicoder v2; -import {TokenInterface} from "../../common/interfaces.sol"; -import {DSMath} from "../../common/math.sol"; -import {Basic} from "../../common/basic.sol"; +import {TokenInterface} from "../../../common/interfaces.sol"; +import {DSMath} from "../../../common/math.sol"; +import {Basic} from "../../../common/basic.sol"; import "./interface.sol"; import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol"; import "@uniswap/v3-core/contracts/libraries/TickMath.sol"; From e62e0cfea84be9d908d274faba8041dbab5bd1b9 Mon Sep 17 00:00:00 2001 From: Thrilok Kumar Date: Wed, 8 Sep 2021 00:00:48 +0530 Subject: [PATCH 38/38] Minor changes --- .../connectors/uniswap/v3_staker/events.sol | 10 +++--- .../connectors/uniswap/v3_staker/helpers.sol | 36 ------------------- .../connectors/uniswap/v3_staker/main.sol | 35 +++++++++--------- 3 files changed, 21 insertions(+), 60 deletions(-) diff --git a/contracts/mainnet/connectors/uniswap/v3_staker/events.sol b/contracts/mainnet/connectors/uniswap/v3_staker/events.sol index 1582d7d2..fa8bbebf 100644 --- a/contracts/mainnet/connectors/uniswap/v3_staker/events.sol +++ b/contracts/mainnet/connectors/uniswap/v3_staker/events.sol @@ -3,21 +3,21 @@ pragma solidity ^0.7.0; contract Events { event LogDeposit(uint256 tokenId); - event LogWithdraw(uint256 indexed tokenId, address to); + event LogWithdraw(uint256 indexed tokenId); event LogDepositTransfer(uint256 indexed tokenId, address to); - event LogStake(uint256 tokenId, address refundee); + event LogStake(uint256 indexed tokenId, bytes32 incentiveId); - event LogUnstake(uint256 tokenId, bytes32 incentiveId); + event LogUnstake(uint256 indexed tokenId, bytes32 incentiveId); event LogRewardClaimed( - address rewardToken, - address receiver, + address indexed rewardToken, uint256 amount ); event LogIncentiveCreated( + bytes32 incentiveId, address poolAddr, address refundee, uint256 startTime, diff --git a/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol b/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol index f6ff4e16..258d0961 100644 --- a/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol +++ b/contracts/mainnet/connectors/uniswap/v3_staker/helpers.sol @@ -32,42 +32,6 @@ abstract contract Helpers is DSMath, Basic { tokenId = nftManager.tokenOfOwnerByIndex(user, len - 1); } - function getMinAmount( - TokenInterface token, - uint256 amt, - uint256 slippage - ) internal view returns (uint256 minAmt) { - uint256 _amt18 = convertTo18(token.decimals(), amt); - minAmt = wmul(_amt18, sub(WAD, slippage)); - minAmt = convert18ToDec(token.decimals(), minAmt); - } - - function getNftTokenPairAddresses(uint256 _tokenId) - internal - view - returns (address token0, address token1) - { - (bool success, bytes memory data) = address(nftManager).staticcall( - abi.encodeWithSelector(nftManager.positions.selector, _tokenId) - ); - require(success, "fetching positions failed"); - { - (, , token0, token1, , , , ) = abi.decode( - data, - ( - uint96, - address, - address, - address, - uint24, - int24, - int24, - uint128 - ) - ); - } - } - function getPoolAddress(uint256 _tokenId) internal view diff --git a/contracts/mainnet/connectors/uniswap/v3_staker/main.sol b/contracts/mainnet/connectors/uniswap/v3_staker/main.sol index e65f44d9..2da11c59 100644 --- a/contracts/mainnet/connectors/uniswap/v3_staker/main.sol +++ b/contracts/mainnet/connectors/uniswap/v3_staker/main.sol @@ -6,7 +6,7 @@ pragma abicoder v2; * @dev Decentralized Exchange. */ -import {TokenInterface} from "../../common/interfaces.sol"; +import {TokenInterface} from "../../../common/interfaces.sol"; import "./interface.sol"; import {Helpers} from "./helpers.sol"; import {Events} from "./events.sol"; @@ -56,18 +56,17 @@ abstract contract UniswapResolver is Helpers, Events { * @dev Withdraw NFT LP token * @notice Withdraw NFT LP token from staking pool * @param _tokenId NFT LP Token ID - * @param _to address to transfer */ - function withdraw(uint256 _tokenId, address _to) + function withdraw(uint256 _tokenId) external payable returns (string memory _eventName, bytes memory _eventParam) { if (_tokenId == 0) _tokenId = _getLastNftId(address(this)); - staker.withdrawToken(_tokenId, _to, ""); + staker.withdrawToken(_tokenId, address(this), ""); - _eventName = "LogWithdraw(uint256,address)"; - _eventParam = abi.encode(_tokenId, _to); + _eventName = "LogWithdraw(uint256)"; + _eventParam = abi.encode(_tokenId); } /** @@ -104,8 +103,8 @@ abstract contract UniswapResolver is Helpers, Events { ); _stake(_tokenId, _key); - _eventName = "LogStake(uint256,address)"; - _eventParam = abi.encode(_tokenId, _refundee); + _eventName = "LogStake(uint256,bytes32)"; + _eventParam = abi.encode(_tokenId, keccak256(abi.encode(_key))); } /** @@ -142,20 +141,18 @@ abstract contract UniswapResolver is Helpers, Events { ); _unstake(_key, _tokenId); _eventName = "LogUnstake(uint256,bytes32)"; - _eventParam = abi.encode(_tokenId, _key); + _eventParam = abi.encode(_tokenId, keccak256(abi.encode(_key))); } /** * @dev Claim rewards * @notice Claim rewards * @param _rewardToken _rewardToken address - * @param _to address to receive - * @param _amountRequested requested amount + * @param _amount requested amount */ function claimRewards( address _rewardToken, - address _to, - uint256 _amountRequested + uint256 _amount ) external payable @@ -163,12 +160,12 @@ abstract contract UniswapResolver is Helpers, Events { { uint256 rewards = _claimRewards( IERC20Minimal(_rewardToken), - _to, - _amountRequested + address(this), + _amount ); - _eventName = "LogRewardClaimed(address,address,uint256)"; - _eventParam = abi.encode(_rewardToken, _to, rewards); + _eventName = "LogRewardClaimed(address,uint256)"; + _eventParam = abi.encode(_rewardToken, rewards); } /** @@ -207,8 +204,8 @@ abstract contract UniswapResolver is Helpers, Events { } staker.createIncentive(_key, _reward); - _eventName = "LogIncentiveCreated(address,uint256,uint256,uint256)"; - _eventParam = abi.encode(_poolAddr, _startTime, _endTime, _reward); + _eventName = "LogIncentiveCreated(bytes32,address,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(keccak256(abi.encode(_key)), _poolAddr, _refundee, _startTime, _endTime, _reward); } }