Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers. Name tag integration is not available in advanced view.
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
||||
---|---|---|---|---|---|---|---|
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14970705 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969663 | 912 days ago | 0 ETH | |||||
14969593 | 912 days ago | 0 ETH | |||||
14969593 | 912 days ago | 0 ETH | |||||
14969593 | 912 days ago | 0 ETH |
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.