diff --git a/gas-relayer/config/config.js b/gas-relayer/config/config.js index f15a048..7dcc33b 100644 --- a/gas-relayer/config/config.js +++ b/gas-relayer/config/config.js @@ -36,7 +36,7 @@ module.exports = { "currency": "USD" } }, - "%STTAddress%": { + "0xe9da775D1563DF526F031D241082722C492c7492": { "name": "Status Test Token", "symbol": "STT", "minAccepted":{ @@ -51,7 +51,7 @@ module.exports = { "IdentityGasRelay": { "abiFile": "../abi/IdentityGasRelay.json", "isIdentity": true, - "factoryAddress": "%IdentityFactoryAddress%", + "factoryAddress": "0x163b607b43002776f2901b8b5Ee33b9c0e83149C", "kernelVerification": "isKernel(bytes32)", "allowedFunctions": [ { @@ -68,7 +68,7 @@ module.exports = { "SNTController": { "abiFile": "../abi/SNTController.json", "isIdentity": false, - "address": "%SNTController%", + "address": "0x31B50180F8120964a689492BcE4B44f54C4A2F4e", "allowedFunctions": [ { "function":"transferSNT(address,uint256,uint256,uint256,bytes)" diff --git a/gas-relayer/config/config.json b/gas-relayer/config/config.json deleted file mode 100644 index 6c230b8..0000000 --- a/gas-relayer/config/config.json +++ /dev/null @@ -1,82 +0,0 @@ -{ - "gasPrice": 20, - "node": { - "local":{ - "protocol": "ws", - "host": "localhost", - "port": 8546 - }, - "ganache": { - "protocol": "http", - "host": "localhost", - "port": 8545 - }, - "blockchain": { - "account": "0xb8d851486d1c953e31a44374aca11151d49b8bb3" - }, - "whisper": { - "symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b", - "ttl": 1000, - "minPow": 0.2, - "powTime": 1000 - } - }, - - "heartbeat": { - "enabled": true, - "symKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b" - }, - - "tokens": { - "0x0000000000000000000000000000000000000000": { - "name": "Ethereum", - "symbol": "ETH", - "minAccepted":{ - "value": 1, - "currency": "USD" - } - }, - "%STTAddress%": { - "name": "Status Test Token", - "symbol": "STT", - "minAccepted":{ - "value": 1, - "currency": "USD" - }, - "pricePlugin": "../plugins/token-utils.js" - } - }, - - "contracts":{ - "IdentityGasRelay": { - "abiFile": "../abi/IdentityGasRelay.json", - "isIdentity": true, - "factoryAddress": "%IdentityFactoryAddress%", - "kernelVerification": "isKernel(bytes32)", - "allowedFunctions": [ - { - "function": "approveAndCallGasRelayed(address,address,uint256,bytes,uint256,uint256,uint256,address,bytes)", - "isToken": true - }, - { - "function": "callGasRelayed(address,uint256,bytes,uint256,uint256,uint256,address,bytes)", - "isToken": false - } - ], - "strategy": "../src/strategy/IdentityGasRelay.js" - }, - "SNTController": { - "abiFile": "../abi/SNTController.json", - "isIdentity": false, - "address": "0x96f0811c6484c59c2674da1f64e725c01d82c1b5", - "allowedFunctions": [ - { - "function":"transferSNT(address,uint256,uint256,uint256,bytes)" - }, - { - "function":"executeGasRelayed(address,bytes,uint256,uint256,uint256,bytes)" - } - ] - } - } -} diff --git a/gas-relayer/src/message-processor.js b/gas-relayer/src/message-processor.js index 4cce1ae..28c9ce8 100644 --- a/gas-relayer/src/message-processor.js +++ b/gas-relayer/src/message-processor.js @@ -23,13 +23,10 @@ class MessageProcessor { } async _validateInput(message){ + console.info("Processing request to: %s, %s", message.input.address, message.input.functionName); + const contract = this.settings.getContractByTopic(message.topic); - if(!(/^0x[0-9a-f]{40}$/i).test(message.input.address)){ - this._reply('Invalid address', message); - return false; - } - if(contract == undefined){ this._reply('Invalid topic', message); return false; @@ -47,7 +44,12 @@ class MessageProcessor { this._reply('Invalid contract code', message); return false; } - } + } else { + if(!(/^0x[0-9a-f]{40}$/i).test(message.input.address)){ + this._reply('Invalid address', message); + return false; + } + } return true; } @@ -89,8 +91,6 @@ class MessageProcessor { this._extractInput(message); const contract = this.settings.getContractByTopic(message.topic); - console.info("Processing request to: %s, %s", message.input.address, message.input.functionName); - if(!await this._validateInput(message)) return; // TODO Log if(contract.strategy){ diff --git a/gas-relayer/src/service.js b/gas-relayer/src/service.js index a09572c..1ff1d10 100644 --- a/gas-relayer/src/service.js +++ b/gas-relayer/src/service.js @@ -1,11 +1,9 @@ const EventEmitter = require('events'); const Web3 = require('web3'); -const config = require('../config/config.json'); - +const config = require('../config/config.js'); const ContractSettings = require('./contract-settings'); const MessageProcessor = require('./message-processor'); - // IDEA: A node should call an API (probably from a status node) to register itself as a // token gas relayer. diff --git a/gas-relayer/src/strategy/BaseStrategy.js b/gas-relayer/src/strategy/BaseStrategy.js new file mode 100644 index 0000000..010279f --- /dev/null +++ b/gas-relayer/src/strategy/BaseStrategy.js @@ -0,0 +1,62 @@ +const ganache = require("ganache-cli"); +const Web3 = require('web3'); +const erc20ABI = require('../../abi/ERC20Token.json'); + +class BaseStrategy { + constructor(web3, config, settings, contract){ + this.web3 = web3; + this.settings = settings; + this.contract = contract; + this.config = config; + } + + async getBalance(token, message, gasToken){ + // Determining balances of token used + if(token.symbol == "ETH"){ + return new this.web3.utils.BN(await this.web3.eth.getBalance(message.input.address)); + } else { + const Token = new this.web3.eth.Contract(erc20ABI.abi); + Token.options.address = gasToken; + return new this.web3.utils.BN(await Token.methods.balanceOf(message.input.address).call()); + } + } + + _obtainParametersFunc(message){ + const parameterList = this.web3.eth.abi.decodeParameters(this.contract.allowedFunctions[message.input.functionName].inputs, message.input.functionParameters); + return function(parameterName){ + return parameterList[parameterName]; + }; + } + + async _estimateGas(message, gasLimit){ + let web3Sim = new Web3(ganache.provider({ + fork: `${this.config.node.ganache.protocol}://${this.config.node.ganache.host}:${this.config.node.ganache.port}`, + locked: false, + gasLimit: 10000000 + })); + + let simAccounts = await web3Sim.eth.getAccounts(); + + let simulatedReceipt = await web3Sim.eth.sendTransaction({ + from: simAccounts[0], + to: message.input.address, + value: 0, + data: message.input.payload, + gasLimit: gasLimit * 0.95 // 95% of current chain latest gas block limit + + }); + + return web3Sim.utils.toBN(simulatedReceipt.gasUsed); + } + + /* + async execute(message){ + return { + success: true, + message: "Valid transaction" + }; + } + */ +} + +module.exports = BaseStrategy; diff --git a/gas-relayer/src/strategy/IdentityGasRelay.js b/gas-relayer/src/strategy/IdentityStrategy.js similarity index 60% rename from gas-relayer/src/strategy/IdentityGasRelay.js rename to gas-relayer/src/strategy/IdentityStrategy.js index bebfe70..1cbe36a 100644 --- a/gas-relayer/src/strategy/IdentityGasRelay.js +++ b/gas-relayer/src/strategy/IdentityStrategy.js @@ -1,22 +1,7 @@ +const Strategy = require('./BaseStrategy'); const erc20ABI = require('../../abi/ERC20Token.json'); -const ganache = require("ganache-cli"); -const Web3 = require('web3'); -class IdentityStrategy { - - constructor(web3, config, settings, contract){ - this.web3 = web3; - this.settings = settings; - this.contract = contract; - this.config = config; - } - - _obtainParametersFunc(message){ - const parameterList = this.web3.eth.abi.decodeParameters(this.contract.allowedFunctions[message.input.functionName].inputs, message.input.functionParameters); - return function(parameterName){ - return parameterList[parameterName]; - }; - } +class IdentityStrategy extends Strategy { async _validateInstance(message){ const instanceCodeHash = this.web3.utils.soliditySha3(await this.web3.eth.getCode(message.input.address)); @@ -30,40 +15,7 @@ class IdentityStrategy { return this.web3.eth.abi.decodeParameter('bool', verificationResult); } - async getBalance(token, message, gasToken){ - // Determining balances of token used - if(token.symbol == "ETH"){ - return new this.web3.utils.BN(await this.web3.eth.getBalance(message.input.address)); - } else { - const Token = new this.web3.eth.Contract(erc20ABI.abi); - Token.options.address = gasToken; - return new this.web3.utils.BN(await Token.methods.balanceOf(message.input.address).call()); - } - } - - async _estimateGas(message, gasLimit){ - let web3Sim = new Web3(ganache.provider({ - fork: `${this.config.node.ganache.protocol}://${this.config.node.ganache.host}:${this.config.node.ganache.port}`, - locked: false, - gasLimit: 10000000 - })); - - let simAccounts = await web3Sim.eth.getAccounts(); - - let simulatedReceipt = await web3Sim.eth.sendTransaction({ - from: simAccounts[0], - to: message.input.address, - value: 0, - data: message.input.payload, - gasLimit: gasLimit * 0.95 // 95% of current chain latest gas block limit - - }); - - return web3Sim.utils.toBN(simulatedReceipt.gasUsed); - } - async execute(message){ - if(this.contract.isIdentity){ let validInstance = await this._validateInstance(message); if(!validInstance){ @@ -110,7 +62,7 @@ class IdentityStrategy { return { success: true, - message: "Test" + message: "Valid transaction" }; } diff --git a/gas-relayer/src/strategy/SNTStrategy.js b/gas-relayer/src/strategy/SNTStrategy.js new file mode 100644 index 0000000..ab5260f --- /dev/null +++ b/gas-relayer/src/strategy/SNTStrategy.js @@ -0,0 +1,25 @@ +const Strategy = require('./BaseStrategy'); + +class SNTStrategy extends Strategy { + + async execute(message){ + const params = this._obtainParametersFunc(message); + + // TODO: logic is needed for executeGasRelayed. + + + // TODO: Transfers are simple and only need to: + // -------- estimate cost of transfer + // -------- check balance is enough to cover transfer + gas estimate + // ------- notify if not enough balance for transfer too. + + + return { + success: true, + message: "Valid transaction" + }; + } + +} + +module.exports = SNTStrategy;