From aee0690cfdd475dbe71fdd058f1e725c4924d69b Mon Sep 17 00:00:00 2001 From: Mubaris NK Date: Tue, 16 Mar 2021 21:55:39 +0530 Subject: [PATCH] Add compound mapping and update --- contracts/connectors/compound/events.sol | 41 ++++++++- contracts/connectors/compound/helpers.sol | 7 +- contracts/connectors/compound/interface.sol | 13 +++ contracts/connectors/compound/main.sol | 93 +++++++++++---------- contracts/mapping/compound.sol | 79 +++++++++++++++++ 5 files changed, 184 insertions(+), 49 deletions(-) create mode 100644 contracts/mapping/compound.sol diff --git a/contracts/connectors/compound/events.sol b/contracts/connectors/compound/events.sol index 9a0602f3..7d5ac529 100644 --- a/contracts/connectors/compound/events.sol +++ b/contracts/connectors/compound/events.sol @@ -1,13 +1,45 @@ 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 LogDeposit( + address indexed token, + string tokenId, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogWithdraw( + address indexed token, + string tokenId, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogBorrow( + address indexed token, + string tokenId, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); + + event LogPayback( + address indexed token, + string tokenId, + address cToken, + uint256 tokenAmt, + uint256 getId, + uint256 setId + ); event LogDepositCToken( address indexed token, + string tokenId, address cToken, uint256 tokenAmt, uint256 cTokenAmt, @@ -17,6 +49,7 @@ contract Events { event LogWithdrawCToken( address indexed token, + string tokenId, address cToken, uint256 tokenAmt, uint256 cTokenAmt, diff --git a/contracts/connectors/compound/helpers.sol b/contracts/connectors/compound/helpers.sol index 747921b3..236feac8 100644 --- a/contracts/connectors/compound/helpers.sol +++ b/contracts/connectors/compound/helpers.sol @@ -2,7 +2,7 @@ pragma solidity ^0.7.0; import { DSMath } from "../../common/math.sol"; import { Basic } from "../../common/basic.sol"; -import { ComptrollerInterface } from "./interface.sol"; +import { ComptrollerInterface, CompoundMappingInterface } from "./interface.sol"; abstract contract Helpers is DSMath, Basic { /** @@ -10,6 +10,11 @@ abstract contract Helpers is DSMath, Basic { */ ComptrollerInterface internal constant troller = ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); + /** + * @dev Compound Mapping + */ + CompoundMappingInterface internal constant compMapping = CompoundMappingInterface(0xe81F70Cc7C0D46e12d70efc60607F16bbD617E88); // Update the address + /** * @dev enter compound market */ diff --git a/contracts/connectors/compound/interface.sol b/contracts/connectors/compound/interface.sol index 9605dc53..cb89a11c 100644 --- a/contracts/connectors/compound/interface.sol +++ b/contracts/connectors/compound/interface.sol @@ -29,3 +29,16 @@ interface ComptrollerInterface { 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); +} + +struct LiquidateData { + address borrower; + address tokenToPay; + string tokenPayId; + address tokenInReturn; + string tokenReturnId; + uint amt; +} \ No newline at end of file diff --git a/contracts/connectors/compound/main.sol b/contracts/connectors/compound/main.sol index e3db45be..d4bfb967 100644 --- a/contracts/connectors/compound/main.sol +++ b/contracts/connectors/compound/main.sol @@ -1,10 +1,11 @@ pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; 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"; +import { CETHInterface, CTokenInterface, LiquidateData } from "./interface.sol"; abstract contract CompoundResolver is Events, Helpers { /** @@ -16,12 +17,13 @@ abstract contract CompoundResolver is Events, Helpers { */ function deposit( address token, + string calldata tokenId, uint amt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _amt = getUint(getId, amt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); enterMarket(cToken); if (token == ethAddr) { _amt = _amt == uint(-1) ? address(this).balance : _amt; @@ -34,8 +36,8 @@ abstract contract CompoundResolver is Events, Helpers { } setUint(setId, _amt); - _eventName = "LogDeposit(address,address,uint256,uint256,uint256)"; - _eventParam = abi.encode(token, cToken, _amt, getId, setId); + _eventName = "LogDeposit(address,string,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, _amt, getId, setId); } /** @@ -47,12 +49,13 @@ abstract contract CompoundResolver is Events, Helpers { */ function withdraw( address token, + string calldata tokenId, uint amt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _amt = getUint(getId, amt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); CTokenInterface cTokenContract = CTokenInterface(cToken); if (_amt == uint(-1)) { TokenInterface tokenContract = TokenInterface(token); @@ -65,8 +68,8 @@ abstract contract CompoundResolver is Events, Helpers { } setUint(setId, _amt); - _eventName = "LogWithdraw(address,address,uint256,uint256,uint256)"; - _eventParam = abi.encode(token, cToken, _amt, getId, setId); + _eventName = "LogWithdraw(address,string,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, _amt, getId, setId); } /** @@ -78,18 +81,19 @@ abstract contract CompoundResolver is Events, Helpers { */ function borrow( address token, + string calldata tokenId, uint amt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _amt = getUint(getId, amt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); enterMarket(cToken); 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); + _eventName = "LogBorrow(address,string,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, _amt, getId, setId); } /** @@ -101,12 +105,13 @@ abstract contract CompoundResolver is Events, Helpers { */ function payback( address token, + string calldata tokenId, uint amt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _amt = getUint(getId, amt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); CTokenInterface cTokenContract = CTokenInterface(cToken); _amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(address(this)) : _amt; @@ -121,8 +126,8 @@ abstract contract CompoundResolver is Events, Helpers { } setUint(setId, _amt); - _eventName = "LogPayback(address,address,uint256,uint256,uint256)"; - _eventParam = abi.encode(token, cToken, _amt, getId, setId); + _eventName = "LogPayback(address,string,address,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, _amt, getId, setId); } /** @@ -134,12 +139,13 @@ abstract contract CompoundResolver is Events, Helpers { */ function depositCToken( address token, + string calldata tokenId, uint amt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _amt = getUint(getId, amt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); enterMarket(cToken); CTokenInterface ctokenContract = CTokenInterface(cToken); @@ -159,8 +165,8 @@ abstract contract CompoundResolver is Events, Helpers { uint _cAmt = finalBal - initialBal; setUint(setId, _cAmt); - _eventName = "LogDepositCToken(address,address,uint256,uint256,uint256,uint256)"; - _eventParam = abi.encode(token, cToken, _amt, _cAmt, getId, setId); + _eventName = "LogDepositCToken(address,string,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, _amt, _cAmt, getId, setId); } /** @@ -172,63 +178,62 @@ abstract contract CompoundResolver is Events, Helpers { */ function withdrawCToken( address token, + string calldata tokenId, uint cTokenAmt, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { uint _cAmt = getUint(getId, cTokenAmt); - address cToken = instaMapping.cTokenMapping(token); + address cToken = compMapping.cTokenMapping(tokenId); CTokenInterface cTokenContract = CTokenInterface(cToken); TokenInterface tokenContract = TokenInterface(token); _cAmt = _cAmt == uint(-1) ? cTokenContract.balanceOf(address(this)) : _cAmt; - 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; + 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); + } - uint withdrawAmt = sub(finalBal, initialBal); setUint(setId, withdrawAmt); - _eventName = "LogWithdrawCToken(address,address,uint256,uint256,uint256,uint256)"; - _eventParam = abi.encode(token, cToken, withdrawAmt, _cAmt, getId, setId); + _eventName = "LogWithdrawCToken(address,string,address,uint256,uint256,uint256,uint256)"; + _eventParam = abi.encode(token, tokenId, cToken, withdrawAmt, _cAmt, getId, setId); } /** * @dev Liquidate a position. - * @param borrower Borrower's Address. - * @param tokenToPay token address to pay for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) - * @param tokenInReturn token address to return for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) - * @param amt token amount to pay for liquidation. + * @param data Liquidation data * @param getId Get token amount at this ID from `InstaMemory` Contract. * @param setId Set token amount at this ID in `InstaMemory` Contract. */ function liquidate( - address borrower, - address tokenToPay, - address tokenInReturn, - uint amt, + LiquidateData calldata data, uint getId, uint setId ) external payable returns (string memory _eventName, bytes memory _eventParam) { - uint _amt = getUint(getId, amt); - address cTokenPay = instaMapping.cTokenMapping(tokenToPay); - address cTokenColl = instaMapping.cTokenMapping(tokenInReturn); + uint _amt = getUint(getId, data.amt); + address cTokenPay = compMapping.cTokenMapping(data.tokenPayId); + address cTokenColl = compMapping.cTokenMapping(data.tokenReturnId); CTokenInterface cTokenContract = CTokenInterface(cTokenPay); { - (,, uint shortfal) = troller.getAccountLiquidity(borrower); + (,, uint shortfal) = troller.getAccountLiquidity(data.borrower); require(shortfal != 0, "account-cannot-be-liquidated"); } - _amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(borrower) : _amt; - if (tokenToPay == ethAddr) { + _amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(data.borrower) : _amt; + if (data.tokenToPay == ethAddr) { require(address(this).balance >= _amt, "not-enought-eth"); - CETHInterface(cTokenPay).liquidateBorrow{value: _amt}(borrower, cTokenColl); + CETHInterface(cTokenPay).liquidateBorrow{value: _amt}(data.borrower, cTokenColl); } else { - TokenInterface tokenContract = TokenInterface(tokenToPay); + TokenInterface tokenContract = TokenInterface(data.tokenToPay); require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); tokenContract.approve(cTokenPay, _amt); - require(cTokenContract.liquidateBorrow(borrower, _amt, cTokenColl) == 0, "liquidate-failed"); + require(cTokenContract.liquidateBorrow(data.borrower, _amt, cTokenColl) == 0, "liquidate-failed"); } setUint(setId, _amt); @@ -236,8 +241,8 @@ abstract contract CompoundResolver is Events, Helpers { _eventName = "LogLiquidate(address,address,address,uint256,uint256,uint256,uint256)"; _eventParam = abi.encode( address(this), - tokenToPay, - tokenInReturn, + data.tokenToPay, + data.tokenInReturn, _amt, getId, setId @@ -245,6 +250,6 @@ abstract contract CompoundResolver is Events, Helpers { } } -contract ConnectCompound is CompoundResolver { - string public name = "Compound-v1.3"; +contract ConnectV2Compound is CompoundResolver { + string public name = "Compound-v1"; } diff --git a/contracts/mapping/compound.sol b/contracts/mapping/compound.sol new file mode 100644 index 00000000..86284b86 --- /dev/null +++ b/contracts/mapping/compound.sol @@ -0,0 +1,79 @@ +pragma solidity ^0.7.0; +pragma experimental ABIEncoderV2; + +interface IndexInterface { + function master() external view returns (address); +} + +interface ConnectorsInterface { + function chief(address) external view returns (bool); +} + +interface CTokenInterface { + function isCToken() external view returns (bool); +} + +abstract contract Helpers { + + event LogCTokensAdded(string[] names, address[] ctokens); + event LogCTokensUpdated(string[] names, address[] ctokens); + + ConnectorsInterface public immutable connectors; + + // InstaIndex Address. + IndexInterface public constant instaIndex = IndexInterface(0x2971AdFa57b20E5a416aE5a708A8655A9c74f723); + + mapping (string => address) public cTokenMapping; + + modifier isChief { + require(msg.sender == instaIndex.master() || connectors.chief(msg.sender), "not-an-chief"); + _; + } + + constructor(address _connectors) { + connectors = ConnectorsInterface(_connectors); + } + + function _addCtokenMapping(string[] memory _names, address[] memory _ctokens) internal { + require(_names.length == _ctokens.length, "addCtokenMapping: not same length"); + for (uint i = 0; i < _ctokens.length; i++) { + require(cTokenMapping[_names[i]] == address(0), "addCtokenMapping: mapping added already"); + require(_ctokens[i] != address(0), "addCtokenMapping: _ctokens address not vaild"); + require(CTokenInterface(_ctokens[i]).isCToken(), "addCtokenMapping: not a cToken"); + + cTokenMapping[_names[i]] = _ctokens[i]; + // emit LogCTokenAdded(_names[i], _ctokens[i]); + } + emit LogCTokensAdded(_names, _ctokens); + } + + function updateCtokenMapping(string[] calldata _names, address[] calldata _ctokens) external { + require(msg.sender == instaIndex.master(), "not-master"); + require(_names.length == _ctokens.length, "updateCtokenMapping: not same length"); + for (uint i = 0; i < _ctokens.length; i++) { + require(cTokenMapping[_names[i]] != address(0), "updateCtokenMapping: mapping does not exist"); + require(_ctokens[i] != address(0), "updateCtokenMapping: _ctokens address not vaild"); + require(CTokenInterface(_ctokens[i]).isCToken(), "updateCtokenMapping: not a cToken"); + + cTokenMapping[_names[i]] = _ctokens[i]; + } + emit LogCTokensUpdated(_names, _ctokens); + } + + function addCtokenMapping(string[] memory _names, address[] memory _ctokens) external isChief { + _addCtokenMapping(_names, _ctokens); + } + +} + +contract InstaMapping is Helpers { + string constant public name = "Compound-Mapping-v1"; + + constructor( + address _connectors, + string[] memory _ctokenNames, + address[] memory _ctokens + ) Helpers(_connectors) { + _addCtokenMapping(_ctokenNames, _ctokens); + } +} \ No newline at end of file