Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Multi Chain
Multichain Addresses
0 address found via
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x60c06040 | 13366659 | 605 days 17 hrs ago | IN | Create: ExecFacet | 0 ETH | 0.22938006 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ExecFacet
Compiler Version
v0.8.0+commit.c7dfd78e
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; import {BFacetOwner} from "../facets/base/BFacetOwner.sol"; import {LibAddress} from "../libraries/LibAddress.sol"; import {LibDiamond} from "../libraries/standard/LibDiamond.sol"; import {LibExecutor} from "../libraries/LibExecutor.sol"; import { EnumerableSet } from "../../vendor/openzeppelin/contracts/utils/EnumerableSet.sol"; import {GelatoBytes} from "../../lib/GelatoBytes.sol"; import {GelatoString} from "../../lib/GelatoString.sol"; import {getBalance} from "../../vendor/utils/Utils.sol"; import {_getCappedGasPrice} from "../../functions/gelato/FGelato.sol"; import {IGelatoV1} from "../../interfaces/gelato/IGelatoV1.sol"; import {ETH} from "../../constants/CTokens.sol"; import {IOracleAggregator} from "../../interfaces/gelato/IOracleAggregator.sol"; contract ExecFacet is BFacetOwner { using LibDiamond for address; using LibExecutor for address; using GelatoBytes for bytes; using EnumerableSet for EnumerableSet.AddressSet; using GelatoString for string; // solhint-disable var-name-mixedcase uint256 public constant GAS_OVERHEAD = 40000; IGelatoV1 public immutable GELATO_V1; address public immutable GELATO_PROVIDER; // solhint-enable var-name-mixedcase event LogExecSuccess( address indexed executor, address indexed service, bool indexed wasExecutorPaid ); event LogSetGasMargin(uint256 oldGasMargin, uint256 newGasMargin); constructor(IGelatoV1 _gelatoV1, address _gelatoProvider) { GELATO_V1 = _gelatoV1; GELATO_PROVIDER = _gelatoProvider; } // ################ Callable by Gov ################ function addExecutors(address[] calldata _executors) external onlyOwner { for (uint256 i; i < _executors.length; i++) require(_executors[i].addExecutor(), "ExecFacet.addExecutors"); } function addBundleExecutors(address[] calldata _bundleExecutors) external onlyOwner { for (uint256 i; i < _bundleExecutors.length; i++) require( _bundleExecutors[i].addBundleExecutor(), "ExecFacet.addBundleExecutors" ); } function removeExecutors(address[] calldata _executors) external { for (uint256 i; i < _executors.length; i++) { require( msg.sender == _executors[i] || msg.sender.isContractOwner(), "ExecFacet.removeExecutors: msg.sender ! executor || owner" ); require( _executors[i].removeExecutor(), "ExecFacet.removeExecutors" ); } } function removeBundleExecutors(address[] calldata _bundleExecutors) external { for (uint256 i; i < _bundleExecutors.length; i++) { require( msg.sender == _bundleExecutors[i] || msg.sender.isContractOwner(), "ExecFacet.removeBundleExecutors: msg.sender ! bundleExecutor || owner" ); require( _bundleExecutors[i].removeBundleExecutor(), "ExecFacet.removeBundleExecutors" ); } } function setGasMargin(uint256 _gasMargin) external onlyOwner { emit LogSetGasMargin(gasMargin(), _gasMargin); LibExecutor.setGasMargin(_gasMargin); } // solhint-disable function-max-lines // ################ Callable by Executor ################ /// @dev * reverts if Executor overcharges users /// * assumes honest executors /// * verifying correct fee can be removed after staking/slashing /// was introduced // solhint-disable-next-line code-complexity function exec( address _service, bytes calldata _data, address _creditToken ) external { uint256 startGas = gasleft(); require( msg.sender.isExecutor() || msg.sender.isBundleExecutor(), "ExecFacet.exec: onlyExecutors || onlyBundleExecutors" ); if (_service == address(GELATO_V1)) _creditToken = ETH; uint256 preCreditTokenBalance = getBalance(_creditToken, address(this)); (bool success, bytes memory returndata) = _service.call(_data); if (!success) returndata.revertWithError("ExecFacet.exec:"); // Needs to be here in case service relies on GelatoV1 built-in provider ETH payments if (_service == address(GELATO_V1)) GELATO_V1.withdrawExcessExecutorStake(type(uint256).max); uint256 postCreditTokenBalance = getBalance( _creditToken, address(this) ); // TO DO: remove and replace with executor payments based on what services paid out require( postCreditTokenBalance > preCreditTokenBalance, "ExecFacet.exec: postCreditTokenBalance < preCreditTokenBalance" ); uint256 credit = postCreditTokenBalance - preCreditTokenBalance; uint256 gasDebitInETH = (startGas - gasleft() + GAS_OVERHEAD) * _getCappedGasPrice(LibAddress.getGasPriceOracle()); uint256 gasDebitInCreditToken; if (_creditToken == ETH) gasDebitInCreditToken = gasDebitInETH; else { (gasDebitInCreditToken, ) = IOracleAggregator( LibAddress.getOracleAggregator() ).getExpectedReturnAmount(gasDebitInETH, ETH, _creditToken); } require( gasDebitInCreditToken != 0, "ExecFacet.exec: _creditToken not on OracleAggregator" ); uint256 _gasMargin_ = gasMargin(); require( credit <= gasDebitInCreditToken + (gasDebitInCreditToken * _gasMargin_) / 100, "ExecFacet.exec: Executor Overcharged" ); if (_service == address(GELATO_V1)) if (abi.decode(_data[68:100], (address)) == GELATO_PROVIDER) { // solhint-disable no-empty-blocks try GELATO_V1.provideFunds{value: credit}(GELATO_PROVIDER) {} catch {} // solhint-enable no-empty-blocks } /// TO DO: pay executors based 1:1 on what services paid gelato in ETH equivalents (success, ) = msg.sender.call{ value: gasDebitInETH + (gasDebitInETH * _gasMargin_) / 100 }(""); emit LogExecSuccess(msg.sender, _service, success); } function estimateExecGasDebit( address _service, bytes calldata _data, address _creditToken ) external returns (uint256 gasDebitInETH, uint256 gasDebitInCreditToken) { uint256 startGas = gasleft(); require( msg.sender.isExecutor() || msg.sender.isBundleExecutor(), "ExecFacet.exec: onlyExecutors || onlyBundleExecutors" ); if (_service == address(GELATO_V1)) _creditToken = ETH; uint256 preCreditTokenBalance = getBalance(_creditToken, address(this)); (bool success, bytes memory returndata) = _service.call(_data); if (!success) returndata.revertWithError("ExecFacet.exec:"); // Needs to be here in case service relies on GelatoV1 built-in provider ETH payments if (_service == address(GELATO_V1)) GELATO_V1.withdrawExcessExecutorStake(type(uint256).max); uint256 postCreditTokenBalance = getBalance( _creditToken, address(this) ); uint256 credit = postCreditTokenBalance - preCreditTokenBalance; credit; gasDebitInETH = (startGas - gasleft() + GAS_OVERHEAD) * _getCappedGasPrice(LibAddress.getGasPriceOracle()); if (_creditToken == ETH) gasDebitInCreditToken = gasDebitInETH; else { (gasDebitInCreditToken, ) = IOracleAggregator( LibAddress.getOracleAggregator() ).getExpectedReturnAmount(gasDebitInETH, ETH, _creditToken); } } function canExec(address _executor) external view returns (bool) { return _executor.canExec(); } function isExecutor(address _executor) external view returns (bool) { return _executor.isExecutor(); } function isBundleExecutor(address _bundleExecutor) external view returns (bool) { return _bundleExecutor.isBundleExecutor(); } function executors() external view returns (address[] memory) { return LibExecutor.executors(); } function bundleExecutors() external view returns (address[] memory) { return LibExecutor.bundleExecutors(); } function numberOfExecutors() external view returns (uint256) { return LibExecutor.numberOfExecutors(); } function numberOfBundleExecutors() external view returns (uint256) { return LibExecutor.numberOfBundleExecutors(); } function gasMargin() public view returns (uint256) { return LibExecutor.gasMargin(); } }
// "SPDX-License-Identifier: UNLICENSED" pragma solidity >=0.6.10; pragma experimental ABIEncoderV2; /// @title IGelatoCondition - solidity interface of GelatoConditionsStandard /// @notice all the APIs of GelatoConditionsStandard /// @dev all the APIs are implemented inside GelatoConditionsStandard interface IGelatoCondition { /// @notice GelatoCore calls this to verify securely the specified Condition securely /// @dev Be careful only to encode a Task's condition.data as is and not with the /// "ok" selector or _taskReceiptId, since those two things are handled by GelatoCore. /// @param _taskReceiptId This is passed by GelatoCore so we can rely on it as a secure /// source of Task identification. /// @param _conditionData This is the Condition.data field developers must encode their /// Condition's specific parameters in. /// @param _cycleId For Tasks that are executed as part of a cycle. function ok(uint256 _taskReceiptId, bytes calldata _conditionData, uint256 _cycleId) external view returns(string memory); }
// "SPDX-License-Identifier: UNLICENSED" pragma solidity >=0.6.10; pragma experimental ABIEncoderV2; import {IGelatoProviderModule} from "../../gelato_provider_modules/IGelatoProviderModule.sol"; import {IGelatoCondition} from "../../gelato_conditions/IGelatoCondition.sol"; struct Provider { address addr; // if msg.sender == provider => self-Provider IGelatoProviderModule module; // can be IGelatoProviderModule(0) for self-Providers } struct Condition { IGelatoCondition inst; // can be AddressZero for self-conditional Actions bytes data; // can be bytes32(0) for self-conditional Actions } enum Operation { Call, Delegatecall } enum DataFlow { None, In, Out, InAndOut } struct Action { address addr; bytes data; Operation operation; DataFlow dataFlow; uint256 value; bool termsOkCheck; } struct Task { Condition[] conditions; // optional Action[] actions; uint256 selfProviderGasLimit; // optional: 0 defaults to gelatoMaxGas uint256 selfProviderGasPriceCeil; // optional: 0 defaults to NO_CEIL } struct TaskReceipt { uint256 id; address userProxy; Provider provider; uint256 index; Task[] tasks; uint256 expiryDate; uint256 cycleId; // auto-filled by GelatoCore. 0 for non-cyclic/chained tasks uint256 submissionsLeft; } interface IGelatoCore { event LogTaskSubmitted( uint256 indexed taskReceiptId, bytes32 indexed taskReceiptHash, TaskReceipt taskReceipt ); event LogExecSuccess( address indexed executor, uint256 indexed taskReceiptId, uint256 executorSuccessFee, uint256 sysAdminSuccessFee ); event LogCanExecFailed( address indexed executor, uint256 indexed taskReceiptId, string reason ); event LogExecReverted( address indexed executor, uint256 indexed taskReceiptId, uint256 executorRefund, string reason ); event LogTaskCancelled(uint256 indexed taskReceiptId, address indexed cancellor); /// @notice API to query whether Task can be submitted successfully. /// @dev In submitTask the msg.sender must be the same as _userProxy here. /// @param _provider Gelato Provider object: provider address and module. /// @param _userProxy The userProxy from which the task will be submitted. /// @param _task Selected provider, conditions, actions, expiry date of the task function canSubmitTask( address _userProxy, Provider calldata _provider, Task calldata _task, uint256 _expiryDate ) external view returns(string memory); /// @notice API to submit a single Task. /// @dev You can let users submit multiple tasks at once by batching calls to this. /// @param _provider Gelato Provider object: provider address and module. /// @param _task A Gelato Task object: provider, conditions, actions. /// @param _expiryDate From then on the task cannot be executed. 0 for infinity. function submitTask( Provider calldata _provider, Task calldata _task, uint256 _expiryDate ) external; /// @notice A Gelato Task Cycle consists of 1 or more Tasks that automatically submit /// the next one, after they have been executed. /// @param _provider Gelato Provider object: provider address and module. /// @param _tasks This can be a single task or a sequence of tasks. /// @param _expiryDate After this no task of the sequence can be executed any more. /// @param _cycles How many full cycles will be submitted function submitTaskCycle( Provider calldata _provider, Task[] calldata _tasks, uint256 _expiryDate, uint256 _cycles ) external; /// @notice A Gelato Task Cycle consists of 1 or more Tasks that automatically submit /// the next one, after they have been executed. /// @dev CAUTION: _sumOfRequestedTaskSubmits does not mean the number of cycles. /// @dev If _sumOfRequestedTaskSubmits = 1 && _tasks.length = 2, only the first task /// would be submitted, but not the second /// @param _provider Gelato Provider object: provider address and module. /// @param _tasks This can be a single task or a sequence of tasks. /// @param _expiryDate After this no task of the sequence can be executed any more. /// @param _sumOfRequestedTaskSubmits The TOTAL number of Task auto-submits /// that should have occured once the cycle is complete: /// _sumOfRequestedTaskSubmits = 0 => One Task will resubmit the next Task infinitly /// _sumOfRequestedTaskSubmits = 1 => One Task will resubmit no other task /// _sumOfRequestedTaskSubmits = 2 => One Task will resubmit 1 other task /// ... function submitTaskChain( Provider calldata _provider, Task[] calldata _tasks, uint256 _expiryDate, uint256 _sumOfRequestedTaskSubmits ) external; // ================ Exec Suite ========================= /// @notice Off-chain API for executors to check, if a TaskReceipt is executable /// @dev GelatoCore checks this during execution, in order to safeguard the Conditions /// @param _TR TaskReceipt, consisting of user task, user proxy address and id /// @param _gasLimit Task.selfProviderGasLimit is used for SelfProviders. All other /// Providers must use gelatoMaxGas. If the _gasLimit is used by an Executor and the /// tx reverts, a refund is paid by the Provider and the TaskReceipt is annulated. /// @param _execTxGasPrice Must be used by Executors. Gas Price fed by gelatoCore's /// Gas Price Oracle. Executors can query the current gelatoGasPrice from events. function canExec(TaskReceipt calldata _TR, uint256 _gasLimit, uint256 _execTxGasPrice) external view returns(string memory); /// @notice Executors call this when Conditions allow it to execute submitted Tasks. /// @dev Executors get rewarded for successful Execution. The Task remains open until /// successfully executed, or when the execution failed, despite of gelatoMaxGas usage. /// In the latter case Executors are refunded by the Task Provider. /// @param _TR TaskReceipt: id, userProxy, Task. function exec(TaskReceipt calldata _TR) external; /// @notice Cancel task /// @dev Callable only by userProxy or selected provider /// @param _TR TaskReceipt: id, userProxy, Task. function cancelTask(TaskReceipt calldata _TR) external; /// @notice Cancel multiple tasks at once /// @dev Callable only by userProxy or selected provider /// @param _taskReceipts TaskReceipts: id, userProxy, Task. function multiCancelTasks(TaskReceipt[] calldata _taskReceipts) external; /// @notice Compute hash of task receipt /// @param _TR TaskReceipt, consisting of user task, user proxy address and id /// @return hash of taskReceipt function hashTaskReceipt(TaskReceipt calldata _TR) external pure returns(bytes32); // ================ Getters ========================= /// @notice Returns the taskReceiptId of the last TaskReceipt submitted /// @return currentId currentId, last TaskReceiptId submitted function currentTaskReceiptId() external view returns(uint256); /// @notice Returns computed taskReceipt hash, used to check for taskReceipt validity /// @param _taskReceiptId Id of taskReceipt emitted in submission event /// @return hash of taskReceipt function taskReceiptHash(uint256 _taskReceiptId) external view returns(bytes32); }
// "SPDX-License-Identifier: UNLICENSED" pragma solidity >=0.6.10; pragma experimental ABIEncoderV2; import {Action, Task} from "../gelato_core/interfaces/IGelatoCore.sol"; interface IGelatoProviderModule { /// @notice Check if provider agrees to pay for inputted task receipt /// @dev Enables arbitrary checks by provider /// @param _userProxy The smart contract account of the user who submitted the Task. /// @param _provider The account of the Provider who uses the ProviderModule. /// @param _task Gelato Task to be executed. /// @return "OK" if provider agrees function isProvided(address _userProxy, address _provider, Task calldata _task) external view returns(string memory); /// @notice Convert action specific payload into proxy specific payload /// @dev Encoded multiple actions into a multisend /// @param _taskReceiptId Unique ID of Gelato Task to be executed. /// @param _userProxy The smart contract account of the user who submitted the Task. /// @param _provider The account of the Provider who uses the ProviderModule. /// @param _task Gelato Task to be executed. /// @param _cycleId For Tasks that form part of a cycle/chain. /// @return Encoded payload that will be used for low-level .call on user proxy /// @return checkReturndata if true, fwd returndata from userProxy.call to ProviderModule function execPayload( uint256 _taskReceiptId, address _userProxy, address _provider, Task calldata _task, uint256 _cycleId ) external view returns(bytes memory, bool checkReturndata); /// @notice Called by GelatoCore.exec to verifiy that no revert happend on userProxy /// @dev If a caught revert is detected, this fn should revert with the detected error /// @param _proxyReturndata Data from GelatoCore._exec.userProxy.call(execPayload) function execRevertCheck(bytes calldata _proxyReturndata) external pure; }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.0; uint256 constant DECIMALS_USD = 8; uint256 constant DECIMALS_USDT = 6; uint256 constant DECIMALS_USDC = 6; uint256 constant DECIMALS_DAI = 18; uint256 constant DECIMALS_BUSD = 18; uint256 constant DECIMALS_SUSD = 18; uint256 constant DECIMALS_TUSD = 18; address constant USD = 0x7354C81fbCb229187480c4f497F945C6A312d5C3; // Random address address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; address constant BUSD = 0x4Fabb145d64652a948d72533023f6E7A623C7C53; address constant SUSD = 0x57Ab1ec28D129707052df4dF418D58a2D46d5f51; address constant TUSD = 0x0000000000085d4780B73119b644AE5ecd22b376; address constant AAVE = 0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9; address constant ADX = 0xADE00C28244d5CE17D72E40330B1c318cD12B7c3; address constant BAT = 0x0D8775F648430679A709E98d2b0Cb6250d2887EF; address constant BNB = 0xB8c77482e45F1F44dE1745F52C74426C631bDD52; address constant BNT = 0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C; address constant BZRX = 0x56d811088235F11C8920698a204A5010a788f4b3; address constant COMP = 0xc00e94Cb662C3520282E6f5717214004A7f26888; address constant CRO = 0xA0b73E1Ff0B80914AB6fe0444E65848C4C34450b; address constant DMG = 0xEd91879919B71bB6905f23af0A68d231EcF87b14; address constant ENJ = 0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c; address constant KNC = 0xdd974D5C2e2928deA5F71b9825b8b646686BD200; address constant LINK = 0x514910771AF9Ca656af840dff83E8264EcF986CA; address constant LRC = 0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD; address constant MANA = 0x0F5D2fB29fb7d3CFeE444a200298f468908cC942; address constant MKR = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2; address constant NMR = 0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671; address constant REN = 0x408e41876cCCDC0F92210600ef50372656052a38; address constant REP = 0x221657776846890989a759BA2973e427DfF5C9bB; address constant SNX = 0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F; address constant SXP = 0x8CE9137d39326AD0cD6491fb5CC0CbA0e089b6A9; address constant UNI = 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984; address constant WOM = 0xa982B2e19e90b2D9F7948e9C1b65D119F1CE88D6; address constant YFI = 0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e; address constant ZRX = 0xE41d2489571d322189246DaFA5ebDe1F4699F498;
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; import {LibDiamond} from "../../libraries/standard/LibDiamond.sol"; abstract contract BFacetOwner { modifier onlyOwner() { LibDiamond.enforceIsContractOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; import {IDiamondCut} from "./standard/IDiamondCut.sol"; import {IDiamondLoupe} from "./standard/IDiamondLoupe.sol"; import { TaskReceipt } from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; import {IGelatoV1} from "../../interfaces/gelato/IGelatoV1.sol"; // solhint-disable ordering /// @dev includes the interfaces of all facets interface IGelato { // ########## Diamond Cut Facet ######### event DiamondCut( IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata ); function diamondCut( IDiamondCut.FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; // ########## DiamondLoupeFacet ######### function facets() external view returns (IDiamondLoupe.Facet[] memory facets_); function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_); function facetAddresses() external view returns (address[] memory facetAddresses_); function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_); function supportsInterface(bytes4 _interfaceId) external view returns (bool); // ########## Ownership Facet ######### event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); function transferOwnership(address _newOwner) external; function owner() external view returns (address owner_); // ########## AddressFacet ######### event LogSetOracleAggregator(address indexed oracleAggregator); event LogSetGasPriceOracle(address indexed gasPriceOracle); function setOracleAggregator(address _oracleAggregator) external returns (address); function setGasPriceOracle(address _gasPriceOracle) external returns (address); function getOracleAggregator() external view returns (address); function getGasPriceOracle() external view returns (address); // ########## ConcurrentCanExecFacet ######### enum SlotStatus { Open, Closing, Closed } function setSlotLength(uint256 _slotLength) external; function slotLength() external view returns (uint256); function concurrentCanExec(uint256 _buffer) external view returns (bool); function getCurrentExecutorIndex() external view returns (uint256 executorIndex, uint256 remainingBlocksInSlot); function currentExecutor() external view returns ( address executor, uint256 executorIndex, uint256 remainingBlocksInSlot ); function mySlotStatus(uint256 _buffer) external view returns (SlotStatus); function calcExecutorIndex( uint256 _currentBlock, uint256 _blocksPerSlot, uint256 _numberOfExecutors ) external pure returns (uint256 executorIndex, uint256 remainingBlocksInSlot); // ########## ExecFacet ######### // solhint-disable-next-line func-name-mixedcase function GAS_OVERHEAD() external view returns (uint256); // solhint-disable-next-line func-name-mixedcase function GELATO_V1() external view returns (address); // solhint-disable-next-line func-name-mixedcase function GELATO_PROVIDER() external view returns (address); event LogExecSuccess( address indexed executor, address indexed service, bool indexed wasExecutorPaid ); event LogSetGasMargin(uint256 oldGasMargin, uint256 newGasMargin); function addExecutors(address[] calldata _executors) external; function addBundleExecutors(address[] calldata _bundleExecutors) external; function removeExecutors(address[] calldata _executors) external; function removeBundleExecutors(address[] calldata _bundleExecutors) external; function setGasMargin(uint256 _gasMargin) external; function exec( address _service, bytes calldata _data, address _creditToken ) external; function estimateExecGasDebit( address _service, bytes calldata _data, address _creditToken ) external returns (uint256 gasDebitInETH, uint256 gasDebitInCreditToken); function canExec(address _executor) external view returns (bool); function isExecutor(address _executor) external view returns (bool); function isBundleExecutor(address _bundleExecutor) external view returns (bool); function executors() external view returns (address[] memory); function bundleExecutors() external view returns (address[] memory); function numberOfExecutors() external view returns (uint256); function numberOfBundleExecutors() external view returns (uint256); function gasMargin() external view returns (uint256); // ########## GelatoV1Facet ######### struct Response { uint256 taskReceiptId; uint256 taskGasLimit; string response; } function stakeExecutor(IGelatoV1 _gelatoCore) external payable; function unstakeExecutor(IGelatoV1 _gelatoCore, address payable _to) external; function multiReassignProviders( IGelatoV1 _gelatoCore, address[] calldata _providers, address _newExecutor ) external; function providerRefund( IGelatoV1 _gelatoCore, address _provider, uint256 _amount ) external; function withdrawExcessExecutorStake( IGelatoV1 _gelatoCore, uint256 _withdrawAmount, address payable _to ) external; function v1ConcurrentMultiCanExec( address _gelatoCore, TaskReceipt[] calldata _taskReceipts, uint256 _gelatoGasPrice, uint256 _buffer ) external view returns ( bool canExecRes, uint256 blockNumber, Response[] memory responses ); function v1MultiCanExec( address _gelatoCore, TaskReceipt[] calldata _taskReceipts, uint256 _gelatoGasPrice ) external view returns (uint256 blockNumber, Response[] memory responses); function getGasLimit( TaskReceipt calldata _taskReceipt, uint256 _gelatoMaxGas ) external pure returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ interface IDiamondCut { enum FacetCutAction { Add, Replace, Remove } // Add=0, Replace=1, Remove=2 struct FacetCut { address facetAddress; FacetCutAction action; bytes4[] functionSelectors; } event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata); /// @notice Add/replace/remove any number of functions and optionally execute /// a function with delegatecall /// @param _diamondCut Contains the facet addresses and function selectors /// @param _init The address of the contract or facet to execute _calldata /// @param _calldata A function call, including function selector and arguments /// _calldata is executed with delegatecall on _init function diamondCut( FacetCut[] calldata _diamondCut, address _init, bytes calldata _calldata ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ // A loupe is a small magnifying glass used to look at diamonds. // These functions look at diamonds interface IDiamondLoupe { /// These functions are expected to be called frequently /// by tools. struct Facet { address facetAddress; bytes4[] functionSelectors; } /// @notice Gets all facet addresses and their four byte function selectors. /// @return facets_ Facet function facets() external view returns (Facet[] memory facets_); /// @notice Gets all the function selectors supported by a specific facet. /// @param _facet The facet address. /// @return facetFunctionSelectors_ function facetFunctionSelectors(address _facet) external view returns (bytes4[] memory facetFunctionSelectors_); /// @notice Get all the facet addresses used by a diamond. /// @return facetAddresses_ function facetAddresses() external view returns (address[] memory facetAddresses_); /// @notice Gets the facet that supports the given selector. /// @dev If facet is not found return address(0). /// @param _functionSelector The function selector. /// @return facetAddress_ The facet address. function facetAddress(bytes4 _functionSelector) external view returns (address facetAddress_); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; library LibAddress { struct AddressStorage { address oracleAggregator; address gasPriceOracle; } bytes32 private constant _ADDRESS_STORAGE = keccak256("gelato.diamond.address.storage"); function setOracleAggregator(address _oracleAggregator) internal { LibAddress.addressStorage().oracleAggregator = _oracleAggregator; } function setGasPriceOracle(address _gasPriceOracle) internal { LibAddress.addressStorage().gasPriceOracle = _gasPriceOracle; } function getOracleAggregator() internal view returns (address) { return addressStorage().oracleAggregator; } function getGasPriceOracle() internal view returns (address) { return addressStorage().gasPriceOracle; } function addressStorage() internal pure returns (AddressStorage storage ads) { bytes32 position = _ADDRESS_STORAGE; assembly { ads.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; import { EnumerableSet } from "../../vendor/openzeppelin/contracts/utils/EnumerableSet.sol"; library LibExecutor { using EnumerableSet for EnumerableSet.AddressSet; struct ExecutorStorage { EnumerableSet.AddressSet executors; uint256 gasMargin; EnumerableSet.AddressSet bundleExecutors; } bytes32 private constant _EXECUTOR_STORAGE_POSITION = keccak256("gelato.diamond.executor.storage"); function addExecutor(address _executor) internal returns (bool) { return executorStorage().executors.add(_executor); } function addBundleExecutor(address _bundleExecutor) internal returns (bool) { return executorStorage().bundleExecutors.add(_bundleExecutor); } function removeExecutor(address _executor) internal returns (bool) { return executorStorage().executors.remove(_executor); } function removeBundleExecutor(address _bundleExecutor) internal returns (bool) { return executorStorage().bundleExecutors.remove(_bundleExecutor); } function setGasMargin(uint256 _gasMargin) internal { executorStorage().gasMargin = _gasMargin; } function canExec(address _executor) internal view returns (bool) { return isExecutor(_executor); } function isExecutor(address _executor) internal view returns (bool) { return executorStorage().executors.contains(_executor); } function isBundleExecutor(address _bundleExecutor) internal view returns (bool) { return executorStorage().bundleExecutors.contains(_bundleExecutor); } function executorAt(uint256 _index) internal view returns (address) { return executorStorage().executors.at(_index); } function bundleExecutorAt(uint256 _index) internal view returns (address) { return executorStorage().bundleExecutors.at(_index); } function executors() internal view returns (address[] memory executors_) { uint256 length = numberOfExecutors(); executors_ = new address[](length); for (uint256 i; i < length; i++) executors_[i] = executorAt(i); } function bundleExecutors() internal view returns (address[] memory bundleExecutors_) { uint256 length = numberOfBundleExecutors(); bundleExecutors_ = new address[](length); for (uint256 i; i < length; i++) bundleExecutors_[i] = bundleExecutorAt(i); } function numberOfExecutors() internal view returns (uint256) { return executorStorage().executors.length(); } function numberOfBundleExecutors() internal view returns (uint256) { return executorStorage().bundleExecutors.length(); } function gasMargin() internal view returns (uint256) { return executorStorage().gasMargin; } function executorStorage() internal pure returns (ExecutorStorage storage es) { bytes32 position = _EXECUTOR_STORAGE_POSITION; assembly { es.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; // solhint-disable max-line-length // https://github.com/mudgen/diamond-3/blob/b009cd08b7822bad727bbcc47aa1b50d8b50f7f0/contracts/libraries/LibDiamond.sol#L1 /******************************************************************************\ * Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen) * EIP-2535 Diamond Standard: https://eips.ethereum.org/EIPS/eip-2535 /******************************************************************************/ import "../../interfaces/standard/IDiamondCut.sol"; // Custom due to incorrect string casting (non UTF-8 formatted) import {GelatoBytes} from "../../../lib/GelatoBytes.sol"; library LibDiamond { bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage"); struct FacetAddressAndPosition { address facetAddress; uint16 functionSelectorPosition; // position in facetFunctionSelectors.functionSelectors array } struct FacetFunctionSelectors { bytes4[] functionSelectors; uint16 facetAddressPosition; // position of facetAddress in facetAddresses array } struct DiamondStorage { // maps function selector to the facet address and // the position of the selector in the facetFunctionSelectors.selectors array mapping(bytes4 => FacetAddressAndPosition) selectorToFacetAndPosition; // maps facet addresses to function selectors mapping(address => FacetFunctionSelectors) facetFunctionSelectors; // facet addresses address[] facetAddresses; // Used to query if a contract implements an interface. // Used to implement ERC-165. mapping(bytes4 => bool) supportedInterfaces; // owner of the contract address contractOwner; } function diamondStorage() internal pure returns (DiamondStorage storage ds) { bytes32 position = DIAMOND_STORAGE_POSITION; assembly { ds.slot := position } } event OwnershipTransferred( address indexed previousOwner, address indexed newOwner ); function setContractOwner(address _newOwner) internal { DiamondStorage storage ds = diamondStorage(); address previousOwner = ds.contractOwner; ds.contractOwner = _newOwner; emit OwnershipTransferred(previousOwner, _newOwner); } function contractOwner() internal view returns (address contractOwner_) { contractOwner_ = diamondStorage().contractOwner; } function isContractOwner(address _guy) internal view returns (bool) { return _guy == contractOwner(); } function enforceIsContractOwner() internal view { require( msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner" ); } event DiamondCut( IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata ); // Internal function version of diamondCut function diamondCut( IDiamondCut.FacetCut[] memory _diamondCut, address _init, bytes memory _calldata ) internal { for ( uint256 facetIndex; facetIndex < _diamondCut.length; facetIndex++ ) { IDiamondCut.FacetCutAction action = _diamondCut[facetIndex].action; if (action == IDiamondCut.FacetCutAction.Add) { addFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else if (action == IDiamondCut.FacetCutAction.Replace) { replaceFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else if (action == IDiamondCut.FacetCutAction.Remove) { removeFunctions( _diamondCut[facetIndex].facetAddress, _diamondCut[facetIndex].functionSelectors ); } else { revert("LibDiamondCut: Incorrect FacetCutAction"); } } emit DiamondCut(_diamondCut, _init, _calldata); initializeDiamondCut(_init, _calldata); } function addFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); // uint16 selectorCount = uint16(diamondStorage().selectors.length); require( _facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)" ); uint16 selectorPosition = uint16( ds.facetFunctionSelectors[_facetAddress].functionSelectors.length ); // add new facet address if it does not exist if (selectorPosition == 0) { enforceHasContractCode( _facetAddress, "LibDiamondCut: New facet has no code" ); ds .facetFunctionSelectors[_facetAddress] .facetAddressPosition = uint16(ds.facetAddresses.length); ds.facetAddresses.push(_facetAddress); } for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; require( oldFacetAddress == address(0), "LibDiamondCut: Can't add function that already exists" ); ds.facetFunctionSelectors[_facetAddress].functionSelectors.push( selector ); ds .selectorToFacetAndPosition[selector] .facetAddress = _facetAddress; ds .selectorToFacetAndPosition[selector] .functionSelectorPosition = selectorPosition; selectorPosition++; } } function replaceFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); require( _facetAddress != address(0), "LibDiamondCut: Add facet can't be address(0)" ); uint16 selectorPosition = uint16( ds.facetFunctionSelectors[_facetAddress].functionSelectors.length ); // add new facet address if it does not exist if (selectorPosition == 0) { enforceHasContractCode( _facetAddress, "LibDiamondCut: New facet has no code" ); ds .facetFunctionSelectors[_facetAddress] .facetAddressPosition = uint16(ds.facetAddresses.length); ds.facetAddresses.push(_facetAddress); } for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; require( oldFacetAddress != _facetAddress, "LibDiamondCut: Can't replace function with same function" ); removeFunction(oldFacetAddress, selector); // add function ds .selectorToFacetAndPosition[selector] .functionSelectorPosition = selectorPosition; ds.facetFunctionSelectors[_facetAddress].functionSelectors.push( selector ); ds .selectorToFacetAndPosition[selector] .facetAddress = _facetAddress; selectorPosition++; } } function removeFunctions( address _facetAddress, bytes4[] memory _functionSelectors ) internal { require( _functionSelectors.length > 0, "LibDiamondCut: No selectors in facet to cut" ); DiamondStorage storage ds = diamondStorage(); // if function does not exist then do nothing and return require( _facetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)" ); for ( uint256 selectorIndex; selectorIndex < _functionSelectors.length; selectorIndex++ ) { bytes4 selector = _functionSelectors[selectorIndex]; address oldFacetAddress = ds .selectorToFacetAndPosition[selector] .facetAddress; removeFunction(oldFacetAddress, selector); } } function removeFunction(address _facetAddress, bytes4 _selector) internal { DiamondStorage storage ds = diamondStorage(); require( _facetAddress != address(0), "LibDiamondCut: Can't remove function that doesn't exist" ); // an immutable function is a function defined directly in a diamond require( _facetAddress != address(this), "LibDiamondCut: Can't remove immutable function" ); // replace selector with last selector, then delete last selector uint256 selectorPosition = ds .selectorToFacetAndPosition[_selector] .functionSelectorPosition; uint256 lastSelectorPosition = ds .facetFunctionSelectors[_facetAddress] .functionSelectors .length - 1; // if not the same then replace _selector with lastSelector if (selectorPosition != lastSelectorPosition) { bytes4 lastSelector = ds .facetFunctionSelectors[_facetAddress] .functionSelectors[lastSelectorPosition]; ds.facetFunctionSelectors[_facetAddress].functionSelectors[ selectorPosition ] = lastSelector; ds .selectorToFacetAndPosition[lastSelector] .functionSelectorPosition = uint16(selectorPosition); } // delete the last selector ds.facetFunctionSelectors[_facetAddress].functionSelectors.pop(); delete ds.selectorToFacetAndPosition[_selector]; // if no more selectors for facet address then delete the facet address if (lastSelectorPosition == 0) { // replace facet address with last facet address and delete last facet address uint256 lastFacetAddressPosition = ds.facetAddresses.length - 1; uint256 facetAddressPosition = ds .facetFunctionSelectors[_facetAddress] .facetAddressPosition; if (facetAddressPosition != lastFacetAddressPosition) { address lastFacetAddress = ds.facetAddresses[ lastFacetAddressPosition ]; ds.facetAddresses[facetAddressPosition] = lastFacetAddress; ds .facetFunctionSelectors[lastFacetAddress] .facetAddressPosition = uint16(facetAddressPosition); } ds.facetAddresses.pop(); delete ds .facetFunctionSelectors[_facetAddress] .facetAddressPosition; } } function initializeDiamondCut(address _init, bytes memory _calldata) internal { if (_init == address(0)) { require( _calldata.length == 0, "LibDiamondCut: _init is address(0) but_calldata is not empty" ); } else { require( _calldata.length > 0, "LibDiamondCut: _calldata is empty but _init is not address(0)" ); if (_init != address(this)) { enforceHasContractCode( _init, "LibDiamondCut: _init address has no code" ); } (bool success, bytes memory error) = _init.delegatecall(_calldata); if (!success) { if (error.length > 0) { // bubble up the error GelatoBytes.revertWithError(error, "LibDiamondCut:_init:"); } else { revert("LibDiamondCut: _init function reverted"); } } } } function enforceHasContractCode( address _contract, string memory _errorMessage ) internal view { uint256 contractSize; assembly { contractSize := extcodesize(_contract) } require(contractSize > 0, _errorMessage); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.0; import { IChainlinkOracle } from "../../interfaces/chainlink/IChainlinkOracle.sol"; import {ETH} from "../../constants/CTokens.sol"; import {IOracleAggregator} from "../../interfaces/gelato/IOracleAggregator.sol"; import {IGelato} from "../../diamond/interfaces/IGelato.sol"; function _getGelatoGasPrice(address _gasPriceOracle) view returns (uint256) { return uint256(IChainlinkOracle(_gasPriceOracle).latestAnswer()); } function _getGelatoFee( uint256 _gasOverhead, uint256 _gasStart, address _payToken, address _gelato ) view returns (uint256 gelatoFee) { gelatoFee = (_gasStart - gasleft() + _gasOverhead) * _getCappedGasPrice(IGelato(_gelato).getGasPriceOracle()); if (_payToken == ETH) return gelatoFee; // returns purely the ethereum tx fee (gelatoFee, ) = IOracleAggregator(IGelato(_gelato).getOracleAggregator()) .getExpectedReturnAmount(gelatoFee, ETH, _payToken); } function _getCappedGasPrice(address _gasPriceOracle) view returns (uint256) { uint256 oracleGasPrice = _getGelatoGasPrice(_gasPriceOracle); // Use tx.gasprice capped by 1.3x Chainlink Oracle return tx.gasprice <= ((oracleGasPrice * 130) / 100) ? tx.gasprice : ((oracleGasPrice * 130) / 100); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.0; interface IChainlinkOracle { function latestAnswer() external view returns (int256); function decimals() external view returns (uint256); }
// SPDX-License-Identifier: MIT // solhint-disable pragma solidity >=0.6.10; pragma experimental ABIEncoderV2; import { Action, Provider, Task, DataFlow, TaskReceipt } from "@gelatonetwork/core/contracts/gelato_core/interfaces/IGelatoCore.sol"; // TaskSpec - Will be whitelised by providers and selected by users struct TaskSpec { IGelatoCondition[] conditions; // Address: optional AddressZero for self-conditional actions Action[] actions; uint256 gasPriceCeil; } interface IGelatoV1 { /// @notice API to query whether Task can be submitted successfully. /// @dev In submitTask the msg.sender must be the same as _userProxy here. /// @param _provider Gelato Provider object: provider address and module. /// @param _userProxy The userProxy from which the task will be submitted. /// @param _task Selected provider, conditions, actions, expiry date of the task function canSubmitTask( address _userProxy, Provider calldata _provider, Task calldata _task, uint256 _expiryDate ) external view returns (string memory); /// @notice API to submit a single Task. /// @dev You can let users submit multiple tasks at once by batching calls to this. /// @param _provider Gelato Provider object: provider address and module. /// @param _task A Gelato Task object: provider, conditions, actions. /// @param _expiryDate From then on the task cannot be executed. 0 for infinity. function submitTask( Provider calldata _provider, Task calldata _task, uint256 _expiryDate ) external; /// @notice A Gelato Task Cycle consists of 1 or more Tasks that automatically submit /// the next one, after they have been executed. /// @param _provider Gelato Provider object: provider address and module. /// @param _tasks This can be a single task or a sequence of tasks. /// @param _expiryDate After this no task of the sequence can be executed any more. /// @param _cycles How many full cycles will be submitted function submitTaskCycle( Provider calldata _provider, Task[] calldata _tasks, uint256 _expiryDate, uint256 _cycles ) external; /// @notice A Gelato Task Cycle consists of 1 or more Tasks that automatically submit /// the next one, after they have been executed. /// @dev CAUTION: _sumOfRequestedTaskSubmits does not mean the number of cycles. /// @dev If _sumOfRequestedTaskSubmits = 1 && _tasks.length = 2, only the first task /// would be submitted, but not the second /// @param _provider Gelato Provider object: provider address and module. /// @param _tasks This can be a single task or a sequence of tasks. /// @param _expiryDate After this no task of the sequence can be executed any more. /// @param _sumOfRequestedTaskSubmits The TOTAL number of Task auto-submits /// that should have occured once the cycle is complete: /// _sumOfRequestedTaskSubmits = 0 => One Task will resubmit the next Task infinitly /// _sumOfRequestedTaskSubmits = 1 => One Task will resubmit no other task /// _sumOfRequestedTaskSubmits = 2 => One Task will resubmit 1 other task /// ... function submitTaskChain( Provider calldata _provider, Task[] calldata _tasks, uint256 _expiryDate, uint256 _sumOfRequestedTaskSubmits ) external; // ================ Exec Suite ========================= /// @notice Off-chain API for executors to check, if a TaskReceipt is executable /// @dev GelatoCore checks this during execution, in order to safeguard the Conditions /// @param _TR TaskReceipt, consisting of user task, user proxy address and id /// @param _gasLimit Task.selfProviderGasLimit is used for SelfProviders. All other /// Providers must use gelatoMaxGas. If the _gasLimit is used by an Executor and the /// tx reverts, a refund is paid by the Provider and the TaskReceipt is annulated. /// @param _execTxGasPrice Must be used by Executors. Gas Price fed by gelatoCore's /// Gas Price Oracle. Executors can query the current gelatoGasPrice from events. function canExec( TaskReceipt calldata _TR, uint256 _gasLimit, uint256 _execTxGasPrice ) external view returns (string memory); /// @notice Executors call this when Conditions allow it to execute submitted Tasks. /// @dev Executors get rewarded for successful Execution. The Task remains open until /// successfully executed, or when the execution failed, despite of gelatoMaxGas usage. /// In the latter case Executors are refunded by the Task Provider. /// @param _TR TaskReceipt: id, userProxy, Task. function exec(TaskReceipt calldata _TR) external; /// @notice Cancel task /// @dev Callable only by userProxy or selected provider /// @param _TR TaskReceipt: id, userProxy, Task. function cancelTask(TaskReceipt calldata _TR) external; /// @notice Cancel multiple tasks at once /// @dev Callable only by userProxy or selected provider /// @param _taskReceipts TaskReceipts: id, userProxy, Task. function multiCancelTasks(TaskReceipt[] calldata _taskReceipts) external; /// @notice Compute hash of task receipt /// @param _TR TaskReceipt, consisting of user task, user proxy address and id /// @return hash of taskReceipt function hashTaskReceipt(TaskReceipt calldata _TR) external pure returns (bytes32); // ================ Getters ========================= /// @notice Returns the taskReceiptId of the last TaskReceipt submitted /// @return currentId currentId, last TaskReceiptId submitted function currentTaskReceiptId() external view returns (uint256); /// @notice Returns computed taskReceipt hash, used to check for taskReceipt validity /// @param _taskReceiptId Id of taskReceipt emitted in submission event /// @return hash of taskReceipt function taskReceiptHash(uint256 _taskReceiptId) external view returns (bytes32); /// @notice Stake on Gelato to become a whitelisted executor /// @dev Msg.value has to be >= minExecutorStake function stakeExecutor() external payable; /// @notice Unstake on Gelato to become de-whitelisted and withdraw minExecutorStake function unstakeExecutor() external; /// @notice Re-assigns multiple providers to other executors /// @dev Executors must re-assign all providers before being able to unstake /// @param _providers List of providers to re-assign /// @param _newExecutor Address of new executor to assign providers to function multiReassignProviders( address[] calldata _providers, address _newExecutor ) external; /// @notice Withdraw excess Execur Stake /// @dev Can only be called if executor is isExecutorMinStaked /// @param _withdrawAmount Amount to withdraw /// @return Amount that was actually withdrawn function withdrawExcessExecutorStake(uint256 _withdrawAmount) external returns (uint256); // =========== GELATO PROVIDER APIs ============== /// @notice Validation that checks whether Task Spec is being offered by the selected provider /// @dev Checked in submitTask(), unless provider == userProxy /// @param _provider Address of selected provider /// @param _taskSpec Task Spec /// @return Expected to return "OK" function isTaskSpecProvided(address _provider, TaskSpec calldata _taskSpec) external view returns (string memory); /// @notice Validates that provider has provider module whitelisted + conducts isProvided check in ProviderModule /// @dev Checked in submitTask() if provider == userProxy /// @param _userProxy userProxy passed by GelatoCore during submission and exec /// @param _provider Gelato Provider object: provider address and module. /// @param _task Task defined in IGelatoCore /// @return Expected to return "OK" function providerModuleChecks( address _userProxy, Provider calldata _provider, Task calldata _task ) external view returns (string memory); /// @notice Validate if provider module and seleced TaskSpec is whitelisted by provider /// @dev Combines "isTaskSpecProvided" and providerModuleChecks /// @param _userProxy userProxy passed by GelatoCore during submission and exec /// @param _provider Gelato Provider object: provider address and module. /// @param _task Task defined in IGelatoCore /// @return res Expected to return "OK" function isTaskProvided( address _userProxy, Provider calldata _provider, Task calldata _task ) external view returns (string memory res); /// @notice Validate if selected TaskSpec is whitelisted by provider and that current gelatoGasPrice is below GasPriceCeil /// @dev If gasPriceCeil is != 0, Task Spec is whitelisted /// @param _userProxy userProxy passed by GelatoCore during submission and exec /// @param _provider Gelato Provider object: provider address and module. /// @param _task Task defined in IGelatoCore /// @param _gelatoGasPrice Task Receipt defined in IGelatoCore /// @return res Expected to return "OK" function providerCanExec( address _userProxy, Provider calldata _provider, Task calldata _task, uint256 _gelatoGasPrice ) external view returns (string memory res); // =========== PROVIDER STATE WRITE APIs ============== // Provider Funding /// @notice Deposit ETH as provider on Gelato /// @param _provider Address of provider who receives ETH deposit function provideFunds(address _provider) external payable; /// @notice Withdraw provider funds from gelato /// @param _withdrawAmount Amount /// @return amount that will be withdrawn function unprovideFunds(uint256 _withdrawAmount) external returns (uint256); /// @notice Assign executor as provider /// @param _executor Address of new executor function providerAssignsExecutor(address _executor) external; /// @notice Assign executor as previous selected executor /// @param _provider Address of provider whose executor to change /// @param _newExecutor Address of new executor function executorAssignsExecutor(address _provider, address _newExecutor) external; // (Un-)provide Task Spec /// @notice Whitelist TaskSpecs (A combination of a Condition, Action(s) and a gasPriceCeil) that users can select from /// @dev If gasPriceCeil is == 0, Task Spec will be executed at any gas price (no ceil) /// @param _taskSpecs Task Receipt List defined in IGelatoCore function provideTaskSpecs(TaskSpec[] calldata _taskSpecs) external; /// @notice De-whitelist TaskSpecs (A combination of a Condition, Action(s) and a gasPriceCeil) that users can select from /// @dev If gasPriceCeil was set to NO_CEIL, Input NO_CEIL constant as GasPriceCeil /// @param _taskSpecs Task Receipt List defined in IGelatoCore function unprovideTaskSpecs(TaskSpec[] calldata _taskSpecs) external; /// @notice Update gasPriceCeil of selected Task Spec /// @param _taskSpecHash Result of hashTaskSpec() /// @param _gasPriceCeil New gas price ceil for Task Spec function setTaskSpecGasPriceCeil( bytes32 _taskSpecHash, uint256 _gasPriceCeil ) external; // Provider Module /// @notice Whitelist new provider Module(s) /// @param _modules Addresses of the modules which will be called during providerModuleChecks() function addProviderModules(IGelatoProviderModule[] calldata _modules) external; /// @notice De-Whitelist new provider Module(s) /// @param _modules Addresses of the modules which will be removed function removeProviderModules(IGelatoProviderModule[] calldata _modules) external; // Batch (un-)provide /// @notice Whitelist new executor, TaskSpec(s) and Module(s) in one tx /// @param _executor Address of new executor of provider /// @param _taskSpecs List of Task Spec which will be whitelisted by provider /// @param _modules List of module addresses which will be whitelisted by provider function multiProvide( address _executor, TaskSpec[] calldata _taskSpecs, IGelatoProviderModule[] calldata _modules ) external payable; /// @notice De-Whitelist TaskSpec(s), Module(s) and withdraw funds from gelato in one tx /// @param _withdrawAmount Amount to withdraw from ProviderFunds /// @param _taskSpecs List of Task Spec which will be de-whitelisted by provider /// @param _modules List of module addresses which will be de-whitelisted by provider function multiUnprovide( uint256 _withdrawAmount, TaskSpec[] calldata _taskSpecs, IGelatoProviderModule[] calldata _modules ) external; // =========== PROVIDER STATE READ APIs ============== // Provider Funding /// @notice Get balance of provider /// @param _provider Address of provider /// @return Provider Balance function providerFunds(address _provider) external view returns (uint256); /// @notice Get min stake required by all providers for executors to call exec /// @param _gelatoMaxGas Current gelatoMaxGas /// @param _gelatoGasPrice Current gelatoGasPrice /// @return How much provider balance is required for executor to submit exec tx function minExecProviderFunds( uint256 _gelatoMaxGas, uint256 _gelatoGasPrice ) external view returns (uint256); /// @notice Check if provider has sufficient funds for executor to call exec /// @param _provider Address of provider /// @param _gelatoMaxGas Currentt gelatoMaxGas /// @param _gelatoGasPrice Current gelatoGasPrice /// @return Whether provider is liquid (true) or not (false) function isProviderLiquid( address _provider, uint256 _gelatoMaxGas, uint256 _gelatoGasPrice ) external view returns (bool); // Executor Stake /// @notice Get balance of executor /// @param _executor Address of executor /// @return Executor Balance function executorStake(address _executor) external view returns (uint256); /// @notice Check if executor has sufficient stake on gelato /// @param _executor Address of provider /// @return Whether executor has sufficient stake (true) or not (false) function isExecutorMinStaked(address _executor) external view returns (bool); /// @notice Get executor of provider /// @param _provider Address of provider /// @return Provider's executor function executorByProvider(address _provider) external view returns (address); /// @notice Get num. of providers which haved assigned an executor /// @param _executor Address of executor /// @return Count of how many providers assigned the executor function executorProvidersCount(address _executor) external view returns (uint256); /// @notice Check if executor has one or more providers assigned /// @param _executor Address of provider /// @return Where 1 or more providers have assigned the executor function isExecutorAssigned(address _executor) external view returns (bool); // Task Spec and Gas Price Ceil /// @notice The maximum gas price the transaction will be executed with /// @param _provider Address of provider /// @param _taskSpecHash Hash of provider TaskSpec /// @return Max gas price an executor will execute the transaction with in wei function taskSpecGasPriceCeil(address _provider, bytes32 _taskSpecHash) external view returns (uint256); /// @notice Returns the hash of the formatted TaskSpec. /// @dev The action.data field of each Action is stripped before hashing. /// @param _taskSpec TaskSpec /// @return keccak256 hash of encoded condition address and Action List function hashTaskSpec(TaskSpec calldata _taskSpec) external view returns (bytes32); /// @notice Constant used to specify the highest gas price available in the gelato system /// @dev Input 0 as gasPriceCeil and it will be assigned to NO_CEIL /// @return MAX_UINT function NO_CEIL() external pure returns (uint256); // Providers' Module Getters /// @notice Check if inputted module is whitelisted by provider /// @param _provider Address of provider /// @param _module Address of module /// @return true if it is whitelisted function isModuleProvided(address _provider, IGelatoProviderModule _module) external view returns (bool); /// @notice Get all whitelisted provider modules from a given provider /// @param _provider Address of provider /// @return List of whitelisted provider modules function providerModules(address _provider) external view returns (IGelatoProviderModule[] memory); // State Writing /// @notice Assign new gas price oracle /// @dev Only callable by sysAdmin /// @param _newOracle Address of new oracle function setGelatoGasPriceOracle(address _newOracle) external; /// @notice Assign new gas price oracle /// @dev Only callable by sysAdmin /// @param _requestData The encoded payload for the staticcall to the oracle. function setOracleRequestData(bytes calldata _requestData) external; /// @notice Assign new maximum gas limit providers can consume in executionWrapper() /// @dev Only callable by sysAdmin /// @param _newMaxGas New maximum gas limit function setGelatoMaxGas(uint256 _newMaxGas) external; /// @notice Assign new interal gas limit requirement for exec() /// @dev Only callable by sysAdmin /// @param _newRequirement New internal gas requirement function setInternalGasRequirement(uint256 _newRequirement) external; /// @notice Assign new minimum executor stake /// @dev Only callable by sysAdmin /// @param _newMin New minimum executor stake function setMinExecutorStake(uint256 _newMin) external; /// @notice Assign new success share for executors to receive after successful execution /// @dev Only callable by sysAdmin /// @param _percentage New % success share of total gas consumed function setExecutorSuccessShare(uint256 _percentage) external; /// @notice Assign new success share for sysAdmin to receive after successful execution /// @dev Only callable by sysAdmin /// @param _percentage New % success share of total gas consumed function setSysAdminSuccessShare(uint256 _percentage) external; /// @notice Withdraw sysAdmin funds /// @dev Only callable by sysAdmin /// @param _amount Amount to withdraw /// @param _to Address to receive the funds function withdrawSysAdminFunds(uint256 _amount, address payable _to) external returns (uint256); // State Reading /// @notice Unaccounted tx overhead that will be refunded to executors function EXEC_TX_OVERHEAD() external pure returns (uint256); /// @notice Addess of current Gelato Gas Price Oracle function gelatoGasPriceOracle() external view returns (address); /// @notice Getter for oracleRequestData state variable function oracleRequestData() external view returns (bytes memory); /// @notice Gas limit an executor has to submit to get refunded even if actions revert function gelatoMaxGas() external view returns (uint256); /// @notice Internal gas limit requirements ti ensure executor payout function internalGasRequirement() external view returns (uint256); /// @notice Minimum stake required from executors function minExecutorStake() external view returns (uint256); /// @notice % Fee executors get as a reward for a successful execution function executorSuccessShare() external view returns (uint256); /// @notice Total % Fee executors and sysAdmin collectively get as a reward for a successful execution /// @dev Saves a state read function totalSuccessShare() external view returns (uint256); /// @notice Get total fee providers pay executors for a successful execution /// @param _gas Gas consumed by transaction /// @param _gasPrice Current gelato gas price function executorSuccessFee(uint256 _gas, uint256 _gasPrice) external view returns (uint256); /// @notice % Fee sysAdmin gets as a reward for a successful execution function sysAdminSuccessShare() external view returns (uint256); /// @notice Get total fee providers pay sysAdmin for a successful execution /// @param _gas Gas consumed by transaction /// @param _gasPrice Current gelato gas price function sysAdminSuccessFee(uint256 _gas, uint256 _gasPrice) external view returns (uint256); /// @notice Get sysAdminds funds function sysAdminFunds() external view returns (uint256); } /// @title IGelatoCondition - solidity interface of GelatoConditionsStandard /// @notice all the APIs of GelatoConditionsStandard /// @dev all the APIs are implemented inside GelatoConditionsStandard interface IGelatoCondition { /// @notice GelatoCore calls this to verify securely the specified Condition securely /// @dev Be careful only to encode a Task's condition.data as is and not with the /// "ok" selector or _taskReceiptId, since those two things are handled by GelatoCore. /// @param _taskReceiptId This is passed by GelatoCore so we can rely on it as a secure /// source of Task identification. /// @param _conditionData This is the Condition.data field developers must encode their /// Condition's specific parameters in. /// @param _cycleId For Tasks that are executed as part of a cycle. function ok( uint256 _taskReceiptId, bytes calldata _conditionData, uint256 _cycleId ) external view returns (string memory); } /// @notice all the APIs and events of GelatoActionsStandard /// @dev all the APIs are implemented inside GelatoActionsStandard interface IGelatoAction { /// @notice Providers can use this for pre-execution sanity checks, to prevent reverts. /// @dev GelatoCore checks this in canExec and passes the parameters. /// @param _taskReceiptId The id of the task from which all arguments are passed. /// @param _userProxy The userProxy of the task. Often address(this) for delegatecalls. /// @param _actionData The encoded payload to be used in the Action. /// @param _dataFlow The dataFlow of the Action. /// @param _value A special param for ETH sending Actions. If the Action sends ETH /// in its Action function implementation, one should expect msg.value therein to be /// equal to _value. So Providers can check in termsOk that a valid ETH value will /// be used because they also have access to the same value when encoding the /// execPayload on their ProviderModule. /// @param _cycleId For tasks that are part of a Cycle. /// @return Returns OK, if Task can be executed safely according to the Provider's /// terms laid out in this function implementation. function termsOk( uint256 _taskReceiptId, address _userProxy, bytes calldata _actionData, DataFlow _dataFlow, uint256 _value, uint256 _cycleId ) external view returns (string memory); } interface IGelatoProviderModule { /// @notice Check if provider agrees to pay for inputted task receipt /// @dev Enables arbitrary checks by provider /// @param _userProxy The smart contract account of the user who submitted the Task. /// @param _provider The account of the Provider who uses the ProviderModule. /// @param _task Gelato Task to be executed. /// @return "OK" if provider agrees function isProvided( address _userProxy, address _provider, Task calldata _task ) external view returns (string memory); /// @notice Convert action specific payload into proxy specific payload /// @dev Encoded multiple actions into a multisend /// @param _taskReceiptId Unique ID of Gelato Task to be executed. /// @param _userProxy The smart contract account of the user who submitted the Task. /// @param _provider The account of the Provider who uses the ProviderModule. /// @param _task Gelato Task to be executed. /// @param _cycleId For Tasks that form part of a cycle/chain. /// @return Encoded payload that will be used for low-level .call on user proxy /// @return checkReturndata if true, fwd returndata from userProxy.call to ProviderModule function execPayload( uint256 _taskReceiptId, address _userProxy, address _provider, Task calldata _task, uint256 _cycleId ) external view returns (bytes memory, bool checkReturndata); /// @notice Called by GelatoCore.exec to verifiy that no revert happend on userProxy /// @dev If a caught revert is detected, this fn should revert with the detected error /// @param _proxyReturndata Data from GelatoCore._exec.userProxy.call(execPayload) function execRevertCheck(bytes calldata _proxyReturndata) external pure; }
// SPDX-License-Identifier: MIT pragma solidity 0.8.0; /** * @dev Interface of the Oracle Aggregator Contract */ interface IOracleAggregator { function getExpectedReturnAmount( uint256 amount, address tokenAddressA, address tokenAddressB ) external view returns (uint256 returnAmount, uint256 decimals); }
// "SPDX-License-Identifier: UNLICENSED" pragma solidity 0.8.0; library GelatoBytes { function calldataSliceSelector(bytes calldata _bytes) internal pure returns (bytes4 selector) { selector = _bytes[0] | (bytes4(_bytes[1]) >> 8) | (bytes4(_bytes[2]) >> 16) | (bytes4(_bytes[3]) >> 24); } function memorySliceSelector(bytes memory _bytes) internal pure returns (bytes4 selector) { selector = _bytes[0] | (bytes4(_bytes[1]) >> 8) | (bytes4(_bytes[2]) >> 16) | (bytes4(_bytes[3]) >> 24); } function revertWithError(bytes memory _bytes, string memory _tracingInfo) internal pure { // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err if (_bytes.length % 32 == 4) { bytes4 selector; assembly { selector := mload(add(0x20, _bytes)) } if (selector == 0x08c379a0) { // Function selector for Error(string) assembly { _bytes := add(_bytes, 68) } revert(string(abi.encodePacked(_tracingInfo, string(_bytes)))); } else { revert( string(abi.encodePacked(_tracingInfo, "NoErrorSelector")) ); } } else { revert( string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata")) ); } } function returnError(bytes memory _bytes, string memory _tracingInfo) internal pure returns (string memory) { // 68: 32-location, 32-length, 4-ErrorSelector, UTF-8 err if (_bytes.length % 32 == 4) { bytes4 selector; assembly { selector := mload(add(0x20, _bytes)) } if (selector == 0x08c379a0) { // Function selector for Error(string) assembly { _bytes := add(_bytes, 68) } return string(abi.encodePacked(_tracingInfo, string(_bytes))); } else { return string(abi.encodePacked(_tracingInfo, "NoErrorSelector")); } } else { return string(abi.encodePacked(_tracingInfo, "UnexpectedReturndata")); } } }
// "SPDX-License-Identifier: UNLICENSED" pragma solidity 0.8.0; library GelatoString { function startsWithOK(string memory _str) internal pure returns (bool) { if ( bytes(_str).length >= 2 && bytes(_str)[0] == "O" && bytes(_str)[1] == "K" ) return true; return false; } function revertWithInfo(string memory _error, string memory _tracingInfo) internal pure { revert(string(abi.encodePacked(_tracingInfo, _error))); } function prefix(string memory _second, string memory _first) internal pure returns (string memory) { return string(abi.encodePacked(_first, _second)); } function suffix(string memory _first, string memory _second) internal pure returns (string memory) { return string(abi.encodePacked(_first, _second)); } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { function decimals() external view returns (uint8 digits); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval( address indexed owner, address indexed spender, uint256 value ); }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /** * @dev Library for managing * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive * types. * * Sets have the following properties: * * - Elements are added, removed, and checked for existence in constant time * (O(1)). * - Elements are enumerated in O(n). No guarantees are made on the ordering. * * ``` * contract Example { * // Add the library methods * using EnumerableSet for EnumerableSet.AddressSet; * * // Declare a set state variable * EnumerableSet.AddressSet private mySet; * } * ``` * * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`) * and `uint256` (`UintSet`) are supported. */ library EnumerableSet { // To implement this library for multiple types with as little code // repetition as possible, we write it in terms of a generic Set type with // bytes32 values. // The Set implementation uses private functions, and user-facing // implementations (such as AddressSet) are just wrappers around the // underlying Set. // This means that we can only create new EnumerableSets for types that fit // in bytes32. struct Set { // Storage of set values bytes32[] _values; // Position of the value in the `values` array, plus 1 because index 0 // means a value is not in the set. mapping(bytes32 => uint256) _indexes; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function _add(Set storage set, bytes32 value) private returns (bool) { if (!_contains(set, value)) { set._values.push(value); // The value is stored at length-1, but we add 1 to all indexes // and use 0 as a sentinel value set._indexes[value] = set._values.length; return true; } else { return false; } } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function _remove(Set storage set, bytes32 value) private returns (bool) { // We read and store the value's index to prevent multiple reads from the same storage slot uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { // Equivalent to contains(set, value) // To delete an element from the _values array in O(1), we swap the element to delete with the last one in // the array, and then remove the last element (sometimes called as 'swap and pop'). // This modifies the order of the array, as noted in {at}. uint256 toDeleteIndex = valueIndex - 1; uint256 lastIndex = set._values.length - 1; // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement. bytes32 lastvalue = set._values[lastIndex]; // Move the last value to the index where the value to delete is set._values[toDeleteIndex] = lastvalue; // Update the index for the moved value set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based // Delete the slot where the moved value was stored set._values.pop(); // Delete the index for the deleted slot delete set._indexes[value]; return true; } else { return false; } } /** * @dev Returns true if the value is in the set. O(1). */ function _contains(Set storage set, bytes32 value) private view returns (bool) { return set._indexes[value] != 0; } /** * @dev Returns the number of values on the set. O(1). */ function _length(Set storage set) private view returns (uint256) { return set._values.length; } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function _at(Set storage set, uint256 index) private view returns (bytes32) { require( set._values.length > index, "EnumerableSet: index out of bounds" ); return set._values[index]; } // Bytes32Set struct Bytes32Set { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _add(set._inner, value); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) { return _remove(set._inner, value); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) { return _contains(set._inner, value); } /** * @dev Returns the number of values in the set. O(1). */ function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) { return _at(set._inner, index); } // AddressSet struct AddressSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(AddressSet storage set, address value) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(AddressSet storage set, address value) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(AddressSet storage set, address value) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } /** * @dev Returns the number of values in the set. O(1). */ function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(AddressSet storage set, uint256 index) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } // UintSet struct UintSet { Set _inner; } /** * @dev Add a value to a set. O(1). * * Returns true if the value was added to the set, that is if it was not * already present. */ function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } /** * @dev Removes a value from a set. O(1). * * Returns true if the value was removed from the set, that is if it was * present. */ function remove(UintSet storage set, uint256 value) internal returns (bool) { return _remove(set._inner, bytes32(value)); } /** * @dev Returns true if the value is in the set. O(1). */ function contains(UintSet storage set, uint256 value) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } /** * @dev Returns the number of values on the set. O(1). */ function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } /** * @dev Returns the value stored at position `index` in the set. O(1). * * Note that there are no guarantees on the ordering of values inside the * array, and it may change when more values are added or removed. * * Requirements: * * - `index` must be strictly less than {length}. */ function at(UintSet storage set, uint256 index) internal view returns (uint256) { return uint256(_at(set._inner, index)); } }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.0; import {ETH} from "../../constants/CTokens.sol"; import {IERC20} from "../../vendor/openzeppelin/contracts/token/ERC20/IERC20.sol"; function getBalance(address token, address user) view returns (uint256) { if (token == ETH) { return user.balance; } else { return IERC20(token).balanceOf(user); } }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IGelatoV1","name":"_gelatoV1","type":"address"},{"internalType":"address","name":"_gelatoProvider","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"service","type":"address"},{"indexed":true,"internalType":"bool","name":"wasExecutorPaid","type":"bool"}],"name":"LogExecSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"oldGasMargin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newGasMargin","type":"uint256"}],"name":"LogSetGasMargin","type":"event"},{"inputs":[],"name":"GAS_OVERHEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GELATO_PROVIDER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GELATO_V1","outputs":[{"internalType":"contract IGelatoV1","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_bundleExecutors","type":"address[]"}],"name":"addBundleExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_executors","type":"address[]"}],"name":"addExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"bundleExecutors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_executor","type":"address"}],"name":"canExec","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_service","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_creditToken","type":"address"}],"name":"estimateExecGasDebit","outputs":[{"internalType":"uint256","name":"gasDebitInETH","type":"uint256"},{"internalType":"uint256","name":"gasDebitInCreditToken","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_service","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_creditToken","type":"address"}],"name":"exec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"executors","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasMargin","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_bundleExecutor","type":"address"}],"name":"isBundleExecutor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_executor","type":"address"}],"name":"isExecutor","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfBundleExecutors","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numberOfExecutors","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"_bundleExecutors","type":"address[]"}],"name":"removeBundleExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_executors","type":"address[]"}],"name":"removeExecutors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasMargin","type":"uint256"}],"name":"setGasMargin","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60c06040523480156200001157600080fd5b506040516200200f3803806200200f833981016040819052620000349162000053565b6001600160601b0319606092831b8116608052911b1660a052620000aa565b6000806040838503121562000066578182fd5b8251620000738162000091565b6020840151909250620000868162000091565b809150509250929050565b6001600160a01b0381168114620000a757600080fd5b50565b60805160601c60a05160601c611ef36200011c600039600081816104900152818161093e01526109dc01526000818161058901528181610683015281816106d201528181610904015281816109ad01528181610b2c01528181610c2601528181610c750152610f380152611ef36000f3fe608060405234801561001057600080fd5b50600436106101165760003560e01c80639f80fd92116100a2578063b9880caa11610071578063b9880caa1461020f578063dc09c3e414610230578063debfda3014610243578063e52e63c514610256578063f56b75fc1461025e57610116565b80639f80fd92146101ce578063a730cdfb146101e1578063afda35cb146101e9578063b87b0b4c146101fc57610116565b80631ecd9cd8116100e95780631ecd9cd814610169578063334328351461017c578063454b5d0514610191578063489a095c146101a65780638830bb87146101ae57610116565b8063143aebca1461011b5780631499e05b14610130578063156a08d91461014e57806317f255b914610161575b600080fd5b61012e6101293660046117e4565b610266565b005b6101386102fb565b6040516101459190611d5d565b60405180910390f35b61012e61015c3660046117e4565b61030a565b6101386103fd565b61012e6101773660046117e4565b610407565b61018461048e565b6040516101459190611953565b6101996104b2565b6040516101459190611967565b6101386104bc565b6101c16101bc366004611735565b6104c6565b60405161014591906119b4565b61012e6101dc36600461186b565b6104e0565b610138610534565b6101c16101f7366004611735565b61053a565b61012e61020a366004611751565b61054e565b61022261021d366004611751565b610aee565b604051610145929190611d85565b61012e61023e3660046117e4565b610e25565b6101c1610251366004611735565b610f18565b610199610f2c565b610184610f36565b61026e610f5a565b60005b818110156102f6576102bf83838381811061029c57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906102b19190611735565b6001600160a01b0316610f8f565b6102e45760405162461bcd60e51b81526004016102db90611b6e565b60405180910390fd5b806102ee81611e4d565b915050610271565b505050565b6000610305610fa6565b905090565b60005b818110156102f65782828281811061033557634e487b7160e01b600052603260045260246000fd5b905060200201602081019061034a9190611735565b6001600160a01b0316336001600160a01b0316148061036d575061036d33610fb8565b6103895760405162461bcd60e51b81526004016102db90611a76565b6103cf8383838181106103ac57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906103c19190611735565b6001600160a01b0316610fdd565b6103eb5760405162461bcd60e51b81526004016102db90611c02565b806103f581611e4d565b91505061030d565b6000610305610ff4565b61040f610f5a565b60005b818110156102f65761046083838381811061043d57634e487b7160e01b600052603260045260246000fd5b90506020020160208101906104529190611735565b6001600160a01b0316611007565b61047c5760405162461bcd60e51b81526004016102db90611b3e565b8061048681611e4d565b915050610412565b7f000000000000000000000000000000000000000000000000000000000000000081565b606061030561101b565b60006103056110df565b60006104da826001600160a01b03166110f4565b92915050565b6104e8610f5a565b7f0fed5e5113af1ae14d55c14860dc4992d82f571b9af77ddf73be8f6fd869c69d6105116103fd565b82604051610520929190611d85565b60405180910390a16105318161110b565b50565b619c4081565b60006104da826001600160a01b031661111b565b60005a905061055c33611122565b8061056b575061056b336110f4565b6105875760405162461bcd60e51b81526004016102db90611cb4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316856001600160a01b031614156105d95773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee91505b60006105e58330611136565b9050600080876001600160a01b031687876040516106049291906118a6565b6000604051808303816000865af19150503d8060008114610641576040519150601f19603f3d011682016040523d82523d6000602084013e610646565b606091505b5091509150816106815760408051808201909152600f81526e22bc32b1a330b1b2ba1732bc32b19d60891b60208201526106819082906111f1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316886001600160a01b0316141561075d57604051630166f36360e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630b379b18906107099060001990600401611d5d565b602060405180830381600087803b15801561072357600080fd5b505af1158015610737573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075b9190611853565b505b60006107698630611136565b905083811161078a5760405162461bcd60e51b81526004016102db90611ae1565b60006107968583611e06565b905060006107aa6107a5611285565b6112a1565b619c405a6107b8908a611e06565b6107c29190611dbb565b6107cc9190611de7565b905060006001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee14156107fc57508061089a565b6108046112f1565b6001600160a01b0316633c772b6c8373eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8c6040518463ffffffff1660e01b815260040161084793929190611d66565b604080518083038186803b15801561085e57600080fd5b505afa158015610872573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108969190611883565b5090505b806108b75760405162461bcd60e51b81526004016102db90611d08565b60006108c16103fd565b905060646108cf8284611de7565b6108d99190611dd3565b6108e39083611dbb565b8411156109025760405162461bcd60e51b81526004016102db90611c39565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168d6001600160a01b03161415610a31577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168c8c60449060649261097a93929190611d93565b8101906109879190611735565b6001600160a01b03161415610a31576040516328d0cad760e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906328d0cad7908690610a04907f000000000000000000000000000000000000000000000000000000000000000090600401611953565b6000604051808303818588803b158015610a1d57600080fd5b505af193505050508015610a2f575060015b505b336064610a3e8386611de7565b610a489190611dd3565b610a529085611dbb565b604051610a5e90611950565b60006040518083038185875af1925050503d8060008114610a9b576040519150601f19603f3d011682016040523d82523d6000602084013e610aa0565b606091505b5050604051909750871515906001600160a01b038f169033907f300f6143b52cc51ad5dcf9813931eec0d565503b7bf98df212aa0f90c30aca1b90600090a450505050505050505050505050565b60008060005a9050610aff33611122565b80610b0e5750610b0e336110f4565b610b2a5760405162461bcd60e51b81526004016102db90611cb4565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b03161415610b7c5773eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee93505b6000610b888530611136565b9050600080896001600160a01b03168989604051610ba79291906118a6565b6000604051808303816000865af19150503d8060008114610be4576040519150601f19603f3d011682016040523d82523d6000602084013e610be9565b606091505b509150915081610c245760408051808201909152600f81526e22bc32b1a330b1b2ba1732bc32b19d60891b6020820152610c249082906111f1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168a6001600160a01b03161415610d0057604051630166f36360e31b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690630b379b1890610cac9060001990600401611d5d565b602060405180830381600087803b158015610cc657600080fd5b505af1158015610cda573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cfe9190611853565b505b6000610d0c8830611136565b90506000610d1a8583611e06565b9050610d276107a5611285565b619c405a610d359089611e06565b610d3f9190611dbb565b610d499190611de7565b97506001600160a01b03891673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1415610d7857879650610e16565b610d806112f1565b6001600160a01b0316633c772b6c8973eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee8c6040518463ffffffff1660e01b8152600401610dc393929190611d66565b604080518083038186803b158015610dda57600080fd5b505afa158015610dee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e129190611883565b5096505b50505050505094509492505050565b60005b818110156102f657828282818110610e5057634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610e659190611735565b6001600160a01b0316336001600160a01b03161480610e885750610e8833610fb8565b610ea45760405162461bcd60e51b81526004016102db90611ba5565b610eea838383818110610ec757634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610edc9190611735565b6001600160a01b031661130a565b610f065760405162461bcd60e51b81526004016102db90611c7d565b80610f1081611e4d565b915050610e28565b60006104da826001600160a01b0316611122565b606061030561131e565b7f000000000000000000000000000000000000000000000000000000000000000081565b610f626113dd565b600401546001600160a01b03163314610f8d5760405162461bcd60e51b81526004016102db90611a34565b565b60006104da82610f9d611401565b60030190611425565b6000610305610fb3611401565b61143a565b6000610fc2611445565b6001600160a01b0316826001600160a01b0316149050919050565b60006104da82610feb611401565b60030190611461565b6000610ffe611401565b60020154905090565b60006104da82611015611401565b90611425565b606060006110276110df565b90508067ffffffffffffffff81111561105057634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611079578160200160208202803683370190505b50915060005b818110156110da5761109081611476565b8382815181106110b057634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152806110d281611e4d565b91505061107f565b505090565b60006103056110ec611401565b60030161143a565b60006104da82611102611401565b6003019061148d565b80611114611401565b6002015550565b60006104da825b60006104da82611130611401565b9061148d565b60006001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee141561116e57506001600160a01b038116316104da565b6040516370a0823160e01b81526001600160a01b038416906370a082319061119a908590600401611953565b60206040518083038186803b1580156111b257600080fd5b505afa1580156111c6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ea9190611853565b9392505050565b602082516111ff9190611e68565b6004141561127457602082015162461bcd60e51b6001600160e01b03198216141561126357604483019250818360405160200161123d9291906118b6565b60408051601f198184030181529082905262461bcd60e51b82526102db916004016119bf565b8160405160200161123d91906118e5565b8060405160200161123d9190611918565b600061128f6114a2565b600101546001600160a01b0316905090565b6000806112ad836114c6565b905060646112bc826082611de7565b6112c69190611dd3565b3a11156112e95760646112da826082611de7565b6112e49190611dd3565b6111ea565b3a9392505050565b60006112fb6114a2565b546001600160a01b0316905090565b60006104da82611318611401565b90611461565b6060600061132a610fa6565b90508067ffffffffffffffff81111561135357634e487b7160e01b600052604160045260246000fd5b60405190808252806020026020018201604052801561137c578160200160208202803683370190505b50915060005b818110156110da5761139381611539565b8382815181106113b357634e487b7160e01b600052603260045260246000fd5b6001600160a01b0390921660209283029190910190910152806113d581611e4d565b915050611382565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c90565b7f7ad725e6d99a082d357ed78c93550a4ac89ca228cbbe8e92f3140a9c2a3effa590565b60006111ea836001600160a01b03841661154d565b60006104da82611597565b600061144f6113dd565b600401546001600160a01b0316919050565b60006111ea836001600160a01b03841661159b565b60006104da82611484611401565b600301906116b8565b60006111ea836001600160a01b0384166116c4565b7fadbe443bead7f1f673a33db18cf1b434b753911cae379d384aa3bd25cd3075d590565b6000816001600160a01b03166350d25bcd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561150157600080fd5b505afa158015611515573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104da9190611853565b60006104da82611547611401565b906116b8565b600061155983836116c4565b61158f575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556104da565b5060006104da565b5490565b600081815260018301602052604081205480156116ae5760006115bf600183611e06565b85549091506000906115d390600190611e06565b905060008660000182815481106115fa57634e487b7160e01b600052603260045260246000fd5b906000526020600020015490508087600001848154811061162b57634e487b7160e01b600052603260045260246000fd5b600091825260209091200155611642836001611dbb565b6000828152600189016020526040902055865487908061167257634e487b7160e01b600052603160045260246000fd5b600190038181906000526020600020016000905590558660010160008781526020019081526020016000206000905560019450505050506104da565b60009150506104da565b60006111ea83836116dc565b60009081526001919091016020526040902054151590565b815460009082106116ff5760405162461bcd60e51b81526004016102db906119f2565b82600001828154811061172257634e487b7160e01b600052603260045260246000fd5b9060005260206000200154905092915050565b600060208284031215611746578081fd5b81356111ea81611ea8565b60008060008060608587031215611766578283fd5b843561177181611ea8565b9350602085013567ffffffffffffffff8082111561178d578485fd5b818701915087601f8301126117a0578485fd5b8135818111156117ae578586fd5b8860208285010111156117bf578586fd5b60208301955080945050505060408501356117d981611ea8565b939692955090935050565b600080602083850312156117f6578182fd5b823567ffffffffffffffff8082111561180d578384fd5b818501915085601f830112611820578384fd5b81358181111561182e578485fd5b8660208083028501011115611841578485fd5b60209290920196919550909350505050565b600060208284031215611864578081fd5b5051919050565b60006020828403121561187c578081fd5b5035919050565b60008060408385031215611895578182fd5b505080516020909101519092909150565b6000828483379101908152919050565b600083516118c8818460208801611e1d565b8351908301906118dc818360208801611e1d565b01949350505050565b600082516118f7818460208701611e1d565b6e2737a2b93937b929b2b632b1ba37b960891b920191825250600f01919050565b6000825161192a818460208701611e1d565b73556e657870656374656452657475726e6461746160601b920191825250601401919050565b90565b6001600160a01b0391909116815260200190565b6020808252825182820181905260009190848201906040850190845b818110156119a85783516001600160a01b031683529284019291840191600101611983565b50909695505050505050565b901515815260200190565b60006020825282518060208401526119de816040850160208701611e1d565b601f01601f19169190910160400192915050565b60208082526022908201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604082015261647360f01b606082015260800190565b60208082526022908201527f4c69624469616d6f6e643a204d75737420626520636f6e7472616374206f776e60408201526132b960f11b606082015260800190565b60208082526045908201527f4578656346616365742e72656d6f766542756e646c654578656375746f72733a60408201527f206d73672e73656e64657220212062756e646c654578656375746f72207c7c2060608201526437bbb732b960d91b608082015260a00190565b6020808252603e908201527f4578656346616365742e657865633a20706f7374437265646974546f6b656e4260408201527f616c616e6365203c20707265437265646974546f6b656e42616c616e63650000606082015260800190565b6020808252601690820152754578656346616365742e6164644578656375746f727360501b604082015260600190565b6020808252601c908201527f4578656346616365742e61646442756e646c654578656375746f727300000000604082015260600190565b60208082526039908201527f4578656346616365742e72656d6f76654578656375746f72733a206d73672e7360408201527f656e6465722021206578656375746f72207c7c206f776e657200000000000000606082015260800190565b6020808252601f908201527f4578656346616365742e72656d6f766542756e646c654578656375746f727300604082015260600190565b60208082526024908201527f4578656346616365742e657865633a204578656375746f72204f7665726368616040820152631c99d95960e21b606082015260800190565b60208082526019908201527f4578656346616365742e72656d6f76654578656375746f727300000000000000604082015260600190565b60208082526034908201527f4578656346616365742e657865633a206f6e6c794578656375746f7273207c7c604082015273206f6e6c7942756e646c654578656375746f727360601b606082015260800190565b60208082526035908201527f4578656346616365742e657865633a20205f637265646974546f6b656e206e6f6040820152743a1037b71027b930b1b632a0b3b3b932b3b0ba37b960591b606082015260800190565b90815260200190565b9283526001600160a01b03918216602084015216604082015260600190565b918252602082015260400190565b60008085851115611da2578182fd5b83861115611dae578182fd5b5050820193919092039150565b60008219821115611dce57611dce611e7c565b500190565b600082611de257611de2611e92565b500490565b6000816000190483118215151615611e0157611e01611e7c565b500290565b600082821015611e1857611e18611e7c565b500390565b60005b83811015611e38578181015183820152602001611e20565b83811115611e47576000848401525b50505050565b6000600019821415611e6157611e61611e7c565b5060010190565b600082611e7757611e77611e92565b500690565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b6001600160a01b038116811461053157600080fdfea2646970667358221220b3d16c877665985fe9a1001c68ead3139cf8ffb1bc14bed23fde3d90ec7350e064736f6c63430008000033000000000000000000000000025030bdaa159f281cae63873e68313a703725a50000000000000000000000003d9a46b5d421bb097ac28b4f70a4a1441a12920c
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000025030bdaa159f281cae63873e68313a703725a50000000000000000000000003d9a46b5d421bb097ac28b4f70a4a1441a12920c
-----Decoded View---------------
Arg [0] : _gelatoV1 (address): 0x025030BdAa159f281cAe63873E68313a703725A5
Arg [1] : _gelatoProvider (address): 0x3d9A46b5D421bb097AC28B4f70a4A1441A12920C
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000025030bdaa159f281cae63873e68313a703725a5
Arg [1] : 0000000000000000000000003d9a46b5d421bb097ac28b4f70a4a1441a12920c
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
[ 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.