false
true
0
PulseChain
Blockchain
Blocks
Blocks
Uncles
Forked Blocks (Reorgs)
Transactions
Confirmed
Pending
Verified contracts
Tokens
All
PLS
APIs
GraphQL
RPC
Eth RPC
Apps
PulseChain Beacon Explorer
PulseX
PulseChain Bridge
Become a Validator
PulseChain
Mainnets
PulseChain Mainnet
Testnets
Testnet V4
/
Search
/
Search
Connection Lost
New Solidity Smart Contract Verification
Contract Address
The 0x address supplied on contract creation.
Is Yul contract
No
Yes
Select Yes if you want to verify Yul contract.
Contract Name
Must match the name specified in the code. For example, in
contract MyContract {..}
MyContract
is the contract name.
Include nightly builds
No
Yes
Select yes if you want to show nightly builds.
Compiler
v0.8.38+commit.1835d247
v0.8.37+commit.f401782d
v0.8.36+commit.8a079791
v0.8.35+commit.47b9dedd
v0.8.35-pre.1+commit.a99b6d8c
v0.8.34+commit.80d5c536
v0.8.33+commit.64118f21
v0.8.32+commit.ebbd65e5
v0.8.31+commit.fd3a2265
v0.8.31-pre.1+commit.b59566f6
v0.8.30+commit.73712a01
v0.8.29+commit.ab55807c
v0.8.28+commit.7893614a
v0.8.27+commit.40a35a09
v0.8.26+commit.8a97fa7a
v0.8.25+commit.b61c2a91
v0.8.24+commit.e11b9ed9
v0.8.23+commit.f704f362
v0.8.22+commit.4fc1097e
v0.8.21+commit.d9974bed
v0.8.20+commit.a1b79de6
v0.8.19+commit.7dd6d404
v0.8.18+commit.87f61d96
v0.8.17+commit.8df45f5f
v0.8.16+commit.07a7930e
v0.8.15+commit.e14f2714
v0.8.14+commit.80d49f37
v0.8.13+commit.abaa5c0e
v0.8.12+commit.f00d7308
v0.8.11+commit.d7f03943
v0.8.10+commit.fc410830
v0.8.9+commit.e5eed63a
v0.8.8+commit.dddeac2f
v0.8.7+commit.e28d00a7
v0.8.6+commit.11564f7e
v0.8.5+commit.a4f2e591
v0.8.4+commit.c7e474f2
v0.8.3+commit.8d00100c
v0.8.2+commit.661d1103
v0.8.1+commit.df193b15
v0.8.0+commit.c7dfd78e
v0.7.6+commit.7338295f
v0.7.5+commit.eb77ed08
v0.7.4+commit.3f05b770
v0.7.3+commit.9bfce1f6
v0.7.2+commit.51b20bc0
v0.7.1+commit.f4a555be
v0.7.0+commit.9e61f92b
v0.6.12+commit.27d51765
v0.6.11+commit.5ef660b1
v0.6.10+commit.00c0fcaf
v0.6.9+commit.3e3065ac
v0.6.8+commit.0bbfe453
v0.6.7+commit.b8d736ae
v0.6.6+commit.6c089d02
v0.6.5+commit.f956cc89
v0.6.4+commit.1dca32f3
v0.6.3+commit.8dda9521
v0.6.2+commit.bacdbe57
v0.6.1+commit.e6f7d5a4
v0.6.0+commit.26b70077
v0.5.17+commit.d19bba13
v0.5.16+commit.9c3226ce
v0.5.15+commit.6a57276f
v0.5.14+commit.01f1aaa4
v0.5.13+commit.5b0b510c
v0.5.12+commit.7709ece9
v0.5.11+commit.22be8592
v0.5.10+commit.5a6ea5b1
v0.5.9+commit.c68bc34e
v0.5.8+commit.23d335f2
v0.5.7+commit.6da8b019
v0.5.6+commit.b259423e
v0.5.5+commit.47a71e8f
v0.5.4+commit.9549d8ff
v0.5.3+commit.10d17f24
v0.5.2+commit.1df8f40c
v0.5.1+commit.c8a2cb62
v0.5.0+commit.1d4f565a
v0.4.26+commit.4563c3fc
v0.4.25+commit.59dbf8f1
v0.4.24+commit.e67f0147
v0.4.23+commit.124ca40d
v0.4.22+commit.4cb486ee
v0.4.21+commit.dfe3193c
v0.4.20+commit.3155dd80
v0.4.19+commit.c4cbbb05
v0.4.18+commit.9cf6e910
v0.4.17+commit.bdeb9e52
v0.4.16+commit.d7661dd9
v0.4.15+commit.8b45bddb
v0.4.14+commit.c2215d46
v0.4.13+commit.0fb4cb1a
v0.4.12+commit.194ff033
v0.4.11+commit.68ef5810
v0.4.10+commit.9e8cc01b
The compiler version is specified in
pragma solidity X.X.X
. Use the compiler version rather than the nightly build. If using the Solidity compiler, run
solc —version
to check.
EVM Version
homestead
tangerineWhistle
spuriousDragon
byzantium
constantinople
petersburg
istanbul
berlin
london
paris
shanghai
default
The EVM version the contract is written for. If the bytecode does not match the version, we try to verify using the latest EVM version.
EVM version details
.
Optimization
No
Yes
If you enabled optimization during compilation, select yes.
Optimization runs
Enter the Solidity Contract Code
pragma solidity ^0.5.8; interface ILiquidityPool { function take(address _token, uint256 _amount) external; function deposit(address _token, uint256 _amount) external returns (uint256); function withdraw(address _token, uint256 _amount) external; function isEther(address _ether) external pure returns (bool); } contract Context { constructor () internal { } function _msgSender() internal view returns (address payable) { return msg.sender; } function _msgData() internal view returns (bytes memory) { this; return msg.data; } } contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor () internal { _owner = _msgSender(); emit OwnershipTransferred(address(0), _owner); } function owner() public view returns (address) { return _owner; } modifier onlyOwner() { require(isOwner(), "Ownable: caller is not the owner"); _; } function isOwner() public view returns (bool) { return _msgSender() == _owner; } function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } function transferOwnership(address newOwner) public onlyOwner { _transferOwnership(newOwner); } function _transferOwnership(address newOwner) internal { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } } interface IERC20 { function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address recipient, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } contract ERC20 is Context, IERC20 { using SafeMath for uint256; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; function totalSupply() public view returns (uint256) { return _totalSupply; } function balanceOf(address account) public view returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) public returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } function allowance(address owner, address spender) public view returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public returns (bool) { _approve(_msgSender(), spender, amount); return true; } function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } function _burn(address account, uint256 amount) internal { require(account != address(0), "ERC20: burn from the zero address"); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve(address owner, address spender, uint256 amount) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _burnFrom(address account, uint256 amount) internal { _burn(account, amount); _approve(account, _msgSender(), _allowances[account][_msgSender()].sub(amount, "ERC20: burn amount exceeds allowance")); } } library Address { function isContract(address account) internal view returns (bool) { bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; assembly { codehash := extcodehash(account) } return (codehash != 0x0 && codehash != accountHash); } function toPayable(address account) internal pure returns (address payable) { return address(uint160(account)); } function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call.value(amount)(""); require(success, "Address: unable to send value, recipient may have reverted"); } } 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 safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), "SafeERC20: call to non-contract"); (bool success, bytes memory returndata) = address(token).call(data); require(success, "SafeERC20: low-level call failed"); if (returndata.length > 0) { require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } } contract CanReclaimTokens is Ownable { using SafeERC20 for ERC20; mapping(address => bool) private recoverableTokensBlacklist; function blacklistRecoverableToken(address _token) public onlyOwner { recoverableTokensBlacklist[_token] = true; } function recoverTokens(address _token) external onlyOwner { require(!recoverableTokensBlacklist[_token], "CanReclaimTokens: token is not recoverable"); if (_token == address(0x0)) { msg.sender.transfer(address(this).balance); } else { ERC20(_token).safeTransfer(msg.sender, ERC20(_token).balanceOf(address(this))); } } } library Roles { struct Role { mapping (address => bool) bearer; } function add(Role storage role, address account) internal { require(!has(role, account), "Roles: account already has role"); role.bearer[account] = true; } function remove(Role storage role, address account) internal { require(has(role, account), "Roles: account does not have role"); role.bearer[account] = false; } function has(Role storage role, address account) internal view returns (bool) { require(account != address(0), "Roles: account is the zero address"); return role.bearer[account]; } } contract MinterRole is Context { using Roles for Roles.Role; event MinterAdded(address indexed account); event MinterRemoved(address indexed account); Roles.Role private _minters; constructor () internal { _addMinter(_msgSender()); } modifier onlyMinter() { require(isMinter(_msgSender()), "MinterRole: caller does not have the Minter role"); _; } function isMinter(address account) public view returns (bool) { return _minters.has(account); } function addMinter(address account) public onlyMinter { _addMinter(account); } function renounceMinter() public { _removeMinter(_msgSender()); } function _addMinter(address account) internal { _minters.add(account); emit MinterAdded(account); } function _removeMinter(address account) internal { _minters.remove(account); emit MinterRemoved(account); } } contract ERC20Mintable is ERC20, MinterRole { function mint(address account, uint256 amount) public onlyMinter returns (bool) { _mint(account, amount); return true; } } contract ERC20Burnable is Context, ERC20 { function burn(uint256 amount) public { _burn(_msgSender(), amount); } function burnFrom(address account, uint256 amount) public { _burnFrom(account, amount); } } contract PauserRole is Context { using Roles for Roles.Role; event PauserAdded(address indexed account); event PauserRemoved(address indexed account); Roles.Role private _pausers; constructor () internal { _addPauser(_msgSender()); } modifier onlyPauser() { require(isPauser(_msgSender()), "PauserRole: caller does not have the Pauser role"); _; } function isPauser(address account) public view returns (bool) { return _pausers.has(account); } function addPauser(address account) public onlyPauser { _addPauser(account); } function renouncePauser() public { _removePauser(_msgSender()); } function _addPauser(address account) internal { _pausers.add(account); emit PauserAdded(account); } function _removePauser(address account) internal { _pausers.remove(account); emit PauserRemoved(account); } } contract Pausable is Context, PauserRole { event Paused(address account); event Unpaused(address account); bool private _paused; constructor () internal { _paused = false; } function paused() public view returns (bool) { return _paused; } modifier whenNotPaused() { require(!_paused, "Pausable: paused"); _; } modifier whenPaused() { require(_paused, "Pausable: not paused"); _; } function pause() public onlyPauser whenNotPaused { _paused = true; emit Paused(_msgSender()); } function unpause() public onlyPauser whenPaused { _paused = false; emit Unpaused(_msgSender()); } } contract ERC20Pausable is ERC20, Pausable { function transfer(address to, uint256 value) public whenNotPaused returns (bool) { return super.transfer(to, value); } function transferFrom(address from, address to, uint256 value) public whenNotPaused returns (bool) { return super.transferFrom(from, to, value); } function approve(address spender, uint256 value) public whenNotPaused returns (bool) { return super.approve(spender, value); } function increaseAllowance(address spender, uint256 addedValue) public whenNotPaused returns (bool) { return super.increaseAllowance(spender, addedValue); } function decreaseAllowance(address spender, uint256 subtractedValue) public whenNotPaused returns (bool) { return super.decreaseAllowance(spender, subtractedValue); } } contract Token is ERC20Pausable, ERC20Mintable, ERC20Burnable, Ownable, CanReclaimTokens { string private _name; string private _symbol; uint8 private _decimals; event LogRenamed(string _name, string _symbol); constructor (string memory name, string memory symbol, uint8 decimals) public { _name = name; _symbol = symbol; _decimals = decimals; } function name() public view returns (string memory) { return _name; } function symbol() public view returns (string memory) { return _symbol; } function decimals() public view returns (uint8) { return _decimals; } function rename(string calldata name_, string calldata symbol_) external onlyOwner { _name = name_; _symbol = symbol_; emit LogRenamed(name_, symbol_); } } interface ComptrollerInterface { function isComptroller() external view returns (bool); function enterMarkets(address[] calldata cTokens) external returns (uint[] memory); function exitMarket(address cToken) external returns (uint); function mintAllowed(address cToken, address minter, uint mintAmount) external returns (uint); function mintVerify(address cToken, address minter, uint mintAmount, uint mintTokens) external; function redeemAllowed(address cToken, address redeemer, uint redeemTokens) external returns (uint); function redeemVerify(address cToken, address redeemer, uint redeemAmount, uint redeemTokens) external; function borrowAllowed(address cToken, address borrower, uint borrowAmount) external returns (uint); function borrowVerify(address cToken, address borrower, uint borrowAmount) external; function repayBorrowAllowed( address cToken, address payer, address borrower, uint repayAmount) external returns (uint); function repayBorrowVerify( address cToken, address payer, address borrower, uint repayAmount, uint borrowerIndex) external; function liquidateBorrowAllowed( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount) external returns (uint); function liquidateBorrowVerify( address cTokenBorrowed, address cTokenCollateral, address liquidator, address borrower, uint repayAmount, uint seizeTokens) external; function seizeAllowed( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external returns (uint); function seizeVerify( address cTokenCollateral, address cTokenBorrowed, address liquidator, address borrower, uint seizeTokens) external; function transferAllowed(address cToken, address src, address dst, uint transferTokens) external returns (uint); function transferVerify(address cToken, address src, address dst, uint transferTokens) external; function liquidateCalculateSeizeTokens( address cTokenBorrowed, address cTokenCollateral, uint repayAmount) external view returns (uint, uint); } contract ComptrollerErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, COMPTROLLER_MISMATCH, INSUFFICIENT_SHORTFALL, INSUFFICIENT_LIQUIDITY, INVALID_CLOSE_FACTOR, INVALID_COLLATERAL_FACTOR, INVALID_LIQUIDATION_INCENTIVE, MARKET_NOT_ENTERED, MARKET_NOT_LISTED, MARKET_ALREADY_LISTED, MATH_ERROR, NONZERO_BORROW_BALANCE, PRICE_ERROR, REJECTION, SNAPSHOT_ERROR, TOO_MANY_ASSETS, TOO_MUCH_REPAY } enum FailureInfo { ACCEPT_ADMIN_PENDING_ADMIN_CHECK, ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK, EXIT_MARKET_BALANCE_OWED, EXIT_MARKET_REJECTION, SET_CLOSE_FACTOR_OWNER_CHECK, SET_CLOSE_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_OWNER_CHECK, SET_COLLATERAL_FACTOR_NO_EXISTS, SET_COLLATERAL_FACTOR_VALIDATION, SET_COLLATERAL_FACTOR_WITHOUT_PRICE, SET_IMPLEMENTATION_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_OWNER_CHECK, SET_LIQUIDATION_INCENTIVE_VALIDATION, SET_MAX_ASSETS_OWNER_CHECK, SET_PENDING_ADMIN_OWNER_CHECK, SET_PENDING_IMPLEMENTATION_OWNER_CHECK, SET_PRICE_ORACLE_OWNER_CHECK, SUPPORT_MARKET_EXISTS, SUPPORT_MARKET_OWNER_CHECK, SET_PAUSE_GUARDIAN_OWNER_CHECK } event Failure(uint error, uint info, uint detail); function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } } contract TokenErrorReporter { enum Error { NO_ERROR, UNAUTHORIZED, BAD_INPUT, COMPTROLLER_REJECTION, COMPTROLLER_CALCULATION_ERROR, INTEREST_RATE_MODEL_ERROR, INVALID_ACCOUNT_PAIR, INVALID_CLOSE_AMOUNT_REQUESTED, INVALID_COLLATERAL_FACTOR, MATH_ERROR, MARKET_NOT_FRESH, MARKET_NOT_LISTED, TOKEN_INSUFFICIENT_ALLOWANCE, TOKEN_INSUFFICIENT_BALANCE, TOKEN_INSUFFICIENT_CASH, TOKEN_TRANSFER_IN_FAILED, TOKEN_TRANSFER_OUT_FAILED } enum FailureInfo { ACCEPT_ADMIN_PENDING_ADMIN_CHECK, ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, BORROW_ACCRUE_INTEREST_FAILED, BORROW_CASH_NOT_AVAILABLE, BORROW_FRESHNESS_CHECK, BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, BORROW_MARKET_NOT_LISTED, BORROW_COMPTROLLER_REJECTION, LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED, LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED, LIQUIDATE_COLLATERAL_FRESHNESS_CHECK, LIQUIDATE_COMPTROLLER_REJECTION, LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX, LIQUIDATE_CLOSE_AMOUNT_IS_ZERO, LIQUIDATE_FRESHNESS_CHECK, LIQUIDATE_LIQUIDATOR_IS_BORROWER, LIQUIDATE_REPAY_BORROW_FRESH_FAILED, LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER, LIQUIDATE_SEIZE_TOO_MUCH, MINT_ACCRUE_INTEREST_FAILED, MINT_COMPTROLLER_REJECTION, MINT_EXCHANGE_CALCULATION_FAILED, MINT_EXCHANGE_RATE_READ_FAILED, MINT_FRESHNESS_CHECK, MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, MINT_TRANSFER_IN_FAILED, MINT_TRANSFER_IN_NOT_POSSIBLE, REDEEM_ACCRUE_INTEREST_FAILED, REDEEM_COMPTROLLER_REJECTION, REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, REDEEM_EXCHANGE_RATE_READ_FAILED, REDEEM_FRESHNESS_CHECK, REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, REDEEM_TRANSFER_OUT_NOT_POSSIBLE, REDUCE_RESERVES_ACCRUE_INTEREST_FAILED, REDUCE_RESERVES_ADMIN_CHECK, REDUCE_RESERVES_CASH_NOT_AVAILABLE, REDUCE_RESERVES_FRESH_CHECK, REDUCE_RESERVES_VALIDATION, REPAY_BEHALF_ACCRUE_INTEREST_FAILED, REPAY_BORROW_ACCRUE_INTEREST_FAILED, REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, REPAY_BORROW_COMPTROLLER_REJECTION, REPAY_BORROW_FRESHNESS_CHECK, REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE, SET_COLLATERAL_FACTOR_OWNER_CHECK, SET_COLLATERAL_FACTOR_VALIDATION, SET_COMPTROLLER_OWNER_CHECK, SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED, SET_INTEREST_RATE_MODEL_FRESH_CHECK, SET_INTEREST_RATE_MODEL_OWNER_CHECK, SET_MAX_ASSETS_OWNER_CHECK, SET_ORACLE_MARKET_NOT_LISTED, SET_PENDING_ADMIN_OWNER_CHECK, SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED, SET_RESERVE_FACTOR_ADMIN_CHECK, SET_RESERVE_FACTOR_FRESH_CHECK, SET_RESERVE_FACTOR_BOUNDS_CHECK, TRANSFER_COMPTROLLER_REJECTION, TRANSFER_NOT_ALLOWED, TRANSFER_NOT_ENOUGH, TRANSFER_TOO_MUCH } event Failure(uint error, uint info, uint detail); function fail(Error err, FailureInfo info) internal returns (uint) { emit Failure(uint(err), uint(info), 0); return uint(err); } function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) { emit Failure(uint(err), uint(info), opaqueError); return uint(err); } } contract CarefulMath { enum MathError { NO_ERROR, DIVISION_BY_ZERO, INTEGER_OVERFLOW, INTEGER_UNDERFLOW } function mulUInt(uint a, uint b) internal pure returns (MathError, uint) { if (a == 0) { return (MathError.NO_ERROR, 0); } uint c = a * b; if (c / a != b) { return (MathError.INTEGER_OVERFLOW, 0); } else { return (MathError.NO_ERROR, c); } } function divUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b == 0) { return (MathError.DIVISION_BY_ZERO, 0); } return (MathError.NO_ERROR, a / b); } function subUInt(uint a, uint b) internal pure returns (MathError, uint) { if (b <= a) { return (MathError.NO_ERROR, a - b); } else { return (MathError.INTEGER_UNDERFLOW, 0); } } function addUInt(uint a, uint b) internal pure returns (MathError, uint) { uint c = a + b; if (c >= a) { return (MathError.NO_ERROR, c); } else { return (MathError.INTEGER_OVERFLOW, 0); } } function addThenSubUInt(uint a, uint b, uint c) internal pure returns (MathError, uint) { (MathError err0, uint sum) = addUInt(a, b); if (err0 != MathError.NO_ERROR) { return (err0, 0); } return subUInt(sum, c); } } contract Exponential is CarefulMath { uint constant expScale = 1e18; uint constant halfExpScale = expScale/2; uint constant mantissaOne = expScale; struct Exp { uint mantissa; } function getExp(uint num, uint denom) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledNumerator) = mulUInt(num, expScale); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint rational) = divUInt(scaledNumerator, denom); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: rational})); } function addExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = addUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } function subExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError error, uint result) = subUInt(a.mantissa, b.mantissa); return (error, Exp({mantissa: result})); } function mulScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint scaledMantissa) = mulUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: scaledMantissa})); } function mulScalarTruncate(Exp memory a, uint scalar) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(product)); } function mulScalarTruncateAddUInt(Exp memory a, uint scalar, uint addend) pure internal returns (MathError, uint) { (MathError err, Exp memory product) = mulScalar(a, scalar); if (err != MathError.NO_ERROR) { return (err, 0); } return addUInt(truncate(product), addend); } function divScalar(Exp memory a, uint scalar) pure internal returns (MathError, Exp memory) { (MathError err0, uint descaledMantissa) = divUInt(a.mantissa, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return (MathError.NO_ERROR, Exp({mantissa: descaledMantissa})); } function divScalarByExp(uint scalar, Exp memory divisor) pure internal returns (MathError, Exp memory) { (MathError err0, uint numerator) = mulUInt(expScale, scalar); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } return getExp(numerator, divisor.mantissa); } function divScalarByExpTruncate(uint scalar, Exp memory divisor) pure internal returns (MathError, uint) { (MathError err, Exp memory fraction) = divScalarByExp(scalar, divisor); if (err != MathError.NO_ERROR) { return (err, 0); } return (MathError.NO_ERROR, truncate(fraction)); } function mulExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { (MathError err0, uint doubleScaledProduct) = mulUInt(a.mantissa, b.mantissa); if (err0 != MathError.NO_ERROR) { return (err0, Exp({mantissa: 0})); } (MathError err1, uint doubleScaledProductWithHalfScale) = addUInt(halfExpScale, doubleScaledProduct); if (err1 != MathError.NO_ERROR) { return (err1, Exp({mantissa: 0})); } (MathError err2, uint product) = divUInt(doubleScaledProductWithHalfScale, expScale); assert(err2 == MathError.NO_ERROR); return (MathError.NO_ERROR, Exp({mantissa: product})); } function mulExp(uint a, uint b) pure internal returns (MathError, Exp memory) { return mulExp(Exp({mantissa: a}), Exp({mantissa: b})); } function mulExp3(Exp memory a, Exp memory b, Exp memory c) pure internal returns (MathError, Exp memory) { (MathError err, Exp memory ab) = mulExp(a, b); if (err != MathError.NO_ERROR) { return (err, ab); } return mulExp(ab, c); } function divExp(Exp memory a, Exp memory b) pure internal returns (MathError, Exp memory) { return getExp(a.mantissa, b.mantissa); } function truncate(Exp memory exp) pure internal returns (uint) { return exp.mantissa / expScale; } function lessThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa < right.mantissa; } function lessThanOrEqualExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa <= right.mantissa; } function greaterThanExp(Exp memory left, Exp memory right) pure internal returns (bool) { return left.mantissa > right.mantissa; } function isZeroExp(Exp memory value) pure internal returns (bool) { return value.mantissa == 0; } } interface EIP20Interface { function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256 balance); function transfer(address dst, uint256 amount) external returns (bool success); function transferFrom(address src, address dst, uint256 amount) external returns (bool success); function approve(address spender, uint256 amount) external returns (bool success); function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); } interface EIP20NonStandardInterface { function totalSupply() external view returns (uint256); function balanceOf(address owner) external view returns (uint256 balance); function transfer(address dst, uint256 amount) external; function transferFrom(address src, address dst, uint256 amount) external; function approve(address spender, uint256 amount) external returns (bool success); function allowance(address owner, address spender) external view returns (uint256 remaining); event Transfer(address indexed from, address indexed to, uint256 amount); event Approval(address indexed owner, address indexed spender, uint256 amount); } contract ReentrancyGuard { uint256 private _guardCounter; constructor () internal { _guardCounter = 1; } modifier nonReentrant() { _guardCounter += 1; uint256 localCounter = _guardCounter; _; require(localCounter == _guardCounter, "re-entered"); } } interface InterestRateModel { function getBorrowRate(uint cash, uint borrows, uint reserves) external view returns (uint, uint); function isInterestRateModel() external view returns (bool); } contract CToken is EIP20Interface, Exponential, TokenErrorReporter, ReentrancyGuard { bool public constant isCToken = true; string public name; string public symbol; uint8 public decimals; uint internal constant borrowRateMaxMantissa = 0.0005e16; uint internal constant reserveFactorMaxMantissa = 1e18; address payable public admin; address payable public pendingAdmin; ComptrollerInterface public comptroller; InterestRateModel public interestRateModel; uint public initialExchangeRateMantissa; uint public reserveFactorMantissa; uint public accrualBlockNumber; uint public borrowIndex; uint public totalBorrows; uint public totalReserves; uint256 public totalSupply; mapping (address => uint256) internal accountTokens; mapping (address => mapping (address => uint256)) internal transferAllowances; struct BorrowSnapshot { uint principal; uint interestIndex; } mapping(address => BorrowSnapshot) internal accountBorrows; event AccrueInterest(uint interestAccumulated, uint borrowIndex, uint totalBorrows); event Mint(address minter, uint mintAmount, uint mintTokens); event Redeem(address redeemer, uint redeemAmount, uint redeemTokens); event Borrow(address borrower, uint borrowAmount, uint accountBorrows, uint totalBorrows); event RepayBorrow(address payer, address borrower, uint repayAmount, uint accountBorrows, uint totalBorrows); event LiquidateBorrow(address liquidator, address borrower, uint repayAmount, address cTokenCollateral, uint seizeTokens); event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin); event NewAdmin(address oldAdmin, address newAdmin); event NewComptroller(ComptrollerInterface oldComptroller, ComptrollerInterface newComptroller); event NewMarketInterestRateModel(InterestRateModel oldInterestRateModel, InterestRateModel newInterestRateModel); event NewReserveFactor(uint oldReserveFactorMantissa, uint newReserveFactorMantissa); event ReservesReduced(address admin, uint reduceAmount, uint newTotalReserves); constructor(ComptrollerInterface comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_) internal { initialExchangeRateMantissa = initialExchangeRateMantissa_; require(initialExchangeRateMantissa > 0, "Initial exchange rate must be greater than zero."); admin = msg.sender; uint err = _setComptroller(comptroller_); require(err == uint(Error.NO_ERROR), "Setting comptroller failed"); accrualBlockNumber = getBlockNumber(); borrowIndex = mantissaOne; err = _setInterestRateModelFresh(interestRateModel_); require(err == uint(Error.NO_ERROR), "Setting interest rate model failed"); name = name_; symbol = symbol_; decimals = decimals_; admin = admin_; } function transferTokens(address spender, address src, address dst, uint tokens) internal returns (uint) { uint allowed = comptroller.transferAllowed(address(this), src, dst, tokens); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.TRANSFER_COMPTROLLER_REJECTION, allowed); } if (src == dst) { return fail(Error.BAD_INPUT, FailureInfo.TRANSFER_NOT_ALLOWED); } uint startingAllowance = 0; if (spender == src) { startingAllowance = uint(-1); } else { startingAllowance = transferAllowances[src][spender]; } MathError mathErr; uint allowanceNew; uint srcTokensNew; uint dstTokensNew; (mathErr, allowanceNew) = subUInt(startingAllowance, tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ALLOWED); } (mathErr, srcTokensNew) = subUInt(accountTokens[src], tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_NOT_ENOUGH); } (mathErr, dstTokensNew) = addUInt(accountTokens[dst], tokens); if (mathErr != MathError.NO_ERROR) { return fail(Error.MATH_ERROR, FailureInfo.TRANSFER_TOO_MUCH); } accountTokens[src] = srcTokensNew; accountTokens[dst] = dstTokensNew; if (startingAllowance != uint(-1)) { transferAllowances[src][spender] = allowanceNew; } emit Transfer(src, dst, tokens); comptroller.transferVerify(address(this), src, dst, tokens); return uint(Error.NO_ERROR); } function transfer(address dst, uint256 amount) external nonReentrant returns (bool) { return transferTokens(msg.sender, msg.sender, dst, amount) == uint(Error.NO_ERROR); } function transferFrom(address src, address dst, uint256 amount) external nonReentrant returns (bool) { return transferTokens(msg.sender, src, dst, amount) == uint(Error.NO_ERROR); } function approve(address spender, uint256 amount) external returns (bool) { address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } function allowance(address owner, address spender) external view returns (uint256) { return transferAllowances[owner][spender]; } function balanceOf(address owner) external view returns (uint256) { return accountTokens[owner]; } function balanceOfUnderlying(address owner) external returns (uint) { Exp memory exchangeRate = Exp({mantissa: exchangeRateCurrent()}); (MathError mErr, uint balance) = mulScalarTruncate(exchangeRate, accountTokens[owner]); require(mErr == MathError.NO_ERROR); return balance; } function getAccountSnapshot(address account) external view returns (uint, uint, uint, uint) { uint cTokenBalance = accountTokens[account]; uint borrowBalance; uint exchangeRateMantissa; MathError mErr; (mErr, borrowBalance) = borrowBalanceStoredInternal(account); if (mErr != MathError.NO_ERROR) { return (uint(Error.MATH_ERROR), 0, 0, 0); } (mErr, exchangeRateMantissa) = exchangeRateStoredInternal(); if (mErr != MathError.NO_ERROR) { return (uint(Error.MATH_ERROR), 0, 0, 0); } return (uint(Error.NO_ERROR), cTokenBalance, borrowBalance, exchangeRateMantissa); } function getBlockNumber() internal view returns (uint) { return block.number; } function borrowRatePerBlock() external view returns (uint) { (uint opaqueErr, uint borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); require(opaqueErr == 0, "borrowRatePerBlock: interestRateModel.borrowRate failed"); return borrowRateMantissa; } function supplyRatePerBlock() external view returns (uint) { uint exchangeRateMantissa = exchangeRateStored(); (uint e0, uint borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); require(e0 == 0, "supplyRatePerBlock: calculating borrowRate failed"); (MathError e1, Exp memory underlying) = mulScalar(Exp({mantissa: exchangeRateMantissa}), totalSupply); require(e1 == MathError.NO_ERROR, "supplyRatePerBlock: calculating underlying failed"); (MathError e2, Exp memory borrowsPer) = divScalarByExp(totalBorrows, underlying); require(e2 == MathError.NO_ERROR, "supplyRatePerBlock: calculating borrowsPer failed"); (MathError e3, Exp memory oneMinusReserveFactor) = subExp(Exp({mantissa: mantissaOne}), Exp({mantissa: reserveFactorMantissa})); require(e3 == MathError.NO_ERROR, "supplyRatePerBlock: calculating oneMinusReserveFactor failed"); (MathError e4, Exp memory supplyRate) = mulExp3(Exp({mantissa: borrowRateMantissa}), oneMinusReserveFactor, borrowsPer); require(e4 == MathError.NO_ERROR, "supplyRatePerBlock: calculating supplyRate failed"); return supplyRate.mantissa; } function totalBorrowsCurrent() external nonReentrant returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return totalBorrows; } function borrowBalanceCurrent(address account) external nonReentrant returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return borrowBalanceStored(account); } function borrowBalanceStored(address account) public view returns (uint) { (MathError err, uint result) = borrowBalanceStoredInternal(account); require(err == MathError.NO_ERROR, "borrowBalanceStored: borrowBalanceStoredInternal failed"); return result; } function borrowBalanceStoredInternal(address account) internal view returns (MathError, uint) { MathError mathErr; uint principalTimesIndex; uint result; BorrowSnapshot storage borrowSnapshot = accountBorrows[account]; if (borrowSnapshot.principal == 0) { return (MathError.NO_ERROR, 0); } (mathErr, principalTimesIndex) = mulUInt(borrowSnapshot.principal, borrowIndex); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, result) = divUInt(principalTimesIndex, borrowSnapshot.interestIndex); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, result); } function exchangeRateCurrent() public nonReentrant returns (uint) { require(accrueInterest() == uint(Error.NO_ERROR), "accrue interest failed"); return exchangeRateStored(); } function exchangeRateStored() public view returns (uint) { (MathError err, uint result) = exchangeRateStoredInternal(); require(err == MathError.NO_ERROR, "exchangeRateStored: exchangeRateStoredInternal failed"); return result; } function exchangeRateStoredInternal() internal view returns (MathError, uint) { if (totalSupply == 0) { return (MathError.NO_ERROR, initialExchangeRateMantissa); } else { uint totalCash = getCashPrior(); uint cashPlusBorrowsMinusReserves; Exp memory exchangeRate; MathError mathErr; (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, totalSupply); if (mathErr != MathError.NO_ERROR) { return (mathErr, 0); } return (MathError.NO_ERROR, exchangeRate.mantissa); } } function getCash() external view returns (uint) { return getCashPrior(); } struct AccrueInterestLocalVars { MathError mathErr; uint opaqueErr; uint borrowRateMantissa; uint currentBlockNumber; uint blockDelta; Exp simpleInterestFactor; uint interestAccumulated; uint totalBorrowsNew; uint totalReservesNew; uint borrowIndexNew; } function accrueInterest() public returns (uint) { AccrueInterestLocalVars memory vars; (vars.opaqueErr, vars.borrowRateMantissa) = interestRateModel.getBorrowRate(getCashPrior(), totalBorrows, totalReserves); require(vars.borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high"); if (vars.opaqueErr != 0) { return failOpaque(Error.INTEREST_RATE_MODEL_ERROR, FailureInfo.ACCRUE_INTEREST_BORROW_RATE_CALCULATION_FAILED, vars.opaqueErr); } vars.currentBlockNumber = getBlockNumber(); (vars.mathErr, vars.blockDelta) = subUInt(vars.currentBlockNumber, accrualBlockNumber); assert(vars.mathErr == MathError.NO_ERROR); (vars.mathErr, vars.simpleInterestFactor) = mulScalar(Exp({mantissa: vars.borrowRateMantissa}), vars.blockDelta); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_SIMPLE_INTEREST_FACTOR_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.interestAccumulated) = mulScalarTruncate(vars.simpleInterestFactor, totalBorrows); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_ACCUMULATED_INTEREST_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.totalBorrowsNew) = addUInt(vars.interestAccumulated, totalBorrows); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_BORROWS_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.totalReservesNew) = mulScalarTruncateAddUInt(Exp({mantissa: reserveFactorMantissa}), vars.interestAccumulated, totalReserves); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_TOTAL_RESERVES_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.borrowIndexNew) = mulScalarTruncateAddUInt(vars.simpleInterestFactor, borrowIndex, borrowIndex); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.ACCRUE_INTEREST_NEW_BORROW_INDEX_CALCULATION_FAILED, uint(vars.mathErr)); } accrualBlockNumber = vars.currentBlockNumber; borrowIndex = vars.borrowIndexNew; totalBorrows = vars.totalBorrowsNew; totalReserves = vars.totalReservesNew; emit AccrueInterest(vars.interestAccumulated, vars.borrowIndexNew, totalBorrows); return uint(Error.NO_ERROR); } function mintInternal(uint mintAmount) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.MINT_ACCRUE_INTEREST_FAILED); } return mintFresh(msg.sender, mintAmount); } struct MintLocalVars { Error err; MathError mathErr; uint exchangeRateMantissa; uint mintTokens; uint totalSupplyNew; uint accountTokensNew; } function mintFresh(address minter, uint mintAmount) internal returns (uint) { uint allowed = comptroller.mintAllowed(address(this), minter, mintAmount); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.MINT_COMPTROLLER_REJECTION, allowed); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.MINT_FRESHNESS_CHECK); } MintLocalVars memory vars; vars.err = checkTransferIn(minter, mintAmount); if (vars.err != Error.NO_ERROR) { return fail(vars.err, FailureInfo.MINT_TRANSFER_IN_NOT_POSSIBLE); } (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.mintTokens) = divScalarByExpTruncate(mintAmount, Exp({mantissa: vars.exchangeRateMantissa})); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_EXCHANGE_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.totalSupplyNew) = addUInt(totalSupply, vars.mintTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.accountTokensNew) = addUInt(accountTokens[minter], vars.mintTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.MINT_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } vars.err = doTransferIn(minter, mintAmount); if (vars.err != Error.NO_ERROR) { return fail(vars.err, FailureInfo.MINT_TRANSFER_IN_FAILED); } totalSupply = vars.totalSupplyNew; accountTokens[minter] = vars.accountTokensNew; emit Mint(minter, mintAmount, vars.mintTokens); emit Transfer(address(this), minter, vars.mintTokens); comptroller.mintVerify(address(this), minter, mintAmount, vars.mintTokens); return uint(Error.NO_ERROR); } function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); } return redeemFresh(msg.sender, redeemTokens, 0); } function redeemUnderlyingInternal(uint redeemAmount) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.REDEEM_ACCRUE_INTEREST_FAILED); } return redeemFresh(msg.sender, 0, redeemAmount); } struct RedeemLocalVars { Error err; MathError mathErr; uint exchangeRateMantissa; uint redeemTokens; uint redeemAmount; uint totalSupplyNew; uint accountTokensNew; } function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) { require(redeemTokensIn == 0 || redeemAmountIn == 0, "one of redeemTokensIn or redeemAmountIn must be zero"); RedeemLocalVars memory vars; (vars.mathErr, vars.exchangeRateMantissa) = exchangeRateStoredInternal(); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_RATE_READ_FAILED, uint(vars.mathErr)); } if (redeemTokensIn > 0) { vars.redeemTokens = redeemTokensIn; (vars.mathErr, vars.redeemAmount) = mulScalarTruncate(Exp({mantissa: vars.exchangeRateMantissa}), redeemTokensIn); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_TOKENS_CALCULATION_FAILED, uint(vars.mathErr)); } } else { (vars.mathErr, vars.redeemTokens) = divScalarByExpTruncate(redeemAmountIn, Exp({mantissa: vars.exchangeRateMantissa})); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_EXCHANGE_AMOUNT_CALCULATION_FAILED, uint(vars.mathErr)); } vars.redeemAmount = redeemAmountIn; } uint allowed = comptroller.redeemAllowed(address(this), redeemer, vars.redeemTokens); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REDEEM_COMPTROLLER_REJECTION, allowed); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDEEM_FRESHNESS_CHECK); } (vars.mathErr, vars.totalSupplyNew) = subUInt(totalSupply, vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_TOTAL_SUPPLY_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.accountTokensNew) = subUInt(accountTokens[redeemer], vars.redeemTokens); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REDEEM_NEW_ACCOUNT_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } if (getCashPrior() < vars.redeemAmount) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDEEM_TRANSFER_OUT_NOT_POSSIBLE); } vars.err = doTransferOut(redeemer, vars.redeemAmount); require(vars.err == Error.NO_ERROR, "redeem transfer out failed"); totalSupply = vars.totalSupplyNew; accountTokens[redeemer] = vars.accountTokensNew; emit Transfer(redeemer, address(this), vars.redeemTokens); emit Redeem(redeemer, vars.redeemAmount, vars.redeemTokens); comptroller.redeemVerify(address(this), redeemer, vars.redeemAmount, vars.redeemTokens); return uint(Error.NO_ERROR); } function borrowInternal(uint borrowAmount) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.BORROW_ACCRUE_INTEREST_FAILED); } return borrowFresh(msg.sender, borrowAmount); } struct BorrowLocalVars { Error err; MathError mathErr; uint accountBorrows; uint accountBorrowsNew; uint totalBorrowsNew; } function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) { uint allowed = comptroller.borrowAllowed(address(this), borrower, borrowAmount); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.BORROW_COMPTROLLER_REJECTION, allowed); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.BORROW_FRESHNESS_CHECK); } if (getCashPrior() < borrowAmount) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.BORROW_CASH_NOT_AVAILABLE); } BorrowLocalVars memory vars; (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.accountBorrowsNew) = addUInt(vars.accountBorrows, borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.totalBorrowsNew) = addUInt(totalBorrows, borrowAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } vars.err = doTransferOut(borrower, borrowAmount); require(vars.err == Error.NO_ERROR, "borrow transfer out failed"); accountBorrows[borrower].principal = vars.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; emit Borrow(borrower, borrowAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); comptroller.borrowVerify(address(this), borrower, borrowAmount); return uint(Error.NO_ERROR); } function repayBorrowInternal(uint repayAmount) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.REPAY_BORROW_ACCRUE_INTEREST_FAILED); } return repayBorrowFresh(msg.sender, msg.sender, repayAmount); } function repayBorrowBehalfInternal(address borrower, uint repayAmount) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.REPAY_BEHALF_ACCRUE_INTEREST_FAILED); } return repayBorrowFresh(msg.sender, borrower, repayAmount); } struct RepayBorrowLocalVars { Error err; MathError mathErr; uint repayAmount; uint borrowerIndex; uint accountBorrows; uint accountBorrowsNew; uint totalBorrowsNew; } function repayBorrowFresh(address payer, address borrower, uint repayAmount) internal returns (uint) { uint allowed = comptroller.repayBorrowAllowed(address(this), payer, borrower, repayAmount); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.REPAY_BORROW_COMPTROLLER_REJECTION, allowed); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.REPAY_BORROW_FRESHNESS_CHECK); } RepayBorrowLocalVars memory vars; vars.borrowerIndex = accountBorrows[borrower].interestIndex; (vars.mathErr, vars.accountBorrows) = borrowBalanceStoredInternal(borrower); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_ACCUMULATED_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } if (repayAmount == uint(-1)) { vars.repayAmount = vars.accountBorrows; } else { vars.repayAmount = repayAmount; } vars.err = checkTransferIn(payer, vars.repayAmount); if (vars.err != Error.NO_ERROR) { return fail(vars.err, FailureInfo.REPAY_BORROW_TRANSFER_IN_NOT_POSSIBLE); } (vars.mathErr, vars.accountBorrowsNew) = subUInt(vars.accountBorrows, vars.repayAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_NEW_ACCOUNT_BORROW_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } (vars.mathErr, vars.totalBorrowsNew) = subUInt(totalBorrows, vars.repayAmount); if (vars.mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.REPAY_BORROW_NEW_TOTAL_BALANCE_CALCULATION_FAILED, uint(vars.mathErr)); } vars.err = doTransferIn(payer, vars.repayAmount); require(vars.err == Error.NO_ERROR, "repay borrow transfer in failed"); accountBorrows[borrower].principal = vars.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = vars.totalBorrowsNew; emit RepayBorrow(payer, borrower, vars.repayAmount, vars.accountBorrowsNew, vars.totalBorrowsNew); comptroller.repayBorrowVerify(address(this), payer, borrower, vars.repayAmount, vars.borrowerIndex); return uint(Error.NO_ERROR); } function liquidateBorrowInternal(address borrower, uint repayAmount, CToken cTokenCollateral) internal nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_BORROW_INTEREST_FAILED); } error = cTokenCollateral.accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.LIQUIDATE_ACCRUE_COLLATERAL_INTEREST_FAILED); } return liquidateBorrowFresh(msg.sender, borrower, repayAmount, cTokenCollateral); } function liquidateBorrowFresh(address liquidator, address borrower, uint repayAmount, CToken cTokenCollateral) internal returns (uint) { uint allowed = comptroller.liquidateBorrowAllowed(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_COMPTROLLER_REJECTION, allowed); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_FRESHNESS_CHECK); } if (cTokenCollateral.accrualBlockNumber() != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.LIQUIDATE_COLLATERAL_FRESHNESS_CHECK); } if (borrower == liquidator) { return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_LIQUIDATOR_IS_BORROWER); } if (repayAmount == 0) { return fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_ZERO); } if (repayAmount == uint(-1)) { return fail(Error.INVALID_CLOSE_AMOUNT_REQUESTED, FailureInfo.LIQUIDATE_CLOSE_AMOUNT_IS_UINT_MAX); } (uint amountSeizeError, uint seizeTokens) = comptroller.liquidateCalculateSeizeTokens(address(this), address(cTokenCollateral), repayAmount); if (amountSeizeError != 0) { return failOpaque(Error.COMPTROLLER_CALCULATION_ERROR, FailureInfo.LIQUIDATE_COMPTROLLER_CALCULATE_AMOUNT_SEIZE_FAILED, amountSeizeError); } if (seizeTokens > cTokenCollateral.balanceOf(borrower)) { return fail(Error.TOKEN_INSUFFICIENT_BALANCE, FailureInfo.LIQUIDATE_SEIZE_TOO_MUCH); } uint repayBorrowError = repayBorrowFresh(liquidator, borrower, repayAmount); if (repayBorrowError != uint(Error.NO_ERROR)) { return fail(Error(repayBorrowError), FailureInfo.LIQUIDATE_REPAY_BORROW_FRESH_FAILED); } uint seizeError = cTokenCollateral.seize(liquidator, borrower, seizeTokens); require(seizeError == uint(Error.NO_ERROR), "token seizure failed"); emit LiquidateBorrow(liquidator, borrower, repayAmount, address(cTokenCollateral), seizeTokens); comptroller.liquidateBorrowVerify(address(this), address(cTokenCollateral), liquidator, borrower, repayAmount, seizeTokens); return uint(Error.NO_ERROR); } function seize(address liquidator, address borrower, uint seizeTokens) external nonReentrant returns (uint) { uint allowed = comptroller.seizeAllowed(address(this), msg.sender, liquidator, borrower, seizeTokens); if (allowed != 0) { return failOpaque(Error.COMPTROLLER_REJECTION, FailureInfo.LIQUIDATE_SEIZE_COMPTROLLER_REJECTION, allowed); } if (borrower == liquidator) { return fail(Error.INVALID_ACCOUNT_PAIR, FailureInfo.LIQUIDATE_SEIZE_LIQUIDATOR_IS_BORROWER); } MathError mathErr; uint borrowerTokensNew; uint liquidatorTokensNew; (mathErr, borrowerTokensNew) = subUInt(accountTokens[borrower], seizeTokens); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_DECREMENT_FAILED, uint(mathErr)); } (mathErr, liquidatorTokensNew) = addUInt(accountTokens[liquidator], seizeTokens); if (mathErr != MathError.NO_ERROR) { return failOpaque(Error.MATH_ERROR, FailureInfo.LIQUIDATE_SEIZE_BALANCE_INCREMENT_FAILED, uint(mathErr)); } accountTokens[borrower] = borrowerTokensNew; accountTokens[liquidator] = liquidatorTokensNew; emit Transfer(borrower, liquidator, seizeTokens); comptroller.seizeVerify(address(this), msg.sender, liquidator, borrower, seizeTokens); return uint(Error.NO_ERROR); } function _setPendingAdmin(address payable newPendingAdmin) external returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK); } address oldPendingAdmin = pendingAdmin; pendingAdmin = newPendingAdmin; emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin); return uint(Error.NO_ERROR); } function _acceptAdmin() external returns (uint) { if (msg.sender != pendingAdmin || msg.sender == address(0)) { return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK); } address oldAdmin = admin; address oldPendingAdmin = pendingAdmin; admin = pendingAdmin; pendingAdmin = address(0); emit NewAdmin(oldAdmin, admin); emit NewPendingAdmin(oldPendingAdmin, pendingAdmin); return uint(Error.NO_ERROR); } function _setComptroller(ComptrollerInterface newComptroller) public returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_COMPTROLLER_OWNER_CHECK); } ComptrollerInterface oldComptroller = comptroller; require(newComptroller.isComptroller(), "marker method returned false"); comptroller = newComptroller; emit NewComptroller(oldComptroller, newComptroller); return uint(Error.NO_ERROR); } function _setReserveFactor(uint newReserveFactorMantissa) external nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.SET_RESERVE_FACTOR_ACCRUE_INTEREST_FAILED); } return _setReserveFactorFresh(newReserveFactorMantissa); } function _setReserveFactorFresh(uint newReserveFactorMantissa) internal returns (uint) { if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_RESERVE_FACTOR_ADMIN_CHECK); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_RESERVE_FACTOR_FRESH_CHECK); } if (newReserveFactorMantissa > reserveFactorMaxMantissa) { return fail(Error.BAD_INPUT, FailureInfo.SET_RESERVE_FACTOR_BOUNDS_CHECK); } uint oldReserveFactorMantissa = reserveFactorMantissa; reserveFactorMantissa = newReserveFactorMantissa; emit NewReserveFactor(oldReserveFactorMantissa, newReserveFactorMantissa); return uint(Error.NO_ERROR); } function _reduceReserves(uint reduceAmount) external nonReentrant returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.REDUCE_RESERVES_ACCRUE_INTEREST_FAILED); } return _reduceReservesFresh(reduceAmount); } function _reduceReservesFresh(uint reduceAmount) internal returns (uint) { Error err; uint totalReservesNew; if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.REDUCE_RESERVES_ADMIN_CHECK); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.REDUCE_RESERVES_FRESH_CHECK); } if (getCashPrior() < reduceAmount) { return fail(Error.TOKEN_INSUFFICIENT_CASH, FailureInfo.REDUCE_RESERVES_CASH_NOT_AVAILABLE); } if (reduceAmount > totalReserves) { return fail(Error.BAD_INPUT, FailureInfo.REDUCE_RESERVES_VALIDATION); } totalReservesNew = totalReserves - reduceAmount; require(totalReservesNew <= totalReserves, "reduce reserves unexpected underflow"); totalReserves = totalReservesNew; err = doTransferOut(admin, reduceAmount); require(err == Error.NO_ERROR, "reduce reserves transfer out failed"); emit ReservesReduced(admin, reduceAmount, totalReservesNew); return uint(Error.NO_ERROR); } function _setInterestRateModel(InterestRateModel newInterestRateModel) public returns (uint) { uint error = accrueInterest(); if (error != uint(Error.NO_ERROR)) { return fail(Error(error), FailureInfo.SET_INTEREST_RATE_MODEL_ACCRUE_INTEREST_FAILED); } return _setInterestRateModelFresh(newInterestRateModel); } function _setInterestRateModelFresh(InterestRateModel newInterestRateModel) internal returns (uint) { InterestRateModel oldInterestRateModel; if (msg.sender != admin) { return fail(Error.UNAUTHORIZED, FailureInfo.SET_INTEREST_RATE_MODEL_OWNER_CHECK); } if (accrualBlockNumber != getBlockNumber()) { return fail(Error.MARKET_NOT_FRESH, FailureInfo.SET_INTEREST_RATE_MODEL_FRESH_CHECK); } oldInterestRateModel = interestRateModel; require(newInterestRateModel.isInterestRateModel(), "marker method returned false"); interestRateModel = newInterestRateModel; emit NewMarketInterestRateModel(oldInterestRateModel, newInterestRateModel); return uint(Error.NO_ERROR); } function getCashPrior() internal view returns (uint); function checkTransferIn(address from, uint amount) internal view returns (Error); function doTransferIn(address from, uint amount) internal returns (Error); function doTransferOut(address payable to, uint amount) internal returns (Error); } contract CErc20 is CToken { address public underlying; constructor(address underlying_, ComptrollerInterface comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_) public CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_) { underlying = underlying_; EIP20Interface(underlying).totalSupply(); } function mint(uint mintAmount) external returns (uint) { return mintInternal(mintAmount); } function redeem(uint redeemTokens) external returns (uint) { return redeemInternal(redeemTokens); } function redeemUnderlying(uint redeemAmount) external returns (uint) { return redeemUnderlyingInternal(redeemAmount); } function borrow(uint borrowAmount) external returns (uint) { return borrowInternal(borrowAmount); } function repayBorrow(uint repayAmount) external returns (uint) { return repayBorrowInternal(repayAmount); } function repayBorrowBehalf(address borrower, uint repayAmount) external returns (uint) { return repayBorrowBehalfInternal(borrower, repayAmount); } function liquidateBorrow(address borrower, uint repayAmount, CToken cTokenCollateral) external returns (uint) { return liquidateBorrowInternal(borrower, repayAmount, cTokenCollateral); } function getCashPrior() internal view returns (uint) { EIP20Interface token = EIP20Interface(underlying); return token.balanceOf(address(this)); } function checkTransferIn(address from, uint amount) internal view returns (Error) { EIP20Interface token = EIP20Interface(underlying); if (token.allowance(from, address(this)) < amount) { return Error.TOKEN_INSUFFICIENT_ALLOWANCE; } if (token.balanceOf(from) < amount) { return Error.TOKEN_INSUFFICIENT_BALANCE; } return Error.NO_ERROR; } function doTransferIn(address from, uint amount) internal returns (Error) { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); bool result; token.transferFrom(from, address(this), amount); assembly { switch returndatasize() case 0 { result := not(0) } case 32 { returndatacopy(0, 0, 32) result := mload(0) } default { revert(0, 0) } } if (!result) { return Error.TOKEN_TRANSFER_IN_FAILED; } return Error.NO_ERROR; } function doTransferOut(address payable to, uint amount) internal returns (Error) { EIP20NonStandardInterface token = EIP20NonStandardInterface(underlying); bool result; token.transfer(to, amount); assembly { switch returndatasize() case 0 { result := not(0) } case 32 { returndatacopy(0, 0, 32) result := mload(0) } default { revert(0, 0) } } if (!result) { return Error.TOKEN_TRANSFER_OUT_FAILED; } return Error.NO_ERROR; } } contract CEther is CToken { constructor(ComptrollerInterface comptroller_, InterestRateModel interestRateModel_, uint initialExchangeRateMantissa_, string memory name_, string memory symbol_, uint8 decimals_, address payable admin_) public CToken(comptroller_, interestRateModel_, initialExchangeRateMantissa_, name_, symbol_, decimals_, admin_) {} function mint() external payable { requireNoError(mintInternal(msg.value), "mint failed"); } function redeem(uint redeemTokens) external returns (uint) { return redeemInternal(redeemTokens); } function redeemUnderlying(uint redeemAmount) external returns (uint) { return redeemUnderlyingInternal(redeemAmount); } function borrow(uint borrowAmount) external returns (uint) { return borrowInternal(borrowAmount); } function repayBorrow() external payable { requireNoError(repayBorrowInternal(msg.value), "repayBorrow failed"); } function repayBorrowBehalf(address borrower) external payable { requireNoError(repayBorrowBehalfInternal(borrower, msg.value), "repayBorrowBehalf failed"); } function liquidateBorrow(address borrower, CToken cTokenCollateral) external payable { requireNoError(liquidateBorrowInternal(borrower, msg.value, cTokenCollateral), "liquidateBorrow failed"); } function () external payable { requireNoError(mintInternal(msg.value), "mint failed"); } function getCashPrior() internal view returns (uint) { (MathError err, uint startingBalance) = subUInt(address(this).balance, msg.value); require(err == MathError.NO_ERROR); return startingBalance; } function checkTransferIn(address from, uint amount) internal view returns (Error) { require(msg.sender == from, "sender mismatch"); require(msg.value == amount, "value mismatch"); return Error.NO_ERROR; } function doTransferIn(address from, uint amount) internal returns (Error) { require(msg.sender == from, "sender mismatch"); require(msg.value == amount, "value mismatch"); return Error.NO_ERROR; } function doTransferOut(address payable to, uint amount) internal returns (Error) { to.transfer(amount); return Error.NO_ERROR; } function requireNoError(uint errCode, string memory message) internal pure { if (errCode == uint(Error.NO_ERROR)) { return; } bytes memory fullMessage = new bytes(bytes(message).length + 5); uint i; for (i = 0; i < bytes(message).length; i++) { fullMessage[i] = bytes(message)[i]; } fullMessage[i+0] = byte(uint8(32)); fullMessage[i+1] = byte(uint8(40)); fullMessage[i+2] = byte(uint8(48 + ( errCode / 10 ))); fullMessage[i+3] = byte(uint8(48 + ( errCode % 10 ))); fullMessage[i+4] = byte(uint8(41)); require(errCode == uint(Error.NO_ERROR), string(fullMessage)); } } contract LiquidityPool is Ownable, ILiquidityPool, CanReclaimTokens { using SafeMath for uint256; using SafeERC20 for ERC20; CEther public cEther; mapping (address=>CErc20) public cTokens; ERC20 public liquidityToken; Token public liquidityShareToken; mapping(address => bool) public whitelisted; constructor(ERC20 _liquidityToken, Token _liquidityShareToken) public { liquidityToken = _liquidityToken; liquidityShareToken = _liquidityShareToken; } function () external payable {} function register(address _underlying, address _cToken) external onlyOwner { require(_underlying != address(0x0), "Underlying asset cannot be 0x0"); address[] memory cTokenAddrs = new address[](1); cTokenAddrs[0] = _cToken; if (isEther(_underlying)) { cEther = CEther(uint256(_cToken)); } else { cTokens[_underlying] = CErc20(_cToken); } CToken(_cToken).comptroller().enterMarkets(cTokenAddrs); if (_underlying == address(liquidityToken)) { blacklistRecoverableToken(_cToken); } } function deregister(address _underlying) external onlyOwner { if (isEther(_underlying)) { cEther.comptroller().exitMarket(address(cEther)); delete(cEther); } else { cTokens[_underlying].comptroller().exitMarket(address(cTokens[_underlying])); delete(cTokens[_underlying]); } } function updateWhitelist(address _address, bool _status) external onlyOwner { whitelisted[_address] = _status; } function deposit(address _token, uint256 _amount) external returns (uint256) { require(_token == address(liquidityToken), "Invalid token address"); liquidityToken.safeTransferFrom(msg.sender, address(this), _amount); CErc20 cToken = cTokens[address(liquidityToken)]; liquidityToken.approve(address(cToken), _amount); uint256 initialBalance = cToken.balanceOf(address(this)); cToken.mint(_amount); uint256 finalBalance = cToken.balanceOf(address(this)); uint256 liquidity = calculateExpectedLiquidity(finalBalance - initialBalance); liquidityShareToken.mint(msg.sender, liquidity); return liquidity; } function withdraw(address _token, uint256 _amount) external { require(_token == address(liquidityToken), "Invalid token address"); uint256 cTokenAmount = calculateExpectedCAmount(_amount); liquidityShareToken.burnFrom(msg.sender, _amount); require(cTokens[address(liquidityToken)].redeem(cTokenAmount) == 0, "Failed to redeem c tokens"); liquidityToken.safeTransfer(msg.sender, liquidityToken.balanceOf(address(this))); } function take(address _token, uint256 _amount) external { require(whitelisted[msg.sender], "Only whitelisted contracts can take"); if (isEther(_token)) { cEther.borrow(_amount); msg.sender.transfer(_amount); } else { cTokens[_token].borrow(_amount); ERC20(_token).safeTransfer(msg.sender, _amount); } } function isEther(address _addr) public pure returns (bool) { return (_addr == address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE)); } function calculateExpectedLiquidity(uint256 _cTokenAmount) internal view returns (uint256) { uint256 totalSupply = liquidityShareToken.totalSupply(); if (totalSupply == 0) { return _cTokenAmount; } uint256 totalLiquidity = cTokens[address(liquidityToken)].balanceOf(address(this)); return (totalSupply*_cTokenAmount)/totalLiquidity; } function calculateExpectedCAmount(uint256 _liquidityAmount) internal view returns (uint256) { uint256 totalSupply = liquidityShareToken.totalSupply(); require(totalSupply != 0, "Cannot calculate expected amount when there are no liquidity tokens"); uint256 totalLiquidity = cTokens[address(liquidityToken)].balanceOf(address(this)); return (totalLiquidity*_liquidityAmount)/totalSupply; } function destroy() external onlyOwner { cTokens[address(liquidityToken)].transfer(msg.sender, cTokens[address(liquidityToken)].balanceOf(address(this))); liquidityShareToken.addMinter(msg.sender); liquidityShareToken.renounceMinter(); selfdestruct(msg.sender); } }
We recommend using flattened code. This is necessary if your code utilizes a library or inherits dependencies. Use the
POA solidity flattener or the
truffle flattener
.
Try to fetch constructor arguments automatically
No
Yes
ABI-encoded Constructor Arguments (if required by the contract)
00000000000000000000000089d24a6b4ccb1b6faa2625fe562bdd9a23260359000000000000000000000000f79e957afd24cdb68e82687c06ef51a34a6cbaae
Add arguments in
ABI hex encoded form
. Constructor arguments are written right to left, and will be found at the end of the input created bytecode. They may also be
parsed here.
Add Contract Libraries
Contract Libraries
Library 1 Name
A library name called in the .sol file. Multiple libraries (up to 10) may be added for each contract. Click the Add Library button to add an additional one.
Library 1 Address
The 0x library address. This can be found in the generated json file or Truffle output (if using truffle).
Library 2 Name
Library 2 Address
Library 3 Name
Library 3 Address
Library 4 Name
Library 4 Address
Library 5 Name
Library 5 Address
Library 6 Name
Library 6 Address
Library 7 Name
Library 7 Address
Library 8 Name
Library 8 Address
Library 9 Name
Library 9 Address
Library 10 Name
Library 10 Address
Add Library
Loading...
Verify & publish
Cancel
Ok
Ok
Ok
No
Yes