Skip to content

Instantly share code, notes, and snippets.

@gh639
Created January 24, 2021 08:01
Show Gist options
  • Save gh639/eda37dd8bca9edea28a956fe780fdf4b to your computer and use it in GitHub Desktop.
Save gh639/eda37dd8bca9edea28a956fe780fdf4b to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.6.12+commit.27d51765.js&optimize=false&runs=200&gist=
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import { IERC20 } from "./Interfaces.sol";
import { SafeMath,SafeERC20 } from "./Libraries.sol";
import "./ISoloMargin.sol";
contract DydxFlashloanBase {
using SafeMath for uint256;
// -- Internal Helper functions -- //
function _getMarketIdFromTokenAddress(address _solo, address token)
internal
view
returns (uint256)
{
ISoloMargin solo = ISoloMargin(_solo);
uint256 numMarkets = solo.getNumMarkets();
address curToken;
for (uint256 i = 0; i < numMarkets; i++) {
curToken = solo.getMarketTokenAddress(i);
if (curToken == token) {
return i;
}
}
revert("No marketId found for provided token");
}
function _getRepaymentAmountInternal(uint256 amount)
internal
view
returns (uint256)
{
// Needs to be overcollateralize
// Needs to provide +2 wei to be safe
return amount.add(2);
}
function _getAccountInfo() internal view returns (Account.Info memory) {
return Account.Info({owner: address(this), number: 1});
}
function _getWithdrawAction(uint marketId, uint256 amount)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Withdraw,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: ""
});
}
function _getCallAction(bytes memory data)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Call,
accountId: 0,
amount: Types.AssetAmount({
sign: false,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: 0
}),
primaryMarketId: 0,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: data
});
}
function _getDepositAction(uint marketId, uint256 amount)
internal
view
returns (Actions.ActionArgs memory)
{
return
Actions.ActionArgs({
actionType: Actions.ActionType.Deposit,
accountId: 0,
amount: Types.AssetAmount({
sign: true,
denomination: Types.AssetDenomination.Wei,
ref: Types.AssetReference.Delta,
value: amount
}),
primaryMarketId: marketId,
secondaryMarketId: 0,
otherAddress: address(this),
otherAccountId: 0,
data: ""
});
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import { IFlashLoanReceiver, ILendingPoolAddressesProvider, ILendingPool, IERC20 } from "./Interfaces.sol";
import { SafeMath,SafeERC20 } from "./Libraries.sol";
import { Account } from "./ISoloMargin.sol";
import "./DydxFlashloanBase.sol";
//import "github.com/Arachnid/solidity-stringutils/strings.sol";
// get the relevant lendingPool address for _addressProvider
// pass in the tokens to borrow
interface ISimpleKyberProxy {
function swapTokenToEther(
IERC20 token,
uint256 srcAmount,
uint256 minConversionRate
) external returns (uint256 destAmount);
function swapEtherToToken(IERC20 token, uint256 minConversionRate)
external
payable
returns (uint256 destAmount);
function swapTokenToToken(
IERC20 src,
uint256 srcAmount,
IERC20 dest,
uint256 minConversionRate
) external returns (uint256 destAmount);
}
interface UniswapV2Router02 {
function WETH() external pure returns (address);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
}
interface IWETH9 {
function balanceOf(address account) external view returns (uint256);
function deposit() external payable;
function withdraw(uint wad) external;
function transfer(address recipient, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
}
contract FlashRobot is IFlashLoanReceiver, DydxFlashloanBase {
address public owner;
using SafeMath for uint256;
using SafeERC20 for IERC20;
address ETH_TOKEN_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
address public dydxSoloMarginAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
address public WETHAddr = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
//address public kovanDydxSoloMarginAddr = 0x4EC3570cADaAEE08Ae384779B0f3A45EF85289DE;
address public kovanWETHAddr = 0xd0A1E359811322d97991E03f863a0C30C2cF029C;
struct MyCustomData {
address token;
uint256 amount;
uint256 repayAmount;
bytes params;
}
UniswapV2Router02 uniswap;
ISimpleKyberProxy kyber;
//ILendingPoolAddressesProvider _addressesProvider;
ILendingPoolAddressesProvider public addressesProvider;
ILendingPool public aaveLendingPool;
IWETH9 public WETH9;
/*
using strings for *;
string public s;
function foo(string s1, string s2) {
s = s1.toSlice().concat(s2.toSlice());
}
*/
modifier onlyOwner {
require(msg.sender == owner);
_;
}
receive() external payable {}
/**
* LendingPoolAddressesProvider
* Mainnet 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5
* Kovan 0x652B2937Efd0B5beA1c8d54293FC1289672AFC6b
*
constructor(ILendingPoolAddressesProvider _addressProvider) FlashLoanReceiverBase(_addressProvider) public {
owner = msg.sender;
}
*/
constructor(uint256 network_id) public payable {
owner = msg.sender;
if (network_id == 1){
//mainnet
addressesProvider = ILendingPoolAddressesProvider(address(0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5));
dydxSoloMarginAddr = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e;
kyber = ISimpleKyberProxy(0x9AAb3f75489902f3a48495025729a0AF77d4b11e);
WETH9 = IWETH9(WETHAddr);
}else if (network_id == 3){
//ropsten aave v2 没有 ropsten 网络的测试合约
//_AaveLendingPool = ILendingPool(ILendingPoolAddressesProvider(address(0x0000000000000000000000000000000000000000)).getLendingPool());
//_addressProvider = ILendingPoolAddressesProvider(address(0x652B2937Efd0B5beA1c8d54293FC1289672AFC6b));
kyber = ISimpleKyberProxy(0xd719c34261e099Fdb33030ac8909d5788D3039C4);
}else if (network_id == 42){
//kovan
addressesProvider = ILendingPoolAddressesProvider(address(0x652B2937Efd0B5beA1c8d54293FC1289672AFC6b));
kyber = ISimpleKyberProxy(0xc153eeAD19e0DBbDb3462Dcc2B703cC6D738A37c);
dydxSoloMarginAddr = 0x4EC3570cADaAEE08Ae384779B0f3A45EF85289DE;
WETH9 = IWETH9(kovanWETHAddr);
}
aaveLendingPool = ILendingPool(addressesProvider.getLendingPool());
uniswap = UniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);
}
function executeSwap(address _reserve,uint256 _amount,bytes memory params) internal{
uint8[3]memory exs;
uint[3] memory exsParamA;//minOut,expectedRates;
uint[3] memory exsParamB;//choice;
address[2]memory tokens;
//(tokens,exs,expectedRates,minOut,choice) = abi.decode(params,(address[2],uint8[3],uint[3],uint[3],uint8[3]));
(tokens,exs,exsParamA,exsParamB) = abi.decode(params,(address[2],uint8[3],uint[3],uint[3]));
uint256 to_amount = 0;
if (_reserve == tokens[0]){
if(exs[0] == 1) {
to_amount = swapTokensUni(tokens[0], _amount, tokens[1],exsParamA[0],exsParamB[0]);//exsParamA == minOut; exsParamB == choice;
}else{
to_amount = swapTokensKyber(tokens[0], _amount, tokens[1],exsParamA[0]);//exsParamA == expectedRates;
}
if(exs[1] == 1) {
swapTokensUni(tokens[1],to_amount,_reserve,exsParamA[1],exsParamB[1]);
}else{
swapTokensKyber(tokens[1],to_amount,_reserve,exsParamA[1]);
}
}else{
if(exs[0] == 1) {
to_amount = swapTokensUni(_reserve, _amount, tokens[0],exsParamA[0],exsParamB[0]);
}else{
to_amount = swapTokensKyber(_reserve,_amount, tokens[0],exsParamA[0]);
}
if(exs[1] == 1) {
to_amount = swapTokensUni(tokens[0],to_amount, tokens[1],exsParamA[1],exsParamB[1]);
}else{
to_amount = swapTokensKyber(tokens[0],to_amount,tokens[1],exsParamA[1]);
}
if(exs[2] == 1) {
swapTokensUni(tokens[1],to_amount,_reserve,exsParamA[2],exsParamB[2]);
}else{
swapTokensKyber(tokens[1],to_amount,_reserve,exsParamA[2]);
}
}
}
/**
This function is called after your contract has received the flash loaned amount
*/
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
)
external
override
returns (bool)
{
require(assets.length == 1,"Failed assets.length > 1");
address _reserve = assets[0];
uint256 _amount = amounts[0];
executeSwap(_reserve,_amount,params);
//
// This contract now has the funds requested.
// Your logic goes here.
//
// At the end of your logic above, this contract owes
// the flashloaned amounts + premiums.
// Therefore ensure your contract has enough to repay
// these amounts.
//wETHGateway.depositETH
/*
// Approve the LendingPool contract allowance to *pull* the owed amount
for (uint i = 0; i < assets.length; i++) {
uint amountOwing = amounts[i].add(premiums[i]);
IERC20(assets[i]).approve(address(aaveLendingPool), amountOwing);
}*/
uint amountOwing = _amount.add(premiums[0]);
IERC20(_reserve).approve(address(aaveLendingPool), amountOwing);
return true;
}
function myFlashLoanCall(address _reserve, uint256 _amount) public onlyOwner {
address receiverAddress = address(this);
/**
address[] memory assets = new address[](7);
assets[0] = address(0xB597cd8D3217ea6477232F9217fa70837ff667Af); // Kovan AAVE
assets[1] = address(0x2d12186Fbb9f9a8C28B3FfdD4c42920f8539D738); // Kovan BAT
assets[2] = address(0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD); // Kovan DAI
assets[3] = address(0x075A36BA8846C6B6F53644fDd3bf17E5151789DC); // Kovan UNI
assets[4] = address(0xb7c325266ec274fEb1354021D27FA3E3379D840d); // Kovan YFI
assets[5] = address(0xAD5ce863aE3E4E9394Ab43d4ba0D80f419F61789); // Kovan LINK
assets[6] = address(0x7FDb81B0b8a010dd4FFc57C3fecbf145BA8Bd947); // Kovan SNX
0xd0a1e359811322d97991e03f863a0c30c2cf029c //Kovan WETH
uint256[] memory amounts = new uint256[](7);
amounts[0] = 1 ether;
amounts[1] = 1 ether;
amounts[2] = 1 ether;
amounts[3] = 1 ether;
amounts[4] = 1 ether;
amounts[5] = 1 ether;
amounts[6] = 1 ether;
// 0 = no debt, 1 = stable, 2 = variable
uint256[] memory modes = new uint256[](7);
modes[0] = 0;
modes[1] = 0;
modes[2] = 0;
modes[3] = 0;
modes[4] = 0;
modes[5] = 0;
modes[6] = 0;
**/
address[] memory assets = new address[](1);
assets[0] = _reserve;//address(0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD); // Kovan DAI
uint256[] memory amounts = new uint256[](1);
amounts[0] = _amount;//1 ether;
// 0 = no debt, 1 = stable, 2 = variable
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
address onBehalfOf = address(this);
bytes memory params = "";
uint16 referralCode = 0;
aaveLendingPool.flashLoan(
receiverAddress,
assets,
amounts,
modes,
onBehalfOf,
params,
referralCode
);
}
// 合约自毁并且把金额传到指定账户
function kill() public onlyOwner{
selfdestruct(msg.sender); // 自毁函数,ERC20代币不会被转走
}
function ERC20Transfer(address _asset, uint256 amount, address to_addr) public onlyOwner{
IERC20(_asset).transfer(to_addr, amount);
}
function ERC20BalanceOf(address _asset) public view returns (uint256){
return IERC20(_asset).balanceOf(address(this));
}
function ContractEthToWEth(uint256 _amount) external onlyOwner {
address self = address(this);
require(_amount <= self.balance,"Failed _amount > this.balance");
//FlashRobot.address.eth==> FlashRobot.address.weth
WETH9.deposit{value: _amount}();
}
function ContractWEthToEth(uint _amount) public payable onlyOwner{
uint256 balance = WETH9.balanceOf(address(this));
require(_amount <= balance,"Failed _amount > balance");
//FlashRobot.address.weth==> FlashRobot.address.eth
WETH9.withdraw(_amount);
}
//msg.sender eth==>weth
function MsgSenderEthToWEth()
external
payable
onlyOwner
{
uint256 amount = msg.value;
require(amount > 0, "Failed msg.value <=0");
//msg.sender.transfer();
// Wrap ETH.
WETH9.deposit{value:amount}();// msg.sender.eth==> FlashRobot.address.eth==> FlashRobot.address.weth
assert(WETH9.balanceOf(address(this)) >= amount);
WETH9.transfer(msg.sender, amount); //FlashRobot.address.weth==>msg.sender.weth
//WETH9.transferFrom(address(this),msg.sender, amount);
}
//msg.sender weth==>eth,
function MsgSenderWEthToEth(
uint256 amount
)external onlyOwner returns (uint256){
//怎么调用合约时,同时又转代币?在合约中,怎么扣调用者的代币?
//合约内部,无法直接扣除(合约)调用者msg.sender,所持有的代币;必需要先授权approve,但授权操作不能在本合约内操作,需要(合约)调用者,调用“代币”合约,进行授权
//msg.sender.approve(address(this),amount);
//https://kovan.etherscan.io/address/0xd0a1e359811322d97991e03f863a0c30c2cf029c#writeContract WETH approve
uint256 balance = WETH9.balanceOf(msg.sender);
require(amount <= balance,"Failed amount > balance");
uint256 allowance = WETH9.allowance(msg.sender, address(this));
require(amount <= allowance,"Failed amount > allowance");
require(WETH9.transferFrom(msg.sender, address(this), amount) == true, "Could not send tokens to the Contract");
WETH9.withdraw(amount);
msg.sender.transfer(amount);
//WETH9.approve(msg.sender,amount);//allowance[ContractAddress][MsgSenderAddress] = amount;
//WETH9.allowance(msg.sender, address(this));
//IERC20(address(WETH9)).transferFrom(msg.sender,address(this), amount); //allowance[src][msg.sender] >= wad ==>allowance[MsgSenderAddress][ContractAddress] >= amount
//WETH9.withdraw(amount);
//msg.sender.transfer(amount);
return balance;
}
/**
* @dev Withdraw asset.
* @param _assetAddress Asset to be withdrawn.
*/
function withdraw(address _assetAddress) public onlyOwner {
uint assetBalance;
if (_assetAddress == ETH_TOKEN_ADDRESS) {
address self = address(this); // workaround for a possible solidity bug
assetBalance = self.balance;
msg.sender.transfer(assetBalance);
} else {
assetBalance = IERC20(_assetAddress).balanceOf(address(this));
IERC20(_assetAddress).safeTransfer(msg.sender, assetBalance);
}
//emit LogWithdraw(msg.sender, _assetAddress, assetBalance);
}
function swapTokensKyber(address _from, uint _amountIn, address _to, uint _expectedRate) public payable returns (uint256){
uint256 to_amount = 0;
if(_to == ETH_TOKEN_ADDRESS){
to_amount = address(this).balance;
}else{
to_amount = IERC20(_to).balanceOf(address(this));
}
if (_from == ETH_TOKEN_ADDRESS){
//kyber.swapEtherToToken{value:address(this).balance}(IERC20(_to),_expectedRate);
kyber.swapEtherToToken{value:_amountIn}(IERC20(_to),_expectedRate);
}else if(_to ==ETH_TOKEN_ADDRESS){
uint tokenBalance = _amountIn;//IERC20(_from).balanceOf(address(this));
require(IERC20(_from).approve(address(kyber), tokenBalance),"Failed to approve to Kyber");
kyber.swapTokenToEther(IERC20(_from),tokenBalance,_expectedRate);
}else{
uint tokenBalance = _amountIn;//IERC20(_from).balanceOf(address(this));
require(IERC20(_from).approve(address(kyber), tokenBalance),"Failed to approve to Kyber");
kyber.swapTokenToToken(IERC20(_from),tokenBalance,IERC20(_to),_expectedRate);
}
uint256 to_amount2 = 0;
if(_to == ETH_TOKEN_ADDRESS){
to_amount2 = address(this).balance;
}else{
to_amount2 = IERC20(_to).balanceOf(address(this));
}
return to_amount2.sub(to_amount);
}
function swapTokensUni(address _from, uint _amountIn, address _to, uint _minOuts,uint choice) public payable returns (uint256){
uint256 to_amount = 0;
if(_to == ETH_TOKEN_ADDRESS){
to_amount = address(this).balance;
}else{
to_amount = IERC20(_to).balanceOf(address(this));
}
if (_from == ETH_TOKEN_ADDRESS){
address[] memory path = new address[](2);
path[0] = uniswap.WETH();
path[1] = _to;
//uniswap.swapExactETHForTokens{value:address(this).balance}(_minOuts,path,address(this),now);
uniswap.swapExactETHForTokens{value:_amountIn}(_minOuts,path,address(this),now);
}else if(_to == ETH_TOKEN_ADDRESS){
//uint tokenBalance = IERC20(_from).balanceOf(address(this));
uint tokenBalance = _amountIn;
address[]memory path = new address[](2);
path[0]=_from;
path[1]= uniswap.WETH();
require(IERC20(_from).approve(address(uniswap),tokenBalance),"Failed to approve token to Uniswap");
uniswap.swapExactTokensForETH(tokenBalance,_minOuts,path,address(this),now);
}else{
//uint tokenBalance = IERC20(_from).balanceOf(address(this));
uint tokenBalance = _amountIn;
address[] memory path;
if(choice == 3){
path = new address[](3);
path[0]=_from;
path[1]=uniswap.WETH();
path[2]=_to;
}else{
path = new address[](2);
path[0]=_from;
path[1]=_to;
}
require(IERC20(_from).approve(address(uniswap),tokenBalance),"Failed to approve token to Uniswap");
uniswap.swapExactTokensForTokens(tokenBalance,_minOuts,path,address(this),now);
}
uint256 to_amount2 = 0;
if(_to == ETH_TOKEN_ADDRESS){
to_amount2 = address(this).balance;
}else{
to_amount2 = IERC20(_to).balanceOf(address(this));
}
return to_amount2.sub(to_amount);
}
function flashloan(uint _flashex, address _reserve, uint _amount, address[2] memory _tokens,uint8[3] memory _exs,uint[3] memory _exsParamA,uint[3] memory _exsParamB) public onlyOwner {
bytes memory params = abi.encode(_tokens,_exs,_exsParamA,_exsParamB);
if (_flashex == 0){//"aave"
address[] memory assets = new address[](1);
assets[0] = _reserve;//address(0xFf795577d9AC8bD7D90Ee22b6C1703490b6512FD); // Kovan DAI
uint256[] memory amounts = new uint256[](1);
amounts[0] = _amount;
// 0 = no debt, 1 = stable, 2 = variable
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
address onBehalfOf = address(this);
//bytes memory params = "";
uint16 referralCode = 0;
aaveLendingPool.flashLoan(
address(this),
assets,
amounts,
modes,
onBehalfOf,
params,
referralCode
);
//_AaveLendingPool.flashLoan(address(this), _reserve, amount, params);
}else if (_flashex == 1){//'dydx'
dydxFlashLoan(dydxSoloMarginAddr,_reserve,_amount,params);
}else{
require(false,"_flashex error!");
}
//withdraw(_reserve);
}
// _solo = dydxAddr
// _token = WETHAddr
// _amount 借贷数量
function dydxFlashLoan(address _solo, address _token, uint256 _amount, bytes memory params) public
{
ISoloMargin solo = ISoloMargin(_solo);
// Get marketId from token address
uint256 marketId = _getMarketIdFromTokenAddress(_solo, _token);
// Calculate repay amount (_amount + (2 wei))
// Approve transfer from
uint256 repayAmount = _getRepaymentAmountInternal(_amount);
IERC20(_token).approve(_solo, repayAmount);
// 1. Withdraw $
// 2. Call callFunction(...)
// 3. Deposit back $
Actions.ActionArgs[] memory operations = new Actions.ActionArgs[](3);
operations[0] = _getWithdrawAction(marketId, _amount);
operations[1] = _getCallAction(
// Encode MyCustomData for callFunction
abi.encode(MyCustomData({token: _token, amount: _amount, repayAmount: repayAmount, params: params}))
//abi.encode(_token)
);
operations[2] = _getDepositAction(marketId, repayAmount);
Account.Info[] memory accountInfos = new Account.Info[](1);
accountInfos[0] = _getAccountInfo();
solo.operate(accountInfos, operations);
}
function callFunction(
address sender,
Account.Info memory account,
bytes memory data
) public {
MyCustomData memory mcd = abi.decode(data, (MyCustomData));
executeSwap(mcd.token,mcd.amount,mcd.params);
uint256 balOfLoanedToken = IERC20(mcd.token).balanceOf(address(this));
// Note that you can ignore the line below
// if your dydx account (this contract in this case)
// has deposited at least ~2 Wei of assets into the account
// to balance out the collaterization ratio
//WETH9.deposit{value: balOfLoanedToken.add(2)};
//uint256 newBal = IERC20(mcd.token).balanceOf(address(this));
require(
balOfLoanedToken >= mcd.repayAmount,
"Not enough funds to repay dydx loan!"
);
}
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import { DataTypes } from "./Libraries.sol";
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
interface IFlashLoanReceiver {
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool);
}
/**
* @title LendingPoolAddressesProvider contract
* @dev Main registry of addresses part of or connected to the protocol, including permissioned roles
* - Acting also as factory of proxies and admin of those, so with right to change its implementations
* - Owned by the Aave Governance
* @author Aave
**/
interface ILendingPoolAddressesProvider {
event LendingPoolUpdated(address indexed newAddress);
event ConfigurationAdminUpdated(address indexed newAddress);
event EmergencyAdminUpdated(address indexed newAddress);
event LendingPoolConfiguratorUpdated(address indexed newAddress);
event LendingPoolCollateralManagerUpdated(address indexed newAddress);
event PriceOracleUpdated(address indexed newAddress);
event LendingRateOracleUpdated(address indexed newAddress);
event ProxyCreated(bytes32 id, address indexed newAddress);
event AddressSet(bytes32 id, address indexed newAddress, bool hasProxy);
function setAddress(bytes32 id, address newAddress) external;
function setAddressAsProxy(bytes32 id, address impl) external;
function getAddress(bytes32 id) external view returns (address);
function getLendingPool() external view returns (address);
function setLendingPoolImpl(address pool) external;
function getLendingPoolConfigurator() external view returns (address);
function setLendingPoolConfiguratorImpl(address configurator) external;
function getLendingPoolCollateralManager() external view returns (address);
function setLendingPoolCollateralManager(address manager) external;
function getPoolAdmin() external view returns (address);
function setPoolAdmin(address admin) external;
function getEmergencyAdmin() external view returns (address);
function setEmergencyAdmin(address admin) external;
function getPriceOracle() external view returns (address);
function setPriceOracle(address priceOracle) external;
function getLendingRateOracle() external view returns (address);
function setLendingRateOracle(address lendingRateOracle) external;
}
interface ILendingPool {
/**
* @dev Emitted on deposit()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the deposit
* @param onBehalfOf The beneficiary of the deposit, receiving the aTokens
* @param amount The amount deposited
* @param referral The referral code used
**/
event Deposit(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referral
);
/**
* @dev Emitted on withdraw()
* @param reserve The address of the underlyng asset being withdrawn
* @param user The address initiating the withdrawal, owner of aTokens
* @param to Address that will receive the underlying
* @param amount The amount to be withdrawn
**/
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
/**
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
* @param reserve The address of the underlying asset being borrowed
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
* initiator of the transaction on flashLoan()
* @param onBehalfOf The address that will be getting the debt
* @param amount The amount borrowed out
* @param borrowRateMode The rate mode: 1 for Stable, 2 for Variable
* @param borrowRate The numeric rate at which the user has borrowed
* @param referral The referral code used
**/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint256 borrowRateMode,
uint256 borrowRate,
uint16 indexed referral
);
/**
* @dev Emitted on repay()
* @param reserve The address of the underlying asset of the reserve
* @param user The beneficiary of the repayment, getting his debt reduced
* @param repayer The address of the user initiating the repay(), providing the funds
* @param amount The amount repaid
**/
event Repay(
address indexed reserve,
address indexed user,
address indexed repayer,
uint256 amount
);
/**
* @dev Emitted on swapBorrowRateMode()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user swapping his rate mode
* @param rateMode The rate mode that the user wants to swap to
**/
event Swap(address indexed reserve, address indexed user, uint256 rateMode);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
**/
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
**/
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on rebalanceStableBorrowRate()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user for which the rebalance has been executed
**/
event RebalanceStableBorrowRate(address indexed reserve, address indexed user);
/**
* @dev Emitted on flashLoan()
* @param target The address of the flash loan receiver contract
* @param initiator The address initiating the flash loan
* @param asset The address of the asset being flash borrowed
* @param amount The amount flash borrowed
* @param premium The fee flash borrowed
* @param referralCode The referral code used
**/
event FlashLoan(
address indexed target,
address indexed initiator,
address indexed asset,
uint256 amount,
uint256 premium,
uint16 referralCode
);
/**
* @dev Emitted when the pause is triggered.
*/
event Paused();
/**
* @dev Emitted when the pause is lifted.
*/
event Unpaused();
/**
* @dev Emitted when a borrower is liquidated. This event is emitted by the LendingPool via
* LendingPoolCollateral manager using a DELEGATECALL
* This allows to have the events in the generated ABI for LendingPool.
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param liquidatedCollateralAmount The amount of collateral received by the liiquidator
* @param liquidator The address of the liquidator
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the state of a reserve is updated. NOTE: This event is actually declared
* in the ReserveLogic library and emitted in the updateInterestRates() function. Since the function is internal,
* the event will actually be fired by the LendingPool contract. The event is therefore replicated here so it
* gets added to the LendingPool ABI
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The new liquidity rate
* @param stableBorrowRate The new stable borrow rate
* @param variableBorrowRate The new variable borrow rate
* @param liquidityIndex The new liquidity index
* @param variableBorrowIndex The new variable borrow index
**/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Deposits an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User deposits 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to deposit
* @param amount The amount to be deposited
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function deposit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @dev Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to Address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
**/
function withdraw(
address asset,
uint256 amount,
address to
) external;
/**
* @dev Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already deposited enough collateral, or he was given enough allowance by a credit delegator on the
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf Address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
**/
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param rateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
**/
function repay(
address asset,
uint256 amount,
uint256 rateMode,
address onBehalfOf
) external;
/**
* @dev Allows a borrower to swap his debt between stable and variable mode, or viceversa
* @param asset The address of the underlying asset borrowed
* @param rateMode The rate mode that the user wants to swap to
**/
function swapBorrowRateMode(address asset, uint256 rateMode) external;
/**
* @dev Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current deposit APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too much has been
* borrowed at a stable rate and depositors are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
**/
function rebalanceStableBorrowRate(address asset, address user) external;
/**
* @dev Allows depositors to enable/disable a specific deposited asset as collateral
* @param asset The address of the underlying asset deposited
* @param useAsCollateral `true` if the user wants to use the deposit as collateral, `false` otherwise
**/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
/**
* @dev Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken `true` if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
**/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
/**
* @dev Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept into consideration.
* For further details please visit https://developers.aave.com
* @param receiverAddress The address of the contract receiving the funds, implementing the IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts amounts being flash-borrowed
* @param modes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
**/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
/**
* @dev Returns the user account data across all the reserves
* @param user The address of the user
* @return totalCollateralETH the total collateral in ETH of the user
* @return totalDebtETH the total debt in ETH of the user
* @return availableBorrowsETH the borrowing power left of the user
* @return currentLiquidationThreshold the liquidation threshold of the user
* @return ltv the loan to value of the user
* @return healthFactor the current health factor of the user
**/
function getUserAccountData(address user)
external
view
returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
function initReserve(
address reserve,
address aTokenAddress,
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
function setReserveInterestRateStrategyAddress(address reserve, address rateStrategyAddress)
external;
function setConfiguration(address reserve, uint256 configuration) external;
/**
* @dev Returns the configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
**/
function getConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory);
/**
* @dev Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
**/
function getUserConfiguration(address user) external view returns (DataTypes.UserConfigurationMap memory);
/**
* @dev Returns the normalized income normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(address asset) external view returns (uint256);
/**
* @dev Returns the normalized variable debt per unit of asset
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
/**
* @dev Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state of the reserve
**/
function getReserveData(address asset) external view returns (DataTypes.ReserveData memory);
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromAfter,
uint256 balanceToBefore
) external;
function getReservesList() external view returns (address[] memory);
function getAddressesProvider() external view returns (ILendingPoolAddressesProvider);
function setPause(bool val) external;
function paused() external view returns (bool);
}
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
library Account {
enum Status {Normal, Liquid, Vapor}
struct Info {
address owner; // The address that owns the account
uint256 number; // A nonce that allows a single address to control many accounts
}
struct Storage {
mapping(uint256 => Types.Par) balances; // Mapping from marketId to principal
Status status;
}
}
library Actions {
enum ActionType {
Deposit, // supply tokens
Withdraw, // borrow tokens
Transfer, // transfer balance between accounts
Buy, // buy an amount of some token (publicly)
Sell, // sell an amount of some token (publicly)
Trade, // trade tokens against another account
Liquidate, // liquidate an undercollateralized or expiring account
Vaporize, // use excess tokens to zero-out a completely negative account
Call // send arbitrary data to an address
}
enum AccountLayout {OnePrimary, TwoPrimary, PrimaryAndSecondary}
enum MarketLayout {ZeroMarkets, OneMarket, TwoMarkets}
struct ActionArgs {
ActionType actionType;
uint256 accountId;
Types.AssetAmount amount;
uint256 primaryMarketId;
uint256 secondaryMarketId;
address otherAddress;
uint256 otherAccountId;
bytes data;
}
struct DepositArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 market;
address from;
}
struct WithdrawArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 market;
address to;
}
struct TransferArgs {
Types.AssetAmount amount;
Account.Info accountOne;
Account.Info accountTwo;
uint256 market;
}
struct BuyArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 makerMarket;
uint256 takerMarket;
address exchangeWrapper;
bytes orderData;
}
struct SellArgs {
Types.AssetAmount amount;
Account.Info account;
uint256 takerMarket;
uint256 makerMarket;
address exchangeWrapper;
bytes orderData;
}
struct TradeArgs {
Types.AssetAmount amount;
Account.Info takerAccount;
Account.Info makerAccount;
uint256 inputMarket;
uint256 outputMarket;
address autoTrader;
bytes tradeData;
}
struct LiquidateArgs {
Types.AssetAmount amount;
Account.Info solidAccount;
Account.Info liquidAccount;
uint256 owedMarket;
uint256 heldMarket;
}
struct VaporizeArgs {
Types.AssetAmount amount;
Account.Info solidAccount;
Account.Info vaporAccount;
uint256 owedMarket;
uint256 heldMarket;
}
struct CallArgs {
Account.Info account;
address callee;
bytes data;
}
}
library Decimal {
struct D256 {
uint256 value;
}
}
library Interest {
struct Rate {
uint256 value;
}
struct Index {
uint96 borrow;
uint96 supply;
uint32 lastUpdate;
}
}
library Monetary {
struct Price {
uint256 value;
}
struct Value {
uint256 value;
}
}
library Storage {
// All information necessary for tracking a market
struct Market {
// Contract address of the associated ERC20 token
address token;
// Total aggregated supply and borrow amount of the entire market
Types.TotalPar totalPar;
// Interest index of the market
Interest.Index index;
// Contract address of the price oracle for this market
address priceOracle;
// Contract address of the interest setter for this market
address interestSetter;
// Multiplier on the marginRatio for this market
Decimal.D256 marginPremium;
// Multiplier on the liquidationSpread for this market
Decimal.D256 spreadPremium;
// Whether additional borrows are allowed for this market
bool isClosing;
}
// The global risk parameters that govern the health and security of the system
struct RiskParams {
// Required ratio of over-collateralization
Decimal.D256 marginRatio;
// Percentage penalty incurred by liquidated accounts
Decimal.D256 liquidationSpread;
// Percentage of the borrower's interest fee that gets passed to the suppliers
Decimal.D256 earningsRate;
// The minimum absolute borrow value of an account
// There must be sufficient incentivize to liquidate undercollateralized accounts
Monetary.Value minBorrowedValue;
}
// The maximum RiskParam values that can be set
struct RiskLimits {
uint64 marginRatioMax;
uint64 liquidationSpreadMax;
uint64 earningsRateMax;
uint64 marginPremiumMax;
uint64 spreadPremiumMax;
uint128 minBorrowedValueMax;
}
// The entire storage state of Solo
struct State {
// number of markets
uint256 numMarkets;
// marketId => Market
mapping(uint256 => Market) markets;
// owner => account number => Account
mapping(address => mapping(uint256 => Account.Storage)) accounts;
// Addresses that can control other users accounts
mapping(address => mapping(address => bool)) operators;
// Addresses that can control all users accounts
mapping(address => bool) globalOperators;
// mutable risk parameters of the system
RiskParams riskParams;
// immutable risk limits of the system
RiskLimits riskLimits;
}
}
library Types {
enum AssetDenomination {
Wei, // the amount is denominated in wei
Par // the amount is denominated in par
}
enum AssetReference {
Delta, // the amount is given as a delta from the current value
Target // the amount is given as an exact number to end up at
}
struct AssetAmount {
bool sign; // true if positive
AssetDenomination denomination;
AssetReference ref;
uint256 value;
}
struct TotalPar {
uint128 borrow;
uint128 supply;
}
struct Par {
bool sign; // true if positive
uint128 value;
}
struct Wei {
bool sign; // true if positive
uint256 value;
}
}
abstract contract ISoloMargin { //
struct OperatorArg {
address operator;
bool trusted;
}
function ownerSetSpreadPremium(
uint256 marketId,
Decimal.D256 memory spreadPremium
) public virtual;
function getIsGlobalOperator(address operator) public virtual view returns (bool);
function getMarketTokenAddress(uint256 marketId)
public
virtual
view
returns (address);
function ownerSetInterestSetter(uint256 marketId, address interestSetter)
public virtual;
function getAccountValues(Account.Info memory account)
public
virtual
view
returns (Monetary.Value memory, Monetary.Value memory);
function getMarketPriceOracle(uint256 marketId)
public
virtual
view
returns (address);
function getMarketInterestSetter(uint256 marketId)
public
virtual
view
returns (address);
function getMarketSpreadPremium(uint256 marketId)
public
virtual
view
returns (Decimal.D256 memory);
function getNumMarkets() public virtual view returns (uint256);
function ownerWithdrawUnsupportedTokens(address token, address recipient)
public virtual
returns (uint256);
function ownerSetMinBorrowedValue(Monetary.Value memory minBorrowedValue)
public virtual;
function ownerSetLiquidationSpread(Decimal.D256 memory spread) public virtual;
function ownerSetEarningsRate(Decimal.D256 memory earningsRate) public virtual;
function getIsLocalOperator(address owner, address operator)
public
virtual
view
returns (bool);
function getAccountPar(Account.Info memory account, uint256 marketId)
public
virtual
view
returns (Types.Par memory);
function ownerSetMarginPremium(
uint256 marketId,
Decimal.D256 memory marginPremium
) public virtual;
function getMarginRatio() public virtual view returns (Decimal.D256 memory);
function getMarketCurrentIndex(uint256 marketId)
public
virtual
view
returns (Interest.Index memory);
function getMarketIsClosing(uint256 marketId) public virtual view returns (bool);
function getRiskParams() public virtual view returns (Storage.RiskParams memory);
function getAccountBalances(Account.Info memory account)
public
virtual
view
returns (address[] memory, Types.Par[] memory, Types.Wei[] memory);
function renounceOwnership() public virtual;
function getMinBorrowedValue() public virtual view returns (Monetary.Value memory);
function setOperators(OperatorArg[] memory args) public virtual;
function getMarketPrice(uint256 marketId) public virtual view returns (address);
function owner() public virtual view returns (address);
function isOwner() public virtual view returns (bool);
function ownerWithdrawExcessTokens(uint256 marketId, address recipient)
public virtual
returns (uint256);
function ownerAddMarket(
address token,
address priceOracle,
address interestSetter,
Decimal.D256 memory marginPremium,
Decimal.D256 memory spreadPremium
) public virtual;
function operate(
Account.Info[] memory accounts,
Actions.ActionArgs[] memory actions
) public virtual;
function getMarketWithInfo(uint256 marketId)
public
virtual
view
returns (
Storage.Market memory,
Interest.Index memory,
Monetary.Price memory,
Interest.Rate memory
);
function ownerSetMarginRatio(Decimal.D256 memory ratio) public virtual;
function getLiquidationSpread() public virtual view returns (Decimal.D256 memory);
function getAccountWei(Account.Info memory account, uint256 marketId)
public
virtual
view
returns (Types.Wei memory);
function getMarketTotalPar(uint256 marketId)
public
virtual
view
returns (Types.TotalPar memory);
function getLiquidationSpreadForPair(
uint256 heldMarketId,
uint256 owedMarketId
) public virtual view returns (Decimal.D256 memory);
function getNumExcessTokens(uint256 marketId)
public
virtual
view
returns (Types.Wei memory);
function getMarketCachedIndex(uint256 marketId)
public
virtual
view
returns (Interest.Index memory);
function getAccountStatus(Account.Info memory account)
public
virtual
view
returns (uint8);
function getEarningsRate() public virtual view returns (Decimal.D256 memory);
function ownerSetPriceOracle(uint256 marketId, address priceOracle) public virtual;
function getRiskLimits() public virtual view returns (Storage.RiskLimits memory);
function getMarket(uint256 marketId)
public
virtual
view
returns (Storage.Market memory);
function ownerSetIsClosing(uint256 marketId, bool isClosing) public virtual;
function ownerSetGlobalOperator(address operator, bool approved) public virtual;
function transferOwnership(address newOwner) public virtual;
function getAdjustedAccountValues(Account.Info memory account)
public
virtual
view
returns (Monetary.Value memory, Monetary.Value memory);
function getMarketMarginPremium(uint256 marketId)
public
virtual
view
returns (Decimal.D256 memory);
function getMarketInterestRate(uint256 marketId)
public
virtual
view
returns (Interest.Rate memory);
}
// SPDX-License-Identifier: agpl-3.0
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import { IERC20 } from "./Interfaces.sol";
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, 'SafeMath: addition overflow');
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, 'SafeMath: subtraction overflow');
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, 'SafeMath: multiplication overflow');
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, 'SafeMath: division by zero');
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, 'SafeMath: modulo by zero');
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly {
codehash := extcodehash(account)
}
return (codehash != accountHash && codehash != 0x0);
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, 'Address: insufficient balance');
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{value: amount}('');
require(success, 'Address: unable to send value, recipient may have reverted');
}
}
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
'SafeERC20: approve from non-zero to non-zero allowance'
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function callOptionalReturn(IERC20 token, bytes memory data) private {
require(address(token).isContract(), 'SafeERC20: call to non-contract');
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, 'SafeERC20: low-level call failed');
if (returndata.length > 0) {
// Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
}
}
}
library DataTypes {
// refer to the whitepaper, section 1.1 basic concepts for a formal description of these properties.
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
uint40 lastUpdateTimestamp;
//tokens addresses
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the id of the reserve. Represents the position in the list of the active reserves
uint8 id;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: Reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60-63: reserved
//bit 64-79: reserve factor
uint256 data;
}
struct UserConfigurationMap {
uint256 data;
}
enum InterestRateMode {NONE, STABLE, VARIABLE}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment