From 00a203896f531718b2d5b90fd3b2f25a0e121380 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Mon, 27 Aug 2018 11:58:52 -0400 Subject: [PATCH] Documentation for Gas Relayer pt1 --- gas-relayer/src/message-processor.js | 32 ++++++++++++++++++- .../src/strategy/AvailabilityStrategy.js | 13 ++++++-- gas-relayer/src/strategy/BaseStrategy.js | 28 ++++++++++++++++ gas-relayer/src/strategy/IdentityStrategy.js | 14 ++++++++ gas-relayer/src/strategy/SNTStrategy.js | 10 +++++- gas-relayer/src/utils.js | 0 6 files changed, 93 insertions(+), 4 deletions(-) delete mode 100644 gas-relayer/src/utils.js diff --git a/gas-relayer/src/message-processor.js b/gas-relayer/src/message-processor.js index 5dc073c..676da11 100644 --- a/gas-relayer/src/message-processor.js +++ b/gas-relayer/src/message-processor.js @@ -1,5 +1,14 @@ +/** + * Message Processor to analyze and execute strategies based on input objects + */ class MessageProcessor { + /** + * @param {object} config Configuration object obtained from `./config/config.js` + * @param {object} settings Settings obtained from parsing the configuration object + * @param {object} web3 Web3 object already configured + * @param {object} events Event emitter + */ constructor(config, settings, web3, events){ this.config = config; this.settings = settings; @@ -7,6 +16,12 @@ class MessageProcessor { this.events = events; } + /** + * Validate input message content + * @param {object} contract Contract object obtained from the settings based on the message topic + * @param {object} input Input object obtained from a message. + * @returns {object} State of validation + */ async _validateInput(contract, input){ console.info("Processing '%s' request to contract: %s", input.action, input.contract); @@ -37,6 +52,14 @@ class MessageProcessor { return {success: true}; } + /** + * Process strategy and return validation result + * @param {object} contract Contract object obtained from the settings based on the message topic + * @param {object} input Input object obtained from a message. + * @param {function} reply Reply function to return message + * @param {object} strategy Strategy to apply. If undefined, it will use a strategy based on the contract + * @returns {object} State of validation + */ async processStrategy(contract, input, reply, strategy){ const inputValidation = await this._validateInput(contract, input); if(!inputValidation.success){ @@ -62,6 +85,13 @@ class MessageProcessor { } } + /** + * Process strategy and based on its result, send a transaction to the blockchain + * @param {object} contract Contract object obtained from the settings based on the message topic + * @param {object} input Input object obtained from a message. + * @param {function} reply Reply function to return message + * @returns {undefined} + */ async processTransaction(contract, input, reply){ const validationResult = await this.processStrategy(contract, input, reply); @@ -89,7 +119,7 @@ class MessageProcessor { try { const receipt = await this.web3.eth.sendTransaction(p); // TODO: parse events - return reply("Transaction mined", receipt); + reply("Transaction mined", receipt); } catch(err){ reply("Couldn't mine transaction: " + err.message); // TODO log this? diff --git a/gas-relayer/src/strategy/AvailabilityStrategy.js b/gas-relayer/src/strategy/AvailabilityStrategy.js index 447202e..ab24d95 100644 --- a/gas-relayer/src/strategy/AvailabilityStrategy.js +++ b/gas-relayer/src/strategy/AvailabilityStrategy.js @@ -1,13 +1,22 @@ const Strategy = require('./BaseStrategy'); +/** + * Class representing a strategy to validate an 'availability' request. + * @extends Strategy + */ class AvailabilityStrategy extends Strategy { - async execute(input){ + /** + * Process availability strategy + * @param {object} input Input object obtained from an 'availability' request. It expects an object with this structure `{contract, address, action, gasToken, gasPrice}` + * @returns {object} Status of validation, and minimum price + */ + execute(input){ // Verifying if token is allowed const token = this.settings.getToken(input.gasToken); if(token == undefined) return {success: false, message: "Token not allowed"}; - // TODO Validate gasPrice, and return the minPrice accepted + // TODO: Validate gasPrice, and return the minPrice accepted const minPrice = 0.00; return { diff --git a/gas-relayer/src/strategy/BaseStrategy.js b/gas-relayer/src/strategy/BaseStrategy.js index bdd0ec7..8f3860d 100644 --- a/gas-relayer/src/strategy/BaseStrategy.js +++ b/gas-relayer/src/strategy/BaseStrategy.js @@ -2,7 +2,17 @@ const ganache = require("ganache-cli"); const Web3 = require('web3'); const erc20ABI = require('../../abi/ERC20Token.json'); +/** + * Abstract class used for validation strategies + */ class BaseStrategy { + + /** + * @param {object} web3 Web3 object already configured + * @param {object} config Configuration object obtained from `./config/config.js` + * @param {object} settings Settings obtained from parsing the configuration object + * @param {object} contract Contract object obtained from the settings based on the message topic + */ constructor(web3, config, settings, contract){ this.web3 = web3; this.settings = settings; @@ -10,6 +20,12 @@ class BaseStrategy { this.config = config; } + /** + * Obtain the balance in tokens or ETH from an address + * @param {string} address ETH address to obtain the balance from + * @param {object} token Token obtained from `settings.getToken(tokenSymbol)` + * @returns {web3.utils.BN} Balance + */ async getBalance(address, token){ // Determining balances of token used if(token.symbol == "ETH"){ @@ -21,6 +37,11 @@ class BaseStrategy { } } + /** + * Build Parameters Function + * @param {object} input Input object obtained from an `transaction` request. + * @returns {function} Function that simplifies accessing contract functions' parameters + */ _obtainParametersFunc(input){ const parameterList = this.web3.eth.abi.decodeParameters(this.contract.allowedFunctions[input.functionName].inputs, input.functionParameters); return function(parameterName){ @@ -28,6 +49,11 @@ class BaseStrategy { }; } + /** + * Estimate gas using web3 + * @param {object} input Input object obtained from an `transaction` request. + * @returns {web3.utils.toBN} Estimated gas fees + */ async _estimateGas(input){ let p = { from: this.config.node.blockchain.account, @@ -40,6 +66,8 @@ class BaseStrategy { /** * Simulate transaction using ganache. Useful for obtaining events + * @param {object} input Input object obtained from an `transaction` request. + * @returns {object} Simulated transaction receipt */ async _simulateTransaction(input){ let web3Sim = new Web3(ganache.provider({ diff --git a/gas-relayer/src/strategy/IdentityStrategy.js b/gas-relayer/src/strategy/IdentityStrategy.js index f718e9c..910f291 100644 --- a/gas-relayer/src/strategy/IdentityStrategy.js +++ b/gas-relayer/src/strategy/IdentityStrategy.js @@ -1,8 +1,17 @@ const Strategy = require('./BaseStrategy'); const erc20ABI = require('../../abi/ERC20Token.json'); +/** + * Class representing a strategy to validate a `transaction` request when the topic is related to Identities. + * @extends Strategy + */ class IdentityStrategy extends Strategy { + /** + * Validates if the contract being invoked represents an Identity instance + * @param {object} input Input object obtained from a `transaction` request. + * @returns {bool} Valid instance or not + */ async _validateInstance(input){ const instanceCodeHash = this.web3.utils.soliditySha3(await this.web3.eth.getCode(input.contract)); const kernelVerifSignature = this.web3.utils.soliditySha3(this.contract.kernelVerification).slice(0, 10); @@ -15,6 +24,11 @@ class IdentityStrategy extends Strategy { return this.web3.eth.abi.decodeParameter('bool', verificationResult); } + /** + * Process Identity strategy + * @param {object} input Input object obtained from an 'transaction' request. It expects an object with this structure `{contract, address, action, functionName, functionParameters, payload}` + * @returns {object} Status of validation and estimated gas + */ async execute(input){ if(this.contract.isIdentity){ let validInstance = await this._validateInstance(input); diff --git a/gas-relayer/src/strategy/SNTStrategy.js b/gas-relayer/src/strategy/SNTStrategy.js index 6bcc7b6..6725eab 100644 --- a/gas-relayer/src/strategy/SNTStrategy.js +++ b/gas-relayer/src/strategy/SNTStrategy.js @@ -3,9 +3,17 @@ const Strategy = require('./BaseStrategy'); const TransferSNT = "0x916b6511"; const ExecuteGasRelayed = "0x754e6ab0"; - +/** + * Class representing a strategy to validate a `transaction` request when the topic is related to SNTController. + * @extends Strategy + */ class SNTStrategy extends Strategy { + /** + * Process SNTController strategy + * @param {object} input Input object obtained from an 'transaction' request. It expects an object with this structure `{contract, address, action, functionName, functionParameters, payload}` + * @returns {object} Status of validation and estimated gas + */ async execute(input){ const params = this._obtainParametersFunc(input); diff --git a/gas-relayer/src/utils.js b/gas-relayer/src/utils.js deleted file mode 100644 index e69de29..0000000