Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RSK Integration #3427

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/bitcore-node/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
14 changes: 10 additions & 4 deletions packages/bitcore-node/src/modules/ethereum/api/csp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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');
3 changes: 2 additions & 1 deletion packages/bitcore-node/src/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ class ModuleManager extends BaseModule {
BCH: './bitcoin-cash',
DOGE: './dogecoin',
LTC: './litecoin',
XRP: './ripple'
XRP: './ripple',
RSK: './rsk'
};

loadConfigured() {
Expand Down
1 change: 1 addition & 0 deletions packages/bitcore-node/src/modules/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
18 changes: 18 additions & 0 deletions packages/bitcore-node/src/modules/rsk/api/csp.ts
Original file line number Diff line number Diff line change
@@ -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();

36 changes: 36 additions & 0 deletions packages/bitcore-node/src/modules/rsk/api/rsk-routes.ts
Original file line number Diff line number Diff line change
@@ -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);
}
});
15 changes: 15 additions & 0 deletions packages/bitcore-node/src/modules/rsk/index.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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
*/
}
12 changes: 12 additions & 0 deletions packages/bitcore-node/src/modules/rsk/p2p/p2p.ts
Original file line number Diff line number Diff line change
@@ -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';
}
}
4 changes: 3 additions & 1 deletion packages/bitcore-wallet-client/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions packages/bitcore-wallet-client/src/lib/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const Constants = {
'btc',
'bch',
'eth',
'rsk',
'xrp',
'doge',
'ltc',
Expand All @@ -45,16 +46,17 @@ export const Constants = {
'pax', // backwards compatibility
'gusd',
'busd',
'xusd', // Sovryn token
'dai',
'wbtc',
'shib',
'ape',
'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
};
3 changes: 2 additions & 1 deletion packages/bitcore-wallet-client/src/lib/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions packages/bitcore-wallet-client/src/lib/key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down
8 changes: 8 additions & 0 deletions packages/bitcore-wallet-service/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
4 changes: 4 additions & 0 deletions packages/bitcore-wallet-service/src/lib/blockchainexplorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class BlockchainMonitor {
btc: {},
bch: {},
eth: {},
rsk: {},
xrp: {},
doge: {},
ltc: {}
Expand Down
11 changes: 8 additions & 3 deletions packages/bitcore-wallet-service/src/lib/chain/eth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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++) {
Expand All @@ -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;
Expand Down
4 changes: 3 additions & 1 deletion packages/bitcore-wallet-service/src/lib/chain/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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 {
Expand Down
11 changes: 11 additions & 0 deletions packages/bitcore-wallet-service/src/lib/chain/rsk/index.ts
Original file line number Diff line number Diff line change
@@ -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
}
6 changes: 5 additions & 1 deletion packages/bitcore-wallet-service/src/lib/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module.exports = {
BTC: 'btc',
BCH: 'bch',
ETH: 'eth',
RSK: 'rsk',
RBTC: 'rbtc',
XRP: 'xrp',
DOGE: 'doge',
LTC: 'ltc'
Expand All @@ -18,6 +20,7 @@ module.exports = {
BTC: 'btc',
BCH: 'bch',
ETH: 'eth',
RSK: 'rsk',
XRP: 'xrp',
DOGE: 'doge',
LTC: 'ltc',
Expand Down Expand Up @@ -67,7 +70,8 @@ module.exports = {
},

EVM_CHAINS: {
ETH: 'eth'
ETH: 'eth',
RSK: 'rsk'
},

NETWORKS: {
Expand Down