* Add base Context contract
* Add GSNContext and tests
* Add RelayHub deployment to tests
* Add RelayProvider integration, complete GSNContext tests
* Switch dependency to openzeppelin-gsn-provider
* Add default txfee to provider
* Add basic signing recipient
* Sign more values
* Add comment clarifying RelayHub's msg.data
* Make context constructors internal
* Rename SigningRecipient to GSNRecipientSignedData
* Add ERC20Charge recipients
* Harcode RelayHub address into GSNContext
* Fix Solidity linter errors
* Run server from binary, use gsn-helpers to fund it
* Migrate to published @openzeppelin/gsn-helpers
* Silence false-positive compiler warning
* Use GSN helper assertions
* Rename meta-tx to gsn, take out of drafts
* Merge ERC20 charge recipients into a single one
* Rename GSNRecipients to Bouncers
* Add GSNBouncerUtils to decouple the bouncers from GSNRecipient
* Add _upgradeRelayHub
* Store RelayHub address using unstructored storage
* Add IRelayHub
* Add _withdrawDeposits to GSNRecipient
* Add relayHub version to recipient
* Make _acceptRelayedCall and _declineRelayedCall easier to use
* Rename GSNBouncerUtils to GSNBouncerBase, make it IRelayRecipient
* Improve GSNBouncerBase, make pre and post sender-protected and optional
* Fix GSNBouncerERC20Fee, add tests
* Add missing GSNBouncerSignature test
* Override transferFrom in __unstable__ERC20PrimaryAdmin
* Fix gsn dependencies in package.json
* Rhub address slot reduced by 1
* Rename relay hub changed event
* Use released gsn-provider
* Run relayer with short sleep of 1s instead of 100ms
* update package-lock.json
* clear circle cache
* use optimized gsn-provider
* update to latest @openzeppelin/gsn-provider
* replace with gsn dev provider
* remove relay server
* rename arguments in approveFunction
* fix GSNBouncerSignature test
* change gsn txfee
* initialize development provider only once
* update RelayHub interface
* adapt to new IRelayHub.withdraw
* update @openzeppelin/gsn-helpers
* update relayhub singleton address
* fix helper name
* set up gsn provider for coverage too
* lint
* Revert "set up gsn provider for coverage too"
This reverts commit 8a7b5be5f9.
* remove unused code
* add gsn provider to coverage
* move truffle contract options back out
* increase gas limit for coverage
* remove unreachable code
* add more gas for GSNContext test
* fix test suite name
* rename GSNBouncerBase internal API
* remove onlyRelayHub modifier
* add explicit inheritance
* remove redundant event
* update name of bouncers error codes enums
* add basic docs page for gsn contracts
* make gsn directory all caps
* add changelog entry
* lint
* enable test run to fail in coverage
189 lines
10 KiB
Solidity
189 lines
10 KiB
Solidity
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);
|
|
}
|
|
|