Skip to content

Commit

Permalink
feat: RSK integration
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Oct 26, 2023
1 parent 3361b80 commit d8b7a60
Show file tree
Hide file tree
Showing 40 changed files with 668 additions and 418 deletions.
6 changes: 6 additions & 0 deletions bin/boltz-ethereum
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ require('yargs')
type: 'string',
alias: 'p',
},
chain: {
describe: 'EVM chain to use ("rsk" or "ethereum")',
default: 'rsk',
type: 'string',
alias: 'c',
},
})
.commandDir('../dist/lib/cli/ethereum/commands/')
.demandCommand(1, '')
Expand Down
135 changes: 80 additions & 55 deletions lib/Boltz.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import fs from 'fs';
import { Arguments } from 'yargs';
import { Networks } from 'boltz-core';
import { generateMnemonic } from 'bip39';
import { Networks as LiquidNetworks } from 'boltz-core/dist/lib/liquid';
import Api from './api/Api';
import Logger from './Logger';
Expand All @@ -17,12 +15,13 @@ import GrpcService from './grpc/GrpcService';
import ClnClient from './lightning/ClnClient';
import LndClient from './lightning/LndClient';
import ChainClient from './chain/ChainClient';
import Config, { ConfigType } from './Config';
import Config, { ConfigType, TokenConfig } from './Config';
import { CurrencyType } from './consts/Enums';
import { formatError, getVersion } from './Utils';
import ElementsClient from './chain/ElementsClient';
import { registerExitHandler } from './ExitHandler';
import BackupScheduler from './backup/BackupScheduler';
import { Ethereum, NetworkDetails, Rsk } from './wallet/ethereum/EvmNetworks';
import { LightningClient } from './lightning/LightningClient';
import EthereumManager from './wallet/ethereum/EthereumManager';
import WalletManager, { Currency } from './wallet/WalletManager';
Expand All @@ -39,14 +38,14 @@ class Boltz {

private readonly currencies: Map<string, Currency>;

private db: Database;
private notifications!: NotificationProvider;
private readonly db: Database;
private readonly notifications!: NotificationProvider;

private api!: Api;
private readonly api!: Api;
private readonly grpcServer!: GrpcServer;
private readonly prometheus: Prometheus;
private grpcServer!: GrpcServer;

private readonly ethereumManager?: EthereumManager;
private readonly ethereumManagers: EthereumManager[];

constructor(config: Arguments<any>) {
this.config = new Config().load(config);
Expand Down Expand Up @@ -81,40 +80,33 @@ class Boltz {

this.db = new Database(this.logger, this.config.dbpath);

try {
this.ethereumManager = new EthereumManager(
this.logger,
this.config.ethereum,
);
} catch (error) {
this.logger.warn(
`Disabled Ethereum integration because: ${formatError(error)}`,
);
}
this.ethereumManagers = [
{ name: Ethereum.name, isRsk: false, config: this.config.ethereum },
{ name: Rsk.name, isRsk: true, config: this.config.rsk },
]
.map(({ name, isRsk, config }) => {
try {
return new EthereumManager(this.logger, isRsk, config);
} catch (error) {
this.logger.warn(
`Disabled ${name} integration because: ${formatError(error)}`,
);
}

return undefined;
})
.filter((manager): manager is EthereumManager => manager !== undefined);

this.currencies = this.parseCurrencies();

const walletCurrencies = Array.from(this.currencies.values());

if (fs.existsSync(this.config.mnemonicpath)) {
this.walletManager = new WalletManager(
this.logger,
this.config.mnemonicpath,
walletCurrencies,
this.ethereumManager,
);
} else {
const mnemonic = generateMnemonic();
this.logger.info(`Generated new mnemonic: ${mnemonic}`);

this.walletManager = WalletManager.fromMnemonic(
this.logger,
mnemonic,
this.config.mnemonicpath,
walletCurrencies,
this.ethereumManager,
);
}
this.walletManager = new WalletManager(
this.logger,
this.config.mnemonicpath,
walletCurrencies,
this.ethereumManagers,
);

try {
this.service = new Service(
Expand All @@ -135,6 +127,7 @@ class Boltz {
this.notifications = new NotificationProvider(
this.logger,
this.service,
this.walletManager,
this.backup,
this.config.notification,
[this.config.liquid].concat(this.config.currencies),
Expand Down Expand Up @@ -222,15 +215,15 @@ class Boltz {
const rescanPromises: Promise<void>[] = [];

for (const chainTip of chainTips) {
if (chainTip.symbol === 'ETH') {
if (this.walletManager.ethereumManager) {
logRescan(chainTip);
rescanPromises.push(
this.walletManager.ethereumManager.contractEventHandler.rescan(
chainTip.height,
),
);
}
const ethereumManager = this.ethereumManagers.find(
(manager) => manager.networkDetails.symbol === chainTip.symbol,
);

if (ethereumManager !== undefined) {
logRescan(chainTip);
rescanPromises.push(
ethereumManager.contractEventHandler.rescan(chainTip.height),
);
} else {
if (!this.currencies.has(chainTip.symbol)) {
this.logger.warn(
Expand Down Expand Up @@ -350,16 +343,48 @@ class Boltz {
}
});

this.config.ethereum.tokens.forEach((token) => {
result.set(token.symbol, {
symbol: token.symbol,
type: token.symbol === 'ETH' ? CurrencyType.Ether : CurrencyType.ERC20,
limits: {
...token,
},
provider: this.ethereumManager?.provider,
[
{ network: Ethereum, config: this.config.ethereum.tokens },
{ network: Rsk, config: this.config.rsk?.tokens },
]
.map((tokens) => {
const manager = this.ethereumManagers.find(
(manager) => manager.networkDetails === tokens.network,
);

if (manager === undefined) {
return undefined;
}

return {
...tokens,
manager,
};
})
.filter(
(
tokens,
): tokens is {
network: NetworkDetails;
manager: EthereumManager;
config: TokenConfig[];
} => tokens !== undefined && tokens.config !== undefined,
)
.forEach(({ config, manager, network }) => {
config.forEach((token) => {
result.set(token.symbol, {
symbol: token.symbol,
provider: manager.provider,
type:
token.symbol === network.symbol
? CurrencyType.Ether
: CurrencyType.ERC20,
limits: {
...token,
},
});
});
});
});

if (this.config.liquid) {
const { symbol, chain, network } = this.config.liquid;
Expand Down
12 changes: 8 additions & 4 deletions lib/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,18 +85,20 @@ type EthProviderServiceConfig = {
apiKey: string;
};

type EthereumConfig = {
type RskConfig = {
providerEndpoint: string;

infura: EthProviderServiceConfig;
alchemy: EthProviderServiceConfig;

etherSwapAddress: string;
erc20SwapAddress: string;

tokens: TokenConfig[];
};

type EthereumConfig = RskConfig & {
infura: EthProviderServiceConfig;
alchemy: EthProviderServiceConfig;
};

type ApiConfig = {
host: string;
port: number;
Expand Down Expand Up @@ -163,6 +165,7 @@ type ConfigType = {

liquid?: BaseCurrencyConfig;

rsk?: RskConfig;
ethereum: EthereumConfig;
};

Expand Down Expand Up @@ -469,6 +472,7 @@ class Config {
export default Config;
export {
ApiConfig,
RskConfig,
ConfigType,
GrpcConfig,
ChainConfig,
Expand Down
21 changes: 14 additions & 7 deletions lib/api/Controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,13 +211,20 @@ class Controller {
try {
const contracts = await this.service.getContracts();

this.successResponse(res, {
ethereum: {
network: contracts.ethereum.network,
swapContracts: mapToObject(contracts.ethereum.swapContracts),
tokens: mapToObject(contracts.ethereum.tokens),
},
});
const response: Record<string, any> = {};
for (const [network, networkContracts] of Object.entries(contracts)) {
if (contracts === undefined) {
continue;
}

response[network] = {
network: networkContracts.network,
swapContracts: mapToObject(networkContracts.swapContracts),
tokens: mapToObject(networkContracts.tokens),
};
}

this.successResponse(res, response);
} catch (error) {
this.errorResponse(req, res, error, 501);
}
Expand Down
18 changes: 11 additions & 7 deletions lib/cli/ethereum/EthereumUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,33 @@ const getBoltzWallet = (): HDNodeWallet => {
const loadConfig = (): ConfigType =>
new Config().load({ configpath: getBoltzFilePath('boltz.conf') });

export const getContracts = async (
export const getContracts = (
chain: 'rsk' | 'ethereum',
signer: Signer,
): Promise<{
): {
token: ERC20;
etherSwap: EtherSwap;
erc20Swap: ERC20Swap;
}> => {
const config = loadConfig();
} => {
const config = loadConfig()[chain];
if (config === undefined) {
throw `${chain} configuration missing`;
}

const contracts: any = {};

Object.entries({
etherSwap: {
abi: ContractABIs.EtherSwap,
address: config.ethereum.etherSwapAddress,
address: config.etherSwapAddress,
},
erc20Swap: {
abi: ContractABIs.ERC20Swap,
address: config.ethereum.erc20SwapAddress,
address: config.erc20SwapAddress,
},
token: {
abi: ContractABIs.ERC20,
address: config.ethereum.tokens.find(
address: config.tokens.find(
(token) => token.contractAddress !== undefined,
)!.contractAddress!,
},
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/ethereum/commands/Claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const builder = {

export const handler = async (argv: Arguments<any>): Promise<void> => {
const signer = await connectEthereum(argv.provider);
const { etherSwap, erc20Swap } = await getContracts(signer);
const { etherSwap, erc20Swap } = getContracts(argv.chain, signer);

const preimage = getHexBuffer(argv.preimage);

Expand Down
4 changes: 1 addition & 3 deletions lib/cli/ethereum/commands/Lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const builder = {

export const handler = async (argv: Arguments<any>): Promise<void> => {
const signer = await connectEthereum(argv.provider);
const { etherSwap, erc20Swap, token } = await getContracts(signer);
const { etherSwap, erc20Swap, token } = getContracts(argv.chain, signer);

const preimageHash = getHexBuffer(argv.preimageHash);
const amount = BigInt(argv.amount) * etherDecimals;
Expand Down Expand Up @@ -69,8 +69,6 @@ export const handler = async (argv: Arguments<any>): Promise<void> => {
);
}

await transaction.wait(1);

console.log(
`Sent ${argv.token ? 'ERC20 token' : 'Ether'} in: ${transaction.hash}`,
);
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/ethereum/commands/Refund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const builder = {

export const handler = async (argv: Arguments<any>): Promise<void> => {
const signer = await connectEthereum(argv.provider);
const { etherSwap, erc20Swap } = await getContracts(signer);
const { etherSwap, erc20Swap } = getContracts(argv.chain, signer);

const preimageHash = getHexBuffer(argv.preimageHash);

Expand Down
2 changes: 1 addition & 1 deletion lib/cli/ethereum/commands/Send.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const builder = {

export const handler = async (argv: Arguments<any>): Promise<void> => {
const signer = await connectEthereum(argv.provider);
const { token } = await getContracts(signer);
const { token } = getContracts(argv.chain, signer);

const amount = BigInt(argv.amount) * etherDecimals;

Expand Down
2 changes: 1 addition & 1 deletion lib/lightning/LndClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ class LndClient extends BaseClient implements LightningClient {
case lndrpc.PaymentFailureReason.FAILURE_REASON_INCORRECT_PAYMENT_DETAILS:
return 'incorrect payment details';
default:
return 'unknown reason';
return `unknown reason: ${reason.toString()}`;
}
};

Expand Down
Loading

0 comments on commit d8b7a60

Please sign in to comment.