diff --git a/packages/bitcore-node/src/config.ts b/packages/bitcore-node/src/config.ts index a94465716d..6dfea8c06a 100644 --- a/packages/bitcore-node/src/config.ts +++ b/packages/bitcore-node/src/config.ts @@ -62,7 +62,7 @@ const Config = function(): ConfigType { dbPass: process.env.DB_PASS || '', numWorkers: cpus().length, chains: {}, - modules: ['./bitcoin', './bitcoin-cash', './ethereum'], + modules: ['./bitcoin', './bitcoin-cash', './ethereum', './rsk'], services: { api: { rateLimiter: { diff --git a/packages/bitcore-node/src/modules/ethereum/api/csp.ts b/packages/bitcore-node/src/modules/ethereum/api/csp.ts index 9b88654e60..9e20480736 100644 --- a/packages/bitcore-node/src/modules/ethereum/api/csp.ts +++ b/packages/bitcore-node/src/modules/ethereum/api/csp.ts @@ -89,7 +89,7 @@ export class ETHStateProvider extends InternalStateProvider implements IChainSta } async getERC20TokenInfo(network: string, tokenAddress: string) { - const token = await ETH.erc20For(network, tokenAddress); + const token = await this.erc20For(network, tokenAddress); // Use `this` rather than ETH to make it generic for other EVM compatible chains to facilitate the class based inheritance of ETHStateProvider const [name, decimals, symbol] = await Promise.all([ token.methods.name().call(), token.methods.decimals().call(), @@ -360,7 +360,7 @@ export class ETHStateProvider extends InternalStateProvider implements IChainSta async streamWalletTransactions(params: StreamWalletTransactionsParams) { const { network, wallet, res, args } = params; const { web3 } = await this.getWeb3(network); - const query = ETH.getWalletTransactionQuery(params); + const query = this.getWalletTransactionQuery(params); // Use this rather than ETH to make it generic for other EVM compatible chains to facilitate the class based inheritance of ETHStateProvider let transactionStream = new Readable({ objectMode: true }); const walletAddresses = (await this.getWalletAddresses(wallet._id!)).map(waddres => waddres.address); @@ -572,5 +572,11 @@ export class ETHStateProvider extends InternalStateProvider implements IChainSta }; } } - -export const ETH = new ETHStateProvider(); +/* + * + * Use the ETH implementation for RSK by inheriting the ETHStateProvider class rather than making its clone + * This will reduce lot of maintenance cost and avoid code duplication + * For other EVM compatible chains like RSK below export needs to be like new ETHStateProvider('RSK') + * It's just a suggestion to use process.env.chain evn variable untill bitpay team can make it more generic for other EVM like chains + */ +export const ETH = new ETHStateProvider(process.env.chain || 'ETH'); \ No newline at end of file diff --git a/packages/bitcore-node/src/modules/index.ts b/packages/bitcore-node/src/modules/index.ts index 1903b1fbfe..78633f7f0f 100644 --- a/packages/bitcore-node/src/modules/index.ts +++ b/packages/bitcore-node/src/modules/index.ts @@ -53,7 +53,8 @@ class ModuleManager extends BaseModule { BCH: './bitcoin-cash', DOGE: './dogecoin', LTC: './litecoin', - XRP: './ripple' + XRP: './ripple', + RSK: './rsk' }; loadConfigured() { diff --git a/packages/bitcore-node/src/modules/modules.md b/packages/bitcore-node/src/modules/modules.md index b5a03d1f88..784726d445 100644 --- a/packages/bitcore-node/src/modules/modules.md +++ b/packages/bitcore-node/src/modules/modules.md @@ -12,6 +12,7 @@ The modules in this table will automatically register with `bitcore-node` if you | LTC | litecoin | ./litecoin | | DOGE | dogecoin | ./dogecoin | | XRP | ripple | ./ripple | +| RSK | rsk | ./rsk | If there is a custom or third-party module you'd like to use, follow the example below. diff --git a/packages/bitcore-node/src/modules/rsk/api/csp.ts b/packages/bitcore-node/src/modules/rsk/api/csp.ts new file mode 100644 index 0000000000..2860d7f34b --- /dev/null +++ b/packages/bitcore-node/src/modules/rsk/api/csp.ts @@ -0,0 +1,18 @@ +import Config from '../../../config'; +import { ETHStateProvider } from '../../ethereum/api/csp'; + +export { EventLog } from '../../ethereum/api/csp'; +export class RSKStateProvider extends ETHStateProvider { + /* + * Reusing ETHStateProvider class for RSK + * Purpose is to avoid code duplication and reduce maintenance cost + */ + constructor(public chain: string = 'RSK') { + super(chain); + this.config = Config.chains[this.chain]; + } + +} + +export const RSK = new RSKStateProvider(); + diff --git a/packages/bitcore-node/src/modules/rsk/api/rsk-routes.ts b/packages/bitcore-node/src/modules/rsk/api/rsk-routes.ts new file mode 100644 index 0000000000..26bf16a43f --- /dev/null +++ b/packages/bitcore-node/src/modules/rsk/api/rsk-routes.ts @@ -0,0 +1,36 @@ +import { Router } from 'express'; +import logger from '../../../logger'; +import { RSK } from './csp'; +export const RskRoutes = Router(); + +RskRoutes.get('/api/RSK/:network/address/:address/txs/count', async (req, res) => { + let { address, network } = req.params; + try { + const nonce = await RSK.getAccountNonce(network, address); + res.json({ nonce }); + } catch (err) { + logger.error('Nonce Error::' + err); + res.status(500).send(err); + } +}); + +RskRoutes.post('/api/RSK/:network/gas', async (req, res) => { + const { from, to, value, data, gasPrice } = req.body; + const { network } = req.params; + try { + const gasLimit = await RSK.estimateGas({ network, from, to, value, data, gasPrice }); + res.json(gasLimit); + } catch (err) { + res.status(500).send(err); + } +}); + +RskRoutes.get('/api/RSK/:network/token/:tokenAddress', async (req, res) => { + const { network, tokenAddress } = req.params; + try { + const tokenInfo = await RSK.getERC20TokenInfo(network, tokenAddress); + res.json(tokenInfo); + } catch (err) { + res.status(500).send(err); + } +}); diff --git a/packages/bitcore-node/src/modules/rsk/index.ts b/packages/bitcore-node/src/modules/rsk/index.ts new file mode 100644 index 0000000000..3d81080959 --- /dev/null +++ b/packages/bitcore-node/src/modules/rsk/index.ts @@ -0,0 +1,15 @@ +import { BaseModule } from '..'; +import { RSKStateProvider } from './api/csp'; +import { RskRoutes } from './api/rsk-routes'; +import { RskP2pWorker } from './p2p/p2p'; +import { RskVerificationPeer } from './p2p/RskVerificationPeer'; + +export default class RSKModule extends BaseModule { + constructor(services: BaseModule['bitcoreServices']) { + super(services); + services.P2P.register('RSK', RskP2pWorker); + services.CSP.registerService('RSK', new RSKStateProvider('RSK')); + services.Api.app.use(RskRoutes); + services.Verification.register('RSK', RskVerificationPeer); + } +} diff --git a/packages/bitcore-node/src/modules/rsk/p2p/RskVerificationPeer.ts b/packages/bitcore-node/src/modules/rsk/p2p/RskVerificationPeer.ts new file mode 100644 index 0000000000..8aa7f1ce39 --- /dev/null +++ b/packages/bitcore-node/src/modules/rsk/p2p/RskVerificationPeer.ts @@ -0,0 +1,8 @@ +import { EthVerificationPeer } from '../../ethereum/p2p/EthVerificationPeer'; + +export class RskVerificationPeer extends EthVerificationPeer { + /* + * Reusing EthVerificationPeer class for RSK + * Purpose is to avoid code duplication and reduce maintenance cost + */ +} diff --git a/packages/bitcore-node/src/modules/rsk/p2p/p2p.ts b/packages/bitcore-node/src/modules/rsk/p2p/p2p.ts new file mode 100644 index 0000000000..0e31a29443 --- /dev/null +++ b/packages/bitcore-node/src/modules/rsk/p2p/p2p.ts @@ -0,0 +1,12 @@ +import { EthP2pWorker } from '../../ethereum/p2p/p2p'; +import { EthBlockStorage } from '../../ethereum/models/block'; +export class RskP2pWorker extends EthP2pWorker { + /* + * Reusing EthP2pWorker class for RSK + * Purpose is to avoid code duplication and reduce maintenance cost + */ + constructor({ chain, network, chainConfig, blockModel = EthBlockStorage}) { + super({ chain, network, chainConfig, blockModel }); + this.chain = 'RSK'; + } +} \ No newline at end of file diff --git a/packages/bitcore-wallet-client/src/lib/api.ts b/packages/bitcore-wallet-client/src/lib/api.ts index 350611299c..17e6efa256 100644 --- a/packages/bitcore-wallet-client/src/lib/api.ts +++ b/packages/bitcore-wallet-client/src/lib/api.ts @@ -2964,7 +2964,9 @@ export class API extends EventEmitter { ['btc', 'livenet', true], ['bch', 'livenet', true], ['doge', 'livenet', true], - ['ltc', 'livenet', true] + ['ltc', 'livenet', true], + ['rsk', 'livenet'], + ['rbtc', 'livenet'], ]; if (key.use44forMultisig) { // testing old multi sig diff --git a/packages/bitcore-wallet-client/src/lib/common/constants.ts b/packages/bitcore-wallet-client/src/lib/common/constants.ts index 20d23e8ac1..09989ac867 100644 --- a/packages/bitcore-wallet-client/src/lib/common/constants.ts +++ b/packages/bitcore-wallet-client/src/lib/common/constants.ts @@ -25,6 +25,7 @@ export const Constants = { 'btc', 'bch', 'eth', + 'rsk', 'xrp', 'doge', 'ltc', @@ -45,6 +46,7 @@ export const Constants = { 'pax', // backwards compatibility 'gusd', 'busd', + 'xusd', // Sovryn token 'dai', 'wbtc', 'shib', @@ -52,9 +54,9 @@ export const Constants = { 'euroc' ], UTXO_COINS: ['btc', 'bch', 'doge', 'ltc'], - CHAINS: ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc'], + CHAINS: ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc', 'rsk'], UTXO_CHAINS: ['btc', 'bch', 'doge', 'ltc'], - EVM_CHAINS: ['eth'], + EVM_CHAINS: ['eth', 'rsk'], TOKEN_OPTS: CWC.Constants.TOKEN_OPTS, UNITS: CWC.Constants.UNITS }; diff --git a/packages/bitcore-wallet-client/src/lib/common/utils.ts b/packages/bitcore-wallet-client/src/lib/common/utils.ts index 62237a4463..05f0e11f04 100644 --- a/packages/bitcore-wallet-client/src/lib/common/utils.ts +++ b/packages/bitcore-wallet-client/src/lib/common/utils.ts @@ -24,7 +24,8 @@ const Bitcore_ = { eth: Bitcore, xrp: Bitcore, doge: BitcoreLibDoge, - ltc: BitcoreLibLtc + ltc: BitcoreLibLtc, + rsk: Bitcore }; const PrivateKey = Bitcore.PrivateKey; const PublicKey = Bitcore.PublicKey; diff --git a/packages/bitcore-wallet-client/src/lib/key.ts b/packages/bitcore-wallet-client/src/lib/key.ts index 785fcba36d..53d39aa44a 100644 --- a/packages/bitcore-wallet-client/src/lib/key.ts +++ b/packages/bitcore-wallet-client/src/lib/key.ts @@ -397,6 +397,8 @@ export class Key { coinCode = '0'; } else if (opts.coin == 'eth') { coinCode = '60'; + } else if (opts.coin == 'rsk' || opts.coin == 'rbtc') { + coinCode = '137'; } else if (opts.coin == 'xrp') { coinCode = '144'; } else if (opts.coin == 'doge') { diff --git a/packages/bitcore-wallet-service/src/config.ts b/packages/bitcore-wallet-service/src/config.ts index 1f7b3cb8e3..977ba687ee 100644 --- a/packages/bitcore-wallet-service/src/config.ts +++ b/packages/bitcore-wallet-service/src/config.ts @@ -61,6 +61,14 @@ const Config = () => { url: 'https://api-eth.bitcore.io' } }, + rsk: { + livenet: { + url: 'https://api-rsk.bitcore.io' + }, + testnet: { + url: 'https://api-rsk.bitcore.io' + } + }, xrp: { livenet: { url: 'https://api-xrp.bitcore.io' diff --git a/packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts b/packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts index def6b8f7dc..6faba35dd4 100644 --- a/packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts +++ b/packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts @@ -19,6 +19,10 @@ const PROVIDERS = { livenet: 'https://api-eth.bitcore.io', testnet: 'https://api-eth.bitcore.io' }, + rsk: { + livenet: 'https://api-rsk.bitcore.io', + testnet: 'https://api-rsk.bitcore.io' + }, xrp: { livenet: 'https://api-xrp.bitcore.io', testnet: 'https://api-xrp.bitcore.io' diff --git a/packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8.ts b/packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8.ts index 2c541f27f0..b83b934aa3 100644 --- a/packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8.ts +++ b/packages/bitcore-wallet-service/src/lib/blockchainexplorers/v8.ts @@ -13,6 +13,7 @@ const Bitcore_ = { btc: Bitcore, bch: require('bitcore-lib-cash'), eth: Bitcore, + rsk: Bitcore, xrp: Bitcore, doge: require('bitcore-lib-doge'), ltc: require('bitcore-lib-ltc') diff --git a/packages/bitcore-wallet-service/src/lib/blockchainmonitor.ts b/packages/bitcore-wallet-service/src/lib/blockchainmonitor.ts index 76531a05ce..5c2149f6d4 100644 --- a/packages/bitcore-wallet-service/src/lib/blockchainmonitor.ts +++ b/packages/bitcore-wallet-service/src/lib/blockchainmonitor.ts @@ -51,6 +51,7 @@ export class BlockchainMonitor { btc: {}, bch: {}, eth: {}, + rsk: {}, xrp: {}, doge: {}, ltc: {} diff --git a/packages/bitcore-wallet-service/src/lib/chain/eth/index.ts b/packages/bitcore-wallet-service/src/lib/chain/eth/index.ts index 74606cdab4..dae388b1cb 100644 --- a/packages/bitcore-wallet-service/src/lib/chain/eth/index.ts +++ b/packages/bitcore-wallet-service/src/lib/chain/eth/index.ts @@ -31,6 +31,11 @@ function getInvoiceDecoder() { } export class EthChain implements IChain { + chain: string; + constructor() { + // Now RSK will inherit EthChain and override this.chain = 'RSK'; + this.chain = 'ETH'; + } /** * Converts Bitcore Balance Response. * @param {Object} bitcoreBalance - { unconfirmed, confirmed, balance } @@ -193,7 +198,7 @@ export class EthChain implements IChain { const { data, outputs, payProUrl, tokenAddress, multisigContractAddress, isTokenSwap } = txp; const isERC20 = tokenAddress && !payProUrl && !isTokenSwap; const isETHMULTISIG = multisigContractAddress; - const chain = isETHMULTISIG ? 'ETHMULTISIG' : isERC20 ? 'ERC20' : 'ETH'; + const chain = isETHMULTISIG ? 'ETHMULTISIG' : isERC20 ? 'ERC20' : this.chain; const recipients = outputs.map(output => { return { amount: output.amount, @@ -408,7 +413,7 @@ export class EthChain implements IChain { throw new Error('Signatures Required'); } - const chain = 'ETH'; // TODO use lowercase always to avoid confusion + const chain = this.chain; // TODO use lowercase always to avoid confusion const unsignedTxs = tx.uncheckedSerialize(); const signedTxs = []; for (let index = 0; index < signatures.length; index++) { @@ -426,7 +431,7 @@ export class EthChain implements IChain { } validateAddress(wallet, inaddr, opts) { - const chain = 'eth'; + const chain = this.chain.toLowerCase(); const isValidTo = Validation.validateAddress(chain, wallet.network, inaddr); if (!isValidTo) { throw Errors.INVALID_ADDRESS; diff --git a/packages/bitcore-wallet-service/src/lib/chain/index.ts b/packages/bitcore-wallet-service/src/lib/chain/index.ts index e0b4ce0fdb..536627aad7 100644 --- a/packages/bitcore-wallet-service/src/lib/chain/index.ts +++ b/packages/bitcore-wallet-service/src/lib/chain/index.ts @@ -4,6 +4,7 @@ import { BchChain } from './bch'; import { BtcChain } from './btc'; import { DogeChain } from './doge'; import { EthChain } from './eth'; +import { RskChain } from './rsk'; import { LtcChain } from './ltc'; import { XrpChain } from './xrp'; @@ -73,7 +74,8 @@ const chains: { [chain: string]: IChain } = { ETH: new EthChain(), XRP: new XrpChain(), DOGE: new DogeChain(), - LTC: new LtcChain() + LTC: new LtcChain(), + RSK: new RskChain() }; class ChainProxy { diff --git a/packages/bitcore-wallet-service/src/lib/chain/rsk/index.ts b/packages/bitcore-wallet-service/src/lib/chain/rsk/index.ts new file mode 100644 index 0000000000..a2d4746f34 --- /dev/null +++ b/packages/bitcore-wallet-service/src/lib/chain/rsk/index.ts @@ -0,0 +1,11 @@ +import { EthChain } from '../eth'; + +export class RskChain extends EthChain { + constructor() { + super(); + // Now RSK will inherit EthChain and override this.chain = 'RSK'; + this.chain = 'RSK'; + } + + // Rest of functions will be inherited from EthChain +} diff --git a/packages/bitcore-wallet-service/src/lib/common/constants.ts b/packages/bitcore-wallet-service/src/lib/common/constants.ts index 13d6486d0d..ea1f62ed9d 100644 --- a/packages/bitcore-wallet-service/src/lib/common/constants.ts +++ b/packages/bitcore-wallet-service/src/lib/common/constants.ts @@ -6,6 +6,8 @@ module.exports = { BTC: 'btc', BCH: 'bch', ETH: 'eth', + RSK: 'rsk', + RBTC: 'rbtc', XRP: 'xrp', DOGE: 'doge', LTC: 'ltc' @@ -18,6 +20,7 @@ module.exports = { BTC: 'btc', BCH: 'bch', ETH: 'eth', + RSK: 'rsk', XRP: 'xrp', DOGE: 'doge', LTC: 'ltc', @@ -67,7 +70,8 @@ module.exports = { }, EVM_CHAINS: { - ETH: 'eth' + ETH: 'eth', + RSK: 'rsk' }, NETWORKS: { diff --git a/packages/bitcore-wallet-service/src/lib/common/defaults.ts b/packages/bitcore-wallet-service/src/lib/common/defaults.ts index bb2d2d0cfd..2d16abaef4 100644 --- a/packages/bitcore-wallet-service/src/lib/common/defaults.ts +++ b/packages/bitcore-wallet-service/src/lib/common/defaults.ts @@ -83,6 +83,33 @@ module.exports = { defaultValue: 1000000000 } ], + rsk: [ + { + name: 'urgent', + nbBlocks: 1, + defaultValue: 59240000 + }, + { + name: 'priority', + nbBlocks: 1, + defaultValue: 59240000 + }, + { + name: 'normal', + nbBlocks: 1, + defaultValue: 59240000 + }, + { + name: 'economy', + nbBlocks: 1, + defaultValue: 59240000 + }, + { + name: 'superEconomy', + nbBlocks: 1, + defaultValue: 59240000 + } + ], xrp: [ { name: 'normal', @@ -239,6 +266,7 @@ module.exports = { btc: 10000 * 1000, // 10k sat/b bch: 10000 * 1000, // 10k sat/b eth: 1000000000000, // 50 Gwei, + rsk: 1000000000000, xrp: 1000000000000, doge: 100000000 * 100, ltc: 10000 * 1000 // 10k sat/b @@ -248,6 +276,7 @@ module.exports = { btc: 0, bch: 0, eth: 0, + rsk: 59240000, // minGasPrice xrp: 0, doge: 0, ltc: 0 @@ -257,6 +286,7 @@ module.exports = { btc: 0.05 * 1e8, bch: 0.05 * 1e8, eth: 1 * 1e18, // 1 eth + rsk: 1 * 1e18, // 1 rbtc xrp: 1 * 1e6, // 1 xrp doge: 400 * 1e8, ltc: 0.05 * 1e8 diff --git a/packages/bitcore-wallet-service/src/lib/emailservice.ts b/packages/bitcore-wallet-service/src/lib/emailservice.ts index 2272306680..1bcc8a027a 100644 --- a/packages/bitcore-wallet-service/src/lib/emailservice.ts +++ b/packages/bitcore-wallet-service/src/lib/emailservice.ts @@ -252,6 +252,7 @@ export class EmailService { bit: 'bits', bch: 'BCH', eth: 'ETH', + rsk: 'RSK', xrp: 'XRP', doge: 'DOGE', ltc: 'LTC', diff --git a/packages/bitcore-wallet-service/src/lib/fiatrateservice.ts b/packages/bitcore-wallet-service/src/lib/fiatrateservice.ts index fae4823bac..9420de8bf2 100644 --- a/packages/bitcore-wallet-service/src/lib/fiatrateservice.ts +++ b/packages/bitcore-wallet-service/src/lib/fiatrateservice.ts @@ -57,7 +57,7 @@ export class FiatRateService { _fetch(cb?) { cb = cb || function() {}; - const coins = ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc', 'shib', 'ape']; + const coins = ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc', 'shib', 'ape', 'rsk', 'rbtc']; const provider = this.providers[0]; // async.each(this.providers, (provider, next) => { @@ -255,7 +255,7 @@ export class FiatRateService { // Oldest date in timestamp range in epoch number ex. 24 hours ago const now = Date.now() - Defaults.FIAT_RATE_FETCH_INTERVAL * 60 * 1000; const ts = _.isNumber(opts.ts) ? opts.ts : now; - const coins = ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc', 'shib', 'ape']; + const coins = ['btc', 'bch', 'eth', 'xrp', 'doge', 'ltc', 'shib', 'ape', 'rsk', 'rbtc']; async.map( coins, diff --git a/packages/bitcore-wallet-service/src/lib/model/wallet.ts b/packages/bitcore-wallet-service/src/lib/model/wallet.ts index 3d19262523..0aa0c10d10 100644 --- a/packages/bitcore-wallet-service/src/lib/model/wallet.ts +++ b/packages/bitcore-wallet-service/src/lib/model/wallet.ts @@ -16,6 +16,7 @@ const Bitcore = { btc: require('bitcore-lib'), bch: require('bitcore-lib-cash'), eth: require('bitcore-lib'), + rsk: require('bitcore-lib'), xrp: require('bitcore-lib'), doge: require('bitcore-lib-doge'), ltc: require('bitcore-lib-ltc') diff --git a/packages/bitcore-wallet-service/src/lib/pushnotificationsservice.ts b/packages/bitcore-wallet-service/src/lib/pushnotificationsservice.ts index a5e51b018f..fe66926221 100644 --- a/packages/bitcore-wallet-service/src/lib/pushnotificationsservice.ts +++ b/packages/bitcore-wallet-service/src/lib/pushnotificationsservice.ts @@ -461,6 +461,8 @@ export class PushNotificationsService { bit: 'bits', bch: 'BCH', eth: 'ETH', + rsk: 'RSK', + rbtc: 'RBTC', xrp: 'XRP', doge: 'DOGE', ltc: 'LTC', diff --git a/packages/bitcore-wallet-service/src/lib/server.ts b/packages/bitcore-wallet-service/src/lib/server.ts index 0c2afb3cff..a41d77c062 100644 --- a/packages/bitcore-wallet-service/src/lib/server.ts +++ b/packages/bitcore-wallet-service/src/lib/server.ts @@ -41,6 +41,7 @@ const Bitcore_ = { btc: Bitcore, bch: require('bitcore-lib-cash'), eth: Bitcore, + rsk: Bitcore, xrp: Bitcore, doge: require('bitcore-lib-doge'), ltc: require('bitcore-lib-ltc') diff --git a/packages/bitcore-wallet-service/src/scripts/v8tool-list.ts b/packages/bitcore-wallet-service/src/scripts/v8tool-list.ts index 309d173597..fc01728233 100755 --- a/packages/bitcore-wallet-service/src/scripts/v8tool-list.ts +++ b/packages/bitcore-wallet-service/src/scripts/v8tool-list.ts @@ -33,6 +33,7 @@ const BASE = { BTC: `https://api.bitcore.io/api/${coin}/${network}`, BCH: `https://api.bitcore.io/api/${coin}/${network}`, ETH: `https://api-eth.bitcore.io/api/${coin}/${network}`, + RSK: `https://api-rsk.bitcore.io/api/${coin}/${network}`, XRP: `https://api-xrp.bitcore.io/api/${coin}/${network}`, DOGE: `https://api.bitcore.io/api/${coin}/${network}`, LTC: `https://api.bitcore.io/api/${coin}/${network}` diff --git a/packages/bitcore-wallet-service/src/scripts/v8tool.ts b/packages/bitcore-wallet-service/src/scripts/v8tool.ts index 87ace599c1..b7dcac1ae8 100755 --- a/packages/bitcore-wallet-service/src/scripts/v8tool.ts +++ b/packages/bitcore-wallet-service/src/scripts/v8tool.ts @@ -32,6 +32,7 @@ const BASE = { BTC: `https://api.bitcore.io/api/${coin}/${network}`, BCH: `https://api.bitcore.io/api/${coin}/${network}`, ETH: `https://api-eth.bitcore.io/api/${coin}/${network}`, + RSK: `https://api-rsk.bitcore.io/api/${coin}/${network}`, XRP: `https://api-xrp.bitcore.io/api/${coin}/${network}`, DOGE: `https://api.bitcore.io/api/${coin}/${network}`, LTC: `https://api.bitcore.io/api/${coin}/${network}` diff --git a/packages/crypto-wallet-core/src/constants/units.ts b/packages/crypto-wallet-core/src/constants/units.ts index 5b81187285..72f94784a1 100644 --- a/packages/crypto-wallet-core/src/constants/units.ts +++ b/packages/crypto-wallet-core/src/constants/units.ts @@ -32,6 +32,28 @@ export let UNITS = { minDecimals: 2 } }, + rsk: { + toSatoshis: 1e18, + full: { + maxDecimals: 8, + minDecimals: 8 + }, + short: { + maxDecimals: 6, + minDecimals: 2 + } + }, + rbtc: { + toSatoshis: 1e18, + full: { + maxDecimals: 8, + minDecimals: 8 + }, + short: { + maxDecimals: 6, + minDecimals: 2 + } + }, xrp: { toSatoshis: 1e6, full: { diff --git a/packages/crypto-wallet-core/src/derivation/index.ts b/packages/crypto-wallet-core/src/derivation/index.ts index bc7f1811f1..78c90dc970 100644 --- a/packages/crypto-wallet-core/src/derivation/index.ts +++ b/packages/crypto-wallet-core/src/derivation/index.ts @@ -22,6 +22,8 @@ const derivers: { [chain: string]: IDeriver } = { BTC: new BtcDeriver(), BCH: new BchDeriver(), ETH: new EthDeriver(), + RSK: new EthDeriver(), + RBTC: new EthDeriver(), XRP: new XrpDeriver(), DOGE: new DogeDeriver(), LTC: new LtcDeriver() diff --git a/packages/crypto-wallet-core/src/derivation/paths.ts b/packages/crypto-wallet-core/src/derivation/paths.ts index 36b31a448b..f71304b6b2 100644 --- a/packages/crypto-wallet-core/src/derivation/paths.ts +++ b/packages/crypto-wallet-core/src/derivation/paths.ts @@ -12,6 +12,11 @@ export const Paths = { livenet: "m/44'/60'/", testnet: "m/44'/60'/" }, + RSK: { + mainnet: "m/44'/137'/", + livenet: "m/44'/137'/", + testnet: "m/44'/37310'/" + }, XRP: { mainnet: "m/44'/144'/", livenet: "m/44'/144'/", diff --git a/packages/crypto-wallet-core/src/transactions/index.ts b/packages/crypto-wallet-core/src/transactions/index.ts index 97d7762321..5c8694475e 100644 --- a/packages/crypto-wallet-core/src/transactions/index.ts +++ b/packages/crypto-wallet-core/src/transactions/index.ts @@ -3,6 +3,7 @@ import { BTCTxProvider } from './btc'; import { DOGETxProvider } from './doge'; import { ERC20TxProvider } from './erc20'; import { ETHTxProvider } from './eth'; +import { RSKTxProvider } from './rsk'; import { ETHMULTISIGTxProvider } from './eth-multisig'; import { LTCTxProvider } from './ltc'; import { XRPTxProvider } from './xrp'; @@ -11,6 +12,7 @@ const providers = { BTC: new BTCTxProvider(), BCH: new BCHTxProvider(), ETH: new ETHTxProvider(), + RSK: new RSKTxProvider(), // TODO: add multisig support ERC20: new ERC20TxProvider(), ETHMULTISIG: new ETHMULTISIGTxProvider(), XRP: new XRPTxProvider(), diff --git a/packages/crypto-wallet-core/src/transactions/rsk/index.ts b/packages/crypto-wallet-core/src/transactions/rsk/index.ts new file mode 100644 index 0000000000..a9b191e32b --- /dev/null +++ b/packages/crypto-wallet-core/src/transactions/rsk/index.ts @@ -0,0 +1,23 @@ +import { ETHTxProvider } from '../eth'; + +// Reuse ETHTxProvider for RSK and override the required methods +export class RSKTxProvider extends ETHTxProvider { + + // Overridden getChainId for RSK + getChainId(network: string) { + let chainId = 137; + switch (network) { + case 'testnet': + chainId = 37310; + break; + case 'regtest': + chainId = 37310; + break; + default: + chainId = 137; + break; + } + + return chainId; + } +} diff --git a/packages/crypto-wallet-core/src/validation/eth/index.ts b/packages/crypto-wallet-core/src/validation/eth/index.ts index 882361f60a..f8a4d81ea3 100644 --- a/packages/crypto-wallet-core/src/validation/eth/index.ts +++ b/packages/crypto-wallet-core/src/validation/eth/index.ts @@ -14,8 +14,9 @@ export class EthValidation implements IValidation { const ethereumPrefix = /ethereum/i.exec(addressUri); return !!ethereumPrefix && utils.isAddress(address); } - - private extractAddress(data) { + + // Make it protected so that RSK can override extractAddress + protected extractAddress(data) { const prefix = /^[a-z]+:/i; const params = /([\?\&](value|gas|gasPrice|gasLimit)=(\d+([\,\.]\d+)?))+/i; return data.replace(prefix, '').replace(params, ''); diff --git a/packages/crypto-wallet-core/src/validation/index.ts b/packages/crypto-wallet-core/src/validation/index.ts index 7a95ae448c..20e8b1b790 100644 --- a/packages/crypto-wallet-core/src/validation/index.ts +++ b/packages/crypto-wallet-core/src/validation/index.ts @@ -2,6 +2,7 @@ import { BchValidation } from './bch'; import { BtcValidation } from './btc'; import { DogeValidation } from './doge'; import { EthValidation } from './eth'; +import { RskValidation } from './rsk'; import { LtcValidation } from './ltc'; import { XrpValidation } from './xrp'; @@ -14,6 +15,7 @@ const validation: { [chain: string]: IValidation } = { BTC: new BtcValidation(), BCH: new BchValidation(), ETH: new EthValidation(), + RSK: new RskValidation(), XRP: new XrpValidation(), DOGE: new DogeValidation(), LTC: new LtcValidation() diff --git a/packages/crypto-wallet-core/src/validation/rsk/index.ts b/packages/crypto-wallet-core/src/validation/rsk/index.ts new file mode 100644 index 0000000000..3a09e48471 --- /dev/null +++ b/packages/crypto-wallet-core/src/validation/rsk/index.ts @@ -0,0 +1,16 @@ +import { IValidation } from '..'; +import { EthValidation } from '../eth/'; +const utils = require('web3-utils'); + +export class RskValidation extends EthValidation { + + // Overridden validateUri for RSK + validateUri(addressUri: string): boolean { + if (!addressUri) { + return false; + } + const address = this.extractAddress(addressUri); + const rskPrefix = /rsk/i.exec(addressUri); + return !!rskPrefix && utils.isAddress(address); + } +}