dsa-connectors/contracts/mainnet/connectors/reflexer/main.sol
2022-03-22 20:54:40 +05:30

428 lines
15 KiB
Solidity

//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
/**
* @title Reflexer.
* @dev Collateralized Borrowing.
*/
import { TokenInterface } from "../../common/interfaces.sol";
import { Helpers } from "./helpers.sol";
import { Events } from "./events.sol";
import { SafeEngineLike, TokenJoinInterface } from "./interface.sol";
abstract contract GebResolver is Helpers, Events {
/**
* @dev Open Safe
* @notice Open a Reflexer Safe.
* @param colType Type of Collateral.(eg: 'ETH-A')
*/
function open(string calldata colType) external payable returns (string memory _eventName, bytes memory _eventParam) {
bytes32 collateralType = stringToBytes32(colType);
require(getCollateralJoinAddress(collateralType) != address(0), "wrong-col-type");
uint256 safe = managerContract.openSAFE(collateralType, address(this));
_eventName = "LogOpen(uint256,bytes32)";
_eventParam = abi.encode(safe, collateralType);
}
/**
* @dev Close Safe
* @notice Close a Reflexer Safe.
* @param safe Safe ID to close.
*/
function close(uint256 safe) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
(uint collateral, uint debt) = SafeEngineLike(managerContract.safeEngine()).safes(collateralType, handler);
require(collateral == 0 && debt == 0, "safe-has-assets");
require(managerContract.ownsSAFE(_safe) == address(this), "not-owner");
managerContract.transferSAFEOwnership(_safe, giveAddr);
_eventName = "LogClose(uint256,bytes32)";
_eventParam = abi.encode(_safe, collateralType);
}
/**
* @dev Deposit ETH/ERC20_Token Collateral.
* @notice Deposit collateral to a Reflexer safe
* @param safe Safe ID.
* @param amt token amount to deposit.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function deposit(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
address colAddr = getCollateralJoinAddress(collateralType);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
TokenInterface tokenContract = tokenJoinContract.collateral();
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);
SafeEngineLike(managerContract.safeEngine()).modifySAFECollateralization(
collateralType,
handler,
address(this),
address(this),
toInt(convertTo18(tokenJoinContract.decimals(), _amt)),
0
);
setUint(setId, _amt);
_eventName = "LogDeposit(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_safe, collateralType, _amt, getId, setId);
}
/**
* @dev Withdraw ETH/ERC20_Token Collateral.
* @notice Withdraw collateral from a Reflexer Safe
* @param safe Safe ID.
* @param amt token amount to withdraw.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function withdraw(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
address colAddr = getCollateralJoinAddress(collateralType);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
uint _amt18;
if (_amt == uint(-1)) {
(_amt18,) = SafeEngineLike(managerContract.safeEngine()).safes(collateralType, handler);
_amt = convert18ToDec(tokenJoinContract.decimals(), _amt18);
} else {
_amt18 = convertTo18(tokenJoinContract.decimals(), _amt);
}
managerContract.modifySAFECollateralization(
_safe,
-toInt(_amt18),
0
);
managerContract.transferCollateral(
_safe,
address(this),
_amt18
);
TokenInterface tokenContract = tokenJoinContract.collateral();
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(_safe, collateralType, _amt, getId, setId);
}
/**
* @dev Borrow Coin.
* @notice Borrow Coin using a Reflexer safe
* @param safe Safe ID.
* @param amt token amount to borrow.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function borrow(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
SafeEngineLike safeEngineContract = SafeEngineLike(managerContract.safeEngine());
managerContract.modifySAFECollateralization(
_safe,
0,
_getBorrowAmt(
address(safeEngineContract),
handler,
collateralType,
_amt
)
);
managerContract.transferInternalCoins(
_safe,
address(this),
toRad(_amt)
);
if (safeEngineContract.safeRights(address(this), address(coinJoinContract)) == 0) {
safeEngineContract.approveSAFEModification(address(coinJoinContract));
}
coinJoinContract.exit(address(this), _amt);
setUint(setId, _amt);
_eventName = "LogBorrow(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_safe, collateralType, _amt, getId, setId);
}
/**
* @dev Payback borrowed Coin.
* @notice Payback Coin debt owed by a Reflexer safe
* @param safe Safe ID.
* @param amt token amount to payback.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function payback(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
address safeEngine = managerContract.safeEngine();
uint _maxDebt = _getSafeDebt(safeEngine, collateralType, handler);
_amt = _amt == uint(-1) ? _maxDebt : _amt;
require(_maxDebt >= _amt, "paying-excess-debt");
approve(coinJoinContract.systemCoin(), address(coinJoinContract), _amt);
coinJoinContract.join(handler, _amt);
managerContract.modifySAFECollateralization(
_safe,
0,
_getWipeAmt(
safeEngine,
SafeEngineLike(safeEngine).coinBalance(handler),
handler,
collateralType
)
);
setUint(setId, _amt);
_eventName = "LogPayback(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_safe, collateralType, _amt, getId, setId);
}
/**
* @dev Withdraw leftover ETH/ERC20_Token after Liquidation.
* @notice Withdraw leftover collateral after Liquidation.
* @param safe Safe ID.
* @param amt token amount to Withdraw.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function withdrawLiquidated(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
(bytes32 collateralType, address handler) = getSafeData(safe);
address colAddr = getCollateralJoinAddress(collateralType);
TokenJoinInterface tokenJoinContract = TokenJoinInterface(colAddr);
uint _amt18;
if (_amt == uint(-1)) {
_amt18 = SafeEngineLike(managerContract.safeEngine()).tokenCollateral(collateralType, handler);
_amt = convert18ToDec(tokenJoinContract.decimals(), _amt18);
} else {
_amt18 = convertTo18(tokenJoinContract.decimals(), _amt);
}
managerContract.transferCollateral(
safe,
address(this),
_amt18
);
TokenInterface tokenContract = tokenJoinContract.collateral();
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(safe, collateralType, _amt, getId, setId);
}
struct GebData {
uint _safe;
address colAddr;
TokenJoinInterface tokenJoinContract;
SafeEngineLike safeEngineContract;
TokenInterface tokenContract;
}
/**
* @dev Deposit ETH/ERC20_Token Collateral and Borrow Coin.
* @notice Deposit collateral and borrow Coin.
* @param safe Safe ID.
* @param depositAmt token deposit amount to Withdraw.
* @param borrowAmt token borrow amount to Withdraw.
* @param getIdDeposit Get deposit token amount at this ID from `InstaMemory` Contract.
* @param getIdBorrow Get borrow token amount at this ID from `InstaMemory` Contract.
* @param setIdDeposit Set deposit token amount at this ID in `InstaMemory` Contract.
* @param setIdBorrow Set borrow token amount at this ID in `InstaMemory` Contract.
*/
function depositAndBorrow(
uint256 safe,
uint256 depositAmt,
uint256 borrowAmt,
uint256 getIdDeposit,
uint256 getIdBorrow,
uint256 setIdDeposit,
uint256 setIdBorrow
) external payable returns (string memory _eventName, bytes memory _eventParam) {
GebData memory gebData;
uint _amtDeposit = getUint(getIdDeposit, depositAmt);
uint _amtBorrow = getUint(getIdBorrow, borrowAmt);
gebData._safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(gebData._safe);
gebData.colAddr = getCollateralJoinAddress(collateralType);
gebData.tokenJoinContract = TokenJoinInterface(gebData.colAddr);
gebData.safeEngineContract = SafeEngineLike(managerContract.safeEngine());
gebData.tokenContract = gebData.tokenJoinContract.collateral();
if (isEth(address(gebData.tokenContract))) {
_amtDeposit = _amtDeposit == uint(-1) ? address(this).balance : _amtDeposit;
gebData.tokenContract.deposit{value: _amtDeposit}();
} else {
_amtDeposit = _amtDeposit == uint(-1) ? gebData.tokenContract.balanceOf(address(this)) : _amtDeposit;
}
approve(gebData.tokenContract, address(gebData.colAddr), _amtDeposit);
gebData.tokenJoinContract.join(handler, _amtDeposit);
managerContract.modifySAFECollateralization(
gebData._safe,
toInt(convertTo18(gebData.tokenJoinContract.decimals(), _amtDeposit)),
_getBorrowAmt(
address(gebData.safeEngineContract),
handler,
collateralType,
_amtBorrow
)
);
managerContract.transferInternalCoins(
gebData._safe,
address(this),
toRad(_amtBorrow)
);
if (gebData.safeEngineContract.safeRights(address(this), address(coinJoinContract)) == 0) {
gebData.safeEngineContract.approveSAFEModification(address(coinJoinContract));
}
coinJoinContract.exit(address(this), _amtBorrow);
setUint(setIdDeposit, _amtDeposit);
setUint(setIdBorrow, _amtBorrow);
_eventName = "LogDepositAndBorrow(uint256,bytes32,uint256,uint256,uint256,uint256,uint256,uint256)";
_eventParam = abi.encode(
gebData._safe,
collateralType,
_amtDeposit,
_amtBorrow,
getIdDeposit,
getIdBorrow,
setIdDeposit,
setIdBorrow
);
}
/**
* @dev Exit Coin from handler.
* @notice Exit Coin from handler.
* @param safe Safe ID.
* @param amt token amount to exit.
* @param getId Get token amount at this ID from `InstaMemory` Contract.
* @param setId Set token amount at this ID in `InstaMemory` Contract.
*/
function exit(
uint256 safe,
uint256 amt,
uint256 getId,
uint256 setId
) external payable returns (string memory _eventName, bytes memory _eventParam) {
uint _amt = getUint(getId, amt);
uint _safe = getSafe(safe);
(bytes32 collateralType, address handler) = getSafeData(_safe);
SafeEngineLike safeEngineContract = SafeEngineLike(managerContract.safeEngine());
if(_amt == uint(-1)) {
_amt = safeEngineContract.coinBalance(handler);
_amt = _amt / 10 ** 27;
}
managerContract.transferInternalCoins(
_safe,
address(this),
toRad(_amt)
);
if (safeEngineContract.safeRights(address(this), address(coinJoinContract)) == 0) {
safeEngineContract.approveSAFEModification(address(coinJoinContract));
}
coinJoinContract.exit(address(this), _amt);
setUint(setId, _amt);
_eventName = "LogExit(uint256,bytes32,uint256,uint256,uint256)";
_eventParam = abi.encode(_safe, collateralType, _amt, getId, setId);
}
}
contract ConnectV2Reflexer is GebResolver {
string public constant name = "Reflexer-v1";
}