diff --git a/contracts/mainnet/connectors/compound/v2/events.sol b/contracts/mainnet/connectors/compound/v2/events.sol index 22542c39f..b79d007d1 100644 --- a/contracts/mainnet/connectors/compound/v2/events.sol +++ b/contracts/mainnet/connectors/compound/v2/events.sol @@ -26,6 +26,15 @@ contract Events { uint256 setId ); + event LogPaybackOnBehalf( + address indexed token, + address cToken, + uint256 tokenAmt, + address indexed borrower, + uint256 getId, + uint256 setId + ); + event LogPayback( address indexed token, address cToken, @@ -51,13 +60,4 @@ contract Events { 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/compound/v2/main.sol b/contracts/mainnet/connectors/compound/v2/main.sol index aea631eaf..f605d06cc 100644 --- a/contracts/mainnet/connectors/compound/v2/main.sol +++ b/contracts/mainnet/connectors/compound/v2/main.sol @@ -13,7 +13,7 @@ import { Helpers } from "./helpers.sol"; import { Events } from "./events.sol"; import { CETHInterface, CTokenInterface } from "./interface.sol"; -abstract contract CompoundResolver is Events, Helpers { +abstract contract CompoundConnector is Events, Helpers { /** * @dev Deposit ETH/ERC20_Token. * @notice Deposit a token to Compound for lending / collaterization. @@ -206,6 +206,46 @@ abstract contract CompoundResolver is Events, Helpers { _eventParam = abi.encode(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 borrower The address whose debt needs to be repaid. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackRawOnBehalf( + address token, + address cToken, + uint256 amt, + address borrower, + 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(borrower) : _amt; + + if (token == ethAddr) { + require(address(this).balance >= _amt, "not-enough-eth"); + CETHInterface(cToken).repayBorrowBehalf{value: _amt}(borrower); + } else { + TokenInterface tokenContract = TokenInterface(token); + require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); + approve(tokenContract, cToken, _amt); + require(cTokenContract.repayBorrowBehalf(borrower, _amt) == 0, "repay-failed."); + } + setUint(setId, _amt); + + _eventName = "LogPaybackOnBehalf(address,address,uint256,address,uint256,uint256)"; + _eventParam = abi.encode(token, cToken, _amt, borrower, getId, setId); + } + /** * @dev Payback borrowed ETH/ERC20_Token using the Mapping. * @notice Payback debt owed. @@ -224,6 +264,26 @@ abstract contract CompoundResolver is Events, Helpers { (_eventName, _eventParam) = paybackRaw(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 borrower The address whose debt needs to be repaid. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function paybackOnBehalf( + string calldata tokenId, + uint256 amt, + address borrower, + uint256 getId, + uint256 setId + ) external payable returns (string memory _eventName, bytes memory _eventParam) { + (address token, address cToken) = compMapping.getMapping(tokenId); + (_eventName, _eventParam) = paybackRawOnBehalf(token, cToken, amt, borrower, getId, setId); + } + /** * @dev Deposit ETH/ERC20_Token. * @notice Same as depositRaw. The only difference is this method stores cToken amount in set ID. @@ -345,98 +405,8 @@ abstract contract CompoundResolver is Events, Helpers { (address token, address cToken) = compMapping.getMapping(tokenId); (_eventName, _eventParam) = withdrawCTokenRaw(token, cToken, cTokenAmt, getId, setId); } - - /** - * @dev Liquidate a position. - * @notice Liquidate a position. - * @param borrower Borrower's Address. - * @param tokenToPay The address of the token to pay for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) - * @param cTokenPay Corresponding cToken address. - * @param tokenInReturn The address of the token to return for liquidation. - * @param cTokenColl Corresponding cToken address. - * @param amt The token amount to pay for liquidation. - * @param getId ID to retrieve amt. - * @param setId ID stores the amount of paid for liquidation. - */ - function liquidateRaw( - address borrower, - address tokenToPay, - address cTokenPay, - address tokenInReturn, - address cTokenColl, - uint256 amt, - uint256 getId, - uint256 setId - ) public payable returns (string memory _eventName, bytes memory _eventParam) { - uint _amt = getUint(getId, amt); - require(tokenToPay != address(0) && cTokenPay != address(0), "invalid token/ctoken address"); - require(tokenInReturn != address(0) && cTokenColl != address(0), "invalid token/ctoken address"); - - CTokenInterface cTokenContract = CTokenInterface(cTokenPay); - - { - (,, uint shortfal) = troller.getAccountLiquidity(borrower); - require(shortfal != 0, "account-cannot-be-liquidated"); - _amt = _amt == uint(-1) ? cTokenContract.borrowBalanceCurrent(borrower) : _amt; - } - - if (tokenToPay == ethAddr) { - require(address(this).balance >= _amt, "not-enought-eth"); - CETHInterface(cTokenPay).liquidateBorrow{value: _amt}(borrower, cTokenColl); - } else { - TokenInterface tokenContract = TokenInterface(tokenToPay); - require(tokenContract.balanceOf(address(this)) >= _amt, "not-enough-token"); - approve(tokenContract, cTokenPay, _amt); - require(cTokenContract.liquidateBorrow(borrower, _amt, cTokenColl) == 0, "liquidate-failed"); - } - - setUint(setId, _amt); - - _eventName = "LogLiquidate(address,address,address,uint256,uint256,uint256)"; - _eventParam = abi.encode( - address(this), - tokenToPay, - tokenInReturn, - _amt, - getId, - setId - ); - } - - /** - * @dev Liquidate a position using the mapping. - * @notice Liquidate a position using the mapping. - * @param borrower Borrower's Address. - * @param tokenIdToPay token id of the token to pay for liquidation.(For eg: ETH-A) - * @param tokenIdInReturn token id of the token to return for liquidation.(For eg: USDC-A) - * @param amt token amount to pay for liquidation. - * @param getId ID to retrieve amt. - * @param setId ID stores the amount of paid for liquidation. - */ - function liquidate( - address borrower, - string calldata tokenIdToPay, - string calldata tokenIdInReturn, - uint256 amt, - uint256 getId, - uint256 setId - ) external payable returns (string memory _eventName, bytes memory _eventParam) { - (address tokenToPay, address cTokenToPay) = compMapping.getMapping(tokenIdToPay); - (address tokenInReturn, address cTokenColl) = compMapping.getMapping(tokenIdInReturn); - - (_eventName, _eventParam) = liquidateRaw( - borrower, - tokenToPay, - cTokenToPay, - tokenInReturn, - cTokenColl, - amt, - getId, - setId - ); - } } -contract ConnectV2Compound is CompoundResolver { - string public name = "Compound-v1.1"; +contract ConnectV2Compound is CompoundConnector { + string public name = "Compound-v1.2"; } diff --git a/test/mainnet/compound/compound.test.ts b/test/mainnet/compound/compound.test.ts index 89c582ff3..ddbcdf2f4 100644 --- a/test/mainnet/compound/compound.test.ts +++ b/test/mainnet/compound/compound.test.ts @@ -97,8 +97,8 @@ describe("Compound", function () { }, { connector: connectorName, - method: "payback", - args: ["DAI-A", 0, setId, 0] + method: "paybackOnBehalf", + args: ["DAI-A", 0, dsaWallet0.address, setId, 0] } ]