diff --git a/federator/README.md b/federator/README.md index edb7d9331..1aa9a2e5e 100644 --- a/federator/README.md +++ b/federator/README.md @@ -7,7 +7,7 @@ The federators will be the owners of the contracts willing to allow to cross the ## Config Go to /federator/config copy `config.sample.js` file and rename it to `config.js` set mainchain and sidechain to point to the json files of the networks you are suing, for example rsktestnet-kovan.json and kovan.json, `make sure to set the host parameter of those files`. Create the file `federator.key` inside the config folder, and add the private key of the member of the Federation contract. The members of the federation are controled by the MultiSig contract, same that is owner of the Bridge and AllowedTokens contracts. - +You will also need to add an [etherscan api key](https://etherscan.io/myapikey) in this config file. ## Usage Run `npm install` to install the dependencies, make sure you followed the previous config step. Then to start the service run `npm start` which will start a single federator that listen to both networks. Check the logs to see that everything is working properly. @@ -24,14 +24,15 @@ In order to test with multiple federators, ensure they're added as members of th To run the federator using Docker first, go to the /federator/config folder and rename `config.sample.js` to `config.js`. In that file you will dedcide the networks the federate must be listening, for example for the bridge in testnet a federator config.js will look like -```json +```js module.exports = { mainchain: require('./rsktestnet-kovan.json'), sidechain: require('./kovan.json'), runEvery: 1, // In minutes, confirmations: 10,// Number of blocks before processing it, privateKey: require('federator.key'), - storagePath: './db' + storagePath: './db', + etherscanApiKey: '', } ``` diff --git a/federator/config/config.sample.js b/federator/config/config.sample.js index a3c14a7c7..dbd6c7150 100644 --- a/federator/config/config.sample.js +++ b/federator/config/config.sample.js @@ -5,5 +5,6 @@ module.exports = { runEvery: 2, // In minutes, confirmations: 120, // Number of blocks before processing it, if working with ganache set as 0 privateKey: fs.readFileSync(`${__dirname}/federator.key`, 'utf8'), - storagePath: './db' + storagePath: './db', + etherscanApiKey: '', } \ No newline at end of file diff --git a/federator/package-lock.json b/federator/package-lock.json index f600cfd56..171d6ee6b 100644 --- a/federator/package-lock.json +++ b/federator/package-lock.json @@ -508,28 +508,36 @@ } }, "@ethersproject/signing-key": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.0.4.tgz", - "integrity": "sha512-I6pJoga1IvhtjYK5yXzCjs4ZpxrVbt9ZRAlpEw0SW9UuV020YfJH5EIVEGR2evdRceS3nAQIggqbsXSkP8Y1Dg==", - "requires": { - "@ethersproject/bytes": "^5.0.4", - "@ethersproject/logger": "^5.0.5", - "@ethersproject/properties": "^5.0.3", - "elliptic": "6.5.3" + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.1.0.tgz", + "integrity": "sha512-tE5LFlbmdObG8bY04NpuwPWSRPgEswfxweAI1sH7TbP0ml1elNfqcq7ii/3AvIN05i5U0Pkm3Tf8bramt8MmLw==", + "requires": { + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/logger": "^5.1.0", + "@ethersproject/properties": "^5.1.0", + "bn.js": "^4.4.0", + "elliptic": "6.5.4" }, "dependencies": { - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "@ethersproject/bytes": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.1.0.tgz", + "integrity": "sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g==", "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "@ethersproject/logger": "^5.1.0" + } + }, + "@ethersproject/logger": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.1.0.tgz", + "integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw==" + }, + "@ethersproject/properties": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.1.0.tgz", + "integrity": "sha512-519KKTwgmH42AQL3+GFV3SX6khYEfHsvI6v8HYejlkigSDuqttdgVygFTDsGlofNFchhDwuclrxQnD5B0YLNMg==", + "requires": { + "@ethersproject/logger": "^5.1.0" } } } @@ -545,19 +553,95 @@ } }, "@ethersproject/transactions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.0.3.tgz", - "integrity": "sha512-cqsAAFUQV6iWqfgLL7KCPNfd3pXJPDdYtE6QuBEAIpc7cgbJ7TIDCF/dN+1otfERHJIbjGSNrhh4axKRnSFswg==", - "requires": { - "@ethersproject/address": "^5.0.3", - "@ethersproject/bignumber": "^5.0.6", - "@ethersproject/bytes": "^5.0.4", - "@ethersproject/constants": "^5.0.3", - "@ethersproject/keccak256": "^5.0.3", - "@ethersproject/logger": "^5.0.5", - "@ethersproject/properties": "^5.0.3", - "@ethersproject/rlp": "^5.0.3", - "@ethersproject/signing-key": "^5.0.4" + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.1.1.tgz", + "integrity": "sha512-Nwgbp09ttIVN0OoUBatCXaHxR7grWPHbozJN8v7AXDLrl6nnOIBEMDh+yJTnosSQlFhcyjfTGGN+Mx6R8HdvMw==", + "requires": { + "@ethersproject/address": "^5.1.0", + "@ethersproject/bignumber": "^5.1.0", + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/constants": "^5.1.0", + "@ethersproject/keccak256": "^5.1.0", + "@ethersproject/logger": "^5.1.0", + "@ethersproject/properties": "^5.1.0", + "@ethersproject/rlp": "^5.1.0", + "@ethersproject/signing-key": "^5.1.0" + }, + "dependencies": { + "@ethersproject/address": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.1.0.tgz", + "integrity": "sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg==", + "requires": { + "@ethersproject/bignumber": "^5.1.0", + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/keccak256": "^5.1.0", + "@ethersproject/logger": "^5.1.0", + "@ethersproject/rlp": "^5.1.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.1.1.tgz", + "integrity": "sha512-AVz5iqz7+70RIqoQTznsdJ6DOVBYciNlvO+AlQmPTB6ofCvoihI9bQdr6wljsX+d5W7Yc4nyvQvP4JMzg0Agig==", + "requires": { + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/logger": "^5.1.0", + "bn.js": "^4.4.0" + } + }, + "@ethersproject/bytes": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.1.0.tgz", + "integrity": "sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g==", + "requires": { + "@ethersproject/logger": "^5.1.0" + } + }, + "@ethersproject/constants": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.1.0.tgz", + "integrity": "sha512-0/SuHrxc8R8k+JiLmJymxHJbojUDWBQqO+b+XFdwaP0jGzqC09YDy/CAlSZB6qHsBifY8X3I89HcK/oMqxRdBw==", + "requires": { + "@ethersproject/bignumber": "^5.1.0" + } + }, + "@ethersproject/keccak256": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.1.0.tgz", + "integrity": "sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig==", + "requires": { + "@ethersproject/bytes": "^5.1.0", + "js-sha3": "0.5.7" + } + }, + "@ethersproject/logger": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.1.0.tgz", + "integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw==" + }, + "@ethersproject/properties": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.1.0.tgz", + "integrity": "sha512-519KKTwgmH42AQL3+GFV3SX6khYEfHsvI6v8HYejlkigSDuqttdgVygFTDsGlofNFchhDwuclrxQnD5B0YLNMg==", + "requires": { + "@ethersproject/logger": "^5.1.0" + } + }, + "@ethersproject/rlp": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.1.0.tgz", + "integrity": "sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw==", + "requires": { + "@ethersproject/bytes": "^5.1.0", + "@ethersproject/logger": "^5.1.0" + } + }, + "js-sha3": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", + "integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=" + } } }, "@istanbuljs/load-nyc-config": { @@ -1153,6 +1237,14 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "requires": { + "follow-redirects": "^1.10.0" + } + }, "babel-jest": { "version": "26.3.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.3.0.tgz", @@ -1469,27 +1561,6 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==" - }, - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" - } - } } } }, @@ -1867,17 +1938,24 @@ }, "dependencies": { "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", + "bn.js": "^4.11.9", + "brorand": "^1.1.0", "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } } } } @@ -2182,6 +2260,27 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, "emittery": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.1.tgz", @@ -2322,17 +2421,24 @@ }, "dependencies": { "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", + "bn.js": "^4.11.9", + "brorand": "^1.1.0", "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } } } } @@ -2775,6 +2881,11 @@ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.1.tgz", "integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==" }, + "follow-redirects": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.0.tgz", + "integrity": "sha512-0vRwd7RKQBTt+mgu87mtYeofLFZpTas2S9zY+jIeuLJMNvudIgF52nr19q40HOwH5RrhWIPuj9puybzSJiRrVg==" + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -5534,17 +5645,24 @@ }, "dependencies": { "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", + "bn.js": "^4.11.9", + "brorand": "^1.1.0", "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } } }, "nan": { @@ -6727,6 +6845,27 @@ "web3-utils": "1.2.11" }, "dependencies": { + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, "eth-lib": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", @@ -6735,22 +6874,6 @@ "bn.js": "^4.11.6", "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" - }, - "dependencies": { - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - } } }, "ethereumjs-tx": { @@ -6901,6 +7024,20 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "eth-lib": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.2.8.tgz", @@ -6909,22 +7046,6 @@ "bn.js": "^4.11.6", "elliptic": "^6.4.0", "xhr-request-promise": "^0.1.2" - }, - "dependencies": { - "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.0" - } - } } } } diff --git a/federator/package.json b/federator/package.json index 8e3a30a53..e5a5d4e10 100644 --- a/federator/package.json +++ b/federator/package.json @@ -18,6 +18,7 @@ "clean": "rm -rf ./db/*" }, "dependencies": { + "axios": "^0.21.1", "ethereumjs-tx": "^1.3.7", "ethereumjs-util": "^6.1.0", "log4js": "^5.0.0", diff --git a/federator/src/lib/Federator.js b/federator/src/lib/Federator.js index 0227b7971..388cee973 100644 --- a/federator/src/lib/Federator.js +++ b/federator/src/lib/Federator.js @@ -63,10 +63,10 @@ module.exports = class Federator { if (!fs.existsSync(this.config.storagePath)) { fs.mkdirSync(this.config.storagePath); } - let originalFromBlock = this.config.mainchain.fromBlock || 0; + let originalFromBlock = parseInt(this.config.mainchain.fromBlock) || 0; let fromBlock = null; try { - fromBlock = fs.readFileSync(this.lastBlockPath, 'utf8'); + fromBlock = parseInt(fs.readFileSync(this.lastBlockPath, 'utf8')); } catch(err) { fromBlock = originalFromBlock; } @@ -77,7 +77,7 @@ module.exports = class Federator { this.logger.warn(`Current chain Height ${toBlock} is the same or lesser than the last block processed ${fromBlock}`); return false; } - fromBlock = parseInt(fromBlock)+1; + fromBlock = fromBlock + 1; this.logger.debug('Running from Block', fromBlock); const recordsPerPage = 1000; @@ -163,7 +163,8 @@ module.exports = class Federator { this.logger.debug(`Block: ${log.blockHash} Tx: ${log.transactionHash} token: ${symbol} was already processed`); } } - this._saveProgress(this.lastBlockPath, toBlock); + + this._saveProgress(this.lastBlockPath, toBlock.toString()); return true; } catch (err) { diff --git a/federator/src/lib/TransactionSender.js b/federator/src/lib/TransactionSender.js index d2288e805..cb98b692a 100644 --- a/federator/src/lib/TransactionSender.js +++ b/federator/src/lib/TransactionSender.js @@ -4,6 +4,7 @@ const ethUtils = require('ethereumjs-util'); const utils = require('./utils'); const CustomError = require('./CustomError'); const fs = require('fs'); +const axios = require('axios'); module.exports = class TransactionSender { constructor(client, logger, config) { @@ -11,6 +12,7 @@ module.exports = class TransactionSender { this.logger = logger; this.chainId = null; this.manuallyCheck = `${config.storagePath || __dirname}/manuallyCheck.txt`; + this.etherscanApiKey = config.etherscanApiKey; } async getNonce(address) { @@ -24,9 +26,9 @@ module.exports = class TransactionSender { return `0x${Math.ceil(parseInt(number)).toString(16)}`; } - async getGasPrice(chainId) { - chainId = parseInt(chainId) - if(chainId>= 30 && chainId <=33) { + async getGasPrice() { + const chainId = await this.getChainId(); + if (chainId >= 30 && chainId <= 33) { return this.getRskGasPrice(); } return this.getEthGasPrice(); @@ -39,8 +41,49 @@ module.exports = class TransactionSender { } async getEthGasPrice() { + const chainId = await this.getChainId(); const gasPrice = parseInt(await this.client.eth.getGasPrice()); - return gasPrice <= 1 ? 1: Math.round(gasPrice * 1.5); + let useGasPrice = gasPrice <= 1 ? 1: Math.round(gasPrice * 1.5); + if (chainId == 1) { + const data = { + module: 'gastracker', + action: 'gasoracle' + } + const response = await this.useEtherscanApi(data); + const gasOraclePrice = response.result; + const proposeGasPrice = parseInt(this.client.utils.toWei(gasOraclePrice.ProposeGasPrice, 'gwei')); + const fastGasPrice = parseInt(this.client.utils.toWei(gasOraclePrice.FastGasPrice, 'gwei')); + // Add a 1.3% margin to avoid gas spikes as even fast gas price is not enough + const fastGasPricePlus = Math.ceil(fastGasPrice * 1.013); + if (fastGasPrice >= gasPrice && useGasPrice >= fastGasPrice) { + // If fastGasPrice is cheaper than gasPrice x1.5 use fastGasPrice + // we check that fastGasPrice is bigger than gasPrice to avoid posible attacks and API errors + this.logger.info('gasPrice', gasPrice,'useGasPrice', useGasPrice); + this.logger.info('gasOraclePrice', gasOraclePrice); + this.logger.debug('useGasPrice >= fastGasPrice, we will use', fastGasPricePlus); + return fastGasPricePlus; + } + if (useGasPrice <= 25000000000) { + // Currently when we restart an ethereum node the eth_getPrice is given values that are lower than the network + // Usually around 9 GWei or 15 GWei that's why we set the limit in 25 GWei + // When this happens we will use the gas price provided by etherscan + this.logger.info('gasPrice', gasPrice,'useGasPrice', useGasPrice); + this.logger.info('gasOraclePrice', gasOraclePrice); + this.logger.debug('useGasPrice <= 25000000000, we will use', fastGasPricePlus); + return fastGasPricePlus; + } + if (proposeGasPrice >= gasPrice && proposeGasPrice >= useGasPrice && proposeGasPrice < (useGasPrice * 5)) { + // if useGasPrice is lower than proposeGasPrice the transaction will probably get stucked + // we add a control in case proposeGasPrice is way high + // Try to use fastGasPrice if the value is too high, use proposeGasPrice and add 2 Gwei to help avoid gas spikes + const recommendedGas = fastGasPrice < (useGasPrice * 5) ? fastGasPricePlus : proposeGasPrice + 5000000000; + this.logger.info('gasPrice', gasPrice,'useGasPrice', useGasPrice); + this.logger.info('gasOraclePrice', gasOraclePrice); + this.logger.debug('proposeGasPrice >= useGasPrice, we will use', recommendedGas); + return recommendedGas; + } + } + return useGasPrice; } async getRskGasPrice() { @@ -49,10 +92,14 @@ module.exports = class TransactionSender { return gasPrice <= 1 ? 1: Math.round(gasPrice * 1.05); } + async getChainId() { + return parseInt(this.chainId || await this.client.eth.net.getId()); + } + async createRawTransaction(from, to, data, value) { const nonce = await this.getNonce(from); - const chainId = this.chainId || await this.client.eth.net.getId(); - const gasPrice = await this.getGasPrice(chainId); + const chainId = await this.getChainId(); + const gasPrice = await this.getGasPrice(); let rawTx = { chainId: chainId, gasPrice: this.numberToHexString(gasPrice), @@ -87,19 +134,58 @@ module.exports = class TransactionSender { return address; } + async useEtherscanApi(data) { + const chainId = await this.getChainId(); + if(chainId != 1 && chainId != 42) + throw new Error(`ChainId:${chainId} can't use Etherescan API`); + + const url = chainId == 1 ? 'https://api.etherscan.io/api' : 'https://api-kovan.etherscan.io/api'; + + const params = new URLSearchParams() + params.append('apikey', this.etherscanApiKey); + for (const property in data) { + params.append(property, data[property]); + } + + const config = { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }; + const response = await axios.post(url, params, config); + + if (response.data.status == 0) { + throw new Error(`Etherscan API:${url} data:${JSON.stringify(data)} message:${response.data.message} result:${response.data.result}`); + } + return response.data; + } + async sendTransaction(to, data, value, privateKey) { const stack = new Error().stack; - var from = await this.getAddress(privateKey); - let rawTx = await this.createRawTransaction(from, to, data, value); + const chainId = await this.getChainId(); let txHash; let error = ''; let errorInfo = ''; try { + let from = await this.getAddress(privateKey); + let rawTx = await this.createRawTransaction(from, to, data, value); let receipt; if (privateKey && privateKey.length) { let signedTx = this.signRawTransaction(rawTx, privateKey); const serializedTx = ethUtils.bufferToHex(signedTx.serialize()); - receipt = await this.client.eth.sendSignedTransaction(serializedTx).once('transactionHash', hash => txHash = hash); + receipt = await this.client.eth.sendSignedTransaction(serializedTx).once('transactionHash', async (hash) => { + txHash = hash; + if (chainId == 1) { + // send a POST request to Etherscan, we broadcast the same transaction as GETH is not working correclty + // see https://github.com/ethereum/go-ethereum/issues/22308 + const data = { + module: 'proxy', + action: 'eth_sendRawTransaction', + hex: serializedTx, + } + await this.useEtherscanApi(data); + } + }); } else { //If no private key provided we use personal (personal is only for testing) delete rawTx.r; @@ -108,19 +194,19 @@ module.exports = class TransactionSender { receipt = await this.client.eth.sendTransaction(rawTx).once('transactionHash', hash => txHash = hash); } if(receipt.status == 1) { - this.logger.info(`Transaction Successful txHash:${receipt.transactionHash} blockNumber:${receipt.blockNumber}`); + this.logger.info(`Transaction Successful chain:${chainId} txHash:${receipt.transactionHash} blockNumber:${receipt.blockNumber}`); return receipt; } - error = 'Transaction Receipt Status Failed'; + error = `Transaction Receipt Status Failed chain:${chainId}`; errorInfo = receipt; } catch(err) { if (err.message.indexOf('it might still be mined') > 0) { this.logger.warn(`Transaction was not mined within 750 seconds, please make sure your transaction was properly sent. Be aware that - it might still be mined. transactionHash:${txHash}`); - fs.appendFileSync(this.manuallyCheck, `transactionHash:${txHash} to:${to} data:${data}\n`); + it might still be mined. Chain:${chainId} transactionHash:${txHash}`); + fs.appendFileSync(this.manuallyCheck, `chain:${chainId} transactionHash:${txHash} to:${to} data:${data}\n`); return { transactionHash: txHash }; } - error = `Send Signed Transaction Failed TxHash:${txHash}`; + error = `Send Signed Transaction to chain:${chainId} Failed TxHash:${txHash}`; errorInfo = err; } this.logger.error(error, errorInfo); diff --git a/federator/src/main.js b/federator/src/main.js index 5d89c517e..479f31b53 100644 --- a/federator/src/main.js +++ b/federator/src/main.js @@ -13,11 +13,16 @@ const logger = log4js.getLogger('Federators'); logger.info('RSK Host', config.mainchain.host); logger.info('ETH Host', config.sidechain.host); -if(!config.mainchain || !config.sidechain) { +if (!config.mainchain || !config.sidechain) { logger.error('Mainchain and Sidechain configuration are required'); process.exit(); } +if (!config.etherscanApiKey) { + logger.error('Etherscan API configuration is required'); + process.exit(); +} + const mainFederator = new Federator(config, log4js.getLogger('MAIN-FEDERATOR')); const sideFederator = new Federator({ ...config,