Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multi Chain
Multichain Addresses
N/ALatest 10 from a total of 10 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Transfer | 7918625 | 322 days 15 hrs ago | IN | 1 ETH | 0.00005001 | ||||
Transfer | 7917959 | 322 days 18 hrs ago | IN | 1 ETH | 0.00133053 | ||||
Whitelist Method | 7917845 | 322 days 18 hrs ago | IN | 0 ETH | 0.00009764 | ||||
Set Post Gas Usa... | 7917790 | 322 days 18 hrs ago | IN | 0 ETH | 0.00018834 | ||||
Set Target | 7917645 | 322 days 19 hrs ago | IN | 0 ETH | 0.00018859 | ||||
Transfer | 7917535 | 322 days 19 hrs ago | IN | 1 ETH | 0.00004938 | ||||
Set Target | 7917369 | 322 days 20 hrs ago | IN | 0 ETH | 0.0001199 | ||||
Set Trusted Forw... | 7917369 | 322 days 20 hrs ago | IN | 0 ETH | 0.00013578 | ||||
Set Relay Hub | 7917369 | 322 days 20 hrs ago | IN | 0 ETH | 0.0001359 | ||||
0x60806040 | 7917365 | 322 days 20 hrs ago | IN | Create: Web3AnalyticsPaymaster | 0 ETH | 0.00486587 |
Latest 25 internal transactions (View All)
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937501 | 146 days 16 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8937092 | 146 days 17 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH | ||||
8936925 | 146 days 18 hrs ago | 0 ETH |
Loading...
Loading
Contract Name:
Web3AnalyticsPaymaster
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 10 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
//SPDX-License-Identifier: Unlicense pragma solidity ^0.8.7; pragma experimental ABIEncoderV2; import "@opengsn/contracts/src/BasePaymaster.sol"; import "./Web3Analytics.sol"; contract Web3AnalyticsPaymaster is BasePaymaster { address public ourTarget; uint256 public gasUsedByPost; mapping(address => mapping(bytes4 => bool)) public methodWhitelist; event FeeCharged(uint256 baseFee, uint256 networkFee, uint256 totalFee); // allow the owner to set target contract we are willing to pay for event TargetSet(address target); function setTarget(address target) external onlyOwner { ourTarget = target; emit TargetSet(target); } // allow the owner to set methods we are willing to pay for function whitelistMethod(address target, bytes4 method, bool isAllowed) public onlyOwner { methodWhitelist[target][method] = isAllowed; } /** * set gas used by postRelayedCall, for proper gas calculation. * You can use TokenGasCalculator to calculate these values * (they depend on actual code of postRelayedCall, */ function setPostGasUsage(uint256 _gasUsedByPost) external onlyOwner { gasUsedByPost = _gasUsedByPost; } function _preRelayedCall( GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature, bytes calldata approvalData, uint256 maxPossibleGas ) internal override virtual returns (bytes memory context, bool revertOnRecipientRevert) { (signature, maxPossibleGas); // only pay for transactions for our contract require(relayRequest.request.to == ourTarget); // check that the method being called is approved bytes4 method = GsnUtils.getMethodSig(relayRequest.request.data); require(methodWhitelist[ourTarget][method], "method not whitelisted"); // get address of app user is registering for (, address app) = abi.decode(relayRequest.request.data[4:], (string, address) ); // check account balance of app to see if has sufficient funds for user registration Web3Analytics w3 = Web3Analytics(ourTarget); uint256 balance = w3.getBalance(app); uint256 maxEstimatedCost = maxPossibleGas * tx.gasprice; uint256 fee = (maxEstimatedCost / 10000) * w3.getNetworkFee(); uint256 price = maxEstimatedCost + fee; require(balance > price, "insufficient app balance"); return (abi.encode(app), false); } function _postRelayedCall( bytes calldata context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData calldata relayData ) internal override virtual { (context, success, gasUseWithoutPost, relayData); // get app address for this transaction (address app) = abi.decode(context, (address) ); // get actual cost of transaction uint256 ethActualCharge = relayHub.calculateCharge( gasUseWithoutPost + gasUsedByPost, relayData); // calculate price including network fee Web3Analytics w3 = Web3Analytics(ourTarget); uint256 fee = (ethActualCharge / 10000) * w3.getNetworkFee(); uint256 price = ethActualCharge + fee; // deduct fee w3.chargeFee(app, price); emit FeeCharged(ethActualCharge, fee, price); } function versionPaymaster() external virtual view override returns (string memory) { return "3.0.0"; } }
//SPDX-License-Identifier: Unlicense pragma solidity ^0.8.7; import "@openzeppelin/contracts/utils/Address.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "@opengsn/contracts/src/ERC2771Recipient.sol"; contract Web3Analytics is ERC2771Recipient, Ownable { using Address for address; using EnumerableSet for EnumerableSet.AddressSet; struct Registration { address userAddress; string userDid; } struct App { address appAddress; string appName; string appUrl; } address private allowedPaymaster; uint256 private feeInBasisPoints; uint256 private minimumAppRegBalance; EnumerableSet.AddressSet private registeredApps; mapping(address => App) private appData; mapping(address => uint256) private appBalances; mapping(address => Registration[]) private appRegistrations; mapping(address => EnumerableSet.AddressSet) private appUsers; /** * @dev the Web3Analytics contract constructor * @param forwarder the trusted forwarder contract address **/ constructor(address forwarder) { _setTrustedForwarder(forwarder); } /** * @dev sets trusted paymaster * @param paymaster the address of our trusted paymaster **/ function setTrustedPaymaster(address paymaster) public onlyOwner { allowedPaymaster = paymaster; } /** * @dev gets trusted paymaster **/ function getTrustedPaymaster() public view returns(address) { return allowedPaymaster; } /** * @dev sets feeInBasisPoints * @param fee the fee in basis points **/ function setNetworkFee(uint256 fee) public onlyOwner { feeInBasisPoints = fee; } /** * @dev gets feeInBasisPoints **/ function getNetworkFee() public view returns(uint256) { return feeInBasisPoints; } /** * @dev sets minimum balance required to register an app * @param balance the minimum balance **/ function setMinimumAppRegBalance(uint256 balance) public onlyOwner { minimumAppRegBalance = balance; } /** * @dev gets minimum balance required to register an app **/ function getMinimumAppRegBalance() public view returns(uint256) { return minimumAppRegBalance; } /** * @dev provides a list of an app's users * @param app the application to retrieve users for **/ function getUsers(address app) public view returns(address[] memory) { return appUsers[app].values(); } /** * @dev provides a count of an app's users * @param app the application to retrieve users for **/ function getUserCount(address app) public view returns(uint256) { return appUsers[app].length(); } /** * @dev provides a list of an app's registrations * @param app the application to retrieve registrations for **/ function getUserRegistrations(address app) public view returns(Registration[] memory) { return appRegistrations[app]; } /** * @dev returns whether app is registered or not * @param app the application to check registration for **/ function isAppRegistered(address app) public view returns(bool) { return registeredApps.contains(app); } /** * @dev returns whether user is registered for given app * @param app the application to check registration for **/ function isUserRegistered(address app, address user) public view returns(bool) { return appUsers[app].contains(user); } /** * @dev provides a count of apps registered **/ function getAppCount() public view returns(uint256) { return registeredApps.length(); } /** * @dev provides a list of apps registered **/ function getApps() public view returns(address[] memory) { return registeredApps.values(); } /** * @dev adds a new user to an app * @param did the did key for the user to add * @param app the address of the app to register user for **/ function addUser(string memory did, address app) public { // app must be registered and user must not exist for app require(registeredApps.contains(app), "App not registered"); require(!appUsers[app].contains(_msgSender()), "User already exists"); appUsers[app].add(_msgSender()); appRegistrations[app].push(Registration(_msgSender(), did)); } /** * @dev registers new app for web3analytics * @param name the name of the app * @param url the app's url (optional) **/ function registerApp(string memory name, string memory url) public payable { require(!registeredApps.contains(_msgSender()), "App already registered"); require(bytes(name).length != 0, "Name is required"); require(msg.value >= minimumAppRegBalance, "Minimum balance to register not met"); registeredApps.add(_msgSender()); appData[_msgSender()] = App(_msgSender(), name, url); } /** * @dev provides app data for registered app * @param app the application to retrieve data for **/ function getAppData(address app) public view returns(App memory) { return appData[app]; } /** * @dev updates app data for registered app * @param name the name of the app * @param url the app's url (optional) **/ function updateAppData(string memory name, string memory url) public { require(registeredApps.contains(_msgSender()), "App not registered"); require(bytes(name).length != 0, "Name is required"); appData[_msgSender()] = App(_msgSender(), name, url); } /** * @dev gets account balance of an app * @param app the application to retrieve balance for **/ function getBalance(address app) public view returns(uint256) { return appBalances[app]; } /** * @dev allows adding value to account balance of an app * @param app the application to add value to **/ function topUpBalance(address app) public payable { require(msg.value > 0, 'Top up must be greater than 0'); appBalances[app] = appBalances[app] + msg.value; } /** * @dev allows deducting value from account balance of an app * @param app the application to charge fee to * @param fee the amount of the fee **/ function chargeFee(address app, uint256 fee) public payable { require(allowedPaymaster != address(0), 'Trusted paymaster must be set'); require(allowedPaymaster == _msgSender(), 'Only trusted paymaster may charge fee'); appBalances[app] = appBalances[app] - fee; } function _msgSender() internal view override(Context, ERC2771Recipient) returns (address sender) { sender = ERC2771Recipient._msgSender(); } function _msgData() internal view override(Context, ERC2771Recipient) returns (bytes memory) { return ERC2771Recipient._msgData(); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165Checker.sol"; import "./utils/GsnTypes.sol"; import "./interfaces/IPaymaster.sol"; import "./interfaces/IRelayHub.sol"; import "./utils/GsnEip712Library.sol"; import "./forwarder/IForwarder.sol"; /** * @notice An abstract base class to be inherited by a concrete Paymaster. * A subclass must implement: * - preRelayedCall * - postRelayedCall */ abstract contract BasePaymaster is IPaymaster, Ownable, ERC165 { using ERC165Checker for address; IRelayHub internal relayHub; address private _trustedForwarder; /// @inheritdoc IPaymaster function getRelayHub() public override view returns (address) { return address(relayHub); } //overhead of forwarder verify+signature, plus hub overhead. uint256 constant public FORWARDER_HUB_OVERHEAD = 50000; //These parameters are documented in IPaymaster.GasAndDataLimits uint256 constant public PRE_RELAYED_CALL_GAS_LIMIT = 100000; uint256 constant public POST_RELAYED_CALL_GAS_LIMIT = 110000; uint256 constant public PAYMASTER_ACCEPTANCE_BUDGET = PRE_RELAYED_CALL_GAS_LIMIT + FORWARDER_HUB_OVERHEAD; uint256 constant public CALLDATA_SIZE_LIMIT = 10500; /// @inheritdoc IERC165 function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { return interfaceId == type(IPaymaster).interfaceId || interfaceId == type(Ownable).interfaceId || super.supportsInterface(interfaceId); } /// @inheritdoc IPaymaster function getGasAndDataLimits() public override virtual view returns ( IPaymaster.GasAndDataLimits memory limits ) { return IPaymaster.GasAndDataLimits( PAYMASTER_ACCEPTANCE_BUDGET, PRE_RELAYED_CALL_GAS_LIMIT, POST_RELAYED_CALL_GAS_LIMIT, CALLDATA_SIZE_LIMIT ); } /** * @notice this method must be called from preRelayedCall to validate that the forwarder * is approved by the paymaster as well as by the recipient contract. */ function _verifyForwarder(GsnTypes.RelayRequest calldata relayRequest) internal virtual view { require(getTrustedForwarder() == relayRequest.relayData.forwarder, "Forwarder is not trusted"); GsnEip712Library.verifyForwarderTrusted(relayRequest); } function _verifyRelayHubOnly() internal virtual view { require(msg.sender == getRelayHub(), "can only be called by RelayHub"); } function _verifyValue(GsnTypes.RelayRequest calldata relayRequest) internal virtual view{ require(relayRequest.request.value == 0, "value transfer not supported"); } function _verifyPaymasterData(GsnTypes.RelayRequest calldata relayRequest) internal virtual view { require(relayRequest.relayData.paymasterData.length == 0, "should have no paymasterData"); } function _verifyApprovalData(bytes calldata approvalData) internal virtual view{ require(approvalData.length == 0, "should have no approvalData"); } /** * @notice The owner of the Paymaster can change the instance of the RelayHub this Paymaster works with. * :warning: **Warning** :warning: The deposit on the previous RelayHub must be withdrawn first. */ function setRelayHub(IRelayHub hub) public onlyOwner { require(address(hub).supportsInterface(type(IRelayHub).interfaceId), "target is not a valid IRelayHub"); relayHub = hub; } /** * @notice The owner of the Paymaster can change the instance of the Forwarder this Paymaster works with. * @notice the Recipients must trust this Forwarder as well in order for the configuration to remain functional. */ function setTrustedForwarder(address forwarder) public virtual onlyOwner { require(forwarder.supportsInterface(type(IForwarder).interfaceId), "target is not a valid IForwarder"); _trustedForwarder = forwarder; } function getTrustedForwarder() public virtual view override returns (address){ return _trustedForwarder; } /** * @notice Any native Ether transferred into the paymaster is transferred as a deposit to the RelayHub. * This way, we don't need to understand the RelayHub API in order to replenish the paymaster. */ receive() external virtual payable { require(address(relayHub) != address(0), "relay hub address not set"); relayHub.depositFor{value:msg.value}(address(this)); } /** * @notice Withdraw deposit from the RelayHub. * @param amount The amount to be subtracted from the sender. * @param target The target to which the amount will be transferred. */ function withdrawRelayHubDepositTo(uint256 amount, address payable target) public onlyOwner { relayHub.withdraw(target, amount); } /// @inheritdoc IPaymaster function preRelayedCall( GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature, bytes calldata approvalData, uint256 maxPossibleGas ) external override returns (bytes memory, bool) { _verifyRelayHubOnly(); _verifyForwarder(relayRequest); _verifyValue(relayRequest); _verifyPaymasterData(relayRequest); _verifyApprovalData(approvalData); return _preRelayedCall(relayRequest, signature, approvalData, maxPossibleGas); } /** * @notice internal logic the paymasters need to provide to select which transactions they are willing to pay for * @notice see the documentation for `IPaymaster::preRelayedCall` for details */ function _preRelayedCall( GsnTypes.RelayRequest calldata, bytes calldata, bytes calldata, uint256 ) internal virtual returns (bytes memory, bool); /// @inheritdoc IPaymaster function postRelayedCall( bytes calldata context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData calldata relayData ) external override { _verifyRelayHubOnly(); _postRelayedCall(context, success, gasUseWithoutPost, relayData); } /** * @notice internal logic the paymasters need to provide if they need to take some action after the transaction * @notice see the documentation for `IPaymaster::postRelayedCall` for details */ function _postRelayedCall( bytes calldata, bool, uint256, GsnTypes.RelayData calldata ) internal virtual; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // solhint-disable no-inline-assembly pragma solidity >=0.6.9; import "./interfaces/IERC2771Recipient.sol"; /** * @title The ERC-2771 Recipient Base Abstract Class - Implementation * * @notice Note that this contract was called `BaseRelayRecipient` in the previous revision of the GSN. * * @notice A base contract to be inherited by any contract that want to receive relayed transactions. * * @notice A subclass must use `_msgSender()` instead of `msg.sender`. */ abstract contract ERC2771Recipient is IERC2771Recipient { /* * Forwarder singleton we accept calls from */ address private _trustedForwarder; /** * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder. * @notice Method is not a required method to allow Recipients to trust multiple Forwarders. Not recommended yet. * @return forwarder The address of the Forwarder contract that is being used. */ function getTrustedForwarder() public virtual view returns (address forwarder){ return _trustedForwarder; } function _setTrustedForwarder(address _forwarder) internal { _trustedForwarder = _forwarder; } /// @inheritdoc IERC2771Recipient function isTrustedForwarder(address forwarder) public virtual override view returns(bool) { return forwarder == _trustedForwarder; } /// @inheritdoc IERC2771Recipient function _msgSender() internal override virtual view returns (address ret) { if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) { // At this point we know that the sender is a trusted forwarder, // so we trust that the last bytes of msg.data are the verified sender address. // extract sender address from the end of msg.data assembly { ret := shr(96,calldataload(sub(calldatasize(),20))) } } else { ret = msg.sender; } } /// @inheritdoc IERC2771Recipient function _msgData() internal override virtual view returns (bytes calldata ret) { if (msg.data.length >= 20 && isTrustedForwarder(msg.sender)) { return msg.data[0:msg.data.length-20]; } else { return msg.data; } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (utils/structs/EnumerableSet.sol) 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 // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity >=0.6.0; /** * @title The ERC-2771 Recipient Base Abstract Class - Declarations * * @notice A contract must implement this interface in order to support relayed transaction. * * @notice It is recommended that your contract inherits from the ERC2771Recipient contract. */ abstract contract IERC2771Recipient { /** * :warning: **Warning** :warning: The Forwarder can have a full control over your Recipient. Only trust verified Forwarder. * @param forwarder The address of the Forwarder contract that is being used. * @return isTrustedForwarder `true` if the Forwarder is trusted to forward relayed transactions by this Recipient. */ function isTrustedForwarder(address forwarder) public virtual view returns(bool); /** * @notice Use this method the contract anywhere instead of msg.sender to support relayed transactions. * @return sender The real sender of this call. * For a call that came through the Forwarder the real sender is extracted from the last 20 bytes of the `msg.data`. * Otherwise simply returns `msg.sender`. */ function _msgSender() internal virtual view returns (address); /** * @notice Use this method in the contract instead of `msg.data` when difference matters (hashing, signature, etc.) * @return data The real `msg.data` of this call. * For a call that came through the Forwarder, the real sender address was appended as the last 20 bytes * of the `msg.data` - so this method will strip those 20 bytes off. * Otherwise (if the call was made directly and not through the forwarder) simply returns `msg.data`. */ function _msgData() internal virtual view returns (bytes calldata); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; pragma abicoder v2; import "../utils/GsnTypes.sol"; import "../interfaces/IERC2771Recipient.sol"; import "../forwarder/IForwarder.sol"; import "./GsnUtils.sol"; /** * @title The ERC-712 Library for GSN * @notice Bridge Library to convert a GSN RelayRequest into a valid `ForwardRequest` for a `Forwarder`. */ library GsnEip712Library { // maximum length of return value/revert reason for 'execute' method. Will truncate result if exceeded. uint256 private constant MAX_RETURN_SIZE = 1024; //copied from Forwarder (can't reference string constants even from another library) string public constant GENERIC_PARAMS = "address from,address to,uint256 value,uint256 gas,uint256 nonce,bytes data,uint256 validUntilTime"; bytes public constant RELAYDATA_TYPE = "RelayData(uint256 maxFeePerGas,uint256 maxPriorityFeePerGas,uint256 transactionCalldataGasUsed,address relayWorker,address paymaster,address forwarder,bytes paymasterData,uint256 clientId)"; string public constant RELAY_REQUEST_NAME = "RelayRequest"; string public constant RELAY_REQUEST_SUFFIX = string(abi.encodePacked("RelayData relayData)", RELAYDATA_TYPE)); bytes public constant RELAY_REQUEST_TYPE = abi.encodePacked( RELAY_REQUEST_NAME,"(",GENERIC_PARAMS,",", RELAY_REQUEST_SUFFIX); bytes32 public constant RELAYDATA_TYPEHASH = keccak256(RELAYDATA_TYPE); bytes32 public constant RELAY_REQUEST_TYPEHASH = keccak256(RELAY_REQUEST_TYPE); struct EIP712Domain { string name; string version; uint256 chainId; address verifyingContract; } bytes32 public constant EIP712DOMAIN_TYPEHASH = keccak256( "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" ); function splitRequest( GsnTypes.RelayRequest calldata req ) internal pure returns ( bytes memory suffixData ) { suffixData = abi.encode( hashRelayData(req.relayData)); } //verify that the recipient trusts the given forwarder // MUST be called by paymaster function verifyForwarderTrusted(GsnTypes.RelayRequest calldata relayRequest) internal view { (bool success, bytes memory ret) = relayRequest.request.to.staticcall( abi.encodeWithSelector( IERC2771Recipient.isTrustedForwarder.selector, relayRequest.relayData.forwarder ) ); require(success, "isTrustedForwarder: reverted"); require(ret.length == 32, "isTrustedForwarder: bad response"); require(abi.decode(ret, (bool)), "invalid forwarder for recipient"); } function verifySignature(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) internal view { (bytes memory suffixData) = splitRequest(relayRequest); bytes32 _domainSeparator = domainSeparator(relayRequest.relayData.forwarder); IForwarder forwarder = IForwarder(payable(relayRequest.relayData.forwarder)); forwarder.verify(relayRequest.request, _domainSeparator, RELAY_REQUEST_TYPEHASH, suffixData, signature); } function verify(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) internal view { verifyForwarderTrusted(relayRequest); verifySignature(relayRequest, signature); } function execute(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) internal returns (bool forwarderSuccess, bool callSuccess, bytes memory ret) { (bytes memory suffixData) = splitRequest(relayRequest); bytes32 _domainSeparator = domainSeparator(relayRequest.relayData.forwarder); /* solhint-disable-next-line avoid-low-level-calls */ (forwarderSuccess, ret) = relayRequest.relayData.forwarder.call( abi.encodeWithSelector(IForwarder.execute.selector, relayRequest.request, _domainSeparator, RELAY_REQUEST_TYPEHASH, suffixData, signature )); if ( forwarderSuccess ) { //decode return value of execute: (callSuccess, ret) = abi.decode(ret, (bool, bytes)); } truncateInPlace(ret); } //truncate the given parameter (in-place) if its length is above the given maximum length // do nothing otherwise. //NOTE: solidity warns unless the method is marked "pure", but it DOES modify its parameter. function truncateInPlace(bytes memory data) internal pure { MinLibBytes.truncateInPlace(data, MAX_RETURN_SIZE); } function domainSeparator(address forwarder) internal view returns (bytes32) { return hashDomain(EIP712Domain({ name : "GSN Relayed Transaction", version : "3", chainId : getChainID(), verifyingContract : forwarder })); } function getChainID() internal view returns (uint256 id) { /* solhint-disable no-inline-assembly */ assembly { id := chainid() } } function hashDomain(EIP712Domain memory req) internal pure returns (bytes32) { return keccak256(abi.encode( EIP712DOMAIN_TYPEHASH, keccak256(bytes(req.name)), keccak256(bytes(req.version)), req.chainId, req.verifyingContract)); } function hashRelayData(GsnTypes.RelayData calldata req) internal pure returns (bytes32) { return keccak256(abi.encode( RELAYDATA_TYPEHASH, req.maxFeePerGas, req.maxPriorityFeePerGas, req.transactionCalldataGasUsed, req.relayWorker, req.paymaster, req.forwarder, keccak256(req.paymasterData), req.clientId )); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Checker.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; /** * @dev Library used to query support of an interface declared via {IERC165}. * * Note that these functions return the actual result of the query: they do not * `revert` if an interface is not supported. It is up to the caller to decide * what to do in these cases. */ library ERC165Checker { // As per the EIP-165 spec, no interface should ever match 0xffffffff bytes4 private constant _INTERFACE_ID_INVALID = 0xffffffff; /** * @dev Returns true if `account` supports the {IERC165} interface, */ function supportsERC165(address account) internal view returns (bool) { // Any contract that implements ERC165 must explicitly indicate support of // InterfaceId_ERC165 and explicitly indicate non-support of InterfaceId_Invalid return _supportsERC165Interface(account, type(IERC165).interfaceId) && !_supportsERC165Interface(account, _INTERFACE_ID_INVALID); } /** * @dev Returns true if `account` supports the interface defined by * `interfaceId`. Support for {IERC165} itself is queried automatically. * * See {IERC165-supportsInterface}. */ function supportsInterface(address account, bytes4 interfaceId) internal view returns (bool) { // query support of both ERC165 as per the spec and support of _interfaceId return supportsERC165(account) && _supportsERC165Interface(account, interfaceId); } /** * @dev Returns a boolean array where each value corresponds to the * interfaces passed in and whether they're supported or not. This allows * you to batch check interfaces for a contract where your expectation * is that some interfaces may not be supported. * * See {IERC165-supportsInterface}. * * _Available since v3.4._ */ function getSupportedInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool[] memory) { // an array of booleans corresponding to interfaceIds and whether they're supported or not bool[] memory interfaceIdsSupported = new bool[](interfaceIds.length); // query support of ERC165 itself if (supportsERC165(account)) { // query support of each interface in interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { interfaceIdsSupported[i] = _supportsERC165Interface(account, interfaceIds[i]); } } return interfaceIdsSupported; } /** * @dev Returns true if `account` supports all the interfaces defined in * `interfaceIds`. Support for {IERC165} itself is queried automatically. * * Batch-querying can lead to gas savings by skipping repeated checks for * {IERC165} support. * * See {IERC165-supportsInterface}. */ function supportsAllInterfaces(address account, bytes4[] memory interfaceIds) internal view returns (bool) { // query support of ERC165 itself if (!supportsERC165(account)) { return false; } // query support of each interface in _interfaceIds for (uint256 i = 0; i < interfaceIds.length; i++) { if (!_supportsERC165Interface(account, interfaceIds[i])) { return false; } } // all interfaces supported return true; } /** * @notice Query if a contract implements an interface, does not check ERC165 support * @param account The address of the contract to query for support of an interface * @param interfaceId The interface identifier, as specified in ERC-165 * @return true if the contract at account indicates support of the interface with * identifier interfaceId, false otherwise * @dev Assumes that account contains a contract that supports ERC165, otherwise * the behavior of this method is undefined. This precondition can be checked * with {supportsERC165}. * Interface identification is specified in ERC-165. */ function _supportsERC165Interface(address account, bytes4 interfaceId) private view returns (bool) { bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId); (bool success, bytes memory result) = account.staticcall{gas: 30000}(encodedParams); if (result.length < 32) return false; return success && abi.decode(result, (bool)); } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; import "../forwarder/IForwarder.sol"; interface GsnTypes { /// @notice maxFeePerGas, maxPriorityFeePerGas, pctRelayFee and baseRelayFee must be validated inside of the paymaster's preRelayedCall in order not to overpay struct RelayData { uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; uint256 transactionCalldataGasUsed; address relayWorker; address paymaster; address forwarder; bytes paymasterData; uint256 clientId; } //note: must start with the ForwardRequest to be an extension of the generic forwarder struct RelayRequest { IForwarder.ForwardRequest request; RelayData relayData; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/interfaces/IERC165.sol"; import "../utils/GsnTypes.sol"; /** * @title The Paymaster Interface * @notice Contracts implementing this interface exist to make decision about paying the transaction fee to the relay. * * @notice There are two callbacks here that are executed by the RelayHub: `preRelayedCall` and `postRelayedCall`. * * @notice It is recommended that your implementation inherits from the abstract BasePaymaster contract. */ interface IPaymaster is IERC165 { /** * @notice The limits this Paymaster wants to be imposed by the RelayHub on user input. See `getGasAndDataLimits`. */ struct GasAndDataLimits { uint256 acceptanceBudget; uint256 preRelayedCallGasLimit; uint256 postRelayedCallGasLimit; uint256 calldataSizeLimit; } /** * @notice Return the Gas Limits for Paymaster's functions and maximum msg.data length values for this Paymaster. * This function allows different paymasters to have different properties without changes to the RelayHub. * @return limits An instance of the `GasAndDataLimits` struct * * ##### `acceptanceBudget` * If the transactions consumes more than `acceptanceBudget` this Paymaster will be charged for gas no matter what. * Transaction that gets rejected after consuming more than `acceptanceBudget` gas is on this Paymaster's expense. * * Should be set to an amount gas this Paymaster expects to spend deciding whether to accept or reject a request. * This includes gas consumed by calculations in the `preRelayedCall`, `Forwarder` and the recipient contract. * * :warning: **Warning** :warning: As long this value is above `preRelayedCallGasLimit` * (see defaults in `BasePaymaster`), the Paymaster is guaranteed it will never pay for rejected transactions. * If this value is below `preRelayedCallGasLimit`, it might might make Paymaster open to a "griefing" attack. * * The relayers should prefer lower `acceptanceBudget`, as it improves their chances of being compensated. * From a Relay's point of view, this is the highest gas value a bad Paymaster may cost the relay, * since the paymaster will pay anything above that value regardless of whether the transaction succeeds or reverts. * Specifying value too high might make the call rejected by relayers (see `maxAcceptanceBudget` in server config). * * ##### `preRelayedCallGasLimit` * The max gas usage of preRelayedCall. Any revert of the `preRelayedCall` is a request rejection by the paymaster. * As long as `acceptanceBudget` is above `preRelayedCallGasLimit`, any such revert is not payed by the paymaster. * * ##### `postRelayedCallGasLimit` * The max gas usage of postRelayedCall. The Paymaster is not charged for the maximum, only for actually used gas. * Note that an OOG will revert the inner transaction, but the paymaster will be charged for it anyway. */ function getGasAndDataLimits() external view returns ( GasAndDataLimits memory limits ); /** * @notice :warning: **Warning** :warning: using incorrect Forwarder may cause the Paymaster to agreeing to pay for invalid transactions. * @return trustedForwarder The address of the `Forwarder` that is trusted by this Paymaster to execute the requests. */ function getTrustedForwarder() external view returns (address trustedForwarder); /** * @return relayHub The address of the `RelayHub` that is trusted by this Paymaster to execute the requests. */ function getRelayHub() external view returns (address relayHub); /** * @notice Called by the Relay in view mode and later by the `RelayHub` on-chain to validate that * the Paymaster agrees to pay for this call. * * The request is considered to be rejected by the Paymaster in one of the following conditions: * - `preRelayedCall()` method reverts * - the `Forwarder` reverts because of nonce or signature error * - the `Paymaster` returned `rejectOnRecipientRevert: true` and the recipient contract reverted * (and all that did not consume more than `acceptanceBudget` gas). * * In any of the above cases, all Paymaster calls and the recipient call are reverted. * In any other case the Paymaster will pay for the gas cost of the transaction. * Note that even if `postRelayedCall` is reverted the Paymaster will be charged. * * @param relayRequest - the full relay request structure * @param signature - user's EIP712-compatible signature of the `relayRequest`. * Note that in most cases the paymaster shouldn't try use it at all. It is always checked * by the forwarder immediately after preRelayedCall returns. * @param approvalData - extra dapp-specific data (e.g. signature from trusted party) * @param maxPossibleGas - based on values returned from `getGasAndDataLimits` * the RelayHub will calculate the maximum possible amount of gas the user may be charged for. * In order to convert this value to wei, the Paymaster has to call "relayHub.calculateCharge()" * * @return context * A byte array to be passed to postRelayedCall. * Can contain any data needed by this Paymaster in any form or be empty if no extra data is needed. * @return rejectOnRecipientRevert * The flag that allows a Paymaster to "delegate" the rejection to the recipient code. * It also means the Paymaster trust the recipient to reject fast: both preRelayedCall, * forwarder check and recipient checks must fit into the GasLimits.acceptanceBudget, * otherwise the TX is paid by the Paymaster. * `true` if the Paymaster wants to reject the TX if the recipient reverts. * `false` if the Paymaster wants rejects by the recipient to be completed on chain and paid by the Paymaster. */ function preRelayedCall( GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature, bytes calldata approvalData, uint256 maxPossibleGas ) external returns (bytes memory context, bool rejectOnRecipientRevert); /** * @notice This method is called after the actual relayed function call. * It may be used to record the transaction (e.g. charge the caller by some contract logic) for this call. * * Revert in this functions causes a revert of the client's relayed call (and preRelayedCall(), but the Paymaster * is still committed to pay the relay for the entire transaction. * * @param context The call context, as returned by the preRelayedCall * @param success `true` if the relayed call succeeded, false if it reverted * @param gasUseWithoutPost The actual amount of gas used by the entire transaction, EXCEPT * the gas used by the postRelayedCall itself. * @param relayData The relay params of the request. can be used by relayHub.calculateCharge() * */ function postRelayedCall( bytes calldata context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData calldata relayData ) external; /** * @return version The SemVer string of this Paymaster's version. */ function versionPaymaster() external view returns (string memory); }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/interfaces/IERC165.sol"; /** * @title The Forwarder Interface * @notice The contracts implementing this interface take a role of authorization, authentication and replay protection * for contracts that choose to trust a `Forwarder`, instead of relying on a mechanism built into the Ethereum protocol. * * @notice if the `Forwarder` contract decides that an incoming `ForwardRequest` is valid, it must append 20 bytes that * represent the caller to the `data` field of the request and send this new data to the target address (the `to` field) * * :warning: **Warning** :warning: The Forwarder can have a full control over a `Recipient` contract. * Any vulnerability in a `Forwarder` implementation can make all of its `Recipient` contracts susceptible! * Recipient contracts should only trust forwarders that passed through security audit, * otherwise they are susceptible to identity theft. */ interface IForwarder is IERC165 { /** * @notice A representation of a request for a `Forwarder` to send `data` on behalf of a `from` to a target (`to`). */ struct ForwardRequest { address from; address to; uint256 value; uint256 gas; uint256 nonce; bytes data; uint256 validUntilTime; } event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue); event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr); /** * @param from The address of a sender. * @return The nonce for this address. */ function getNonce(address from) external view returns(uint256); /** * @notice Verify the transaction is valid and can be executed. * Implementations must validate the signature and the nonce of the request are correct. * Does not revert and returns successfully if the input is valid. * Reverts if any validation has failed. For instance, if either signature or nonce are incorrect. * Reverts if `domainSeparator` or `requestTypeHash` are not registered as well. */ function verify( ForwardRequest calldata forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature ) external view; /** * @notice Executes a transaction specified by the `ForwardRequest`. * The transaction is first verified and then executed. * The success flag and returned bytes array of the `CALL` are returned as-is. * * This method would revert only in case of a verification error. * * All the target errors are reported using the returned success flag and returned bytes array. * * @param forwardRequest All requested transaction parameters. * @param domainSeparator The domain used when signing this request. * @param requestTypeHash The request type used when signing this request. * @param suffixData The ABI-encoded extension data for the current `RequestType` used when signing this request. * @param signature The client signature to be validated. * * @return success The success flag of the underlying `CALL` to the target address. * @return ret The byte array returned by the underlying `CALL` to the target address. */ function execute( ForwardRequest calldata forwardRequest, bytes32 domainSeparator, bytes32 requestTypeHash, bytes calldata suffixData, bytes calldata signature ) external payable returns (bool success, bytes memory ret); /** * @notice Register a new Request typehash. * * @notice This is necessary for the Forwarder to be able to verify the signatures conforming to the ERC-712. * * @param typeName The name of the request type. * @param typeSuffix Any extra data after the generic params. Must contain add at least one param. * The generic ForwardRequest type is always registered by the constructor. */ function registerRequestType(string calldata typeName, string calldata typeSuffix) external; /** * @notice Register a new domain separator. * * @notice This is necessary for the Forwarder to be able to verify the signatures conforming to the ERC-712. * * @notice The domain separator must have the following fields: `name`, `version`, `chainId`, `verifyingContract`. * The `chainId` is the current network's `chainId`, and the `verifyingContract` is this Forwarder's address. * This method accepts the domain name and version to create and register the domain separator value. * @param name The domain's display name. * @param version The domain/protocol version. */ function registerDomainSeparator(string calldata name, string calldata version) external; }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/interfaces/IERC165.sol"; import "../utils/GsnTypes.sol"; import "./IStakeManager.sol"; /** * @title The RelayHub interface * @notice The implementation of this interface provides all the information the GSN client needs to * create a valid `RelayRequest` and also serves as an entry point for such requests. * * @notice The RelayHub also handles all the related financial records and hold the balances of participants. * The Paymasters keep their Ether deposited in the `RelayHub` in order to pay for the `RelayRequest`s that thay choose * to pay for, and Relay Servers keep their earned Ether in the `RelayHub` until they choose to `withdraw()` * * @notice The RelayHub on each supported network only needs a single instance and there is usually no need for dApp * developers or Relay Server operators to redeploy, reimplement, modify or override the `RelayHub`. */ interface IRelayHub is IERC165 { /** * @notice A struct that contains all the parameters of the `RelayHub` that can be modified after the deployment. */ struct RelayHubConfig { // maximum number of worker accounts allowed per manager uint256 maxWorkerCount; // Gas set aside for all relayCall() instructions to prevent unexpected out-of-gas exceptions uint256 gasReserve; // Gas overhead to calculate gasUseWithoutPost uint256 postOverhead; // Gas cost of all relayCall() instructions after actual 'calculateCharge()' // Assume that relay has non-zero balance (costs 15'000 more otherwise). uint256 gasOverhead; // Minimum unstake delay seconds of a relay manager's stake on the StakeManager uint256 minimumUnstakeDelay; // Developers address address devAddress; // 0 < fee < 100, as percentage of total charge from paymaster to relayer uint8 devFee; // baseRelayFee The base fee the Relay Server charges for a single transaction in Ether, in wei. uint80 baseRelayFee; // pctRelayFee The percent of the total charge to add as a Relay Server fee to the total charge. uint16 pctRelayFee; } /// @notice Emitted when a configuration of the `RelayHub` is changed event RelayHubConfigured(RelayHubConfig config); /// @notice Emitted when relays are added by a relayManager event RelayWorkersAdded( address indexed relayManager, address[] newRelayWorkers, uint256 workersCount ); /// @notice Emitted when an account withdraws funds from the `RelayHub`. event Withdrawn( address indexed account, address indexed dest, uint256 amount ); /// @notice Emitted when `depositFor` is called, including the amount and account that was funded. event Deposited( address indexed paymaster, address indexed from, uint256 amount ); /// @notice Emitted for each token configured for staking in setMinimumStakes event StakingTokenDataChanged( address token, uint256 minimumStake ); /** * @notice Emitted when an attempt to relay a call fails and the `Paymaster` does not accept the transaction. * The actual relayed call was not executed, and the recipient not charged. * @param reason contains a revert reason returned from preRelayedCall or forwarder. */ event TransactionRejectedByPaymaster( address indexed relayManager, address indexed paymaster, bytes32 indexed relayRequestID, address from, address to, address relayWorker, bytes4 selector, uint256 innerGasUsed, bytes reason ); /** * @notice Emitted when a transaction is relayed. Note that the actual internal function call might be reverted. * The reason for a revert will be indicated in the `status` field of a corresponding `RelayCallStatus` value. * @notice `charge` is the Ether value deducted from the `Paymaster` balance. * The amount added to the `relayManager` balance will be lower if there is an activated `devFee` in the `config`. */ event TransactionRelayed( address indexed relayManager, address indexed relayWorker, bytes32 indexed relayRequestID, address from, address to, address paymaster, bytes4 selector, RelayCallStatus status, uint256 charge ); /// @notice This event is emitted in case the internal function returns a value or reverts with a revert string. event TransactionResult( RelayCallStatus status, bytes returnValue ); /// @notice This event is emitted in case this `RelayHub` is deprecated and will stop serving transactions soon. event HubDeprecated(uint256 deprecationTime); /** * @notice This event is emitted in case a `relayManager` has been deemed "abandoned" for being * unresponsive for a prolonged period of time. * @notice This event means the entire balance of the relay has been transferred to the `devAddress`. */ event AbandonedRelayManagerBalanceEscheated( address indexed relayManager, uint256 balance ); /** * Error codes that describe all possible failure reasons reported in the `TransactionRelayed` event `status` field. * @param OK The transaction was successfully relayed and execution successful - never included in the event. * @param RelayedCallFailed The transaction was relayed, but the relayed call failed. * @param RejectedByPreRelayed The transaction was not relayed due to preRelatedCall reverting. * @param RejectedByForwarder The transaction was not relayed due to forwarder check (signature,nonce). * @param PostRelayedFailed The transaction was relayed and reverted due to postRelatedCall reverting. * @param PaymasterBalanceChanged The transaction was relayed and reverted due to the paymaster balance change. */ enum RelayCallStatus { OK, RelayedCallFailed, RejectedByPreRelayed, RejectedByForwarder, RejectedByRecipientRevert, PostRelayedFailed, PaymasterBalanceChanged } /** * @notice Add new worker addresses controlled by the sender who must be a staked Relay Manager address. * Emits a `RelayWorkersAdded` event. * This function can be called multiple times, emitting new events. */ function addRelayWorkers(address[] calldata newRelayWorkers) external; /** * @notice The `RelayRegistrar` callback to notify the `RelayHub` that this `relayManager` has updated registration. */ function onRelayServerRegistered(address relayManager) external; // Balance management /** * @notice Deposits ether for a `Paymaster`, so that it can and pay for relayed transactions. * :warning: **Warning** :warning: Unused balance can only be withdrawn by the holder itself, by calling `withdraw`. * Emits a `Deposited` event. */ function depositFor(address target) external payable; /** * @notice Withdraws from an account's balance, sending it back to the caller. * Relay Managers call this to retrieve their revenue, and `Paymasters` can also use it to reduce their funding. * Emits a `Withdrawn` event. */ function withdraw(address payable dest, uint256 amount) external; /** * @notice Withdraws from an account's balance, sending funds to multiple provided addresses. * Relay Managers call this to retrieve their revenue, and `Paymasters` can also use it to reduce their funding. * Emits a `Withdrawn` event for each destination. */ function withdrawMultiple(address payable[] memory dest, uint256[] memory amount) external; // Relaying /** * @notice Relays a transaction. For this to succeed, multiple conditions must be met: * - `Paymaster`'s `preRelayCall` method must succeed and not revert. * - the `msg.sender` must be a registered Relay Worker that the user signed to use. * - the transaction's gas fees must be equal or larger than the ones that were signed by the sender. * - the transaction must have enough gas to run all internal transactions if they use all gas available to them. * - the `Paymaster` must have enough balance to pay the Relay Worker if all gas is spent. * * @notice If all conditions are met, the call will be relayed and the `Paymaster` charged. * * @param maxAcceptanceBudget The maximum valid value for `paymaster.getGasLimits().acceptanceBudget` to return. * @param relayRequest All details of the requested relayed call. * @param signature The client's EIP-712 signature over the `relayRequest` struct. * @param approvalData The dapp-specific data forwarded to the `Paymaster`'s `preRelayedCall` method. * This value is **not** verified by the `RelayHub` in any way. * As an example, it can be used to pass some kind of a third-party signature to the `Paymaster` for verification. * * Emits a `TransactionRelayed` event regardless of whether the transaction succeeded or failed. */ function relayCall( uint256 maxAcceptanceBudget, GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature, bytes calldata approvalData ) external returns ( bool paymasterAccepted, uint256 charge, IRelayHub.RelayCallStatus status, bytes memory returnValue ); /** * @notice In case the Relay Worker has been found to be in violation of some rules by the `Penalizer` contract, * the `Penalizer` will call this method to execute a penalization. * The `RelayHub` will look up the Relay Manager of the given Relay Worker and will forward the call to * the `StakeManager` contract. The `RelayHub` does not perform the actual penalization either. * @param relayWorker The address of the Relay Worker that committed a penalizable offense. * @param beneficiary The address that called the `Penalizer` and will receive a reward for it. */ function penalize(address relayWorker, address payable beneficiary) external; /** * @notice Sets or changes the configuration of this `RelayHub`. * @param _config The new configuration. */ function setConfiguration(RelayHubConfig memory _config) external; /** * @notice Sets or changes the minimum amount of a given `token` that needs to be staked so that the Relay Manager * is considered to be 'staked' by this `RelayHub`. Zero value means this token is not allowed for staking. * @param token An array of addresses of ERC-20 compatible tokens. * @param minimumStake An array of minimal amounts necessary for a corresponding token, in wei. */ function setMinimumStakes(IERC20[] memory token, uint256[] memory minimumStake) external; /** * @notice Deprecate hub by reverting all incoming `relayCall()` calls starting from a given timestamp * @param _deprecationTime The timestamp in seconds after which the `RelayHub` stops serving transactions. */ function deprecateHub(uint256 _deprecationTime) external; /** * @notice * @param relayManager */ function escheatAbandonedRelayBalance(address relayManager) external; /** * @notice The fee is expressed as a base fee in wei plus percentage of the actual charge. * For example, a value '40' stands for a 40% fee, so the recipient will be charged for 1.4 times the spent amount. * @param gasUsed An amount of gas used by the transaction. * @param relayData The details of a transaction signed by the sender. * @return The calculated charge, in wei. */ function calculateCharge(uint256 gasUsed, GsnTypes.RelayData calldata relayData) external view returns (uint256); /** * @notice The fee is expressed as a percentage of the actual charge. * For example, a value '40' stands for a 40% fee, so the Relay Manager will only get 60% of the `charge`. * @param charge The amount of Ether in wei the Paymaster will be charged for this transaction. * @return The calculated devFee, in wei. */ function calculateDevCharge(uint256 charge) external view returns (uint256); /* getters */ /// @return config The configuration of the `RelayHub`. function getConfiguration() external view returns (RelayHubConfig memory config); /** * @param token An address of an ERC-20 compatible tokens. * @return The minimum amount of a given `token` that needs to be staked so that the Relay Manager * is considered to be 'staked' by this `RelayHub`. Zero value means this token is not allowed for staking. */ function getMinimumStakePerToken(IERC20 token) external view returns (uint256); /** * @param worker An address of the Relay Worker. * @return The address of its Relay Manager. */ function getWorkerManager(address worker) external view returns (address); /** * @param manager An address of the Relay Manager. * @return The count of Relay Workers associated with this Relay Manager. */ function getWorkerCount(address manager) external view returns (uint256); /// @return An account's balance. It can be either a deposit of a `Paymaster`, or a revenue of a Relay Manager. function balanceOf(address target) external view returns (uint256); /// @return The `StakeManager` address for this `RelayHub`. function getStakeManager() external view returns (IStakeManager); /// @return The `Penalizer` address for this `RelayHub`. function getPenalizer() external view returns (address); /// @return The `RelayRegistrar` address for this `RelayHub`. function getRelayRegistrar() external view returns (address); /// @return The `BatchGateway` address for this `RelayHub`. function getBatchGateway() external view returns (address); /** * @notice Uses `StakeManager` to decide if the Relay Manager can be considered staked or not. * Returns if the stake's token, amount and delay satisfy all requirements, reverts otherwise. */ function verifyRelayManagerStaked(address relayManager) external view; /** * @notice Uses `StakeManager` to check if the Relay Manager can be considered abandoned or not. * Returns true if the stake's abandonment time is in the past including the escheatment delay, false otherwise. */ function isRelayEscheatable(address relayManager) external view returns (bool); /// @return `true` if the `RelayHub` is deprecated, `false` it it is not deprecated and can serve transactions. function isDeprecated() external view returns (bool); /// @return The timestamp from which the hub no longer allows relaying calls. function getDeprecationTime() external view returns (uint256); /// @return The block number in which the contract has been deployed. function getCreationBlock() external view returns (uint256); /// @return a SemVer-compliant version of the `RelayHub` contract. function versionHub() external view returns (string memory); /// @return A total measurable amount of gas left to current execution. Same as 'gasleft()' for pure EVMs. function aggregateGasleft() external view returns (uint256); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
/* solhint-disable no-inline-assembly */ // SPDX-License-Identifier: GPL-3.0-only pragma solidity ^0.8.0; import "../utils/MinLibBytes.sol"; import "./GsnTypes.sol"; /** * @title The GSN Solidity Utils Library * @notice Some library functions used throughout the GSN Solidity codebase. */ library GsnUtils { bytes32 constant private RELAY_REQUEST_ID_MASK = 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; /** * @notice Calculate an identifier for the meta-transaction in a format similar to a transaction hash. * Note that uniqueness relies on signature and may not be enforced if meta-transactions are verified * with a different algorithm, e.g. when batching. * @param relayRequest The `RelayRequest` for which an ID is being calculated. * @param signature The signature for the `RelayRequest`. It is not validated here and may even remain empty. */ function getRelayRequestID(GsnTypes.RelayRequest calldata relayRequest, bytes calldata signature) internal pure returns (bytes32) { return keccak256(abi.encode(relayRequest.request.from, relayRequest.request.nonce, signature)) & RELAY_REQUEST_ID_MASK; } /** * @notice Extract the method identifier signature from the encoded function call. */ function getMethodSig(bytes memory msgData) internal pure returns (bytes4) { return MinLibBytes.readBytes4(msgData, 0); } /** * @notice Extract a parameter from encoded-function block. * see: https://solidity.readthedocs.io/en/develop/abi-spec.html#formal-specification-of-the-encoding * The return value should be casted to the right type (`uintXXX`/`bytesXXX`/`address`/`bool`/`enum`). * @param msgData Byte array containing a uint256 value. * @param index Index in byte array of uint256 value. * @return result uint256 value from byte array. */ function getParam(bytes memory msgData, uint256 index) internal pure returns (uint256 result) { return MinLibBytes.readUint256(msgData, 4 + index * 32); } /// @notice Re-throw revert with the same revert data. function revertWithData(bytes memory data) internal pure { assembly { revert(add(data,32), mload(data)) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT // minimal bytes manipulation required by GSN // a minimal subset from 0x/LibBytes /* solhint-disable no-inline-assembly */ pragma solidity ^0.8.0; library MinLibBytes { //truncate the given parameter (in-place) if its length is above the given maximum length // do nothing otherwise. //NOTE: solidity warns unless the method is marked "pure", but it DOES modify its parameter. function truncateInPlace(bytes memory data, uint256 maxlen) internal pure { if (data.length > maxlen) { assembly { mstore(data, maxlen) } } } /// @dev Reads an address from a position in a byte array. /// @param b Byte array containing an address. /// @param index Index in byte array of address. /// @return result address from byte array. function readAddress( bytes memory b, uint256 index ) internal pure returns (address result) { require (b.length >= index + 20, "readAddress: data too short"); // Add offset to index: // 1. Arrays are prefixed by 32-byte length parameter (add 32 to index) // 2. Account for size difference between address length and 32-byte storage word (subtract 12 from index) index += 20; // Read address from array memory assembly { // 1. Add index to address of bytes array // 2. Load 32-byte word from memory // 3. Apply 20-byte mask to obtain address result := and(mload(add(b, index)), 0xffffffffffffffffffffffffffffffffffffffff) } return result; } function readBytes32( bytes memory b, uint256 index ) internal pure returns (bytes32 result) { require(b.length >= index + 32, "readBytes32: data too short" ); // Read the bytes32 from array memory assembly { result := mload(add(b, add(index,32))) } return result; } /// @dev Reads a uint256 value from a position in a byte array. /// @param b Byte array containing a uint256 value. /// @param index Index in byte array of uint256 value. /// @return result uint256 value from byte array. function readUint256( bytes memory b, uint256 index ) internal pure returns (uint256 result) { result = uint256(readBytes32(b, index)); return result; } function readBytes4( bytes memory b, uint256 index ) internal pure returns (bytes4 result) { require(b.length >= index + 4, "readBytes4: data too short"); // Read the bytes4 from array memory assembly { result := mload(add(b, add(index,32))) // Solidity does not require us to clean the trailing bytes. // We do it anyway result := and(result, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000) } return result; } }
// SPDX-License-Identifier: GPL-3.0-only pragma solidity >=0.7.6; pragma abicoder v2; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/utils/introspection/ERC165.sol"; /** * @title The StakeManager Interface * @notice In order to prevent an attacker from registering a large number of unresponsive relays, the GSN requires * the Relay Server to maintain a permanently locked stake in the system before being able to register. * * @notice Also, in some cases the behavior of a Relay Server may be found to be illegal by a `Penalizer` contract. * In such case, the stake will never be returned to the Relay Server operator and will be slashed. * * @notice An implementation of this interface is tasked with keeping Relay Servers' stakes, made in any ERC-20 token. * Note that the `RelayHub` chooses which ERC-20 tokens to support and how much stake is needed. */ interface IStakeManager is IERC165 { /// @notice Emitted when a `stake` or `unstakeDelay` are initialized or increased. event StakeAdded( address indexed relayManager, address indexed owner, IERC20 token, uint256 stake, uint256 unstakeDelay ); /// @notice Emitted once a stake is scheduled for withdrawal. event StakeUnlocked( address indexed relayManager, address indexed owner, uint256 withdrawTime ); /// @notice Emitted when owner withdraws `relayManager` funds. event StakeWithdrawn( address indexed relayManager, address indexed owner, IERC20 token, uint256 amount ); /// @notice Emitted when an authorized `RelayHub` penalizes a `relayManager`. event StakePenalized( address indexed relayManager, address indexed beneficiary, IERC20 token, uint256 reward ); /// @notice Emitted when a `relayManager` adds a new `RelayHub` to a list of authorized. event HubAuthorized( address indexed relayManager, address indexed relayHub ); /// @notice Emitted when a `relayManager` removes a `RelayHub` from a list of authorized. event HubUnauthorized( address indexed relayManager, address indexed relayHub, uint256 removalTime ); /// @notice Emitted when a `relayManager` sets its `owner`. This is necessary to prevent stake hijacking. event OwnerSet( address indexed relayManager, address indexed owner ); /// @notice Emitted when a `burnAddress` is changed. event BurnAddressSet( address indexed burnAddress ); /// @notice Emitted when a `devAddress` is changed. event DevAddressSet( address indexed devAddress ); /// @notice Emitted if Relay Server is inactive for an `abandonmentDelay` and contract owner initiates its removal. event RelayServerAbandoned( address indexed relayManager, uint256 abandonedTime ); /// @notice Emitted to indicate an action performed by a relay server to prevent it from being marked as abandoned. event RelayServerKeepalive( address indexed relayManager, uint256 keepaliveTime ); /// @notice Emitted when the stake of an abandoned relayer has been confiscated and transferred to the `devAddress`. event AbandonedRelayManagerStakeEscheated( address indexed relayManager, address indexed owner, IERC20 token, uint256 amount ); /** * @param stake - amount of ether staked for this relay * @param unstakeDelay - number of seconds to elapse before the owner can retrieve the stake after calling 'unlock' * @param withdrawTime - timestamp in seconds when 'withdraw' will be callable, or zero if the unlock has not been called * @param owner - address that receives revenue and manages relayManager's stake */ struct StakeInfo { uint256 stake; uint256 unstakeDelay; uint256 withdrawTime; uint256 abandonedTime; uint256 keepaliveTime; IERC20 token; address owner; } struct RelayHubInfo { uint256 removalTime; } /** * @param devAddress - the address that will receive the 'abandoned' stake * @param abandonmentDelay - the amount of time after which the relay can be marked as 'abandoned' * @param escheatmentDelay - the amount of time after which the abandoned relay's stake and balance may be withdrawn to the `devAddress` */ struct AbandonedRelayServerConfig { address devAddress; uint256 abandonmentDelay; uint256 escheatmentDelay; } /** * @notice Set the owner of a Relay Manager. Called only by the RelayManager itself. * Note that owners cannot transfer ownership - if the entry already exists, reverts. * @param owner - owner of the relay (as configured off-chain) */ function setRelayManagerOwner(address owner) external; /** * @notice Put a stake for a relayManager and set its unstake delay. * Only the owner can call this function. If the entry does not exist, reverts. * The owner must give allowance of the ERC-20 token to the StakeManager before calling this method. * It is the RelayHub who has a configurable list of minimum stakes per token. StakeManager accepts all tokens. * @param token The address of an ERC-20 token that is used by the relayManager as a stake * @param relayManager The address that represents a stake entry and controls relay registrations on relay hubs * @param unstakeDelay The number of seconds to elapse before an owner can retrieve the stake after calling `unlock` * @param amount The amount of tokens to be taken from the relayOwner and locked in the StakeManager as a stake */ function stakeForRelayManager(IERC20 token, address relayManager, uint256 unstakeDelay, uint256 amount) external; /** * @notice Schedule the unlocking of the stake. The `unstakeDelay` must pass before owner can call `withdrawStake`. * @param relayManager The address of a Relay Manager whose stake is to be unlocked. */ function unlockStake(address relayManager) external; /** * @notice Withdraw the unlocked stake. * @param relayManager The address of a Relay Manager whose stake is to be withdrawn. */ function withdrawStake(address relayManager) external; /** * @notice Add the `RelayHub` to a list of authorized by this Relay Manager. * This allows the RelayHub to penalize this Relay Manager. The `RelayHub` cannot trust a Relay it cannot penalize. * @param relayManager The address of a Relay Manager whose stake is to be authorized for the new `RelayHub`. * @param relayHub The address of a `RelayHub` to be authorized. */ function authorizeHubByOwner(address relayManager, address relayHub) external; /** * @notice Same as `authorizeHubByOwner` but can be called by the RelayManager itself. */ function authorizeHubByManager(address relayHub) external; /** * @notice Remove the `RelayHub` from a list of authorized by this Relay Manager. * @param relayManager The address of a Relay Manager. * @param relayHub The address of a `RelayHub` to be unauthorized. */ function unauthorizeHubByOwner(address relayManager, address relayHub) external; /** * @notice Same as `unauthorizeHubByOwner` but can be called by the RelayManager itself. */ function unauthorizeHubByManager(address relayHub) external; /** * Slash the stake of the relay relayManager. In order to prevent stake kidnapping, burns part of stake on the way. * @param relayManager The address of a Relay Manager to be penalized. * @param beneficiary The address that receives part of the penalty amount. * @param amount A total amount of penalty to be withdrawn from stake. */ function penalizeRelayManager(address relayManager, address beneficiary, uint256 amount) external; /** * @notice Allows the contract owner to set the given `relayManager` as abandoned after a configurable delay. * Its entire stake and balance will be taken from a relay if it does not respond to being marked as abandoned. */ function markRelayAbandoned(address relayManager) external; /** * @notice If more than `abandonmentDelay` has passed since the last Keepalive transaction, and relay manager * has been marked as abandoned, and after that more that `escheatmentDelay` have passed, entire stake and * balance will be taken from this relay. */ function escheatAbandonedRelayStake(address relayManager) external; /** * @notice Sets a new `keepaliveTime` for the given `relayManager`, preventing it from being marked as abandoned. * Can be called by an authorized `RelayHub` or by the `relayOwner` address. */ function updateRelayKeepaliveTime(address relayManager) external; /** * @notice Check if the Relay Manager can be considered abandoned or not. * Returns true if the stake's abandonment time is in the past including the escheatment delay, false otherwise. */ function isRelayEscheatable(address relayManager) external view returns(bool); /** * @notice Get the stake details information for the given Relay Manager. * @param relayManager The address of a Relay Manager. * @return stakeInfo The `StakeInfo` structure. * @return isSenderAuthorizedHub `true` if the `msg.sender` for this call was a `RelayHub` that is authorized now. * `false` if the `msg.sender` for this call is not authorized. */ function getStakeInfo(address relayManager) external view returns (StakeInfo memory stakeInfo, bool isSenderAuthorizedHub); /** * @return The maximum unstake delay this `StakeManger` allows. This is to prevent locking money forever by mistake. */ function getMaxUnstakeDelay() external view returns (uint256); /** * @notice Change the address that will receive the 'burned' part of the penalized stake. * This is done to prevent malicious Relay Server from penalizing itself and breaking even. */ function setBurnAddress(address _burnAddress) external; /** * @return The address that will receive the 'burned' part of the penalized stake. */ function getBurnAddress() external view returns (address); /** * @notice Change the address that will receive the 'abandoned' stake. * This is done to prevent Relay Servers that lost their keys from losing access to funds. */ function setDevAddress(address _burnAddress) external; /** * @return The structure that contains all configuration values for the 'abandoned' stake. */ function getAbandonedRelayServerConfig() external view returns (AbandonedRelayServerConfig memory); /** * @return the block number in which the contract has been deployed. */ function getCreationBlock() external view returns (uint256); /** * @return a SemVer-compliant version of the `StakeManager` contract. */ function versionSM() external view returns (string memory); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @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); /** * @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 `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount ) external returns (bool); }
{ "optimizer": { "enabled": true, "runs": 10 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"baseFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"networkFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"}],"name":"FeeCharged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"target","type":"address"}],"name":"TargetSet","type":"event"},{"inputs":[],"name":"CALLDATA_SIZE_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FORWARDER_HUB_OVERHEAD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PAYMASTER_ACCEPTANCE_BUDGET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POST_RELAYED_CALL_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRE_RELAYED_CALL_GAS_LIMIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gasUsedByPost","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGasAndDataLimits","outputs":[{"components":[{"internalType":"uint256","name":"acceptanceBudget","type":"uint256"},{"internalType":"uint256","name":"preRelayedCallGasLimit","type":"uint256"},{"internalType":"uint256","name":"postRelayedCallGasLimit","type":"uint256"},{"internalType":"uint256","name":"calldataSizeLimit","type":"uint256"}],"internalType":"struct IPaymaster.GasAndDataLimits","name":"limits","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getRelayHub","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTrustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"methodWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ourTarget","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"context","type":"bytes"},{"internalType":"bool","name":"success","type":"bool"},{"internalType":"uint256","name":"gasUseWithoutPost","type":"uint256"},{"components":[{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"transactionCalldataGasUsed","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"address","name":"forwarder","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"name":"postRelayedCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gas","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"validUntilTime","type":"uint256"}],"internalType":"struct IForwarder.ForwardRequest","name":"request","type":"tuple"},{"components":[{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"uint256","name":"transactionCalldataGasUsed","type":"uint256"},{"internalType":"address","name":"relayWorker","type":"address"},{"internalType":"address","name":"paymaster","type":"address"},{"internalType":"address","name":"forwarder","type":"address"},{"internalType":"bytes","name":"paymasterData","type":"bytes"},{"internalType":"uint256","name":"clientId","type":"uint256"}],"internalType":"struct GsnTypes.RelayData","name":"relayData","type":"tuple"}],"internalType":"struct GsnTypes.RelayRequest","name":"relayRequest","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"bytes","name":"approvalData","type":"bytes"},{"internalType":"uint256","name":"maxPossibleGas","type":"uint256"}],"name":"preRelayedCall","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasUsedByPost","type":"uint256"}],"name":"setPostGasUsage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IRelayHub","name":"hub","type":"address"}],"name":"setRelayHub","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"setTarget","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"setTrustedForwarder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"versionPaymaster","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes4","name":"method","type":"bytes4"},{"internalType":"bool","name":"isAllowed","type":"bool"}],"name":"whitelistMethod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"target","type":"address"}],"name":"withdrawRelayHubDepositTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
608060405234801561001057600080fd5b5061001a3361001f565b61006f565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b611cc08061007e6000396000f3fe60806040526004361061011e5760003560e01c8062be5dd4146101e757806301ffc9a71461021e5780632d14c4b71461024e5780633a0892e3146102705780635c5e3db1146102ab5780636d7c3e2b146102cf578063715018a6146102ef57806376fa01c314610304578063776d1a01146103245780637bb05264146103445780637bdf2ec71461036457806380d324f1146103865780638da5cb5b146103a6578063921276ea146103bb578063ad12e50e146103ef578063b039a88f14610405578063b90b41cf1461044d578063bbdaa3c914610463578063ce1b815f1461047a578063da7422281461048f578063df463a66146104af578063e1838f8d146104c4578063f2fde38b146104e4578063f9c002f71461050457600080fd5b366101e2576001546001600160a01b031661017c5760405162461bcd60e51b81526020600482015260196024820152781c995b185e481a1d58881859191c995cdcc81b9bdd081cd95d603a1b60448201526064015b60405180910390fd5b60015460405163aa67c91960e01b81526001600160a01b039091169063aa67c9199034906101ae903090600401611985565b6000604051808303818588803b1580156101c757600080fd5b505af11580156101db573d6000803e3d6000fd5b5050505050005b600080fd5b3480156101f357600080fd5b50610207610202366004611801565b61051b565b6040516102159291906119b2565b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461169f565b610569565b6040519015158152602001610215565b34801561025a57600080fd5b5061026e6102693660046118d7565b6105bb565b005b34801561027c57600080fd5b5061023e61028b366004611604565b600560209081526000928352604080842090915290825290205460ff1681565b3480156102b757600080fd5b506102c161290481565b604051908152602001610215565b3480156102db57600080fd5b5061026e6102ea3660046118a5565b610652565b3480156102fb57600080fd5b5061026e610686565b34801561031057600080fd5b5061026e61031f3660046116ba565b6106c1565b34801561033057600080fd5b5061026e61033f3660046115e7565b6106dd565b34801561035057600080fd5b5061026e61035f3660046115e7565b610762565b34801561037057600080fd5b50610379610819565b6040516102159190611985565b34801561039257600080fd5b50600354610379906001600160a01b031681565b3480156103b257600080fd5b50610379610828565b3480156103c757600080fd5b5060408051808201825260058152640332e302e360dc1b6020820152905161021591906119d6565b3480156103fb57600080fd5b506102c160045481565b34801561041157600080fd5b5061041a610837565b60405161021591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561045957600080fd5b506102c161c35081565b34801561046f57600080fd5b506102c16201adb081565b34801561048657600080fd5b506103796108a0565b34801561049b57600080fd5b5061026e6104aa3660046115e7565b6108af565b3480156104bb57600080fd5b506102c1610966565b3480156104d057600080fd5b5061026e6104df366004611639565b610978565b3480156104f057600080fd5b5061026e6104ff3660046115e7565b6109e8565b34801561051057600080fd5b506102c1620186a081565b60606000610527610a88565b61053088610af0565b61053988610b79565b61054288610bd3565b61054c8585610c3c565b61055a888888888888610c8c565b91509150965096945050505050565b60006001600160e01b031982166370d596f560e11b148061059a57506001600160e01b03198216630704183b60e11b145b806105b557506301ffc9a760e01b6001600160e01b03198316145b92915050565b336105c4610828565b6001600160a01b0316146105ea5760405162461bcd60e51b8152600401610173906119e9565b60015460405163f3fef3a360e01b81526001600160a01b039091169063f3fef3a39061061c9084908690600401611999565b600060405180830381600087803b15801561063657600080fd5b505af115801561064a573d6000803e3d6000fd5b505050505050565b3361065b610828565b6001600160a01b0316146106815760405162461bcd60e51b8152600401610173906119e9565b600455565b3361068f610828565b6001600160a01b0316146106b55760405162461bcd60e51b8152600401610173906119e9565b6106bf6000610f84565b565b6106c9610a88565b6106d68585858585610fd4565b5050505050565b336106e6610828565b6001600160a01b03161461070c5760405162461bcd60e51b8152600401610173906119e9565b600380546001600160a01b0319166001600160a01b0383161790556040517f3bfb4bbf112628248058745a3c57e35b13369386e474b8e56c552f3063a4a19690610757908390611985565b60405180910390a150565b3361076b610828565b6001600160a01b0316146107915760405162461bcd60e51b8152600401610173906119e9565b6107ab6001600160a01b0382166334f57c6760e01b6111dc565b6107f75760405162461bcd60e51b815260206004820152601f60248201527f746172676574206973206e6f7420612076616c6964204952656c6179487562006044820152606401610173565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031690565b6000546001600160a01b031690565b6108626040518060800160405280600081526020016000815260200160008152602001600081525090565b604051806080016040528061c350620186a061087e9190611bb2565b8152602001620186a081526020016201adb08152602001612904815250905090565b6002546001600160a01b031690565b336108b8610828565b6001600160a01b0316146108de5760405162461bcd60e51b8152600401610173906119e9565b6108f86001600160a01b0382166309788f9960e21b6111dc565b6109445760405162461bcd60e51b815260206004820181905260248201527f746172676574206973206e6f7420612076616c69642049466f727761726465726044820152606401610173565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61097561c350620186a0611bb2565b81565b33610981610828565b6001600160a01b0316146109a75760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b0390921660009081526005602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b336109f1610828565b6001600160a01b031614610a175760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b038116610a7c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610173565b610a8581610f84565b50565b610a90610819565b6001600160a01b0316336001600160a01b0316146106bf5760405162461bcd60e51b815260206004820152601e60248201527f63616e206f6e6c792062652063616c6c65642062792052656c617948756200006044820152606401610173565b610afd6020820182611b2d565b610b0e9060c081019060a0016115e7565b6001600160a01b0316610b1f6108a0565b6001600160a01b031614610b705760405162461bcd60e51b8152602060048201526018602482015277119bdc9dd85c99195c881a5cc81b9bdd081d1c9d5cdd195960421b6044820152606401610173565b610a85816111ff565b610b838180611b17565b6040013515610a855760405162461bcd60e51b815260206004820152601c60248201527b1d985b1d59481d1c985b9cd9995c881b9bdd081cdd5c1c1bdc9d195960221b6044820152606401610173565b610be06020820182611b2d565b610bee9060c0810190611ad1565b159050610a855760405162461bcd60e51b815260206004820152601c60248201527b73686f756c642068617665206e6f207061796d61737465724461746160201b6044820152606401610173565b8015610c885760405162461bcd60e51b815260206004820152601b60248201527a73686f756c642068617665206e6f20617070726f76616c4461746160281b6044820152606401610173565b5050565b6003546060906000906001600160a01b0316610ca88980611b17565b610cb99060408101906020016115e7565b6001600160a01b031614610ccc57600080fd5b6000610d23610cdb8a80611b17565b610ce99060a0810190611ad1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e192505050565b6003546001600160a01b031660009081526005602090815260408083206001600160e01b03198516845290915290205490915060ff16610d9e5760405162461bcd60e51b81526020600482015260166024820152751b595d1a1bd9081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610173565b6000610daa8a80611b17565b610db89060a0810190611ad1565b610dc6916004908290611b88565b810190610dd39190611749565b60035460405163f8b2cb4f60e01b81529193506001600160a01b03169150600090829063f8b2cb4f90610e0a908690600401611985565b60206040518083038186803b158015610e2257600080fd5b505afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906118be565b90506000610e683a89611bec565b90506000836001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ea557600080fd5b505afa158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd91906118be565b610ee961271084611bca565b610ef39190611bec565b90506000610f018284611bb2565b9050808411610f4d5760405162461bcd60e51b8152602060048201526018602482015277696e73756666696369656e74206170702062616c616e636560401b6044820152606401610173565b85604051602001610f5e9190611985565b60408051601f198184030181529190529f60009f509d5050505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610fe2858701876115e7565b6001546004549192506000916001600160a01b0390911690638e53548b9061100a9087611bb2565b856040518363ffffffff1660e01b8152600401611028929190611a1e565b60206040518083038186803b15801561104057600080fd5b505afa158015611054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107891906118be565b90506000600360009054906101000a90046001600160a01b031690506000816001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b1580156110cf57600080fd5b505afa1580156110e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110791906118be565b61111361271085611bca565b61111d9190611bec565b9050600061112b8285611bb2565b604051631a77d65360e31b81529091506001600160a01b0384169063d3beb2989061115c9088908590600401611999565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b505060408051878152602081018690529081018490527faad61a9664bc6be1128f98485df350d149d1d8f3dce21e21c1741501960b88099250606001905060405180910390a150505050505050505050565b60006111e7836113ee565b80156111f857506111f88383611421565b9392505050565b60008061120c8380611b17565b61121d9060408101906020016115e7565b6001600160a01b031663572b6c0560e01b61123b6020860186611b2d565b61124c9060c081019060a0016115e7565b60405160240161125c9190611985565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161129a9190611969565b600060405180830381855afa9150503d80600081146112d5576040519150601f19603f3d011682016040523d82523d6000602084013e6112da565b606091505b50915091508161132b5760405162461bcd60e51b815260206004820152601c60248201527b1a5cd51c9d5cdd1959119bdc9dd85c99195c8e881c995d995c9d195960221b6044820152606401610173565b805160201461137c5760405162461bcd60e51b815260206004820181905260248201527f697354727573746564466f727761726465723a2062616420726573706f6e73656044820152606401610173565b808060200190518101906113909190611682565b6113dc5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420666f7277617264657220666f7220726563697069656e74006044820152606401610173565b505050565b60006105b582600061150a565b6000611401826301ffc9a760e01b611421565b80156105b5575061141a826001600160e01b0319611421565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b0387169061753090611488908690611969565b6000604051808303818686fa925050503d80600081146114c4576040519150601f19603f3d011682016040523d82523d6000602084013e6114c9565b606091505b50915091506020815110156114e457600093505050506105b5565b8180156115005750808060200190518101906115009190611682565b9695505050505050565b6000611517826004611bb2565b835110156115645760405162461bcd60e51b815260206004820152601a6024820152791c995859109e5d195ccd0e8819185d18481d1bdbc81cda1bdc9d60321b6044820152606401610173565b5001602001516001600160e01b03191690565b803561158281611c67565b919050565b80356001600160e01b03198116811461158257600080fd5b60008083601f8401126115b157600080fd5b5081356001600160401b038111156115c857600080fd5b6020830191508360208285010111156115e057600080fd5b9250929050565b6000602082840312156115f957600080fd5b81356111f881611c67565b6000806040838503121561161757600080fd5b823561162281611c67565b915061163060208401611587565b90509250929050565b60008060006060848603121561164e57600080fd5b833561165981611c67565b925061166760208501611587565b9150604084013561167781611c7c565b809150509250925092565b60006020828403121561169457600080fd5b81516111f881611c7c565b6000602082840312156116b157600080fd5b6111f882611587565b6000806000806000608086880312156116d257600080fd5b85356001600160401b03808211156116e957600080fd5b6116f589838a0161159f565b90975095506020880135915061170a82611c7c565b909350604087013592506060870135908082111561172757600080fd5b508601610100818903121561173b57600080fd5b809150509295509295909350565b6000806040838503121561175c57600080fd5b82356001600160401b038082111561177357600080fd5b818501915085601f83011261178757600080fd5b81358181111561179957611799611c51565b604051601f8201601f19908116603f011681019083821181831017156117c1576117c1611c51565b816040528281528860208487010111156117da57600080fd5b82602086016020830137600060208483010152809650505050505061163060208401611577565b6000806000806000806080878903121561181a57600080fd5b86356001600160401b038082111561183157600080fd5b908801906040828b03121561184557600080fd5b9096506020880135908082111561185b57600080fd5b6118678a838b0161159f565b9097509550604089013591508082111561188057600080fd5b5061188d89828a0161159f565b979a9699509497949695606090950135949350505050565b6000602082840312156118b757600080fd5b5035919050565b6000602082840312156118d057600080fd5b5051919050565b600080604083850312156118ea57600080fd5b8235915060208301356118fc81611c67565b809150509250929050565b6001600160a01b03169052565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452611955816020860160208601611c0b565b601f01601f19169290920160200192915050565b6000825161197b818460208701611c0b565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6040815260006119c5604083018561193d565b905082151560208301529392505050565b6020815260006111f8602083018461193d565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135611a5381611c67565b6001600160a01b031660a0830152611a6d60808401611577565b611a7a60c0840182611907565b50611a8760a08401611577565b611a9460e0840182611907565b50611aa260c0840184611b43565b61010084810152611ab861014085018284611914565b91505060e0840135610120840152809150509392505050565b6000808335601e19843603018112611ae857600080fd5b8301803591506001600160401b03821115611b0257600080fd5b6020019150368190038213156115e057600080fd5b6000823560de1983360301811261197b57600080fd5b6000823560fe1983360301811261197b57600080fd5b6000808335601e19843603018112611b5a57600080fd5b83016020810192503590506001600160401b03811115611b7957600080fd5b8036038313156115e057600080fd5b60008085851115611b9857600080fd5b83861115611ba557600080fd5b5050820193919092039150565b60008219821115611bc557611bc5611c3b565b500190565b600082611be757634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611c0657611c06611c3b565b500290565b60005b83811015611c26578181015183820152602001611c0e565b83811115611c35576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a8557600080fd5b8015158114610a8557600080fdfea26469706673582212204477e91f97281fe0c3e7e6faa8f2e54e2e0ff29535215e81cbc56823c2bcfdfd64736f6c63430008070033
Deployed Bytecode
0x60806040526004361061011e5760003560e01c8062be5dd4146101e757806301ffc9a71461021e5780632d14c4b71461024e5780633a0892e3146102705780635c5e3db1146102ab5780636d7c3e2b146102cf578063715018a6146102ef57806376fa01c314610304578063776d1a01146103245780637bb05264146103445780637bdf2ec71461036457806380d324f1146103865780638da5cb5b146103a6578063921276ea146103bb578063ad12e50e146103ef578063b039a88f14610405578063b90b41cf1461044d578063bbdaa3c914610463578063ce1b815f1461047a578063da7422281461048f578063df463a66146104af578063e1838f8d146104c4578063f2fde38b146104e4578063f9c002f71461050457600080fd5b366101e2576001546001600160a01b031661017c5760405162461bcd60e51b81526020600482015260196024820152781c995b185e481a1d58881859191c995cdcc81b9bdd081cd95d603a1b60448201526064015b60405180910390fd5b60015460405163aa67c91960e01b81526001600160a01b039091169063aa67c9199034906101ae903090600401611985565b6000604051808303818588803b1580156101c757600080fd5b505af11580156101db573d6000803e3d6000fd5b5050505050005b600080fd5b3480156101f357600080fd5b50610207610202366004611801565b61051b565b6040516102159291906119b2565b60405180910390f35b34801561022a57600080fd5b5061023e61023936600461169f565b610569565b6040519015158152602001610215565b34801561025a57600080fd5b5061026e6102693660046118d7565b6105bb565b005b34801561027c57600080fd5b5061023e61028b366004611604565b600560209081526000928352604080842090915290825290205460ff1681565b3480156102b757600080fd5b506102c161290481565b604051908152602001610215565b3480156102db57600080fd5b5061026e6102ea3660046118a5565b610652565b3480156102fb57600080fd5b5061026e610686565b34801561031057600080fd5b5061026e61031f3660046116ba565b6106c1565b34801561033057600080fd5b5061026e61033f3660046115e7565b6106dd565b34801561035057600080fd5b5061026e61035f3660046115e7565b610762565b34801561037057600080fd5b50610379610819565b6040516102159190611985565b34801561039257600080fd5b50600354610379906001600160a01b031681565b3480156103b257600080fd5b50610379610828565b3480156103c757600080fd5b5060408051808201825260058152640332e302e360dc1b6020820152905161021591906119d6565b3480156103fb57600080fd5b506102c160045481565b34801561041157600080fd5b5061041a610837565b60405161021591908151815260208083015190820152604080830151908201526060918201519181019190915260800190565b34801561045957600080fd5b506102c161c35081565b34801561046f57600080fd5b506102c16201adb081565b34801561048657600080fd5b506103796108a0565b34801561049b57600080fd5b5061026e6104aa3660046115e7565b6108af565b3480156104bb57600080fd5b506102c1610966565b3480156104d057600080fd5b5061026e6104df366004611639565b610978565b3480156104f057600080fd5b5061026e6104ff3660046115e7565b6109e8565b34801561051057600080fd5b506102c1620186a081565b60606000610527610a88565b61053088610af0565b61053988610b79565b61054288610bd3565b61054c8585610c3c565b61055a888888888888610c8c565b91509150965096945050505050565b60006001600160e01b031982166370d596f560e11b148061059a57506001600160e01b03198216630704183b60e11b145b806105b557506301ffc9a760e01b6001600160e01b03198316145b92915050565b336105c4610828565b6001600160a01b0316146105ea5760405162461bcd60e51b8152600401610173906119e9565b60015460405163f3fef3a360e01b81526001600160a01b039091169063f3fef3a39061061c9084908690600401611999565b600060405180830381600087803b15801561063657600080fd5b505af115801561064a573d6000803e3d6000fd5b505050505050565b3361065b610828565b6001600160a01b0316146106815760405162461bcd60e51b8152600401610173906119e9565b600455565b3361068f610828565b6001600160a01b0316146106b55760405162461bcd60e51b8152600401610173906119e9565b6106bf6000610f84565b565b6106c9610a88565b6106d68585858585610fd4565b5050505050565b336106e6610828565b6001600160a01b03161461070c5760405162461bcd60e51b8152600401610173906119e9565b600380546001600160a01b0319166001600160a01b0383161790556040517f3bfb4bbf112628248058745a3c57e35b13369386e474b8e56c552f3063a4a19690610757908390611985565b60405180910390a150565b3361076b610828565b6001600160a01b0316146107915760405162461bcd60e51b8152600401610173906119e9565b6107ab6001600160a01b0382166334f57c6760e01b6111dc565b6107f75760405162461bcd60e51b815260206004820152601f60248201527f746172676574206973206e6f7420612076616c6964204952656c6179487562006044820152606401610173565b600180546001600160a01b0319166001600160a01b0392909216919091179055565b6001546001600160a01b031690565b6000546001600160a01b031690565b6108626040518060800160405280600081526020016000815260200160008152602001600081525090565b604051806080016040528061c350620186a061087e9190611bb2565b8152602001620186a081526020016201adb08152602001612904815250905090565b6002546001600160a01b031690565b336108b8610828565b6001600160a01b0316146108de5760405162461bcd60e51b8152600401610173906119e9565b6108f86001600160a01b0382166309788f9960e21b6111dc565b6109445760405162461bcd60e51b815260206004820181905260248201527f746172676574206973206e6f7420612076616c69642049466f727761726465726044820152606401610173565b600280546001600160a01b0319166001600160a01b0392909216919091179055565b61097561c350620186a0611bb2565b81565b33610981610828565b6001600160a01b0316146109a75760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b0390921660009081526005602090815260408083206001600160e01b0319909416835292905220805491151560ff19909216919091179055565b336109f1610828565b6001600160a01b031614610a175760405162461bcd60e51b8152600401610173906119e9565b6001600160a01b038116610a7c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610173565b610a8581610f84565b50565b610a90610819565b6001600160a01b0316336001600160a01b0316146106bf5760405162461bcd60e51b815260206004820152601e60248201527f63616e206f6e6c792062652063616c6c65642062792052656c617948756200006044820152606401610173565b610afd6020820182611b2d565b610b0e9060c081019060a0016115e7565b6001600160a01b0316610b1f6108a0565b6001600160a01b031614610b705760405162461bcd60e51b8152602060048201526018602482015277119bdc9dd85c99195c881a5cc81b9bdd081d1c9d5cdd195960421b6044820152606401610173565b610a85816111ff565b610b838180611b17565b6040013515610a855760405162461bcd60e51b815260206004820152601c60248201527b1d985b1d59481d1c985b9cd9995c881b9bdd081cdd5c1c1bdc9d195960221b6044820152606401610173565b610be06020820182611b2d565b610bee9060c0810190611ad1565b159050610a855760405162461bcd60e51b815260206004820152601c60248201527b73686f756c642068617665206e6f207061796d61737465724461746160201b6044820152606401610173565b8015610c885760405162461bcd60e51b815260206004820152601b60248201527a73686f756c642068617665206e6f20617070726f76616c4461746160281b6044820152606401610173565b5050565b6003546060906000906001600160a01b0316610ca88980611b17565b610cb99060408101906020016115e7565b6001600160a01b031614610ccc57600080fd5b6000610d23610cdb8a80611b17565b610ce99060a0810190611ad1565b8080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506113e192505050565b6003546001600160a01b031660009081526005602090815260408083206001600160e01b03198516845290915290205490915060ff16610d9e5760405162461bcd60e51b81526020600482015260166024820152751b595d1a1bd9081b9bdd081dda1a5d195b1a5cdd195960521b6044820152606401610173565b6000610daa8a80611b17565b610db89060a0810190611ad1565b610dc6916004908290611b88565b810190610dd39190611749565b60035460405163f8b2cb4f60e01b81529193506001600160a01b03169150600090829063f8b2cb4f90610e0a908690600401611985565b60206040518083038186803b158015610e2257600080fd5b505afa158015610e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5a91906118be565b90506000610e683a89611bec565b90506000836001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b158015610ea557600080fd5b505afa158015610eb9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edd91906118be565b610ee961271084611bca565b610ef39190611bec565b90506000610f018284611bb2565b9050808411610f4d5760405162461bcd60e51b8152602060048201526018602482015277696e73756666696369656e74206170702062616c616e636560401b6044820152606401610173565b85604051602001610f5e9190611985565b60408051601f198184030181529190529f60009f509d5050505050505050505050505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000610fe2858701876115e7565b6001546004549192506000916001600160a01b0390911690638e53548b9061100a9087611bb2565b856040518363ffffffff1660e01b8152600401611028929190611a1e565b60206040518083038186803b15801561104057600080fd5b505afa158015611054573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107891906118be565b90506000600360009054906101000a90046001600160a01b031690506000816001600160a01b031663fc0438306040518163ffffffff1660e01b815260040160206040518083038186803b1580156110cf57600080fd5b505afa1580156110e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110791906118be565b61111361271085611bca565b61111d9190611bec565b9050600061112b8285611bb2565b604051631a77d65360e31b81529091506001600160a01b0384169063d3beb2989061115c9088908590600401611999565b600060405180830381600087803b15801561117657600080fd5b505af115801561118a573d6000803e3d6000fd5b505060408051878152602081018690529081018490527faad61a9664bc6be1128f98485df350d149d1d8f3dce21e21c1741501960b88099250606001905060405180910390a150505050505050505050565b60006111e7836113ee565b80156111f857506111f88383611421565b9392505050565b60008061120c8380611b17565b61121d9060408101906020016115e7565b6001600160a01b031663572b6c0560e01b61123b6020860186611b2d565b61124c9060c081019060a0016115e7565b60405160240161125c9190611985565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161129a9190611969565b600060405180830381855afa9150503d80600081146112d5576040519150601f19603f3d011682016040523d82523d6000602084013e6112da565b606091505b50915091508161132b5760405162461bcd60e51b815260206004820152601c60248201527b1a5cd51c9d5cdd1959119bdc9dd85c99195c8e881c995d995c9d195960221b6044820152606401610173565b805160201461137c5760405162461bcd60e51b815260206004820181905260248201527f697354727573746564466f727761726465723a2062616420726573706f6e73656044820152606401610173565b808060200190518101906113909190611682565b6113dc5760405162461bcd60e51b815260206004820152601f60248201527f696e76616c696420666f7277617264657220666f7220726563697069656e74006044820152606401610173565b505050565b60006105b582600061150a565b6000611401826301ffc9a760e01b611421565b80156105b5575061141a826001600160e01b0319611421565b1592915050565b604080516001600160e01b0319831660248083019190915282518083039091018152604490910182526020810180516001600160e01b03166301ffc9a760e01b179052905160009190829081906001600160a01b0387169061753090611488908690611969565b6000604051808303818686fa925050503d80600081146114c4576040519150601f19603f3d011682016040523d82523d6000602084013e6114c9565b606091505b50915091506020815110156114e457600093505050506105b5565b8180156115005750808060200190518101906115009190611682565b9695505050505050565b6000611517826004611bb2565b835110156115645760405162461bcd60e51b815260206004820152601a6024820152791c995859109e5d195ccd0e8819185d18481d1bdbc81cda1bdc9d60321b6044820152606401610173565b5001602001516001600160e01b03191690565b803561158281611c67565b919050565b80356001600160e01b03198116811461158257600080fd5b60008083601f8401126115b157600080fd5b5081356001600160401b038111156115c857600080fd5b6020830191508360208285010111156115e057600080fd5b9250929050565b6000602082840312156115f957600080fd5b81356111f881611c67565b6000806040838503121561161757600080fd5b823561162281611c67565b915061163060208401611587565b90509250929050565b60008060006060848603121561164e57600080fd5b833561165981611c67565b925061166760208501611587565b9150604084013561167781611c7c565b809150509250925092565b60006020828403121561169457600080fd5b81516111f881611c7c565b6000602082840312156116b157600080fd5b6111f882611587565b6000806000806000608086880312156116d257600080fd5b85356001600160401b03808211156116e957600080fd5b6116f589838a0161159f565b90975095506020880135915061170a82611c7c565b909350604087013592506060870135908082111561172757600080fd5b508601610100818903121561173b57600080fd5b809150509295509295909350565b6000806040838503121561175c57600080fd5b82356001600160401b038082111561177357600080fd5b818501915085601f83011261178757600080fd5b81358181111561179957611799611c51565b604051601f8201601f19908116603f011681019083821181831017156117c1576117c1611c51565b816040528281528860208487010111156117da57600080fd5b82602086016020830137600060208483010152809650505050505061163060208401611577565b6000806000806000806080878903121561181a57600080fd5b86356001600160401b038082111561183157600080fd5b908801906040828b03121561184557600080fd5b9096506020880135908082111561185b57600080fd5b6118678a838b0161159f565b9097509550604089013591508082111561188057600080fd5b5061188d89828a0161159f565b979a9699509497949695606090950135949350505050565b6000602082840312156118b757600080fd5b5035919050565b6000602082840312156118d057600080fd5b5051919050565b600080604083850312156118ea57600080fd5b8235915060208301356118fc81611c67565b809150509250929050565b6001600160a01b03169052565b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b60008151808452611955816020860160208601611c0b565b601f01601f19169290920160200192915050565b6000825161197b818460208701611c0b565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b6040815260006119c5604083018561193d565b905082151560208301529392505050565b6020815260006111f8602083018461193d565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b8281526040602082015281356040820152602082013560608201526040820135608082015260006060830135611a5381611c67565b6001600160a01b031660a0830152611a6d60808401611577565b611a7a60c0840182611907565b50611a8760a08401611577565b611a9460e0840182611907565b50611aa260c0840184611b43565b61010084810152611ab861014085018284611914565b91505060e0840135610120840152809150509392505050565b6000808335601e19843603018112611ae857600080fd5b8301803591506001600160401b03821115611b0257600080fd5b6020019150368190038213156115e057600080fd5b6000823560de1983360301811261197b57600080fd5b6000823560fe1983360301811261197b57600080fd5b6000808335601e19843603018112611b5a57600080fd5b83016020810192503590506001600160401b03811115611b7957600080fd5b8036038313156115e057600080fd5b60008085851115611b9857600080fd5b83861115611ba557600080fd5b5050820193919092039150565b60008219821115611bc557611bc5611c3b565b500190565b600082611be757634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615611c0657611c06611c3b565b500290565b60005b83811015611c26578181015183820152602001611c0e565b83811115611c35576000848401525b50505050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610a8557600080fd5b8015158114610a8557600080fdfea26469706673582212204477e91f97281fe0c3e7e6faa8f2e54e2e0ff29535215e81cbc56823c2bcfdfd64736f6c63430008070033
Loading...
Loading
[ Download: CSV Export ]
[ 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.