735546619e
Signed-off-by: T-Hax <>
270 lines
12 KiB
Solidity
270 lines
12 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
|
|
pragma solidity ^0.6.0;
|
|
|
|
/**
|
|
* @dev Interface for `RelayHub`, the core contract of the GSN. Users should not need to interact with this contract
|
|
* directly.
|
|
*
|
|
* See the https://github.com/OpenZeppelin/openzeppelin-gsn-helpers[OpenZeppelin GSN helpers] for more information on
|
|
* how to deploy an instance of `RelayHub` on your local test network.
|
|
*/
|
|
interface IRelayHub {
|
|
// Relay management
|
|
|
|
/**
|
|
* @dev Adds stake to a relay and sets its `unstakeDelay`. If the relay does not exist, it is created, and the caller
|
|
* of this function becomes its owner. If the relay already exists, only the owner can call this function. A relay
|
|
* cannot be its own owner.
|
|
*
|
|
* All Ether in this function call will be added to the relay's stake.
|
|
* Its unstake delay will be assigned to `unstakeDelay`, but the new value must be greater or equal to the current one.
|
|
*
|
|
* Emits a {Staked} event.
|
|
*/
|
|
function stake(address relayaddr, uint256 unstakeDelay) external payable;
|
|
|
|
/**
|
|
* @dev Emitted when a relay's stake or unstakeDelay are increased
|
|
*/
|
|
event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);
|
|
|
|
/**
|
|
* @dev Registers the caller as a relay.
|
|
* The relay must be staked for, and not be a contract (i.e. this function must be called directly from an EOA).
|
|
*
|
|
* This function can be called multiple times, emitting new {RelayAdded} events. Note that the received
|
|
* `transactionFee` is not enforced by {relayCall}.
|
|
*
|
|
* Emits a {RelayAdded} event.
|
|
*/
|
|
function registerRelay(uint256 transactionFee, string calldata url) external;
|
|
|
|
/**
|
|
* @dev Emitted when a relay is registered or re-registered. Looking at these events (and filtering out
|
|
* {RelayRemoved} events) lets a client discover the list of available relays.
|
|
*/
|
|
event RelayAdded(address indexed relay, address indexed owner, uint256 transactionFee, uint256 stake, uint256 unstakeDelay, string url);
|
|
|
|
/**
|
|
* @dev Removes (deregisters) a relay. Unregistered (but staked for) relays can also be removed.
|
|
*
|
|
* Can only be called by the owner of the relay. After the relay's `unstakeDelay` has elapsed, {unstake} will be
|
|
* callable.
|
|
*
|
|
* Emits a {RelayRemoved} event.
|
|
*/
|
|
function removeRelayByOwner(address relay) external;
|
|
|
|
/**
|
|
* @dev Emitted when a relay is removed (deregistered). `unstakeTime` is the time when unstake will be callable.
|
|
*/
|
|
event RelayRemoved(address indexed relay, uint256 unstakeTime);
|
|
|
|
/** Deletes the relay from the system, and gives back its stake to the owner.
|
|
*
|
|
* Can only be called by the relay owner, after `unstakeDelay` has elapsed since {removeRelayByOwner} was called.
|
|
*
|
|
* Emits an {Unstaked} event.
|
|
*/
|
|
function unstake(address relay) external;
|
|
|
|
/**
|
|
* @dev Emitted when a relay is unstaked for, including the returned stake.
|
|
*/
|
|
event Unstaked(address indexed relay, uint256 stake);
|
|
|
|
// States a relay can be in
|
|
enum RelayState {
|
|
Unknown, // The relay is unknown to the system: it has never been staked for
|
|
Staked, // The relay has been staked for, but it is not yet active
|
|
Registered, // The relay has registered itself, and is active (can relay calls)
|
|
Removed // The relay has been removed by its owner and can no longer relay calls. It must wait for its unstakeDelay to elapse before it can unstake
|
|
}
|
|
|
|
/**
|
|
* @dev Returns a relay's status. Note that relays can be deleted when unstaked or penalized, causing this function
|
|
* to return an empty entry.
|
|
*/
|
|
function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);
|
|
|
|
// Balance management
|
|
|
|
/**
|
|
* @dev Deposits Ether for a contract, so that it can receive (and pay for) relayed transactions.
|
|
*
|
|
* Unused balance can only be withdrawn by the contract itself, by calling {withdraw}.
|
|
*
|
|
* Emits a {Deposited} event.
|
|
*/
|
|
function depositFor(address target) external payable;
|
|
|
|
/**
|
|
* @dev Emitted when {depositFor} is called, including the amount and account that was funded.
|
|
*/
|
|
event Deposited(address indexed recipient, address indexed from, uint256 amount);
|
|
|
|
/**
|
|
* @dev Returns an account's deposits. These can be either a contract's funds, or a relay owner's revenue.
|
|
*/
|
|
function balanceOf(address target) external view returns (uint256);
|
|
|
|
/**
|
|
* Withdraws from an account's balance, sending it back to it. Relay owners call this to retrieve their revenue, and
|
|
* contracts can use it to reduce their funding.
|
|
*
|
|
* Emits a {Withdrawn} event.
|
|
*/
|
|
function withdraw(uint256 amount, address payable dest) external;
|
|
|
|
/**
|
|
* @dev Emitted when an account withdraws funds from `RelayHub`.
|
|
*/
|
|
event Withdrawn(address indexed account, address indexed dest, uint256 amount);
|
|
|
|
// Relaying
|
|
|
|
/**
|
|
* @dev Checks if the `RelayHub` will accept a relayed operation.
|
|
* Multiple things must be true for this to happen:
|
|
* - all arguments must be signed for by the sender (`from`)
|
|
* - the sender's nonce must be the current one
|
|
* - the recipient must accept this transaction (via {acceptRelayedCall})
|
|
*
|
|
* Returns a `PreconditionCheck` value (`OK` when the transaction can be relayed), or a recipient-specific error
|
|
* code if it returns one in {acceptRelayedCall}.
|
|
*/
|
|
function canRelay(
|
|
address relay,
|
|
address from,
|
|
address to,
|
|
bytes calldata encodedFunction,
|
|
uint256 transactionFee,
|
|
uint256 gasPrice,
|
|
uint256 gasLimit,
|
|
uint256 nonce,
|
|
bytes calldata signature,
|
|
bytes calldata approvalData
|
|
) external view returns (uint256 status, bytes memory recipientContext);
|
|
|
|
// Preconditions for relaying, checked by canRelay and returned as the corresponding numeric values.
|
|
enum PreconditionCheck {
|
|
OK, // All checks passed, the call can be relayed
|
|
WrongSignature, // The transaction to relay is not signed by requested sender
|
|
WrongNonce, // The provided nonce has already been used by the sender
|
|
AcceptRelayedCallReverted, // The recipient rejected this call via acceptRelayedCall
|
|
InvalidRecipientStatusCode // The recipient returned an invalid (reserved) status code
|
|
}
|
|
|
|
/**
|
|
* @dev Relays a transaction.
|
|
*
|
|
* For this to succeed, multiple conditions must be met:
|
|
* - {canRelay} must `return PreconditionCheck.OK`
|
|
* - the sender must be a registered relay
|
|
* - the transaction's gas price must be larger or equal to the one that was requested by the sender
|
|
* - the transaction must have enough gas to not run out of gas if all internal transactions (calls to the
|
|
* recipient) use all gas available to them
|
|
* - the recipient must have enough balance to pay the relay for the worst-case scenario (i.e. when all gas is
|
|
* spent)
|
|
*
|
|
* If all conditions are met, the call will be relayed and the recipient charged. {preRelayedCall}, the encoded
|
|
* function and {postRelayedCall} will be called in that order.
|
|
*
|
|
* Parameters:
|
|
* - `from`: the client originating the request
|
|
* - `to`: the target {IRelayRecipient} contract
|
|
* - `encodedFunction`: the function call to relay, including data
|
|
* - `transactionFee`: fee (%) the relay takes over actual gas cost
|
|
* - `gasPrice`: gas price the client is willing to pay
|
|
* - `gasLimit`: gas to forward when calling the encoded function
|
|
* - `nonce`: client's nonce
|
|
* - `signature`: client's signature over all previous params, plus the relay and RelayHub addresses
|
|
* - `approvalData`: dapp-specific data forwarded to {acceptRelayedCall}. This value is *not* verified by the
|
|
* `RelayHub`, but it still can be used for e.g. a signature.
|
|
*
|
|
* Emits a {TransactionRelayed} event.
|
|
*/
|
|
function relayCall(
|
|
address from,
|
|
address to,
|
|
bytes calldata encodedFunction,
|
|
uint256 transactionFee,
|
|
uint256 gasPrice,
|
|
uint256 gasLimit,
|
|
uint256 nonce,
|
|
bytes calldata signature,
|
|
bytes calldata approvalData
|
|
) external;
|
|
|
|
/**
|
|
* @dev Emitted when an attempt to relay a call failed.
|
|
*
|
|
* This can happen due to incorrect {relayCall} arguments, or the recipient not accepting the relayed call. The
|
|
* actual relayed call was not executed, and the recipient not charged.
|
|
*
|
|
* The `reason` parameter contains an error code: values 1-10 correspond to `PreconditionCheck` entries, and values
|
|
* over 10 are custom recipient error codes returned from {acceptRelayedCall}.
|
|
*/
|
|
event CanRelayFailed(address indexed relay, address indexed from, address indexed to, bytes4 selector, uint256 reason);
|
|
|
|
/**
|
|
* @dev Emitted when a transaction is relayed.
|
|
* Useful when monitoring a relay's operation and relayed calls to a contract
|
|
*
|
|
* Note that the actual encoded function might be reverted: this is indicated in the `status` parameter.
|
|
*
|
|
* `charge` is the Ether value deducted from the recipient's balance, paid to the relay's owner.
|
|
*/
|
|
event TransactionRelayed(address indexed relay, address indexed from, address indexed to, bytes4 selector, RelayCallStatus status, uint256 charge);
|
|
|
|
// Reason error codes for the TransactionRelayed event
|
|
enum RelayCallStatus {
|
|
OK, // The transaction was successfully relayed and execution successful - never included in the event
|
|
RelayedCallFailed, // The transaction was relayed, but the relayed call failed
|
|
PreRelayedFailed, // The transaction was not relayed due to preRelatedCall reverting
|
|
PostRelayedFailed, // The transaction was relayed and reverted due to postRelatedCall reverting
|
|
RecipientBalanceChanged // The transaction was relayed and reverted due to the recipient's balance changing
|
|
}
|
|
|
|
/**
|
|
* @dev Returns how much gas should be forwarded to a call to {relayCall}, in order to relay a transaction that will
|
|
* spend up to `relayedCallStipend` gas.
|
|
*/
|
|
function requiredGas(uint256 relayedCallStipend) external view returns (uint256);
|
|
|
|
/**
|
|
* @dev Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
|
|
*/
|
|
function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) external view returns (uint256);
|
|
|
|
// Relay penalization.
|
|
// Any account can penalize relays, removing them from the system immediately, and rewarding the
|
|
// reporter with half of the relay's stake. The other half is burned so that, even if the relay penalizes itself, it
|
|
// still loses half of its stake.
|
|
|
|
/**
|
|
* @dev Penalize a relay that signed two transactions using the same nonce (making only the first one valid) and
|
|
* different data (gas price, gas limit, etc. may be different).
|
|
*
|
|
* The (unsigned) transaction data and signature for both transactions must be provided.
|
|
*/
|
|
function penalizeRepeatedNonce(bytes calldata unsignedTx1, bytes calldata signature1, bytes calldata unsignedTx2, bytes calldata signature2) external;
|
|
|
|
/**
|
|
* @dev Penalize a relay that sent a transaction that didn't target ``RelayHub``'s {registerRelay} or {relayCall}.
|
|
*/
|
|
function penalizeIllegalTransaction(bytes calldata unsignedTx, bytes calldata signature) external;
|
|
|
|
/**
|
|
* @dev Emitted when a relay is penalized.
|
|
*/
|
|
event Penalized(address indexed relay, address sender, uint256 amount);
|
|
|
|
/**
|
|
* @dev Returns an account's nonce in `RelayHub`.
|
|
*/
|
|
function getNonce(address from) external view returns (uint256);
|
|
}
|
|
|