/ DEMOS / status.im.md
status.im.md
  1  # SNT Gas Relay
  2  
  3  **Links of project**:
  4  
  5  - https://github.com/status-im/snt-gas-relay
  6  - https://ideas.status.im/ideas/150-gas-abstraction
  7  
  8  With the goals of simplifying the onboarding experience of users at Status.im, the idea of the gas relay network was created to have a series of nodes connected to Whisper, and competing between them for processing transactions, being able to accept specific tokens as a reward for the gas fees spent for processing transactions
  9  
 10  **Operation**
 11  1. User sends an availability request to a whisper symmetric key (equivalent to a public channel), containing the details of the transaction: contract to execute, function, gas price, gas token
 12  2. Relayers will analyze the request and if they accept the gas token, price and trust the contract, will reply back indicating their availability and min gas price accepted.
 13  3. In the user end, they will pick a relayer that has replied back, and proceed to send a whisper message to the relayer, with the same parameters and specifying the transaction data (to, value data)
 14  4. Once the relayer receives the transaction, it will perform the following validations:
 15  a. Validate the contract to invoke is known by the relayer
 16  b. Validate the gas token is accepted by the relayer and the gas price is greater or equal than the minimum accepted
 17  c. Validation of balances / estimation of gas
 18  d. Validation of transaction via estimation or simulation through Ganache
 19  5. If the transaction is valid, it will be broadcasted and a whisper message with the transaction hash will be sent back to the user
 20  6. Once the transaction is mined, a transaction receipt will be sent via whisper to the user
 21  
 22  For these operations, two contracts were developed:
 23  - **[SNTController](https://github.com/status-im/snt-gas-relay/blob/master/test-dapp/contracts/status/SNTController.sol)**: This contract is intended to be the owner of [SNT](https://etherscan.io/token/0x744d70fdbe2ba4cf95131626614a1763df805b9e) (a MiniMeToken). This contract allows the etherless transfer of SNT among parties, and contracts execution (this part intended to be used to generate new Identities via a factory)
 24  - **[IdentityGasRelay](https://github.com/status-im/snt-gas-relay/blob/master/test-dapp/contracts/identity/IdentityGasRelay.sol)**: Provides additional meta-transaction related functions to our implementation of ERC725/735 - Identities & Claims
 25  
 26  
 27  **How do we prevent a malicious relayer from either censoring a DApp they don't like or compete with, or just costing them gas by submitting a TX and then simultaneously submitting the same tx to their own relayer node, paying a slightly higher gas fee and then the honest relayers TX will fail and they will lose gas. It seems having miners act as relayers will solve this problem, but we don't want just miners to run the software right, any desktop client should be able to do it?**
 28  Our gas relayer does not work like that, we are doing gas abstraction, and it's decentralized, therefore it don't matter what a gas relayer thinks, their only incentive is to include a transaction for getting SNT (or other erc20 that gas relayer have interest) for it.
 29  
 30  **What about state channels with deterministic contract addresses for handling gas-less transactions? So, we agree that the state channel contract will be at 0xdeadbeef, then - as soon as some funds show up there, I as the operator deploy the contract and open the channel that the user can then use to send tokens without paying gas at any point?**
 31  
 32  State channels can be used with gas relayer just if they would be used with ether gas. We are doing gas abstraction in top of account contract, so everything that works with EOA+ethergas works with Identity+ERC20gas. You basically could use any erc20 to open a state channel and transfer those tokens there, all only ever holding SNT.
 33  
 34  
 35  **Would it not be possible for a user to submit a tx to an honest relayer node, and then submit that same tx to their own, malicious relayer node, have their node broadcast the tx at a higher gas fee, get it included first, and then the honest relayer's tx will fail and they will lose the gas they spent without receiving any tokens?**
 36  
 37  We don't solve that problem right now. We expect to solve that by integrating the gas relayer in PoS. The gas cost wasted in the case mentioned would be low. To avoid that, gas relayers would black list addresses that behave like this. Integrating with PoS means validators themselves include that transactions using ether gas price zero. At the moment we will not deal with this, unless it proven to be a problem. The most natural solution is to, instead "transaction signer" making a signature than anyone can include, it would select one of many and make a signature specifically to that. There, we might not need a blocklist, while the "transaction signer" can still sign the same nonce to multiple accounts, however then we can punish the transaction signer.
 38  
 39  
 40  
 41  **Video DEMO Link:**
 42  
 43  - https://youtu.be/8AeIe2YMKnk
 44  
 45  **Video DEMO summary**
 46  
 47  - On the video it's shown the process of creating a etherless transaction for the transfer of tokens and a contract function invokation.
 48  
 49  ## Code
 50  
 51  ### Meta-tx format
 52  
 53  #### Format 
 54  
 55  Signed message hashes are built via the following functions:
 56  
 57  ##### SNTController
 58  ```
 59  /**
 60   * @notice get execution hash
 61   * @param _allowedContract address of a contract in execution trust list;
 62   * @param _data msg.data to be sent to `_allowedContract`
 63   * @param _nonce current signNonce of message signer
 64   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
 65   * @param _gasMinimal minimal amount of gas needed to complete the execution
 66   */
 67  function getExecuteGasRelayedHash(
 68      address _allowedContract,
 69      bytes _data,
 70      uint256 _nonce,
 71      uint256 _gasPrice,
 72      uint256 _gasMinimal
 73  ) public view returns (bytes32 execHash);
 74  
 75  /**
 76   * @notice get transfer hash
 77   * @param _to address receving the tokens from message signer
 78   * @param _amount total being transfered
 79   * @param _nonce current signNonce of message signer
 80   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
 81   */
 82  function getTransferSNTHash(
 83      address _to,
 84      uint256 _amount,
 85      uint256 _nonce,
 86      uint256 _gasPrice
 87  ) public view returns (bytes32 txHash);
 88  ```
 89  
 90  ##### IdentityGasRelay
 91  ```
 92  /**
 93   * @notice get callGasRelay Hash
 94   * @param _to destination of call
 95   * @param _value call value (ether)
 96   * @param _dataHash call data hash
 97   * @param _nonce current identity nonce
 98   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
 99   * @param _gasLimit minimal gasLimit required to execute this call
100   * @param _gasToken token being used for paying `msg.sender` 
101   * @return callGasRelayHash the hash to be signed by wallet
102   */
103  function callGasRelayHash(
104      address _to,
105      uint256 _value,
106      bytes32 _dataHash,
107      uint _nonce,
108      uint256 _gasPrice,
109      uint256 _gasLimit,
110      address _gasToken
111  ) public view returns (bytes32 _callGasRelayHash);
112  
113  /**
114   * @notice get deployGasRelay Hash
115   * @param _value call value (ether)
116   * @param _dataHash call data hash
117   * @param _nonce current identity nonce
118   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
119   * @param _gasLimit minimal gasLimit required to execute this call
120   * @param _gasToken token being used for paying `msg.sender` 
121   * @return callGasRelayHash the hash to be signed by wallet
122   */
123  function deployGasRelayHash(
124      uint256 _value,
125      bytes32 _dataHash,
126      uint256 _nonce,
127      uint256 _gasPrice,
128      uint256 _gasLimit,
129      address _gasToken
130  ) public view returns (bytes32 _callGasRelayHash);
131  
132  /**
133   * @notice get approveAndCallHash
134   * @param _to destination of call
135   * @param _value call value (ether)
136   * @param _dataHash call data hash
137   * @param _nonce current identity nonce
138   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
139   * @param _gasLimit minimal gasLimit required to execute this call
140   * @param _gasToken token being used for paying `msg.sender` 
141   * @return callGasRelayHash the hash to be signed by wallet
142   */
143  function approveAndCallGasRelayHash(
144      address _baseToken,
145      address _to,
146      uint256 _value,
147      bytes32 _dataHash,
148      uint _nonce,
149      uint256 _gasPrice,
150      uint256 _gasLimit,
151      address _gasToken
152  ) public view returns (bytes32 _callGasRelayHash);
153  
154  ```
155  
156  #### Tx 
157  
158  - [Protocol](https://github.com/status-im/snt-gas-relay/blob/master/relayer-protocol.md)
159  - [JS library for building mrelayer whisper comms](https://github.com/status-im/snt-gas-relay/blob/master/javascript-library.md)
160  
161  #### Rx
162  TODO - Documentation for transaction receipts is still in progress
163      
164  ### Contract interface + Execution function
165  
166  #### SNTController
167  
168  ```
169  /** 
170   * @notice allows externally owned address sign a message to transfer SNT and pay for the fees in SNT
171   * @param _to address receving the tokens from message signer
172   * @param _amount total being transfered
173   * @param _nonce current signNonce of message signer
174   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
175   * @param _signature concatenated rsv of message
176   */
177  function transferSNT(
178      address _to,
179      uint256 _amount,
180      uint256 _nonce,
181      uint256 _gasPrice,
182      bytes _signature
183  ) external;
184  
185   /**
186   * @notice allows externally owned address sign a message to offer SNT for an execution 
187   * @param _allowedContract address of a contracts in execution trust list;
188   * @param _data msg.data to be sent to `_allowedContract`
189   * @param _nonce current signNonce of message signer
190   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
191   * @param _gasMinimal minimal amount of gas needed to complete the execution
192   * @param _signature concatenated rsv of message
193   */
194  function executeGasRelayed(
195      address _allowedContract,
196      bytes _data,
197      uint256 _nonce,
198      uint256 _gasPrice,
199      uint256 _gasMinimal,
200      bytes _signature
201  ) external;
202  
203  ```
204  
205  #### IdentityGasRelay
206  
207  ```
208  /**
209   * @notice include ethereum signed callHash in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
210   *         allows identity of being controlled without requiring ether in key balace
211   * @param _to destination of call
212   * @param _value call value (ether)
213   * @param _data call data
214   * @param _nonce current identity nonce
215   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
216   * @param _gasLimit minimal gasLimit required to execute this call
217   * @param _gasToken token being used for paying `msg.sender`
218   * @param _messageSignatures rsv concatenated ethereum signed message signatures required
219   */
220  function callGasRelayed(
221      address _to,
222      uint256 _value,
223      bytes _data,
224      uint _nonce,
225      uint _gasPrice,
226      uint _gasLimit,
227      address _gasToken, 
228      bytes _messageSignatures
229  );
230      
231  /**
232   * @notice deploys contract in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
233   *         allows identity of being controlled without requiring ether in key balace
234   * @param _value call value (ether) to be sent to newly created contract
235   * @param _data contract code data
236   * @param _nonce current identity nonce
237   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
238   * @param _gasLimit minimal gasLimit required to execute this call
239   * @param _gasToken token being used for paying `msg.sender`
240   * @param _messageSignatures rsv concatenated ethereum signed message signatures required
241   */
242  function deployGasRelayed(
243      uint256 _value, 
244      bytes _data,
245      uint _nonce,
246      uint _gasPrice,
247      uint _gasLimit,
248      address _gasToken, 
249      bytes _messageSignatures
250  ) external returns(address deployedAddress);
251          
252  /**
253   * @notice include ethereum signed approve ERC20 and call hash 
254   *         (`ERC20Token(baseToken).approve(_to, _value)` + `_to.call(_data)`).
255   *         in return of gas proportional amount multiplied by `_gasPrice` of `_gasToken`
256   *         fixes race condition in double transaction for ERC20.
257   * @param _baseToken token approved for `_to`
258   * @param _to destination of call
259   * @param _value call value (in `_baseToken`)
260   * @param _data call data
261   * @param _nonce current identity nonce
262   * @param _gasPrice price in SNT paid back to msg.sender for each gas unit used
263   * @param _gasLimit minimal gasLimit required to execute this call
264   * @param _gasToken token being used for paying `msg.sender`
265   * @param _messageSignatures rsv concatenated ethereum signed message signatures required
266   */
267  function approveAndCallGasRelayed(
268      address _baseToken, 
269      address _to,
270      uint256 _value,
271      bytes _data,
272      uint _nonce,
273      uint _gasPrice,
274      uint _gasLimit,
275      address _gasToken,
276      bytes _messageSignatures
277  ) external returns(bool success);
278  ```