Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
FLMaker
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2022-02-14 */ // SPDX-License-Identifier: MIT pragma solidity =0.8.10; pragma experimental ABIEncoderV2; abstract contract IDFSRegistry { function getAddr(bytes4 _id) public view virtual returns (address); function addNewContract( bytes32 _id, address _contractAddr, uint256 _waitPeriod ) public virtual; function startContractChange(bytes32 _id, address _newContractAddr) public virtual; function approveContractChange(bytes32 _id) public virtual; function cancelContractChange(bytes32 _id) public virtual; function changeWaitPeriod(bytes32 _id, uint256 _newWaitPeriod) public virtual; } interface IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint256 digits); function totalSupply() external view returns (uint256 supply); function balanceOf(address _owner) external view returns (uint256 balance); function transfer(address _to, uint256 _value) external returns (bool success); function transferFrom( address _from, address _to, uint256 _value ) external returns (bool success); function approve(address _spender, uint256 _value) external returns (bool success); function allowance(address _owner, address _spender) external view returns (uint256 remaining); event Approval(address indexed _owner, address indexed _spender, uint256 _value); } library Address { //insufficient balance error InsufficientBalance(uint256 available, uint256 required); //unable to send value, recipient may have reverted error SendingValueFail(); //insufficient balance for call error InsufficientBalanceForCall(uint256 available, uint256 required); //call to non-contract error NonContractCall(); function isContract(address account) internal view returns (bool) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } function sendValue(address payable recipient, uint256 amount) internal { uint256 balance = address(this).balance; if (balance < amount){ revert InsufficientBalance(balance, amount); } // solhint-disable-next-line avoid-low-level-calls, avoid-call-value (bool success, ) = recipient.call{value: amount}(""); if (!(success)){ revert SendingValueFail(); } } function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, errorMessage); } 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"); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { uint256 balance = address(this).balance; if (balance < value){ revert InsufficientBalanceForCall(balance, value); } return _functionCallWithValue(target, data, value, errorMessage); } function _functionCallWithValue( address target, bytes memory data, uint256 weiValue, string memory errorMessage ) private returns (bytes memory) { if (!(isContract(target))){ revert NonContractCall(); } // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = target.call{value: weiValue}(data); if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly // solhint-disable-next-line no-inline-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } } library SafeMath { function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn( token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value) ); } /// @dev Edited so it always first approves 0 and then the value, because of non standard tokens function safeApprove( IERC20 token, address spender, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0)); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender).add(value); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance) ); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender).sub( value, "SafeERC20: decreased allowance below zero" ); _callOptionalReturn( token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance) ); } function _callOptionalReturn(IERC20 token, bytes memory data) private { 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"); } } } contract MainnetAuthAddresses { address internal constant ADMIN_VAULT_ADDR = 0xCCf3d848e08b94478Ed8f46fFead3008faF581fD; address internal constant FACTORY_ADDRESS = 0x5a15566417e6C1c9546523066500bDDBc53F88C7; address internal constant ADMIN_ADDR = 0x25eFA336886C74eA8E282ac466BdCd0199f85BB9; // USED IN ADMIN VAULT CONSTRUCTOR } contract AuthHelper is MainnetAuthAddresses { } contract AdminVault is AuthHelper { address public owner; address public admin; error SenderNotAdmin(); constructor() { owner = msg.sender; admin = ADMIN_ADDR; } /// @notice Admin is able to change owner /// @param _owner Address of new owner function changeOwner(address _owner) public { if (admin != msg.sender){ revert SenderNotAdmin(); } owner = _owner; } /// @notice Admin is able to set new admin /// @param _admin Address of multisig that becomes new admin function changeAdmin(address _admin) public { if (admin != msg.sender){ revert SenderNotAdmin(); } admin = _admin; } } contract AdminAuth is AuthHelper { using SafeERC20 for IERC20; AdminVault public constant adminVault = AdminVault(ADMIN_VAULT_ADDR); error SenderNotOwner(); error SenderNotAdmin(); modifier onlyOwner() { if (adminVault.owner() != msg.sender){ revert SenderNotOwner(); } _; } modifier onlyAdmin() { if (adminVault.admin() != msg.sender){ revert SenderNotAdmin(); } _; } /// @notice withdraw stuck funds function withdrawStuckFunds(address _token, address _receiver, uint256 _amount) public onlyOwner { if (_token == 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) { payable(_receiver).transfer(_amount); } else { IERC20(_token).safeTransfer(_receiver, _amount); } } /// @notice Destroy the contract function kill() public onlyAdmin { selfdestruct(payable(msg.sender)); } } contract DFSRegistry is AdminAuth { error EntryAlreadyExistsError(bytes4); error EntryNonExistentError(bytes4); error EntryNotInChangeError(bytes4); error ChangeNotReadyError(uint256,uint256); error EmptyPrevAddrError(bytes4); error AlreadyInContractChangeError(bytes4); error AlreadyInWaitPeriodChangeError(bytes4); event AddNewContract(address,bytes4,address,uint256); event RevertToPreviousAddress(address,bytes4,address,address); event StartContractChange(address,bytes4,address,address); event ApproveContractChange(address,bytes4,address,address); event CancelContractChange(address,bytes4,address,address); event StartWaitPeriodChange(address,bytes4,uint256); event ApproveWaitPeriodChange(address,bytes4,uint256,uint256); event CancelWaitPeriodChange(address,bytes4,uint256,uint256); struct Entry { address contractAddr; uint256 waitPeriod; uint256 changeStartTime; bool inContractChange; bool inWaitPeriodChange; bool exists; } mapping(bytes4 => Entry) public entries; mapping(bytes4 => address) public previousAddresses; mapping(bytes4 => address) public pendingAddresses; mapping(bytes4 => uint256) public pendingWaitTimes; /// @notice Given an contract id returns the registered address /// @dev Id is keccak256 of the contract name /// @param _id Id of contract function getAddr(bytes4 _id) public view returns (address) { return entries[_id].contractAddr; } /// @notice Helper function to easily query if id is registered /// @param _id Id of contract function isRegistered(bytes4 _id) public view returns (bool) { return entries[_id].exists; } /////////////////////////// OWNER ONLY FUNCTIONS /////////////////////////// /// @notice Adds a new contract to the registry /// @param _id Id of contract /// @param _contractAddr Address of the contract /// @param _waitPeriod Amount of time to wait before a contract address can be changed function addNewContract( bytes4 _id, address _contractAddr, uint256 _waitPeriod ) public onlyOwner { if (entries[_id].exists){ revert EntryAlreadyExistsError(_id); } entries[_id] = Entry({ contractAddr: _contractAddr, waitPeriod: _waitPeriod, changeStartTime: 0, inContractChange: false, inWaitPeriodChange: false, exists: true }); emit AddNewContract(msg.sender, _id, _contractAddr, _waitPeriod); } /// @notice Reverts to the previous address immediately /// @dev In case the new version has a fault, a quick way to fallback to the old contract /// @param _id Id of contract function revertToPreviousAddress(bytes4 _id) public onlyOwner { if (!(entries[_id].exists)){ revert EntryNonExistentError(_id); } if (previousAddresses[_id] == address(0)){ revert EmptyPrevAddrError(_id); } address currentAddr = entries[_id].contractAddr; entries[_id].contractAddr = previousAddresses[_id]; emit RevertToPreviousAddress(msg.sender, _id, currentAddr, previousAddresses[_id]); } /// @notice Starts an address change for an existing entry /// @dev Can override a change that is currently in progress /// @param _id Id of contract /// @param _newContractAddr Address of the new contract function startContractChange(bytes4 _id, address _newContractAddr) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (entries[_id].inWaitPeriodChange){ revert AlreadyInWaitPeriodChangeError(_id); } entries[_id].changeStartTime = block.timestamp; // solhint-disable-line entries[_id].inContractChange = true; pendingAddresses[_id] = _newContractAddr; emit StartContractChange(msg.sender, _id, entries[_id].contractAddr, _newContractAddr); } /// @notice Changes new contract address, correct time must have passed /// @param _id Id of contract function approveContractChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inContractChange){ revert EntryNotInChangeError(_id); } if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){// solhint-disable-line revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod)); } address oldContractAddr = entries[_id].contractAddr; entries[_id].contractAddr = pendingAddresses[_id]; entries[_id].inContractChange = false; entries[_id].changeStartTime = 0; pendingAddresses[_id] = address(0); previousAddresses[_id] = oldContractAddr; emit ApproveContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr); } /// @notice Cancel pending change /// @param _id Id of contract function cancelContractChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inContractChange){ revert EntryNotInChangeError(_id); } address oldContractAddr = pendingAddresses[_id]; pendingAddresses[_id] = address(0); entries[_id].inContractChange = false; entries[_id].changeStartTime = 0; emit CancelContractChange(msg.sender, _id, oldContractAddr, entries[_id].contractAddr); } /// @notice Starts the change for waitPeriod /// @param _id Id of contract /// @param _newWaitPeriod New wait time function startWaitPeriodChange(bytes4 _id, uint256 _newWaitPeriod) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (entries[_id].inContractChange){ revert AlreadyInContractChangeError(_id); } pendingWaitTimes[_id] = _newWaitPeriod; entries[_id].changeStartTime = block.timestamp; // solhint-disable-line entries[_id].inWaitPeriodChange = true; emit StartWaitPeriodChange(msg.sender, _id, _newWaitPeriod); } /// @notice Changes new wait period, correct time must have passed /// @param _id Id of contract function approveWaitPeriodChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inWaitPeriodChange){ revert EntryNotInChangeError(_id); } if (block.timestamp < (entries[_id].changeStartTime + entries[_id].waitPeriod)){ // solhint-disable-line revert ChangeNotReadyError(block.timestamp, (entries[_id].changeStartTime + entries[_id].waitPeriod)); } uint256 oldWaitTime = entries[_id].waitPeriod; entries[_id].waitPeriod = pendingWaitTimes[_id]; entries[_id].inWaitPeriodChange = false; entries[_id].changeStartTime = 0; pendingWaitTimes[_id] = 0; emit ApproveWaitPeriodChange(msg.sender, _id, oldWaitTime, entries[_id].waitPeriod); } /// @notice Cancel wait period change /// @param _id Id of contract function cancelWaitPeriodChange(bytes4 _id) public onlyOwner { if (!entries[_id].exists){ revert EntryNonExistentError(_id); } if (!entries[_id].inWaitPeriodChange){ revert EntryNotInChangeError(_id); } uint256 oldWaitPeriod = pendingWaitTimes[_id]; pendingWaitTimes[_id] = 0; entries[_id].inWaitPeriodChange = false; entries[_id].changeStartTime = 0; emit CancelWaitPeriodChange(msg.sender, _id, oldWaitPeriod, entries[_id].waitPeriod); } } abstract contract DSAuthority { function canCall( address src, address dst, bytes4 sig ) public view virtual returns (bool); } contract DSAuthEvents { event LogSetAuthority(address indexed authority); event LogSetOwner(address indexed owner); } contract DSAuth is DSAuthEvents { DSAuthority public authority; address public owner; constructor() { owner = msg.sender; emit LogSetOwner(msg.sender); } function setOwner(address owner_) public auth { owner = owner_; emit LogSetOwner(owner); } function setAuthority(DSAuthority authority_) public auth { authority = authority_; emit LogSetAuthority(address(authority)); } modifier auth { require(isAuthorized(msg.sender, msg.sig), "Not authorized"); _; } function isAuthorized(address src, bytes4 sig) internal view returns (bool) { if (src == address(this)) { return true; } else if (src == owner) { return true; } else if (authority == DSAuthority(address(0))) { return false; } else { return authority.canCall(src, address(this), sig); } } } contract DSNote { event LogNote( bytes4 indexed sig, address indexed guy, bytes32 indexed foo, bytes32 indexed bar, uint256 wad, bytes fax ) anonymous; modifier note { bytes32 foo; bytes32 bar; assembly { foo := calldataload(4) bar := calldataload(36) } emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data); _; } } abstract contract DSProxy is DSAuth, DSNote { DSProxyCache public cache; // global cache for contracts constructor(address _cacheAddr) { if (!(setCache(_cacheAddr))){ require(isAuthorized(msg.sender, msg.sig), "Not authorized"); } } // solhint-disable-next-line no-empty-blocks receive() external payable {} // use the proxy to execute calldata _data on contract _code function execute(bytes memory _code, bytes memory _data) public payable virtual returns (address target, bytes32 response); function execute(address _target, bytes memory _data) public payable virtual returns (bytes32 response); //set new cache function setCache(address _cacheAddr) public payable virtual returns (bool); } contract DSProxyCache { mapping(bytes32 => address) cache; function read(bytes memory _code) public view returns (address) { bytes32 hash = keccak256(_code); return cache[hash]; } function write(bytes memory _code) public returns (address target) { assembly { target := create(0, add(_code, 0x20), mload(_code)) switch iszero(extcodesize(target)) case 1 { // throw if contract failed to deploy revert(0, 0) } } bytes32 hash = keccak256(_code); cache[hash] = target; } } contract DefisaverLogger { event RecipeEvent( address indexed caller, string indexed logName ); event ActionDirectEvent( address indexed caller, string indexed logName, bytes data ); function logRecipeEvent( string memory _logName ) public { emit RecipeEvent(msg.sender, _logName); } function logActionDirectEvent( string memory _logName, bytes memory _data ) public { emit ActionDirectEvent(msg.sender, _logName, _data); } } contract MainnetActionsUtilAddresses { address internal constant DFS_REG_CONTROLLER_ADDR = 0xF8f8B3C98Cf2E63Df3041b73f80F362a4cf3A576; address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b; address internal constant DFS_LOGGER_ADDR = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3; } contract ActionsUtilHelper is MainnetActionsUtilAddresses { } abstract contract ActionBase is AdminAuth, ActionsUtilHelper { event ActionEvent( string indexed logName, bytes data ); DFSRegistry public constant registry = DFSRegistry(REGISTRY_ADDR); DefisaverLogger public constant logger = DefisaverLogger( DFS_LOGGER_ADDR ); //Wrong sub index value error SubIndexValueError(); //Wrong return index value error ReturnIndexValueError(); /// @dev Subscription params index range [128, 255] uint8 public constant SUB_MIN_INDEX_VALUE = 128; uint8 public constant SUB_MAX_INDEX_VALUE = 255; /// @dev Return params index range [1, 127] uint8 public constant RETURN_MIN_INDEX_VALUE = 1; uint8 public constant RETURN_MAX_INDEX_VALUE = 127; /// @dev If the input value should not be replaced uint8 public constant NO_PARAM_MAPPING = 0; /// @dev We need to parse Flash loan actions in a different way enum ActionType { FL_ACTION, STANDARD_ACTION, FEE_ACTION, CHECK_ACTION, CUSTOM_ACTION } /// @notice Parses inputs and runs the implemented action through a proxy /// @dev Is called by the RecipeExecutor chaining actions together /// @param _callData Array of input values each value encoded as bytes /// @param _subData Array of subscribed vales, replaces input values if specified /// @param _paramMapping Array that specifies how return and subscribed values are mapped in input /// @param _returnValues Returns values from actions before, which can be injected in inputs /// @return Returns a bytes32 value through DSProxy, each actions implements what that value is function executeAction( bytes memory _callData, bytes32[] memory _subData, uint8[] memory _paramMapping, bytes32[] memory _returnValues ) public payable virtual returns (bytes32); /// @notice Parses inputs and runs the single implemented action through a proxy /// @dev Used to save gas when executing a single action directly function executeActionDirect(bytes memory _callData) public virtual payable; /// @notice Returns the type of action we are implementing function actionType() public pure virtual returns (uint8); //////////////////////////// HELPER METHODS //////////////////////////// /// @notice Given an uint256 input, injects return/sub values if specified /// @param _param The original input value /// @param _mapType Indicated the type of the input in paramMapping /// @param _subData Array of subscription data we can replace the input value with /// @param _returnValues Array of subscription data we can replace the input value with function _parseParamUint( uint _param, uint8 _mapType, bytes32[] memory _subData, bytes32[] memory _returnValues ) internal pure returns (uint) { if (isReplaceable(_mapType)) { if (isReturnInjection(_mapType)) { _param = uint(_returnValues[getReturnIndex(_mapType)]); } else { _param = uint256(_subData[getSubIndex(_mapType)]); } } return _param; } /// @notice Given an addr input, injects return/sub values if specified /// @param _param The original input value /// @param _mapType Indicated the type of the input in paramMapping /// @param _subData Array of subscription data we can replace the input value with /// @param _returnValues Array of subscription data we can replace the input value with function _parseParamAddr( address _param, uint8 _mapType, bytes32[] memory _subData, bytes32[] memory _returnValues ) internal view returns (address) { if (isReplaceable(_mapType)) { if (isReturnInjection(_mapType)) { _param = address(bytes20((_returnValues[getReturnIndex(_mapType)]))); } else { /// @dev The last two values are specially reserved for proxy addr and owner addr if (_mapType == 254) return address(this); //DSProxy address if (_mapType == 255) return DSProxy(payable(address(this))).owner(); // owner of DSProxy _param = address(uint160(uint256(_subData[getSubIndex(_mapType)]))); } } return _param; } /// @notice Given an bytes32 input, injects return/sub values if specified /// @param _param The original input value /// @param _mapType Indicated the type of the input in paramMapping /// @param _subData Array of subscription data we can replace the input value with /// @param _returnValues Array of subscription data we can replace the input value with function _parseParamABytes32( bytes32 _param, uint8 _mapType, bytes32[] memory _subData, bytes32[] memory _returnValues ) internal pure returns (bytes32) { if (isReplaceable(_mapType)) { if (isReturnInjection(_mapType)) { _param = (_returnValues[getReturnIndex(_mapType)]); } else { _param = _subData[getSubIndex(_mapType)]; } } return _param; } /// @notice Checks if the paramMapping value indicated that we need to inject values /// @param _type Indicated the type of the input function isReplaceable(uint8 _type) internal pure returns (bool) { return _type != NO_PARAM_MAPPING; } /// @notice Checks if the paramMapping value is in the return value range /// @param _type Indicated the type of the input function isReturnInjection(uint8 _type) internal pure returns (bool) { return (_type >= RETURN_MIN_INDEX_VALUE) && (_type <= RETURN_MAX_INDEX_VALUE); } /// @notice Transforms the paramMapping value to the index in return array value /// @param _type Indicated the type of the input function getReturnIndex(uint8 _type) internal pure returns (uint8) { if (!(isReturnInjection(_type))){ revert SubIndexValueError(); } return (_type - RETURN_MIN_INDEX_VALUE); } /// @notice Transforms the paramMapping value to the index in sub array value /// @param _type Indicated the type of the input function getSubIndex(uint8 _type) internal pure returns (uint8) { if (_type < SUB_MIN_INDEX_VALUE){ revert ReturnIndexValueError(); } return (_type - SUB_MIN_INDEX_VALUE); } } abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; error ReentrantCall(); constructor () { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and make it call a * `private` function that does the actual work. */ modifier nonReentrant() { // On the first call to nonReentrant, _notEntered will be true if (_status == _ENTERED){ revert ReentrantCall(); } // Any calls to nonReentrant after this point will fail _status = _ENTERED; _; // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } interface IERC3156FlashBorrower { /** * @dev Receive a flash loan. * @param initiator The initiator of the loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @param fee The additional amount of tokens to repay. * @param data Arbitrary data structure, intended to contain user-defined parameters. * @return The keccak256 hash of "ERC3156FlashBorrower.onFlashLoan" */ function onFlashLoan( address initiator, address token, uint256 amount, uint256 fee, bytes calldata data ) external returns (bytes32); } interface IERC3156FlashLender { /** * @dev The amount of currency available to be lent. * @param token The loan currency. * @return The amount of `token` that can be borrowed. */ function maxFlashLoan( address token ) external view returns (uint256); /** * @dev The fee to be charged for a given loan. * @param token The loan currency. * @param amount The amount of tokens lent. * @return The amount of `token` to be charged for the loan, on top of the returned principal. */ function flashFee( address token, uint256 amount ) external view returns (uint256); /** * @dev Initiate a flash loan. * @param receiver The receiver of the tokens in the loan, and the receiver of the callback. * @param token The loan currency. * @param amount The amount of tokens lent. * @param data Arbitrary data structure, intended to contain user-defined parameters. */ function flashLoan( IERC3156FlashBorrower receiver, address token, uint256 amount, bytes calldata data ) external returns (bool); } abstract contract IFlashLoanBase{ struct FlashLoanParams { address[] tokens; uint256[] amounts; uint256[] modes; address onBehalfOf; address flParamGetterAddr; bytes flParamGetterData; bytes recipeData; } } contract StrategyModel { bytes4 constant STRATEGY_STORAGE_ID = bytes4(keccak256("StrategyStorage")); bytes4 constant SUB_STORAGE_ID = bytes4(keccak256("SubStorage")); bytes4 constant BUNDLE_STORAGE_ID = bytes4(keccak256("BundleStorage")); /// @dev Group of strategies bundled together so user can sub to multiple strategies at once /// @param creator Address of the user who created the bundle /// @param strategyIds Array of strategy ids stored in StrategyStorage struct StrategyBundle { address creator; uint64[] strategyIds; } /// @dev Template/Class which defines a Strategy /// @param name Name of the strategy useful for logging what strategy is executing /// @param creator Address of the user which created the strategy /// @param triggerIds Array of identifiers for trigger - bytes4(keccak256(TriggerName)) /// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName)) /// @param paramMapping Describes how inputs to functions are piped from return/subbed values /// @param continuous If the action is repeated (continuos) or one time struct Strategy { string name; address creator; bytes4[] triggerIds; bytes4[] actionIds; uint8[][] paramMapping; bool continuous; } /// @dev List of actions grouped as a recipe /// @param name Name of the recipe useful for logging what recipe is executing /// @param callData Array of calldata inputs to each action /// @param subData Used only as part of strategy, subData injected from StrategySub.subData /// @param actionIds Array of identifiers for actions - bytes4(keccak256(ActionName)) /// @param paramMapping Describes how inputs to functions are piped from return/subbed values struct Recipe { string name; bytes[] callData; bytes32[] subData; bytes4[] actionIds; uint8[][] paramMapping; } /// @dev Actual data of the sub we store on-chain /// @dev In order to save on gas we store a keccak256(StrategySub) and verify later on /// @param userProxy Address of the users smart wallet/proxy /// @param isEnabled Toggle if the subscription is active /// @param strategySubHash Hash of the StrategySub data the user inputted struct StoredSubData { bytes20 userProxy; // address but put in bytes20 for gas savings bool isEnabled; bytes32 strategySubHash; } /// @dev Instance of a strategy, user supplied data /// @param strategyOrBundleId Id of the strategy or bundle, depending on the isBundle bool /// @param isBundle If true the id points to bundle, if false points directly to strategyId /// @param triggerData User supplied data needed for checking trigger conditions /// @param subData User supplied data used in recipe struct StrategySub { uint64 strategyOrBundleId; bool isBundle; bytes[] triggerData; bytes32[] subData; } } abstract contract IDSProxy { // function execute(bytes memory _code, bytes memory _data) // public // payable // virtual // returns (address, bytes32); function execute(address _target, bytes memory _data) public payable virtual returns (bytes32); function setCache(address _cacheAddr) public payable virtual returns (bool); function owner() public view virtual returns (address); } abstract contract IFLParamGetter { function getFlashLoanParams(bytes memory _data) public view virtual returns ( address[] memory tokens, uint256[] memory amount, uint256[] memory modes ); } abstract contract IWETH { function allowance(address, address) public virtual view returns (uint256); function balanceOf(address) public virtual view returns (uint256); function approve(address, uint256) public virtual; function transfer(address, uint256) public virtual returns (bool); function transferFrom( address, address, uint256 ) public virtual returns (bool); function deposit() public payable virtual; function withdraw(uint256) public virtual; } library TokenUtils { using SafeERC20 for IERC20; address public constant WETH_ADDR = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address public constant ETH_ADDR = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; function approveToken( address _tokenAddr, address _to, uint256 _amount ) internal { if (_tokenAddr == ETH_ADDR) return; if (IERC20(_tokenAddr).allowance(address(this), _to) < _amount) { IERC20(_tokenAddr).safeApprove(_to, _amount); } } function pullTokensIfNeeded( address _token, address _from, uint256 _amount ) internal returns (uint256) { // handle max uint amount if (_amount == type(uint256).max) { _amount = getBalance(_token, _from); } if (_from != address(0) && _from != address(this) && _token != ETH_ADDR && _amount != 0) { IERC20(_token).safeTransferFrom(_from, address(this), _amount); } return _amount; } function withdrawTokens( address _token, address _to, uint256 _amount ) internal returns (uint256) { if (_amount == type(uint256).max) { _amount = getBalance(_token, address(this)); } if (_to != address(0) && _to != address(this) && _amount != 0) { if (_token != ETH_ADDR) { IERC20(_token).safeTransfer(_to, _amount); } else { payable(_to).transfer(_amount); } } return _amount; } function depositWeth(uint256 _amount) internal { IWETH(WETH_ADDR).deposit{value: _amount}(); } function withdrawWeth(uint256 _amount) internal { IWETH(WETH_ADDR).withdraw(_amount); } function getBalance(address _tokenAddr, address _acc) internal view returns (uint256) { if (_tokenAddr == ETH_ADDR) { return _acc.balance; } else { return IERC20(_tokenAddr).balanceOf(_acc); } } function getTokenDecimals(address _token) internal view returns (uint256) { if (_token == ETH_ADDR) return 18; return IERC20(_token).decimals(); } } contract MainnetFLAddresses { address internal constant SOLO_MARGIN_ADDRESS = 0x1E0447b19BB6EcFdAe1e4AE1694b0C3659614e4e; address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address internal constant WETH_ADDRESS = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address internal constant DYDX_FL_FEE_FAUCET = 0x47f159C90850D5cE09E21F931d504536840f34b4; address internal constant AAVE_LENDING_POOL = 0x7d2768dE32b0b80b7a3454c06BdAc94A69DDc7A9; address internal constant AAVE_LENDING_POOL_ADDRESS_PROVIDER = 0xB53C1a33016B2DC2fF3653530bfF1848a515c8c5; address internal constant DSS_FLASH_ADDR = 0x1EB4CF3A948E7D72A198fe073cCb8C7a948cD853; address internal constant DAI_ADDR = 0x6B175474E89094C44Da98b954EedeAC495271d0F; } contract FLHelper is MainnetFLAddresses { } contract FLMaker is ActionBase, ReentrancyGuard, IERC3156FlashBorrower, IFlashLoanBase, StrategyModel, FLHelper { using TokenUtils for address; using SafeMath for uint256; /// @dev Function sig of RecipeExecutor._executeActionsFromFL() bytes4 public constant CALLBACK_SELECTOR = bytes4(keccak256("_executeActionsFromFL((string,bytes[],bytes32[],bytes4[],uint8[][]),bytes32)")); bytes32 constant RECIPE_EXECUTOR_ID = keccak256("RecipeExecutor"); bytes32 public constant CALLBACK_SUCCESS = keccak256("ERC3156FlashBorrower.onFlashLoan"); function executeAction( bytes memory _callData, bytes32[] memory, uint8[] memory, bytes32[] memory ) public override payable returns (bytes32) { FlashLoanParams memory params = parseInputs(_callData); if (params.flParamGetterAddr != address(0)) { (, uint256[] memory amounts,) = IFLParamGetter(params.flParamGetterAddr).getFlashLoanParams(params.flParamGetterData); params.amounts[0] = amounts[0]; } bytes memory recipeData = params.recipeData; uint256 amount = _flMaker(params.amounts[0], recipeData); return bytes32(amount); } // solhint-disable-next-line no-empty-blocks function executeActionDirect(bytes memory _callData) public override payable {} /// @inheritdoc ActionBase function actionType() public override pure returns (uint8) { return uint8(ActionType.FL_ACTION); } /// @notice Gets a DAI flash loan from Maker and returns back the execution to the action address /// @param _amount Amount of DAI to FL /// @param _taskData Rest of the data we have in the task function _flMaker(uint256 _amount, bytes memory _taskData) internal returns (uint256) { IERC3156FlashLender(DSS_FLASH_ADDR).flashLoan( IERC3156FlashBorrower(address(this)), DAI_ADDR, _amount, _taskData ); emit ActionEvent("FLMaker", abi.encode(_amount)); return _amount; } /// @notice ERC3156 callback function that formats and calls back TaskExecutor function onFlashLoan( address _initiator, address _token, uint256 _amount, uint256 _fee, bytes calldata _data ) external override nonReentrant returns (bytes32) { require(msg.sender == address(DSS_FLASH_ADDR), "Untrusted lender"); require(_initiator == address(this), "Untrusted loan initiator"); (Recipe memory currRecipe, address proxy) = abi.decode(_data, (Recipe, address)); _token.withdrawTokens(proxy, _amount); address payable recipeExecutorAddr = payable(registry.getAddr(bytes4(RECIPE_EXECUTOR_ID))); uint256 paybackAmount = _amount.add(_fee); // call Action execution IDSProxy(proxy).execute{value: address(this).balance}( recipeExecutorAddr, abi.encodeWithSelector(CALLBACK_SELECTOR, currRecipe, paybackAmount) ); require(_token.getBalance(address(this)) == paybackAmount, "Wrong payback amount"); _token.approveToken(DSS_FLASH_ADDR, paybackAmount); return CALLBACK_SUCCESS; } function parseInputs(bytes memory _callData) public pure returns (FlashLoanParams memory params) { params = abi.decode(_callData, (FlashLoanParams)); } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"NonContractCall","type":"error"},{"inputs":[],"name":"ReentrantCall","type":"error"},{"inputs":[],"name":"ReturnIndexValueError","type":"error"},{"inputs":[],"name":"SenderNotAdmin","type":"error"},{"inputs":[],"name":"SenderNotOwner","type":"error"},{"inputs":[],"name":"SubIndexValueError","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"logName","type":"string"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"ActionEvent","type":"event"},{"inputs":[],"name":"CALLBACK_SELECTOR","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_PARAM_MAPPING","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RETURN_MAX_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RETURN_MIN_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUB_MAX_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUB_MIN_INDEX_VALUE","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"actionType","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"adminVault","outputs":[{"internalType":"contract AdminVault","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_callData","type":"bytes"},{"internalType":"bytes32[]","name":"","type":"bytes32[]"},{"internalType":"uint8[]","name":"","type":"uint8[]"},{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"name":"executeAction","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_callData","type":"bytes"}],"name":"executeActionDirect","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"logger","outputs":[{"internalType":"contract DefisaverLogger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_initiator","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"_callData","type":"bytes"}],"name":"parseInputs","outputs":[{"components":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"uint256[]","name":"modes","type":"uint256[]"},{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"address","name":"flParamGetterAddr","type":"address"},{"internalType":"bytes","name":"flParamGetterData","type":"bytes"},{"internalType":"bytes","name":"recipeData","type":"bytes"}],"internalType":"struct IFlashLoanBase.FlashLoanParams","name":"params","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"registry","outputs":[{"internalType":"contract DFSRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawStuckFunds","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506001600055612322806100256000396000f3fe60806040526004361061010e5760003560e01c80638bcb6216116100a55780639864dcdd11610074578063c579d49011610059578063c579d49014610336578063d3c2e7ed14610356578063f24ccbfe1461036b57600080fd5b80639864dcdd146102bc5780639ce3e919146102d157600080fd5b80638bcb62161461023f5780638cedca71146102545780638df50f741461027c5780639093410d1461028f57600080fd5b8063389f87ff116100e1578063389f87ff1461019657806341c0e1b5146101a95780637b103999146101be5780638237e5381461020b57600080fd5b80630f2eee421461011357806323e30c8b1461013f578063247492f81461016d5780632fa13cb814610181575b600080fd5b34801561011f57600080fd5b50610128608081565b60405160ff90911681526020015b60405180910390f35b34801561014b57600080fd5b5061015f61015a3660046114b1565b610393565b604051908152602001610136565b34801561017957600080fd5b506000610128565b34801561018d57600080fd5b50610128600081565b6101a76101a4366004611685565b50565b005b3480156101b557600080fd5b506101a76107c8565b3480156101ca57600080fd5b506101e673287778f121f134c66212fb16c9b53ec991d32f5b81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610136565b34801561021757600080fd5b5061015f7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b34801561024b57600080fd5b50610128600181565b34801561026057600080fd5b506101e673ccf3d848e08b94478ed8f46ffead3008faf581fd81565b61015f61028a3660046117af565b6108b2565b34801561029b57600080fd5b506102af6102aa366004611685565b610a08565b60405161013691906118ef565b3480156102c857600080fd5b50610128607f81565b3480156102dd57600080fd5b506103057ff890814b417745d791c9230c2f130c9c0a442917386da77dda5dc34b2a22b9b881565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610136565b34801561034257600080fd5b506101a7610351366004611a15565b610a8e565b34801561036257600080fd5b5061012860ff81565b34801561037757600080fd5b506101e673ce7a977cac4a481bc84ac06b2da0df614e621cf381565b6000600260005414156103d2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260005533731eb4cf3a948e7d72a198fe073ccb8c7a948cd85314610459576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f556e74727573746564206c656e6465720000000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff871630146104d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e74727573746564206c6f616e20696e69746961746f7200000000000000006044820152606401610450565b6000806104e784860186611bf0565b909250905061050d73ffffffffffffffffffffffffffffffffffffffff89168289610c16565b506040517f93b188540000000000000000000000000000000000000000000000000000000081527f4c69ee1e00000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa158015610599573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bd9190611d0a565b905060006105cb8989610d3b565b90508273ffffffffffffffffffffffffffffffffffffffff16631cff79cd47847ff890814b417745d791c9230c2f130c9c0a442917386da77dda5dc34b2a22b9b8888660405160240161061f929190611df8565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b90921682526106929291600401611efb565b60206040518083038185885af11580156106b0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906106d59190611f2a565b50806106f773ffffffffffffffffffffffffffffffffffffffff8c1630610dbb565b1461075e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796261636b20616d6f756e740000000000000000000000006044820152606401610450565b61079373ffffffffffffffffffffffffffffffffffffffff8b16731eb4cf3a948e7d72a198fe073ccb8c7a948cd85383610ea4565b50506001600055507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd998975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108629190611d0a565b73ffffffffffffffffffffffffffffffffffffffff16146108af576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6000806108be86610a08565b608081015190915073ffffffffffffffffffffffffffffffffffffffff16156109c757608081015160a08201516040517f0ae1cc8e00000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff1691630ae1cc8e9161093e9190600401611f43565b600060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109839190810190612015565b509150508060008151811061099a5761099a61209d565b602002602001015182602001516000815181106109b9576109b961209d565b602002602001018181525050505b60008160c00151905060006109fa83602001516000815181106109ec576109ec61209d565b602002602001015183610f9b565b93505050505b949350505050565b610a746040518060e00160405280606081526020016060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b81806020019051810190610a889190612111565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b289190611d0a565b73ffffffffffffffffffffffffffffffffffffffff1614610b75576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610bf05760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610bea573d6000803e3d6000fd5b50505050565b610c1173ffffffffffffffffffffffffffffffffffffffff841683836110da565b505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610c4d57610c4a8430610dbb565b91505b73ffffffffffffffffffffffffffffffffffffffff831615801590610c88575073ffffffffffffffffffffffffffffffffffffffff83163014155b8015610c9357508115155b15610d345773ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610cef57610cea73ffffffffffffffffffffffffffffffffffffffff851684846110da565b610d34565b60405173ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f19350505050158015610d32573d6000803e3d6000fd5b505b5092915050565b600080610d488385612230565b905083811015610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610450565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610e0d575073ffffffffffffffffffffffffffffffffffffffff811631610a88565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190611f2a565b9050610a88565b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610edb57505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610f50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f749190611f2a565b1015610c1157610c1173ffffffffffffffffffffffffffffffffffffffff84168383611190565b6040517f5cffe9de000000000000000000000000000000000000000000000000000000008152600090731eb4cf3a948e7d72a198fe073ccb8c7a948cd85390635cffe9de90611008903090736b175474e89094c44da98b954eedeac495271d0f908890889060040161226f565b6020604051808303816000875af1158015611027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104b91906122ae565b506040517f464c4d616b657200000000000000000000000000000000000000000000000000815260070160405180910390207f2b6d22f419271bcc89bbac8deec947c664365d6e24d06fef0ca7c325c704dce3846040516020016110b191815260200190565b60408051601f19818403018152908290526110cb91611f43565b60405180910390a25090919050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610c119084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261123c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152600060448201526111e69084907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161112c565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610c119084907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161112c565b600061129e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166113489092919063ffffffff16565b805190915015610c1157808060200190518101906112bc91906122ae565b610c11576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610450565b6060610a008484600085606061135d85611456565b611393576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113bc91906122d0565b60006040518083038185875af1925050503d80600081146113f9576040519150601f19603f3d011682016040523d82523d6000602084013e6113fe565b606091505b50915091508115611412579150610a009050565b8051156114225780518082602001fd5b836040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104509190611f43565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610a00575050151592915050565b73ffffffffffffffffffffffffffffffffffffffff811681146101a457600080fd5b60008060008060008060a087890312156114ca57600080fd5b86356114d58161148f565b955060208701356114e58161148f565b94506040870135935060608701359250608087013567ffffffffffffffff8082111561151057600080fd5b818901915089601f83011261152457600080fd5b81358181111561153357600080fd5b8a602082850101111561154557600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115ad576115ad61155b565b60405290565b60405160e0810167ffffffffffffffff811182821017156115ad576115ad61155b565b604051601f8201601f1916810167ffffffffffffffff811182821017156115ff576115ff61155b565b604052919050565b600067ffffffffffffffff8211156116215761162161155b565b50601f01601f191660200190565b600082601f83011261164057600080fd5b813561165361164e82611607565b6115d6565b81815284602083860101111561166857600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561169757600080fd5b813567ffffffffffffffff8111156116ae57600080fd5b610a008482850161162f565b600067ffffffffffffffff8211156116d4576116d461155b565b5060051b60200190565b600082601f8301126116ef57600080fd5b813560206116ff61164e836116ba565b82815260059290921b8401810191818101908684111561171e57600080fd5b8286015b848110156117395780358352918301918301611722565b509695505050505050565b600082601f83011261175557600080fd5b8135602061176561164e836116ba565b82815260059290921b8401810191818101908684111561178457600080fd5b8286015b8481101561173957803560ff811681146117a25760008081fd5b8352918301918301611788565b600080600080608085870312156117c557600080fd5b843567ffffffffffffffff808211156117dd57600080fd5b6117e98883890161162f565b955060208701359150808211156117ff57600080fd5b61180b888389016116de565b9450604087013591508082111561182157600080fd5b61182d88838901611744565b9350606087013591508082111561184357600080fd5b50611850878288016116de565b91505092959194509250565b600081518084526020808501945080840160005b8381101561188c57815187529582019590820190600101611870565b509495945050505050565b60005b838110156118b257818101518382015260200161189a565b83811115610bea5750506000910152565b600081518084526118db816020860160208601611897565b601f01601f19169290920160200192915050565b6020808252825160e083830152805161010084018190526000929182019083906101208601905b8083101561194c57835173ffffffffffffffffffffffffffffffffffffffff168252928401926001929092019190840190611916565b50838701519350601f1992508286820301604087015261196c818561185c565b93505050604085015181858403016060860152611989838261185c565b92505060608501516119b3608086018273ffffffffffffffffffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a0850151818584030160c08601526119ef83826118c3565b92505060c0850151818584030160e0860152611a0b83826118c3565b9695505050505050565b600080600060608486031215611a2a57600080fd5b8335611a358161148f565b92506020840135611a458161148f565b929592945050506040919091013590565b600082601f830112611a6757600080fd5b81356020611a7761164e836116ba565b82815260059290921b84018101918181019086841115611a9657600080fd5b8286015b8481101561173957803567ffffffffffffffff811115611aba5760008081fd5b611ac88986838b010161162f565b845250918301918301611a9a565b600082601f830112611ae757600080fd5b81356020611af761164e836116ba565b82815260059290921b84018101918181019086841115611b1657600080fd5b8286015b848110156117395780357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b535760008081fd5b8352918301918301611b1a565b600082601f830112611b7157600080fd5b81356020611b8161164e836116ba565b82815260059290921b84018101918181019086841115611ba057600080fd5b8286015b8481101561173957803567ffffffffffffffff811115611bc45760008081fd5b611bd28986838b0101611744565b845250918301918301611ba4565b8035611beb8161148f565b919050565b60008060408385031215611c0357600080fd5b823567ffffffffffffffff80821115611c1b57600080fd5b9084019060a08287031215611c2f57600080fd5b611c3761158a565b823582811115611c4657600080fd5b611c528882860161162f565b825250602083013582811115611c6757600080fd5b611c7388828601611a56565b602083015250604083013582811115611c8b57600080fd5b611c97888286016116de565b604083015250606083013582811115611caf57600080fd5b611cbb88828601611ad6565b606083015250608083013582811115611cd357600080fd5b611cdf88828601611b60565b6080830152509350611cf691505060208401611be0565b90509250929050565b8051611beb8161148f565b600060208284031215611d1c57600080fd5b8151610db48161148f565b600081518084526020808501945080840160005b8381101561188c5781517fffffffff000000000000000000000000000000000000000000000000000000001687529582019590820190600101611d3b565b600081518084526020808501808196508360051b810191508286016000805b86811015611dea578385038a52825180518087529087019087870190845b81811015611dd557835160ff1683529289019291890191600101611db6565b50509a87019a95505091850191600101611d98565b509298975050505050505050565b604081526000835160a06040840152611e1460e08401826118c3565b90506020808601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0808685030160608701528382518086528486019150848160051b870101858501945060005b82811015611e9057601f19888303018452611e7e8287516118c3565b95870195938701939150600101611e62565b5060408b01519650838982030160808a0152611eac818861185c565b965050505060608801519150808685030160a0870152611ecc8483611d27565b935060808801519150808685030160c087015250611eea8382611d79565b935050848185015250509392505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a0060408301846118c3565b600060208284031215611f3c57600080fd5b5051919050565b602081526000610db460208301846118c3565b600082601f830112611f6757600080fd5b81516020611f7761164e836116ba565b82815260059290921b84018101918181019086841115611f9657600080fd5b8286015b84811015611739578051611fad8161148f565b8352918301918301611f9a565b600082601f830112611fcb57600080fd5b81516020611fdb61164e836116ba565b82815260059290921b84018101918181019086841115611ffa57600080fd5b8286015b848110156117395780518352918301918301611ffe565b60008060006060848603121561202a57600080fd5b835167ffffffffffffffff8082111561204257600080fd5b61204e87838801611f56565b9450602086015191508082111561206457600080fd5b61207087838801611fba565b9350604086015191508082111561208657600080fd5b5061209386828701611fba565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082601f8301126120dd57600080fd5b81516120eb61164e82611607565b81815284602083860101111561210057600080fd5b610a00826020830160208701611897565b60006020828403121561212357600080fd5b815167ffffffffffffffff8082111561213b57600080fd5b9083019060e0828603121561214f57600080fd5b6121576115b3565b82518281111561216657600080fd5b61217287828601611f56565b82525060208301518281111561218757600080fd5b61219387828601611fba565b6020830152506040830151828111156121ab57600080fd5b6121b787828601611fba565b6040830152506121c960608401611cff565b60608201526121da60808401611cff565b608082015260a0830151828111156121f157600080fd5b6121fd878286016120cc565b60a08301525060c08301518281111561221557600080fd5b612221878286016120cc565b60c08301525095945050505050565b6000821982111561226a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611a0b60808301846118c3565b6000602082840312156122c057600080fd5b81518015158114610db457600080fd5b600082516122e2818460208701611897565b919091019291505056fea2646970667358221220733f0e016913bbd4dfcb7617c8c35815f18b2c43c50459d1cc2c6046f63c95e964736f6c634300080a0033
Deployed Bytecode
0x60806040526004361061010e5760003560e01c80638bcb6216116100a55780639864dcdd11610074578063c579d49011610059578063c579d49014610336578063d3c2e7ed14610356578063f24ccbfe1461036b57600080fd5b80639864dcdd146102bc5780639ce3e919146102d157600080fd5b80638bcb62161461023f5780638cedca71146102545780638df50f741461027c5780639093410d1461028f57600080fd5b8063389f87ff116100e1578063389f87ff1461019657806341c0e1b5146101a95780637b103999146101be5780638237e5381461020b57600080fd5b80630f2eee421461011357806323e30c8b1461013f578063247492f81461016d5780632fa13cb814610181575b600080fd5b34801561011f57600080fd5b50610128608081565b60405160ff90911681526020015b60405180910390f35b34801561014b57600080fd5b5061015f61015a3660046114b1565b610393565b604051908152602001610136565b34801561017957600080fd5b506000610128565b34801561018d57600080fd5b50610128600081565b6101a76101a4366004611685565b50565b005b3480156101b557600080fd5b506101a76107c8565b3480156101ca57600080fd5b506101e673287778f121f134c66212fb16c9b53ec991d32f5b81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610136565b34801561021757600080fd5b5061015f7f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd981565b34801561024b57600080fd5b50610128600181565b34801561026057600080fd5b506101e673ccf3d848e08b94478ed8f46ffead3008faf581fd81565b61015f61028a3660046117af565b6108b2565b34801561029b57600080fd5b506102af6102aa366004611685565b610a08565b60405161013691906118ef565b3480156102c857600080fd5b50610128607f81565b3480156102dd57600080fd5b506103057ff890814b417745d791c9230c2f130c9c0a442917386da77dda5dc34b2a22b9b881565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610136565b34801561034257600080fd5b506101a7610351366004611a15565b610a8e565b34801561036257600080fd5b5061012860ff81565b34801561037757600080fd5b506101e673ce7a977cac4a481bc84ac06b2da0df614e621cf381565b6000600260005414156103d2576040517f37ed32e800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600260005533731eb4cf3a948e7d72a198fe073ccb8c7a948cd85314610459576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f556e74727573746564206c656e6465720000000000000000000000000000000060448201526064015b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff871630146104d8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f556e74727573746564206c6f616e20696e69746961746f7200000000000000006044820152606401610450565b6000806104e784860186611bf0565b909250905061050d73ffffffffffffffffffffffffffffffffffffffff89168289610c16565b506040517f93b188540000000000000000000000000000000000000000000000000000000081527f4c69ee1e00000000000000000000000000000000000000000000000000000000600482015260009073287778f121f134c66212fb16c9b53ec991d32f5b906393b1885490602401602060405180830381865afa158015610599573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bd9190611d0a565b905060006105cb8989610d3b565b90508273ffffffffffffffffffffffffffffffffffffffff16631cff79cd47847ff890814b417745d791c9230c2f130c9c0a442917386da77dda5dc34b2a22b9b8888660405160240161061f929190611df8565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009485161790525160e086901b90921682526106929291600401611efb565b60206040518083038185885af11580156106b0573d6000803e3d6000fd5b50505050506040513d601f19601f820116820180604052508101906106d59190611f2a565b50806106f773ffffffffffffffffffffffffffffffffffffffff8c1630610dbb565b1461075e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f57726f6e67207061796261636b20616d6f756e740000000000000000000000006044820152606401610450565b61079373ffffffffffffffffffffffffffffffffffffffff8b16731eb4cf3a948e7d72a198fe073ccb8c7a948cd85383610ea4565b50506001600055507f439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd998975050505050505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108629190611d0a565b73ffffffffffffffffffffffffffffffffffffffff16146108af576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6000806108be86610a08565b608081015190915073ffffffffffffffffffffffffffffffffffffffff16156109c757608081015160a08201516040517f0ae1cc8e00000000000000000000000000000000000000000000000000000000815260009273ffffffffffffffffffffffffffffffffffffffff1691630ae1cc8e9161093e9190600401611f43565b600060405180830381865afa15801561095b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109839190810190612015565b509150508060008151811061099a5761099a61209d565b602002602001015182602001516000815181106109b9576109b961209d565b602002602001018181525050505b60008160c00151905060006109fa83602001516000815181106109ec576109ec61209d565b602002602001015183610f9b565b93505050505b949350505050565b610a746040518060e00160405280606081526020016060815260200160608152602001600073ffffffffffffffffffffffffffffffffffffffff168152602001600073ffffffffffffffffffffffffffffffffffffffff16815260200160608152602001606081525090565b81806020019051810190610a889190612111565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b289190611d0a565b73ffffffffffffffffffffffffffffffffffffffff1614610b75576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610bf05760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610bea573d6000803e3d6000fd5b50505050565b610c1173ffffffffffffffffffffffffffffffffffffffff841683836110da565b505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415610c4d57610c4a8430610dbb565b91505b73ffffffffffffffffffffffffffffffffffffffff831615801590610c88575073ffffffffffffffffffffffffffffffffffffffff83163014155b8015610c9357508115155b15610d345773ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14610cef57610cea73ffffffffffffffffffffffffffffffffffffffff851684846110da565b610d34565b60405173ffffffffffffffffffffffffffffffffffffffff84169083156108fc029084906000818181858888f19350505050158015610d32573d6000803e3d6000fd5b505b5092915050565b600080610d488385612230565b905083811015610db4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f7700000000006044820152606401610450565b9392505050565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610e0d575073ffffffffffffffffffffffffffffffffffffffff811631610a88565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015610e79573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e9d9190611f2a565b9050610a88565b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610edb57505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015610f50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f749190611f2a565b1015610c1157610c1173ffffffffffffffffffffffffffffffffffffffff84168383611190565b6040517f5cffe9de000000000000000000000000000000000000000000000000000000008152600090731eb4cf3a948e7d72a198fe073ccb8c7a948cd85390635cffe9de90611008903090736b175474e89094c44da98b954eedeac495271d0f908890889060040161226f565b6020604051808303816000875af1158015611027573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104b91906122ae565b506040517f464c4d616b657200000000000000000000000000000000000000000000000000815260070160405180910390207f2b6d22f419271bcc89bbac8deec947c664365d6e24d06fef0ca7c325c704dce3846040516020016110b191815260200190565b60408051601f19818403018152908290526110cb91611f43565b60405180910390a25090919050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610c119084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261123c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152600060448201526111e69084907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161112c565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610c119084907f095ea7b3000000000000000000000000000000000000000000000000000000009060640161112c565b600061129e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166113489092919063ffffffff16565b805190915015610c1157808060200190518101906112bc91906122ae565b610c11576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610450565b6060610a008484600085606061135d85611456565b611393576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516113bc91906122d0565b60006040518083038185875af1925050503d80600081146113f9576040519150601f19603f3d011682016040523d82523d6000602084013e6113fe565b606091505b50915091508115611412579150610a009050565b8051156114225780518082602001fd5b836040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016104509190611f43565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610a00575050151592915050565b73ffffffffffffffffffffffffffffffffffffffff811681146101a457600080fd5b60008060008060008060a087890312156114ca57600080fd5b86356114d58161148f565b955060208701356114e58161148f565b94506040870135935060608701359250608087013567ffffffffffffffff8082111561151057600080fd5b818901915089601f83011261152457600080fd5b81358181111561153357600080fd5b8a602082850101111561154557600080fd5b6020830194508093505050509295509295509295565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405160a0810167ffffffffffffffff811182821017156115ad576115ad61155b565b60405290565b60405160e0810167ffffffffffffffff811182821017156115ad576115ad61155b565b604051601f8201601f1916810167ffffffffffffffff811182821017156115ff576115ff61155b565b604052919050565b600067ffffffffffffffff8211156116215761162161155b565b50601f01601f191660200190565b600082601f83011261164057600080fd5b813561165361164e82611607565b6115d6565b81815284602083860101111561166857600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561169757600080fd5b813567ffffffffffffffff8111156116ae57600080fd5b610a008482850161162f565b600067ffffffffffffffff8211156116d4576116d461155b565b5060051b60200190565b600082601f8301126116ef57600080fd5b813560206116ff61164e836116ba565b82815260059290921b8401810191818101908684111561171e57600080fd5b8286015b848110156117395780358352918301918301611722565b509695505050505050565b600082601f83011261175557600080fd5b8135602061176561164e836116ba565b82815260059290921b8401810191818101908684111561178457600080fd5b8286015b8481101561173957803560ff811681146117a25760008081fd5b8352918301918301611788565b600080600080608085870312156117c557600080fd5b843567ffffffffffffffff808211156117dd57600080fd5b6117e98883890161162f565b955060208701359150808211156117ff57600080fd5b61180b888389016116de565b9450604087013591508082111561182157600080fd5b61182d88838901611744565b9350606087013591508082111561184357600080fd5b50611850878288016116de565b91505092959194509250565b600081518084526020808501945080840160005b8381101561188c57815187529582019590820190600101611870565b509495945050505050565b60005b838110156118b257818101518382015260200161189a565b83811115610bea5750506000910152565b600081518084526118db816020860160208601611897565b601f01601f19169290920160200192915050565b6020808252825160e083830152805161010084018190526000929182019083906101208601905b8083101561194c57835173ffffffffffffffffffffffffffffffffffffffff168252928401926001929092019190840190611916565b50838701519350601f1992508286820301604087015261196c818561185c565b93505050604085015181858403016060860152611989838261185c565b92505060608501516119b3608086018273ffffffffffffffffffffffffffffffffffffffff169052565b50608085015173ffffffffffffffffffffffffffffffffffffffff811660a08601525060a0850151818584030160c08601526119ef83826118c3565b92505060c0850151818584030160e0860152611a0b83826118c3565b9695505050505050565b600080600060608486031215611a2a57600080fd5b8335611a358161148f565b92506020840135611a458161148f565b929592945050506040919091013590565b600082601f830112611a6757600080fd5b81356020611a7761164e836116ba565b82815260059290921b84018101918181019086841115611a9657600080fd5b8286015b8481101561173957803567ffffffffffffffff811115611aba5760008081fd5b611ac88986838b010161162f565b845250918301918301611a9a565b600082601f830112611ae757600080fd5b81356020611af761164e836116ba565b82815260059290921b84018101918181019086841115611b1657600080fd5b8286015b848110156117395780357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b535760008081fd5b8352918301918301611b1a565b600082601f830112611b7157600080fd5b81356020611b8161164e836116ba565b82815260059290921b84018101918181019086841115611ba057600080fd5b8286015b8481101561173957803567ffffffffffffffff811115611bc45760008081fd5b611bd28986838b0101611744565b845250918301918301611ba4565b8035611beb8161148f565b919050565b60008060408385031215611c0357600080fd5b823567ffffffffffffffff80821115611c1b57600080fd5b9084019060a08287031215611c2f57600080fd5b611c3761158a565b823582811115611c4657600080fd5b611c528882860161162f565b825250602083013582811115611c6757600080fd5b611c7388828601611a56565b602083015250604083013582811115611c8b57600080fd5b611c97888286016116de565b604083015250606083013582811115611caf57600080fd5b611cbb88828601611ad6565b606083015250608083013582811115611cd357600080fd5b611cdf88828601611b60565b6080830152509350611cf691505060208401611be0565b90509250929050565b8051611beb8161148f565b600060208284031215611d1c57600080fd5b8151610db48161148f565b600081518084526020808501945080840160005b8381101561188c5781517fffffffff000000000000000000000000000000000000000000000000000000001687529582019590820190600101611d3b565b600081518084526020808501808196508360051b810191508286016000805b86811015611dea578385038a52825180518087529087019087870190845b81811015611dd557835160ff1683529289019291890191600101611db6565b50509a87019a95505091850191600101611d98565b509298975050505050505050565b604081526000835160a06040840152611e1460e08401826118c3565b90506020808601517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0808685030160608701528382518086528486019150848160051b870101858501945060005b82811015611e9057601f19888303018452611e7e8287516118c3565b95870195938701939150600101611e62565b5060408b01519650838982030160808a0152611eac818861185c565b965050505060608801519150808685030160a0870152611ecc8483611d27565b935060808801519150808685030160c087015250611eea8382611d79565b935050848185015250509392505050565b73ffffffffffffffffffffffffffffffffffffffff83168152604060208201526000610a0060408301846118c3565b600060208284031215611f3c57600080fd5b5051919050565b602081526000610db460208301846118c3565b600082601f830112611f6757600080fd5b81516020611f7761164e836116ba565b82815260059290921b84018101918181019086841115611f9657600080fd5b8286015b84811015611739578051611fad8161148f565b8352918301918301611f9a565b600082601f830112611fcb57600080fd5b81516020611fdb61164e836116ba565b82815260059290921b84018101918181019086841115611ffa57600080fd5b8286015b848110156117395780518352918301918301611ffe565b60008060006060848603121561202a57600080fd5b835167ffffffffffffffff8082111561204257600080fd5b61204e87838801611f56565b9450602086015191508082111561206457600080fd5b61207087838801611fba565b9350604086015191508082111561208657600080fd5b5061209386828701611fba565b9150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082601f8301126120dd57600080fd5b81516120eb61164e82611607565b81815284602083860101111561210057600080fd5b610a00826020830160208701611897565b60006020828403121561212357600080fd5b815167ffffffffffffffff8082111561213b57600080fd5b9083019060e0828603121561214f57600080fd5b6121576115b3565b82518281111561216657600080fd5b61217287828601611f56565b82525060208301518281111561218757600080fd5b61219387828601611fba565b6020830152506040830151828111156121ab57600080fd5b6121b787828601611fba565b6040830152506121c960608401611cff565b60608201526121da60808401611cff565b608082015260a0830151828111156121f157600080fd5b6121fd878286016120cc565b60a08301525060c08301518281111561221557600080fd5b612221878286016120cc565b60c08301525095945050505050565b6000821982111561226a577f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b500190565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525083604083015260806060830152611a0b60808301846118c3565b6000602082840312156122c057600080fd5b81518015158114610db457600080fd5b600082516122e2818460208701611897565b919091019291505056fea2646970667358221220733f0e016913bbd4dfcb7617c8c35815f18b2c43c50459d1cc2c6046f63c95e964736f6c634300080a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
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.