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 | ||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 14004717 | 505 days 17 hrs ago | IN | Create: ExecFacet | 0 ETH | 0.13175303 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ExecFacet
Compiler Version
v0.8.10+commit.fc410830
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {LibAddress} from "../libraries/diamond/LibAddress.sol"; import {LibDiamond} from "../libraries/diamond/standard/LibDiamond.sol"; import {LibExecAccess} from "../libraries/diamond/LibExecAccess.sol"; import {LibExecAccounting} from "../libraries/diamond/LibExecAccounting.sol"; import {_execServiceCall} from "../functions/FExec.sol"; contract ExecFacet { using LibAddress for address; using LibDiamond for address; using LibExecAccess for address; event LogExecSuccess( address indexed executor, address indexed service, address creditToken, uint256 credit, uint256 gasDebitInCreditToken, uint256 gasDebitInNativeToken ); // 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 returns ( uint256 credit, uint256 gasDebitInNativeToken, uint256 gasDebitInCreditToken, uint256 estimatedGasUsed ) { uint256 startGas = gasleft(); require(msg.sender.canExec(), "ExecFacet.exec: canExec"); credit = _execServiceCall(address(this), _service, _data, _creditToken); gasDebitInNativeToken = LibExecAccounting.getGasDebitInNativeToken( startGas, gasleft() ); gasDebitInCreditToken = LibExecAccounting.getGasDebitInCreditToken( credit, _creditToken, gasDebitInNativeToken, LibAddress.getOracleAggregator() ); require( credit <= gasDebitInCreditToken + (gasDebitInCreditToken * LibExecAccess.gasMargin()) / 100, "ExecFacet.exec: Executor Overcharged" ); emit LogExecSuccess( msg.sender, _service, _creditToken, credit, gasDebitInCreditToken, gasDebitInNativeToken ); estimatedGasUsed = startGas - gasleft(); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; /** * @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; if (lastIndex != toDeleteIndex) { 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] = valueIndex; // Replace lastvalue's index to valueIndex } // 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) { return set._values[index]; } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function _values(Set storage set) private view returns (bytes32[] memory) { return set._values; } // 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); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(Bytes32Set storage set) internal view returns (bytes32[] memory) { return _values(set._inner); } // 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)))); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(AddressSet storage set) internal view returns (address[] memory) { bytes32[] memory store = _values(set._inner); address[] memory result; assembly { result := store } return result; } // 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)); } /** * @dev Return the entire set in an array * * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that * this function has an unbounded cost, and using it as part of a state-changing function may render the function * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block. */ function values(UintSet storage set) internal view returns (uint256[] memory) { bytes32[] memory store = _values(set._inner); uint256[] memory result; assembly { result := store } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; uint256 constant GAS_OVERHEAD = 40000;
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; address constant NATIVE_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {_getBalance} from "./FUtils.sol"; import {GelatoBytes} from "../libraries/GelatoBytes.sol"; function _execServiceCall( address _gelato, address _service, bytes calldata _data, address _creditToken ) returns (uint256 credit) { uint256 preCreditTokenBalance = _getBalance(_creditToken, _gelato); _prepaidExecServiceCall(_service, _data); uint256 postCreditTokenBalance = _getBalance(_creditToken, _gelato); credit = postCreditTokenBalance - preCreditTokenBalance; } function _prepaidExecServiceCall(address _service, bytes calldata _data) { (bool success, bytes memory returndata) = _service.call(_data); if (!success) GelatoBytes.revertWithError( returndata, "LibExecAccess.execContractCall:" ); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import {NATIVE_TOKEN} from "../constants/CTokens.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; function _getBalance(address token, address user) view returns (uint256) { if (token == address(0)) return 0; return token == NATIVE_TOKEN ? user.balance : IERC20(token).balanceOf(user); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; /** * @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: MIT pragma solidity 0.8.10; /******************************************************************************\ * 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.10; 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: MIT pragma solidity 0.8.10; 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.8.10; library LibAddress { struct AddressStorage { address oracleAggregator; } bytes32 private constant _ADDRESS_STORAGE = keccak256("gelato.diamond.address.storage"); function setOracleAggregator(address _oracleAggregator) internal { LibAddress.addressStorage().oracleAggregator = _oracleAggregator; } function getOracleAggregator() internal view returns (address) { return addressStorage().oracleAggregator; } function addressStorage() internal pure returns (AddressStorage storage ads) { bytes32 position = _ADDRESS_STORAGE; assembly { ads.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; library LibExecAccess { 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) || isBundleExecutor(_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.10; import {GelatoString} from "../GelatoString.sol"; import {GAS_OVERHEAD} from "../../constants/CExec.sol"; import {NATIVE_TOKEN} from "../../constants/CTokens.sol"; import {IOracleAggregator} from "../../interfaces/IOracleAggregator.sol"; library LibExecAccounting { using GelatoString for string; struct ExecAccountingStorage { uint256 maxPriorityFee; } bytes32 private constant _EXECUTOR_STORAGE_POSITION = keccak256("gelato.diamond.ExecAccounting.storage"); function setMaxPriorityFee(uint256 _maxPriorityFee) internal { execAccountingStorage().maxPriorityFee = _maxPriorityFee; } function maxPriorityFee() internal view returns (uint256) { return execAccountingStorage().maxPriorityFee; } function getGasDebitInNativeToken(uint256 _gasStart, uint256 _gasEnd) internal view returns (uint256 gasDebitInNativeToken) { uint256 priorityFee = tx.gasprice - block.basefee; uint256 _maxPriorityFee = maxPriorityFee(); uint256 cappedPriorityFee = priorityFee <= _maxPriorityFee ? priorityFee : _maxPriorityFee; // Does not account for gas refunds uint256 estimatedGasUsed = _gasStart - _gasEnd + GAS_OVERHEAD; gasDebitInNativeToken = estimatedGasUsed * (block.basefee + cappedPriorityFee); } function getGasDebitInCreditToken( uint256 _credit, address _creditToken, uint256 _gasDebitInNativeToken, address _oracleAggregator ) internal view returns (uint256 gasDebitInCreditToken) { if (_credit == 0) return 0; try IOracleAggregator(_oracleAggregator).getExpectedReturnAmount( _gasDebitInNativeToken, NATIVE_TOKEN, _creditToken ) returns (uint256 gasDebitInCreditToken_, uint256) { require( gasDebitInCreditToken_ != 0, "LibExecAccess.getGasDebitInCreditToken: _creditToken not on OracleAggregator" ); gasDebitInCreditToken = gasDebitInCreditToken_; } catch Error(string memory err) { err.revertWithInfo( "LibExecAccess.getGasDebitInCreditToken: OracleAggregator:" ); } catch { revert( "LibExecAccess.getGasDebitInCreditToken: OracleAggregator: unknown error" ); } } function execAccountingStorage() internal pure returns (ExecAccountingStorage storage eas) { bytes32 position = _EXECUTOR_STORAGE_POSITION; assembly { eas.slot := position } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.10; // 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/diamond/standard/IDiamondCut.sol"; // Custom due to incorrect string casting (non UTF-8 formatted) import {GelatoBytes} from "../../../libraries/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); } }
{ "evmVersion": "london", "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
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":true,"internalType":"address","name":"service","type":"address"},{"indexed":false,"internalType":"address","name":"creditToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"credit","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasDebitInCreditToken","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasDebitInNativeToken","type":"uint256"}],"name":"LogExecSuccess","type":"event"},{"inputs":[{"internalType":"address","name":"_service","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"address","name":"_creditToken","type":"address"}],"name":"exec","outputs":[{"internalType":"uint256","name":"credit","type":"uint256"},{"internalType":"uint256","name":"gasDebitInNativeToken","type":"uint256"},{"internalType":"uint256","name":"gasDebitInCreditToken","type":"uint256"},{"internalType":"uint256","name":"estimatedGasUsed","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50610b95806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063b87b0b4c14610030575b600080fd5b61004361003e3660046107c5565b610067565b60408051948552602085019390935291830152606082015260800160405180910390f35b60008060008060005a905061007b33610239565b6100cc5760405162461bcd60e51b815260206004820152601760248201527f4578656346616365742e657865633a2063616e4578656300000000000000000060448201526064015b60405180910390fd5b6100d9308a8a8a8a610259565b94506100e5815a610297565b935061012385878661011e7fadbe443bead7f1f673a33db18cf1b434b753911cae379d384aa3bd25cd3075d5546001600160a01b031690565b610320565b9250606461014f7f7ad725e6d99a082d357ed78c93550a4ac89ca228cbbe8e92f3140a9c2a3effa75490565b610159908561086f565b61016391906108a4565b61016d90846108b8565b8511156101c85760405162461bcd60e51b8152602060048201526024808201527f4578656346616365742e657865633a204578656375746f72204f7665726368616044820152631c99d95960e21b60648201526084016100c3565b604080516001600160a01b0388811682526020820188905291810185905260608101869052908a169033907f66c4011e59db1d425e14edc51069e4f5ec3d042d2a254511a8dbc6e3996c91409060800160405180910390a35a61022b90826108d0565b915050945094509450949050565b60006102448261051b565b80610253575061025382610547565b92915050565b6000806102668388610573565b9050610273868686610631565b600061027f8489610573565b905061028b82826108d0565b98975050505050505050565b6000806102a4483a6108d0565b905060006102d07fe2d520f241e0a2a2ca6bf761ac409a1cc33698ceb62dd4caccaee9cdf550cc345490565b90506000818311156102e257816102e4565b825b90506000619c406102f587896108d0565b6102ff91906108b8565b905061030b82486108b8565b610315908261086f565b979650505050505050565b60008461032f57506000610513565b604051630f1dcadb60e21b81526004810184905273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee60248201526001600160a01b038581166044830152831690633c772b6c906064016040805180830381865afa9250505080156103b1575060408051601f3d908101601f191682019092526103ae918101906108e7565b60015b610486576103bd61090b565b806308c379a0141561040657506103d2610962565b806103dd5750610408565b610400604051806060016040528060398152602001610b276039913982906106e0565b50610513565b505b60405162461bcd60e51b815260206004820152604760248201527f4c6962457865634163636573732e6765744761734465626974496e437265646960448201527f74546f6b656e3a204f7261636c6541676772656761746f723a20756e6b6e6f77606482015266371032b93937b960c91b608482015260a4016100c3565b8161050f5760405162461bcd60e51b815260206004820152604d60248201527f4c6962457865634163636573732e6765744761734465626974496e437265646960448201527f74546f6b656e3a20205f637265646974546f6b656e206e6f74206f6e204f726160648201526c31b632a0b3b3b932b3b0ba37b960991b608482015260a4016100c3565b5090505b949350505050565b60006102537f7ad725e6d99a082d357ed78c93550a4ac89ca228cbbe8e92f3140a9c2a3effa583610719565b60006102537f7ad725e6d99a082d357ed78c93550a4ac89ca228cbbe8e92f3140a9c2a3effa883610719565b60006001600160a01b03831661058b57506000610253565b6001600160a01b03831673eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1461061e576040516370a0823160e01b81526001600160a01b0383811660048301528416906370a0823190602401602060405180830381865afa1580156105f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061061991906109ec565b61062a565b816001600160a01b0316315b9392505050565b600080846001600160a01b0316848460405161064e929190610a05565b6000604051808303816000865af19150503d806000811461068b576040519150601f19603f3d011682016040523d82523d6000602084013e610690565b606091505b5091509150816106d9576106d9816040518060400160405280601f81526020017f4c6962457865634163636573732e65786563436f6e747261637443616c6c3a0081525061073b565b5050505050565b80826040516020016106f3929190610a45565b60408051601f198184030181529082905262461bcd60e51b82526100c391600401610a74565b6001600160a01b0381166000908152600183016020526040812054151561062a565b602082516107499190610aa7565b6004141561079857602082015162461bcd60e51b6001600160e01b0319821614156107875760448301925081836040516020016106f3929190610a45565b816040516020016106f39190610abb565b806040516020016106f39190610aee565b80356001600160a01b03811681146107c057600080fd5b919050565b600080600080606085870312156107db57600080fd5b6107e4856107a9565b9350602085013567ffffffffffffffff8082111561080157600080fd5b818701915087601f83011261081557600080fd5b81358181111561082457600080fd5b88602082850101111561083657600080fd5b60208301955080945050505061084e604086016107a9565b905092959194509250565b634e487b7160e01b600052601160045260246000fd5b600081600019048311821515161561088957610889610859565b500290565b634e487b7160e01b600052601260045260246000fd5b6000826108b3576108b361088e565b500490565b600082198211156108cb576108cb610859565b500190565b6000828210156108e2576108e2610859565b500390565b600080604083850312156108fa57600080fd5b505080516020909101519092909150565b600060033d11156109245760046000803e5060005160e01c5b90565b601f8201601f1916810167ffffffffffffffff8111828210171561095b57634e487b7160e01b600052604160045260246000fd5b6040525050565b600060443d10156109705790565b6040516003193d81016004833e81513d67ffffffffffffffff81602484011181841117156109a057505050505090565b82850191508151818111156109b85750505050505090565b843d87010160208285010111156109d25750505050505090565b6109e160208286010187610927565b509095945050505050565b6000602082840312156109fe57600080fd5b5051919050565b8183823760009101908152919050565b60005b83811015610a30578181015183820152602001610a18565b83811115610a3f576000848401525b50505050565b60008351610a57818460208801610a15565b835190830190610a6b818360208801610a15565b01949350505050565b6020815260008251806020840152610a93816040850160208701610a15565b601f01601f19169190910160400192915050565b600082610ab657610ab661088e565b500690565b60008251610acd818460208701610a15565b6e2737a2b93937b929b2b632b1ba37b960891b920191825250600f01919050565b60008251610b00818460208701610a15565b73556e657870656374656452657475726e6461746160601b92019182525060140191905056fe4c6962457865634163636573732e6765744761734465626974496e437265646974546f6b656e3a204f7261636c6541676772656761746f723aa2646970667358221220ab86091421855ecf411330b5e6d477c203a5c7adac2c0d3987e9ea7a4a6f058764736f6c634300080a0033
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.