Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 117 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Get Current Pric... | 14056581 | 1100 days ago | IN | 0 ETH | 0.01179948 | ||||
Get Current Pric... | 14056580 | 1100 days ago | IN | 0 ETH | 0.00996698 | ||||
Get Current Pric... | 13966382 | 1114 days ago | IN | 0 ETH | 0.01984925 | ||||
Get Current Pric... | 13966382 | 1114 days ago | IN | 0 ETH | 0.0167666 | ||||
Get Current Pric... | 13840119 | 1133 days ago | IN | 0 ETH | 0.003227 | ||||
Get Current Pric... | 13803711 | 1139 days ago | IN | 0 ETH | 0.01004458 | ||||
Get Current Pric... | 13803711 | 1139 days ago | IN | 0 ETH | 0.01005425 | ||||
Get Current Pric... | 13803711 | 1139 days ago | IN | 0 ETH | 0.00987169 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.00744442 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.0074527 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.00861016 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.00744442 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.00860622 | ||||
Get Current Pric... | 13799503 | 1140 days ago | IN | 0 ETH | 0.00766216 | ||||
Get Current Pric... | 13789409 | 1141 days ago | IN | 0 ETH | 0.00328605 | ||||
Get Current Pric... | 13783023 | 1142 days ago | IN | 0 ETH | 0.00416303 | ||||
Get Current Pric... | 13776493 | 1143 days ago | IN | 0 ETH | 0.00442412 | ||||
Get Current Pric... | 13776069 | 1143 days ago | IN | 0 ETH | 0.00542789 | ||||
Get Current Pric... | 13745332 | 1148 days ago | IN | 0 ETH | 0.00590091 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.04387078 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.04391961 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.05074063 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.04387078 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.05071742 | ||||
Get Current Pric... | 13738125 | 1149 days ago | IN | 0 ETH | 0.05071742 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
CrossMarginTrading
Compiler Version
v0.8.3+commit.8d00100c
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./Fund.sol"; import "./Lending.sol"; import "./RoleAware.sol"; import "./CrossMarginLiquidation.sol"; // Goal: all external functions only accessible to margintrader role // except for view functions of course contract CrossMarginTrading is CrossMarginLiquidation, IMarginTrading { constructor( address _peg, address _amm1Factory, address _amm2Factory, address _amm3Factory, bytes32 _amm1InitHash, bytes32 _amm2InitHash, bytes32 _amm3InitHash, address _roles ) RoleAware(_roles) PriceAware(_peg) UniswapStyleLib( _amm1Factory, _amm2Factory, _amm3Factory, _amm1InitHash, _amm2InitHash, _amm3InitHash ) {} /// @dev admin function to set the token cap function setTokenCap(address token, uint256 cap) external onlyOwnerExecActivator { tokenCaps[token] = cap; } /// @dev setter for cooling off period for withdrawing funds after deposit function setCoolingOffPeriod(uint256 blocks) external onlyOwnerExec { coolingOffPeriod = blocks; } /// @dev admin function to set leverage function setLeveragePercent(uint256 _leveragePercent) external onlyOwnerExec { leveragePercent = _leveragePercent; } /// @dev admin function to set liquidation threshold function setLiquidationThresholdPercent(uint256 threshold) external onlyOwnerExec { liquidationThresholdPercent = threshold; } /// @dev gets called by router to affirm a deposit to an account function registerDeposit( address trader, address token, uint256 depositAmount ) external override returns (uint256 extinguishableDebt) { require(isMarginTrader(msg.sender), "Calling contr. not authorized"); CrossMarginAccount storage account = marginAccounts[trader]; account.lastDepositBlock = block.number; uint256 currentBorrowed = account.borrowed[token]; if (currentBorrowed > 0) { (uint256 borrowAmount, uint256 yieldQuotientFP) = Lending(lending()).applyBorrowInterest( currentBorrowed, token, account.borrowedYieldQuotientsFP[token] ); account.borrowed[token] = borrowAmount; account.borrowedYieldQuotientsFP[token] = yieldQuotientFP; extinguishableDebt = min(depositAmount, borrowAmount); extinguishDebt(account, token, extinguishableDebt); } // no overflow because depositAmount >= extinguishableDebt uint256 addedHolding = depositAmount - extinguishableDebt; _registerDeposit(account, token, addedHolding); } function _registerDeposit( CrossMarginAccount storage account, address token, uint256 addedHolding ) internal { addHolding(account, token, addedHolding); totalLong[token] += addedHolding; require( tokenCaps[token] >= totalLong[token], "Exceeds global token cap" ); } /// @dev gets called by router to affirm borrowing event function registerBorrow( address trader, address borrowToken, uint256 borrowAmount ) external override { require(isMarginTrader(msg.sender), "Calling contr. not authorized"); CrossMarginAccount storage account = marginAccounts[trader]; addHolding(account, borrowToken, borrowAmount); _registerBorrow(account, borrowToken, borrowAmount); } function _registerBorrow( CrossMarginAccount storage account, address borrowToken, uint256 borrowAmount ) internal { totalLong[borrowToken] += borrowAmount; require( tokenCaps[borrowToken] >= totalLong[borrowToken], "Exceeds global token cap" ); borrow(account, borrowToken, borrowAmount); } function registerRawBorrow( address trader, address borrowToken, uint256 borrowAmount ) external onlyOwnerExec { CrossMarginAccount storage account = marginAccounts[trader]; account.borrowTokens.push(borrowToken); account.borrowedYieldQuotientsFP[borrowToken] = Lending(lending()) .getUpdatedBorrowYieldAccuFP(borrowToken); account.borrowed[borrowToken] = borrowAmount; Lending(lending()).registerBorrow(borrowToken, borrowAmount); } /// @dev gets called by router to affirm withdrawal of tokens from account function registerWithdrawal( address trader, address withdrawToken, uint256 withdrawAmount ) external override { require(isMarginTrader(msg.sender), "Calling contr not authorized"); CrossMarginAccount storage account = marginAccounts[trader]; _registerWithdrawal(account, withdrawToken, withdrawAmount); } function _registerWithdrawal( CrossMarginAccount storage account, address withdrawToken, uint256 withdrawAmount ) internal { require( block.number > account.lastDepositBlock + coolingOffPeriod, "No withdrawal soon after deposit" ); totalLong[withdrawToken] -= withdrawAmount; // throws on underflow account.holdings[withdrawToken] = account.holdings[withdrawToken] - withdrawAmount; require(positiveBalance(account), "Insufficient balance"); } /// @dev overcollateralized borrowing on a cross margin account, called by router function registerOvercollateralizedBorrow( address trader, address depositToken, uint256 depositAmount, address borrowToken, uint256 withdrawAmount ) external override { require(isMarginTrader(msg.sender), "Calling contr. not authorized"); CrossMarginAccount storage account = marginAccounts[trader]; _registerDeposit(account, depositToken, depositAmount); _registerBorrow(account, borrowToken, withdrawAmount); _registerWithdrawal(account, borrowToken, withdrawAmount); account.lastDepositBlock = block.number; } /// @dev gets called by router to register a trade and borrow and extinguish as necessary function registerTradeAndBorrow( address trader, address tokenFrom, address tokenTo, uint256 inAmount, uint256 outAmount ) external override returns (uint256 extinguishableDebt, uint256 borrowAmount) { require(isMarginTrader(msg.sender), "Calling contr. not an authorized"); CrossMarginAccount storage account = marginAccounts[trader]; if (account.borrowed[tokenTo] > 0) { (uint256 extantBorrow, uint256 yieldQuotientFP) = Lending(lending()).applyBorrowInterest( account.borrowed[tokenTo], tokenTo, account.borrowedYieldQuotientsFP[tokenTo] ); account.borrowed[tokenTo] = extantBorrow; account.borrowedYieldQuotientsFP[tokenTo] = yieldQuotientFP; extinguishableDebt = min(outAmount, extantBorrow); extinguishDebt(account, tokenTo, extinguishableDebt); } uint256 sellAmount = inAmount; uint256 fromHoldings = account.holdings[tokenFrom]; if (inAmount > fromHoldings) { sellAmount = fromHoldings; /// won't overflow borrowAmount = inAmount - sellAmount; } if (inAmount > borrowAmount) { totalLong[tokenFrom] -= inAmount - borrowAmount; } if (outAmount > extinguishableDebt) { totalLong[tokenTo] += outAmount - extinguishableDebt; } require( tokenCaps[tokenTo] >= totalLong[tokenTo], "Exceeds global token cap" ); adjustAmounts( account, tokenFrom, tokenTo, sellAmount, outAmount - extinguishableDebt ); if (borrowAmount > 0) { borrow(account, tokenFrom, borrowAmount); } } /// @dev can get called by router to register the dissolution of an account function registerLiquidation(address trader) external override { require(isMarginTrader(msg.sender), "Calling contr. not authorized"); CrossMarginAccount storage account = marginAccounts[trader]; require(loanInPeg(account) == 0, "Can't liquidate: borrowing"); deleteAccount(account); } /// @dev currently holding in this token function viewBalanceInToken(address trader, address token) external view returns (uint256) { CrossMarginAccount storage account = marginAccounts[trader]; return account.holdings[token]; } /// @dev view function to display account held assets state function getHoldingAmounts(address trader) external view override returns ( address[] memory holdingTokens, uint256[] memory holdingAmounts ) { CrossMarginAccount storage account = marginAccounts[trader]; holdingTokens = account.holdingTokens; holdingAmounts = new uint256[](account.holdingTokens.length); for (uint256 idx = 0; holdingTokens.length > idx; idx++) { address tokenAddress = holdingTokens[idx]; holdingAmounts[idx] = account.holdings[tokenAddress]; } } /// @dev view function to display account borrowing state function getBorrowAmounts(address trader) external view override returns (address[] memory borrowTokens, uint256[] memory borrowAmounts) { CrossMarginAccount storage account = marginAccounts[trader]; borrowTokens = account.borrowTokens; borrowAmounts = new uint256[](account.borrowTokens.length); for (uint256 idx = 0; borrowTokens.length > idx; idx++) { address tokenAddress = borrowTokens[idx]; borrowAmounts[idx] = Lending(lending()).viewWithBorrowInterest( account.borrowed[tokenAddress], tokenAddress, account.borrowedYieldQuotientsFP[tokenAddress] ); } } /// @dev view function to get loan amount in peg function viewLoanInPeg(address trader) external view returns (uint256 amount) { CrossMarginAccount storage account = marginAccounts[trader]; return viewTokensInPegWithYield( account.borrowTokens, account.borrowed, account.borrowedYieldQuotientsFP ); } /// @dev total of assets of account, expressed in reference currency function viewHoldingsInPeg(address trader) external view returns (uint256) { CrossMarginAccount storage account = marginAccounts[trader]; return viewTokensInPeg(account.holdingTokens, account.holdings); } /// @dev can this trader be liquidated? function canBeLiquidated(address trader) external view returns (bool) { CrossMarginAccount storage account = marginAccounts[trader]; uint256 loan = viewTokensInPegWithYield( account.borrowTokens, account.borrowed, account.borrowedYieldQuotientsFP ); uint256 holdings = viewTokensInPeg(account.holdingTokens, account.holdings); return liquidationThresholdPercent * loan >= 100 * holdings; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor () { address msgSender = _msgSender(); _owner = msgSender; emit OwnershipTransferred(address(0), msgSender); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { emit OwnershipTransferred(_owner, address(0)); _owner = address(0); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @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 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) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _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 pragma solidity ^0.8.0; /** * @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 on 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"); require(isContract(target), "Address: call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{ value: value }(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.staticcall(data); return _verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.delegatecall(data); return _verifyCallResult(success, returndata, errorMessage); } function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) { 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 pragma solidity ^0.8.0; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
pragma solidity >=0.5.0; interface IUniswapV2Pair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./RoleAware.sol"; import "./Fund.sol"; import "./CrossMarginTrading.sol"; import "../libraries/IncentiveReporter.sol"; /** @title Here we support staking for MFI incentives as well as staking to perform the maintenance role. */ contract Admin is RoleAware { /// Margenswap (MFI) token address address public immutable MFI; mapping(address => uint256) public stakes; uint256 public totalStakes; uint256 public constant mfiStakeTranche = 1; uint256 public maintenanceStakePerBlock = 15 ether; mapping(address => address) public nextMaintenanceStaker; mapping(address => mapping(address => bool)) public maintenanceDelegateTo; address public currentMaintenanceStaker; address public prevMaintenanceStaker; uint256 public currentMaintenanceStakerStartBlock; address public immutable lockedMFI; constructor( address _MFI, address _lockedMFI, address lockedMFIDelegate, address _roles ) RoleAware(_roles) { MFI = _MFI; lockedMFI = _lockedMFI; // for initialization purposes and to ensure availability of service // the team's locked MFI participate in maintenance staking only // (not in the incentive staking part) // this implies some trust of the team to execute, which we deem reasonable // since the locked stake is temporary and diminishing as well as the fact // that the team is heavily invested in the protocol and incentivized // by fees like any other maintainer // furthermore others could step in to liquidate via the attacker route // and take away the team fees if they were delinquent nextMaintenanceStaker[_lockedMFI] = _lockedMFI; currentMaintenanceStaker = _lockedMFI; prevMaintenanceStaker = _lockedMFI; maintenanceDelegateTo[_lockedMFI][lockedMFIDelegate] = true; currentMaintenanceStakerStartBlock = block.number; } /// Maintence stake setter function setMaintenanceStakePerBlock(uint256 amount) external onlyOwnerExec { maintenanceStakePerBlock = amount; } function _stake(address holder, uint256 amount) internal { Fund(fund()).depositFor(holder, MFI, amount); stakes[holder] += amount; totalStakes += amount; IncentiveReporter.addToClaimAmount(MFI, holder, amount); } function _withdrawStake( address holder, uint256 amount, address recipient ) internal { // overflow failure desirable stakes[holder] -= amount; totalStakes -= amount; Fund(fund()).withdraw(MFI, recipient, amount); IncentiveReporter.subtractFromClaimAmount(MFI, holder, amount); } /// Withdraw stake for sender function withdrawStake(uint256 amount) external { require( !isAuthorizedStaker(msg.sender), "You can't withdraw while you're authorized staker" ); _withdrawStake(msg.sender, amount, msg.sender); } /// Deposit maintenance stake function depositMaintenanceStake(uint256 amount) external { require( amount + stakes[msg.sender] >= maintenanceStakePerBlock, "Insufficient stake to call even one block" ); _stake(msg.sender, amount); if (nextMaintenanceStaker[msg.sender] == address(0)) { nextMaintenanceStaker[msg.sender] = getUpdatedCurrentStaker(); nextMaintenanceStaker[prevMaintenanceStaker] = msg.sender; } } function getMaintenanceStakerStake(address staker) public view returns (uint256) { if (staker == lockedMFI) { return IERC20(MFI).balanceOf(lockedMFI) / 2; } else { return stakes[staker]; } } function getUpdatedCurrentStaker() public returns (address) { uint256 currentStake = getMaintenanceStakerStake(currentMaintenanceStaker); if ( (block.number - currentMaintenanceStakerStartBlock) * maintenanceStakePerBlock >= currentStake ) { currentMaintenanceStakerStartBlock = block.number; prevMaintenanceStaker = currentMaintenanceStaker; currentMaintenanceStaker = nextMaintenanceStaker[ currentMaintenanceStaker ]; currentStake = getMaintenanceStakerStake(currentMaintenanceStaker); if (maintenanceStakePerBlock > currentStake) { // delete current from daisy chain address nextOne = nextMaintenanceStaker[currentMaintenanceStaker]; nextMaintenanceStaker[prevMaintenanceStaker] = nextOne; nextMaintenanceStaker[currentMaintenanceStaker] = address(0); currentMaintenanceStaker = nextOne; currentStake = getMaintenanceStakerStake( currentMaintenanceStaker ); } } return currentMaintenanceStaker; } function viewCurrentMaintenanceStaker() public view returns (address staker, uint256 startBlock) { staker = currentMaintenanceStaker; uint256 currentStake = getMaintenanceStakerStake(staker); startBlock = currentMaintenanceStakerStartBlock; if ( (block.number - startBlock) * maintenanceStakePerBlock >= currentStake ) { staker = nextMaintenanceStaker[staker]; currentStake = getMaintenanceStakerStake(staker); startBlock = block.number; if (maintenanceStakePerBlock > currentStake) { staker = nextMaintenanceStaker[staker]; } } } /// Add a delegate for staker function addDelegate(address forStaker, address delegate) external { require( msg.sender == forStaker || maintenanceDelegateTo[forStaker][msg.sender], "msg.sender not authorized to delegate for staker" ); maintenanceDelegateTo[forStaker][delegate] = true; } /// Remove a delegate for staker function removeDelegate(address forStaker, address delegate) external { require( msg.sender == forStaker || maintenanceDelegateTo[forStaker][msg.sender], "msg.sender not authorized to delegate for staker" ); maintenanceDelegateTo[forStaker][delegate] = false; } function isAuthorizedStaker(address caller) public returns (bool isAuthorized) { address currentStaker = getUpdatedCurrentStaker(); isAuthorized = currentStaker == caller || maintenanceDelegateTo[currentStaker][caller]; } /// Penalize a staker function penalizeMaintenanceStake( address maintainer, uint256 penalty, address recipient ) external returns (uint256 stakeTaken) { require( isStakePenalizer(msg.sender), "msg.sender not authorized to penalize stakers" ); if (penalty > stakes[maintainer]) { stakeTaken = stakes[maintainer]; } else { stakeTaken = penalty; } _withdrawStake(maintainer, stakeTaken, recipient); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./RoleAware.sol"; /// @title Base lending behavior abstract contract BaseLending { uint256 constant FP48 = 2**48; uint256 constant ACCUMULATOR_INIT = 10**18; uint256 constant hoursPerYear = 365 days / (1 hours); uint256 constant CHANGE_POINT = 82; uint256 public normalRatePerPercent = (FP48 * 12) / hoursPerYear / CHANGE_POINT / 100; uint256 public highRatePerPercent = (FP48 * (135 - 12)) / hoursPerYear / (100 - CHANGE_POINT) / 100; struct YieldAccumulator { uint256 accumulatorFP; uint256 lastUpdated; uint256 hourlyYieldFP; } struct LendingMetadata { uint256 totalLending; uint256 totalBorrowed; uint256 lendingCap; uint256 cumulIncentiveAllocationFP; uint256 incentiveLastUpdated; uint256 incentiveEnd; uint256 incentiveTarget; } mapping(address => LendingMetadata) public lendingMeta; /// @dev accumulate interest per issuer (like compound indices) mapping(address => YieldAccumulator) public borrowYieldAccumulators; /// @dev simple formula for calculating interest relative to accumulator function applyInterest( uint256 balance, uint256 accumulatorFP, uint256 yieldQuotientFP ) internal pure returns (uint256) { // 1 * FP / FP = 1 return (balance * accumulatorFP) / yieldQuotientFP; } function currentLendingRateFP(uint256 totalLending, uint256 totalBorrowing) internal view returns (uint256 rate) { rate = FP48; uint256 utilizationPercent = totalLending > 0 ? (100 * totalBorrowing) / totalLending : 0; if (utilizationPercent < CHANGE_POINT) { rate += utilizationPercent * normalRatePerPercent; } else { rate += CHANGE_POINT * normalRatePerPercent + (utilizationPercent - CHANGE_POINT) * highRatePerPercent; } } /// @dev minimum function min(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return b; } else { return a; } } /// @dev maximum function max(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return a; } else { return b; } } /// Available tokens to this issuance function issuanceBalance(address issuance) internal view virtual returns (uint256); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Fund.sol"; import "../libraries/UniswapStyleLib.sol"; abstract contract BaseRouter is UniswapStyleLib { modifier ensure(uint256 deadline) { require(deadline >= block.timestamp, "Trade has expired"); _; } // **** SWAP **** /// @dev requires the initial amount to have already been sent to the first pair /// and for pairs to be vetted (which getAmountsIn / getAmountsOut do) function _swap( uint256[] memory amounts, address[] memory pairs, address[] memory tokens, address _to ) internal { for (uint256 i; i < pairs.length; i++) { (address input, address output) = (tokens[i], tokens[i + 1]); (address token0, ) = UniswapStyleLib.sortTokens(input, output); uint256 amountOut = amounts[i + 1]; (uint256 amount0Out, uint256 amount1Out) = input == token0 ? (uint256(0), amountOut) : (amountOut, uint256(0)); address to = i < pairs.length - 1 ? pairs[i + 1] : _to; IUniswapV2Pair pair = IUniswapV2Pair(pairs[i]); pair.swap(amount0Out, amount1Out, to, new bytes(0)); } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./Fund.sol"; import "./Lending.sol"; import "./RoleAware.sol"; import "./PriceAware.sol"; // Goal: all external functions only accessible to margintrader role // except for view functions of course struct CrossMarginAccount { uint256 lastDepositBlock; address[] borrowTokens; // borrowed token address => amount mapping(address => uint256) borrowed; // borrowed token => yield quotient mapping(address => uint256) borrowedYieldQuotientsFP; address[] holdingTokens; // token held in portfolio => amount mapping(address => uint256) holdings; // boolean value of whether an account holds a token mapping(address => bool) holdsToken; } abstract contract CrossMarginAccounts is RoleAware, PriceAware { /// @dev gets used in calculating how much accounts can borrow uint256 public leveragePercent = 300; /// @dev percentage of assets held per assets borrowed at which to liquidate uint256 public liquidationThresholdPercent = 115; /// @dev record of all cross margin accounts mapping(address => CrossMarginAccount) internal marginAccounts; /// @dev total token caps mapping(address => uint256) public tokenCaps; /// @dev tracks total of long positions per token mapping(address => uint256) public totalLong; uint256 public coolingOffPeriod = 10; /// @dev add an asset to be held by account function addHolding( CrossMarginAccount storage account, address token, uint256 depositAmount ) internal { if (!hasHoldingToken(account, token)) { account.holdingTokens.push(token); account.holdsToken[token] = true; } account.holdings[token] += depositAmount; } /// @dev adjust account to reflect borrowing of token amount function borrow( CrossMarginAccount storage account, address borrowToken, uint256 borrowAmount ) internal { if (!hasBorrowedToken(account, borrowToken)) { account.borrowTokens.push(borrowToken); account.borrowedYieldQuotientsFP[borrowToken] = Lending(lending()) .getUpdatedBorrowYieldAccuFP(borrowToken); account.borrowed[borrowToken] = borrowAmount; } else { (uint256 oldBorrowed, uint256 accumulatorFP) = Lending(lending()).applyBorrowInterest( account.borrowed[borrowToken], borrowToken, account.borrowedYieldQuotientsFP[borrowToken] ); account.borrowedYieldQuotientsFP[borrowToken] = accumulatorFP; account.borrowed[borrowToken] = oldBorrowed + borrowAmount; } require(positiveBalance(account), "Insufficient balance"); } /// @dev checks whether account is in the black, deposit + earnings relative to borrowed function positiveBalance(CrossMarginAccount storage account) internal returns (bool) { uint256 loan = loanInPeg(account); uint256 holdings = holdingsInPeg(account); // The following condition should hold: // holdings / loan >= leveragePercent / (leveragePercent - 100) // => return holdings * (leveragePercent - 100) >= loan * leveragePercent; } /// @dev internal function adjusting holding and borrow balances when debt extinguished function extinguishDebt( CrossMarginAccount storage account, address debtToken, uint256 extinguishAmount ) internal { // will throw if insufficient funds (uint256 borrowAmount, uint256 newYieldQuot) = Lending(lending()).applyBorrowInterest( account.borrowed[debtToken], debtToken, account.borrowedYieldQuotientsFP[debtToken] ); uint256 newBorrowAmount = borrowAmount - extinguishAmount; account.borrowed[debtToken] = newBorrowAmount; if (newBorrowAmount > 0) { account.borrowedYieldQuotientsFP[debtToken] = newYieldQuot; } else { delete account.borrowedYieldQuotientsFP[debtToken]; bool decrement = false; uint256 len = account.borrowTokens.length; for (uint256 i; len > i; i++) { address currToken = account.borrowTokens[i]; if (currToken == debtToken) { decrement = true; } else if (decrement) { account.borrowTokens[i - 1] = currToken; } } account.borrowTokens.pop(); } } /// @dev checks whether an account holds a token function hasHoldingToken(CrossMarginAccount storage account, address token) internal view returns (bool) { return account.holdsToken[token]; } /// @dev checks whether an account has borrowed a token function hasBorrowedToken(CrossMarginAccount storage account, address token) internal view returns (bool) { return account.borrowedYieldQuotientsFP[token] > 0; } /// @dev calculate total loan in reference currency, including compound interest function loanInPeg(CrossMarginAccount storage account) internal returns (uint256) { return sumTokensInPegWithYield( account.borrowTokens, account.borrowed, account.borrowedYieldQuotientsFP ); } /// @dev total of assets of account, expressed in reference currency function holdingsInPeg(CrossMarginAccount storage account) internal returns (uint256) { return sumTokensInPeg(account.holdingTokens, account.holdings); } /// @dev check whether an account can/should be liquidated function belowMaintenanceThreshold(CrossMarginAccount storage account) internal returns (bool) { uint256 loan = loanInPeg(account); uint256 holdings = holdingsInPeg(account); // The following should hold: // holdings / loan >= 1.1 // => holdings >= loan * 1.1 return 100 * holdings < liquidationThresholdPercent * loan; } /// @dev go through list of tokens and their amounts, summing up function sumTokensInPeg( address[] storage tokens, mapping(address => uint256) storage amounts ) internal returns (uint256 totalPeg) { uint256 len = tokens.length; for (uint256 tokenId; tokenId < len; tokenId++) { address token = tokens[tokenId]; totalPeg += PriceAware.getCurrentPriceInPeg(token, amounts[token]); } } /// @dev go through list of tokens and their amounts, summing up function viewTokensInPeg( address[] storage tokens, mapping(address => uint256) storage amounts ) internal view returns (uint256 totalPeg) { uint256 len = tokens.length; for (uint256 tokenId; tokenId < len; tokenId++) { address token = tokens[tokenId]; totalPeg += PriceAware.viewCurrentPriceInPeg(token, amounts[token]); } } /// @dev go through list of tokens and ammounts, summing up with interest function sumTokensInPegWithYield( address[] storage tokens, mapping(address => uint256) storage amounts, mapping(address => uint256) storage yieldQuotientsFP ) internal returns (uint256 totalPeg) { uint256 len = tokens.length; for (uint256 tokenId; tokenId < len; tokenId++) { address token = tokens[tokenId]; totalPeg += yieldTokenInPeg( token, amounts[token], yieldQuotientsFP ); } } /// @dev go through list of tokens and ammounts, summing up with interest function viewTokensInPegWithYield( address[] storage tokens, mapping(address => uint256) storage amounts, mapping(address => uint256) storage yieldQuotientsFP ) internal view returns (uint256 totalPeg) { uint256 len = tokens.length; for (uint256 tokenId; tokenId < len; tokenId++) { address token = tokens[tokenId]; totalPeg += viewYieldTokenInPeg( token, amounts[token], yieldQuotientsFP ); } } /// @dev calculate yield for token amount and convert to reference currency function yieldTokenInPeg( address token, uint256 amount, mapping(address => uint256) storage yieldQuotientsFP ) internal returns (uint256) { uint256 yieldFP = Lending(lending()).viewAccumulatedBorrowingYieldFP(token); // 1 * FP / FP = 1 uint256 amountInToken = (amount * yieldFP) / yieldQuotientsFP[token]; return PriceAware.getCurrentPriceInPeg(token, amountInToken); } /// @dev calculate yield for token amount and convert to reference currency function viewYieldTokenInPeg( address token, uint256 amount, mapping(address => uint256) storage yieldQuotientsFP ) internal view returns (uint256) { uint256 yieldFP = Lending(lending()).viewAccumulatedBorrowingYieldFP(token); // 1 * FP / FP = 1 uint256 amountInToken = (amount * yieldFP) / yieldQuotientsFP[token]; return PriceAware.viewCurrentPriceInPeg(token, amountInToken); } /// @dev move tokens from one holding to another function adjustAmounts( CrossMarginAccount storage account, address fromToken, address toToken, uint256 soldAmount, uint256 boughtAmount ) internal { account.holdings[fromToken] = account.holdings[fromToken] - soldAmount; addHolding(account, toToken, boughtAmount); } /// sets borrow and holding to zero function deleteAccount(CrossMarginAccount storage account) internal { uint256 len = account.borrowTokens.length; for (uint256 borrowIdx; len > borrowIdx; borrowIdx++) { address borrowToken = account.borrowTokens[borrowIdx]; account.borrowed[borrowToken] = 0; account.borrowedYieldQuotientsFP[borrowToken] = 0; } len = account.holdingTokens.length; for (uint256 holdingIdx; len > holdingIdx; holdingIdx++) { address holdingToken = account.holdingTokens[holdingIdx]; totalLong[holdingToken] -= account.holdings[holdingToken]; account.holdings[holdingToken] = 0; account.holdsToken[holdingToken] = false; } delete account.borrowTokens; delete account.holdingTokens; } /// @dev minimum function min(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return b; } else { return a; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./CrossMarginAccounts.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "./Admin.sol"; /** @title Handles liquidation of accounts below maintenance threshold @notice Liquidation can be called by the authorized staker, as determined in the Admin contract. If the authorized staker is delinquent, other participants can jump in and attack, taking their fees and potentially even their stake, depending how delinquent the responsible authorized staker is. */ abstract contract CrossMarginLiquidation is CrossMarginAccounts { event LiquidationShortfall(uint256 amount); event AccountLiquidated(address account); struct Liquidation { uint256 buy; uint256 sell; uint256 blockNum; } /// record kept around until a stake attacker can claim their reward struct AccountLiqRecord { uint256 blockNum; address loser; uint256 amount; address stakeAttacker; } mapping(address => Liquidation) liquidationAmounts; address[] internal liquidationTokens; address[] internal tradersToLiquidate; mapping(address => uint256) public maintenanceFailures; mapping(address => AccountLiqRecord) public stakeAttackRecords; uint256 public avgLiquidationPerCall = 10; uint256 public liqStakeAttackWindow = 5; uint256 public MAINTAINER_CUT_PERCENT = 5; uint256 public failureThreshold = 10; /// Set failure threshold function setFailureThreshold(uint256 threshFactor) external onlyOwnerExec { failureThreshold = threshFactor; } /// Set liquidity stake attack window function setLiqStakeAttackWindow(uint256 window) external onlyOwnerExec { liqStakeAttackWindow = window; } /// Set maintainer's percent cut function setMaintainerCutPercent(uint256 cut) external onlyOwnerExec { MAINTAINER_CUT_PERCENT = cut; } /// @dev calcLiquidationAmounts does a number of tasks in this contract /// and some of them are not straightforward. /// First of all it aggregates liquidation amounts, /// as well as which traders are ripe for liquidation, in storage (not in memory) /// owing to the fact that arrays can't be pushed to and hash maps don't /// exist in memory. /// Then it also returns any stake attack funds if the stake was unsuccessful /// (i.e. current caller is authorized). Also see context below. function calcLiquidationAmounts( address[] memory liquidationCandidates, bool isAuthorized ) internal returns (uint256 attackReturns) { liquidationTokens = new address[](0); tradersToLiquidate = new address[](0); for ( uint256 traderIndex = 0; liquidationCandidates.length > traderIndex; traderIndex++ ) { address traderAddress = liquidationCandidates[traderIndex]; CrossMarginAccount storage account = marginAccounts[traderAddress]; if (belowMaintenanceThreshold(account)) { tradersToLiquidate.push(traderAddress); uint256 len = account.holdingTokens.length; for (uint256 sellIdx = 0; len > sellIdx; sellIdx++) { address token = account.holdingTokens[sellIdx]; Liquidation storage liquidation = liquidationAmounts[token]; if (liquidation.blockNum != block.number) { liquidation.sell = account.holdings[token]; liquidation.buy = 0; liquidation.blockNum = block.number; liquidationTokens.push(token); } else { liquidation.sell += account.holdings[token]; } } len = account.borrowTokens.length; for (uint256 buyIdx = 0; len > buyIdx; buyIdx++) { address token = account.borrowTokens[buyIdx]; Liquidation storage liquidation = liquidationAmounts[token]; (uint256 loanAmount, ) = Lending(lending()).applyBorrowInterest( account.borrowed[token], token, account.borrowedYieldQuotientsFP[token] ); Lending(lending()).payOff(token, loanAmount); if (liquidation.blockNum != block.number) { liquidation.sell = 0; liquidation.buy = loanAmount; liquidation.blockNum = block.number; liquidationTokens.push(token); } else { liquidation.buy += loanAmount; } } } AccountLiqRecord storage liqAttackRecord = stakeAttackRecords[traderAddress]; if (isAuthorized) { attackReturns += _disburseLiqAttack(liqAttackRecord); } } } function _disburseLiqAttack(AccountLiqRecord storage liqAttackRecord) internal returns (uint256 returnAmount) { if (liqAttackRecord.amount > 0) { // validate attack records, if any uint256 blockDiff = min( block.number - liqAttackRecord.blockNum, liqStakeAttackWindow ); uint256 attackerCut = (liqAttackRecord.amount * blockDiff) / liqStakeAttackWindow; Fund(fund()).withdraw( PriceAware.peg, liqAttackRecord.stakeAttacker, attackerCut ); Admin a = Admin(admin()); uint256 penalty = (a.maintenanceStakePerBlock() * attackerCut) / (1 + avgLiquidationPerCall); a.penalizeMaintenanceStake( liqAttackRecord.loser, penalty, liqAttackRecord.stakeAttacker ); // return remainder, after cut was taken to authorized stakekr returnAmount = liqAttackRecord.amount - attackerCut; } } /// Disburse liquidity stake attacks function disburseLiqStakeAttacks(address[] memory liquidatedAccounts) external { for (uint256 i = 0; liquidatedAccounts.length > i; i++) { address liqAccount = liquidatedAccounts[i]; AccountLiqRecord storage liqAttackRecord = stakeAttackRecords[liqAccount]; if ( block.number > liqAttackRecord.blockNum + liqStakeAttackWindow ) { _disburseLiqAttack(liqAttackRecord); delete stakeAttackRecords[liqAccount]; } } } function liquidateFromPeg() internal returns (uint256 pegAmount) { uint256 len = liquidationTokens.length; for (uint256 tokenIdx = 0; len > tokenIdx; tokenIdx++) { address buyToken = liquidationTokens[tokenIdx]; Liquidation storage liq = liquidationAmounts[buyToken]; if (liq.buy > liq.sell) { pegAmount += PriceAware.liquidateFromPeg( buyToken, liq.buy - liq.sell ); delete liquidationAmounts[buyToken]; } } } function liquidateToPeg() internal returns (uint256 pegAmount) { uint256 len = liquidationTokens.length; for (uint256 tokenIndex = 0; len > tokenIndex; tokenIndex++) { address token = liquidationTokens[tokenIndex]; Liquidation storage liq = liquidationAmounts[token]; if (liq.sell > liq.buy) { uint256 sellAmount = liq.sell - liq.buy; pegAmount += PriceAware.liquidateToPeg(token, sellAmount); delete liquidationAmounts[token]; } } } function maintainerIsFailing() internal view returns (bool) { (address currentMaintainer, ) = Admin(admin()).viewCurrentMaintenanceStaker(); return maintenanceFailures[currentMaintainer] > failureThreshold * avgLiquidationPerCall; } /// called by maintenance stakers to liquidate accounts below liquidation threshold function liquidate(address[] memory liquidationCandidates) external noIntermediary returns (uint256 maintainerCut) { bool isAuthorized = Admin(admin()).isAuthorizedStaker(msg.sender); bool canTakeNow = isAuthorized || maintainerIsFailing(); // calcLiquidationAmounts does a lot of the work here // * aggregates both sell and buy side targets to be liquidated // * returns attacker cuts to them // * aggregates any returned fees from unauthorized (attacking) attempts maintainerCut = calcLiquidationAmounts( liquidationCandidates, isAuthorized ); uint256 sale2pegAmount = liquidateToPeg(); uint256 peg2targetCost = liquidateFromPeg(); delete liquidationTokens; // this may be a bit imprecise, since individual shortfalls may be obscured // by overall returns and the maintainer cut is taken out of the net total, // but it gives us the general picture uint256 costWithCut = (peg2targetCost * (100 + MAINTAINER_CUT_PERCENT)) / 100; if (costWithCut > sale2pegAmount) { emit LiquidationShortfall(costWithCut - sale2pegAmount); canTakeNow = canTakeNow && IERC20(peg).balanceOf(fund()) > costWithCut; } address loser = address(0); if (!canTakeNow) { // whoever is the current responsible maintenance staker // and liable to lose their stake loser = Admin(admin()).getUpdatedCurrentStaker(); } // iterate over traders and send back their money // as well as giving attackers their due, in case caller isn't authorized for ( uint256 traderIdx = 0; tradersToLiquidate.length > traderIdx; traderIdx++ ) { address traderAddress = tradersToLiquidate[traderIdx]; CrossMarginAccount storage account = marginAccounts[traderAddress]; uint256 holdingsValue = holdingsInPeg(account); uint256 borrowValue = loanInPeg(account); // 5% of value borrowed uint256 maintainerCut4Account = (borrowValue * MAINTAINER_CUT_PERCENT) / 100; maintainerCut += maintainerCut4Account; if (!canTakeNow) { // This could theoretically lead to a previous attackers // record being overwritten, but only if the trader restarts // their account and goes back into the red within the short time window // which would be a costly attack requiring collusion without upside AccountLiqRecord storage liqAttackRecord = stakeAttackRecords[traderAddress]; liqAttackRecord.amount = maintainerCut4Account; liqAttackRecord.stakeAttacker = msg.sender; liqAttackRecord.blockNum = block.number; liqAttackRecord.loser = loser; } // send back trader money // include 1% for protocol uint256 forfeited = maintainerCut4Account + (borrowValue * 101) / 100; if (holdingsValue > forfeited) { // send remaining funds back to trader Fund(fund()).withdraw( PriceAware.peg, traderAddress, holdingsValue - forfeited ); } emit AccountLiquidated(traderAddress); deleteAccount(account); } avgLiquidationPerCall = (avgLiquidationPerCall * 99 + maintainerCut) / 100; if (canTakeNow) { Fund(fund()).withdraw(PriceAware.peg, msg.sender, maintainerCut); } address currentMaintainer = Admin(admin()).getUpdatedCurrentStaker(); if (isAuthorized) { if (maintenanceFailures[currentMaintainer] > maintainerCut) { maintenanceFailures[currentMaintainer] -= maintainerCut; } else { maintenanceFailures[currentMaintainer] = 0; } } else { maintenanceFailures[currentMaintainer] += maintainerCut; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/Address.sol"; import "../interfaces/IWETH.sol"; import "./RoleAware.sol"; /// @title Manage funding contract Fund is RoleAware { using SafeERC20 for IERC20; /// wrapped ether address public immutable WETH; constructor(address _WETH, address _roles) RoleAware(_roles) { WETH = _WETH; } /// Deposit an active token function deposit(address depositToken, uint256 depositAmount) external { IERC20(depositToken).safeTransferFrom( msg.sender, address(this), depositAmount ); } /// Deposit token on behalf of `sender` function depositFor( address sender, address depositToken, uint256 depositAmount ) external { require(isFundTransferer(msg.sender), "Unauthorized deposit"); IERC20(depositToken).safeTransferFrom( sender, address(this), depositAmount ); } /// Deposit to wrapped ether function depositToWETH() external payable { IWETH(WETH).deposit{value: msg.value}(); } // withdrawers role function withdraw( address withdrawalToken, address recipient, uint256 withdrawalAmount ) external { require(isFundTransferer(msg.sender), "Unauthorized withdraw"); IERC20(withdrawalToken).safeTransfer(recipient, withdrawalAmount); } // withdrawers role function withdrawETH(address recipient, uint256 withdrawalAmount) external { require(isFundTransferer(msg.sender), "Unauthorized withdraw"); IWETH(WETH).withdraw(withdrawalAmount); Address.sendValue(payable(recipient), withdrawalAmount); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./BaseLending.sol"; struct HourlyBond { uint256 amount; uint256 yieldQuotientFP; uint256 moduloHour; uint256 incentiveAllocationStart; } /// @title Here we offer subscriptions to auto-renewing hourly bonds /// Funds are locked in for an 50 minutes per hour, while interest rates float abstract contract HourlyBondSubscriptionLending is BaseLending { mapping(address => YieldAccumulator) hourlyBondYieldAccumulators; uint256 constant RATE_UPDATE_WINDOW = 10 minutes; uint256 public withdrawalWindow = 20 minutes; uint256 constant MAX_HOUR_UPDATE = 4; // issuer => holder => bond record mapping(address => mapping(address => HourlyBond)) public hourlyBondAccounts; uint256 public borrowingFactorPercent = 200; uint256 constant borrowMinAPR = 25; uint256 constant borrowMinHourlyYield = FP48 + (borrowMinAPR * FP48) / 1000 / hoursPerYear; function _makeHourlyBond( address issuer, address holder, uint256 amount ) internal { HourlyBond storage bond = hourlyBondAccounts[issuer][holder]; LendingMetadata storage meta = lendingMeta[issuer]; addToTotalLending(meta, amount); updateHourlyBondAmount(issuer, bond, holder); if (bond.amount == 0) { bond.moduloHour = block.timestamp % (1 hours); } bond.amount += amount; } function updateHourlyBondAmount( address issuer, HourlyBond storage bond, address holder ) internal { uint256 yieldQuotientFP = bond.yieldQuotientFP; YieldAccumulator storage yA = getUpdatedHourlyYield( issuer, hourlyBondYieldAccumulators[issuer], RATE_UPDATE_WINDOW ); LendingMetadata storage meta = lendingMeta[issuer]; if (yieldQuotientFP > 0) { disburseIncentive(bond, meta, holder); uint256 oldAmount = bond.amount; bond.amount = applyInterest( bond.amount, yA.accumulatorFP, yieldQuotientFP ); uint256 deltaAmount = bond.amount - oldAmount; addToTotalLending(meta, deltaAmount); } else { bond.incentiveAllocationStart = meta.cumulIncentiveAllocationFP; } bond.yieldQuotientFP = yA.accumulatorFP; } // Retrieves bond balance for issuer and holder function viewHourlyBondAmount(address issuer, address holder) public view returns (uint256) { HourlyBond storage bond = hourlyBondAccounts[issuer][holder]; uint256 yieldQuotientFP = bond.yieldQuotientFP; uint256 cumulativeYield = viewCumulativeYieldFP( hourlyBondYieldAccumulators[issuer], block.timestamp ); if (yieldQuotientFP > 0) { return applyInterest(bond.amount, cumulativeYield, yieldQuotientFP); } else { return bond.amount; } } function _withdrawHourlyBond( address issuer, HourlyBond storage bond, uint256 amount, address holder ) internal { subtractFromTotalLending(lendingMeta[issuer], amount); updateHourlyBondAmount(issuer, bond, holder); // how far the current hour has advanced (relative to acccount hourly clock) uint256 currentOffset = (block.timestamp - bond.moduloHour) % (1 hours); require( withdrawalWindow >= currentOffset, "Tried withdrawing outside subscription cancellation time window" ); bond.amount -= amount; } function calcCumulativeYieldFP( YieldAccumulator storage yieldAccumulator, uint256 timeDelta ) internal view returns (uint256 accumulatorFP) { uint256 secondsDelta = timeDelta % (1 hours); // linearly interpolate interest for seconds // FP * FP * 1 / (FP * 1) = FP accumulatorFP = yieldAccumulator.accumulatorFP + (yieldAccumulator.accumulatorFP * (yieldAccumulator.hourlyYieldFP - FP48) * secondsDelta) / (FP48 * 1 hours); uint256 hoursDelta = timeDelta / (1 hours); if (hoursDelta > 0) { uint256 accumulatorBeforeFP = accumulatorFP; for (uint256 i = 0; hoursDelta > i && MAX_HOUR_UPDATE > i; i++) { // FP48 * FP48 / FP48 = FP48 accumulatorFP = (accumulatorFP * yieldAccumulator.hourlyYieldFP) / FP48; } // a lot of time has passed if (hoursDelta > MAX_HOUR_UPDATE) { // apply interest in non-compounding way accumulatorFP += ((accumulatorFP - accumulatorBeforeFP) * (hoursDelta - MAX_HOUR_UPDATE)) / MAX_HOUR_UPDATE; } } } /// @dev updates yield accumulators for both borrowing and lending /// issuer address represents a token function updateHourlyYield(address issuer) public returns (uint256 hourlyYield) { return getUpdatedHourlyYield( issuer, hourlyBondYieldAccumulators[issuer], RATE_UPDATE_WINDOW ) .hourlyYieldFP; } /// @dev updates yield accumulators for both borrowing and lending function getUpdatedHourlyYield( address issuer, YieldAccumulator storage accumulator, uint256 window ) internal returns (YieldAccumulator storage) { uint256 lastUpdated = accumulator.lastUpdated; uint256 timeDelta = (block.timestamp - lastUpdated); if (timeDelta > window) { YieldAccumulator storage borrowAccumulator = borrowYieldAccumulators[issuer]; accumulator.accumulatorFP = calcCumulativeYieldFP( accumulator, timeDelta ); LendingMetadata storage meta = lendingMeta[issuer]; accumulator.hourlyYieldFP = currentLendingRateFP( meta.totalLending, meta.totalBorrowed ); accumulator.lastUpdated = block.timestamp; updateBorrowYieldAccu(borrowAccumulator); borrowAccumulator.hourlyYieldFP = max( borrowMinHourlyYield, FP48 + (borrowingFactorPercent * (accumulator.hourlyYieldFP - FP48)) / 100 ); } return accumulator; } function updateBorrowYieldAccu(YieldAccumulator storage borrowAccumulator) internal { uint256 timeDelta = block.timestamp - borrowAccumulator.lastUpdated; if (timeDelta > RATE_UPDATE_WINDOW) { borrowAccumulator.accumulatorFP = calcCumulativeYieldFP( borrowAccumulator, timeDelta ); borrowAccumulator.lastUpdated = block.timestamp; } } function getUpdatedBorrowYieldAccuFP(address issuer) external returns (uint256) { YieldAccumulator storage yA = borrowYieldAccumulators[issuer]; updateBorrowYieldAccu(yA); return yA.accumulatorFP; } function viewCumulativeYieldFP( YieldAccumulator storage yA, uint256 timestamp ) internal view returns (uint256) { uint256 timeDelta = (timestamp - yA.lastUpdated); if (timeDelta > RATE_UPDATE_WINDOW) { return calcCumulativeYieldFP(yA, timeDelta); } else { return yA.accumulatorFP; } } function viewYearlyIncentivePer10k(address token) external view returns (uint256) { LendingMetadata storage meta = lendingMeta[token]; if ( meta.incentiveEnd < block.timestamp || meta.incentiveLastUpdated > meta.incentiveEnd ) { return 0; } else { uint256 timeDelta = meta.incentiveEnd - meta.incentiveLastUpdated; // scale to 1 year return (10_000 * (365 days) * meta.incentiveTarget) / (1 + meta.totalLending * timeDelta); } } function updateIncentiveAllocation(LendingMetadata storage meta) internal { uint256 endTime = min(meta.incentiveEnd, block.timestamp); if (meta.incentiveTarget > 0 && endTime > meta.incentiveLastUpdated) { uint256 timeDelta = endTime - meta.incentiveLastUpdated; uint256 targetDelta = min( meta.incentiveTarget, (timeDelta * meta.incentiveTarget) / (meta.incentiveEnd - meta.incentiveLastUpdated) ); meta.incentiveTarget -= targetDelta; meta.cumulIncentiveAllocationFP += (targetDelta * FP48) / (1 + meta.totalLending); meta.incentiveLastUpdated = block.timestamp; } } function addToTotalLending(LendingMetadata storage meta, uint256 amount) internal { updateIncentiveAllocation(meta); meta.totalLending += amount; } function subtractFromTotalLending( LendingMetadata storage meta, uint256 amount ) internal { updateIncentiveAllocation(meta); meta.totalLending -= amount; } function disburseIncentive( HourlyBond storage bond, LendingMetadata storage meta, address holder ) internal virtual; }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Fund.sol"; import "./HourlyBondSubscriptionLending.sol"; import "../libraries/IncentiveReporter.sol"; // TODO activate bonds for lending /// @title Manage lending for a variety of bond issuers contract Lending is RoleAware, HourlyBondSubscriptionLending { /// mapping issuers to tokens /// (in crossmargin, the issuers are tokens themselves) mapping(address => address) public issuerTokens; /// In case of shortfall, adjust debt mapping(address => uint256) public haircuts; /// map of available issuers mapping(address => bool) public activeIssuers; uint256 constant BORROW_RATE_UPDATE_WINDOW = 60 minutes; address public immutable MFI; constructor(address _MFI, address _roles) RoleAware(_roles) { MFI = _MFI; } /// Make a issuer available for protocol function activateIssuer(address issuer) external { activateIssuer(issuer, issuer); } /// Make issuer != token available for protocol (isol. margin) function activateIssuer(address issuer, address token) public onlyOwnerExecActivator { activeIssuers[issuer] = true; issuerTokens[issuer] = token; } /// Remove a issuer from trading availability function deactivateIssuer(address issuer) external onlyOwnerExecActivator { activeIssuers[issuer] = false; } /// Set lending cap function setLendingCap(address issuer, uint256 cap) external onlyOwnerExecActivator { lendingMeta[issuer].lendingCap = cap; } /// Set withdrawal window function setWithdrawalWindow(uint256 window) external onlyOwnerExec { withdrawalWindow = window; } function setNormalRatePerPercent(uint256 rate) external onlyOwnerExec { normalRatePerPercent = rate; } function setHighRatePerPercent(uint256 rate) external onlyOwnerExec { highRatePerPercent = rate; } /// Set hourly yield APR for issuer function setHourlyYieldAPR(address issuer, uint256 aprPercent) external onlyOwnerExecActivator { YieldAccumulator storage yieldAccumulator = hourlyBondYieldAccumulators[issuer]; if (yieldAccumulator.accumulatorFP == 0) { uint256 yieldFP = FP48 + (FP48 * aprPercent) / 100 / (24 * 365); hourlyBondYieldAccumulators[issuer] = YieldAccumulator({ accumulatorFP: FP48, lastUpdated: block.timestamp, hourlyYieldFP: yieldFP }); } else { YieldAccumulator storage yA = getUpdatedHourlyYield( issuer, yieldAccumulator, RATE_UPDATE_WINDOW ); yA.hourlyYieldFP = (FP48 * (100 + aprPercent)) / 100 / (24 * 365); } } /// @dev how much interest has accrued to a borrowed balance over time function applyBorrowInterest( uint256 balance, address issuer, uint256 yieldQuotientFP ) external returns (uint256 balanceWithInterest, uint256 accumulatorFP) { require(isBorrower(msg.sender), "Not approved call"); YieldAccumulator storage yA = borrowYieldAccumulators[issuer]; updateBorrowYieldAccu(yA); accumulatorFP = yA.accumulatorFP; balanceWithInterest = applyInterest( balance, accumulatorFP, yieldQuotientFP ); uint256 deltaAmount = balanceWithInterest - balance; LendingMetadata storage meta = lendingMeta[issuer]; meta.totalBorrowed += deltaAmount; } /// @dev view function to get balance with borrowing interest applied function viewWithBorrowInterest( uint256 balance, address issuer, uint256 yieldQuotientFP ) external view returns (uint256) { uint256 accumulatorFP = viewCumulativeYieldFP( borrowYieldAccumulators[issuer], block.timestamp ); return applyInterest(balance, accumulatorFP, yieldQuotientFP); } /// @dev gets called by router to register if a trader borrows issuers function registerBorrow(address issuer, uint256 amount) external { require(isBorrower(msg.sender), "Not approved borrower"); require(activeIssuers[issuer], "Not approved issuer"); LendingMetadata storage meta = lendingMeta[issuer]; meta.totalBorrowed += amount; getUpdatedHourlyYield( issuer, hourlyBondYieldAccumulators[issuer], BORROW_RATE_UPDATE_WINDOW ); require( meta.totalLending >= meta.totalBorrowed, "Insufficient lending" ); } /// @dev gets called when external sources provide lending function registerLend(address issuer, uint256 amount) external { require(isLender(msg.sender), "Not an approved lender"); require(activeIssuers[issuer], "Not approved issuer"); LendingMetadata storage meta = lendingMeta[issuer]; addToTotalLending(meta, amount); getUpdatedHourlyYield( issuer, hourlyBondYieldAccumulators[issuer], RATE_UPDATE_WINDOW ); } /// @dev gets called when external sources pay withdraw their bobnd function registerWithdrawal(address issuer, uint256 amount) external { require(isLender(msg.sender), "Not an approved lender"); require(activeIssuers[issuer], "Not approved issuer"); LendingMetadata storage meta = lendingMeta[issuer]; subtractFromTotalLending(meta, amount); getUpdatedHourlyYield( issuer, hourlyBondYieldAccumulators[issuer], RATE_UPDATE_WINDOW ); } /// @dev gets called by router if loan is extinguished function payOff(address issuer, uint256 amount) external { require(isBorrower(msg.sender), "Not approved borrower"); lendingMeta[issuer].totalBorrowed -= amount; } /// @dev get the borrow yield for a specific issuer/token function viewAccumulatedBorrowingYieldFP(address issuer) external view returns (uint256) { YieldAccumulator storage yA = borrowYieldAccumulators[issuer]; return viewCumulativeYieldFP(yA, block.timestamp); } function viewAPRPer10k(YieldAccumulator storage yA) internal view returns (uint256) { uint256 hourlyYieldFP = yA.hourlyYieldFP; uint256 aprFP = ((hourlyYieldFP * 10_000 - FP48 * 10_000) * 365 days) / (1 hours); return aprFP / FP48; } /// @dev get current borrowing interest per 10k for a token / issuer function viewBorrowAPRPer10k(address issuer) external view returns (uint256) { return viewAPRPer10k(borrowYieldAccumulators[issuer]); } /// @dev get current lending APR per 10k for a token / issuer function viewHourlyBondAPRPer10k(address issuer) external view returns (uint256) { return viewAPRPer10k(hourlyBondYieldAccumulators[issuer]); } /// @dev In a liquidity crunch make a fallback bond until liquidity is good again function makeFallbackBond( address issuer, address holder, uint256 amount ) external { require(isLender(msg.sender), "Not an approved lender"); _makeHourlyBond(issuer, holder, amount); } /// @dev withdraw an hour bond function withdrawHourlyBond(address issuer, uint256 amount) external { HourlyBond storage bond = hourlyBondAccounts[issuer][msg.sender]; super._withdrawHourlyBond(issuer, bond, amount, msg.sender); if (bond.amount == 0) { delete hourlyBondAccounts[issuer][msg.sender]; } disburse(issuer, msg.sender, amount); IncentiveReporter.subtractFromClaimAmount(issuer, msg.sender, amount); } /// Shut down hourly bond account for `issuer` function closeHourlyBondAccount(address issuer) external { HourlyBond storage bond = hourlyBondAccounts[issuer][msg.sender]; uint256 amount = bond.amount; super._withdrawHourlyBond(issuer, bond, amount, msg.sender); disburse(issuer, msg.sender, amount); delete hourlyBondAccounts[issuer][msg.sender]; IncentiveReporter.subtractFromClaimAmount(issuer, msg.sender, amount); } /// @dev buy hourly bond subscription function buyHourlyBondSubscription(address issuer, uint256 amount) external { require(activeIssuers[issuer], "Not approved issuer"); collectToken(issuer, msg.sender, amount); super._makeHourlyBond(issuer, msg.sender, amount); IncentiveReporter.addToClaimAmount(issuer, msg.sender, amount); } function initBorrowYieldAccumulator(address issuer) external onlyOwnerExecActivator { YieldAccumulator storage yA = borrowYieldAccumulators[issuer]; require(yA.accumulatorFP == 0, "don't re-initialize"); yA.accumulatorFP = FP48; yA.lastUpdated = block.timestamp; yA.hourlyYieldFP = FP48 + (FP48 * borrowMinAPR) / 1000 / (365 * 24); } function setBorrowingFactorPercent(uint256 borrowingFactor) external onlyOwnerExec { borrowingFactorPercent = borrowingFactor; } function issuanceBalance(address issuer) internal view override returns (uint256) { address token = issuerTokens[issuer]; if (token == issuer) { // cross margin return IERC20(token).balanceOf(fund()); } else { return lendingMeta[issuer].totalLending - haircuts[issuer]; } } function disburse( address issuer, address recipient, uint256 amount ) internal { uint256 haircutAmount = haircuts[issuer]; if (haircutAmount > 0 && amount > 0) { uint256 totalLending = lendingMeta[issuer].totalLending; uint256 adjustment = (amount * min(totalLending, haircutAmount)) / totalLending; amount = amount - adjustment; haircuts[issuer] -= adjustment; } address token = issuerTokens[issuer]; Fund(fund()).withdraw(token, recipient, amount); } function collectToken( address issuer, address source, uint256 amount ) internal { Fund(fund()).depositFor(source, issuerTokens[issuer], amount); } function haircut(uint256 amount) external { haircuts[msg.sender] += amount; } function addIncentive( address token, uint256 amount, uint256 endTimestamp ) external onlyOwnerExecActivator { LendingMetadata storage meta = lendingMeta[token]; meta.incentiveEnd = endTimestamp; meta.incentiveTarget = amount; meta.incentiveLastUpdated = block.timestamp; } function disburseIncentive( HourlyBond storage bond, LendingMetadata storage meta, address holder ) internal override { uint256 allocationDelta = meta.cumulIncentiveAllocationFP - bond.incentiveAllocationStart; if (allocationDelta > 0) { uint256 disburseAmount = (allocationDelta * bond.amount) / FP48; Fund(fund()).withdraw(MFI, holder, disburseAmount); bond.incentiveAllocationStart += allocationDelta; } } function withdrawIncentive(address token) external { LendingMetadata storage meta = lendingMeta[token]; updateIncentiveAllocation(meta); disburseIncentive( hourlyBondAccounts[token][msg.sender], meta, msg.sender ); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./RoleAware.sol"; import "../interfaces/IMarginTrading.sol"; import "./Lending.sol"; import "./BaseRouter.sol"; import "../libraries/IncentiveReporter.sol"; /// @title Top level transaction controller contract MarginRouter is RoleAware, BaseRouter { event AccountUpdated(address indexed trader); event MarginTrade( address indexed trader, address fromToken, address toToken, uint256 fromAmount, uint256 toAmount ); uint256 public constant mswapFeesPer10k = 10; address public immutable WETH; constructor( address _WETH, address _amm1Factory, address _amm2Factory, address _amm3Factory, bytes32 _amm1InitHash, bytes32 _amm2InitHash, bytes32 _amm3InitHash, address _roles ) UniswapStyleLib( _amm1Factory, _amm2Factory, _amm3Factory, _amm1InitHash, _amm2InitHash, _amm3InitHash ) RoleAware(_roles) { WETH = _WETH; } /////////////////////////// // Cross margin endpoints /////////////////////////// /// @notice traders call this to deposit funds on cross margin function crossDeposit(address depositToken, uint256 depositAmount) external { Fund(fund()).depositFor(msg.sender, depositToken, depositAmount); uint256 extinguishAmount = IMarginTrading(crossMarginTrading()).registerDeposit( msg.sender, depositToken, depositAmount ); if (extinguishAmount > 0) { Lending(lending()).payOff(depositToken, extinguishAmount); IncentiveReporter.subtractFromClaimAmount( depositToken, msg.sender, extinguishAmount ); } emit AccountUpdated(msg.sender); } /// @notice deposit wrapped ehtereum into cross margin account function crossDepositETH() external payable { Fund(fund()).depositToWETH{value: msg.value}(); uint256 extinguishAmount = IMarginTrading(crossMarginTrading()).registerDeposit( msg.sender, WETH, msg.value ); if (extinguishAmount > 0) { Lending(lending()).payOff(WETH, extinguishAmount); IncentiveReporter.subtractFromClaimAmount( WETH, msg.sender, extinguishAmount ); } emit AccountUpdated(msg.sender); } /// @notice withdraw deposits/earnings from cross margin account function crossWithdraw(address withdrawToken, uint256 withdrawAmount) external { IMarginTrading(crossMarginTrading()).registerWithdrawal( msg.sender, withdrawToken, withdrawAmount ); Fund(fund()).withdraw(withdrawToken, msg.sender, withdrawAmount); emit AccountUpdated(msg.sender); } /// @notice withdraw ethereum from cross margin account function crossWithdrawETH(uint256 withdrawAmount) external { IMarginTrading(crossMarginTrading()).registerWithdrawal( msg.sender, WETH, withdrawAmount ); Fund(fund()).withdrawETH(msg.sender, withdrawAmount); emit AccountUpdated(msg.sender); } /// @notice borrow into cross margin trading account function crossBorrow(address borrowToken, uint256 borrowAmount) external { Lending(lending()).registerBorrow(borrowToken, borrowAmount); IMarginTrading(crossMarginTrading()).registerBorrow( msg.sender, borrowToken, borrowAmount ); Lending(lending()).updateHourlyYield(borrowToken); IncentiveReporter.addToClaimAmount( borrowToken, msg.sender, borrowAmount ); emit AccountUpdated(msg.sender); } /// @notice convenience function to perform overcollateralized borrowing /// against a cross margin account. /// @dev caution: the account still has to have a positive balaance at the end /// of the withdraw. So an underwater account may not be able to withdraw function crossOvercollateralizedBorrow( address depositToken, uint256 depositAmount, address borrowToken, uint256 withdrawAmount ) external { Fund(fund()).depositFor(msg.sender, depositToken, depositAmount); Lending(lending()).registerBorrow(borrowToken, withdrawAmount); IMarginTrading(crossMarginTrading()).registerOvercollateralizedBorrow( msg.sender, depositToken, depositAmount, borrowToken, withdrawAmount ); Lending(lending()).updateHourlyYield(borrowToken); Fund(fund()).withdraw(borrowToken, msg.sender, withdrawAmount); IncentiveReporter.addToClaimAmount( borrowToken, msg.sender, withdrawAmount ); emit AccountUpdated(msg.sender); } /// @notice close an account that is no longer borrowing and return gains function crossCloseAccount() external { (address[] memory holdingTokens, uint256[] memory holdingAmounts) = IMarginTrading(crossMarginTrading()).getHoldingAmounts(msg.sender); // requires all debts paid off IMarginTrading(crossMarginTrading()).registerLiquidation(msg.sender); for (uint256 i; holdingTokens.length > i; i++) { Fund(fund()).withdraw( holdingTokens[i], msg.sender, holdingAmounts[i] ); } emit AccountUpdated(msg.sender); } /// @notice entry point for swapping tokens held in cross margin account function swapExactTokensForTokens( uint256 amountIn, uint256 amountOutMin, bytes32 amms, address[] calldata tokens, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { // calc fees uint256 fees = takeFeesFromInput(amountIn); address[] memory pairs; (amounts, pairs) = UniswapStyleLib._getAmountsOut( amountIn - fees, amms, tokens ); // checks that trader is within allowed lending bounds registerTrade( msg.sender, tokens[0], tokens[tokens.length - 1], amountIn, amounts[amounts.length - 1] ); _fundSwapExactT4T(amounts, amountOutMin, pairs, tokens); } /// @notice entry point for swapping tokens held in cross margin account function swapTokensForExactTokens( uint256 amountOut, uint256 amountInMax, bytes32 amms, address[] calldata tokens, uint256 deadline ) external ensure(deadline) returns (uint256[] memory amounts) { address[] memory pairs; (amounts, pairs) = UniswapStyleLib._getAmountsIn( amountOut + takeFeesFromOutput(amountOut), amms, tokens ); // checks that trader is within allowed lending bounds registerTrade( msg.sender, tokens[0], tokens[tokens.length - 1], amounts[0], amountOut ); _fundSwapT4ExactT(amounts, amountInMax, pairs, tokens); } /// @dev helper function does all the work of telling other contracts /// about a cross margin trade function registerTrade( address trader, address inToken, address outToken, uint256 inAmount, uint256 outAmount ) internal { (uint256 extinguishAmount, uint256 borrowAmount) = IMarginTrading(crossMarginTrading()).registerTradeAndBorrow( trader, inToken, outToken, inAmount, outAmount ); if (extinguishAmount > 0) { Lending(lending()).payOff(outToken, extinguishAmount); Lending(lending()).updateHourlyYield(outToken); IncentiveReporter.subtractFromClaimAmount( outToken, trader, extinguishAmount ); } if (borrowAmount > 0) { Lending(lending()).registerBorrow(inToken, borrowAmount); Lending(lending()).updateHourlyYield(inToken); IncentiveReporter.addToClaimAmount(inToken, trader, borrowAmount); } emit AccountUpdated(trader); emit MarginTrade(trader, inToken, outToken, inAmount, outAmount); } ///////////// // Helpers ///////////// /// @dev internal helper swapping exact token for token on AMM function _fundSwapExactT4T( uint256[] memory amounts, uint256 amountOutMin, address[] memory pairs, address[] calldata tokens ) internal { require( amounts[amounts.length - 1] >= amountOutMin, "MarginRouter: INSUFFICIENT_OUTPUT_AMOUNT" ); Fund(fund()).withdraw(tokens[0], pairs[0], amounts[0]); _swap(amounts, pairs, tokens, fund()); } /// @notice make swaps on AMM using protocol funds, only for authorized contracts function authorizedSwapExactT4T( uint256 amountIn, uint256 amountOutMin, bytes32 amms, address[] calldata tokens ) external returns (uint256[] memory amounts) { require( isAuthorizedFundTrader(msg.sender), "Calling contract is not authorized to trade with protocl funds" ); address[] memory pairs; (amounts, pairs) = UniswapStyleLib._getAmountsOut( amountIn, amms, tokens ); _fundSwapExactT4T(amounts, amountOutMin, pairs, tokens); } // @dev internal helper swapping exact token for token on on AMM function _fundSwapT4ExactT( uint256[] memory amounts, uint256 amountInMax, address[] memory pairs, address[] calldata tokens ) internal { require( amounts[0] <= amountInMax, "MarginRouter: EXCESSIVE_INPUT_AMOUNT" ); Fund(fund()).withdraw(tokens[0], pairs[0], amounts[0]); _swap(amounts, pairs, tokens, fund()); } //// @notice swap protocol funds on AMM, only for authorized function authorizedSwapT4ExactT( uint256 amountOut, uint256 amountInMax, bytes32 amms, address[] calldata tokens ) external returns (uint256[] memory amounts) { require( isAuthorizedFundTrader(msg.sender), "Calling contract is not authorized to trade with protocl funds" ); address[] memory pairs; (amounts, pairs) = UniswapStyleLib._getAmountsIn( amountOut, amms, tokens ); _fundSwapT4ExactT(amounts, amountInMax, pairs, tokens); } function takeFeesFromOutput(uint256 amount) internal pure returns (uint256 fees) { fees = (mswapFeesPer10k * amount) / 10_000; } function takeFeesFromInput(uint256 amount) internal pure returns (uint256 fees) { fees = (mswapFeesPer10k * amount) / (10_000 + mswapFeesPer10k); } function getAmountsOut( uint256 inAmount, bytes32 amms, address[] calldata tokens ) external view returns (uint256[] memory amounts) { (amounts, ) = UniswapStyleLib._getAmountsOut(inAmount, amms, tokens); } function getAmountsIn( uint256 outAmount, bytes32 amms, address[] calldata tokens ) external view returns (uint256[] memory amounts) { (amounts, ) = UniswapStyleLib._getAmountsIn(outAmount, amms, tokens); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./RoleAware.sol"; import "./MarginRouter.sol"; import "../libraries/UniswapStyleLib.sol"; /// Stores how many of token you could get for 1k of peg struct TokenPrice { uint256 lastUpdated; uint256 priceFP; address[] liquidationTokens; bytes32 amms; address[] inverseLiquidationTokens; bytes32 inverseAmms; } struct VolatilitySetting { uint256 priceUpdateWindow; uint256 updateRatePermil; uint256 voluntaryUpdateWindow; } struct PairPrice { uint256 cumulative; uint256 lastUpdated; uint256 priceFP; } /// @title The protocol features several mechanisms to prevent vulnerability to /// price manipulation: /// 1) global exposure caps on all tokens which need to be raised gradually /// during the process of introducing a new token, making attacks unprofitable /// due to lack of scale /// 2) Exponential moving average with cautious price update. Prices for estimating /// how much a trader can borrow need not be extremely current and precise, mainly /// they must be resilient against extreme manipulation /// 3) Liquidators may not call from a contract address, to prevent extreme forms of /// of front-running and other price manipulation. abstract contract PriceAware is RoleAware, UniswapStyleLib { uint256 constant FP112 = 2**112; uint256 constant FP8 = 2**8; uint256 constant FP96 = 2**(112 - 2 * 8); address public immutable peg; mapping(address => TokenPrice) public tokenPrices; mapping(address => mapping(address => PairPrice)) public pairPrices; /// update window in blocks // TODO uint256 public priceUpdateWindow = 20 minutes; uint256 public voluntaryUpdateWindow = 5 minutes; uint256 public UPDATE_RATE_PERMIL = 400; VolatilitySetting[] public volatilitySettings; constructor(address _peg) { peg = _peg; } /// Set window for price updates function setPriceUpdateWindow(uint16 window, uint256 voluntaryWindow) external onlyOwnerExec { priceUpdateWindow = window; voluntaryUpdateWindow = voluntaryWindow; } /// Add a new volatility setting function addVolatilitySetting( uint256 _priceUpdateWindow, uint256 _updateRatePermil, uint256 _voluntaryUpdateWindow ) external onlyOwnerExec { volatilitySettings.push( VolatilitySetting({ priceUpdateWindow: _priceUpdateWindow, updateRatePermil: _updateRatePermil, voluntaryUpdateWindow: _voluntaryUpdateWindow }) ); } /// Choose a volatitlity setting function chooseVolatilitySetting(uint256 index) external onlyOwnerExecDisabler { VolatilitySetting storage vs = volatilitySettings[index]; if (vs.updateRatePermil > 0) { UPDATE_RATE_PERMIL = vs.updateRatePermil; priceUpdateWindow = vs.priceUpdateWindow; voluntaryUpdateWindow = vs.voluntaryUpdateWindow; } } /// Set rate for updates function setUpdateRate(uint256 rate) external onlyOwnerExec { UPDATE_RATE_PERMIL = rate; } function getCurrentPriceInPeg(address token, uint256 inAmount) internal returns (uint256) { return getCurrentPriceInPeg(token, inAmount, false); } function getCurrentPriceInPeg( address token, uint256 inAmount, bool voluntary ) public returns (uint256 priceInPeg) { if (token == peg) { return inAmount; } else { TokenPrice storage tokenPrice = tokenPrices[token]; uint256 timeDelta = block.timestamp - tokenPrice.lastUpdated; if ( timeDelta > priceUpdateWindow || tokenPrice.priceFP == 0 || (voluntary && timeDelta > voluntaryUpdateWindow) ) { // update the currently cached price uint256 priceUpdateFP; priceUpdateFP = getPriceByPairs( tokenPrice.liquidationTokens, tokenPrice.amms ); _setPriceVal(tokenPrice, priceUpdateFP, UPDATE_RATE_PERMIL); } priceInPeg = (inAmount * tokenPrice.priceFP) / FP112; } } /// Get view of current price of token in peg function viewCurrentPriceInPeg(address token, uint256 inAmount) public view returns (uint256 priceInPeg) { if (token == peg) { return inAmount; } else { TokenPrice storage tokenPrice = tokenPrices[token]; uint256 priceFP = tokenPrice.priceFP; priceInPeg = (inAmount * priceFP) / FP112; } } function _setPriceVal( TokenPrice storage tokenPrice, uint256 updateFP, uint256 weightPerMil ) internal { tokenPrice.priceFP = (tokenPrice.priceFP * (1000 - weightPerMil) + updateFP * weightPerMil) / 1000; tokenPrice.lastUpdated = block.timestamp; } /// add path from token to current liquidation peg function setLiquidationPath(bytes32 amms, address[] memory tokens) external onlyOwnerExecActivator { address token = tokens[0]; if (token != peg) { TokenPrice storage tokenPrice = tokenPrices[token]; tokenPrice.amms = amms; tokenPrice.liquidationTokens = tokens; tokenPrice.inverseLiquidationTokens = new address[](tokens.length); bytes32 inverseAmms; for (uint256 i = 0; tokens.length - 1 > i; i++) { initPairPrice(tokens[i], tokens[i + 1], amms[i]); bytes32 shifted = bytes32(amms[i]) >> ((tokens.length - 2 - i) * 8); inverseAmms = inverseAmms | shifted; } tokenPrice.inverseAmms = inverseAmms; for (uint256 i = 0; tokens.length > i; i++) { tokenPrice.inverseLiquidationTokens[i] = tokens[ tokens.length - i - 1 ]; } tokenPrice.priceFP = getPriceByPairs(tokens, amms); tokenPrice.lastUpdated = block.timestamp; } } function liquidateToPeg(address token, uint256 amount) internal returns (uint256) { if (token == peg) { return amount; } else { TokenPrice storage tP = tokenPrices[token]; uint256[] memory amounts = MarginRouter(marginRouter()).authorizedSwapExactT4T( amount, 0, tP.amms, tP.liquidationTokens ); uint256 outAmount = amounts[amounts.length - 1]; return outAmount; } } function liquidateFromPeg(address token, uint256 targetAmount) internal returns (uint256) { if (token == peg) { return targetAmount; } else { TokenPrice storage tP = tokenPrices[token]; uint256[] memory amounts = MarginRouter(marginRouter()).authorizedSwapT4ExactT( targetAmount, type(uint256).max, tP.amms, tP.inverseLiquidationTokens ); return amounts[0]; } } function getPriceByPairs(address[] memory tokens, bytes32 amms) internal returns (uint256 priceFP) { priceFP = FP112; for (uint256 i; i < tokens.length - 1; i++) { address inToken = tokens[i]; address outToken = tokens[i + 1]; address pair = amms[i] == 0 ? UniswapStyleLib.pairForAMM1(inToken, outToken) : UniswapStyleLib.pairForAMM2(inToken, outToken); PairPrice storage pairPrice = pairPrices[pair][inToken]; (, , uint256 pairLastUpdated) = IUniswapV2Pair(pair).getReserves(); uint256 timeDelta = pairLastUpdated - pairPrice.lastUpdated; if (timeDelta > voluntaryUpdateWindow) { // we are in business (address token0, ) = UniswapStyleLib.sortTokens(inToken, outToken); uint256 cumulative = inToken == token0 ? IUniswapV2Pair(pair).price0CumulativeLast() : IUniswapV2Pair(pair).price1CumulativeLast(); uint256 pairPriceFP = (cumulative - pairPrice.cumulative) / timeDelta; priceFP = scaleMul(priceFP, pairPriceFP); pairPrice.priceFP = pairPriceFP; pairPrice.cumulative = cumulative; pairPrice.lastUpdated = pairLastUpdated; } else { priceFP = scaleMul(priceFP, pairPrice.priceFP); } } } function scaleMul(uint256 a, uint256 b) internal pure returns (uint256) { return ((a / FP8) * (b / FP8)) / FP96; } function initPairPrice( address inToken, address outToken, bytes1 amm ) internal { address pair = amm == 0 ? UniswapStyleLib.pairForAMM1(inToken, outToken) : UniswapStyleLib.pairForAMM2(inToken, outToken); PairPrice storage pairPrice = pairPrices[pair][inToken]; if (pairPrice.lastUpdated == 0) { (uint112 reserve0, uint112 reserve1, uint256 pairLastUpdated) = IUniswapV2Pair(pair).getReserves(); (address token0, ) = UniswapStyleLib.sortTokens(inToken, outToken); if (inToken == token0) { pairPrice.priceFP = (FP112 * reserve1) / reserve0; pairPrice.cumulative = IUniswapV2Pair(pair) .price0CumulativeLast(); } else { pairPrice.priceFP = (FP112 * reserve0) / reserve1; pairPrice.cumulative = IUniswapV2Pair(pair) .price1CumulativeLast(); } pairPrice.lastUpdated = block.timestamp; pairPrice.lastUpdated = pairLastUpdated; } } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "./Roles.sol"; /// @title Role management behavior /// Main characters are for service discovery /// Whereas roles are for access control contract RoleAware { Roles public immutable roles; mapping(uint256 => address) public mainCharacterCache; mapping(address => mapping(uint256 => bool)) public roleCache; constructor(address _roles) { require(_roles != address(0), "Please provide valid roles address"); roles = Roles(_roles); } modifier noIntermediary() { require( msg.sender == tx.origin, "Currently no intermediaries allowed for this function call" ); _; } // @dev Throws if called by any account other than the owner or executor modifier onlyOwnerExec() { require( owner() == msg.sender || executor() == msg.sender, "Roles: caller is not the owner" ); _; } modifier onlyOwnerExecDisabler() { require( owner() == msg.sender || executor() == msg.sender || disabler() == msg.sender, "Caller is not the owner, executor or authorized disabler" ); _; } modifier onlyOwnerExecActivator() { require( owner() == msg.sender || executor() == msg.sender || isTokenActivator(msg.sender), "Caller is not the owner, executor or authorized activator" ); _; } function updateRoleCache(uint256 role, address contr) public virtual { roleCache[contr][role] = roles.getRole(role, contr); } function updateMainCharacterCache(uint256 role) public virtual { mainCharacterCache[role] = roles.mainCharacters(role); } function owner() internal view returns (address) { return roles.owner(); } function executor() internal returns (address) { return roles.executor(); } function disabler() internal view returns (address) { return mainCharacterCache[DISABLER]; } function fund() internal view returns (address) { return mainCharacterCache[FUND]; } function lending() internal view returns (address) { return mainCharacterCache[LENDING]; } function marginRouter() internal view returns (address) { return mainCharacterCache[MARGIN_ROUTER]; } function crossMarginTrading() internal view returns (address) { return mainCharacterCache[CROSS_MARGIN_TRADING]; } function feeController() internal view returns (address) { return mainCharacterCache[FEE_CONTROLLER]; } function price() internal view returns (address) { return mainCharacterCache[PRICE_CONTROLLER]; } function admin() internal view returns (address) { return mainCharacterCache[ADMIN]; } function incentiveDistributor() internal view returns (address) { return mainCharacterCache[INCENTIVE_DISTRIBUTION]; } function tokenAdmin() internal view returns (address) { return mainCharacterCache[TOKEN_ADMIN]; } function isBorrower(address contr) internal view returns (bool) { return roleCache[contr][BORROWER]; } function isFundTransferer(address contr) internal view returns (bool) { return roleCache[contr][FUND_TRANSFERER]; } function isMarginTrader(address contr) internal view returns (bool) { return roleCache[contr][MARGIN_TRADER]; } function isFeeSource(address contr) internal view returns (bool) { return roleCache[contr][FEE_SOURCE]; } function isMarginCaller(address contr) internal view returns (bool) { return roleCache[contr][MARGIN_CALLER]; } function isLiquidator(address contr) internal view returns (bool) { return roleCache[contr][LIQUIDATOR]; } function isAuthorizedFundTrader(address contr) internal view returns (bool) { return roleCache[contr][AUTHORIZED_FUND_TRADER]; } function isIncentiveReporter(address contr) internal view returns (bool) { return roleCache[contr][INCENTIVE_REPORTER]; } function isTokenActivator(address contr) internal view returns (bool) { return roleCache[contr][TOKEN_ACTIVATOR]; } function isStakePenalizer(address contr) internal view returns (bool) { return roleCache[contr][STAKE_PENALIZER]; } function isLender(address contr) internal view returns (bool) { return roleCache[contr][LENDER]; } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; import "@openzeppelin/contracts/access/Ownable.sol"; import "../interfaces/IDependencyController.sol"; // we chose not to go with an enum // to make this list easy to extend uint256 constant FUND_TRANSFERER = 1; uint256 constant MARGIN_CALLER = 2; uint256 constant BORROWER = 3; uint256 constant MARGIN_TRADER = 4; uint256 constant FEE_SOURCE = 5; uint256 constant LIQUIDATOR = 6; uint256 constant AUTHORIZED_FUND_TRADER = 7; uint256 constant INCENTIVE_REPORTER = 8; uint256 constant TOKEN_ACTIVATOR = 9; uint256 constant STAKE_PENALIZER = 10; uint256 constant LENDER = 11; uint256 constant FUND = 101; uint256 constant LENDING = 102; uint256 constant MARGIN_ROUTER = 103; uint256 constant CROSS_MARGIN_TRADING = 104; uint256 constant FEE_CONTROLLER = 105; uint256 constant PRICE_CONTROLLER = 106; uint256 constant ADMIN = 107; uint256 constant INCENTIVE_DISTRIBUTION = 108; uint256 constant TOKEN_ADMIN = 109; uint256 constant DISABLER = 1001; uint256 constant DEPENDENCY_CONTROLLER = 1002; /// @title Manage permissions of contracts and ownership of everything /// owned by a multisig wallet (0xEED9D1c6B4cdEcB3af070D85bfd394E7aF179CBd) during /// beta and will then be transfered to governance /// https://github.com/marginswap/governance contract Roles is Ownable { mapping(address => mapping(uint256 => bool)) public roles; mapping(uint256 => address) public mainCharacters; constructor() Ownable() { // token activation from the get-go roles[msg.sender][TOKEN_ACTIVATOR] = true; } /// @dev Throws if called by any account other than the owner. modifier onlyOwnerExecDepController() { require( owner() == msg.sender || executor() == msg.sender || mainCharacters[DEPENDENCY_CONTROLLER] == msg.sender, "Roles: caller is not the owner" ); _; } function giveRole(uint256 role, address actor) external onlyOwnerExecDepController { roles[actor][role] = true; } function removeRole(uint256 role, address actor) external onlyOwnerExecDepController { roles[actor][role] = false; } function setMainCharacter(uint256 role, address actor) external onlyOwnerExecDepController { mainCharacters[role] = actor; } function getRole(uint256 role, address contr) external view returns (bool) { return roles[contr][role]; } /// @dev current executor function executor() public returns (address exec) { address depController = mainCharacters[DEPENDENCY_CONTROLLER]; if (depController != address(0)) { exec = IDependencyController(depController).currentExecutor(); } } }
// SPDX-License-Identifier: MIT pragma solidity >= 0.4.22 <0.9.0; library console { address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67); function _sendLogPayload(bytes memory payload) private view { uint256 payloadLength = payload.length; address consoleAddress = CONSOLE_ADDRESS; assembly { let payloadStart := add(payload, 32) let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0) } } function log() internal view { _sendLogPayload(abi.encodeWithSignature("log()")); } function logInt(int p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(int)", p0)); } function logUint(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function logString(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function logBool(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function logAddress(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function logBytes(bytes memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0)); } function logBytes1(bytes1 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0)); } function logBytes2(bytes2 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0)); } function logBytes3(bytes3 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0)); } function logBytes4(bytes4 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0)); } function logBytes5(bytes5 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0)); } function logBytes6(bytes6 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0)); } function logBytes7(bytes7 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0)); } function logBytes8(bytes8 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0)); } function logBytes9(bytes9 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0)); } function logBytes10(bytes10 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0)); } function logBytes11(bytes11 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0)); } function logBytes12(bytes12 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0)); } function logBytes13(bytes13 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0)); } function logBytes14(bytes14 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0)); } function logBytes15(bytes15 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0)); } function logBytes16(bytes16 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0)); } function logBytes17(bytes17 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0)); } function logBytes18(bytes18 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0)); } function logBytes19(bytes19 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0)); } function logBytes20(bytes20 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0)); } function logBytes21(bytes21 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0)); } function logBytes22(bytes22 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0)); } function logBytes23(bytes23 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0)); } function logBytes24(bytes24 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0)); } function logBytes25(bytes25 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0)); } function logBytes26(bytes26 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0)); } function logBytes27(bytes27 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0)); } function logBytes28(bytes28 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0)); } function logBytes29(bytes29 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0)); } function logBytes30(bytes30 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0)); } function logBytes31(bytes31 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0)); } function logBytes32(bytes32 p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0)); } function log(uint p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint)", p0)); } function log(string memory p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(string)", p0)); } function log(bool p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool)", p0)); } function log(address p0) internal view { _sendLogPayload(abi.encodeWithSignature("log(address)", p0)); } function log(uint p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1)); } function log(uint p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1)); } function log(uint p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1)); } function log(uint p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1)); } function log(string memory p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1)); } function log(string memory p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1)); } function log(string memory p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1)); } function log(string memory p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1)); } function log(bool p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1)); } function log(bool p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1)); } function log(bool p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1)); } function log(bool p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1)); } function log(address p0, uint p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1)); } function log(address p0, string memory p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1)); } function log(address p0, bool p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1)); } function log(address p0, address p1) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1)); } function log(uint p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2)); } function log(uint p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2)); } function log(uint p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2)); } function log(uint p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2)); } function log(uint p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2)); } function log(uint p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2)); } function log(uint p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2)); } function log(uint p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2)); } function log(uint p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2)); } function log(uint p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2)); } function log(uint p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2)); } function log(uint p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2)); } function log(uint p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2)); } function log(uint p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2)); } function log(uint p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2)); } function log(uint p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2)); } function log(string memory p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2)); } function log(string memory p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2)); } function log(string memory p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2)); } function log(string memory p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2)); } function log(string memory p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2)); } function log(string memory p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2)); } function log(string memory p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2)); } function log(string memory p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2)); } function log(string memory p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2)); } function log(string memory p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2)); } function log(string memory p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2)); } function log(string memory p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2)); } function log(string memory p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2)); } function log(string memory p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2)); } function log(string memory p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2)); } function log(string memory p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2)); } function log(bool p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2)); } function log(bool p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2)); } function log(bool p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2)); } function log(bool p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2)); } function log(bool p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2)); } function log(bool p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2)); } function log(bool p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2)); } function log(bool p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2)); } function log(bool p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2)); } function log(bool p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2)); } function log(bool p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2)); } function log(bool p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2)); } function log(bool p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2)); } function log(bool p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2)); } function log(bool p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2)); } function log(bool p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2)); } function log(address p0, uint p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2)); } function log(address p0, uint p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2)); } function log(address p0, uint p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2)); } function log(address p0, uint p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2)); } function log(address p0, string memory p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2)); } function log(address p0, string memory p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2)); } function log(address p0, string memory p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2)); } function log(address p0, string memory p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2)); } function log(address p0, bool p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2)); } function log(address p0, bool p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2)); } function log(address p0, bool p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2)); } function log(address p0, bool p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2)); } function log(address p0, address p1, uint p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2)); } function log(address p0, address p1, string memory p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2)); } function log(address p0, address p1, bool p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2)); } function log(address p0, address p1, address p2) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2)); } function log(uint p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3)); } function log(uint p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3)); } function log(uint p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3)); } function log(uint p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3)); } function log(uint p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3)); } function log(string memory p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3)); } function log(bool p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3)); } function log(bool p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3)); } function log(bool p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3)); } function log(bool p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3)); } function log(address p0, uint p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3)); } function log(address p0, string memory p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3)); } function log(address p0, bool p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, uint p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, string memory p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, bool p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, uint p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, string memory p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, bool p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3)); } function log(address p0, address p1, address p2, address p3) internal view { _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3)); } }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IDependencyController { function currentExecutor() external returns (address); }
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; interface IMarginTrading { function registerDeposit( address trader, address token, uint256 amount ) external returns (uint256 extinguishAmount); function registerWithdrawal( address trader, address token, uint256 amount ) external; function registerBorrow( address trader, address token, uint256 amount ) external; function registerTradeAndBorrow( address trader, address inToken, address outToken, uint256 inAmount, uint256 outAmount ) external returns (uint256 extinguishAmount, uint256 borrowAmount); function registerOvercollateralizedBorrow( address trader, address depositToken, uint256 depositAmount, address borrowToken, uint256 withdrawAmount ) external; function registerLiquidation(address trader) external; function getHoldingAmounts(address trader) external view returns ( address[] memory holdingTokens, uint256[] memory holdingAmounts ); function getBorrowAmounts(address trader) external view returns (address[] memory borrowTokens, uint256[] memory borrowAmounts); }
pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address to, uint256 value) external returns (bool); function withdraw(uint256) external; }
library IncentiveReporter { event AddToClaim(address topic, address indexed claimant, uint256 amount); event SubtractFromClaim( address topic, address indexed claimant, uint256 amount ); /// Start / increase amount of claim function addToClaimAmount( address topic, address recipient, uint256 claimAmount ) internal { emit AddToClaim(topic, recipient, claimAmount); } /// Decrease amount of claim function subtractFromClaimAmount( address topic, address recipient, uint256 subtractAmount ) internal { emit SubtractFromClaim(topic, recipient, subtractAmount); } }
pragma solidity >=0.5.0; import "@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol"; import "hardhat/console.sol"; abstract contract UniswapStyleLib { address public immutable amm1Factory; address public immutable amm2Factory; address public immutable amm3Factory; bytes32 public amm1InitHash; bytes32 public amm2InitHash; bytes32 public amm3InitHash; constructor( address _amm1Factory, address _amm2Factory, address _amm3Factory, bytes32 _amm1InitHash, bytes32 _amm2InitHash, bytes32 _amm3InitHash ) { amm1Factory = _amm1Factory; amm2Factory = _amm2Factory; amm3Factory = _amm3Factory; amm1InitHash = _amm1InitHash; amm2InitHash = _amm2InitHash; amm3InitHash = _amm3InitHash; } // returns sorted token addresses, used to handle return values from pairs sorted in this order function sortTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) { require(tokenA != tokenB, "Identical address!"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "Zero address!"); } // fetches and sorts the reserves for a pair function getReserves( address pair, address tokenA, address tokenB ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = IUniswapV2Pair(pair).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset function getAmountOut( uint256 amountIn, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountOut) { require(amountIn > 0, "INSUFFICIENT_INPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 amountInWithFee = amountIn * 997; uint256 numerator = amountInWithFee * reserveOut; uint256 denominator = reserveIn * 1_000 + amountInWithFee; amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "INSUFFICIENT_OUTPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY" ); uint256 numerator = reserveIn * amountOut * 1_000; uint256 denominator = (reserveOut - amountOut) * 997; amountIn = (numerator / denominator) + 1; } // performs chained getAmountOut calculations on any number of pairs function _getAmountsOut( uint256 amountIn, bytes32 amms, address[] memory tokens ) internal view returns (uint256[] memory amounts, address[] memory pairs) { require(tokens.length >= 2, "token path too short"); amounts = new uint256[](tokens.length); amounts[0] = amountIn; pairs = new address[](tokens.length - 1); for (uint256 i; i < tokens.length - 1; i++) { address inToken = tokens[i]; address outToken = tokens[i + 1]; address pair = amms[i] == 0 ? pairForAMM1(inToken, outToken) : (amms[i] == 0x01 ? pairForAMM2(inToken, outToken) : pairForAMM3(inToken, outToken)); pairs[i] = pair; (uint256 reserveIn, uint256 reserveOut) = getReserves(pair, inToken, outToken); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function _getAmountsIn( uint256 amountOut, bytes32 amms, address[] memory tokens ) internal view returns (uint256[] memory amounts, address[] memory pairs) { require(tokens.length >= 2, "token path too short"); amounts = new uint256[](tokens.length); amounts[amounts.length - 1] = amountOut; pairs = new address[](tokens.length - 1); for (uint256 i = tokens.length - 1; i > 0; i--) { address inToken = tokens[i - 1]; address outToken = tokens[i]; address pair = amms[i - 1] == 0 ? pairForAMM1(inToken, outToken) : (amms[i -1 ] == 0x01 ? pairForAMM2(inToken, outToken) : pairForAMM3(inToken, outToken)); pairs[i - 1] = pair; (uint256 reserveIn, uint256 reserveOut) = getReserves(pair, inToken, outToken); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } // calculates the CREATE2 address for a pair without making any external calls function pairForAMM1(address tokenA, address tokenB) internal view returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", amm1Factory, keccak256(abi.encodePacked(token0, token1)), amm1InitHash ) ) ) ) ); } function pairForAMM2(address tokenA, address tokenB) internal view returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", amm2Factory, keccak256(abi.encodePacked(token0, token1)), amm2InitHash ) ) ) ) ); } function pairForAMM3(address tokenA, address tokenB) internal view returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( uint160( uint256( keccak256( abi.encodePacked( hex"ff", amm3Factory, keccak256(abi.encodePacked(token0, token1)), amm3InitHash ) ) ) ) ); } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 5000 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_peg","type":"address"},{"internalType":"address","name":"_amm1Factory","type":"address"},{"internalType":"address","name":"_amm2Factory","type":"address"},{"internalType":"address","name":"_amm3Factory","type":"address"},{"internalType":"bytes32","name":"_amm1InitHash","type":"bytes32"},{"internalType":"bytes32","name":"_amm2InitHash","type":"bytes32"},{"internalType":"bytes32","name":"_amm3InitHash","type":"bytes32"},{"internalType":"address","name":"_roles","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"AccountLiquidated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"LiquidationShortfall","type":"event"},{"inputs":[],"name":"MAINTAINER_CUT_PERCENT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UPDATE_RATE_PERMIL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_priceUpdateWindow","type":"uint256"},{"internalType":"uint256","name":"_updateRatePermil","type":"uint256"},{"internalType":"uint256","name":"_voluntaryUpdateWindow","type":"uint256"}],"name":"addVolatilitySetting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"amm1Factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm1InitHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm2Factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm2InitHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm3Factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"amm3InitHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"avgLiquidationPerCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"canBeLiquidated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"chooseVolatilitySetting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"coolingOffPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"liquidatedAccounts","type":"address[]"}],"name":"disburseLiqStakeAttacks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"failureThreshold","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getBorrowAmounts","outputs":[{"internalType":"address[]","name":"borrowTokens","type":"address[]"},{"internalType":"uint256[]","name":"borrowAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"bool","name":"voluntary","type":"bool"}],"name":"getCurrentPriceInPeg","outputs":[{"internalType":"uint256","name":"priceInPeg","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"getHoldingAmounts","outputs":[{"internalType":"address[]","name":"holdingTokens","type":"address[]"},{"internalType":"uint256[]","name":"holdingAmounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"leveragePercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liqStakeAttackWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"liquidationCandidates","type":"address[]"}],"name":"liquidate","outputs":[{"internalType":"uint256","name":"maintainerCut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"liquidationThresholdPercent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mainCharacterCache","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maintenanceFailures","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pairPrices","outputs":[{"internalType":"uint256","name":"cumulative","type":"uint256"},{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"priceFP","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"peg","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceUpdateWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"borrowToken","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"registerBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"}],"name":"registerDeposit","outputs":[{"internalType":"uint256","name":"extinguishableDebt","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"registerLiquidation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"depositToken","type":"address"},{"internalType":"uint256","name":"depositAmount","type":"uint256"},{"internalType":"address","name":"borrowToken","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"registerOvercollateralizedBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"borrowToken","type":"address"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"registerRawBorrow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"tokenFrom","type":"address"},{"internalType":"address","name":"tokenTo","type":"address"},{"internalType":"uint256","name":"inAmount","type":"uint256"},{"internalType":"uint256","name":"outAmount","type":"uint256"}],"name":"registerTradeAndBorrow","outputs":[{"internalType":"uint256","name":"extinguishableDebt","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"withdrawToken","type":"address"},{"internalType":"uint256","name":"withdrawAmount","type":"uint256"}],"name":"registerWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"roleCache","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roles","outputs":[{"internalType":"contract Roles","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blocks","type":"uint256"}],"name":"setCoolingOffPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"threshFactor","type":"uint256"}],"name":"setFailureThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_leveragePercent","type":"uint256"}],"name":"setLeveragePercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"window","type":"uint256"}],"name":"setLiqStakeAttackWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"amms","type":"bytes32"},{"internalType":"address[]","name":"tokens","type":"address[]"}],"name":"setLiquidationPath","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"threshold","type":"uint256"}],"name":"setLiquidationThresholdPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"cut","type":"uint256"}],"name":"setMaintainerCutPercent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"window","type":"uint16"},{"internalType":"uint256","name":"voluntaryWindow","type":"uint256"}],"name":"setPriceUpdateWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"cap","type":"uint256"}],"name":"setTokenCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rate","type":"uint256"}],"name":"setUpdateRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakeAttackRecords","outputs":[{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"address","name":"loser","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"stakeAttacker","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenCaps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenPrices","outputs":[{"internalType":"uint256","name":"lastUpdated","type":"uint256"},{"internalType":"uint256","name":"priceFP","type":"uint256"},{"internalType":"bytes32","name":"amms","type":"bytes32"},{"internalType":"bytes32","name":"inverseAmms","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalLong","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"role","type":"uint256"}],"name":"updateMainCharacterCache","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"role","type":"uint256"},{"internalType":"address","name":"contr","type":"address"}],"name":"updateRoleCache","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"viewBalanceInToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"inAmount","type":"uint256"}],"name":"viewCurrentPriceInPeg","outputs":[{"internalType":"uint256","name":"priceInPeg","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"viewHoldingsInPeg","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"trader","type":"address"}],"name":"viewLoanInPeg","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"volatilitySettings","outputs":[{"internalType":"uint256","name":"priceUpdateWindow","type":"uint256"},{"internalType":"uint256","name":"updateRatePermil","type":"uint256"},{"internalType":"uint256","name":"voluntaryUpdateWindow","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"voluntaryUpdateWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6101206040526104b060075561012c60085561019060095561012c600b556073600c55600a601055600a60165560056017556005601855600a6019553480156200004857600080fd5b50604051620061ff380380620061ff8339810160408190526200006b9162000145565b87878787878787876001600160a01b038116620000d95760405162461bcd60e51b815260206004820152602260248201527f506c656173652070726f766964652076616c696420726f6c6573206164647265604482015261737360f01b606482015260840160405180910390fd5b6001600160601b0319606091821b811660805296811b871660a05294851b861660c05292841b851660e0526002919091556003556004559190911b166101005250620001d19650505050505050565b80516001600160a01b03811681146200014057600080fd5b919050565b600080600080600080600080610100898b03121562000162578384fd5b6200016d8962000128565b97506200017d60208a0162000128565b96506200018d60408a0162000128565b95506200019d60608a0162000128565b94506080890151935060a0890151925060c08901519150620001c260e08a0162000128565b90509295985092959890939650565b60805160601c60a05160601c60c05160601c60e05160601c6101005160601c615f716200028e6000396000818161047101528181610b6201528181610fa601528181611bb10152818161202901528181612338015281816124d501528181613198015281816152d2015261543e015260006108920152600081816103980152614fdc01526000818161078c01526150d201526000818161056f015281816109b401528181611778015281816133b001526134480152615f716000f3fe608060405234801561001057600080fd5b506004361061038e5760003560e01c80637a1a04df116101de578063bc70c6661161010f578063df7c20f9116100ad578063ef859fc81161007c578063ef859fc81461090f578063f04c68651461094c578063f3f5f9b51461095f578063f99fd97c146109725761038e565b8063df7c20f9146108b4578063e0f3871f146108bd578063e2abb5c4146108dd578063e9c3f77d146108e65761038e565b8063d0eb6653116100e9578063d0eb665314610854578063d510c53514610867578063db2d904d1461087a578063db4292351461088d5761038e565b8063bc70c6661461081b578063c73afac21461082e578063c74303aa146108415761038e565b8063a53ac0d91161017c578063a985994b11610156578063a985994b14610761578063b25b454814610774578063b852eb0d14610787578063badb5048146107ae5761038e565b8063a53ac0d91461072f578063a75208a814610738578063a75697a5146107415761038e565b80639c56522c116101b85780639c56522c146106ed578063a17ab527146106f6578063a20ec49314610709578063a37189191461071c5761038e565b80637a1a04df146106615780637d100e841461068f5780638dc6a529146106985761038e565b8063320d2fa0116102c3578063498d55eb11610261578063538edb2911610230578063538edb291461062957806354554b581461063257806360b3fa40146106455780636585b5a6146106585761038e565b8063498d55eb146105f15780634aa4aca314610604578063519bda851461060d57806352a664d9146106165761038e565b80633ed456fa1161029d5780633ed456fa14610591578063409fdb721461059a578063447d52ba146105bb57806347788cd0146105ce5761038e565b8063320d2fa0146105395780633500aa0b14610542578063392f5f641461056a5761038e565b80631d84cc1811610330578063204120bc1161030a578063204120bc146104a657806320c27126146104fd5780632b23f8571461051d5780632febaa74146105305761038e565b80631d84cc18146104595780631f1cb62b1461046c5780631f692a64146104935761038e565b8063093a483a1161036c578063093a483a146103ff57806310d584341461042057806316317e7e146104335780631d47e4a3146104465761038e565b8063059b157a14610393578063071060a6146103d757806307c20175146103ec575b600080fd5b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b6103ea6103e5366004615c89565b610985565b005b6103ea6103fa366004615af4565b610a71565b61041261040d366004615a5b565b610b5e565b6040519081526020016103ce565b6103ea61042e366004615c89565b610bed565b6103ea610441366004615c89565b610c70565b6103ea610454366004615a5b565b610cee565b6103ea610467366004615a01565b610dcf565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b6104126104a13660046158f7565b610e7d565b6104dd6104b43660046158f7565b600560208190526000918252604090912080546001820154600383015492909301549092919084565b6040805194855260208501939093529183015260608201526080016103ce565b61041261050b3660046158f7565b600f6020526000908152604090205481565b6103ea61052b366004615bde565b610eb2565b61041260105481565b610412600c5481565b610555610550366004615967565b61127e565b604080519283526020830191909152016103ce565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b61041260075481565b6105ad6105a83660046158f7565b6115c2565b6040516103ce929190615d71565b6103ea6105c9366004615cb9565b611739565b6105e16105dc3660046158f7565b61182a565b60405190151581526020016103ce565b6103ea6105ff3660046159c1565b611891565b61041260175481565b61041260095481565b6104126106243660046159c1565b611930565b61041260185481565b6103ea610640366004615c89565b611b2f565b610412610653366004615ab3565b611bad565b61041260165481565b6105e161066f366004615a5b565b600160209081526000928352604080842090915290825290205460ff1681565b61041260195481565b6106d26106a636600461592f565b600660209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103ce565b61041260085481565b6104126107043660046158f7565b611cf7565b6103ea610717366004615c66565b611d1f565b6103ea61072a366004615c89565b611da6565b610412600b5481565b61041260025481565b61041261074f3660046158f7565b60146020526000908152604090205481565b61041261076f366004615af4565b611e24565b6103ea6107823660046159c1565b6126ac565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b6107f06107bc3660046158f7565b601560205260009081526040902080546001820154600283015460039093015491926001600160a01b039182169290911684565b604080519485526001600160a01b0393841660208601528401919091521660608201526080016103ce565b6106d2610829366004615c89565b61291c565b6103ea61083c366004615c89565b61294f565b6103ea61084f366004615c89565b6129cd565b6103ea6108623660046159c1565b612a4b565b6105ad6108753660046158f7565b612ad9565b6103ea6108883660046158f7565b612d1d565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b61041260035481565b6104126108cb3660046158f7565b600e6020526000908152604090205481565b61041260045481565b6103ba6108f4366004615c89565b6000602081905290815260409020546001600160a01b031681565b61041261091d36600461592f565b6001600160a01b039182166000908152600d602090815260408083209390941682526005909201909152205490565b6103ea61095a366004615c89565b612dff565b6103ea61096d366004615d00565b612f43565b6103ea610980366004615c89565b61305f565b6040517fb4ed0b6d000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063b4ed0b6d9060240160206040518083038186803b1580156109fe57600080fd5b505afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a369190615913565b600091825260208290526040909120805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055565b60005b8082511115610b5a576000828281518110610a9f57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600060156000836001600160a01b03166001600160a01b0316815260200190815260200160002090506017548160000154610ae49190615e63565b431115610b4557610af4816130dd565b506001600160a01b038216600090815260156020526040812081815560018101805473ffffffffffffffffffffffffffffffffffffffff199081169091556002820192909255600301805490911690555b50508080610b5290615ed1565b915050610a74565b5050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415610ba1575080610be7565b6001600160a01b038316600090815260056020526040902060018101546e010000000000000000000000000000610bd88286615e9b565b610be29190615e7b565b925050505b92915050565b33610bf66133ac565b6001600160a01b03161480610c1a575033610c0f613444565b6001600160a01b0316145b610c6b5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e6572000060448201526064015b60405180910390fd5b601955565b33610c796133ac565b6001600160a01b03161480610c9d575033610c92613444565b6001600160a01b0316145b610ce95760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600c55565b33610cf76133ac565b6001600160a01b03161480610d1b575033610d10613444565b6001600160a01b0316145b80610d4157503360009081526001602090815260408083206009845290915290205460ff165b610db35760405162461bcd60e51b815260206004820152603960248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a656420616374697661746f72000000000000006064820152608401610c62565b6001600160a01b039091166000908152600e6020526040902055565b3360009081526001602090815260408083206004845290915290205460ff16610e3a5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0385166000908152600d60205260409020610e5d8186866134b5565b610e68818484613560565b610e7381848461360b565b4390555050505050565b6001600160a01b0381166000908152600d60205260408120610ea960018201600283016003840161372b565b9150505b919050565b33610ebb6133ac565b6001600160a01b03161480610edf575033610ed4613444565b6001600160a01b0316145b80610f0557503360009081526001602090815260408083206009845290915290205460ff165b610f775760405162461bcd60e51b815260206004820152603960248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a656420616374697661746f72000000000000006064820152608401610c62565b600081600081518110610f9a57634e487b7160e01b600052603260045260246000fd5b602002602001015190507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316816001600160a01b031614611279576001600160a01b038116600090815260056020908152604090912060038101859055835190916110149160028401918601906157b9565b50825167ffffffffffffffff81111561103d57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611066578160200160208202803683370190505b50805161107d9160048401916020909101906157b9565b506000805b80600186516110919190615eba565b11156111a55761111f8582815181106110ba57634e487b7160e01b600052603260045260246000fd5b6020026020010151868360016110d09190615e63565b815181106110ee57634e487b7160e01b600052603260045260246000fd5b602002602001015188846020811061111657634e487b7160e01b600052603260045260246000fd5b1a60f81b6137b8565b600081600287516111309190615eba565b61113a9190615eba565b611145906008615e9b565b87836020811061116557634e487b7160e01b600052603260045260246000fd5b1a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791508061119d81615ed1565b915050611082565b506005820181905560005b8085511115611264578460018287516111c99190615eba565b6111d39190615eba565b815181106111f157634e487b7160e01b600052603260045260246000fd5b602002602001015183600401828154811061121c57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790558061125c81615ed1565b9150506111b0565b5061126f8486613a70565b6001830155504290555b505050565b33600090815260016020908152604080832060048452909152812054819060ff166112eb5760405162461bcd60e51b815260206004820181905260248201527f43616c6c696e6720636f6e74722e206e6f7420616e20617574686f72697a65646044820152606401610c62565b6001600160a01b038088166000908152600d602090815260408083209389168352600284019091529020541561146657600080611359606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03898116600081815260028701602090815260408083205460038a01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b1580156113e357600080fd5b505af11580156113f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141b9190615cdd565b6001600160a01b038a166000908152600286016020908152604080832085905560038801909152902081905590925090506114568683613dc3565b9450611463838987613ddb565b50505b6001600160a01b038716600090815260058201602052604090205485908082111561149b579050806114988188615eba565b93505b838711156114db576114ad8488615eba565b6001600160a01b038a166000908152600f6020526040812080549091906114d5908490615eba565b90915550505b8486111561151b576114ed8587615eba565b6001600160a01b0389166000908152600f602052604081208054909190611515908490615e63565b90915550505b6001600160a01b0388166000908152600f6020908152604080832054600e90925290912054101561158e5760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6115a4838a8a8561159f8a8c615eba565b614083565b83156115b5576115b5838a866140cf565b5050509550959350505050565b6001600160a01b0381166000908152600d602090815260409182902060048101805484518185028101850190955280855260609485949092919083018282801561163557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611617575b5050506004840154929550505067ffffffffffffffff81111561166857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611691578160200160208202803683370190505b50915060005b80845111156117325760008482815181106116c257634e487b7160e01b600052603260045260246000fd5b60200260200101519050826005016000826001600160a01b03166001600160a01b031681526020019081526020016000205484838151811061171457634e487b7160e01b600052603260045260246000fd5b6020908102919091010152508061172a81615ed1565b915050611697565b5050915091565b6040517f93552a3d000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0382811660248301527f000000000000000000000000000000000000000000000000000000000000000016906393552a3d9060440160206040518083038186803b1580156117ba57600080fd5b505afa1580156117ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f29190615bc2565b6001600160a01b0391909116600090815260016020908152604080832094835293905291909120805460ff1916911515919091179055565b6001600160a01b0381166000908152600d602052604081208161185760018301600284016003850161372b565b9050600061186b836004018460050161437e565b9050611878816064615e9b565b82600c546118869190615e9b565b101595945050505050565b3360009081526001602090815260408083206004845290915290205460ff166118fc5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0383166000908152600d6020526040902061191f818484614409565b61192a818484613560565b50505050565b3360009081526001602090815260408083206004845290915281205460ff1661199b5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b038085166000908152600d602090815260408083204381559387168352600284019091529020548015611b0c57600080611a0d606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b038881166000818152600388016020526040908190205490517fe695fa68000000000000000000000000000000000000000000000000000000008152600481018890526024810192909252604482015291169063e695fa68906064016040805180830381600087803b158015611a8957600080fd5b505af1158015611a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac19190615cdd565b6001600160a01b038916600090815260028701602090815260408083208590556003890190915290208190559092509050611afc8683613dc3565b9450611b09848887613ddb565b50505b6000611b188486615eba565b9050611b258387836134b5565b5050509392505050565b33611b386133ac565b6001600160a01b03161480611b5c575033611b51613444565b6001600160a01b0316145b611ba85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600955565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316846001600160a01b03161415611bf0575081611cf0565b6001600160a01b03841660009081526005602052604081208054909190611c179042615eba565b9050600754811180611c2b57506001820154155b80611c3f5750838015611c3f575060085481115b15611cc1576000611cb083600201805480602002602001604051908101604052809291908181526020018280548015611ca157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c83575b50505050508460030154613a70565b9050611cbf83826009546144bc565b505b6e010000000000000000000000000000826001015486611ce19190615e9b565b611ceb9190615e7b565b925050505b9392505050565b6001600160a01b0381166000908152600d60205260408120610ea9600482016005830161437e565b33611d286133ac565b6001600160a01b03161480611d4c575033611d41613444565b6001600160a01b0316145b611d985760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b61ffff909116600755600855565b33611daf6133ac565b6001600160a01b03161480611dd3575033611dc8613444565b6001600160a01b0316145b611e1f5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601755565b6000333214611e9b5760405162461bcd60e51b815260206004820152603a60248201527f43757272656e746c79206e6f20696e7465726d656469617269657320616c6c6f60448201527f77656420666f7220746869732066756e6374696f6e2063616c6c0000000000006064820152608401610c62565b6000611ed8606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6040517f7b23cbce0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b039190911690637b23cbce90602401602060405180830381600087803b158015611f3457600080fd5b505af1158015611f48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6c9190615bc2565b905060008180611f7f5750611f7f614504565b9050611f8b84836145e4565b92506000611f97614b25565b90506000611fa3614bfb565b9050611fb16012600061582b565b600060646018546064611fc49190615e63565b611fce9084615e9b565b611fd89190615e7b565b905082811115612125577f3555ffae7677eb42103f0b9e11b61c758f452fae446684dec7a363dd38ab58fc61200d8483615eba565b60405190815260200160405180910390a18380156121225750807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166370a08231612091606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b1580156120e857600080fd5b505afa1580156120fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121209190615ca1565b115b93505b6000846121d657606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b03166001600160a01b0316631a38de1d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561219b57600080fd5b505af11580156121af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d39190615913565b90505b60005b6013548110156124405760006013828154811061220657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352600d909152604082209092509061223682614cc9565b9050600061224383614cdb565b905060006064601854836122579190615e9b565b6122619190615e7b565b905061226d818e615e63565b9c508a6122cf576001600160a01b038581166000908152601560205260409020600281018390556003810180543373ffffffffffffffffffffffffffffffffffffffff1991821617909155438255600190910180549091169189169190911790555b600060646122de846065615e9b565b6122e89190615e7b565b6122f29083615e63565b9050808411156123e257606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031663d9caed127f0000000000000000000000000000000000000000000000000000000000000000886123628589615eba565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b1580156123c957600080fd5b505af11580156123dd573d6000803e3d6000fd5b505050505b6040516001600160a01b03871681527f1d2cc4c8661a04a00b4e727426220501b36d85bb330947642c2d4320667028cf9060200160405180910390a161242785614cf1565b505050505050808061243890615ed1565b9150506121d9565b5060648760165460636124539190615e9b565b61245d9190615e63565b6124679190615e7b565b601655841561254957606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b03166040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152336024830152604482018a9052919091169063d9caed1290606401600060405180830381600087803b15801561253057600080fd5b505af1158015612544573d6000803e3d6000fd5b505050505b6000612586606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6001600160a01b0316631a38de1d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156125c057600080fd5b505af11580156125d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f89190615913565b90508615612672576001600160a01b038116600090815260146020526040902054881015612653576001600160a01b038116600090815260146020526040812080548a9290612648908490615eba565b9091555061266d9050565b6001600160a01b0381166000908152601460205260408120555b6126a0565b6001600160a01b038116600090815260146020526040812080548a929061269a908490615e63565b90915550505b50505050505050919050565b336126b56133ac565b6001600160a01b031614806126d95750336126ce613444565b6001600160a01b0316145b6127255760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b6001600160a01b038381166000908152600d602090815260408220600180820180549182018155845282842001805473ffffffffffffffffffffffffffffffffffffffff1916878616179055606683529190527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b549091166040517f46c87f800000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291909116906346c87f8090602401602060405180830381600087803b1580156127fb57600080fd5b505af115801561280f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128339190615ca1565b6001600160a01b038416600090815260038301602090815260408083209390935560028401905220829055612899606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517fee0862bf0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015260248201859052919091169063ee0862bf90604401600060405180830381600087803b1580156128fe57600080fd5b505af1158015612912573d6000803e3d6000fd5b5050505050505050565b600a818154811061292c57600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b336129586133ac565b6001600160a01b0316148061297c575033612971613444565b6001600160a01b0316145b6129c85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601855565b336129d66133ac565b6001600160a01b031614806129fa5750336129ef613444565b6001600160a01b0316145b612a465760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600b55565b3360009081526001602090815260408083206004845290915290205460ff16612ab65760405162461bcd60e51b815260206004820152601c60248201527f43616c6c696e6720636f6e7472206e6f7420617574686f72697a6564000000006044820152606401610c62565b6001600160a01b0383166000908152600d6020526040902061192a81848461360b565b6001600160a01b0381166000908152600d6020908152604091829020600181018054845181850281018501909552808552606094859490929190830182828015612b4c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612b2e575b5050506001840154929550505067ffffffffffffffff811115612b7f57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612ba8578160200160208202803683370190505b50915060005b8084511115611732576000848281518110612bd957634e487b7160e01b600052603260045260246000fd5b60200260200101519050612c1e606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03828116600081815260028701602090815260408083205460038a01909252918290205491517f76668b670000000000000000000000000000000000000000000000000000000081526004810191909152602481019290925260448201529116906376668b679060640160206040518083038186803b158015612ca757600080fd5b505afa158015612cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cdf9190615ca1565b848381518110612cff57634e487b7160e01b600052603260045260246000fd5b60209081029190910101525080612d1581615ed1565b915050612bae565b3360009081526001602090815260408083206004845290915290205460ff16612d885760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0381166000908152600d60205260409020612da981614cdb565b15612df65760405162461bcd60e51b815260206004820152601a60248201527f43616e2774206c69717569646174653a20626f72726f77696e670000000000006044820152606401610c62565b610b5a81614cf1565b33612e086133ac565b6001600160a01b03161480612e2c575033612e21613444565b6001600160a01b0316145b80612e7a575033612e6f6103e960009081526020527f236f539bf6e1b3b15a335e3cd157d360bc4be88c071635c19ba8a82b4f665e9f546001600160a01b031690565b6001600160a01b0316145b612eec5760405162461bcd60e51b815260206004820152603860248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a65642064697361626c657200000000000000006064820152608401610c62565b6000600a8281548110612f0f57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600302019050600081600101541115610b5a57600181015460095580546007556002015460085550565b33612f4c6133ac565b6001600160a01b03161480612f70575033612f65613444565b6001600160a01b0316145b612fbc5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b60408051606081018252938452602084019283528301908152600a805460018101825560009190915292517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a860039094029384015590517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a9830155517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2aa90910155565b336130686133ac565b6001600160a01b0316148061308c575033613081613444565b6001600160a01b0316145b6130d85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601055565b600281015460009015610ead578154600090613105906130fd9043615eba565b601754613dc3565b9050600060175482856002015461311c9190615e9b565b6131269190615e7b565b9050613163606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031690565b60038501546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015291821660248201526044810184905291169063d9caed1290606401600060405180830381600087803b1580156131f357600080fd5b505af1158015613207573d6000803e3d6000fd5b505050506000613248606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b90506000601654600161325b9190615e63565b83836001600160a01b0316630ad691506040518163ffffffff1660e01b815260040160206040518083038186803b15801561329557600080fd5b505afa1580156132a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cd9190615ca1565b6132d79190615e9b565b6132e19190615e7b565b600187015460038801546040517f0a45bc1b0000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152602481018490529082166044820152919250831690630a45bc1b90606401602060405180830381600087803b15801561335957600080fd5b505af115801561336d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133919190615ca1565b508286600201546133a29190615eba565b9695505050505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561340757600080fd5b505afa15801561341b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343f9190615913565b905090565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c34c08e56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156134a157600080fd5b505af115801561341b573d6000803e3d6000fd5b6134c0838383614409565b6001600160a01b0382166000908152600f6020526040812080548392906134e8908490615e63565b90915550506001600160a01b0382166000908152600f6020908152604080832054600e9092529091205410156112795760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6001600160a01b0382166000908152600f602052604081208054839290613588908490615e63565b90915550506001600160a01b0382166000908152600f6020908152604080832054600e9092529091205410156136005760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6112798383836140cf565b601054835461361a9190615e63565b43116136685760405162461bcd60e51b815260206004820181905260248201527f4e6f207769746864726177616c20736f6f6e206166746572206465706f7369746044820152606401610c62565b6001600160a01b0382166000908152600f602052604081208054839290613690908490615eba565b90915550506001600160a01b03821660009081526005840160205260409020546136bb908290615eba565b6001600160a01b03831660009081526005850160205260409020556136df83614e45565b6112795760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610c62565b8254600090815b818110156137af57600086828154811061375c57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083529088905260409091205490915061378f90829087614e91565b6137999085615e63565b93505080806137a790615ed1565b915050613732565b50509392505050565b60007fff000000000000000000000000000000000000000000000000000000000000008216156137f1576137ec8484614fa0565b6137fb565b6137fb8484615096565b6001600160a01b038082166000908152600660209081526040808320938916835292905220600181015491925090613a69576000806000846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561386b57600080fd5b505afa15801561387f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a39190615c23565b63ffffffff1692509250925060006138bb898961516b565b509050806001600160a01b0316896001600160a01b0316141561399e57836dffffffffffffffffffffffffffff16836dffffffffffffffffffffffffffff166e0100000000000000000000000000006139149190615e9b565b61391e9190615e7b565b8560020181905550856001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561395f57600080fd5b505afa158015613973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139979190615ca1565b8555613a60565b826dffffffffffffffffffffffffffff16846dffffffffffffffffffffffffffff166e0100000000000000000000000000006139da9190615e9b565b6139e49190615e7b565b8560020181905550856001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015613a2557600080fd5b505afa158015613a39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5d9190615ca1565b85555b50600184015550505b5050505050565b6e01000000000000000000000000000060005b60018451613a919190615eba565b811015613dbc576000848281518110613aba57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600085836001613ad49190615e63565b81518110613af257634e487b7160e01b600052603260045260246000fd5b602002602001015190506000858460208110613b1e57634e487b7160e01b600052603260045260246000fd5b1a60f81b7fff000000000000000000000000000000000000000000000000000000000000001615613b5857613b538383614fa0565b613b62565b613b628383615096565b6001600160a01b038082166000818152600660209081526040808320948916835293905282812083517f0902f1ac0000000000000000000000000000000000000000000000000000000081529351949550939092630902f1ac916004808301926060929190829003018186803b158015613bdb57600080fd5b505afa158015613bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c139190615c23565b63ffffffff16925050506000826001015482613c2f9190615eba565b9050600854811115613d92576000613c47878761516b565b5090506000816001600160a01b0316886001600160a01b031614613cdb57856001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015613c9e57600080fd5b505afa158015613cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd69190615ca1565b613d4c565b856001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015613d1457600080fd5b505afa158015613d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d4c9190615ca1565b9050600083866000015483613d619190615eba565b613d6b9190615e7b565b9050613d778b82615255565b6002870191909155908555600185018490559850613da39050565b613da0888460020154615255565b97505b5050505050508080613db490615ed1565b915050613a83565b5092915050565b600081831115613dd4575080610be7565b5081610be7565b600080613e19606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03858116600081815260028901602090815260408083205460038c01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b158015613ea357600080fd5b505af1158015613eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613edb9190615cdd565b90925090506000613eec8484615eba565b6001600160a01b0386166000908152600288016020526040902081905590508015613f33576001600160a01b0385166000908152600387016020526040902082905561407b565b6001600160a01b038516600090815260038701602052604081208190556001870154815b80821115614027576000896001018281548110613f8457634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0390811691508916811415613faf5760019350614014565b831561401457808a600101600184613fc79190615eba565b81548110613fe557634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b508061401f81615ed1565b915050613f57565b508760010180548061404957634e487b7160e01b600052603160045260246000fd5b6000828152602090208101600019908101805473ffffffffffffffffffffffffffffffffffffffff1916905501905550505b505050505050565b6001600160a01b03841660009081526005860160205260409020546140a9908390615eba565b6001600160a01b0385166000908152600587016020526040902055613a69858483614409565b6001600160a01b038216600090815260038401602052604090205461422b5760018381018054918201815560009081526020902001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055614165606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f46c87f800000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291909116906346c87f8090602401602060405180830381600087803b1580156141c357600080fd5b505af11580156141d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141fb9190615ca1565b6001600160a01b038316600090815260038501602090815260408083209390935560028601905220819055614375565b600080614269606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03858116600081815260028901602090815260408083205460038c01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b1580156142f357600080fd5b505af1158015614307573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061432b9190615cdd565b6001600160a01b0386166000908152600388016020526040902081905590925090506143578383615e63565b6001600160a01b038516600090815260028701602052604090205550505b6136df83614e45565b8154600090815b818110156144015760008582815481106143af57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352908790526040909120549091506143e1908290610b5e565b6143eb9085615e63565b93505080806143f990615ed1565b915050614385565b505092915050565b6001600160a01b038216600090815260068401602052604090205460ff16614488576004830180546001808201835560009283526020808420909201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0387169081179091558352600686019091526040909120805460ff191690911790555b6001600160a01b0382166000908152600584016020526040812080548392906144b2908490615e63565b9091555050505050565b6103e86144c98284615e9b565b6144d5836103e8615eba565b85600101546144e49190615e9b565b6144ee9190615e63565b6144f89190615e7b565b60018401555050429055565b600080614542606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6001600160a01b031663b0411f466040518163ffffffff1660e01b8152600401604080518083038186803b15801561457957600080fd5b505afa15801561458d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b19190615a86565b5090506016546019546145c49190615e9b565b6001600160a01b0390911660009081526014602052604090205411905090565b60408051600080825260208201928390529051909161460691601291906157b9565b506040805160008152602081019182905251614624916013916157b9565b5060005b8084511115613dbc57600084828151811061465357634e487b7160e01b600052603260045260246000fd5b602002602001015190506000600d6000836001600160a01b03166001600160a01b03168152602001908152602001600020905061468f81615291565b15614adb576013805460018101825560009182527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385161790556004820154905b8082111561481b57600083600401828154811061471f57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083526011909152604090912060028101549192509043146147d0576001600160a01b03821660008181526005870160205260408120546001808501919091558184554360028501556012805491820181559091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344401805473ffffffffffffffffffffffffffffffffffffffff19169091179055614806565b6001600160a01b038216600090815260058601602052604081205460018301805491929091614800908490615e63565b90915550505b5050808061481390615ed1565b9150506146f2565b5050600181015460005b80821115614ad857600083600101828154811061485257634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260408220909250906148b4606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03848116600081815260028a01602090815260408083205460038d01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b15801561493e57600080fd5b505af1158015614952573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149769190615cdd565b5090506149b4606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f2a6a897b0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152602482018490529190911690632a6a897b90604401600060405180830381600087803b158015614a1957600080fd5b505af1158015614a2d573d6000803e3d6000fd5b5050505043826002015414614aa857600060018381018290558284554360028501556012805491820181559091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344401805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038516179055614ac2565b80826000016000828254614abc9190615e63565b90915550505b5050508080614ad090615ed1565b915050614825565b50505b6001600160a01b03821660009081526015602052604090208515614b0f57614b02816130dd565b614b0c9086615e63565b94505b5050508080614b1d90615ed1565b915050614628565b601254600090815b80821115614bf657600060128281548110614b5857634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260409091208054600182015492935090911115614be15780546001820154600091614ba191615eba565b9050614bad83826152ce565b614bb79087615e63565b6001600160a01b038416600090815260116020526040812081815560018101829055600201559550505b50508080614bee90615ed1565b915050614b2d565b505090565b601254600090815b80821115614bf657600060128281548110614c2e57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260409091206001810154815492935090911115614cb457614c818282600101548360000154614c7c9190615eba565b61543a565b614c8b9086615e63565b6001600160a01b0383166000908152601160205260408120818155600181018290556002015594505b50508080614cc190615ed1565b915050614c03565b6000610be78260040183600501615595565b6000610be7826001018360020184600301615618565b600181015460005b80821115614d6a576000836001018281548110614d2657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031682526002860181526040808320839055600387019091528120555080614d6281615ed1565b915050614cf9565b5050600481015460005b80821115614e28576000836004018281548110614da157634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352600587018252604080842054600f90935283208054919450919290614de1908490615eba565b90915550506001600160a01b031660009081526005840160209081526040808320839055600686019091529020805460ff1916905580614e2081615ed1565b915050614d74565b50614e3760018301600061582b565b610b5a60048301600061582b565b600080614e5183614cdb565b90506000614e5e84614cc9565b9050600b5482614e6e9190615e9b565b6064600b54614e7d9190615eba565b614e879083615e9b565b1015949350505050565b600080614ecf606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f14189db20000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015291909116906314189db29060240160206040518083038186803b158015614f2b57600080fd5b505afa158015614f3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f639190615ca1565b6001600160a01b03861660009081526020859052604081205491925090614f8a8387615e9b565b614f949190615e7b565b9050611ceb8682610b5e565b6000806000614faf858561516b565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015291935091507f00000000000000000000000000000000000000000000000000000000000000009060480160405160208183030381529060405280519060200120600354604051602001615075939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b60408051601f19818403018152919052805160209091012095945050505050565b60008060006150a5858561516b565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015291935091507f00000000000000000000000000000000000000000000000000000000000000009060480160405160208183030381529060405280519060200120600254604051602001615075939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b600080826001600160a01b0316846001600160a01b031614156151d05760405162461bcd60e51b815260206004820152601260248201527f4964656e746963616c20616464726573732100000000000000000000000000006044820152606401610c62565b826001600160a01b0316846001600160a01b0316106151f05782846151f3565b83835b90925090506001600160a01b03821661524e5760405162461bcd60e51b815260206004820152600d60248201527f5a65726f206164647265737321000000000000000000000000000000000000006044820152606401610c62565b9250929050565b60006c0100000000000000000000000061527161010084615e7b565b61527d61010086615e7b565b6152879190615e9b565b611cf09190615e7b565b60008061529d83614cdb565b905060006152aa84614cc9565b905081600c546152ba9190615e9b565b6152c5826064615e9b565b10949350505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415615311575080610be7565b6001600160a01b038316600090815260056020526040812090615365606760009081526020527f682158d08466d11c566d5712d4396197fdd67e65be71d83c97ef719ec468867b546001600160a01b031690565b6001600160a01b031663351ae6108560008560030154866002016040518563ffffffff1660e01b815260040161539e9493929190615de9565b600060405180830381600087803b1580156153b857600080fd5b505af11580156153cc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526153f49190810190615b2f565b9050600081600183516154079190615eba565b8151811061542557634e487b7160e01b600052603260045260246000fd5b60200260200101519050809350505050610be7565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b0316141561547d575080610be7565b6001600160a01b0383166000908152600560205260408120906154d1606760009081526020527f682158d08466d11c566d5712d4396197fdd67e65be71d83c97ef719ec468867b546001600160a01b031690565b6001600160a01b03166353d7ff9f856000198560030154866004016040518563ffffffff1660e01b815260040161550b9493929190615de9565b600060405180830381600087803b15801561552557600080fd5b505af1158015615539573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526155619190810190615b2f565b90508060008151811061558457634e487b7160e01b600052603260045260246000fd5b602002602001015192505050610be7565b8154600090815b818110156144015760008582815481106155c657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352908790526040909120549091506155f890829061569c565b6156029085615e63565b935050808061561090615ed1565b91505061559c565b8254600090815b818110156137af57600086828154811061564957634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083529088905260409091205490915061567c908290876156aa565b6156869085615e63565b935050808061569490615ed1565b91505061561f565b6000611cf083836000611bad565b6000806156e8606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f14189db20000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015291909116906314189db29060240160206040518083038186803b15801561574457600080fd5b505afa158015615758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061577c9190615ca1565b6001600160a01b038616600090815260208590526040812054919250906157a38387615e9b565b6157ad9190615e7b565b9050611ceb868261569c565b82805482825590600052602060002090810192821561581b579160200282015b8281111561581b578251825473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039091161782556020909201916001909101906157d9565b5061582792915061584c565b5090565b5080546000825590600052602060002090810190615849919061584c565b50565b5b80821115615827576000815560010161584d565b600082601f830112615871578081fd5b8135602061588661588183615e3f565b615e0e565b80838252828201915082860187848660051b89010111156158a5578586fd5b855b858110156158cc5781356158ba81615f18565b845292840192908401906001016158a7565b5090979650505050505050565b80516dffffffffffffffffffffffffffff81168114610ead57600080fd5b600060208284031215615908578081fd5b8135611cf081615f18565b600060208284031215615924578081fd5b8151611cf081615f18565b60008060408385031215615941578081fd5b823561594c81615f18565b9150602083013561595c81615f18565b809150509250929050565b600080600080600060a0868803121561597e578081fd5b853561598981615f18565b9450602086013561599981615f18565b935060408601356159a981615f18565b94979396509394606081013594506080013592915050565b6000806000606084860312156159d5578283fd5b83356159e081615f18565b925060208401356159f081615f18565b929592945050506040919091013590565b600080600080600060a08688031215615a18578081fd5b8535615a2381615f18565b94506020860135615a3381615f18565b9350604086013592506060860135615a4a81615f18565b949793965091946080013592915050565b60008060408385031215615a6d578182fd5b8235615a7881615f18565b946020939093013593505050565b60008060408385031215615a98578182fd5b8251615aa381615f18565b6020939093015192949293505050565b600080600060608486031215615ac7578081fd5b8335615ad281615f18565b9250602084013591506040840135615ae981615f2d565b809150509250925092565b600060208284031215615b05578081fd5b813567ffffffffffffffff811115615b1b578182fd5b615b2784828501615861565b949350505050565b60006020808385031215615b41578182fd5b825167ffffffffffffffff811115615b57578283fd5b8301601f81018513615b67578283fd5b8051615b7561588182615e3f565b80828252848201915084840188868560051b8701011115615b94578687fd5b8694505b83851015615bb6578051835260019490940193918501918501615b98565b50979650505050505050565b600060208284031215615bd3578081fd5b8151611cf081615f2d565b60008060408385031215615bf0578182fd5b82359150602083013567ffffffffffffffff811115615c0d578182fd5b615c1985828601615861565b9150509250929050565b600080600060608486031215615c37578081fd5b615c40846158d9565b9250615c4e602085016158d9565b9150604084015163ffffffff81168114615ae9578182fd5b60008060408385031215615c78578182fd5b823561ffff81168114615a78578283fd5b600060208284031215615c9a578081fd5b5035919050565b600060208284031215615cb2578081fd5b5051919050565b60008060408385031215615ccb578182fd5b82359150602083013561595c81615f18565b60008060408385031215615cef578182fd5b505080516020909101519092909150565b600080600060608486031215615d14578081fd5b505081359360208301359350604090920135919050565b6000815480845260208085019450838352808320835b83811015615d665781546001600160a01b031687529582019560019182019101615d41565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b82811015615db55781516001600160a01b0316845260208401935090840190600101615d8e565b50505083810382850152845180825285830191830190845b818110156158cc57835183529284019291840191600101615dcd565b6000858252846020830152836040830152608060608301526133a26080830184615d2b565b604051601f8201601f1916810167ffffffffffffffff81118282101715615e3757615e37615f02565b604052919050565b600067ffffffffffffffff821115615e5957615e59615f02565b5060051b60200190565b60008219821115615e7657615e76615eec565b500190565b600082615e9657634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615eb557615eb5615eec565b500290565b600082821015615ecc57615ecc615eec565b500390565b6000600019821415615ee557615ee5615eec565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461584957600080fd5b801515811461584957600080fdfea26469706673582212207c310013677046eae3e75c3e7f504f30afb6e141a8904b63d61aef5af1678be964736f6c63430008030033000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000000000000000000000000000000000000000000096e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c63030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061038e5760003560e01c80637a1a04df116101de578063bc70c6661161010f578063df7c20f9116100ad578063ef859fc81161007c578063ef859fc81461090f578063f04c68651461094c578063f3f5f9b51461095f578063f99fd97c146109725761038e565b8063df7c20f9146108b4578063e0f3871f146108bd578063e2abb5c4146108dd578063e9c3f77d146108e65761038e565b8063d0eb6653116100e9578063d0eb665314610854578063d510c53514610867578063db2d904d1461087a578063db4292351461088d5761038e565b8063bc70c6661461081b578063c73afac21461082e578063c74303aa146108415761038e565b8063a53ac0d91161017c578063a985994b11610156578063a985994b14610761578063b25b454814610774578063b852eb0d14610787578063badb5048146107ae5761038e565b8063a53ac0d91461072f578063a75208a814610738578063a75697a5146107415761038e565b80639c56522c116101b85780639c56522c146106ed578063a17ab527146106f6578063a20ec49314610709578063a37189191461071c5761038e565b80637a1a04df146106615780637d100e841461068f5780638dc6a529146106985761038e565b8063320d2fa0116102c3578063498d55eb11610261578063538edb2911610230578063538edb291461062957806354554b581461063257806360b3fa40146106455780636585b5a6146106585761038e565b8063498d55eb146105f15780634aa4aca314610604578063519bda851461060d57806352a664d9146106165761038e565b80633ed456fa1161029d5780633ed456fa14610591578063409fdb721461059a578063447d52ba146105bb57806347788cd0146105ce5761038e565b8063320d2fa0146105395780633500aa0b14610542578063392f5f641461056a5761038e565b80631d84cc1811610330578063204120bc1161030a578063204120bc146104a657806320c27126146104fd5780632b23f8571461051d5780632febaa74146105305761038e565b80631d84cc18146104595780631f1cb62b1461046c5780631f692a64146104935761038e565b8063093a483a1161036c578063093a483a146103ff57806310d584341461042057806316317e7e146104335780631d47e4a3146104465761038e565b8063059b157a14610393578063071060a6146103d757806307c20175146103ec575b600080fd5b6103ba7f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac81565b6040516001600160a01b0390911681526020015b60405180910390f35b6103ea6103e5366004615c89565b610985565b005b6103ea6103fa366004615af4565b610a71565b61041261040d366004615a5b565b610b5e565b6040519081526020016103ce565b6103ea61042e366004615c89565b610bed565b6103ea610441366004615c89565b610c70565b6103ea610454366004615a5b565b610cee565b6103ea610467366004615a01565b610dcf565b6103ba7f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781565b6104126104a13660046158f7565b610e7d565b6104dd6104b43660046158f7565b600560208190526000918252604090912080546001820154600383015492909301549092919084565b6040805194855260208501939093529183015260608201526080016103ce565b61041261050b3660046158f7565b600f6020526000908152604090205481565b6103ea61052b366004615bde565b610eb2565b61041260105481565b610412600c5481565b610555610550366004615967565b61127e565b604080519283526020830191909152016103ce565b6103ba7f000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c81565b61041260075481565b6105ad6105a83660046158f7565b6115c2565b6040516103ce929190615d71565b6103ea6105c9366004615cb9565b611739565b6105e16105dc3660046158f7565b61182a565b60405190151581526020016103ce565b6103ea6105ff3660046159c1565b611891565b61041260175481565b61041260095481565b6104126106243660046159c1565b611930565b61041260185481565b6103ea610640366004615c89565b611b2f565b610412610653366004615ab3565b611bad565b61041260165481565b6105e161066f366004615a5b565b600160209081526000928352604080842090915290825290205460ff1681565b61041260195481565b6106d26106a636600461592f565b600660209081526000928352604080842090915290825290208054600182015460029092015490919083565b604080519384526020840192909252908201526060016103ce565b61041260085481565b6104126107043660046158f7565b611cf7565b6103ea610717366004615c66565b611d1f565b6103ea61072a366004615c89565b611da6565b610412600b5481565b61041260025481565b61041261074f3660046158f7565b60146020526000908152604090205481565b61041261076f366004615af4565b611e24565b6103ea6107823660046159c1565b6126ac565b6103ba7f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f81565b6107f06107bc3660046158f7565b601560205260009081526040902080546001820154600283015460039093015491926001600160a01b039182169290911684565b604080519485526001600160a01b0393841660208601528401919091521660608201526080016103ce565b6106d2610829366004615c89565b61291c565b6103ea61083c366004615c89565b61294f565b6103ea61084f366004615c89565b6129cd565b6103ea6108623660046159c1565b612a4b565b6105ad6108753660046158f7565b612ad9565b6103ea6108883660046158f7565b612d1d565b6103ba7f000000000000000000000000000000000000000000000000000000000000000081565b61041260035481565b6104126108cb3660046158f7565b600e6020526000908152604090205481565b61041260045481565b6103ba6108f4366004615c89565b6000602081905290815260409020546001600160a01b031681565b61041261091d36600461592f565b6001600160a01b039182166000908152600d602090815260408083209390941682526005909201909152205490565b6103ea61095a366004615c89565b612dff565b6103ea61096d366004615d00565b612f43565b6103ea610980366004615c89565b61305f565b6040517fb4ed0b6d000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c6001600160a01b03169063b4ed0b6d9060240160206040518083038186803b1580156109fe57600080fd5b505afa158015610a12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a369190615913565b600091825260208290526040909120805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03909216919091179055565b60005b8082511115610b5a576000828281518110610a9f57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600060156000836001600160a01b03166001600160a01b0316815260200190815260200160002090506017548160000154610ae49190615e63565b431115610b4557610af4816130dd565b506001600160a01b038216600090815260156020526040812081815560018101805473ffffffffffffffffffffffffffffffffffffffff199081169091556002820192909255600301805490911690555b50508080610b5290615ed1565b915050610a74565b5050565b60007f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316836001600160a01b03161415610ba1575080610be7565b6001600160a01b038316600090815260056020526040902060018101546e010000000000000000000000000000610bd88286615e9b565b610be29190615e7b565b925050505b92915050565b33610bf66133ac565b6001600160a01b03161480610c1a575033610c0f613444565b6001600160a01b0316145b610c6b5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e6572000060448201526064015b60405180910390fd5b601955565b33610c796133ac565b6001600160a01b03161480610c9d575033610c92613444565b6001600160a01b0316145b610ce95760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600c55565b33610cf76133ac565b6001600160a01b03161480610d1b575033610d10613444565b6001600160a01b0316145b80610d4157503360009081526001602090815260408083206009845290915290205460ff165b610db35760405162461bcd60e51b815260206004820152603960248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a656420616374697661746f72000000000000006064820152608401610c62565b6001600160a01b039091166000908152600e6020526040902055565b3360009081526001602090815260408083206004845290915290205460ff16610e3a5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0385166000908152600d60205260409020610e5d8186866134b5565b610e68818484613560565b610e7381848461360b565b4390555050505050565b6001600160a01b0381166000908152600d60205260408120610ea960018201600283016003840161372b565b9150505b919050565b33610ebb6133ac565b6001600160a01b03161480610edf575033610ed4613444565b6001600160a01b0316145b80610f0557503360009081526001602090815260408083206009845290915290205460ff165b610f775760405162461bcd60e51b815260206004820152603960248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a656420616374697661746f72000000000000006064820152608401610c62565b600081600081518110610f9a57634e487b7160e01b600052603260045260246000fd5b602002602001015190507f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316816001600160a01b031614611279576001600160a01b038116600090815260056020908152604090912060038101859055835190916110149160028401918601906157b9565b50825167ffffffffffffffff81111561103d57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611066578160200160208202803683370190505b50805161107d9160048401916020909101906157b9565b506000805b80600186516110919190615eba565b11156111a55761111f8582815181106110ba57634e487b7160e01b600052603260045260246000fd5b6020026020010151868360016110d09190615e63565b815181106110ee57634e487b7160e01b600052603260045260246000fd5b602002602001015188846020811061111657634e487b7160e01b600052603260045260246000fd5b1a60f81b6137b8565b600081600287516111309190615eba565b61113a9190615eba565b611145906008615e9b565b87836020811061116557634e487b7160e01b600052603260045260246000fd5b1a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016901c9290921791508061119d81615ed1565b915050611082565b506005820181905560005b8085511115611264578460018287516111c99190615eba565b6111d39190615eba565b815181106111f157634e487b7160e01b600052603260045260246000fd5b602002602001015183600401828154811061121c57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03929092169190911790558061125c81615ed1565b9150506111b0565b5061126f8486613a70565b6001830155504290555b505050565b33600090815260016020908152604080832060048452909152812054819060ff166112eb5760405162461bcd60e51b815260206004820181905260248201527f43616c6c696e6720636f6e74722e206e6f7420616e20617574686f72697a65646044820152606401610c62565b6001600160a01b038088166000908152600d602090815260408083209389168352600284019091529020541561146657600080611359606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03898116600081815260028701602090815260408083205460038a01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b1580156113e357600080fd5b505af11580156113f7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061141b9190615cdd565b6001600160a01b038a166000908152600286016020908152604080832085905560038801909152902081905590925090506114568683613dc3565b9450611463838987613ddb565b50505b6001600160a01b038716600090815260058201602052604090205485908082111561149b579050806114988188615eba565b93505b838711156114db576114ad8488615eba565b6001600160a01b038a166000908152600f6020526040812080549091906114d5908490615eba565b90915550505b8486111561151b576114ed8587615eba565b6001600160a01b0389166000908152600f602052604081208054909190611515908490615e63565b90915550505b6001600160a01b0388166000908152600f6020908152604080832054600e90925290912054101561158e5760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6115a4838a8a8561159f8a8c615eba565b614083565b83156115b5576115b5838a866140cf565b5050509550959350505050565b6001600160a01b0381166000908152600d602090815260409182902060048101805484518185028101850190955280855260609485949092919083018282801561163557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611617575b5050506004840154929550505067ffffffffffffffff81111561166857634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611691578160200160208202803683370190505b50915060005b80845111156117325760008482815181106116c257634e487b7160e01b600052603260045260246000fd5b60200260200101519050826005016000826001600160a01b03166001600160a01b031681526020019081526020016000205484838151811061171457634e487b7160e01b600052603260045260246000fd5b6020908102919091010152508061172a81615ed1565b915050611697565b5050915091565b6040517f93552a3d000000000000000000000000000000000000000000000000000000008152600481018390526001600160a01b0382811660248301527f000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c16906393552a3d9060440160206040518083038186803b1580156117ba57600080fd5b505afa1580156117ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f29190615bc2565b6001600160a01b0391909116600090815260016020908152604080832094835293905291909120805460ff1916911515919091179055565b6001600160a01b0381166000908152600d602052604081208161185760018301600284016003850161372b565b9050600061186b836004018460050161437e565b9050611878816064615e9b565b82600c546118869190615e9b565b101595945050505050565b3360009081526001602090815260408083206004845290915290205460ff166118fc5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0383166000908152600d6020526040902061191f818484614409565b61192a818484613560565b50505050565b3360009081526001602090815260408083206004845290915281205460ff1661199b5760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b038085166000908152600d602090815260408083204381559387168352600284019091529020548015611b0c57600080611a0d606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b038881166000818152600388016020526040908190205490517fe695fa68000000000000000000000000000000000000000000000000000000008152600481018890526024810192909252604482015291169063e695fa68906064016040805180830381600087803b158015611a8957600080fd5b505af1158015611a9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ac19190615cdd565b6001600160a01b038916600090815260028701602090815260408083208590556003890190915290208190559092509050611afc8683613dc3565b9450611b09848887613ddb565b50505b6000611b188486615eba565b9050611b258387836134b5565b5050509392505050565b33611b386133ac565b6001600160a01b03161480611b5c575033611b51613444565b6001600160a01b0316145b611ba85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600955565b60007f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316846001600160a01b03161415611bf0575081611cf0565b6001600160a01b03841660009081526005602052604081208054909190611c179042615eba565b9050600754811180611c2b57506001820154155b80611c3f5750838015611c3f575060085481115b15611cc1576000611cb083600201805480602002602001604051908101604052809291908181526020018280548015611ca157602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611c83575b50505050508460030154613a70565b9050611cbf83826009546144bc565b505b6e010000000000000000000000000000826001015486611ce19190615e9b565b611ceb9190615e7b565b925050505b9392505050565b6001600160a01b0381166000908152600d60205260408120610ea9600482016005830161437e565b33611d286133ac565b6001600160a01b03161480611d4c575033611d41613444565b6001600160a01b0316145b611d985760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b61ffff909116600755600855565b33611daf6133ac565b6001600160a01b03161480611dd3575033611dc8613444565b6001600160a01b0316145b611e1f5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601755565b6000333214611e9b5760405162461bcd60e51b815260206004820152603a60248201527f43757272656e746c79206e6f20696e7465726d656469617269657320616c6c6f60448201527f77656420666f7220746869732066756e6374696f6e2063616c6c0000000000006064820152608401610c62565b6000611ed8606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6040517f7b23cbce0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b039190911690637b23cbce90602401602060405180830381600087803b158015611f3457600080fd5b505af1158015611f48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f6c9190615bc2565b905060008180611f7f5750611f7f614504565b9050611f8b84836145e4565b92506000611f97614b25565b90506000611fa3614bfb565b9050611fb16012600061582b565b600060646018546064611fc49190615e63565b611fce9084615e9b565b611fd89190615e7b565b905082811115612125577f3555ffae7677eb42103f0b9e11b61c758f452fae446684dec7a363dd38ab58fc61200d8483615eba565b60405190815260200160405180910390a18380156121225750807f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b03166370a08231612091606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031690565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526001600160a01b03909116600482015260240160206040518083038186803b1580156120e857600080fd5b505afa1580156120fc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121209190615ca1565b115b93505b6000846121d657606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b03166001600160a01b0316631a38de1d6040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561219b57600080fd5b505af11580156121af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121d39190615913565b90505b60005b6013548110156124405760006013828154811061220657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352600d909152604082209092509061223682614cc9565b9050600061224383614cdb565b905060006064601854836122579190615e9b565b6122619190615e7b565b905061226d818e615e63565b9c508a6122cf576001600160a01b038581166000908152601560205260409020600281018390556003810180543373ffffffffffffffffffffffffffffffffffffffff1991821617909155438255600190910180549091169189169190911790555b600060646122de846065615e9b565b6122e89190615e7b565b6122f29083615e63565b9050808411156123e257606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031663d9caed127f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7886123628589615eba565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b0393841660048201529290911660248301526044820152606401600060405180830381600087803b1580156123c957600080fd5b505af11580156123dd573d6000803e3d6000fd5b505050505b6040516001600160a01b03871681527f1d2cc4c8661a04a00b4e727426220501b36d85bb330947642c2d4320667028cf9060200160405180910390a161242785614cf1565b505050505050808061243890615ed1565b9150506121d9565b5060648760165460636124539190615e9b565b61245d9190615e63565b6124679190615e7b565b601655841561254957606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b03166040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec781166004830152336024830152604482018a9052919091169063d9caed1290606401600060405180830381600087803b15801561253057600080fd5b505af1158015612544573d6000803e3d6000fd5b505050505b6000612586606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6001600160a01b0316631a38de1d6040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156125c057600080fd5b505af11580156125d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125f89190615913565b90508615612672576001600160a01b038116600090815260146020526040902054881015612653576001600160a01b038116600090815260146020526040812080548a9290612648908490615eba565b9091555061266d9050565b6001600160a01b0381166000908152601460205260408120555b6126a0565b6001600160a01b038116600090815260146020526040812080548a929061269a908490615e63565b90915550505b50505050505050919050565b336126b56133ac565b6001600160a01b031614806126d95750336126ce613444565b6001600160a01b0316145b6127255760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b6001600160a01b038381166000908152600d602090815260408220600180820180549182018155845282842001805473ffffffffffffffffffffffffffffffffffffffff1916878616179055606683529190527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b549091166040517f46c87f800000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015291909116906346c87f8090602401602060405180830381600087803b1580156127fb57600080fd5b505af115801561280f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128339190615ca1565b6001600160a01b038416600090815260038301602090815260408083209390935560028401905220829055612899606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517fee0862bf0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015260248201859052919091169063ee0862bf90604401600060405180830381600087803b1580156128fe57600080fd5b505af1158015612912573d6000803e3d6000fd5b5050505050505050565b600a818154811061292c57600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b336129586133ac565b6001600160a01b0316148061297c575033612971613444565b6001600160a01b0316145b6129c85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601855565b336129d66133ac565b6001600160a01b031614806129fa5750336129ef613444565b6001600160a01b0316145b612a465760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b600b55565b3360009081526001602090815260408083206004845290915290205460ff16612ab65760405162461bcd60e51b815260206004820152601c60248201527f43616c6c696e6720636f6e7472206e6f7420617574686f72697a6564000000006044820152606401610c62565b6001600160a01b0383166000908152600d6020526040902061192a81848461360b565b6001600160a01b0381166000908152600d6020908152604091829020600181018054845181850281018501909552808552606094859490929190830182828015612b4c57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612b2e575b5050506001840154929550505067ffffffffffffffff811115612b7f57634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015612ba8578160200160208202803683370190505b50915060005b8084511115611732576000848281518110612bd957634e487b7160e01b600052603260045260246000fd5b60200260200101519050612c1e606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03828116600081815260028701602090815260408083205460038a01909252918290205491517f76668b670000000000000000000000000000000000000000000000000000000081526004810191909152602481019290925260448201529116906376668b679060640160206040518083038186803b158015612ca757600080fd5b505afa158015612cbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cdf9190615ca1565b848381518110612cff57634e487b7160e01b600052603260045260246000fd5b60209081029190910101525080612d1581615ed1565b915050612bae565b3360009081526001602090815260408083206004845290915290205460ff16612d885760405162461bcd60e51b815260206004820152601d60248201527f43616c6c696e6720636f6e74722e206e6f7420617574686f72697a65640000006044820152606401610c62565b6001600160a01b0381166000908152600d60205260409020612da981614cdb565b15612df65760405162461bcd60e51b815260206004820152601a60248201527f43616e2774206c69717569646174653a20626f72726f77696e670000000000006044820152606401610c62565b610b5a81614cf1565b33612e086133ac565b6001600160a01b03161480612e2c575033612e21613444565b6001600160a01b0316145b80612e7a575033612e6f6103e960009081526020527f236f539bf6e1b3b15a335e3cd157d360bc4be88c071635c19ba8a82b4f665e9f546001600160a01b031690565b6001600160a01b0316145b612eec5760405162461bcd60e51b815260206004820152603860248201527f43616c6c6572206973206e6f7420746865206f776e65722c206578656375746f60448201527f72206f7220617574686f72697a65642064697361626c657200000000000000006064820152608401610c62565b6000600a8281548110612f0f57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600302019050600081600101541115610b5a57600181015460095580546007556002015460085550565b33612f4c6133ac565b6001600160a01b03161480612f70575033612f65613444565b6001600160a01b0316145b612fbc5760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b60408051606081018252938452602084019283528301908152600a805460018101825560009190915292517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a860039094029384015590517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a9830155517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2aa90910155565b336130686133ac565b6001600160a01b0316148061308c575033613081613444565b6001600160a01b0316145b6130d85760405162461bcd60e51b815260206004820152601e60248201527f526f6c65733a2063616c6c6572206973206e6f7420746865206f776e657200006044820152606401610c62565b601055565b600281015460009015610ead578154600090613105906130fd9043615eba565b601754613dc3565b9050600060175482856002015461311c9190615e9b565b6131269190615e7b565b9050613163606560009081526020527f4a7203f705e51df4a56139a9b86b4a0970bed7ab7a3446eaffe2289989c1645c546001600160a01b031690565b60038501546040517fd9caed120000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec78116600483015291821660248201526044810184905291169063d9caed1290606401600060405180830381600087803b1580156131f357600080fd5b505af1158015613207573d6000803e3d6000fd5b505050506000613248606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b90506000601654600161325b9190615e63565b83836001600160a01b0316630ad691506040518163ffffffff1660e01b815260040160206040518083038186803b15801561329557600080fd5b505afa1580156132a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132cd9190615ca1565b6132d79190615e9b565b6132e19190615e7b565b600187015460038801546040517f0a45bc1b0000000000000000000000000000000000000000000000000000000081526001600160a01b039283166004820152602481018490529082166044820152919250831690630a45bc1b90606401602060405180830381600087803b15801561335957600080fd5b505af115801561336d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133919190615ca1565b508286600201546133a29190615eba565b9695505050505050565b60007f000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c6001600160a01b0316638da5cb5b6040518163ffffffff1660e01b815260040160206040518083038186803b15801561340757600080fd5b505afa15801561341b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061343f9190615913565b905090565b60007f000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c6001600160a01b031663c34c08e56040518163ffffffff1660e01b8152600401602060405180830381600087803b1580156134a157600080fd5b505af115801561341b573d6000803e3d6000fd5b6134c0838383614409565b6001600160a01b0382166000908152600f6020526040812080548392906134e8908490615e63565b90915550506001600160a01b0382166000908152600f6020908152604080832054600e9092529091205410156112795760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6001600160a01b0382166000908152600f602052604081208054839290613588908490615e63565b90915550506001600160a01b0382166000908152600f6020908152604080832054600e9092529091205410156136005760405162461bcd60e51b815260206004820152601860248201527f4578636565647320676c6f62616c20746f6b656e2063617000000000000000006044820152606401610c62565b6112798383836140cf565b601054835461361a9190615e63565b43116136685760405162461bcd60e51b815260206004820181905260248201527f4e6f207769746864726177616c20736f6f6e206166746572206465706f7369746044820152606401610c62565b6001600160a01b0382166000908152600f602052604081208054839290613690908490615eba565b90915550506001600160a01b03821660009081526005840160205260409020546136bb908290615eba565b6001600160a01b03831660009081526005850160205260409020556136df83614e45565b6112795760405162461bcd60e51b815260206004820152601460248201527f496e73756666696369656e742062616c616e63650000000000000000000000006044820152606401610c62565b8254600090815b818110156137af57600086828154811061375c57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083529088905260409091205490915061378f90829087614e91565b6137999085615e63565b93505080806137a790615ed1565b915050613732565b50509392505050565b60007fff000000000000000000000000000000000000000000000000000000000000008216156137f1576137ec8484614fa0565b6137fb565b6137fb8484615096565b6001600160a01b038082166000908152600660209081526040808320938916835292905220600181015491925090613a69576000806000846001600160a01b0316630902f1ac6040518163ffffffff1660e01b815260040160606040518083038186803b15801561386b57600080fd5b505afa15801561387f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138a39190615c23565b63ffffffff1692509250925060006138bb898961516b565b509050806001600160a01b0316896001600160a01b0316141561399e57836dffffffffffffffffffffffffffff16836dffffffffffffffffffffffffffff166e0100000000000000000000000000006139149190615e9b565b61391e9190615e7b565b8560020181905550856001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b15801561395f57600080fd5b505afa158015613973573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139979190615ca1565b8555613a60565b826dffffffffffffffffffffffffffff16846dffffffffffffffffffffffffffff166e0100000000000000000000000000006139da9190615e9b565b6139e49190615e7b565b8560020181905550856001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015613a2557600080fd5b505afa158015613a39573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613a5d9190615ca1565b85555b50600184015550505b5050505050565b6e01000000000000000000000000000060005b60018451613a919190615eba565b811015613dbc576000848281518110613aba57634e487b7160e01b600052603260045260246000fd5b60200260200101519050600085836001613ad49190615e63565b81518110613af257634e487b7160e01b600052603260045260246000fd5b602002602001015190506000858460208110613b1e57634e487b7160e01b600052603260045260246000fd5b1a60f81b7fff000000000000000000000000000000000000000000000000000000000000001615613b5857613b538383614fa0565b613b62565b613b628383615096565b6001600160a01b038082166000818152600660209081526040808320948916835293905282812083517f0902f1ac0000000000000000000000000000000000000000000000000000000081529351949550939092630902f1ac916004808301926060929190829003018186803b158015613bdb57600080fd5b505afa158015613bef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c139190615c23565b63ffffffff16925050506000826001015482613c2f9190615eba565b9050600854811115613d92576000613c47878761516b565b5090506000816001600160a01b0316886001600160a01b031614613cdb57856001600160a01b0316635a3d54936040518163ffffffff1660e01b815260040160206040518083038186803b158015613c9e57600080fd5b505afa158015613cb2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd69190615ca1565b613d4c565b856001600160a01b0316635909c0d56040518163ffffffff1660e01b815260040160206040518083038186803b158015613d1457600080fd5b505afa158015613d28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613d4c9190615ca1565b9050600083866000015483613d619190615eba565b613d6b9190615e7b565b9050613d778b82615255565b6002870191909155908555600185018490559850613da39050565b613da0888460020154615255565b97505b5050505050508080613db490615ed1565b915050613a83565b5092915050565b600081831115613dd4575080610be7565b5081610be7565b600080613e19606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03858116600081815260028901602090815260408083205460038c01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b158015613ea357600080fd5b505af1158015613eb7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613edb9190615cdd565b90925090506000613eec8484615eba565b6001600160a01b0386166000908152600288016020526040902081905590508015613f33576001600160a01b0385166000908152600387016020526040902082905561407b565b6001600160a01b038516600090815260038701602052604081208190556001870154815b80821115614027576000896001018281548110613f8457634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0390811691508916811415613faf5760019350614014565b831561401457808a600101600184613fc79190615eba565b81548110613fe557634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b508061401f81615ed1565b915050613f57565b508760010180548061404957634e487b7160e01b600052603160045260246000fd5b6000828152602090208101600019908101805473ffffffffffffffffffffffffffffffffffffffff1916905501905550505b505050505050565b6001600160a01b03841660009081526005860160205260409020546140a9908390615eba565b6001600160a01b0385166000908152600587016020526040902055613a69858483614409565b6001600160a01b038216600090815260038401602052604090205461422b5760018381018054918201815560009081526020902001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055614165606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f46c87f800000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291909116906346c87f8090602401602060405180830381600087803b1580156141c357600080fd5b505af11580156141d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141fb9190615ca1565b6001600160a01b038316600090815260038501602090815260408083209390935560028601905220819055614375565b600080614269606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03858116600081815260028901602090815260408083205460038c01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b1580156142f357600080fd5b505af1158015614307573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061432b9190615cdd565b6001600160a01b0386166000908152600388016020526040902081905590925090506143578383615e63565b6001600160a01b038516600090815260028701602052604090205550505b6136df83614e45565b8154600090815b818110156144015760008582815481106143af57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352908790526040909120549091506143e1908290610b5e565b6143eb9085615e63565b93505080806143f990615ed1565b915050614385565b505092915050565b6001600160a01b038216600090815260068401602052604090205460ff16614488576004830180546001808201835560009283526020808420909201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0387169081179091558352600686019091526040909120805460ff191690911790555b6001600160a01b0382166000908152600584016020526040812080548392906144b2908490615e63565b9091555050505050565b6103e86144c98284615e9b565b6144d5836103e8615eba565b85600101546144e49190615e9b565b6144ee9190615e63565b6144f89190615e7b565b60018401555050429055565b600080614542606b60009081526020527f2dc7a963308417ad45132da282495eb244f38a7db03940a4d808be607669c622546001600160a01b031690565b6001600160a01b031663b0411f466040518163ffffffff1660e01b8152600401604080518083038186803b15801561457957600080fd5b505afa15801561458d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145b19190615a86565b5090506016546019546145c49190615e9b565b6001600160a01b0390911660009081526014602052604090205411905090565b60408051600080825260208201928390529051909161460691601291906157b9565b506040805160008152602081019182905251614624916013916157b9565b5060005b8084511115613dbc57600084828151811061465357634e487b7160e01b600052603260045260246000fd5b602002602001015190506000600d6000836001600160a01b03166001600160a01b03168152602001908152602001600020905061468f81615291565b15614adb576013805460018101825560009182527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0385161790556004820154905b8082111561481b57600083600401828154811061471f57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083526011909152604090912060028101549192509043146147d0576001600160a01b03821660008181526005870160205260408120546001808501919091558184554360028501556012805491820181559091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344401805473ffffffffffffffffffffffffffffffffffffffff19169091179055614806565b6001600160a01b038216600090815260058601602052604081205460018301805491929091614800908490615e63565b90915550505b5050808061481390615ed1565b9150506146f2565b5050600181015460005b80821115614ad857600083600101828154811061485257634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260408220909250906148b4606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6001600160a01b03848116600081815260028a01602090815260408083205460038d01909252918290205491517fe695fa6800000000000000000000000000000000000000000000000000000000815260048101919091526024810192909252604482015291169063e695fa68906064016040805180830381600087803b15801561493e57600080fd5b505af1158015614952573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906149769190615cdd565b5090506149b4606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f2a6a897b0000000000000000000000000000000000000000000000000000000081526001600160a01b038581166004830152602482018490529190911690632a6a897b90604401600060405180830381600087803b158015614a1957600080fd5b505af1158015614a2d573d6000803e3d6000fd5b5050505043826002015414614aa857600060018381018290558284554360028501556012805491820181559091527fbb8a6a4669ba250d26cd7a459eca9d215f8307e33aebe50379bc5a3617ec344401805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038516179055614ac2565b80826000016000828254614abc9190615e63565b90915550505b5050508080614ad090615ed1565b915050614825565b50505b6001600160a01b03821660009081526015602052604090208515614b0f57614b02816130dd565b614b0c9086615e63565b94505b5050508080614b1d90615ed1565b915050614628565b601254600090815b80821115614bf657600060128281548110614b5857634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260409091208054600182015492935090911115614be15780546001820154600091614ba191615eba565b9050614bad83826152ce565b614bb79087615e63565b6001600160a01b038416600090815260116020526040812081815560018101829055600201559550505b50508080614bee90615ed1565b915050614b2d565b505090565b601254600090815b80821115614bf657600060128281548110614c2e57634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352601190915260409091206001810154815492935090911115614cb457614c818282600101548360000154614c7c9190615eba565b61543a565b614c8b9086615e63565b6001600160a01b0383166000908152601160205260408120818155600181018290556002015594505b50508080614cc190615ed1565b915050614c03565b6000610be78260040183600501615595565b6000610be7826001018360020184600301615618565b600181015460005b80821115614d6a576000836001018281548110614d2657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b031682526002860181526040808320839055600387019091528120555080614d6281615ed1565b915050614cf9565b5050600481015460005b80821115614e28576000836004018281548110614da157634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352600587018252604080842054600f90935283208054919450919290614de1908490615eba565b90915550506001600160a01b031660009081526005840160209081526040808320839055600686019091529020805460ff1916905580614e2081615ed1565b915050614d74565b50614e3760018301600061582b565b610b5a60048301600061582b565b600080614e5183614cdb565b90506000614e5e84614cc9565b9050600b5482614e6e9190615e9b565b6064600b54614e7d9190615eba565b614e879083615e9b565b1015949350505050565b600080614ecf606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f14189db20000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015291909116906314189db29060240160206040518083038186803b158015614f2b57600080fd5b505afa158015614f3f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614f639190615ca1565b6001600160a01b03861660009081526020859052604081205491925090614f8a8387615e9b565b614f949190615e7b565b9050611ceb8682610b5e565b6000806000614faf858561516b565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015291935091507f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac9060480160405160208183030381529060405280519060200120600354604051602001615075939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b60408051601f19818403018152919052805160209091012095945050505050565b60008060006150a5858561516b565b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b16603482015291935091507f0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f9060480160405160208183030381529060405280519060200120600254604051602001615075939291907fff00000000000000000000000000000000000000000000000000000000000000815260609390931b6bffffffffffffffffffffffff191660018401526015830191909152603582015260550190565b600080826001600160a01b0316846001600160a01b031614156151d05760405162461bcd60e51b815260206004820152601260248201527f4964656e746963616c20616464726573732100000000000000000000000000006044820152606401610c62565b826001600160a01b0316846001600160a01b0316106151f05782846151f3565b83835b90925090506001600160a01b03821661524e5760405162461bcd60e51b815260206004820152600d60248201527f5a65726f206164647265737321000000000000000000000000000000000000006044820152606401610c62565b9250929050565b60006c0100000000000000000000000061527161010084615e7b565b61527d61010086615e7b565b6152879190615e9b565b611cf09190615e7b565b60008061529d83614cdb565b905060006152aa84614cc9565b905081600c546152ba9190615e9b565b6152c5826064615e9b565b10949350505050565b60007f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316836001600160a01b03161415615311575080610be7565b6001600160a01b038316600090815260056020526040812090615365606760009081526020527f682158d08466d11c566d5712d4396197fdd67e65be71d83c97ef719ec468867b546001600160a01b031690565b6001600160a01b031663351ae6108560008560030154866002016040518563ffffffff1660e01b815260040161539e9493929190615de9565b600060405180830381600087803b1580156153b857600080fd5b505af11580156153cc573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526153f49190810190615b2f565b9050600081600183516154079190615eba565b8151811061542557634e487b7160e01b600052603260045260246000fd5b60200260200101519050809350505050610be7565b60007f000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec76001600160a01b0316836001600160a01b0316141561547d575080610be7565b6001600160a01b0383166000908152600560205260408120906154d1606760009081526020527f682158d08466d11c566d5712d4396197fdd67e65be71d83c97ef719ec468867b546001600160a01b031690565b6001600160a01b03166353d7ff9f856000198560030154866004016040518563ffffffff1660e01b815260040161550b9493929190615de9565b600060405180830381600087803b15801561552557600080fd5b505af1158015615539573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526155619190810190615b2f565b90508060008151811061558457634e487b7160e01b600052603260045260246000fd5b602002602001015192505050610be7565b8154600090815b818110156144015760008582815481106155c657634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b0316808352908790526040909120549091506155f890829061569c565b6156029085615e63565b935050808061561090615ed1565b91505061559c565b8254600090815b818110156137af57600086828154811061564957634e487b7160e01b600052603260045260246000fd5b60009182526020808320909101546001600160a01b03168083529088905260409091205490915061567c908290876156aa565b6156869085615e63565b935050808061569490615ed1565b91505061561f565b6000611cf083836000611bad565b6000806156e8606660009081526020527f422cccb7cea5c0e46f340bb7b21b81debac329f72e31669c20ff0f3a05cc2b5b546001600160a01b031690565b6040517f14189db20000000000000000000000000000000000000000000000000000000081526001600160a01b03878116600483015291909116906314189db29060240160206040518083038186803b15801561574457600080fd5b505afa158015615758573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061577c9190615ca1565b6001600160a01b038616600090815260208590526040812054919250906157a38387615e9b565b6157ad9190615e7b565b9050611ceb868261569c565b82805482825590600052602060002090810192821561581b579160200282015b8281111561581b578251825473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b039091161782556020909201916001909101906157d9565b5061582792915061584c565b5090565b5080546000825590600052602060002090810190615849919061584c565b50565b5b80821115615827576000815560010161584d565b600082601f830112615871578081fd5b8135602061588661588183615e3f565b615e0e565b80838252828201915082860187848660051b89010111156158a5578586fd5b855b858110156158cc5781356158ba81615f18565b845292840192908401906001016158a7565b5090979650505050505050565b80516dffffffffffffffffffffffffffff81168114610ead57600080fd5b600060208284031215615908578081fd5b8135611cf081615f18565b600060208284031215615924578081fd5b8151611cf081615f18565b60008060408385031215615941578081fd5b823561594c81615f18565b9150602083013561595c81615f18565b809150509250929050565b600080600080600060a0868803121561597e578081fd5b853561598981615f18565b9450602086013561599981615f18565b935060408601356159a981615f18565b94979396509394606081013594506080013592915050565b6000806000606084860312156159d5578283fd5b83356159e081615f18565b925060208401356159f081615f18565b929592945050506040919091013590565b600080600080600060a08688031215615a18578081fd5b8535615a2381615f18565b94506020860135615a3381615f18565b9350604086013592506060860135615a4a81615f18565b949793965091946080013592915050565b60008060408385031215615a6d578182fd5b8235615a7881615f18565b946020939093013593505050565b60008060408385031215615a98578182fd5b8251615aa381615f18565b6020939093015192949293505050565b600080600060608486031215615ac7578081fd5b8335615ad281615f18565b9250602084013591506040840135615ae981615f2d565b809150509250925092565b600060208284031215615b05578081fd5b813567ffffffffffffffff811115615b1b578182fd5b615b2784828501615861565b949350505050565b60006020808385031215615b41578182fd5b825167ffffffffffffffff811115615b57578283fd5b8301601f81018513615b67578283fd5b8051615b7561588182615e3f565b80828252848201915084840188868560051b8701011115615b94578687fd5b8694505b83851015615bb6578051835260019490940193918501918501615b98565b50979650505050505050565b600060208284031215615bd3578081fd5b8151611cf081615f2d565b60008060408385031215615bf0578182fd5b82359150602083013567ffffffffffffffff811115615c0d578182fd5b615c1985828601615861565b9150509250929050565b600080600060608486031215615c37578081fd5b615c40846158d9565b9250615c4e602085016158d9565b9150604084015163ffffffff81168114615ae9578182fd5b60008060408385031215615c78578182fd5b823561ffff81168114615a78578283fd5b600060208284031215615c9a578081fd5b5035919050565b600060208284031215615cb2578081fd5b5051919050565b60008060408385031215615ccb578182fd5b82359150602083013561595c81615f18565b60008060408385031215615cef578182fd5b505080516020909101519092909150565b600080600060608486031215615d14578081fd5b505081359360208301359350604090920135919050565b6000815480845260208085019450838352808320835b83811015615d665781546001600160a01b031687529582019560019182019101615d41565b509495945050505050565b604080825283519082018190526000906020906060840190828701845b82811015615db55781516001600160a01b0316845260208401935090840190600101615d8e565b50505083810382850152845180825285830191830190845b818110156158cc57835183529284019291840191600101615dcd565b6000858252846020830152836040830152608060608301526133a26080830184615d2b565b604051601f8201601f1916810167ffffffffffffffff81118282101715615e3757615e37615f02565b604052919050565b600067ffffffffffffffff821115615e5957615e59615f02565b5060051b60200190565b60008219821115615e7657615e76615eec565b500190565b600082615e9657634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615615eb557615eb5615eec565b500290565b600082821015615ecc57615ecc615eec565b500390565b6000600019821415615ee557615ee5615eec565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461584957600080fd5b801515811461584957600080fdfea26469706673582212207c310013677046eae3e75c3e7f504f30afb6e141a8904b63d61aef5af1678be964736f6c63430008030033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac000000000000000000000000000000000000000000000000000000000000000096e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845fe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c63030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c
-----Decoded View---------------
Arg [0] : _peg (address): 0xdAC17F958D2ee523a2206206994597C13D831ec7
Arg [1] : _amm1Factory (address): 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
Arg [2] : _amm2Factory (address): 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac
Arg [3] : _amm3Factory (address): 0x0000000000000000000000000000000000000000
Arg [4] : _amm1InitHash (bytes32): 0x96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f
Arg [5] : _amm2InitHash (bytes32): 0xe18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303
Arg [6] : _amm3InitHash (bytes32): 0x0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : _roles (address): 0xC6D13A49cdC5Afc7798dd0eBA7698DB9BFCc1D8c
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [1] : 0000000000000000000000005c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f
Arg [2] : 000000000000000000000000c0aee478e3658e2610c5f7a4a2e1777ce9e4f2ac
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f
Arg [5] : e18a34eb0e04b04f7a0ac29a6e80748dca96319b42c54d679cb821dca90c6303
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 000000000000000000000000c6d13a49cdc5afc7798dd0eba7698db9bfcc1d8c
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.