Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 17734088 | 437 days ago | IN | 0 ETH | 0.04011142 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
SparkPayback
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-07-20 */ // SPDX-License-Identifier: MIT pragma solidity =0.8.10; contract MainnetActionsUtilAddresses { address internal constant DFS_REG_CONTROLLER_ADDR = 0xF8f8B3C98Cf2E63Df3041b73f80F362a4cf3A576; address internal constant REGISTRY_ADDR = 0x287778F121F134C66212FB16c9b53eC991D32f5b; address internal constant DFS_LOGGER_ADDR = 0xcE7a977Cac4a481bc84AC06b2Da0df614e621cf3; address internal constant SUB_STORAGE_ADDR = 0x1612fc28Ee0AB882eC99842Cde0Fc77ff0691e90; address internal constant PROXY_AUTH_ADDR = 0x149667b6FAe2c63D1B4317C716b0D0e4d3E2bD70; } contract ActionsUtilHelper is MainnetActionsUtilAddresses { } 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; } } 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 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); } } 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); } } contract MainnetSparkAddresses { address internal constant REWARDS_CONTROLLER_ADDRESS = 0x4370D3b6C9588E02ce9D22e684387859c7Ff5b34; address internal constant DEFAULT_SPARK_MARKET = 0x02C3eA4e34C0cBd694D2adFa2c690EECbC1793eE; address internal constant SPARK_ORACLE_V3 = 0x8105f69D9C41644c6A0803fDA7D03Aa70996cFD9; address internal constant TRANSIENT_STORAGE = 0x2F7Ef2ea5E8c97B8687CA703A0e50Aa5a49B7eb2; address internal constant SDAI_ADDR = 0x83F20F44975D03b1b09e64809B757c47f942BEeA; address internal constant DAI_ADDR = 0x6B175474E89094C44Da98b954EedeAC495271d0F; } interface IAaveProtocolDataProvider { /** * @notice Returns the user data in a reserve * @param asset The address of the underlying asset of the reserve * @param user The address of the user * @return currentATokenBalance The current AToken balance of the user * @return currentStableDebt The current stable debt of the user * @return currentVariableDebt The current variable debt of the user * @return principalStableDebt The principal stable debt of the user * @return scaledVariableDebt The scaled variable debt of the user * @return stableBorrowRate The stable borrow rate of the user * @return liquidityRate The liquidity rate of the reserve * @return stableRateLastUpdated The timestamp of the last update of the user stable rate * @return usageAsCollateralEnabled True if the user is using the asset as collateral, false * otherwise **/ function getUserReserveData(address asset, address user) external view returns ( uint256 currentATokenBalance, uint256 currentStableDebt, uint256 currentVariableDebt, uint256 principalStableDebt, uint256 scaledVariableDebt, uint256 stableBorrowRate, uint256 liquidityRate, uint40 stableRateLastUpdated, bool usageAsCollateralEnabled ); function getSiloedBorrowing(address asset) external view returns (bool); } library DataTypes { struct ReserveData { //stores the reserve configuration ReserveConfigurationMap configuration; //the liquidity index. Expressed in ray uint128 liquidityIndex; //the current supply rate. Expressed in ray uint128 currentLiquidityRate; //variable borrow index. Expressed in ray uint128 variableBorrowIndex; //the current variable borrow rate. Expressed in ray uint128 currentVariableBorrowRate; //the current stable borrow rate. Expressed in ray uint128 currentStableBorrowRate; //timestamp of last update uint40 lastUpdateTimestamp; //the id of the reserve. Represents the position in the list of the active reserves uint16 id; //aToken address address aTokenAddress; //stableDebtToken address address stableDebtTokenAddress; //variableDebtToken address address variableDebtTokenAddress; //address of the interest rate strategy address interestRateStrategyAddress; //the current treasury balance, scaled uint128 accruedToTreasury; //the outstanding unbacked aTokens minted through the bridging feature uint128 unbacked; //the outstanding debt borrowed against this asset in isolation mode uint128 isolationModeTotalDebt; } struct ReserveConfigurationMap { //bit 0-15: LTV //bit 16-31: Liq. threshold //bit 32-47: Liq. bonus //bit 48-55: Decimals //bit 56: reserve is active //bit 57: reserve is frozen //bit 58: borrowing is enabled //bit 59: stable rate borrowing enabled //bit 60: asset is paused //bit 61: borrowing in isolation mode is enabled //bit 62-63: reserved //bit 64-79: reserve factor //bit 80-115 borrow cap in whole tokens, borrowCap == 0 => no cap //bit 116-151 supply cap in whole tokens, supplyCap == 0 => no cap //bit 152-167 liquidation protocol fee //bit 168-175 eMode category //bit 176-211 unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled //bit 212-251 debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals //bit 252-255 unused uint256 data; } struct UserConfigurationMap { /** * @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset. * The first bit indicates if an asset is used as collateral by the user, the second whether an * asset is borrowed by the user. */ uint256 data; } struct EModeCategory { // each eMode category has a custom ltv and liquidation threshold uint16 ltv; uint16 liquidationThreshold; uint16 liquidationBonus; // each eMode category may or may not have a custom oracle to override the individual assets price oracles address priceSource; string label; } enum InterestRateMode { NONE, STABLE, VARIABLE } struct ReserveCache { uint256 currScaledVariableDebt; uint256 nextScaledVariableDebt; uint256 currPrincipalStableDebt; uint256 currAvgStableBorrowRate; uint256 currTotalStableDebt; uint256 nextAvgStableBorrowRate; uint256 nextTotalStableDebt; uint256 currLiquidityIndex; uint256 nextLiquidityIndex; uint256 currVariableBorrowIndex; uint256 nextVariableBorrowIndex; uint256 currLiquidityRate; uint256 currVariableBorrowRate; uint256 reserveFactor; ReserveConfigurationMap reserveConfiguration; address aTokenAddress; address stableDebtTokenAddress; address variableDebtTokenAddress; uint40 reserveLastUpdateTimestamp; uint40 stableDebtLastUpdateTimestamp; } struct ExecuteLiquidationCallParams { uint256 reservesCount; uint256 debtToCover; address collateralAsset; address debtAsset; address user; bool receiveAToken; address priceOracle; uint8 userEModeCategory; address priceOracleSentinel; } struct ExecuteSupplyParams { address asset; uint256 amount; address onBehalfOf; uint16 referralCode; } struct ExecuteBorrowParams { address asset; address user; address onBehalfOf; uint256 amount; InterestRateMode interestRateMode; uint16 referralCode; bool releaseUnderlying; uint256 maxStableRateBorrowSizePercent; uint256 reservesCount; address oracle; uint8 userEModeCategory; address priceOracleSentinel; } struct ExecuteRepayParams { address asset; uint256 amount; InterestRateMode interestRateMode; address onBehalfOf; bool useATokens; } struct ExecuteWithdrawParams { address asset; uint256 amount; address to; uint256 reservesCount; address oracle; uint8 userEModeCategory; } struct ExecuteSetUserEModeParams { uint256 reservesCount; address oracle; uint8 categoryId; } struct FinalizeTransferParams { address asset; address from; address to; uint256 amount; uint256 balanceFromBefore; uint256 balanceToBefore; uint256 reservesCount; address oracle; uint8 fromEModeCategory; } struct FlashloanParams { address receiverAddress; address[] assets; uint256[] amounts; uint256[] interestRateModes; address onBehalfOf; bytes params; uint16 referralCode; uint256 flashLoanPremiumToProtocol; uint256 flashLoanPremiumTotal; uint256 maxStableRateBorrowSizePercent; uint256 reservesCount; address addressesProvider; uint8 userEModeCategory; bool isAuthorizedFlashBorrower; } struct FlashloanSimpleParams { address receiverAddress; address asset; uint256 amount; bytes params; uint16 referralCode; uint256 flashLoanPremiumToProtocol; uint256 flashLoanPremiumTotal; } struct FlashLoanRepaymentParams { uint256 amount; uint256 totalPremium; uint256 flashLoanPremiumToProtocol; address asset; address receiverAddress; uint16 referralCode; } struct CalculateUserAccountDataParams { UserConfigurationMap userConfig; uint256 reservesCount; address user; address oracle; uint8 userEModeCategory; } struct ValidateBorrowParams { ReserveCache reserveCache; UserConfigurationMap userConfig; address asset; address userAddress; uint256 amount; InterestRateMode interestRateMode; uint256 maxStableLoanPercent; uint256 reservesCount; address oracle; uint8 userEModeCategory; address priceOracleSentinel; bool isolationModeActive; address isolationModeCollateralAddress; uint256 isolationModeDebtCeiling; } struct ValidateLiquidationCallParams { ReserveCache debtReserveCache; uint256 totalDebt; uint256 healthFactor; address priceOracleSentinel; } struct CalculateInterestRatesParams { uint256 unbacked; uint256 liquidityAdded; uint256 liquidityTaken; uint256 totalStableDebt; uint256 totalVariableDebt; uint256 averageStableBorrowRate; uint256 reserveFactor; address reserve; address aToken; } struct InitReserveParams { address asset; address aTokenAddress; address stableDebtAddress; address variableDebtAddress; address interestRateStrategyAddress; uint16 reservesCount; uint16 maxNumberReserves; } } interface IPoolAddressesProvider { /** * @dev Emitted when the market identifier is updated. * @param oldMarketId The old id of the market * @param newMarketId The new id of the market */ event MarketIdSet(string indexed oldMarketId, string indexed newMarketId); /** * @dev Emitted when the pool is updated. * @param oldAddress The old address of the Pool * @param newAddress The new address of the Pool */ event PoolUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the pool configurator is updated. * @param oldAddress The old address of the PoolConfigurator * @param newAddress The new address of the PoolConfigurator */ event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the price oracle is updated. * @param oldAddress The old address of the PriceOracle * @param newAddress The new address of the PriceOracle */ event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the ACL manager is updated. * @param oldAddress The old address of the ACLManager * @param newAddress The new address of the ACLManager */ event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the ACL admin is updated. * @param oldAddress The old address of the ACLAdmin * @param newAddress The new address of the ACLAdmin */ event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the price oracle sentinel is updated. * @param oldAddress The old address of the PriceOracleSentinel * @param newAddress The new address of the PriceOracleSentinel */ event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the pool data provider is updated. * @param oldAddress The old address of the PoolDataProvider * @param newAddress The new address of the PoolDataProvider */ event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when a new proxy is created. * @param id The identifier of the proxy * @param proxyAddress The address of the created proxy contract * @param implementationAddress The address of the implementation contract */ event ProxyCreated( bytes32 indexed id, address indexed proxyAddress, address indexed implementationAddress ); /** * @dev Emitted when a new non-proxied contract address is registered. * @param id The identifier of the contract * @param oldAddress The address of the old contract * @param newAddress The address of the new contract */ event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress); /** * @dev Emitted when the implementation of the proxy registered with id is updated * @param id The identifier of the contract * @param proxyAddress The address of the proxy contract * @param oldImplementationAddress The address of the old implementation contract * @param newImplementationAddress The address of the new implementation contract */ event AddressSetAsProxy( bytes32 indexed id, address indexed proxyAddress, address oldImplementationAddress, address indexed newImplementationAddress ); /** * @notice Returns the id of the Aave market to which this contract points to. * @return The market id **/ function getMarketId() external view returns (string memory); /** * @notice Associates an id with a specific PoolAddressesProvider. * @dev This can be used to create an onchain registry of PoolAddressesProviders to * identify and validate multiple Aave markets. * @param newMarketId The market id */ function setMarketId(string calldata newMarketId) external; /** * @notice Returns an address by its identifier. * @dev The returned address might be an EOA or a contract, potentially proxied * @dev It returns ZERO if there is no registered address with the given id * @param id The id * @return The address of the registered for the specified id */ function getAddress(bytes32 id) external view returns (address); /** * @notice General function to update the implementation of a proxy registered with * certain `id`. If there is no proxy registered, it will instantiate one and * set as implementation the `newImplementationAddress`. * @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit * setter function, in order to avoid unexpected consequences * @param id The id * @param newImplementationAddress The address of the new implementation */ function setAddressAsProxy(bytes32 id, address newImplementationAddress) external; /** * @notice Sets an address for an id replacing the address saved in the addresses map. * @dev IMPORTANT Use this function carefully, as it will do a hard replacement * @param id The id * @param newAddress The address to set */ function setAddress(bytes32 id, address newAddress) external; /** * @notice Returns the address of the Pool proxy. * @return The Pool proxy address **/ function getPool() external view returns (address); /** * @notice Updates the implementation of the Pool, or creates a proxy * setting the new `pool` implementation when the function is called for the first time. * @param newPoolImpl The new Pool implementation **/ function setPoolImpl(address newPoolImpl) external; /** * @notice Returns the address of the PoolConfigurator proxy. * @return The PoolConfigurator proxy address **/ function getPoolConfigurator() external view returns (address); /** * @notice Updates the implementation of the PoolConfigurator, or creates a proxy * setting the new `PoolConfigurator` implementation when the function is called for the first time. * @param newPoolConfiguratorImpl The new PoolConfigurator implementation **/ function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external; /** * @notice Returns the address of the price oracle. * @return The address of the PriceOracle */ function getPriceOracle() external view returns (address); /** * @notice Updates the address of the price oracle. * @param newPriceOracle The address of the new PriceOracle */ function setPriceOracle(address newPriceOracle) external; /** * @notice Returns the address of the ACL manager. * @return The address of the ACLManager */ function getACLManager() external view returns (address); /** * @notice Updates the address of the ACL manager. * @param newAclManager The address of the new ACLManager **/ function setACLManager(address newAclManager) external; /** * @notice Returns the address of the ACL admin. * @return The address of the ACL admin */ function getACLAdmin() external view returns (address); /** * @notice Updates the address of the ACL admin. * @param newAclAdmin The address of the new ACL admin */ function setACLAdmin(address newAclAdmin) external; /** * @notice Returns the address of the price oracle sentinel. * @return The address of the PriceOracleSentinel */ function getPriceOracleSentinel() external view returns (address); /** * @notice Updates the address of the price oracle sentinel. * @param newPriceOracleSentinel The address of the new PriceOracleSentinel **/ function setPriceOracleSentinel(address newPriceOracleSentinel) external; /** * @notice Returns the address of the data provider. * @return The address of the DataProvider */ function getPoolDataProvider() external view returns (address); /** * @notice Updates the address of the data provider. * @param newDataProvider The address of the new DataProvider **/ function setPoolDataProvider(address newDataProvider) external; } interface IPoolV3 { /** * @dev Emitted on mintUnbacked() * @param reserve The address of the underlying asset of the reserve * @param user The address initiating the supply * @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens * @param amount The amount of supplied assets * @param referralCode The referral code used **/ event MintUnbacked( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referralCode ); /** * @dev Emitted on backUnbacked() * @param reserve The address of the underlying asset of the reserve * @param backer The address paying for the backing * @param amount The amount added as backing * @param fee The amount paid in fees **/ event BackUnbacked(address indexed reserve, address indexed backer, uint256 amount, uint256 fee); /** * @dev Emitted on supply() * @param reserve The address of the underlying asset of the reserve * @param user The address initiating the supply * @param onBehalfOf The beneficiary of the supply, receiving the aTokens * @param amount The amount supplied * @param referralCode The referral code used **/ event Supply( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, uint16 indexed referralCode ); /** * @dev Emitted on withdraw() * @param reserve The address of the underlying asset being withdrawn * @param user The address initiating the withdrawal, owner of aTokens * @param to The address that will receive the underlying * @param amount The amount to be withdrawn **/ event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount); /** * @dev Emitted on borrow() and flashLoan() when debt needs to be opened * @param reserve The address of the underlying asset being borrowed * @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just * initiator of the transaction on flashLoan() * @param onBehalfOf The address that will be getting the debt * @param amount The amount borrowed out * @param interestRateMode The rate mode: 1 for Stable, 2 for Variable * @param borrowRate The numeric rate at which the user has borrowed, expressed in ray * @param referralCode The referral code used **/ event Borrow( address indexed reserve, address user, address indexed onBehalfOf, uint256 amount, DataTypes.InterestRateMode interestRateMode, uint256 borrowRate, uint16 indexed referralCode ); /** * @dev Emitted on repay() * @param reserve The address of the underlying asset of the reserve * @param user The beneficiary of the repayment, getting his debt reduced * @param repayer The address of the user initiating the repay(), providing the funds * @param amount The amount repaid * @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly **/ event Repay( address indexed reserve, address indexed user, address indexed repayer, uint256 amount, bool useATokens ); /** * @dev Emitted on swapBorrowRateMode() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user swapping his rate mode * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable **/ event SwapBorrowRateMode( address indexed reserve, address indexed user, DataTypes.InterestRateMode interestRateMode ); /** * @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets * @param asset The address of the underlying asset of the reserve * @param totalDebt The total isolation mode debt for the reserve */ event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt); /** * @dev Emitted when the user selects a certain asset category for eMode * @param user The address of the user * @param categoryId The category id **/ event UserEModeSet(address indexed user, uint8 categoryId); /** * @dev Emitted on setUserUseReserveAsCollateral() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user enabling the usage as collateral **/ event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user); /** * @dev Emitted on setUserUseReserveAsCollateral() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user enabling the usage as collateral **/ event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user); /** * @dev Emitted on rebalanceStableBorrowRate() * @param reserve The address of the underlying asset of the reserve * @param user The address of the user for which the rebalance has been executed **/ event RebalanceStableBorrowRate(address indexed reserve, address indexed user); /** * @dev Emitted on flashLoan() * @param target The address of the flash loan receiver contract * @param initiator The address initiating the flash loan * @param asset The address of the asset being flash borrowed * @param amount The amount flash borrowed * @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt * @param premium The fee flash borrowed * @param referralCode The referral code used **/ event FlashLoan( address indexed target, address initiator, address indexed asset, uint256 amount, DataTypes.InterestRateMode interestRateMode, uint256 premium, uint16 indexed referralCode ); /** * @dev Emitted when a borrower is liquidated. * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation * @param user The address of the borrower getting liquidated * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover * @param liquidatedCollateralAmount The amount of collateral received by the liquidator * @param liquidator The address of the liquidator * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants * to receive the underlying collateral asset directly **/ event LiquidationCall( address indexed collateralAsset, address indexed debtAsset, address indexed user, uint256 debtToCover, uint256 liquidatedCollateralAmount, address liquidator, bool receiveAToken ); /** * @dev Emitted when the state of a reserve is updated. * @param reserve The address of the underlying asset of the reserve * @param liquidityRate The next liquidity rate * @param stableBorrowRate The next stable borrow rate * @param variableBorrowRate The next variable borrow rate * @param liquidityIndex The next liquidity index * @param variableBorrowIndex The next variable borrow index **/ event ReserveDataUpdated( address indexed reserve, uint256 liquidityRate, uint256 stableBorrowRate, uint256 variableBorrowRate, uint256 liquidityIndex, uint256 variableBorrowIndex ); /** * @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest. * @param reserve The address of the reserve * @param amountMinted The amount minted to the treasury **/ event MintedToTreasury(address indexed reserve, uint256 amountMinted); /** * @dev Mints an `amount` of aTokens to the `onBehalfOf` * @param asset The address of the underlying asset to mint * @param amount The amount to mint * @param onBehalfOf The address that will receive the aTokens * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function mintUnbacked( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @dev Back the current unbacked underlying with `amount` and pay `fee`. * @param asset The address of the underlying asset to back * @param amount The amount to back * @param fee The amount paid in fees **/ function backUnbacked( address asset, uint256 amount, uint256 fee ) external; /** * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User supplies 100 USDC and gets in return 100 aUSDC * @param asset The address of the underlying asset to supply * @param amount The amount to be supplied * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function supply( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @notice Supply with transfer approval of asset to be supplied done via permit function * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 * @param asset The address of the underlying asset to supply * @param amount The amount to be supplied * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param deadline The deadline timestamp that the permit is valid * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man * @param permitV The V parameter of ERC712 permit sig * @param permitR The R parameter of ERC712 permit sig * @param permitS The S parameter of ERC712 permit sig **/ function supplyWithPermit( address asset, uint256 amount, address onBehalfOf, uint16 referralCode, uint256 deadline, uint8 permitV, bytes32 permitR, bytes32 permitS ) external; /** * @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned * E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC * @param asset The address of the underlying asset to withdraw * @param amount The underlying amount to be withdrawn * - Send the value type(uint256).max in order to withdraw the whole aToken balance * @param to The address that will receive the underlying, same as msg.sender if the user * wants to receive it on his own wallet, or a different address if the beneficiary is a * different wallet * @return The final amount withdrawn **/ function withdraw( address asset, uint256 amount, address to ) external returns (uint256); /** * @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower * already supplied enough collateral, or he was given enough allowance by a credit delegator on the * corresponding debt token (StableDebtToken or VariableDebtToken) * - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet * and 100 stable/variable debt tokens, depending on the `interestRateMode` * @param asset The address of the underlying asset to borrow * @param amount The amount to be borrowed * @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable * @param referralCode The code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man * @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself * calling the function if he wants to borrow against his own collateral, or the address of the credit delegator * if he has been given credit delegation allowance **/ function borrow( address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf ) external; /** * @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned * - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address * @param asset The address of the borrowed underlying asset previously borrowed * @param amount The amount to repay * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable * @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the * user calling the function if he wants to reduce/remove his own debt, or the address of any other * other borrower whose debt should be removed * @return The final amount repaid **/ function repay( address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf ) external returns (uint256); /** * @notice Repay with transfer approval of asset to be repaid done via permit function * see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713 * @param asset The address of the borrowed underlying asset previously borrowed * @param amount The amount to repay * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable * @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the * user calling the function if he wants to reduce/remove his own debt, or the address of any other * other borrower whose debt should be removed * @param deadline The deadline timestamp that the permit is valid * @param permitV The V parameter of ERC712 permit sig * @param permitR The R parameter of ERC712 permit sig * @param permitS The S parameter of ERC712 permit sig * @return The final amount repaid **/ function repayWithPermit( address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf, uint256 deadline, uint8 permitV, bytes32 permitR, bytes32 permitS ) external returns (uint256); /** * @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the * equivalent debt tokens * - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens * @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken * balance is not enough to cover the whole debt * @param asset The address of the borrowed underlying asset previously borrowed * @param amount The amount to repay * - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode` * @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable * @return The final amount repaid **/ function repayWithATokens( address asset, uint256 amount, uint256 interestRateMode ) external returns (uint256); /** * @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa * @param asset The address of the underlying asset borrowed * @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable **/ function swapBorrowRateMode(address asset, uint256 interestRateMode) external; /** * @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve. * - Users can be rebalanced if the following conditions are satisfied: * 1. Usage ratio is above 95% * 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too * much has been borrowed at a stable rate and suppliers are not earning enough * @param asset The address of the underlying asset borrowed * @param user The address of the user to be rebalanced **/ function rebalanceStableBorrowRate(address asset, address user) external; /** * @notice Allows suppliers to enable/disable a specific supplied asset as collateral * @param asset The address of the underlying asset supplied * @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise **/ function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external; /** * @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1 * - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives * a proportionally amount of the `collateralAsset` plus a bonus to cover market risk * @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation * @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation * @param user The address of the borrower getting liquidated * @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover * @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants * to receive the underlying collateral asset directly **/ function liquidationCall( address collateralAsset, address debtAsset, address user, uint256 debtToCover, bool receiveAToken ) external; /** * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, * as long as the amount taken plus a fee is returned. * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept * into consideration. For further details please visit https://developers.aave.com * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface * @param assets The addresses of the assets being flash-borrowed * @param amounts The amounts of the assets being flash-borrowed * @param interestRateModes Types of the debt to open if the flash loan is not returned: * 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver * 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address * 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address * @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2 * @param params Variadic packed params to pass to the receiver as extra information * @param referralCode The code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function flashLoan( address receiverAddress, address[] calldata assets, uint256[] calldata amounts, uint256[] calldata interestRateModes, address onBehalfOf, bytes calldata params, uint16 referralCode ) external; /** * @notice Allows smartcontracts to access the liquidity of the pool within one transaction, * as long as the amount taken plus a fee is returned. * @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept * into consideration. For further details please visit https://developers.aave.com * @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface * @param asset The address of the asset being flash-borrowed * @param amount The amount of the asset being flash-borrowed * @param params Variadic packed params to pass to the receiver as extra information * @param referralCode The code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function flashLoanSimple( address receiverAddress, address asset, uint256 amount, bytes calldata params, uint16 referralCode ) external; /** * @notice Returns the user account data across all the reserves * @param user The address of the user * @return totalCollateralBase The total collateral of the user in the base currency used by the price feed * @return totalDebtBase The total debt of the user in the base currency used by the price feed * @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed * @return currentLiquidationThreshold The liquidation threshold of the user * @return ltv The loan to value of The user * @return healthFactor The current health factor of the user **/ function getUserAccountData(address user) external view returns ( uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 ltv, uint256 healthFactor ); /** * @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an * interest rate strategy * @dev Only callable by the PoolConfigurator contract * @param asset The address of the underlying asset of the reserve * @param aTokenAddress The address of the aToken that will be assigned to the reserve * @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve * @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve * @param interestRateStrategyAddress The address of the interest rate strategy contract **/ function initReserve( address asset, address aTokenAddress, address stableDebtAddress, address variableDebtAddress, address interestRateStrategyAddress ) external; /** * @notice Drop a reserve * @dev Only callable by the PoolConfigurator contract * @param asset The address of the underlying asset of the reserve **/ function dropReserve(address asset) external; /** * @notice Updates the address of the interest rate strategy contract * @dev Only callable by the PoolConfigurator contract * @param asset The address of the underlying asset of the reserve * @param rateStrategyAddress The address of the interest rate strategy contract **/ function setReserveInterestRateStrategyAddress(address asset, address rateStrategyAddress) external; /** * @notice Sets the configuration bitmap of the reserve as a whole * @dev Only callable by the PoolConfigurator contract * @param asset The address of the underlying asset of the reserve * @param configuration The new configuration bitmap **/ function setConfiguration(address asset, DataTypes.ReserveConfigurationMap calldata configuration) external; /** * @notice Returns the configuration of the reserve * @param asset The address of the underlying asset of the reserve * @return The configuration of the reserve **/ function getConfiguration(address asset) external view returns (DataTypes.ReserveConfigurationMap memory); /** * @notice Returns the configuration of the user across all the reserves * @param user The user address * @return The configuration of the user **/ function getUserConfiguration(address user) external view returns (DataTypes.UserConfigurationMap memory); /** * @notice Returns the normalized income normalized income of the reserve * @param asset The address of the underlying asset of the reserve * @return The reserve's normalized income */ function getReserveNormalizedIncome(address asset) external view returns (uint256); /** * @notice Returns the normalized variable debt per unit of asset * @param asset The address of the underlying asset of the reserve * @return The reserve normalized variable debt */ function getReserveNormalizedVariableDebt(address asset) external view returns (uint256); /** * @notice Returns the state and configuration of the reserve * @param asset The address of the underlying asset of the reserve * @return The state and configuration data of the reserve **/ function getReserveData(address asset) external view returns (DataTypes.ReserveData memory); /** * @notice Validates and finalizes an aToken transfer * @dev Only callable by the overlying aToken of the `asset` * @param asset The address of the underlying asset of the aToken * @param from The user from which the aTokens are transferred * @param to The user receiving the aTokens * @param amount The amount being transferred/withdrawn * @param balanceFromBefore The aToken balance of the `from` user before the transfer * @param balanceToBefore The aToken balance of the `to` user before the transfer */ function finalizeTransfer( address asset, address from, address to, uint256 amount, uint256 balanceFromBefore, uint256 balanceToBefore ) external; /** * @notice Returns the list of the initialized reserves * @dev It does not include dropped reserves * @return The addresses of the reserves **/ function getReservesList() external view returns (address[] memory); /** * @notice Returns the PoolAddressesProvider connected to this contract * @return The address of the PoolAddressesProvider **/ function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); /** * @notice Updates the protocol fee on the bridging * @param bridgeProtocolFee The part of the premium sent to the protocol treasury */ function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external; /** * @notice Updates flash loan premiums. Flash loan premium consists of two parts: * - A part is sent to aToken holders as extra, one time accumulated interest * - A part is collected by the protocol treasury * @dev The total premium is calculated on the total borrowed amount * @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal` * @dev Only callable by the PoolConfigurator contract * @param flashLoanPremiumTotal The total premium, expressed in bps * @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps */ function updateFlashloanPremiums( uint128 flashLoanPremiumTotal, uint128 flashLoanPremiumToProtocol ) external; /** * @notice Configures a new category for the eMode. * @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category. * The category 0 is reserved as it's the default for volatile assets * @param id The id of the category * @param config The configuration of the category */ function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external; /** * @notice Returns the data of an eMode category * @param id The id of the category * @return The configuration data of the category */ function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory); /** * @notice Allows a user to use the protocol in eMode * @param categoryId The id of the category */ function setUserEMode(uint8 categoryId) external; /** * @notice Returns the eMode the user is using * @param user The address of the user * @return The eMode id */ function getUserEMode(address user) external view returns (uint256); /** * @notice Resets the isolation mode total debt of the given asset to zero * @dev It requires the given asset has zero debt ceiling * @param asset The address of the underlying asset to reset the isolationModeTotalDebt */ function resetIsolationModeTotalDebt(address asset) external; /** * @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate * @return The percentage of available liquidity to borrow, expressed in bps */ function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256); /** * @notice Returns the total fee on flash loans * @return The total fee on flashloans */ function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128); /** * @notice Returns the part of the bridge fees sent to protocol * @return The bridge fee sent to the protocol treasury */ function BRIDGE_PROTOCOL_FEE() external view returns (uint256); /** * @notice Returns the part of the flashloan fees sent to protocol * @return The flashloan fee sent to the protocol treasury */ function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128); /** * @notice Returns the maximum number of reserves supported to be listed in this Pool * @return The maximum number of reserves supported */ function MAX_NUMBER_RESERVES() external view returns (uint16); /** * @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens * @param assets The list of reserves for which the minting needs to be executed **/ function mintToTreasury(address[] calldata assets) external; /** * @notice Rescue and transfer tokens locked in this contract * @param token The address of the token * @param to The address of the recipient * @param amount The amount of token to transfer */ function rescueTokens( address token, address to, uint256 amount ) external; /** * @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens. * - E.g. User supplies 100 USDC and gets in return 100 aUSDC * @dev Deprecated: Use the `supply` function instead * @param asset The address of the underlying asset to supply * @param amount The amount to be supplied * @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user * wants to receive them on his own wallet, or a different address if the beneficiary of aTokens * is a different wallet * @param referralCode Code used to register the integrator originating the operation, for potential rewards. * 0 if the action is executed directly by the user, without any middle-man **/ function deposit( address asset, uint256 amount, address onBehalfOf, uint16 referralCode ) external; /** * @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct * @param id The id of the reserve as stored in the DataTypes.ReserveData struct * @return The address of the reserve associated with id **/ function getReserveAddressById(uint16 id) external view returns (address); } interface IL2PoolV3 is IPoolV3{ /** * @notice Calldata efficient wrapper of the supply function on behalf of the caller * @param args Arguments for the supply function packed in one bytes32 * 96 bits 16 bits 128 bits 16 bits * | 0-padding | referralCode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. */ function supply(bytes32 args) external; /** * @notice Calldata efficient wrapper of the supplyWithPermit function on behalf of the caller * @param args Arguments for the supply function packed in one bytes32 * 56 bits 8 bits 32 bits 16 bits 128 bits 16 bits * | 0-padding | permitV | shortenedDeadline | referralCode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. * @param r The R parameter of ERC712 permit sig * @param s The S parameter of ERC712 permit sig */ function supplyWithPermit( bytes32 args, bytes32 r, bytes32 s ) external; /** * @notice Calldata efficient wrapper of the withdraw function, withdrawing to the caller * @param args Arguments for the withdraw function packed in one bytes32 * 112 bits 128 bits 16 bits * | 0-padding | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. */ function withdraw(bytes32 args) external; /** * @notice Calldata efficient wrapper of the borrow function, borrowing on behalf of the caller * @param args Arguments for the borrow function packed in one bytes32 * 88 bits 16 bits 8 bits 128 bits 16 bits * | 0-padding | referralCode | shortenedInterestRateMode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. */ function borrow(bytes32 args) external; /** * @notice Calldata efficient wrapper of the repay function, repaying on behalf of the caller * @param args Arguments for the repay function packed in one bytes32 * 104 bits 8 bits 128 bits 16 bits * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. * @return The final amount repaid */ function repay(bytes32 args) external returns (uint256); /** * @notice Calldata efficient wrapper of the repayWithPermit function, repaying on behalf of the caller * @param args Arguments for the repayWithPermit function packed in one bytes32 * 64 bits 8 bits 32 bits 8 bits 128 bits 16 bits * | 0-padding | permitV | shortenedDeadline | shortenedInterestRateMode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. * @param r The R parameter of ERC712 permit sig * @param s The S parameter of ERC712 permit sig * @return The final amount repaid */ function repayWithPermit( bytes32 args, bytes32 r, bytes32 s ) external returns (uint256); /** * @notice Calldata efficient wrapper of the repayWithATokens function * @param args Arguments for the repayWithATokens function packed in one bytes32 * 104 bits 8 bits 128 bits 16 bits * | 0-padding | shortenedInterestRateMode | shortenedAmount | assetId | * @dev the shortenedAmount is cast to 256 bits at decode time, if type(uint128).max the value will be expanded to * type(uint256).max * @dev assetId is the index of the asset in the reservesList. * @return The final amount repaid */ function repayWithATokens(bytes32 args) external returns (uint256); /** * @notice Calldata efficient wrapper of the swapBorrowRateMode function * @param args Arguments for the swapBorrowRateMode function packed in one bytes32 * 232 bits 8 bits 16 bits * | 0-padding | shortenedInterestRateMode | assetId | * @dev assetId is the index of the asset in the reservesList. */ function swapBorrowRateMode(bytes32 args) external; /** * @notice Calldata efficient wrapper of the rebalanceStableBorrowRate function * @param args Arguments for the rebalanceStableBorrowRate function packed in one bytes32 * 80 bits 160 bits 16 bits * | 0-padding | user address | assetId | * @dev assetId is the index of the asset in the reservesList. */ function rebalanceStableBorrowRate(bytes32 args) external; /** * @notice Calldata efficient wrapper of the setUserUseReserveAsCollateral function * @param args Arguments for the setUserUseReserveAsCollateral function packed in one bytes32 * 239 bits 1 bit 16 bits * | 0-padding | useAsCollateral | assetId | * @dev assetId is the index of the asset in the reservesList. */ function setUserUseReserveAsCollateral(bytes32 args) external; /** * @notice Calldata efficient wrapper of the liquidationCall function * @param args1 part of the arguments for the liquidationCall function packed in one bytes32 * 64 bits 160 bits 16 bits 16 bits * | 0-padding | user address | debtAssetId | collateralAssetId | * @param args2 part of the arguments for the liquidationCall function packed in one bytes32 * 127 bits 1 bit 128 bits * | 0-padding | receiveAToken | shortenedDebtToCover | * @dev the shortenedDebtToCover is cast to 256 bits at decode time, * if type(uint128).max the value will be expanded to type(uint256).max */ function liquidationCall(bytes32 args1, bytes32 args2) external; } contract SparkHelper is MainnetSparkAddresses { uint16 public constant SPARK_REFERRAL_CODE = 0; uint256 public constant STABLE_ID = 1; uint256 public constant VARIABLE_ID = 2; /// @notice Returns the lending pool contract of the specified market function getLendingPool(address _market) internal view returns (IL2PoolV3) { return IL2PoolV3(IPoolAddressesProvider(_market).getPool()); } /// @notice Fetch the data provider for the specified market function getDataProvider(address _market) internal view returns (IAaveProtocolDataProvider) { return IAaveProtocolDataProvider( IPoolAddressesProvider(_market).getPoolDataProvider() ); } function boolToBytes(bool x) internal pure returns (bytes1 r) { return x ? bytes1(0x01) : bytes1(0x00); } function bytesToBool(bytes1 x) internal pure returns (bool r) { return x != bytes1(0x00); } function getWholeDebt(address _market, address _tokenAddr, uint _borrowType, address _debtOwner) internal view returns (uint256 debt) { IAaveProtocolDataProvider dataProvider = getDataProvider(_market); (, uint256 borrowsStable, uint256 borrowsVariable, , , , , , ) = dataProvider.getUserReserveData(_tokenAddr, _debtOwner); if (_borrowType == STABLE_ID) { debt = borrowsStable; } else if (_borrowType == VARIABLE_ID) { debt = borrowsVariable; } } } 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 WSTETH_ADDR = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0; address public constant STETH_ADDR = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; 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 { (bool success, ) = _to.call{value: _amount}(""); require(success, "Eth send fail"); } } 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 SparkPayback is ActionBase, SparkHelper { using TokenUtils for address; struct Params { uint256 amount; address from; uint8 rateMode; uint16 assetId; bool useDefaultMarket; bool useOnBehalf; address market; address onBehalf; } /// @inheritdoc ActionBase function executeAction( bytes calldata _callData, bytes32[] memory _subData, uint8[] memory _paramMapping, bytes32[] memory _returnValues ) public payable virtual override returns (bytes32) { Params memory params = parseInputs(_callData); params.amount = _parseParamUint(params.amount, _paramMapping[0], _subData, _returnValues); params.from = _parseParamAddr(params.from, _paramMapping[1], _subData, _returnValues); params.rateMode = uint8(_parseParamUint(uint8(params.rateMode), _paramMapping[2], _subData, _returnValues)); params.assetId = uint16(_parseParamUint(uint16(params.assetId), _paramMapping[3], _subData, _returnValues)); params.useDefaultMarket = _parseParamUint(params.useDefaultMarket ? 1 : 0, _paramMapping[4], _subData, _returnValues) == 1; params.useOnBehalf = _parseParamUint(params.useOnBehalf ? 1 : 0, _paramMapping[5], _subData, _returnValues) == 1; params.market = _parseParamAddr(params.market, _paramMapping[6], _subData, _returnValues); params.onBehalf = _parseParamAddr( params.onBehalf, _paramMapping[7], _subData, _returnValues ); if (params.useDefaultMarket) { params.market = DEFAULT_SPARK_MARKET; } if (!params.useOnBehalf) { params.onBehalf = address(0); } (uint256 paybackAmount, bytes memory logData) = _payback( params.market, params.assetId, params.amount, params.rateMode, params.from, params.onBehalf ); emit ActionEvent("SparkPayback", logData); return bytes32(paybackAmount); } /// @inheritdoc ActionBase function executeActionDirect(bytes memory _callData) public payable override { Params memory params = parseInputs(_callData); (, bytes memory logData) = _payback( params.market, params.assetId, params.amount, params.rateMode, params.from, params.onBehalf ); logger.logActionDirectEvent("SparkPayback", logData); } function executeActionDirectL2() public payable { Params memory params = decodeInputs(msg.data[4:]); (, bytes memory logData) = _payback( params.market, params.assetId, params.amount, params.rateMode, params.from, params.onBehalf ); logger.logActionDirectEvent("SparkPayback", logData); } /// @inheritdoc ActionBase function actionType() public pure virtual override returns (uint8) { return uint8(ActionType.STANDARD_ACTION); } //////////////////////////// ACTION LOGIC //////////////////////////// /// @notice User paybacks tokens to the Spark protocol /// @dev User needs to approve the DSProxy to pull the _tokenAddr tokens /// @param _market Address provider for specific market /// @param _assetId The id of the underlying asset to be repaid /// @param _amount Amount of tokens to be paid back /// @param _rateMode Type of borrow debt [Stable: 1, Variable: 2] /// @param _from Where are we pulling the payback tokens amount from /// @param _onBehalf For what user we are paying back the debt, defaults to proxy function _payback( address _market, uint16 _assetId, uint256 _amount, uint256 _rateMode, address _from, address _onBehalf ) internal returns (uint256, bytes memory) { // default to onBehalf of proxy if (_onBehalf == address(0)) { _onBehalf = address(this); } IPoolV3 lendingPool = getLendingPool(_market); address tokenAddr = lendingPool.getReserveAddressById(_assetId); uint256 maxDebt = getWholeDebt(_market, tokenAddr, _rateMode, _onBehalf); _amount = _amount > maxDebt ? maxDebt : _amount; tokenAddr.pullTokensIfNeeded(_from, _amount); tokenAddr.approveToken(address(lendingPool), _amount); uint256 tokensBefore = tokenAddr.getBalance(address(this)); lendingPool.repay(tokenAddr, _amount, _rateMode, _onBehalf); uint256 tokensAfter = tokenAddr.getBalance(address(this)); bytes memory logData = abi.encode(_market, tokenAddr, _amount, _rateMode, _from, _onBehalf); return (tokensBefore - tokensAfter, logData); } function parseInputs(bytes memory _callData) public pure returns (Params memory params) { params = abi.decode(_callData, (Params)); } function encodeInputs(Params memory params) public pure returns (bytes memory encodedInput) { encodedInput = bytes.concat(this.executeActionDirectL2.selector); encodedInput = bytes.concat(encodedInput, bytes32(params.amount)); encodedInput = bytes.concat(encodedInput, bytes20(params.from)); encodedInput = bytes.concat(encodedInput, bytes1(params.rateMode)); encodedInput = bytes.concat(encodedInput, bytes2(params.assetId)); encodedInput = bytes.concat(encodedInput, boolToBytes(params.useDefaultMarket)); encodedInput = bytes.concat(encodedInput, boolToBytes(params.useOnBehalf)); if (!params.useDefaultMarket) { encodedInput = bytes.concat(encodedInput, bytes20(params.market)); } if (params.useOnBehalf) { encodedInput = bytes.concat(encodedInput, bytes20(params.onBehalf)); } } function decodeInputs(bytes calldata encodedInput) public pure returns (Params memory params) { params.amount = uint256(bytes32(encodedInput[0:32])); params.from = address(bytes20(encodedInput[32:52])); params.rateMode = uint8(bytes1(encodedInput[52:53])); params.assetId = uint16(bytes2(encodedInput[53:55])); params.useDefaultMarket = bytesToBool(bytes1(encodedInput[55:56])); params.useOnBehalf = bytesToBool(bytes1(encodedInput[56:57])); uint256 mark = 57; if (params.useDefaultMarket) { params.market = DEFAULT_SPARK_MARKET; } else { params.market = address(bytes20(encodedInput[mark:mark + 20])); mark += 20; } if (params.useOnBehalf) { params.onBehalf = address(bytes20(encodedInput[mark:mark + 20])); } else { params.onBehalf = address(0); } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"name":"NonContractCall","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":"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":"SPARK_REFERRAL_CODE","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STABLE_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"VARIABLE_ID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"encodedInput","type":"bytes"}],"name":"decodeInputs","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint8","name":"rateMode","type":"uint8"},{"internalType":"uint16","name":"assetId","type":"uint16"},{"internalType":"bool","name":"useDefaultMarket","type":"bool"},{"internalType":"bool","name":"useOnBehalf","type":"bool"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"onBehalf","type":"address"}],"internalType":"struct SparkPayback.Params","name":"params","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint8","name":"rateMode","type":"uint8"},{"internalType":"uint16","name":"assetId","type":"uint16"},{"internalType":"bool","name":"useDefaultMarket","type":"bool"},{"internalType":"bool","name":"useOnBehalf","type":"bool"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"onBehalf","type":"address"}],"internalType":"struct SparkPayback.Params","name":"params","type":"tuple"}],"name":"encodeInputs","outputs":[{"internalType":"bytes","name":"encodedInput","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"_callData","type":"bytes"},{"internalType":"bytes32[]","name":"_subData","type":"bytes32[]"},{"internalType":"uint8[]","name":"_paramMapping","type":"uint8[]"},{"internalType":"bytes32[]","name":"_returnValues","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":"executeActionDirectL2","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":"bytes","name":"_callData","type":"bytes"}],"name":"parseInputs","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint8","name":"rateMode","type":"uint8"},{"internalType":"uint16","name":"assetId","type":"uint16"},{"internalType":"bool","name":"useDefaultMarket","type":"bool"},{"internalType":"bool","name":"useOnBehalf","type":"bool"},{"internalType":"address","name":"market","type":"address"},{"internalType":"address","name":"onBehalf","type":"address"}],"internalType":"struct SparkPayback.Params","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
608060405234801561001057600080fd5b5061272d806100206000396000f3fe60806040526004361061015f5760003560e01c80638cedca71116100c0578063d3bb4b1e11610074578063d4f922dc11610059578063d4f922dc1461036a578063e197b16c1461037f578063f24ccbfe146103ac57600080fd5b8063d3bb4b1e1461032d578063d3c2e7ed1461035557600080fd5b80639093410d116100a55780639093410d146102d85780639864dcdd146102f8578063c579d4901461030d57600080fd5b80638cedca711461029d5780638df50f74146102c557600080fd5b8063389f87ff116101175780637b103999116100fc5780637b1039991461020e5780638b8359791461025b5780638bcb62161461028857600080fd5b8063389f87ff146101e657806341c0e1b5146101f957600080fd5b80632895f3aa116101485780632895f3aa146101a45780632ba38bcb146101ae5780632fa13cb8146101d157600080fd5b80630f2eee4214610164578063247492f814610190575b600080fd5b34801561017057600080fd5b50610179608081565b60405160ff90911681526020015b60405180910390f35b34801561019c57600080fd5b506001610179565b6101ac6103d4565b005b3480156101ba57600080fd5b506101c3600181565b604051908152602001610187565b3480156101dd57600080fd5b50610179600081565b6101ac6101f4366004611cb1565b61049d565b34801561020557600080fd5b506101ac610560565b34801561021a57600080fd5b5061023673287778f121f134c66212fb16c9b53ec991d32f5b81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610187565b34801561026757600080fd5b5061027b610276366004611dad565b61064a565b6040516101879190611def565b34801561029457600080fd5b50610179600181565b3480156102a957600080fd5b5061023673ccf3d848e08b94478ed8f46ffead3008faf581fd81565b6101c36102d3366004611f47565b610811565b3480156102e457600080fd5b5061027b6102f3366004611cb1565b610ad9565b34801561030457600080fd5b50610179607f81565b34801561031957600080fd5b506101ac610328366004612083565b610b32565b34801561033957600080fd5b50610342600081565b60405161ffff9091168152602001610187565b34801561036157600080fd5b5061017960ff81565b34801561037657600080fd5b506101c3600281565b34801561038b57600080fd5b5061039f61039a3660046120f8565b610cba565b604051610187919061220f565b3480156103b857600080fd5b5061023673ce7a977cac4a481bc84ac06b2da0df614e621cf381565b60006103e66102763660048185612222565b905060006104138260c0015183606001518460000151856040015160ff1686602001518760e00151610e68565b6040517ff4b24b5500000000000000000000000000000000000000000000000000000000815290925073ce7a977cac4a481bc84ac06b2da0df614e621cf3915063f4b24b559061046790849060040161224c565b600060405180830381600087803b15801561048157600080fd5b505af1158015610495573d6000803e3d6000fd5b505050505050565b60006104a882610ad9565b905060006104d58260c0015183606001518460000151856040015160ff1686602001518760e00151610e68565b6040517ff4b24b5500000000000000000000000000000000000000000000000000000000815290925073ce7a977cac4a481bc84ac06b2da0df614e621cf3915063f4b24b559061052990849060040161224c565b600060405180830381600087803b15801561054357600080fd5b505af1158015610557573d6000803e3d6000fd5b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa919061229e565b73ffffffffffffffffffffffffffffffffffffffff1614610647576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152610699602060008486612222565b6106a2916122bb565b81526106b2603460208486612222565b6106bb916122f7565b60601c60208201526106d1603560348486612222565b6106da9161233f565b60f81c60408201526106f0603760358486612222565b6106f991612385565b60f01c6060820152610742610712603860378587612222565b61071b9161233f565b7fff0000000000000000000000000000000000000000000000000000000000000016151590565b1515608082015261075a610712603960388587612222565b151560a082015260808101516039901561078d577302c3ea4e34c0cbd694d2adfa2c690eecbc1793ee60c08301526107c7565b83818461079b8260146123fa565b926107a893929190612222565b6107b1916122f7565b60601c60c08301526107c46014826123fa565b90505b8160a0015115610802578381846107df8260146123fa565b926107ec93929190612222565b6107f5916122f7565b60601c60e083015261080a565b600060e08301525b5092915050565b60008061085387878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ad992505050565b905061087f81600001518560008151811061087057610870612412565b60200260200101518786611133565b8152602081015184516108af9190869060019081106108a0576108a0612412565b602002602001015187866111b1565b73ffffffffffffffffffffffffffffffffffffffff166020820152604081015184516108ec9160ff16908690600290811061087057610870612412565b60ff166040820152606081015184516109179161ffff16908690600390811061087057610870612412565b61ffff166060820152608081015161094d90610934576000610937565b60015b60ff168560048151811061087057610870612412565b600114608082015260a08101516109829061096957600061096c565b60015b60ff168560058151811061087057610870612412565b60011460a082015260c081015184516109a99190869060069081106108a0576108a0612412565b73ffffffffffffffffffffffffffffffffffffffff1660c082015260e081015184516109e39190869060079081106108a0576108a0612412565b73ffffffffffffffffffffffffffffffffffffffff1660e0820152608081015115610a23577302c3ea4e34c0cbd694d2adfa2c690eecbc1793ee60c08201525b8060a00151610a3457600060e08201525b600080610a608360c0015184606001518560000151866040015160ff1687602001518860e00151610e68565b6040517f537061726b5061796261636b000000000000000000000000000000000000000081529193509150600c0160405180910390207f2b6d22f419271bcc89bbac8deec947c664365d6e24d06fef0ca7c325c704dce382604051610ac5919061220f565b60405180910390a250979650505050505050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282519091610b2c9184018101908401612457565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcc919061229e565b73ffffffffffffffffffffffffffffffffffffffff1614610c19576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610c945760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610c8e573d6000803e3d6000fd5b50505050565b610cb573ffffffffffffffffffffffffffffffffffffffff8416838361128e565b505050565b604080517f2895f3aa00000000000000000000000000000000000000000000000000000000602082015281516004818303018152602482019092528251610d06918391906044016124ec565b604051602081830303815290604052905080826020015160601b604051602001610d3192919061250e565b604051602081830303815290604052905080826040015160f81b604051602001610d5c929190612555565b604051602081830303815290604052905080826060015160f01b604051602001610d8792919061259c565b604051602081830303815290604052905080610da68360800151611362565b604051602001610db7929190612555565b604051602081830303815290604052905080610dd68360a00151611362565b604051602001610de7929190612555565b60405160208183030381529060405290508160800151610e2d57808260c0015160601b604051602001610e1b92919061250e565b60405160208183030381529060405290505b8160a0015115610e6357808260e0015160601b604051602001610e5192919061250e565b60405160208183030381529060405290505b919050565b6000606073ffffffffffffffffffffffffffffffffffffffff8316610e8b573092505b6000610e9689611397565b6040517f5275179700000000000000000000000000000000000000000000000000000000815261ffff8a16600482015290915060009073ffffffffffffffffffffffffffffffffffffffff831690635275179790602401602060405180830381865afa158015610f0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2e919061229e565b90506000610f3e8b838a89611408565b9050808911610f4d5788610f4f565b805b9850610f7273ffffffffffffffffffffffffffffffffffffffff8316888b6114ea565b50610f9473ffffffffffffffffffffffffffffffffffffffff8316848b6115c4565b6000610fb673ffffffffffffffffffffffffffffffffffffffff8416306116bb565b6040517f573ade8100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018d9052604482018c905289811660648301529192509085169063573ade81906084016020604051808303816000875af115801561103e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106291906125e3565b50600061108573ffffffffffffffffffffffffffffffffffffffff8516306116bb565b905060008d858d8d8d8d6040516020016110e69695949392919073ffffffffffffffffffffffffffffffffffffffff96871681529486166020860152604085019390935260608401919091528316608083015290911660a082015260c00190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905061112082846125fc565b9e909d509b505050505050505050505050565b600060ff8416156111a657611147846117a4565b1561117b5781611156856117c3565b60ff168151811061116957611169612412565b602002602001015160001c94506111a6565b826111858561180f565b60ff168151811061119857611198612412565b602002602001015160001c94505b50835b949350505050565b600060ff8416156111a6576111c5846117a4565b156111f957816111d4856117c3565b60ff16815181106111e7576111e7612412565b602002602001015160601c94506111a6565b8360ff1660fe141561120c5750306111a9565b8360ff1660ff141561117b573073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611263573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611287919061229e565b90506111a9565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cb59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261185a565b600081611370576000610b2c565b7f010000000000000000000000000000000000000000000000000000000000000092915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2c919061229e565b6000806114148661196b565b6040517f28dd2d0100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015285811660248301529192506000918291908416906328dd2d019060440161012060405180830381865afa158015611492573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b69190612613565b505050505050925092505060018614156114d2578193506114df565b60028614156114df578093505b505050949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156115215761151e84846116bb565b91505b73ffffffffffffffffffffffffffffffffffffffff83161580159061155c575073ffffffffffffffffffffffffffffffffffffffff83163014155b8015611592575073ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b801561159d57508115155b1561080a5761080a73ffffffffffffffffffffffffffffffffffffffff85168430856119b8565b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156115fb57505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611670573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169491906125e3565b1015610cb557610cb573ffffffffffffffffffffffffffffffffffffffff84168383611a16565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561170d575073ffffffffffffffffffffffffffffffffffffffff811631610b2c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611779573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179d91906125e3565b9392505050565b6000600160ff831610801590610b2c5750607f60ff8316111592915050565b60006117ce826117a4565b611804576040517fdcc95a3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2c60018361269b565b6000608060ff8316101561184f576040517f866f6e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2c60808361269b565b60006118bc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ac29092919063ffffffff16565b805190915015610cb557808060200190518101906118da91906126be565b610cb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1663e860accb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610c8e9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016112e0565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260006044820152611a6c9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016112e0565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cb59084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016112e0565b60606111a984846000856060611ad785611bd0565b611b0d576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611b3691906126db565b60006040518083038185875af1925050503d8060008114611b73576040519150601f19603f3d011682016040523d82523d6000602084013e611b78565b606091505b50915091508115611b8c5791506111a99050565b805115611b9c5780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611962919061220f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906111a9575050151592915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715611c5c57611c5c611c09565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611ca957611ca9611c09565b604052919050565b60006020808385031215611cc457600080fd5b823567ffffffffffffffff80821115611cdc57600080fd5b818501915085601f830112611cf057600080fd5b813581811115611d0257611d02611c09565b611d32847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611c62565b91508082528684828501011115611d4857600080fd5b8084840185840137600090820190930192909252509392505050565b60008083601f840112611d7657600080fd5b50813567ffffffffffffffff811115611d8e57600080fd5b602083019150836020828501011115611da657600080fd5b9250929050565b60008060208385031215611dc057600080fd5b823567ffffffffffffffff811115611dd757600080fd5b611de385828601611d64565b90969095509350505050565b6000610100820190508251825273ffffffffffffffffffffffffffffffffffffffff602084015116602083015260ff604084015116604083015261ffff606084015116606083015260808301511515608083015260a0830151611e5660a084018215159052565b5060c0830151611e7e60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161080a60e084018273ffffffffffffffffffffffffffffffffffffffff169052565b600067ffffffffffffffff821115611ec057611ec0611c09565b5060051b60200190565b600082601f830112611edb57600080fd5b81356020611ef0611eeb83611ea6565b611c62565b82815260059290921b84018101918181019086841115611f0f57600080fd5b8286015b84811015611f2a5780358352918301918301611f13565b509695505050505050565b60ff81168114611f4457600080fd5b50565b600080600080600060808688031215611f5f57600080fd5b853567ffffffffffffffff80821115611f7757600080fd5b611f8389838a01611d64565b9097509550602091508782013581811115611f9d57600080fd5b611fa98a828b01611eca565b955050604088013581811115611fbe57600080fd5b8801601f81018a13611fcf57600080fd5b8035611fdd611eeb82611ea6565b81815260059190911b8201840190848101908c831115611ffc57600080fd5b928501925b8284101561202357833561201481611f35565b82529285019290850190612001565b9650505050606088013591508082111561203c57600080fd5b5061204988828901611eca565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff81168114611f4457600080fd5b8035610e6381612056565b60008060006060848603121561209857600080fd5b83356120a381612056565b925060208401356120b381612056565b929592945050506040919091013590565b61ffff81168114611f4457600080fd5b8035610e63816120c4565b8015158114611f4457600080fd5b8035610e63816120df565b6000610100828403121561210b57600080fd5b612113611c38565b82358152602083013561212581612056565b6020820152604083013561213881611f35565b6040820152612149606084016120d4565b606082015261215a608084016120ed565b608082015261216b60a084016120ed565b60a082015261217c60c08401612078565b60c082015261218d60e08401612078565b60e08201529392505050565b60005b838110156121b457818101518382015260200161219c565b83811115610c8e5750506000910152565b600081518084526121dd816020860160208601612199565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061179d60208301846121c5565b6000808585111561223257600080fd5b8386111561223f57600080fd5b5050820193919092039150565b60408152600c60408201527f537061726b5061796261636b0000000000000000000000000000000000000000606082015260806020820152600061179d60808301846121c5565b8051610e6381612056565b6000602082840312156122b057600080fd5b815161179d81612056565b80356020831015610b2c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156123375780818660140360031b1b83161692505b505092915050565b7fff0000000000000000000000000000000000000000000000000000000000000081358181169160018510156123375760019490940360031b84901b1690921692915050565b7fffff00000000000000000000000000000000000000000000000000000000000081358181169160028510156123375760029490940360031b84901b1690921692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561240d5761240d6123cb565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051610e63816120c4565b8051610e63816120df565b6000610100828403121561246a57600080fd5b612472611c38565b82518152602083015161248481612056565b6020820152604083015161249781611f35565b60408201526124a860608401612441565b60608201526124b96080840161244c565b60808201526124ca60a0840161244c565b60a08201526124db60c08401612293565b60c082015261218d60e08401612293565b600083516124fe818460208801612199565b9190910191825250602001919050565b60008351612520818460208801612199565b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000939093169190920190815260140192915050565b60008351612567818460208801612199565b7fff00000000000000000000000000000000000000000000000000000000000000939093169190920190815260010192915050565b600083516125ae818460208801612199565b7fffff000000000000000000000000000000000000000000000000000000000000939093169190920190815260020192915050565b6000602082840312156125f557600080fd5b5051919050565b60008282101561260e5761260e6123cb565b500390565b60008060008060008060008060006101208a8c03121561263257600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015164ffffffffff8116811461267857600080fd5b6101008b015190925061268a816120df565b809150509295985092959850929598565b600060ff821660ff8416808210156126b5576126b56123cb565b90039392505050565b6000602082840312156126d057600080fd5b815161179d816120df565b600082516126ed818460208701612199565b919091019291505056fea2646970667358221220ab049d7d19e200280efbaf171bb2e519f22e95ebd1e48a518f1eb7dbaeaad3df64736f6c634300080a0033
Deployed Bytecode
0x60806040526004361061015f5760003560e01c80638cedca71116100c0578063d3bb4b1e11610074578063d4f922dc11610059578063d4f922dc1461036a578063e197b16c1461037f578063f24ccbfe146103ac57600080fd5b8063d3bb4b1e1461032d578063d3c2e7ed1461035557600080fd5b80639093410d116100a55780639093410d146102d85780639864dcdd146102f8578063c579d4901461030d57600080fd5b80638cedca711461029d5780638df50f74146102c557600080fd5b8063389f87ff116101175780637b103999116100fc5780637b1039991461020e5780638b8359791461025b5780638bcb62161461028857600080fd5b8063389f87ff146101e657806341c0e1b5146101f957600080fd5b80632895f3aa116101485780632895f3aa146101a45780632ba38bcb146101ae5780632fa13cb8146101d157600080fd5b80630f2eee4214610164578063247492f814610190575b600080fd5b34801561017057600080fd5b50610179608081565b60405160ff90911681526020015b60405180910390f35b34801561019c57600080fd5b506001610179565b6101ac6103d4565b005b3480156101ba57600080fd5b506101c3600181565b604051908152602001610187565b3480156101dd57600080fd5b50610179600081565b6101ac6101f4366004611cb1565b61049d565b34801561020557600080fd5b506101ac610560565b34801561021a57600080fd5b5061023673287778f121f134c66212fb16c9b53ec991d32f5b81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610187565b34801561026757600080fd5b5061027b610276366004611dad565b61064a565b6040516101879190611def565b34801561029457600080fd5b50610179600181565b3480156102a957600080fd5b5061023673ccf3d848e08b94478ed8f46ffead3008faf581fd81565b6101c36102d3366004611f47565b610811565b3480156102e457600080fd5b5061027b6102f3366004611cb1565b610ad9565b34801561030457600080fd5b50610179607f81565b34801561031957600080fd5b506101ac610328366004612083565b610b32565b34801561033957600080fd5b50610342600081565b60405161ffff9091168152602001610187565b34801561036157600080fd5b5061017960ff81565b34801561037657600080fd5b506101c3600281565b34801561038b57600080fd5b5061039f61039a3660046120f8565b610cba565b604051610187919061220f565b3480156103b857600080fd5b5061023673ce7a977cac4a481bc84ac06b2da0df614e621cf381565b60006103e66102763660048185612222565b905060006104138260c0015183606001518460000151856040015160ff1686602001518760e00151610e68565b6040517ff4b24b5500000000000000000000000000000000000000000000000000000000815290925073ce7a977cac4a481bc84ac06b2da0df614e621cf3915063f4b24b559061046790849060040161224c565b600060405180830381600087803b15801561048157600080fd5b505af1158015610495573d6000803e3d6000fd5b505050505050565b60006104a882610ad9565b905060006104d58260c0015183606001518460000151856040015160ff1686602001518760e00151610e68565b6040517ff4b24b5500000000000000000000000000000000000000000000000000000000815290925073ce7a977cac4a481bc84ac06b2da0df614e621cf3915063f4b24b559061052990849060040161224c565b600060405180830381600087803b15801561054357600080fd5b505af1158015610557573d6000803e3d6000fd5b50505050505050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff1663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105d6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105fa919061229e565b73ffffffffffffffffffffffffffffffffffffffff1614610647576040517fa6c827a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b33ff5b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810191909152610699602060008486612222565b6106a2916122bb565b81526106b2603460208486612222565b6106bb916122f7565b60601c60208201526106d1603560348486612222565b6106da9161233f565b60f81c60408201526106f0603760358486612222565b6106f991612385565b60f01c6060820152610742610712603860378587612222565b61071b9161233f565b7fff0000000000000000000000000000000000000000000000000000000000000016151590565b1515608082015261075a610712603960388587612222565b151560a082015260808101516039901561078d577302c3ea4e34c0cbd694d2adfa2c690eecbc1793ee60c08301526107c7565b83818461079b8260146123fa565b926107a893929190612222565b6107b1916122f7565b60601c60c08301526107c46014826123fa565b90505b8160a0015115610802578381846107df8260146123fa565b926107ec93929190612222565b6107f5916122f7565b60601c60e083015261080a565b600060e08301525b5092915050565b60008061085387878080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ad992505050565b905061087f81600001518560008151811061087057610870612412565b60200260200101518786611133565b8152602081015184516108af9190869060019081106108a0576108a0612412565b602002602001015187866111b1565b73ffffffffffffffffffffffffffffffffffffffff166020820152604081015184516108ec9160ff16908690600290811061087057610870612412565b60ff166040820152606081015184516109179161ffff16908690600390811061087057610870612412565b61ffff166060820152608081015161094d90610934576000610937565b60015b60ff168560048151811061087057610870612412565b600114608082015260a08101516109829061096957600061096c565b60015b60ff168560058151811061087057610870612412565b60011460a082015260c081015184516109a99190869060069081106108a0576108a0612412565b73ffffffffffffffffffffffffffffffffffffffff1660c082015260e081015184516109e39190869060079081106108a0576108a0612412565b73ffffffffffffffffffffffffffffffffffffffff1660e0820152608081015115610a23577302c3ea4e34c0cbd694d2adfa2c690eecbc1793ee60c08201525b8060a00151610a3457600060e08201525b600080610a608360c0015184606001518560000151866040015160ff1687602001518860e00151610e68565b6040517f537061726b5061796261636b000000000000000000000000000000000000000081529193509150600c0160405180910390207f2b6d22f419271bcc89bbac8deec947c664365d6e24d06fef0ca7c325c704dce382604051610ac5919061220f565b60405180910390a250979650505050505050565b604080516101008101825260008082526020808301829052928201819052606082018190526080820181905260a0820181905260c0820181905260e082015282519091610b2c9184018101908401612457565b92915050565b3373ffffffffffffffffffffffffffffffffffffffff1673ccf3d848e08b94478ed8f46ffead3008faf581fd73ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ba8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcc919061229e565b73ffffffffffffffffffffffffffffffffffffffff1614610c19576040517f19494c8a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee73ffffffffffffffffffffffffffffffffffffffff84161415610c945760405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610c8e573d6000803e3d6000fd5b50505050565b610cb573ffffffffffffffffffffffffffffffffffffffff8416838361128e565b505050565b604080517f2895f3aa00000000000000000000000000000000000000000000000000000000602082015281516004818303018152602482019092528251610d06918391906044016124ec565b604051602081830303815290604052905080826020015160601b604051602001610d3192919061250e565b604051602081830303815290604052905080826040015160f81b604051602001610d5c929190612555565b604051602081830303815290604052905080826060015160f01b604051602001610d8792919061259c565b604051602081830303815290604052905080610da68360800151611362565b604051602001610db7929190612555565b604051602081830303815290604052905080610dd68360a00151611362565b604051602001610de7929190612555565b60405160208183030381529060405290508160800151610e2d57808260c0015160601b604051602001610e1b92919061250e565b60405160208183030381529060405290505b8160a0015115610e6357808260e0015160601b604051602001610e5192919061250e565b60405160208183030381529060405290505b919050565b6000606073ffffffffffffffffffffffffffffffffffffffff8316610e8b573092505b6000610e9689611397565b6040517f5275179700000000000000000000000000000000000000000000000000000000815261ffff8a16600482015290915060009073ffffffffffffffffffffffffffffffffffffffff831690635275179790602401602060405180830381865afa158015610f0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2e919061229e565b90506000610f3e8b838a89611408565b9050808911610f4d5788610f4f565b805b9850610f7273ffffffffffffffffffffffffffffffffffffffff8316888b6114ea565b50610f9473ffffffffffffffffffffffffffffffffffffffff8316848b6115c4565b6000610fb673ffffffffffffffffffffffffffffffffffffffff8416306116bb565b6040517f573ade8100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8581166004830152602482018d9052604482018c905289811660648301529192509085169063573ade81906084016020604051808303816000875af115801561103e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061106291906125e3565b50600061108573ffffffffffffffffffffffffffffffffffffffff8516306116bb565b905060008d858d8d8d8d6040516020016110e69695949392919073ffffffffffffffffffffffffffffffffffffffff96871681529486166020860152604085019390935260608401919091528316608083015290911660a082015260c00190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152919052905061112082846125fc565b9e909d509b505050505050505050505050565b600060ff8416156111a657611147846117a4565b1561117b5781611156856117c3565b60ff168151811061116957611169612412565b602002602001015160001c94506111a6565b826111858561180f565b60ff168151811061119857611198612412565b602002602001015160001c94505b50835b949350505050565b600060ff8416156111a6576111c5846117a4565b156111f957816111d4856117c3565b60ff16815181106111e7576111e7612412565b602002602001015160601c94506111a6565b8360ff1660fe141561120c5750306111a9565b8360ff1660ff141561117b573073ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611263573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611287919061229e565b90506111a9565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cb59084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261185a565b600081611370576000610b2c565b7f010000000000000000000000000000000000000000000000000000000000000092915050565b60008173ffffffffffffffffffffffffffffffffffffffff1663026b1d5f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b2c919061229e565b6000806114148661196b565b6040517f28dd2d0100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff878116600483015285811660248301529192506000918291908416906328dd2d019060440161012060405180830381865afa158015611492573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b69190612613565b505050505050925092505060018614156114d2578193506114df565b60028614156114df578093505b505050949350505050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156115215761151e84846116bb565b91505b73ffffffffffffffffffffffffffffffffffffffff83161580159061155c575073ffffffffffffffffffffffffffffffffffffffff83163014155b8015611592575073ffffffffffffffffffffffffffffffffffffffff841673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14155b801561159d57508115155b1561080a5761080a73ffffffffffffffffffffffffffffffffffffffff85168430856119b8565b73ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156115fb57505050565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282919085169063dd62ed3e90604401602060405180830381865afa158015611670573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169491906125e3565b1015610cb557610cb573ffffffffffffffffffffffffffffffffffffffff84168383611a16565b600073ffffffffffffffffffffffffffffffffffffffff831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561170d575073ffffffffffffffffffffffffffffffffffffffff811631610b2c565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301528416906370a0823190602401602060405180830381865afa158015611779573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061179d91906125e3565b9392505050565b6000600160ff831610801590610b2c5750607f60ff8316111592915050565b60006117ce826117a4565b611804576040517fdcc95a3900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2c60018361269b565b6000608060ff8316101561184f576040517f866f6e8700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b2c60808361269b565b60006118bc826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ac29092919063ffffffff16565b805190915015610cb557808060200190518101906118da91906126be565b610cb5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f7420737563636565640000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b60008173ffffffffffffffffffffffffffffffffffffffff1663e860accb6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156113e4573d6000803e3d6000fd5b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610c8e9085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016112e0565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260006044820152611a6c9084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016112e0565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610cb59084907f095ea7b300000000000000000000000000000000000000000000000000000000906064016112e0565b60606111a984846000856060611ad785611bd0565b611b0d576040517f304619b500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611b3691906126db565b60006040518083038185875af1925050503d8060008114611b73576040519150601f19603f3d011682016040523d82523d6000602084013e611b78565b606091505b50915091508115611b8c5791506111a99050565b805115611b9c5780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611962919061220f565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a4708181148015906111a9575050151592915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051610100810167ffffffffffffffff81118282101715611c5c57611c5c611c09565b60405290565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611ca957611ca9611c09565b604052919050565b60006020808385031215611cc457600080fd5b823567ffffffffffffffff80821115611cdc57600080fd5b818501915085601f830112611cf057600080fd5b813581811115611d0257611d02611c09565b611d32847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611c62565b91508082528684828501011115611d4857600080fd5b8084840185840137600090820190930192909252509392505050565b60008083601f840112611d7657600080fd5b50813567ffffffffffffffff811115611d8e57600080fd5b602083019150836020828501011115611da657600080fd5b9250929050565b60008060208385031215611dc057600080fd5b823567ffffffffffffffff811115611dd757600080fd5b611de385828601611d64565b90969095509350505050565b6000610100820190508251825273ffffffffffffffffffffffffffffffffffffffff602084015116602083015260ff604084015116604083015261ffff606084015116606083015260808301511515608083015260a0830151611e5660a084018215159052565b5060c0830151611e7e60c084018273ffffffffffffffffffffffffffffffffffffffff169052565b5060e083015161080a60e084018273ffffffffffffffffffffffffffffffffffffffff169052565b600067ffffffffffffffff821115611ec057611ec0611c09565b5060051b60200190565b600082601f830112611edb57600080fd5b81356020611ef0611eeb83611ea6565b611c62565b82815260059290921b84018101918181019086841115611f0f57600080fd5b8286015b84811015611f2a5780358352918301918301611f13565b509695505050505050565b60ff81168114611f4457600080fd5b50565b600080600080600060808688031215611f5f57600080fd5b853567ffffffffffffffff80821115611f7757600080fd5b611f8389838a01611d64565b9097509550602091508782013581811115611f9d57600080fd5b611fa98a828b01611eca565b955050604088013581811115611fbe57600080fd5b8801601f81018a13611fcf57600080fd5b8035611fdd611eeb82611ea6565b81815260059190911b8201840190848101908c831115611ffc57600080fd5b928501925b8284101561202357833561201481611f35565b82529285019290850190612001565b9650505050606088013591508082111561203c57600080fd5b5061204988828901611eca565b9150509295509295909350565b73ffffffffffffffffffffffffffffffffffffffff81168114611f4457600080fd5b8035610e6381612056565b60008060006060848603121561209857600080fd5b83356120a381612056565b925060208401356120b381612056565b929592945050506040919091013590565b61ffff81168114611f4457600080fd5b8035610e63816120c4565b8015158114611f4457600080fd5b8035610e63816120df565b6000610100828403121561210b57600080fd5b612113611c38565b82358152602083013561212581612056565b6020820152604083013561213881611f35565b6040820152612149606084016120d4565b606082015261215a608084016120ed565b608082015261216b60a084016120ed565b60a082015261217c60c08401612078565b60c082015261218d60e08401612078565b60e08201529392505050565b60005b838110156121b457818101518382015260200161219c565b83811115610c8e5750506000910152565b600081518084526121dd816020860160208601612199565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152600061179d60208301846121c5565b6000808585111561223257600080fd5b8386111561223f57600080fd5b5050820193919092039150565b60408152600c60408201527f537061726b5061796261636b0000000000000000000000000000000000000000606082015260806020820152600061179d60808301846121c5565b8051610e6381612056565b6000602082840312156122b057600080fd5b815161179d81612056565b80356020831015610b2c577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff602084900360031b1b1692915050565b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000081358181169160148510156123375780818660140360031b1b83161692505b505092915050565b7fff0000000000000000000000000000000000000000000000000000000000000081358181169160018510156123375760019490940360031b84901b1690921692915050565b7fffff00000000000000000000000000000000000000000000000000000000000081358181169160028510156123375760029490940360031b84901b1690921692915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561240d5761240d6123cb565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8051610e63816120c4565b8051610e63816120df565b6000610100828403121561246a57600080fd5b612472611c38565b82518152602083015161248481612056565b6020820152604083015161249781611f35565b60408201526124a860608401612441565b60608201526124b96080840161244c565b60808201526124ca60a0840161244c565b60a08201526124db60c08401612293565b60c082015261218d60e08401612293565b600083516124fe818460208801612199565b9190910191825250602001919050565b60008351612520818460208801612199565b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000939093169190920190815260140192915050565b60008351612567818460208801612199565b7fff00000000000000000000000000000000000000000000000000000000000000939093169190920190815260010192915050565b600083516125ae818460208801612199565b7fffff000000000000000000000000000000000000000000000000000000000000939093169190920190815260020192915050565b6000602082840312156125f557600080fd5b5051919050565b60008282101561260e5761260e6123cb565b500390565b60008060008060008060008060006101208a8c03121561263257600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a015164ffffffffff8116811461267857600080fd5b6101008b015190925061268a816120df565b809150509295985092959850929598565b600060ff821660ff8416808210156126b5576126b56123cb565b90039392505050565b6000602082840312156126d057600080fd5b815161179d816120df565b600082516126ed818460208701612199565b919091019291505056fea2646970667358221220ab049d7d19e200280efbaf171bb2e519f22e95ebd1e48a518f1eb7dbaeaad3df64736f6c634300080a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 27 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.