Contract Overview
Contract Name:
FToken
Compiler Version
v0.6.4+commit.1dca32f3
pragma experimental ABIEncoderV2; pragma solidity 0.6.4; // SPDX-License-Identifier: MIT interface IInterestRateModel { function utilizationRate( uint256 cash, uint256 borrows, uint256 reserves ) external pure returns (uint256); function getBorrowRate( uint256 cash, uint256 borrows, uint256 reserves ) external view returns (uint256); function getSupplyRate( uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa ) external view returns (uint256); function APR( uint256 cash, uint256 borrows, uint256 reserves ) external view returns (uint256); function APY( uint256 cash, uint256 borrows, uint256 reserves, uint256 reserveFactorMantissa ) external view returns (uint256); } // SPDX-License-Identifier: MIT interface IBankController { function getCashPrior(address underlying) external view returns (uint256); function getCashAfter(address underlying, uint256 msgValue) external view returns (uint256); function getFTokeAddress(address underlying) external view returns (address); function transferToUser( address token, address payable user, uint256 amount ) external; function transferIn( address account, address underlying, uint256 amount ) external payable; function borrowCheck( address account, address underlying, address fToken, uint256 borrowAmount ) external; function repayCheck(address underlying) external; function liquidateBorrowCheck( address fTokenBorrowed, address fTokenCollateral, address borrower, address liquidator, uint256 repayAmount ) external; function liquidateTokens( address fTokenBorrowed, address fTokenCollateral, uint256 actualRepayAmount ) external view returns (uint256); function withdrawCheck( address fToken, address withdrawer, uint256 withdrawTokens ) external view returns (uint256); function transferCheck( address fToken, address src, address dst, uint256 transferTokens ) external; function marketsContains(address fToken) external view returns (bool); function seizeCheck(address cTokenCollateral, address cTokenBorrowed) external; function mintCheck(address underlying, address minter, uint256 amount) external; function addReserves(address underlying, uint256 addAmount) external payable; function reduceReserves( address underlying, address payable account, uint256 reduceAmount ) external; function calcMaxBorrowAmount(address user, address token) external view returns (uint256); function calcMaxWithdrawAmount(address user, address token) external view returns (uint256); function calcMaxCashOutAmount(address user, address token) external view returns (uint256); function calcMaxBorrowAmountWithRatio(address user, address token) external view returns (uint256); function transferEthGasCost() external view returns (uint256); function isFTokenValid(address fToken) external view returns (bool); function balance(address token) external view returns (uint256); function flashloanFeeBips() external view returns (uint256); function flashloanVault() external view returns (address); function transferFlashloanAsset( address token, address payable user, uint256 amount ) external; } // SPDX-License-Identifier: MIT /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ 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) { 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; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a <= b ? a : b; } function abs(uint256 a, uint256 b) internal pure returns (uint256) { if (a < b) { return b - a; } return a - b; } } // SPDX-License-Identifier: MIT contract Exponential { uint256 constant expScale = 1e18; uint256 constant doubleScale = 1e36; uint256 constant halfExpScale = expScale / 2; using SafeMath for uint256; function getExp(uint256 num, uint256 denom) public pure returns (uint256 rational) { rational = num.mul(expScale).div(denom); } function getDiv(uint256 num, uint256 denom) public pure returns (uint256 rational) { rational = num.mul(expScale).div(denom); } function addExp(uint256 a, uint256 b) public pure returns (uint256 result) { result = a.add(b); } function subExp(uint256 a, uint256 b) public pure returns (uint256 result) { result = a.sub(b); } function mulExp(uint256 a, uint256 b) public pure returns (uint256) { uint256 doubleScaledProduct = a.mul(b); uint256 doubleScaledProductWithHalfScale = halfExpScale.add( doubleScaledProduct ); return doubleScaledProductWithHalfScale.div(expScale); } function divExp(uint256 a, uint256 b) public pure returns (uint256) { return getDiv(a, b); } function mulExp3( uint256 a, uint256 b, uint256 c ) public pure returns (uint256) { return mulExp(mulExp(a, b), c); } function mulScalar(uint256 a, uint256 scalar) public pure returns (uint256 scaled) { scaled = a.mul(scalar); } function mulScalarTruncate(uint256 a, uint256 scalar) public pure returns (uint256) { uint256 product = mulScalar(a, scalar); return truncate(product); } function mulScalarTruncateAddUInt( uint256 a, uint256 scalar, uint256 addend ) public pure returns (uint256) { uint256 product = mulScalar(a, scalar); return truncate(product).add(addend); } function divScalarByExpTruncate(uint256 scalar, uint256 divisor) public pure returns (uint256) { uint256 fraction = divScalarByExp(scalar, divisor); return truncate(fraction); } function divScalarByExp(uint256 scalar, uint256 divisor) public pure returns (uint256) { uint256 numerator = expScale.mul(scalar); return getExp(numerator, divisor); } function divScalar(uint256 a, uint256 scalar) public pure returns (uint256) { return a.div(scalar); } function truncate(uint256 exp) public pure returns (uint256) { return exp.div(expScale); } } // SPDX-License-Identifier: MIT /** * @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. */ function decimals() external view returns (uint8); event Approval( address indexed owner, address indexed spender, uint256 value ); } // SPDX-License-Identifier: MIT /** * @dev Collection of functions related to the address type */ 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) { // This method relies in extcodesize, which returns 0 for contracts in // construction, since the code is only stored at the end of the // constructor execution. uint256 size; // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } /** * @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" ); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain`call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, "Address: low-level call with value failed" ); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require( address(this).balance >= value, "Address: insufficient balance for call" ); return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}( data ); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } // SPDX-License-Identifier: MIT /** * @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) ); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' // solhint-disable-next-line max-line-length 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 ) ); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall( data, "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" ); } } } // SPDX-License-Identifier: MIT library EthAddressLib { /** * @dev returns the address used within the protocol to identify ETH * @return the address assigned to ETH */ function ethAddress() internal pure returns (address) { return 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; } } // SPDX-License-Identifier: MIT interface IFToken is IERC20 { function mint(address user, uint256 amount) external returns (bytes memory); function borrow(address borrower, uint256 borrowAmount) external returns (bytes memory); function withdraw( address payable withdrawer, uint256 withdrawTokensIn, uint256 withdrawAmountIn ) external returns (uint256, bytes memory); function underlying() external view returns (address); function accrueInterest() external; function getAccountState(address account) external view returns ( uint256, uint256, uint256 ); function MonitorEventCallback( address who, bytes32 funcName, bytes calldata payload ) external; //用户存借取还操作后的兑换率 function exchangeRateCurrent() external view returns (uint256 exchangeRate); function repay(address borrower, uint256 repayAmount) external returns (uint256, bytes memory); function borrowBalanceStored(address account) external view returns (uint256); function exchangeRateStored() external view returns (uint256 exchangeRate); function liquidateBorrow( address liquidator, address borrower, uint256 repayAmount, address fTokenCollateral ) external returns (bytes memory); function borrowBalanceCurrent(address account) external returns (uint256); function balanceOfUnderlying(address owner) external returns (uint256); function _reduceReserves(uint256 reduceAmount) external; function _addReservesFresh(uint256 addAmount) external; function cancellingOut(address striker) external returns (bool strikeOk, bytes memory strikeLog); function APR() external view returns (uint256); function APY() external view returns (uint256); function calcBalanceOfUnderlying(address owner) external view returns (uint256); function borrowSafeRatio() external view returns (uint256); function tokenCash(address token, address account) external view returns (uint256); function getBorrowRate() external view returns (uint256); function addTotalCash(uint256 _addAmount) external; function subTotalCash(uint256 _subAmount) external; function totalCash() external view returns (uint256); function totalReserves() external view returns (uint256); function totalBorrows() external view returns (uint256); } // SPDX-License-Identifier: MIT interface IBank { function MonitorEventCallback(bytes32 funcName, bytes calldata payload) external; function deposit(address token, uint256 amount) external payable; function borrow(address token, uint256 amount) external; function withdraw(address underlying, uint256 withdrawTokens) external; function withdrawUnderlying(address underlying, uint256 amount) external; function repay(address token, uint256 amount) external payable; function liquidateBorrow( address borrower, address underlyingBorrow, address underlyingCollateral, uint256 repayAmount ) external payable; function tokenIn(address token, uint256 amountIn) external payable; function tokenOut(address token, uint256 amountOut) external; function cancellingOut(address token) external; function paused() external view returns (bool); } /** * @title Initializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. */ contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private initializing; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized"); bool isTopLevelCall = !initializing; if (isTopLevelCall) { initializing = true; initialized = true; } _; if (isTopLevelCall) { initializing = false; } } /// @dev Returns true if and only if the function is running in the constructor function isConstructor() private view returns (bool) { // extcodesize checks the size of the code stored in an address, and // address returns the current address. Since the code is still not // deployed when running a constructor, any checks on its code size will // yield zero, making it an effective way to detect if a contract is // under construction or not. address self = address(this); uint256 cs; assembly { cs := extcodesize(self) } return cs == 0; } // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; } // SPDX-License-Identifier: MIT contract FToken is Exponential, Initializable { using SafeERC20 for IERC20; uint256 public totalSupply; string public name; string public symbol; uint8 public decimals; mapping(address => mapping(address => uint256)) internal transferAllowances; uint256 public initialExchangeRate; address public admin; uint256 public totalBorrows; uint256 public totalReserves; uint256 public reserveFactor; uint256 public borrowIndex; uint256 internal constant borrowRateMax = 0.0005e16; uint256 public accrualBlockNumber; IInterestRateModel public interestRateModel; // 该 fToken 所代表的原生代币 address public underlying; mapping(address => uint256) public accountTokens; IBankController public controller; uint256 public borrowSafeRatio; address public bank; // bank主合约入口地址 bool internal _notEntered; uint256 public constant ONE = 1e18; // 借款人账户 struct BorrowSnapshot { uint256 principal; uint256 interestIndex; } mapping(address => BorrowSnapshot) public accountBorrows; uint256 public totalCash; event Transfer(address indexed from, address indexed to, uint256 value); event NewInterestRateModel(address oldIRM, uint256 oldUR, uint256 oldAPR, uint256 oldAPY, uint256 exRate1, address newIRM, uint256 newUR, uint256 newAPR, uint256 newAPY, uint256 exRate2 ); event NewInitialExchangeRate(uint256 oldInitialExchangeRate, uint256 oldUR, uint256 oldAPR, uint256 oldAPY, uint256 exRate1, uint256 _initialExchangeRate, uint256 newUR, uint256 newAPR, uint256 newAPY, uint256 exRate2); event Approval( address indexed owner, address indexed spender, uint256 value ); function initialize( uint256 _initialExchangeRate, address _controller, address _initialInterestRateModel, address _underlying, address _bank, uint256 _borrowSafeRatio, string memory _name, string memory _symbol, uint8 _decimals ) public initializer { initialExchangeRate = _initialExchangeRate; controller = IBankController(_controller); interestRateModel = IInterestRateModel(_initialInterestRateModel); admin = msg.sender; underlying = _underlying; borrowSafeRatio = _borrowSafeRatio; accrualBlockNumber = getBlockNumber(); borrowIndex = ONE; bank = _bank; name = _name; symbol = _symbol; decimals = _decimals; _notEntered = true; } modifier onlyAdmin { require(msg.sender == admin, "require admin"); _; } modifier onlyBank { require(msg.sender == bank, "require admin"); _; } modifier onlyController { require(msg.sender == address(controller), "require controller"); _; } modifier onlyRestricted { require( msg.sender == admin || msg.sender == bank || msg.sender == address(controller) || controller.marketsContains(msg.sender), "only restricted user" ); _; } modifier onlyBankComponent { require( msg.sender == bank || msg.sender == address(controller) || msg.sender == address(this) || controller.marketsContains(msg.sender), "only bank component" ); _; } modifier whenUnpaused { require(!IBank(bank).paused(), "System paused"); _; } function _setController(address _controller) external onlyAdmin { controller = IBankController(_controller); } function tokenCash(address token, address account) public view returns (uint256) { return token != EthAddressLib.ethAddress() ? IERC20(token).balanceOf(account) : address(account).balance; } struct TransferLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_transferred; uint256 account_balance; address payee_address; uint256 payee_balance; uint256 global_token_reserved; } /** * @notice Transfer `amount` tokens from `msg.sender` to `dst` * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transfer(address dst, uint256 amount) external nonReentrant returns (bool) { // spender - src - dst transferTokens(msg.sender, msg.sender, dst, amount); TransferLogStruct memory tls = TransferLogStruct( msg.sender, underlying, address(this), amount, balanceOf(msg.sender), dst, balanceOf(dst), tokenCash(underlying, address(controller)) ); IBank(bank).MonitorEventCallback("Transfer", abi.encode(tls)); return true; } /** * @notice Transfer `amount` tokens from `src` to `dst` * @param src The address of the source account * @param dst The address of the destination account * @param amount The number of tokens to transfer */ function transferFrom( address src, address dst, uint256 amount ) external nonReentrant returns (bool) { // spender - src - dst transferTokens(msg.sender, src, dst, amount); TransferLogStruct memory tls = TransferLogStruct( src, underlying, address(this), amount, balanceOf(src), dst, balanceOf(dst), tokenCash(underlying, address(controller)) ); IBank(bank).MonitorEventCallback("TransferFrom", abi.encode(tls)); return true; } // tokens -> 转账的 fToken 的数量 function transferTokens( address spender, address src, address dst, uint256 tokens ) internal whenUnpaused returns (bool) { //accrueInterest(); controller.transferCheck(address(this), src, dst, mulScalarTruncate(tokens, borrowSafeRatio)); require(src != dst, "Cannot transfer to self"); uint256 startingAllowance = 0; if (spender == src) { startingAllowance = uint256(-1); } else { startingAllowance = transferAllowances[src][spender]; } uint256 allowanceNew = startingAllowance.sub(tokens); accountTokens[src] = accountTokens[src].sub(tokens); accountTokens[dst] = accountTokens[dst].add(tokens); if (startingAllowance != uint256(-1)) { transferAllowances[src][spender] = allowanceNew; } emit Transfer(src, dst, tokens); return true; } /** * @notice Approve `spender` to transfer up to `amount` from `src` * @dev This will overwrite the approval amount for `spender` * and is subject to issues noted [here](https://eips.ethereum.org/EIPS/eip-20#approve) * @param spender The address of the account which may transfer tokens * @param amount The number of tokens that are approved (-1 means infinite) */ function approve(address spender, uint256 amount) external returns (bool) { address src = msg.sender; transferAllowances[src][spender] = amount; emit Approval(src, spender, amount); return true; } /** * @notice Get the current allowance from `owner` for `spender` * @param owner The address of the account which owns the tokens to be spent * @param spender The address of the account which may transfer tokens */ function allowance(address owner, address spender) external view returns (uint256) { return transferAllowances[owner][spender]; } struct MintLocals { uint256 exchangeRate; uint256 mintTokens; uint256 totalSupplyNew; uint256 accountTokensNew; uint256 actualMintAmount; } struct DepositLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_deposited; uint256 underlying_deposited; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_balance; uint256 global_token_reserved; } // 存款记账 function mint(address user, uint256 amount) external onlyBank nonReentrant returns (bytes memory) { accrueInterest(); return mintInternal(user, amount); } // 存款记账 function mintInternal(address user, uint256 amount) internal returns (bytes memory) { require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); MintLocals memory tmp; controller.mintCheck(underlying, user, amount); tmp.exchangeRate = exchangeRateStored(); tmp.mintTokens = divScalarByExpTruncate(amount, tmp.exchangeRate); tmp.totalSupplyNew = addExp(totalSupply, tmp.mintTokens); tmp.accountTokensNew = addExp(accountTokens[user], tmp.mintTokens); totalSupply = tmp.totalSupplyNew; accountTokens[user] = tmp.accountTokensNew; uint256 preCalcTokenCash = tokenCash(underlying, address(controller)) .add(amount); DepositLogStruct memory dls = DepositLogStruct( user, underlying, address(this), tmp.mintTokens, amount, exchangeRateAfter(amount), //cheque_token_value, 存之后的交换率(预判) interestRateModel.getBorrowRate( preCalcTokenCash, totalBorrows, totalReserves ), //loan_interest_rate 借款利率,存之后的价款利率 tokenCash(address(this), user), preCalcTokenCash ); emit Transfer(address(0), user, tmp.mintTokens); return abi.encode(dls); } struct BorrowLocals { uint256 accountBorrows; uint256 accountBorrowsNew; uint256 totalBorrowsNew; } struct BorrowLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_borrowed; uint256 interest_accrued; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_debt; uint256 global_token_reserved; } // 用户借钱 function borrow(address payable borrower, uint256 borrowAmount) external onlyBank nonReentrant returns (bytes memory) { accrueInterest(); return borrowInternal(borrower, borrowAmount); } // 用户借钱 function borrowInternal(address payable borrower, uint256 borrowAmount) internal returns (bytes memory) { controller.borrowCheck( borrower, underlying, address(this), mulScalarTruncate(borrowAmount, borrowSafeRatio) ); require( controller.getCashPrior(underlying) >= borrowAmount, "Insufficient balance" ); BorrowLocals memory tmp; uint256 lastPrincipal = accountBorrows[borrower].principal; tmp.accountBorrows = borrowBalanceStoredInternal(borrower); tmp.accountBorrowsNew = addExp(tmp.accountBorrows, borrowAmount); tmp.totalBorrowsNew = addExp(totalBorrows, borrowAmount); accountBorrows[borrower].principal = tmp.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = tmp.totalBorrowsNew; controller.transferToUser(underlying, borrower, borrowAmount); subTotalCash(borrowAmount); BorrowLogStruct memory bls = BorrowLogStruct( borrower, underlying, address(this), borrowAmount, SafeMath.abs(tmp.accountBorrows, lastPrincipal), exchangeRateStored(), getBorrowRate(), accountBorrows[borrower].principal, tokenCash(underlying, address(controller)) ); return abi.encode(bls); } struct RepayLocals { uint256 repayAmount; uint256 borrowerIndex; uint256 accountBorrows; uint256 accountBorrowsNew; uint256 totalBorrowsNew; uint256 actualRepayAmount; } // 计算兑换率 function exchangeRateStored() public view returns (uint256 exchangeRate) { return calcExchangeRate(totalBorrows, totalReserves); } function calcExchangeRate(uint256 _totalBorrows, uint256 _totalReserves) public view returns (uint256 exchangeRate) { uint256 _totalSupply = totalSupply; if (_totalSupply == 0) { return initialExchangeRate; } else { /* * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint256 totalCash = controller.getCashPrior(underlying); uint256 cashPlusBorrowsMinusReserves = subExp( addExp(totalCash, _totalBorrows), _totalReserves ); exchangeRate = getDiv(cashPlusBorrowsMinusReserves, _totalSupply); } } // 计算兑换率(预判),在实际转账之前调用,只是用于发事件,用户后端审计 function exchangeRateAfter(uint256 transferInAmout) public view returns (uint256 exchangeRate) { uint256 _totalSupply = totalSupply; if (_totalSupply == 0) { // 如果市场是初始化状态,那么返回初始兑换率 return initialExchangeRate; } else { /* * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply */ uint256 totalCash = controller.getCashAfter( underlying, transferInAmout ); uint256 cashPlusBorrowsMinusReserves = subExp( addExp(totalCash, totalBorrows), totalReserves ); exchangeRate = getDiv(cashPlusBorrowsMinusReserves, _totalSupply); } } function balanceOfUnderlying(address owner) external returns (uint256) { // 获取利率 uint256 exchangeRate = exchangeRateCurrent(); // 利率乘余额 uint256 balance = mulScalarTruncate(exchangeRate, accountTokens[owner]); return balance; } function calcBalanceOfUnderlying(address owner) public view returns (uint256) { (, , uint256 _totalBorrows, uint256 _trotalReserves) = peekInterest(); uint256 _exchangeRate = calcExchangeRate( _totalBorrows, _trotalReserves ); // 利率乘余额 uint256 balance = mulScalarTruncate( _exchangeRate, accountTokens[owner] ); return balance; } function exchangeRateCurrent() public nonReentrant returns (uint256) { accrueInterest(); return exchangeRateStored(); } // 获取账户信息 function getAccountState(address account) external view returns ( uint256, uint256, uint256 ) { uint256 fTokenBalance = accountTokens[account]; uint256 borrowBalance = borrowBalanceStoredInternal(account); uint256 exchangeRate = exchangeRateStored(); return (fTokenBalance, borrowBalance, exchangeRate); } struct WithdrawLocals { uint256 exchangeRate; uint256 withdrawTokens; uint256 withdrawAmount; uint256 totalSupplyNew; uint256 accountTokensNew; } struct WithdrawLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_withdrawed; uint256 underlying_withdrawed; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_balance; uint256 global_token_reserved; } // todo onlyController function withdraw( address payable withdrawer, uint256 withdrawTokensIn, uint256 withdrawAmountIn ) external onlyBank nonReentrant returns (uint256, bytes memory) { accrueInterest(); return withdrawInternal(withdrawer, withdrawTokensIn, withdrawAmountIn); } function withdrawInternal( address payable withdrawer, uint256 withdrawTokensIn, uint256 withdrawAmountIn ) internal returns (uint256, bytes memory) { // 一个是想要兑换 cTokens 的数量,一个是想要兑换 asset 的数量,必须有一个是 0 require( withdrawTokensIn == 0 || withdrawAmountIn == 0, "withdraw parameter not valid" ); WithdrawLocals memory tmp; tmp.exchangeRate = exchangeRateStored(); if (withdrawTokensIn > 0) { tmp.withdrawTokens = withdrawTokensIn; tmp.withdrawAmount = mulScalarTruncate( tmp.exchangeRate, withdrawTokensIn ); } else { tmp.withdrawTokens = divScalarByExpTruncate( withdrawAmountIn, tmp.exchangeRate ); tmp.withdrawAmount = withdrawAmountIn; } controller.withdrawCheck(address(this), withdrawer, tmp.withdrawTokens); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); tmp.totalSupplyNew = totalSupply.sub(tmp.withdrawTokens); tmp.accountTokensNew = accountTokens[withdrawer].sub( tmp.withdrawTokens ); require( controller.getCashPrior(underlying) >= tmp.withdrawAmount, "Insufficient money" ); controller.transferToUser(underlying, withdrawer, tmp.withdrawAmount); subTotalCash(tmp.withdrawAmount); totalSupply = tmp.totalSupplyNew; accountTokens[withdrawer] = tmp.accountTokensNew; WithdrawLogStruct memory wls = WithdrawLogStruct( withdrawer, underlying, address(this), tmp.withdrawTokens, tmp.withdrawAmount, exchangeRateStored(), getBorrowRate(), tokenCash(address(this), withdrawer), tokenCash(underlying, address(controller)) ); emit Transfer(withdrawer, address(0), tmp.withdrawTokens); return (tmp.withdrawAmount, abi.encode(wls)); } function strikeWithdrawInternal( address withdrawer, uint256 withdrawTokensIn, uint256 withdrawAmountIn ) internal returns (uint256, bytes memory) { // 一个是想要兑换 cTokens 的数量,一个是想要兑换 asset 的数量,必须有一个是 0 require( withdrawTokensIn == 0 || withdrawAmountIn == 0, "withdraw parameter not valid" ); WithdrawLocals memory tmp; tmp.exchangeRate = exchangeRateStored(); if (withdrawTokensIn > 0) { tmp.withdrawTokens = withdrawTokensIn; tmp.withdrawAmount = mulScalarTruncate( tmp.exchangeRate, withdrawTokensIn ); } else { tmp.withdrawTokens = divScalarByExpTruncate( withdrawAmountIn, tmp.exchangeRate ); tmp.withdrawAmount = withdrawAmountIn; } require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); tmp.totalSupplyNew = totalSupply.sub(tmp.withdrawTokens); tmp.accountTokensNew = accountTokens[withdrawer].sub( tmp.withdrawTokens ); totalSupply = tmp.totalSupplyNew; accountTokens[withdrawer] = tmp.accountTokensNew; uint256 preCalcTokenCash = tokenCash(underlying, address(controller)) .add(tmp.withdrawAmount); WithdrawLogStruct memory wls = WithdrawLogStruct( withdrawer, underlying, address(this), tmp.withdrawTokens, tmp.withdrawAmount, exchangeRateStored(), interestRateModel.getBorrowRate( preCalcTokenCash, totalBorrows, totalReserves ), tokenCash(address(this), withdrawer), preCalcTokenCash ); emit Transfer(withdrawer, address(0), tmp.withdrawTokens); return (tmp.withdrawAmount, abi.encode(wls)); } // 更新利息 function accrueInterest() public onlyRestricted { uint256 currentBlockNumber = getBlockNumber(); uint256 accrualBlockNumberPrior = accrualBlockNumber; // 太短 零利息 if (accrualBlockNumberPrior == currentBlockNumber) { return; } uint256 cashPrior = controller.getCashPrior(underlying); uint256 borrowsPrior = totalBorrows; uint256 reservesPrior = totalReserves; uint256 borrowIndexPrior = borrowIndex; // // 计算借贷利率 uint256 borrowRate = interestRateModel.getBorrowRate( cashPrior, borrowsPrior, reservesPrior ); // // 不能超过最大利率 require(borrowRate <= borrowRateMax, "borrow rate is too high"); // // 计算块差 uint256 blockDelta = currentBlockNumber.sub(accrualBlockNumberPrior); /* * simpleInterestFactor = borrowRate * blockDelta * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ uint256 simpleInterestFactor; uint256 interestAccumulated; uint256 totalBorrowsNew; uint256 totalReservesNew; uint256 borrowIndexNew; simpleInterestFactor = mulScalar(borrowRate, blockDelta); interestAccumulated = divExp( mulExp(simpleInterestFactor, borrowsPrior), expScale ); totalBorrowsNew = addExp(interestAccumulated, borrowsPrior); totalReservesNew = addExp( divExp(mulExp(reserveFactor, interestAccumulated), expScale), reservesPrior ); borrowIndexNew = addExp( divExp(mulExp(simpleInterestFactor, borrowIndexPrior), expScale), borrowIndexPrior ); accrualBlockNumber = currentBlockNumber; borrowIndex = borrowIndexNew; totalBorrows = totalBorrowsNew; totalReserves = totalReservesNew; borrowRate = interestRateModel.getBorrowRate( cashPrior, totalBorrows, totalReserves ); // 不能超过最大利率 require(borrowRate <= borrowRateMax, "borrow rate is too high"); } function peekInterest() public view returns ( uint256 _accrualBlockNumber, uint256 _borrowIndex, uint256 _totalBorrows, uint256 _totalReserves ) { _accrualBlockNumber = getBlockNumber(); uint256 accrualBlockNumberPrior = accrualBlockNumber; // 太短 零利息 if (accrualBlockNumberPrior == _accrualBlockNumber) { return ( accrualBlockNumber, borrowIndex, totalBorrows, totalReserves ); } uint256 cashPrior = controller.getCashPrior(underlying); uint256 borrowsPrior = totalBorrows; uint256 reservesPrior = totalReserves; uint256 borrowIndexPrior = borrowIndex; // // 计算借贷利率 uint256 borrowRate = interestRateModel.getBorrowRate( cashPrior, borrowsPrior, reservesPrior ); // // 不能超过最大利率 require(borrowRate <= borrowRateMax, "borrow rate is too high"); // // 计算块差 uint256 blockDelta = _accrualBlockNumber.sub(accrualBlockNumberPrior); /* * simpleInterestFactor = borrowRate * blockDelta * interestAccumulated = simpleInterestFactor * totalBorrows * totalBorrowsNew = interestAccumulated + totalBorrows * totalReservesNew = interestAccumulated * reserveFactor + totalReserves * borrowIndexNew = simpleInterestFactor * borrowIndex + borrowIndex */ uint256 simpleInterestFactor; uint256 interestAccumulated; uint256 totalBorrowsNew; uint256 totalReservesNew; uint256 borrowIndexNew; simpleInterestFactor = mulScalar(borrowRate, blockDelta); interestAccumulated = divExp( mulExp(simpleInterestFactor, borrowsPrior), expScale ); totalBorrowsNew = addExp(interestAccumulated, borrowsPrior); totalReservesNew = addExp( divExp(mulExp(reserveFactor, interestAccumulated), expScale), reservesPrior ); borrowIndexNew = addExp( divExp(mulExp(simpleInterestFactor, borrowIndexPrior), expScale), borrowIndexPrior ); _borrowIndex = borrowIndexNew; _totalBorrows = totalBorrowsNew; _totalReserves = totalReservesNew; borrowRate = interestRateModel.getBorrowRate( cashPrior, totalBorrows, totalReserves ); // 不能超过最大利率 require(borrowRate <= borrowRateMax, "borrow rate is too high"); } function borrowBalanceCurrent(address account) external nonReentrant returns (uint256) { accrueInterest(); BorrowSnapshot memory borrowSnapshot = accountBorrows[account]; require(borrowSnapshot.interestIndex <= borrowIndex, "borrowIndex error"); return borrowBalanceStoredInternal(account); } function borrowBalanceStoredInternal(address user) internal view returns (uint256 result) { // 借贷数量 BorrowSnapshot memory borrowSnapshot = accountBorrows[user]; if (borrowSnapshot.principal == 0) { return 0; } result = mulExp(borrowSnapshot.principal, divExp(borrowIndex, borrowSnapshot.interestIndex)); } function _setReserveFactorFresh(uint256 newReserveFactor) external onlyAdmin nonReentrant { accrueInterest(); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); reserveFactor = newReserveFactor; } struct ReserveDepositLogStruct { address token_address; uint256 reserve_funded; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 global_token_reserved; } function _setInterestRateModel(IInterestRateModel newInterestRateModel) public onlyAdmin { address oldIRM = address(interestRateModel); uint256 oldUR = utilizationRate(); uint256 oldAPR = APR(); uint256 oldAPY = APY(); uint256 exRate1 = exchangeRateStored(); accrueInterest(); uint256 exRate2 = exchangeRateStored(); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); interestRateModel = newInterestRateModel; uint256 newUR = utilizationRate(); uint256 newAPR = APR(); uint256 newAPY = APY(); emit NewInterestRateModel(oldIRM, oldUR, oldAPR, oldAPY, exRate1, address(newInterestRateModel), newUR, newAPR, newAPY, exRate2); ReserveDepositLogStruct memory rds = ReserveDepositLogStruct( underlying, 0, exchangeRateStored(), getBorrowRate(), tokenCash(underlying, address(controller)) ); IBank(bank).MonitorEventCallback( "ReserveDeposit", abi.encode(rds) ); } function _setInitialExchangeRate(uint256 _initialExchangeRate) external onlyAdmin { uint256 oldInitialExchangeRate = initialExchangeRate; uint256 oldUR = utilizationRate(); uint256 oldAPR = APR(); uint256 oldAPY = APY(); uint256 exRate1 = exchangeRateStored(); accrueInterest(); uint256 exRate2 = exchangeRateStored(); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); initialExchangeRate = _initialExchangeRate; uint256 newUR = utilizationRate(); uint256 newAPR = APR(); uint256 newAPY = APY(); emit NewInitialExchangeRate(oldInitialExchangeRate, oldUR, oldAPR, oldAPY, exRate1, initialExchangeRate, newUR, newAPR, newAPY, exRate2); ReserveDepositLogStruct memory rds = ReserveDepositLogStruct( underlying, 0, exchangeRateStored(), getBorrowRate(), tokenCash(underlying, address(controller)) ); IBank(bank).MonitorEventCallback( "ReserveDeposit", abi.encode(rds) ); } function getBlockNumber() internal view returns (uint256) { return block.number; } function repay(address borrower, uint256 repayAmount) external onlyBank nonReentrant returns (uint256, bytes memory) { accrueInterest(); return repayInternal(borrower, repayAmount); } struct RepayLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_repayed; uint256 interest_accrued; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_debt; uint256 global_token_reserved; } function repayInternal(address borrower, uint256 repayAmount) internal returns (uint256, bytes memory) { controller.repayCheck(underlying); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); RepayLocals memory tmp; uint256 lastPrincipal = accountBorrows[borrower].principal; tmp.borrowerIndex = accountBorrows[borrower].interestIndex; tmp.accountBorrows = borrowBalanceStoredInternal(borrower); // -1 表示还最大 if (repayAmount == uint256(-1)) { tmp.repayAmount = tmp.accountBorrows; } else { tmp.repayAmount = repayAmount; } tmp.accountBorrowsNew = tmp.accountBorrows.sub(tmp.repayAmount); if (totalBorrows < tmp.repayAmount) { tmp.totalBorrowsNew = 0; } else { tmp.totalBorrowsNew = totalBorrows.sub(tmp.repayAmount); } accountBorrows[borrower].principal = tmp.accountBorrowsNew; accountBorrows[borrower].interestIndex = borrowIndex; totalBorrows = tmp.totalBorrowsNew; uint256 preCalcTokenCash = tokenCash(underlying, address(controller)) .add(tmp.repayAmount); RepayLogStruct memory rls = RepayLogStruct( borrower, underlying, address(this), tmp.repayAmount, SafeMath.abs(tmp.accountBorrows, lastPrincipal), exchangeRateAfter(tmp.repayAmount), //repay之后的交换率 interestRateModel.getBorrowRate( preCalcTokenCash, totalBorrows, totalReserves ), //repay之后的借款利率 accountBorrows[borrower].principal, preCalcTokenCash ); return (tmp.repayAmount, abi.encode(rls)); } function borrowBalanceStored(address account) external view returns (uint256) { return borrowBalanceStoredInternal(account); } struct LiquidateBorrowLogStruct { address user_address; address token_address; address cheque_token_address; uint256 debt_written_off; uint256 interest_accrued; address debtor_address; uint256 collateral_purchased; address collateral_cheque_token_address; uint256 debtor_balance; uint256 debt_remaining; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_balance; uint256 global_token_reserved; } function liquidateBorrow( address liquidator, address borrower, uint256 repayAmount, FToken fTokenCollateral ) public onlyBank nonReentrant returns (bytes memory) { require( controller.isFTokenValid(address(this)) && controller.isFTokenValid(address(fTokenCollateral)), "Market not listed" ); accrueInterest(); fTokenCollateral.accrueInterest(); uint256 lastPrincipal = accountBorrows[borrower].principal; uint256 newPrincipal = borrowBalanceStoredInternal(borrower); controller.liquidateBorrowCheck( address(this), address(fTokenCollateral), borrower, liquidator, repayAmount ); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); require( fTokenCollateral.accrualBlockNumber() == getBlockNumber(), "Blocknumber fails" ); // 还钱 (uint256 actualRepayAmount, ) = repayInternal(borrower, repayAmount); // 计算清算的质押物数量(fToken数量) uint256 seizeTokens = controller.liquidateTokens( address(this), address(fTokenCollateral), actualRepayAmount ); // 借款人得要有这么多余额才行 require( fTokenCollateral.balanceOf(borrower) >= seizeTokens, "Seize too much" ); if (address(fTokenCollateral) == address(this)) { seizeInternal(address(this), liquidator, borrower, seizeTokens); } else { fTokenCollateral.seize(liquidator, borrower, seizeTokens); } uint256 preCalcTokenCash = tokenCash(underlying, address(controller)) .add(actualRepayAmount); LiquidateBorrowLogStruct memory lbls = LiquidateBorrowLogStruct( liquidator, underlying, address(this), actualRepayAmount, SafeMath.abs(newPrincipal, lastPrincipal), borrower, seizeTokens, address(fTokenCollateral), tokenCash(address(fTokenCollateral), borrower), accountBorrows[borrower].principal, //debt_remaining exchangeRateAfter(actualRepayAmount), interestRateModel.getBorrowRate( preCalcTokenCash, totalBorrows, totalReserves ), tokenCash(address(fTokenCollateral), liquidator), preCalcTokenCash ); return abi.encode(lbls); } function seize( address liquidator, address borrower, uint256 seizeTokens ) external nonReentrant { return seizeInternal(msg.sender, liquidator, borrower, seizeTokens); } struct CallingOutLogStruct { address user_address; address token_address; address cheque_token_address; uint256 amount_wiped_out; uint256 debt_cancelled_out; uint256 interest_accrued; uint256 cheque_token_value; uint256 loan_interest_rate; uint256 account_balance; uint256 account_debt; uint256 global_token_reserved; } //冲账处理 function cancellingOut(address striker) public onlyBank nonReentrant returns (bool strikeOk, bytes memory strikeLog) { // 需要冲账时,计算利息 if ( borrowBalanceStoredInternal(striker) > 0 && balanceOf(striker) > 0 ) { accrueInterest(); uint256 lastPrincipal = accountBorrows[striker].principal; uint256 curBorrowBalance = borrowBalanceStoredInternal(striker); uint256 userSupplyBalance = calcBalanceOfUnderlying(striker); uint256 lastFtokenBalance = balanceOf(striker); uint256 actualRepayAmount; bytes memory repayLog; uint256 withdrawAmount; bytes memory withdrawLog; // 有借款和存款(fToken) if (curBorrowBalance > 0 && userSupplyBalance > 0) { //无实际转账的赎回(冲账赎回) if (userSupplyBalance > curBorrowBalance) { (withdrawAmount, withdrawLog) = strikeWithdrawInternal( striker, 0, curBorrowBalance ); } else { (withdrawAmount, withdrawLog) = strikeWithdrawInternal( striker, balanceOf(striker), 0 ); } (actualRepayAmount, repayLog) = repayInternal( striker, withdrawAmount ); CallingOutLogStruct memory cols; cols.user_address = striker; cols.token_address = underlying; cols.cheque_token_address = address(this); cols.amount_wiped_out = SafeMath.abs( lastFtokenBalance, balanceOf(striker) ); cols.debt_cancelled_out = actualRepayAmount; cols.interest_accrued = SafeMath.abs( curBorrowBalance, lastPrincipal ); cols.cheque_token_value = exchangeRateStored(); cols.loan_interest_rate = interestRateModel.getBorrowRate( tokenCash(underlying, address(controller)), totalBorrows, totalReserves ); cols.account_balance = tokenCash(address(this), striker); cols.account_debt = accountBorrows[striker].principal; cols.global_token_reserved = tokenCash( underlying, address(controller) ); strikeLog = abi.encode(cols); strikeOk = true; } } } function balanceOf(address owner) public view returns (uint256) { return accountTokens[owner]; } function _setBorrowSafeRatio(uint256 _borrowSafeRatio) public onlyAdmin { borrowSafeRatio = _borrowSafeRatio; } function seizeInternal( address seizerToken, address liquidator, address borrower, uint256 seizeTokens ) internal { require(borrower != liquidator, "Liquidator cannot be borrower"); controller.seizeCheck(address(this), seizerToken); accountTokens[borrower] = accountTokens[borrower].sub(seizeTokens); accountTokens[liquidator] = accountTokens[liquidator].add(seizeTokens); emit Transfer(borrower, liquidator, seizeTokens); } // onlyController function _reduceReserves(uint256 reduceAmount) external onlyController { accrueInterest(); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); require( controller.getCashPrior(underlying) >= reduceAmount, "Insufficient cash" ); require(totalReserves >= reduceAmount, "Insufficient reserves"); totalReserves = SafeMath.sub( totalReserves, reduceAmount, "reduce reserves underflow" ); } function _addReservesFresh(uint256 addAmount) external onlyController { accrueInterest(); require(accrualBlockNumber == getBlockNumber(), "Blocknumber fails"); totalReserves = SafeMath.add(totalReserves, addAmount); } function addTotalCash(uint256 _addAmount) public onlyBankComponent { totalCash = totalCash.add(_addAmount); } function subTotalCash(uint256 _subAmount) public onlyBankComponent { totalCash = totalCash.sub(_subAmount); } modifier nonReentrant() { require(_notEntered, "re-entered"); _notEntered = false; _; _notEntered = true; } // 借款年利率 function APR() public view returns (uint256) { uint256 cash = tokenCash(underlying, address(controller)); return interestRateModel.APR(cash, totalBorrows, totalReserves); } // 存款年利率 function APY() public view returns (uint256) { uint256 cash = tokenCash(underlying, address(controller)); return interestRateModel.APY( cash, totalBorrows, totalReserves, reserveFactor ); } function utilizationRate() public view returns (uint256) { uint256 cash = tokenCash(underlying, address(controller)); return interestRateModel.utilizationRate(cash, totalBorrows, totalReserves); } // 借款年利率 function getBorrowRate() public view returns (uint256) { uint256 cash = tokenCash(underlying, address(controller)); return interestRateModel.getBorrowRate(cash, totalBorrows, totalReserves); } // 存款年利率 function getSupplyRate() public view returns (uint256) { uint256 cash = tokenCash(underlying, address(controller)); return interestRateModel.getSupplyRate( cash, totalBorrows, totalReserves, reserveFactor ); } }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldInitialExchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate2","type":"uint256"}],"name":"NewInitialExchangeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate1","type":"uint256"},{"indexed":false,"internalType":"address","name":"newIRM","type":"address"},{"indexed":false,"internalType":"uint256","name":"newUR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPR","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAPY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exRate2","type":"uint256"}],"name":"NewInterestRateModel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"APR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"APY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"addAmount","type":"uint256"}],"name":"_addReservesFresh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"reduceAmount","type":"uint256"}],"name":"_reduceReserves","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_borrowSafeRatio","type":"uint256"}],"name":"_setBorrowSafeRatio","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"_setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"}],"name":"_setInitialExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IInterestRateModel","name":"newInterestRateModel","type":"address"}],"name":"_setInterestRateModel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newReserveFactor","type":"uint256"}],"name":"_setReserveFactorFresh","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountBorrows","outputs":[{"internalType":"uint256","name":"principal","type":"uint256"},{"internalType":"uint256","name":"interestIndex","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"accountTokens","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrualBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accrueInterest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"addExp","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_addAmount","type":"uint256"}],"name":"addTotalCash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bank","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"borrower","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"borrow","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"borrowBalanceStored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"borrowSafeRatio","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"calcBalanceOfUnderlying","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"}],"name":"calcExchangeRate","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"striker","type":"address"}],"name":"cancellingOut","outputs":[{"internalType":"bool","name":"strikeOk","type":"bool"},{"internalType":"bytes","name":"strikeLog","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IBankController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"divExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"divScalar","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"divisor","type":"uint256"}],"name":"divScalarByExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"divisor","type":"uint256"}],"name":"divScalarByExpTruncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"transferInAmout","type":"uint256"}],"name":"exchangeRateAfter","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchangeRateCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"exchangeRateStored","outputs":[{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getAccountState","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBorrowRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"uint256","name":"denom","type":"uint256"}],"name":"getDiv","outputs":[{"internalType":"uint256","name":"rational","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"num","type":"uint256"},{"internalType":"uint256","name":"denom","type":"uint256"}],"name":"getExp","outputs":[{"internalType":"uint256","name":"rational","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getSupplyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_initialExchangeRate","type":"uint256"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_initialInterestRateModel","type":"address"},{"internalType":"address","name":"_underlying","type":"address"},{"internalType":"address","name":"_bank","type":"address"},{"internalType":"uint256","name":"_borrowSafeRatio","type":"uint256"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"interestRateModel","outputs":[{"internalType":"contract IInterestRateModel","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"},{"internalType":"contract FToken","name":"fTokenCollateral","type":"address"}],"name":"liquidateBorrow","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"mulExp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"},{"internalType":"uint256","name":"c","type":"uint256"}],"name":"mulExp3","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"mulScalar","outputs":[{"internalType":"uint256","name":"scaled","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"}],"name":"mulScalarTruncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"scalar","type":"uint256"},{"internalType":"uint256","name":"addend","type":"uint256"}],"name":"mulScalarTruncateAddUInt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peekInterest","outputs":[{"internalType":"uint256","name":"_accrualBlockNumber","type":"uint256"},{"internalType":"uint256","name":"_borrowIndex","type":"uint256"},{"internalType":"uint256","name":"_totalBorrows","type":"uint256"},{"internalType":"uint256","name":"_totalReserves","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"repayAmount","type":"uint256"}],"name":"repay","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"liquidator","type":"address"},{"internalType":"address","name":"borrower","type":"address"},{"internalType":"uint256","name":"seizeTokens","type":"uint256"}],"name":"seize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"a","type":"uint256"},{"internalType":"uint256","name":"b","type":"uint256"}],"name":"subExp","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"_subAmount","type":"uint256"}],"name":"subTotalCash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"account","type":"address"}],"name":"tokenCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBorrows","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCash","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalReserves","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"src","type":"address"},{"internalType":"address","name":"dst","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"exp","type":"uint256"}],"name":"truncate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"underlying","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"utilizationRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"withdrawer","type":"address"},{"internalType":"uint256","name":"withdrawTokensIn","type":"uint256"},{"internalType":"uint256","name":"withdrawAmountIn","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50600436106104335760003560e01c806385cc148611610236578063ba1c5e801161013b578063d40e8f4a116100c3578063ef8bd30511610087578063ef8bd305146108c9578063f2b3abbd146108d1578063f3fdb15a146108e4578063f77c4791146108ec578063f851a440146108f457610433565b8063d40e8f4a1461085c578063d6079cc61461087d578063dd62ed3e14610890578063de32abd1146108a3578063e61de305146108b657610433565b8063bee12d531161010a578063bee12d5314610813578063c2ee3a081461081b578063c319f86614610823578063c5e9cadc14610836578063ce603aad1461084957610433565b8063ba1c5e80146107fb578063ba9316b7146105f8578063bd30558e14610803578063bd6d894d1461080b57610433565b8063a19d1460116101be578063ae8a473d1161018d578063ae8a473d1461079c578063b2a02ff1146107af578063b4ab15e7146107c2578063b507f9f9146107d5578063b5c5f672146107e857610433565b8063a19d146014610766578063a6afed9514610779578063a9059cbb14610781578063aa5af0fd1461079457610433565b806395bd6a4c1161020557806395bd6a4c1461070357806395d89b411461071657806395dd91931461071e5780639c92779c146107315780639ee2735b1461074457610433565b806385cc1486146106cd5780638de46362146106d55780638f840ddd146106e857806393508164146106f057610433565b80634751b79c1161033c5780636c540baf116102c457806370a082311161029357806370a082311461068457806376cdb03b146106975780637b94aaac1461069f57806383de424e146106b257806384bdc9a8146106c557610433565b80636c540baf1461064c5780636d019f35146106545780636f307dc31461065c5780636f4a3de91461067157610433565b80635293ff311161030b5780635293ff31146105f8578063601a0bf11461060b5780636208fc411461061e57806364fd7078146106315780636c321c8a1461064457610433565b80634751b79c146105b757806347bd3718146105ca5780634b3ac1c2146105d25780634b8a3529146105e557610433565b806323b872dd116103bf5780633af9e6691161038e5780633af9e6691461056157806340c10f19146105745780634147da13146105875780634322b7141461059a578063474a5e05146105a257610433565b806323b872dd146105135780632985fa3114610526578063313ce56714610539578063396a98cf1461054e57610433565b806315f14eaa1161040657806315f14eaa146104ae57806317bfdfbc146104cf57806318160ddd146104e2578063182df0f5146104ea57806322867d78146104f257610433565b806306fdde031461043857806308186ecf146104565780630873f15014610476578063095ea7b31461048e575b600080fd5b6104406108fc565b60405161044d9190614eda565b60405180910390f35b610469610464366004614b84565b61098a565b60405161044d919061556e565b61047e610a5b565b60405161044d94939291906155b4565b6104a161049c366004614b52565b610d41565b60405161044d9190614eb4565b6104c16104bc366004614a0d565b610daf565b60405161044d929190614ebf565b6104696104dd366004614a0d565b61107c565b61046961113d565b610469611143565b610505610500366004614b52565b611159565b60405161044d929190615577565b6104a1610521366004614ac0565b6111f1565b610469610534366004614c83565b611361565b61054161137a565b60405161044d9190615614565b61046961055c366004614c83565b611383565b61046961056f366004614a0d565b611395565b610440610582366004614b52565b6113d0565b610469610595366004614c83565b611460565b610469611472565b6105b56105b0366004614b84565b611478565b005b6104696105c5366004614c83565b6114a7565b6104696114b9565b6105b56105e0366004614b84565b6114bf565b6104406105f3366004614a29565b6116c1565b610469610606366004614c83565b611736565b6105b5610619366004614b84565b611760565b61046961062c366004614ca4565b6118c9565b61044061063f366004614b00565b6118fa565b610469611f96565b610469612049565b61046961204f565b610664612055565b60405161044d9190614d8f565b6105b561067f366004614bb4565b612064565b610469610692366004614a0d565b6121bf565b6106646121da565b6104696106ad366004614b84565b6121e9565b6105b56106c0366004614a0d565b612203565b61046961224f565b6104696122b1565b6104696106e3366004614ca4565b6122b7565b6104696122cc565b6104696106fe366004614a88565b6122d2565b6105b5610711366004614b84565b612381565b610440612469565b61046961072c366004614a0d565b6124c4565b6105b561073f366004614b84565b6124cf565b610757610752366004614a0d565b612535565b60405161044d9392919061559e565b610469610774366004614a0d565b612576565b6105b5612588565b6104a161078f366004614b52565b612900565b610469612a70565b6105b56107aa366004614b84565b612a76565b6105b56107bd366004614ac0565b612b1e565b6104696107d0366004614c83565b612b78565b6104696107e3366004614c83565b612b90565b6105056107f6366004614a54565b612b9c565b610469612c36565b610469612c93565b610469612cf0565b610469612d51565b610469612d57565b6105b5610831366004614b84565b612d63565b610469610844366004614c83565b612e45565b610469610857366004614c83565b612f0f565b61086f61086a366004614a0d565b612f36565b60405161044d929190615590565b61046961088b366004614c83565b612f4f565b61046961089e366004614a88565b612f5c565b6104696108b1366004614c83565b612f87565b6104696108c4366004614a0d565b612fca565b610469613011565b6105b56108df366004614a0d565b613073565b610664613195565b6106646131a4565b6106646131b3565b6034805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156109825780601f1061095757610100808354040283529160200191610982565b820191906000526020600020905b81548152906001019060200180831161096557829003601f168201915b505050505081565b6033546000908061099f575050603854610a56565b60425460408054905163051f87d160e51b81526000926001600160a01b039081169263a3f0fa20926109d992909116908890600401614e3e565b60206040518083038186803b1580156109f157600080fd5b505afa158015610a05573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a299190614b9c565b90506000610a44610a3c83603a54611460565b603b54611383565b9050610a508184611736565b93505050505b919050565b600080600080610a696131c2565b603e5490945080851415610a9157603e54603d54603a54603b54945094509450945050610d3b565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b92610ac99290911690600401614d8f565b60206040518083038186803b158015610ae157600080fd5b505afa158015610af5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b199190614b9c565b603a54603b54603d54603f546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f2405390610b609088908890889060040161559e565b60206040518083038186803b158015610b7857600080fd5b505afa158015610b8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bb09190614b9c565b905065048c27395000811115610be15760405162461bcd60e51b8152600401610bd8906152a9565b60405180910390fd5b6000610bf38b8863ffffffff6131c616565b90506000806000806000610c078787611361565b9450610c24610c16868c612f87565b670de0b6b3a7640000612b90565b9350610c30848b611460565b9250610c4a610c44610c16603c5487612f87565b8a611460565b9150610c62610c5c610c16878b612f87565b89611460565b9050809e50829d50819c50603f60009054906101000a90046001600160a01b03166001600160a01b03166315f240538c603a54603b546040518463ffffffff1660e01b8152600401610cb69392919061559e565b60206040518083038186803b158015610cce57600080fd5b505afa158015610ce2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d069190614b9c565b965065048c27395000871115610d2e5760405162461bcd60e51b8152600401610bd8906152a9565b5050505050505050505050505b90919293565b3360008181526037602090815260408083206001600160a01b03871680855292528083208590555191929182907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610d9b90879061556e565b60405180910390a360019150505b92915050565b6044546000906060906001600160a01b03163314610ddf5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16610e085760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556000610e2084613208565b118015610e3557506000610e33846121bf565b115b1561106257610e42612588565b6001600160a01b03831660009081526045602052604081205490610e6585613208565b90506000610e7286612fca565b90506000610e7f876121bf565b90506000606060006060600087118015610e995750600086115b156110595786861115610ebc57610eb28b60008961326f565b9092509050610ed6565b610ed08b610ec98d6121bf565b600061326f565b90925090505b610ee08b83613512565b9094509250610eed614622565b6001600160a01b03808d1682526040805490911660208301523090820152610f1d86610f188e6121bf565b6137e1565b606082015260808101859052610f33888a6137e1565b60a0820152610f40611143565b60c0820152603f546040546042546001600160a01b03928316926315f2405392610f6e9290821691166122d2565b603a54603b546040518463ffffffff1660e01b8152600401610f929392919061559e565b60206040518083038186803b158015610faa57600080fd5b505afa158015610fbe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe29190614b9c565b60e0820152610ff1308d6122d2565b6101008201526001600160a01b03808d1660009081526045602052604090819020546101208401525460425461102b9291821691166122d2565b61014082015260405161104290829060200161536a565b604051602081830303815290604052995060019a50505b50505050505050505b6044805460ff60a01b1916600160a01b1790559092909150565b604454600090600160a01b900460ff166110a85760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556110bd612588565b6110c5614697565b506001600160a01b03821660009081526045602090815260409182902082518084019093528054835260010154908201819052603d5410156111195760405162461bcd60e51b8152600401610bd890615036565b61112283613208565b9150506044805460ff60a01b1916600160a01b179055919050565b60335481565b6000611153603a54603b54612e45565b90505b90565b6044546000906060906001600160a01b031633146111895760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166111b25760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b191690556111c7612588565b6111d18484613512565b915091506044805460ff60a01b1916600160a01b17905590939092509050565b604454600090600160a01b900460ff1661121d5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055611236338585856137fa565b5061123f6146b1565b60408051610100810182526001600160a01b03808816825282541660208201523091810191909152606081018490526080810161127b876121bf565b8152602001856001600160a01b03168152602001611298866121bf565b81526040546042546020909201916112bc916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906112e5908490602001615505565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401611310919061519b565b600060405180830381600087803b15801561132a57600080fd5b505af115801561133e573d6000803e3d6000fd5b5050505060019150506044805460ff60a01b1916600160a01b1790559392505050565b6000611373838363ffffffff613a9516565b9392505050565b60365460ff1681565b6000611373838363ffffffff6131c616565b6000806113a0612cf0565b6001600160a01b038416600090815260416020526040812054919250906113c8908390612b78565b949350505050565b6044546060906001600160a01b031633146113fd5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166114265760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b1916905561143b612588565b6114458383613acf565b90506044805460ff60a01b1916600160a01b17905592915050565b6000611373838363ffffffff613d6e16565b603c5481565b6039546001600160a01b031633146114a25760405162461bcd60e51b8152600401610bd890615214565b604355565b6000611373838363ffffffff613d9316565b603a5481565b6039546001600160a01b031633146114e95760405162461bcd60e51b8152600401610bd890615214565b60385460006114f6611f96565b90506000611502612c93565b9050600061150e613011565b9050600061151a611143565b9050611524612588565b600061152e611143565b90506115386131c2565b603e54146115585760405162461bcd60e51b8152600401610bd890614fb4565b60388790556000611567611f96565b90506000611573612c93565b9050600061157f613011565b90507fcff2ff0c9e99b301907279a45536b658e0227bfa9d6fba4799b46b268e804e2789898989896038548989898d6040516115c49a999897969594939291906155cf565b60405180910390a16115d461471a565b6040805160a08101825281546001600160a01b03168152600060208201529081016115fd611143565b815260200161160a612c36565b815260405460425460209092019161162e916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906116579084906020016154c7565b6040516020818303038152906040526040518263ffffffff1660e01b815260040161168291906151ea565b600060405180830381600087803b15801561169c57600080fd5b505af11580156116b0573d6000803e3d6000fd5b505050505050505050505050505050565b6044546060906001600160a01b031633146116ee5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166117175760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b1916905561172c612588565b6114458383613dd5565b60006113738261175485670de0b6b3a764000063ffffffff613a9516565b9063ffffffff613d9316565b6042546001600160a01b0316331461178a5760405162461bcd60e51b8152600401610bd89061508e565b611792612588565b61179a6131c2565b603e54146117ba5760405162461bcd60e51b8152600401610bd890614fb4565b604254604080549051639f77437b60e01b815283926001600160a01b0390811692639f77437b926117f19290911690600401614d8f565b60206040518083038186803b15801561180957600080fd5b505afa15801561181d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118419190614b9c565b101561185f5760405162461bcd60e51b8152600401610bd8906152e0565b80603b5410156118815760405162461bcd60e51b8152600401610bd890614fdf565b6118c3603b54826040518060400160405280601981526020017f72656475636520726573657276657320756e646572666c6f7700000000000000815250614098565b603b5550565b6000806118d68585611361565b90506118f1836118e5836121e9565b9063ffffffff613d6e16565b95945050505050565b6044546060906001600160a01b031633146119275760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff166119505760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055604254604051632a4d98cf60e01b81526001600160a01b0390911690632a4d98cf9061198d903090600401614d8f565b60206040518083038186803b1580156119a557600080fd5b505afa1580156119b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dd9190614b64565b8015611a645750604254604051632a4d98cf60e01b81526001600160a01b0390911690632a4d98cf90611a14908590600401614d8f565b60206040518083038186803b158015611a2c57600080fd5b505afa158015611a40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a649190614b64565b611a805760405162461bcd60e51b8152600401610bd890614f5b565b611a88612588565b816001600160a01b031663a6afed956040518163ffffffff1660e01b8152600401600060405180830381600087803b158015611ac357600080fd5b505af1158015611ad7573d6000803e3d6000fd5b5050506001600160a01b0385166000908152604560205260408120549150611afe86613208565b604254604051633e5cd62160e11b81529192506001600160a01b031690637cb9ac4290611b3790309088908b908d908c90600401614e0b565b600060405180830381600087803b158015611b5157600080fd5b505af1158015611b65573d6000803e3d6000fd5b50505050611b716131c2565b603e5414611b915760405162461bcd60e51b8152600401610bd890614fb4565b611b996131c2565b846001600160a01b0316636c540baf6040518163ffffffff1660e01b815260040160206040518083038186803b158015611bd257600080fd5b505afa158015611be6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c0a9190614b9c565b14611c275760405162461bcd60e51b8152600401610bd890614fb4565b6000611c338787613512565b506042546040516263fd3760e51b81529192506000916001600160a01b0390911690630c7fa6e090611c6d9030908a908790600401614de7565b60206040518083038186803b158015611c8557600080fd5b505afa158015611c99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cbd9190614b9c565b905080866001600160a01b03166370a082318a6040518263ffffffff1660e01b8152600401611cec9190614d8f565b60206040518083038186803b158015611d0457600080fd5b505afa158015611d18573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d3c9190614b9c565b1015611d5a5760405162461bcd60e51b8152600401610bd89061500e565b6001600160a01b038616301415611d7c57611d77308a8a846140c4565b611ddf565b60405163b2a02ff160e01b81526001600160a01b0387169063b2a02ff190611dac908c908c908690600401614de7565b600060405180830381600087803b158015611dc657600080fd5b505af1158015611dda573d6000803e3d6000fd5b505050505b604054604254600091611e049185916118e5916001600160a01b0391821691166122d2565b9050611e0e614752565b604080516101c0810182526001600160a01b03808e168252825416602082015230918101919091526060810185905260808101611e4b87896137e1565b81526020018b6001600160a01b03168152602001848152602001896001600160a01b03168152602001611e7e8a8d6122d2565b81526001600160a01b038c16600090815260456020908152604091829020549083015201611eab8661098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f2405392611ee992899260040161559e565b60206040518083038186803b158015611f0157600080fd5b505afa158015611f15573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f399190614b9c565b8152602001611f488a8e6122d2565b815260200183815250905080604051602001611f649190615400565b60405160208183030381529060405296505050505050506044805460ff60a01b1916600160a01b179055949350505050565b6040546042546000918291611fb7916001600160a01b0390811691166122d2565b603f54603a54603b54604051630dce3c5b60e31b81529394506001600160a01b0390921692636e71e2d892611ff392869290919060040161559e565b60206040518083038186803b15801561200b57600080fd5b505afa15801561201f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120439190614b9c565b91505090565b603e5481565b60385481565b6040546001600160a01b031681565b600054610100900460ff168061207d575061207d614206565b8061208b575060005460ff16155b6120a75760405162461bcd60e51b8152600401610bd89061514d565b600054610100900460ff161580156120d2576000805460ff1961ff0019909116610100171660011790555b60388a9055604280546001600160a01b03808c166001600160a01b031992831617909255603f80548b84169083161790556039805482163317905560408054928a1692909116919091179055604385905561212b6131c2565b603e55670de0b6b3a7640000603d55604480546001600160a01b0319166001600160a01b03881617905583516121689060349060208701906147ee565b50825161217c9060359060208601906147ee565b506036805460ff841660ff199091161790556044805460ff60a01b1916600160a01b17905580156121b3576000805461ff00191690555b50505050505050505050565b6001600160a01b031660009081526041602052604090205490565b6044546001600160a01b031681565b6000610da982670de0b6b3a764000063ffffffff613d9316565b6039546001600160a01b0316331461222d5760405162461bcd60e51b8152600401610bd890615214565b604280546001600160a01b0319166001600160a01b0392909216919091179055565b6040546042546000918291612270916001600160a01b0390811691166122d2565b603f54603a54603b54603c54604051635c0b440b60e11b81529495506001600160a01b039093169363b816881693611ff393879390929091906004016155b4565b60435481565b60006113c86122c68585612f87565b83612f87565b603b5481565b60006122dc61420c565b6001600160a01b0316836001600160a01b0316141561230557816001600160a01b031631611373565b6040516370a0823160e01b81526001600160a01b038416906370a0823190612331908590600401614d8f565b60206040518083038186803b15801561234957600080fd5b505afa15801561235d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113739190614b9c565b6044546001600160a01b03163314806123a457506042546001600160a01b031633145b806123ae57503330145b806124345750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb906123e4903390600401614d8f565b60206040518083038186803b1580156123fc57600080fd5b505afa158015612410573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124349190614b64565b6124505760405162461bcd60e51b8152600401610bd890615061565b604654612463908263ffffffff613d6e16565b60465550565b6035805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156109825780601f1061095757610100808354040283529160200191610982565b6000610da982613208565b6042546001600160a01b031633146124f95760405162461bcd60e51b8152600401610bd89061508e565b612501612588565b6125096131c2565b603e54146125295760405162461bcd60e51b8152600401610bd890614fb4565b6118c3603b5482613d6e565b6001600160a01b038116600090815260416020526040812054819081908161255c86613208565b90506000612568611143565b929791965091945092505050565b60416020526000908152604090205481565b6039546001600160a01b03163314806125ab57506044546001600160a01b031633145b806125c057506042546001600160a01b031633145b806126465750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb906125f6903390600401614d8f565b60206040518083038186803b15801561260e57600080fd5b505afa158015612622573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126469190614b64565b6126625760405162461bcd60e51b8152600401610bd89061511f565b600061266c6131c2565b603e54909150808214156126815750506128fe565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b926126b99290911690600401614d8f565b60206040518083038186803b1580156126d157600080fd5b505afa1580156126e5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127099190614b9c565b603a54603b54603d54603f546040516315f2405360e01b81529495509293919290916000916001600160a01b0316906315f24053906127509088908890889060040161559e565b60206040518083038186803b15801561276857600080fd5b505afa15801561277c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127a09190614b9c565b905065048c273950008111156127c85760405162461bcd60e51b8152600401610bd8906152a9565b60006127da888863ffffffff6131c616565b905060008060008060006127ee8787611361565b94506127fd610c16868c612f87565b9350612809848b611460565b925061281d610c44610c16603c5487612f87565b915061282f610c5c610c16878b612f87565b603e8e9055603d819055603a849055603b839055603f546040516315f2405360e01b81529192506001600160a01b0316906315f2405390612878908e908790879060040161559e565b60206040518083038186803b15801561289057600080fd5b505afa1580156128a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128c89190614b9c565b965065048c273950008711156128f05760405162461bcd60e51b8152600401610bd8906152a9565b505050505050505050505050505b565b604454600090600160a01b900460ff1661292c5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612945338085856137fa565b5061294e6146b1565b60408051610100810182523380825282546001600160a01b0316602083015230928201929092526060810185905290608082019061298b906121bf565b8152602001856001600160a01b031681526020016129a8866121bf565b81526040546042546020909201916129cc916001600160a01b0390811691166122d2565b90526044546040519192506001600160a01b031690637bc597aa906129f5908490602001615505565b6040516020818303038152906040526040518263ffffffff1660e01b8152600401612a20919061530b565b600060405180830381600087803b158015612a3a57600080fd5b505af1158015612a4e573d6000803e3d6000fd5b5050505060019150506044805460ff60a01b1916600160a01b17905592915050565b603d5481565b6039546001600160a01b03163314612aa05760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16612ac95760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612ade612588565b612ae66131c2565b603e5414612b065760405162461bcd60e51b8152600401610bd890614fb4565b603c556044805460ff60a01b1916600160a01b179055565b604454600160a01b900460ff16612b475760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612b60338484846140c4565b50506044805460ff60a01b1916600160a01b17905550565b600080612b858484611361565b90506113c8816121e9565b60006113738383611736565b6044546000906060906001600160a01b03163314612bcc5760405162461bcd60e51b8152600401610bd890615214565b604454600160a01b900460ff16612bf55760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612c0a612588565b612c15858585614224565b915091506044805460ff60a01b1916600160a01b1790559094909350915050565b6040546042546000918291612c57916001600160a01b0390811691166122d2565b603f54603a54603b546040516315f2405360e01b81529394506001600160a01b03909216926315f2405392611ff392869290919060040161559e565b6040546042546000918291612cb4916001600160a01b0390811691166122d2565b603f54603a54603b5460405163ca9cdd1b60e01b81529394506001600160a01b039092169263ca9cdd1b92611ff392869290919060040161559e565b604454600090600160a01b900460ff16612d1c5760405162461bcd60e51b8152600401610bd8906150fb565b6044805460ff60a01b19169055612d31612588565b612d39611143565b90506044805460ff60a01b1916600160a01b17905590565b60465481565b670de0b6b3a764000081565b6044546001600160a01b0316331480612d8657506042546001600160a01b031633145b80612d9057503330145b80612e165750604254604051639deec7cb60e01b81526001600160a01b0390911690639deec7cb90612dc6903390600401614d8f565b60206040518083038186803b158015612dde57600080fd5b505afa158015612df2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e169190614b64565b612e325760405162461bcd60e51b8152600401610bd890615061565b604654612463908263ffffffff6131c616565b60335460009080612e5a575050603854610da9565b604254604080549051639f77437b60e01b81526000926001600160a01b0390811692639f77437b92612e929290911690600401614d8f565b60206040518083038186803b158015612eaa57600080fd5b505afa158015612ebe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ee29190614b9c565b90506000612ef9612ef38388611460565b86611383565b9050612f058184611736565b9695505050505050565b600080612f2a670de0b6b3a76400008563ffffffff613a9516565b90506113c88184611736565b6045602052600090815260409020805460019091015482565b600080612b858484612f0f565b6001600160a01b03918216600090815260376020908152604080832093909416825291909152205490565b600080612f9a848463ffffffff613a9516565b90506000612fb06706f05b59d3b2000083613d6e565b90506118f181670de0b6b3a764000063ffffffff613d9316565b6000806000612fd7610a5b565b9350935050506000612fe98383612e45565b6001600160a01b03861660009081526041602052604081205491925090612f05908390612b78565b6040546042546000918291613032916001600160a01b0390811691166122d2565b603f54603a54603b54603c5460405163ae8b520f60e01b81529495506001600160a01b039093169363ae8b520f93611ff393879390929091906004016155b4565b6039546001600160a01b0316331461309d5760405162461bcd60e51b8152600401610bd890615214565b603f546001600160a01b031660006130b3611f96565b905060006130bf612c93565b905060006130cb613011565b905060006130d7611143565b90506130e1612588565b60006130eb611143565b90506130f56131c2565b603e54146131155760405162461bcd60e51b8152600401610bd890614fb4565b603f80546001600160a01b0319166001600160a01b038916179055600061313a611f96565b90506000613146612c93565b90506000613152613011565b90507fdeb648bcaeacc8fe85ac80af712d28507d5040e38de659e3981835f7732b580e89898989898f8989898d6040516115c49a99989796959493929190614e57565b603f546001600160a01b031681565b6042546001600160a01b031681565b6039546001600160a01b031681565b4390565b600061137383836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250614098565b6000613212614697565b506001600160a01b0382166000908152604560209081526040918290208251808401909352805480845260019091015491830191909152613257576000915050610a56565b61137381600001516108b1603d548460200151612b90565b6000606083158061327e575082155b61329a5760405162461bcd60e51b8152600401610bd890614eed565b6132a261486c565b6132aa611143565b815284156132cf576020810185905280516132c59086612b78565b60408201526132ea565b6132dd848260000151612f4f565b6020820152604081018490525b6132f26131c2565b603e54146133125760405162461bcd60e51b8152600401610bd890614fb4565b60208101516033546133299163ffffffff6131c616565b60608201526020808201516001600160a01b0388166000908152604190925260409091205461335d9163ffffffff6131c616565b6080820181905260608201516033556001600160a01b038088166000908152604160205260408082209390935582840151925460425491936133a89390926118e592821691166122d2565b90506133b261489b565b60408051610120810182526001600160a01b03808b1682528254166020808301919091523082840152850151606082015290840151608082015260a081016133f8611143565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f240539261343692899260040161559e565b60206040518083038186803b15801561344e57600080fd5b505afa158015613462573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134869190614b9c565b8152602001613495308b6122d2565b815260200183815250905060006001600160a01b0316886001600160a01b031660008051602061563b83398151915285602001516040516134d6919061556e565b60405180910390a38260400151816040516020016134f4919061535b565b60405160208183030381529060405294509450505050935093915050565b60425460408054905163227a5a8360e11b81526000926060926001600160a01b03918216926344f4b5069261354b921690600401614d8f565b600060405180830381600087803b15801561356557600080fd5b505af1158015613579573d6000803e3d6000fd5b505050506135856131c2565b603e54146135a55760405162461bcd60e51b8152600401610bd890614fb4565b6135ad614902565b6001600160a01b03851660009081526045602090815260409091208054600190910154918301919091526135e086613208565b60408301526000198514156135fb57604082015182526135ff565b8482525b815160408301516136159163ffffffff6131c616565b60608301528151603a541015613631576000608083015261364b565b8151603a546136459163ffffffff6131c616565b60808301525b60608201516001600160a01b03808816600090815260456020526040808220938455603d546001909401939093556080850151603a5584519254604254919361369d9390926118e592821691166122d2565b90506136a761489b565b60408051610120810182526001600160a01b03808b16825282541660208201523081830152855160608201529085015160808201906136e690866137e1565b81526020016136f8866000015161098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f240539261373692899260040161559e565b60206040518083038186803b15801561374e57600080fd5b505afa158015613762573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137869190614b9c565b81526001600160a01b038a16600090815260456020908152604091829020548184015291810185905286519051929350916137c39184910161535b565b60405160208183030381529060405295509550505050509250929050565b6000818310156137f45750818103610da9565b50900390565b60445460408051635c975abb60e01b815290516000926001600160a01b031691635c975abb916004808301926020929190829003018186803b15801561383f57600080fd5b505afa158015613853573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138779190614b64565b156138945760405162461bcd60e51b8152600401610bd8906151c3565b604260009054906101000a90046001600160a01b03166001600160a01b031663d38120c93086866138c787604354612b78565b6040518563ffffffff1660e01b81526004016138e69493929190614da3565b600060405180830381600087803b15801561390057600080fd5b505af1158015613914573d6000803e3d6000fd5b50505050826001600160a01b0316846001600160a01b0316141561394a5760405162461bcd60e51b8152600401610bd890615272565b60006001600160a01b0386811690861614156139695750600019613991565b506001600160a01b038085166000908152603760209081526040808320938916835292905220545b60006139a3828563ffffffff6131c616565b6001600160a01b0387166000908152604160205260409020549091506139cf908563ffffffff6131c616565b6001600160a01b038088166000908152604160205260408082209390935590871681522054613a04908563ffffffff613d6e16565b6001600160a01b0386166000908152604160205260409020556000198214613a4f576001600160a01b038087166000908152603760209081526040808320938b168352929052208190555b846001600160a01b0316866001600160a01b031660008051602061563b83398151915286604051613a80919061556e565b60405180910390a35060019695505050505050565b600082613aa457506000610da9565b82820282848281613ab157fe5b04146113735760405162461bcd60e51b8152600401610bd8906150ba565b6060613ad96131c2565b603e5414613af95760405162461bcd60e51b8152600401610bd890614fb4565b613b0161486c565b604254604080549051631f3c14ef60e11b81526001600160a01b0392831692633e7829de92613b399291169088908890600401614de7565b600060405180830381600087803b158015613b5357600080fd5b505af1158015613b67573d6000803e3d6000fd5b50505050613b73611143565b808252613b81908490612f4f565b60208201819052603354613b9491611460565b6040808301919091526001600160a01b0385166000908152604160209081529190205490820151613bc59190611460565b606082018190526040808301516033556001600160a01b0380871660009081526041602052828120939093559054604254613c0a9287926118e59290821691166122d2565b9050613c1461489b565b60408051610120810182526001600160a01b03808916825282541660208083019190915230928201929092529084015160608201526080810186905260a08101613c5d8761098a565b8152603f54603a54603b546040516315f2405360e01b81526020909401936001600160a01b03909316926315f2405392613c9b92899260040161559e565b60206040518083038186803b158015613cb357600080fd5b505afa158015613cc7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ceb9190614b9c565b8152602001613cfa30896122d2565b8152602001838152509050856001600160a01b031660006001600160a01b031660008051602061563b8339815191528560200151604051613d3b919061556e565b60405180910390a380604051602001613d54919061535b565b604051602081830303815290604052935050505092915050565b6000828201838110156113735760405162461bcd60e51b8152600401610bd890614f24565b600061137383836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f0000000000008152506145eb565b6042546040546043546060926001600160a01b03908116926396a13b32928792909116903090613e06908890612b78565b6040518563ffffffff1660e01b8152600401613e259493929190614da3565b600060405180830381600087803b158015613e3f57600080fd5b505af1158015613e53573d6000803e3d6000fd5b5050604254604080549051639f77437b60e01b81528694506001600160a01b039283169350639f77437b92613e8c921690600401614d8f565b60206040518083038186803b158015613ea457600080fd5b505afa158015613eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613edc9190614b9c565b1015613efa5760405162461bcd60e51b8152600401610bd890614f86565b613f02614938565b6001600160a01b038416600090815260456020526040902054613f2485613208565b808352613f319085611460565b6020830152603a54613f439085611460565b60408084019182526020808501516001600160a01b03808a166000908152604590935291839020908155603d546001909101559151603a556042548154915163fa93b2a560e01b81529083169263fa93b2a592613fa99291169089908990600401614de7565b600060405180830381600087803b158015613fc357600080fd5b505af1158015613fd7573d6000803e3d6000fd5b50505050613fe484612d63565b613fec61489b565b60408051610120810182526001600160a01b03808916825282541660208201523091810191909152606081018690528351608082019061402c90856137e1565b8152602001614039611143565b8152602001614046612c36565b81526001600160a01b038089166000908152604560209081526040918290205490840152805460425491909301926140829290811691166122d2565b815250905080604051602001613d54919061535b565b600081848411156140bc5760405162461bcd60e51b8152600401610bd89190614eda565b505050900390565b826001600160a01b0316826001600160a01b031614156140f65760405162461bcd60e51b8152600401610bd89061523b565b604254604051637ceb4c9760e01b81526001600160a01b0390911690637ceb4c97906141289030908890600401614dcd565b600060405180830381600087803b15801561414257600080fd5b505af1158015614156573d6000803e3d6000fd5b5050506001600160a01b03831660009081526041602052604090205461418391508263ffffffff6131c616565b6001600160a01b0380841660009081526041602052604080822093909355908516815220546141b8908263ffffffff613d6e16565b6001600160a01b03808516600081815260416020526040908190209390935591519084169060008051602061563b833981519152906141f890859061556e565b60405180910390a350505050565b303b1590565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee90565b60006060831580614233575082155b61424f5760405162461bcd60e51b8152600401610bd890614eed565b61425761486c565b61425f611143565b815284156142845760208101859052805161427a9086612b78565b604082015261429f565b614292848260000151612f4f565b6020820152604081018490525b6042546020820151604051635798612960e01b81526001600160a01b03909216916357986129916142d69130918b91600401614de7565b60206040518083038186803b1580156142ee57600080fd5b505afa158015614302573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906143269190614b9c565b5061432f6131c2565b603e541461434f5760405162461bcd60e51b8152600401610bd890614fb4565b60208101516033546143669163ffffffff6131c616565b60608201526020808201516001600160a01b0388166000908152604190925260409091205461439a9163ffffffff6131c616565b608082015260408082015160425482549251639f77437b60e01b815291926001600160a01b0391821692639f77437b926143d8921690600401614d8f565b60206040518083038186803b1580156143f057600080fd5b505afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190614b9c565b10156144465760405162461bcd60e51b8152600401610bd89061532f565b6042546040805483820151915163fa93b2a560e01b81526001600160a01b039384169363fa93b2a59361448293909116918b9190600401614de7565b600060405180830381600087803b15801561449c57600080fd5b505af11580156144b0573d6000803e3d6000fd5b505050506144c18160400151612d63565b606081015160335560808101516001600160a01b0387166000908152604160205260409020556144ef61489b565b60408051610120810182526001600160a01b03808a1682528254166020808301919091523082840152840151606082015290830151608082015260a08101614535611143565b8152602001614542612c36565b8152602001614551308a6122d2565b8152604054604254602090920191614575916001600160a01b0390811691166122d2565b815250905060006001600160a01b0316876001600160a01b031660008051602061563b83398151915284602001516040516145b0919061556e565b60405180910390a38160400151816040516020016145ce919061535b565b604051602081830303815290604052935093505050935093915050565b6000818361460c5760405162461bcd60e51b8152600401610bd89190614eda565b50600083858161461857fe5b0495945050505050565b60405180610160016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b604051806040016040528060008152602001600081525090565b60405180610100016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b0316815260200160008152602001600081525090565b6040518060a0016040528060006001600160a01b03168152602001600081526020016000815260200160008152602001600081525090565b604051806101c0016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b03168152602001600081526020016000815260200160006001600160a01b031681526020016000815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061482f57805160ff191683800117855561485c565b8280016001018555821561485c579182015b8281111561485c578251825591602001919060010190614841565b50614868929150614959565b5090565b6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b6040518060c001604052806000815260200160008152602001600081526020016000815260200160008152602001600081525090565b60405180606001604052806000815260200160008152602001600081525090565b61115691905b80821115614868576000815560010161495f565b8035610da981615622565b600082601f83011261498e578081fd5b813567ffffffffffffffff808211156149a5578283fd5b604051601f8301601f1916810160200182811182821017156149c5578485fd5b6040528281529250828483016020018610156149e057600080fd5b8260208601602083013760006020848301015250505092915050565b803560ff81168114610da957600080fd5b600060208284031215614a1e578081fd5b813561137381615622565b60008060408385031215614a3b578081fd5b8235614a4681615622565b946020939093013593505050565b600080600060608486031215614a68578081fd5b8335614a7381615622565b95602085013595506040909401359392505050565b60008060408385031215614a9a578182fd5b8235614aa581615622565b91506020830135614ab581615622565b809150509250929050565b600080600060608486031215614ad4578283fd5b8335614adf81615622565b92506020840135614aef81615622565b929592945050506040919091013590565b60008060008060808587031215614b15578081fd5b8435614b2081615622565b93506020850135614b3081615622565b9250604085013591506060850135614b4781615622565b939692955090935050565b60008060408385031215614a3b578182fd5b600060208284031215614b75578081fd5b81518015158114611373578182fd5b600060208284031215614b95578081fd5b5035919050565b600060208284031215614bad578081fd5b5051919050565b60008060008060008060008060006101208a8c031215614bd2578485fd5b8935985060208a0135614be481615622565b975060408a0135614bf481615622565b9650614c038b60608c01614973565b9550614c128b60808c01614973565b945060a08a0135935060c08a013567ffffffffffffffff80821115614c35578485fd5b614c418d838e0161497e565b945060e08c0135915080821115614c56578384fd5b50614c638c828d0161497e565b925050614c748b6101008c016149fc565b90509295985092959850929598565b60008060408385031215614c95578081fd5b50508035926020909101359150565b600080600060608486031215614cb8578081fd5b505081359360208301359350604090920135919050565b6001600160a01b03169052565b60008151808452815b81811015614d0157602081850181015186830182015201614ce5565b81811115614d125782602083870101525b50601f01601f19169290920160200192915050565b60018060a01b0380825116835280602083015116602084015280604083015116604084015250606081015160608301526080810151608083015260a081015160a083015260c081015160c083015260e081015160e08301526101008082015181840152505050565b6001600160a01b0391909116815260200190565b6001600160a01b039485168152928416602084015292166040820152606081019190915260800190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b039586168152938516602085015291841660408401529092166060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b6001600160a01b039a8b1681526020810199909952604089019790975260608801959095526080870193909352951660a085015260c084019490945260e08301939093526101008201929092526101208101919091526101400190565b901515815260200190565b60008315158252604060208301526113c86040830184614cdc565b6000602082526113736020830184614cdc565b6020808252601c908201527f776974686472617720706172616d65746572206e6f742076616c696400000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526011908201527013585c9ad95d081b9bdd081b1a5cdd1959607a1b604082015260600190565b602080825260149082015273496e73756666696369656e742062616c616e636560601b604082015260600190565b602080825260119082015270426c6f636b6e756d626572206661696c7360781b604082015260600190565b602080825260159082015274496e73756666696369656e7420726573657276657360581b604082015260600190565b6020808252600e908201526d0a6cad2f4ca40e8dede40daeac6d60931b604082015260600190565b6020808252601190820152703137b93937bba4b73232bc1032b93937b960791b604082015260600190565b6020808252601390820152721bdb9b1e4818985b9ac818dbdb5c1bdb995b9d606a1b604082015260600190565b6020808252601290820152713932b8bab4b9329031b7b73a3937b63632b960711b604082015260600190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f6040820152607760f81b606082015260800190565b6020808252600a90820152691c994b595b9d195c995960b21b604082015260600190565b60208082526014908201527337b7363c903932b9ba3934b1ba32b2103ab9b2b960611b604082015260600190565b6020808252602e908201527f436f6e747261637420696e7374616e63652068617320616c726561647920626560408201526d195b881a5b9a5d1a585b1a5e995960921b606082015260800190565b60006b5472616e7366657246726f6d60a01b8252604060208301526113736040830184614cdc565b6020808252600d908201526c14de5cdd195b481c185d5cd959609a1b604082015260600190565b60006d14995cd95c9d9951195c1bdcda5d60921b8252604060208301526113736040830184614cdc565b6020808252600d908201526c3932b8bab4b9329030b236b4b760991b604082015260600190565b6020808252601d908201527f4c697175696461746f722063616e6e6f7420626520626f72726f776572000000604082015260600190565b60208082526017908201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604082015260600190565b60208082526017908201527f626f72726f77207261746520697320746f6f2068696768000000000000000000604082015260600190565b602080825260119082015270092dce6eaccccd2c6d2cadce840c6c2e6d607b1b604082015260600190565b6000672a3930b739b332b960c11b8252604060208301526113736040830184614cdc565b602080825260129082015271496e73756666696369656e74206d6f6e657960701b604082015260600190565b6101208101610da98284614d27565b60006101608201905061537e828451614ccf565b60208301516153906020840182614ccf565b5060408301516153a36040840182614ccf565b50606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525061012080840151818401525061014080840151818401525092915050565b60006101c082019050615414828451614ccf565b60208301516154266020840182614ccf565b5060408301516154396040840182614ccf565b50606083015160608301526080830151608083015260a083015161546060a0840182614ccf565b5060c083015160c083015260e083015161547d60e0840182614ccf565b50610100838101519083015261012080840151908301526101408084015190830152610160808401519083015261018080840151908301526101a092830151929091019190915290565b81516001600160a01b031681526020808301519082015260408083015190820152606080830151908201526080918201519181019190915260a00190565b60006101008201905060018060a01b0380845116835280602085015116602084015280604085015116604084015260608401516060840152608084015160808401528060a08501511660a08401525060c083015160c083015260e083015160e083015292915050565b90815260200190565b6000838252604060208301526113c86040830184614cdc565b918252602082015260400190565b9283526020830191909152604082015260600190565b93845260208401929092526040830152606082015260800190565b998a5260208a019890985260408901969096526060880194909452608087019290925260a086015260c085015260e08401526101008301526101208201526101400190565b60ff91909116815260200190565b6001600160a01b038116811461563757600080fd5b5056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220b4a3535465e8afd15762e942628abf29ac8304f5de6aa713dae5948dd4e1784f64736f6c63430006040033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for
interesting conversations.