|
@@ -0,0 +1,188 @@
|
|
|
+pragma solidity ^0.5.0;
|
|
|
+
|
|
|
+contract IRelayHub {
|
|
|
+ // Relay management
|
|
|
+
|
|
|
+ // Add 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;
|
|
|
+
|
|
|
+ // Emited when a relay's stake or unstakeDelay are increased
|
|
|
+ event Staked(address indexed relay, uint256 stake, uint256 unstakeDelay);
|
|
|
+
|
|
|
+ // 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).
|
|
|
+ // Emits a RelayAdded event.
|
|
|
+ // This function can be called multiple times, emitting new RelayAdded events. Note that the received transactionFee
|
|
|
+ // is not enforced by relayCall.
|
|
|
+ function registerRelay(uint256 transactionFee, string memory url) public;
|
|
|
+
|
|
|
+ // Emitted when a relay is registered or re-registerd. 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);
|
|
|
+
|
|
|
+ // 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) public;
|
|
|
+
|
|
|
+ // 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) public;
|
|
|
+
|
|
|
+ // 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
|
|
|
+ }
|
|
|
+
|
|
|
+ // Returns a relay's status. Note that relays can be deleted when unstaked or penalized.
|
|
|
+ function getRelay(address relay) external view returns (uint256 totalStake, uint256 unstakeDelay, uint256 unstakeTime, address payable owner, RelayState state);
|
|
|
+
|
|
|
+ // Balance management
|
|
|
+
|
|
|
+ // 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 callingn withdraw.
|
|
|
+ // Emits a Deposited event.
|
|
|
+ function depositFor(address target) public payable;
|
|
|
+
|
|
|
+ // Emitted when depositFor is called, including the amount and account that was funded.
|
|
|
+ event Deposited(address indexed recipient, address indexed from, uint256 amount);
|
|
|
+
|
|
|
+ // Returns an account's deposits. These can be either a contnract'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 also use it to reduce their funding.
|
|
|
+ // Emits a Withdrawn event.
|
|
|
+ function withdraw(uint256 amount, address payable dest) public;
|
|
|
+
|
|
|
+ // Emitted when an account withdraws funds from RelayHub.
|
|
|
+ event Withdrawn(address indexed account, address indexed dest, uint256 amount);
|
|
|
+
|
|
|
+ // Relaying
|
|
|
+
|
|
|
+ // Check 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 memory encodedFunction,
|
|
|
+ uint256 transactionFee,
|
|
|
+ uint256 gasPrice,
|
|
|
+ uint256 gasLimit,
|
|
|
+ uint256 nonce,
|
|
|
+ bytes memory signature,
|
|
|
+ bytes memory approvalData
|
|
|
+ ) public 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
|
|
|
+ }
|
|
|
+
|
|
|
+ // Relays a transaction. For this to suceed, 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 order.
|
|
|
+ //
|
|
|
+ // Arguments:
|
|
|
+ // - from: the client originating the request
|
|
|
+ // - recipient: 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 forwared to acceptRelayedCall. This value is *not* verified by the Hub, but
|
|
|
+ // it still can be used for e.g. a signature.
|
|
|
+ //
|
|
|
+ // Emits a TransactionRelayed event.
|
|
|
+ function relayCall(
|
|
|
+ address from,
|
|
|
+ address to,
|
|
|
+ bytes memory encodedFunction,
|
|
|
+ uint256 transactionFee,
|
|
|
+ uint256 gasPrice,
|
|
|
+ uint256 gasLimit,
|
|
|
+ uint256 nonce,
|
|
|
+ bytes memory signature,
|
|
|
+ bytes memory approvalData
|
|
|
+ ) public;
|
|
|
+
|
|
|
+ // 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 field 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);
|
|
|
+
|
|
|
+ // Emitted when a transaction is relayed. Note that the actual encoded function might be reverted: this will be
|
|
|
+ // indicated in the status field.
|
|
|
+ // Useful when monitoring a relay's operation and relayed calls to a contract.
|
|
|
+ // 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
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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) public view returns (uint256);
|
|
|
+
|
|
|
+ // Returns the maximum recipient charge, given the amount of gas forwarded, gas price and relay fee.
|
|
|
+ function maxPossibleCharge(uint256 relayedCallStipend, uint256 gasPrice, uint256 transactionFee) public 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.
|
|
|
+
|
|
|
+ // 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 memory unsignedTx1, bytes memory signature1, bytes memory unsignedTx2, bytes memory signature2) public;
|
|
|
+
|
|
|
+ // Penalize a relay that sent a transaction that didn't target RelayHub's registerRelay or relayCall.
|
|
|
+ function penalizeIllegalTransaction(bytes memory unsignedTx, bytes memory signature) public;
|
|
|
+
|
|
|
+ event Penalized(address indexed relay, address sender, uint256 amount);
|
|
|
+
|
|
|
+ function getNonce(address from) external view returns (uint256);
|
|
|
+}
|
|
|
+
|