From 541a10970c292a8887a23ae070fabe2106df715e Mon Sep 17 00:00:00 2001 From: Kendrick Tan Date: Sun, 5 Apr 2020 08:48:03 +1000 Subject: [PATCH] fixed supply bug --- .../frontend/features/position/SupplyCoin.tsx | 188 +++++++++++++----- packages/scripts/supply.ts | 115 +++++++++++ .../artifacts/DedgeCompoundManager.json | 4 +- .../artifacts/DeployedAddresses.json | 2 +- .../src/lib/compound/CompoundBase.sol | 41 ++-- 5 files changed, 278 insertions(+), 72 deletions(-) create mode 100644 packages/scripts/supply.ts diff --git a/packages/frontend/features/position/SupplyCoin.tsx b/packages/frontend/features/position/SupplyCoin.tsx index 299aa14..7ebaa9d 100644 --- a/packages/frontend/features/position/SupplyCoin.tsx +++ b/packages/frontend/features/position/SupplyCoin.tsx @@ -1,73 +1,163 @@ +import { dedgeHelpers } from "../../../smart-contracts/dist/helpers"; import { ethers } from "ethers"; +import { legos } from "money-legos/dist"; import { Button, Loader, Box, Flex, Field, Input } from "rimble-ui"; import CompoundPositions from "../../containers/CompoundPositions"; import ContractsContainer from "../../containers/Contracts"; +import ConnectionContainer from "../../containers/Connection"; import DACProxyContainer from "../../containers/DACProxy"; -import { useState } from "react"; - -import { dedgeHelpers } from "../../../smart-contracts/dist/helpers"; +import { useState, useEffect } from "react"; const SupplyCoin = ({ coin }) => { const { getBalances } = CompoundPositions.useContainer(); const { contracts } = ContractsContainer.useContainer(); - const { proxy } = DACProxyContainer.useContainer(); + const { signer, address } = ConnectionContainer.useContainer(); + const { hasProxy, proxy, proxyAddress } = DACProxyContainer.useContainer(); const [loading, setLoading] = useState(false); const [amount, setAmount] = useState(""); + const [transferLoading, setTransferLoading] = useState(false); + const [canTransfer, setCanTransfer] = useState(null); + + const getCanTransfer = async () => { + if (coin.symbol === "ETH") { + setCanTransfer(true); + return; + } + + const tokenContract = new ethers.Contract( + coin.address, + legos.erc20.abi, + signer + ); + + const allowance = await tokenContract.allowance(address, proxyAddress); + + if (allowance.toString() === "0") { + setCanTransfer(false); + return; + } + + setCanTransfer(true); + }; + + useEffect(() => { + if (hasProxy) { + getCanTransfer(); + } + }, [proxy]); + return ( {/* Supply {coin.symbol} */} - - setAmount(e.target.value.toString())} - /> + + {canTransfer === false || canTransfer === null ? ( + + ) : ( + setAmount(e.target.value.toString())} + /> + )} - + {canTransfer === false || canTransfer === null ? ( + + ) : ( + + )} ); }; diff --git a/packages/scripts/supply.ts b/packages/scripts/supply.ts new file mode 100644 index 0000000..14a1115 --- /dev/null +++ b/packages/scripts/supply.ts @@ -0,0 +1,115 @@ +import { getLegos, networkIds } from "money-legos"; +import { + wallet, + newERC20Contract, + getTokenFromUniswapAndApproveProxyTransfer, +} from "dedge-smart-contracts/test/common"; +import { dedgeHelpers } from "dedge-smart-contracts/helpers"; +import { ethers } from "ethers"; + +import { + dacProxyFactoryAddress, + dedgeCompoundManagerAddress, +} from "dedge-smart-contracts/build/DeployedAddresses.json"; + +import dacProxyDef from "dedge-smart-contracts/build/DACProxy.json"; +import dacProxyFactoryDef from "dedge-smart-contracts/build/DACProxyFactory.json"; + +const legos = getLegos(networkIds.mainnet); +const erc20Tokens = Object.keys(legos.erc20).filter((x) => x !== "abi"); +const cTokens = Object.keys(legos.compound).filter( + (x) => x !== "cTokenAbi" && x !== "comptroller" && x[0] === "c" +); + +if (process.argv.length !== 5) { + console.log( + `ts-node supply.ts [${erc20Tokens.join("|")}] [${cTokens.join( + "|" + )}]` + ); + process.exit(1); +} + +if (!erc20Tokens.includes(process.argv[2])) { + console.log( + `ts-node supply.ts ${erc20Tokens.join("|")}] [${cTokens.join( + "|" + )}]` + ); + process.exit(1); +} + +if (!cTokens.includes(process.argv[4])) { + console.log( + `ts-node supply.ts ${erc20Tokens.join("|")}] [${cTokens.join( + "|" + )}]` + ); + process.exit(1); +} + +const token = process.argv[2]; +const ctoken = process.argv[4]; +const amount = process.argv[3]; +const tokenAddress = legos.erc20[token].address; +const cTokenEquilavent = legos.compound[ctoken].address; + +const dacProxyFactoryContract = new ethers.Contract( + dacProxyFactoryAddress, + dacProxyFactoryDef.abi, + wallet +); + +const main = async () => { + console.log("Supplying...."); + let dacProxyAddress = await dacProxyFactoryContract.proxies(wallet.address); + if (dacProxyAddress === "0x0000000000000000000000000000000000000000") { + const cTokensToEnter = [ + legos.compound.cEther.address, + legos.compound.cSAI.address, + legos.compound.cDAI.address, + legos.compound.cREP.address, + legos.compound.cUSDC.address, + legos.compound.cBAT.address, + legos.compound.cZRX.address, + legos.compound.cWBTC.address, + ]; + + console.log("Creating proxy address and entering market...."); + await dedgeHelpers.proxyFactory.buildAndEnterMarkets( + dacProxyFactoryContract, + dedgeCompoundManagerAddress, + cTokensToEnter + ); + dacProxyAddress = await dacProxyFactoryContract.proxies(wallet.address); + } + const dacProxyContract = new ethers.Contract( + dacProxyAddress, + dacProxyDef.abi, + wallet + ); + console.log("Getting tokens from uniswap"); + await getTokenFromUniswapAndApproveProxyTransfer( + dacProxyAddress, + tokenAddress, + 1 + ); + const amountWei = ethers.utils.parseUnits(amount, token === "usdc" ? 6 : 18); + console.log("Approving erc20 transferFrom...."); + await newERC20Contract(tokenAddress).approve( + dacProxyAddress, + amountWei.toString(), + { + gasLimit: 4000000, + } + ); + console.log("supplying..."); + await dedgeHelpers.compound.supplyThroughProxy( + dacProxyContract, + dedgeCompoundManagerAddress, + cTokenEquilavent, + amountWei.toString() + ); +}; + +main(); diff --git a/packages/smart-contracts/artifacts/DedgeCompoundManager.json b/packages/smart-contracts/artifacts/DedgeCompoundManager.json index 5238c65..59ef529 100644 --- a/packages/smart-contracts/artifacts/DedgeCompoundManager.json +++ b/packages/smart-contracts/artifacts/DedgeCompoundManager.json @@ -20401,8 +20401,8 @@ "1": { "events": {}, "links": {}, - "address": "0x16493dfB0281bA27C8B712f6Eb8eC32bcc50EAEc", - "transactionHash": "0x98046a27999965dfff9390719dec08d335b3f480fafa14249a17956afb392b36" + "address": "0xd219e1cad8cde8c46f2d923ace35a8e5b729a683", + "transactionHash": "0xfcdabce2ffc0b4b892e7338140eff3da4e6575bdfd2e8375f7064434767cedd4" } }, "schemaVersion": "3.0.23", diff --git a/packages/smart-contracts/artifacts/DeployedAddresses.json b/packages/smart-contracts/artifacts/DeployedAddresses.json index cb10b4f..4c81ceb 100644 --- a/packages/smart-contracts/artifacts/DeployedAddresses.json +++ b/packages/smart-contracts/artifacts/DeployedAddresses.json @@ -1,6 +1,6 @@ { "dacProxyFactoryAddress": "0x572bfabaeb0f7F5d65EEa04D85595010756Ba986", - "dedgeCompoundManagerAddress": "0x16493dfB0281bA27C8B712f6Eb8eC32bcc50EAEc", + "dedgeCompoundManagerAddress": "0xd219e1cad8cde8c46f2d923ace35a8e5b729a683", "dedgeMakerManagerAddress": "0x1C9c3ED6De13F423a4457aCCfa4e09bc436D5e89", "dedgeExitManagerAddress": "0x81BFDCF729B5cAC3c4f1F906b63F26E5865b615B", "dedgeGeneralManagerAddress": "0x40b4C8B5EE1FDd5259E40907E257f11819681b3d", diff --git a/packages/smart-contracts/src/lib/compound/CompoundBase.sol b/packages/smart-contracts/src/lib/compound/CompoundBase.sol index f5044ab..7a4df1f 100644 --- a/packages/smart-contracts/src/lib/compound/CompoundBase.sol +++ b/packages/smart-contracts/src/lib/compound/CompoundBase.sol @@ -20,7 +20,7 @@ contract CompoundBase { return c; } - function _transferFrom( + function _transferFromUnderlying( address sender, address recipient, address cToken, @@ -29,11 +29,11 @@ contract CompoundBase { address underlying = ICToken(cToken).underlying(); require( IERC20(underlying).transferFrom(sender, recipient, amount), - "cmpnd-mgr-transfer-from-failed" + "cmpnd-mgr-transferFrom-underlying-failed" ); } - function _transfer( + function _transferUnderlying( address cToken, address recipient, uint amount @@ -43,11 +43,22 @@ contract CompoundBase { } else { require( IERC20(ICToken(cToken).underlying()).transfer(recipient, amount), - "cmpnd-mgr-transfer-failed" + "cmpnd-mgr-transfer-underlying-failed" ); } } + function _transfer( + address token, + address recipient, + uint amount + ) internal { + require( + IERC20(token).transfer(recipient, amount), + "cmpnd-mgr-transfer-failed" + ); + } + function enterMarkets( address[] memory cTokens // Address of the Compound derivation token (e.g. cDAI) ) public { @@ -166,39 +177,29 @@ contract CompoundBase { address cToken, uint amount ) public payable { - // Gets initial CToken balance - uint initialBal = ICToken(cToken).balanceOf(address(this)); - - // If cToken isn't an ether address, we need to transferFrom - // If this fails, users needs to execute `approve(spender, amount)` to this proxy if (cToken != CEtherAddress) { - _transferFrom(msg.sender, address(this), cToken, amount); + _transferFromUnderlying(msg.sender, address(this), cToken, amount); } supply(cToken, amount); - - // Sends CToken back to user - uint finalBal = ICToken(cToken).balanceOf(address(this)); - - _transfer(cToken, msg.sender, sub(finalBal, initialBal)); } function repayBorrowThroughProxy(address cToken, uint amount) public payable { if (cToken != CEtherAddress) { - _transferFrom(msg.sender, address(this), cToken, amount); + _transferFromUnderlying(msg.sender, address(this), cToken, amount); } repayBorrow(cToken, amount); } function repayBorrowBehalfThroughProxy(address recipient, address cToken, uint amount) public payable { if (cToken != CEtherAddress) { - _transferFrom(msg.sender, address(this), cToken, amount); + _transferFromUnderlying(msg.sender, address(this), cToken, amount); } repayBorrowBehalf(recipient, cToken, amount); } function borrowThroughProxy(address cToken, uint amount) public { borrow(cToken, amount); - _transfer(cToken, msg.sender, amount); + _transferUnderlying(cToken, msg.sender, amount); } function redeemThroughProxy( @@ -206,7 +207,7 @@ contract CompoundBase { uint amount ) public payable { redeem(cToken, amount); - _transfer(cToken, msg.sender, amount); + _transferUnderlying(cToken, msg.sender, amount); } function redeemUnderlyingThroughProxy( @@ -214,6 +215,6 @@ contract CompoundBase { uint amount ) public payable { redeemUnderlying(cToken, amount); - _transfer(cToken, msg.sender, amount); + _transferUnderlying(cToken, msg.sender, amount); } }