Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
/**
* @title: BackStop DAI wrapper
* @summary: Used for interacting with Backstop Protocol. Has
* a common interface with all other protocol wrappers.
* This contract holds assets only during a tx, after tx it should be empty
* @author: Idle Labs Inc., idle.finance
*/
pragma solidity 0.5.16;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
import "@openzeppelin/contracts/ownership/Ownable.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "../interfaces/ILendingProtocol.sol";
import "../interfaces/CERC20.sol";
// B.Protocol Token Interface
interface IBErc20 {
function mint(uint256 mintAmount) external returns (uint256);
function redeem(uint256 redeemTokens) external returns (uint256);
function underlying() external view returns (uint256);
function cToken() external view returns (uint256);
function exchangeRateStored() external view returns (uint256);
}
// Ctoken InterestRate Model
interface WhitePaperInterestRateModel {
function getSupplyRate(uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa) external view returns (uint256);
}
contract IdleBackStop is ILendingProtocol, Ownable {
using SafeERC20 for IERC20;
using SafeMath for uint256;
// protocol token (bTokenDAI) address
address public token;
address public cToken;
// underlying token (token eg DAI) address
address public underlying;
address public idleToken;
uint256 public blocksPerYear;
bool public initialized;
/**
* @param _token : bTokenDAI address
* @param _idleToken : idleToken address
*/
function initialize(address _token, address _idleToken) public {
require(!initialized, "Already initialized");
require(_token != address(0), 'bToken: addr is 0');
token = _token;
idleToken = _idleToken;
cToken = address(IBErc20(_token).cToken());
underlying = address(IBErc20(_token).underlying());
IERC20(underlying).safeApprove(_token, uint256(-1));
// (1 day = 6570 blocks) => (365 days * 6570 per day blocks = 2398050 total blocks per year)
blocksPerYear = 2398050;
initialized = true;
}
/**
* Throws if called by any account other than IdleToken contract.
*/
modifier onlyIdle() {
require(msg.sender == idleToken, "Ownable: caller is not IdleToken");
_;
}
function nextSupplyRateWithParams(uint256[] memory)
public view
returns (uint256) {
return nextSupplyRate(0);
}
/**
* Calculate next supply rate for bTokenDAI, given an `_amount` supplied
*
* @param _amount : new underlying amount supplied (eg DAI)
* @return : yearly net rate
*/
function nextSupplyRate(uint256 _amount) public view returns (uint256) {
uint256 ratePerBlock;
CERC20 cERC20Token = CERC20(cToken);
if (_amount > 0) {
WhitePaperInterestRateModel white = WhitePaperInterestRateModel(cERC20Token.interestRateModel());
ratePerBlock = white.getSupplyRate(
cERC20Token.getCash().add(_amount),
cERC20Token.totalBorrows(),
cERC20Token.totalReserves(),
cERC20Token.reserveFactorMantissa()
);
} else {
ratePerBlock = cERC20Token.supplyRatePerBlock();
}
return ratePerBlock.mul(blocksPerYear).mul(100);
}
/**
* @return current price of bTokenDAI
*/
function getPriceInToken()
external view
returns (uint256) {
return IBErc20(token).exchangeRateStored();
}
/**
* @return current apr
*/
function getAPR()
external view
returns (uint256) {
return nextSupplyRate(0); // current apr whne you pass amount 0
}
/**
* Gets all underlying tokens in this contract and mints bTokenDAI Tokens
* tokens are then transferred to msg.sender
* NOTE: underlying tokens needs to be sent here before calling this
*
* @return bTokenDAI Tokens minted
*/
function mint()
external onlyIdle
returns (uint256 bDAITokens) {
uint256 balance = IERC20(underlying).balanceOf(address(this));
if (balance == 0) {
return bDAITokens;
}
IBErc20(token).mint(balance);
bDAITokens = IERC20(token).balanceOf(address(this));
IERC20(token).safeTransfer(msg.sender, bDAITokens);
}
/**
* Gets all bTokenDAI in this contract and redeems underlying tokens.
* underlying tokens are then transferred to `_account`
* NOTE: bTokenDAI needs to be sent here before calling this
*
* @return underlying tokens redeemd
*/
function redeem(address _account)
external onlyIdle
returns (uint256 tokens) {
IBErc20(token).redeem(IERC20(token).balanceOf(address(this)));
IERC20 _underlying = IERC20(underlying);
tokens = _underlying.balanceOf(address(this));
_underlying.safeTransfer(_account, tokens);
}
/**
* Get the underlying balance on the lending protocol
*
* @return underlying tokens available
*/
function availableLiquidity() external view returns (uint256) {
return CERC20(cToken).getCash();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment