Skip to content

Commit

Permalink
Merge pull request #452 from BoltzExchange/taproot-swaps
Browse files Browse the repository at this point in the history
Taproot swaps
  • Loading branch information
michael1011 authored Jan 22, 2024
2 parents 1a93026 + 85289bd commit c47927e
Show file tree
Hide file tree
Showing 218 changed files with 9,288 additions and 3,465 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib/proto/**/*.d.ts
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"plugins": ["@trivago/prettier-plugin-sort-imports"],
"importOrder": ["<THIRD_PARTY_MODULES>", "^[../]", "^[./]"],
"importOrderSeparation": false,
"importOrderSortSpecifiers": true,
"importOrderParserPlugins": ["typescript"],
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
Expand Down
4 changes: 2 additions & 2 deletions docker/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ class Image:

GOLANG_VERSION = BuildArgument(
name="GOLANG_VERSION",
value="1.21.5-bullseye",
value="1.21.6-bullseye",
)

BITCOIN_VERSION = "26.0"
LITECOIN_VERSION = "0.21.2.2"
ELEMENTS_VERSION = "23.2.1"
GETH_VERSION = "1.13.5"
GETH_VERSION = "1.13.10"

C_LIGHTNING_VERSION = "23.11.2"
ECLAIR_VERSION = "0.9.0"
Expand Down
36 changes: 18 additions & 18 deletions lib/Boltz.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import { Arguments } from 'yargs';
import { Networks } from 'boltz-core';
import { Networks as LiquidNetworks } from 'boltz-core/dist/lib/liquid';
import Api from './api/Api';
import Logger from './Logger';
import { Arguments } from 'yargs';
import Config, { ConfigType, TokenConfig } from './Config';
import { setup } from './Core';
import Database from './db/Database';
import { registerExitHandler } from './ExitHandler';
import Logger from './Logger';
import Prometheus from './Prometheus';
import Service from './service/Service';
import { formatError, getVersion } from './Utils';
import VersionCheck from './VersionCheck';
import GrpcServer from './grpc/GrpcServer';
import NodeSwitch from './swap/NodeSwitch';
import Api from './api/Api';
import BackupScheduler from './backup/BackupScheduler';
import ChainClient from './chain/ChainClient';
import ElementsClient from './chain/ElementsClient';
import { CurrencyType } from './consts/Enums';
import Database from './db/Database';
import ChainTip from './db/models/ChainTip';
import ChainTipRepository from './db/repositories/ChainTipRepository';
import GrpcServer from './grpc/GrpcServer';
import GrpcService from './grpc/GrpcService';
import ClnClient from './lightning/ClnClient';
import LndClient from './lightning/LndClient';
import ChainClient from './chain/ChainClient';
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 Config, { ConfigType, TokenConfig } from './Config';
import { LightningClient } from './lightning/LightningClient';
import EthereumManager from './wallet/ethereum/EthereumManager';
import WalletManager, { Currency } from './wallet/WalletManager';
import ChainTipRepository from './db/repositories/ChainTipRepository';
import LndClient from './lightning/LndClient';
import NotificationProvider from './notifications/NotificationProvider';
import Service from './service/Service';
import NodeSwitch from './swap/NodeSwitch';
import WalletManager, { Currency } from './wallet/WalletManager';
import EthereumManager from './wallet/ethereum/EthereumManager';
import { Ethereum, NetworkDetails, Rsk } from './wallet/ethereum/EvmNetworks';

class Boltz {
Expand Down
12 changes: 6 additions & 6 deletions lib/Config.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import toml from '@iarna/toml';
import fs from 'fs';
import path from 'path';
import toml from '@iarna/toml';
import { Arguments } from 'yargs';
import Errors from './consts/Errors';
import { PrometheusConfig } from './Prometheus';
import { deepMerge, getServiceDataDir, resolveHome } from './Utils';
import { GoogleCloudConfig } from './backup/providers/GoogleCloud';
import { WebdavConfig } from './backup/providers/Webdav';
import { Network } from './consts/Enums';
import Errors from './consts/Errors';
import { PairConfig } from './consts/Types';
import { PrometheusConfig } from './Prometheus';
import { ClnConfig } from './lightning/ClnClient';
import { LndConfig } from './lightning/LndClient';
import { NodeSwitchConfig } from './swap/NodeSwitch';
import { WebdavConfig } from './backup/providers/Webdav';
import { GoogleCloudConfig } from './backup/providers/GoogleCloud';
import { deepMerge, getServiceDataDir, resolveHome } from './Utils';

type PostgresConfig = {
host: string;
Expand Down
154 changes: 110 additions & 44 deletions lib/Core.ts
Original file line number Diff line number Diff line change
@@ -1,71 +1,85 @@
import * as ecc from 'tiny-secp256k1';
import zkp from '@vulpemventures/secp256k1-zkp';
import { Network as LiquidNetwork } from 'liquidjs-lib/src/networks';
import zkpInit, { Secp256k1ZKP } from '@vulpemventures/secp256k1-zkp';
import { BIP32Interface } from 'bip32';
import {
address,
Network,
Transaction,
TxOutput,
address,
initEccLib,
Transaction,
} from 'bitcoinjs-lib';
import {
confidential,
address as addressLiquid,
TxOutput as TxOutputLiquid,
Transaction as TransactionLiquid,
} from 'liquidjs-lib';
import {
ClaimDetails,
Musig,
RefundDetails,
targetFee,
TaprootUtils,
Types,
constructClaimTransaction as constructClaimTransactionBitcoin,
constructRefundTransaction as constructRefundTransactionBitcoin,
init,
targetFee,
} from 'boltz-core';
import {
init as initLiquid,
LiquidClaimDetails,
LiquidRefundDetails,
TaprootUtils as TaprootUtilsLiquid,
constructClaimTransaction as constructClaimTransactionLiquid,
constructRefundTransaction as constructRefundTransactionLiquid,
init as initLiquid,
} from 'boltz-core/dist/lib/liquid';
import Wallet from './wallet/Wallet';
import ChainClient from './chain/ChainClient';
import { CurrencyType } from './consts/Enums';
import WalletLiquid from './wallet/WalletLiquid';
import { liquidSymbol } from './consts/LiquidTypes';
import { randomBytes } from 'crypto';
import { ECPairInterface } from 'ecpair';
import {
Transaction as LiquidTransaction,
TxOutput as LiquidTxOutput,
confidential,
address as liquidAddress,
} from 'liquidjs-lib';
import { Network as LiquidNetwork } from 'liquidjs-lib/src/networks';
import * as ecc from 'tiny-secp256k1';
import { ECPair } from './ECPairHelper';
import {
calculateLiquidTransactionFee,
calculateUtxoTransactionFee,
getHexBuffer,
getHexString,
reverseBuffer,
calculateUtxoTransactionFee,
calculateLiquidTransactionFee,
} from './Utils';
import ChainClient from './chain/ChainClient';
import { CurrencyType } from './consts/Enums';
import { liquidSymbol } from './consts/LiquidTypes';
import Wallet from './wallet/Wallet';
import WalletLiquid from './wallet/WalletLiquid';
import { Currency } from './wallet/WalletManager';

type UnblindedOutput = Omit<TxOutputLiquid, 'value'> & {
type UnblindedOutput = Omit<LiquidTxOutput, 'value'> & {
value: number;
isLbtc: boolean;
};

export let zkp: Secp256k1ZKP;
let confi: confidential.Confidential;

export const setup = async () => {
const zkpLib = await zkp();
confi = new confidential.Confidential(zkpLib);
init(ecc);
initEccLib(ecc);
initLiquid(zkpLib);

zkp = await zkpInit();
confi = new confidential.Confidential(zkp as any);
initLiquid(zkp);
};

export const parseTransaction = (
type: CurrencyType,
rawTx: string | Buffer,
): Transaction | TransactionLiquid => {
): Transaction | LiquidTransaction => {
if (rawTx instanceof Buffer) {
return isBitcoin(type)
? Transaction.fromBuffer(rawTx)
: TransactionLiquid.fromBuffer(rawTx);
: LiquidTransaction.fromBuffer(rawTx);
} else {
return isBitcoin(type)
? Transaction.fromHex(rawTx)
: TransactionLiquid.fromHex(rawTx);
: LiquidTransaction.fromHex(rawTx);
}
};

Expand All @@ -76,7 +90,7 @@ export const fromOutputScript = (
) => {
return isBitcoin(type)
? address.fromOutputScript(outputScript, network)
: addressLiquid.fromOutputScript(outputScript, network as LiquidNetwork);
: liquidAddress.fromOutputScript(outputScript, network as LiquidNetwork);
};

export const toOutputScript = (
Expand All @@ -86,12 +100,12 @@ export const toOutputScript = (
) => {
return isBitcoin(type)
? address.toOutputScript(toDecode, network)
: addressLiquid.toOutputScript(toDecode, network as LiquidNetwork);
: liquidAddress.toOutputScript(toDecode, network as LiquidNetwork);
};

export const unblindOutput = (
wallet: Wallet,
output: TxOutputLiquid,
output: LiquidTxOutput,
blindingKey?: Buffer,
): UnblindedOutput => {
let value = 0;
Expand Down Expand Up @@ -126,15 +140,15 @@ export const unblindOutput = (

export const getOutputValue = (
wallet: Wallet,
output: TxOutput | TxOutputLiquid,
output: TxOutput | LiquidTxOutput,
) => {
if (isBitcoin(wallet.type)) {
return output.value as number;
}

const unblinded = unblindOutput(
wallet,
output as TxOutputLiquid,
output as LiquidTxOutput,
(wallet as WalletLiquid).deriveBlindingKeyFromScript(output.script)
.privateKey!,
);
Expand All @@ -147,7 +161,6 @@ export const constructClaimTransaction = (
claimDetails: ClaimDetails[] | LiquidClaimDetails[],
destinationAddress: string,
feePerVbyte: number,
assetHash?: string,
) => {
if (isBitcoin(wallet.type)) {
return targetFee(feePerVbyte, (fee) =>
Expand All @@ -164,15 +177,15 @@ export const constructClaimTransaction = (
wallet as WalletLiquid,
claimDetails as LiquidClaimDetails[],
);
const decodedAddress = addressLiquid.fromConfidential(destinationAddress);
const decodedAddress = liquidAddress.fromConfidential(destinationAddress);

return targetFee(feePerVbyte, (fee) =>
constructClaimTransactionLiquid(
liquidDetails,
decodedAddress.scriptPubKey!,
fee,
true,
assetHash,
wallet.network as LiquidNetwork,
decodedAddress.blindingKey,
),
);
Expand All @@ -184,7 +197,6 @@ export const constructRefundTransaction = (
destinationAddress: string,
timeoutBlockHeight: number,
feePerVbyte: number,
assetHash?: string,
) => {
if (isBitcoin(wallet.type)) {
return targetFee(feePerVbyte, (fee) =>
Expand All @@ -202,7 +214,7 @@ export const constructRefundTransaction = (
wallet as WalletLiquid,
refundDetails as LiquidRefundDetails[],
);
const decodedAddress = addressLiquid.fromConfidential(destinationAddress);
const decodedAddress = liquidAddress.fromConfidential(destinationAddress);

return targetFee(feePerVbyte, (fee) =>
constructRefundTransactionLiquid(
Expand All @@ -211,26 +223,80 @@ export const constructRefundTransaction = (
timeoutBlockHeight,
fee,
true,
assetHash,
wallet.network as LiquidNetwork,
decodedAddress.blindingKey,
),
);
};

export const calculateTransactionFee = async (
chainClient: ChainClient,
transaction: Transaction | TransactionLiquid,
transaction: Transaction | LiquidTransaction,
) => {
return chainClient.symbol !== liquidSymbol
? calculateUtxoTransactionFee(chainClient, transaction as Transaction)
: calculateLiquidTransactionFee(transaction as TransactionLiquid);
: calculateLiquidTransactionFee(transaction as LiquidTransaction);
};

export const getAssetHash = (
export const createMusig = (
ourKeys: ECPairInterface | BIP32Interface,
theirPublicKey: Buffer,
) =>
new Musig(zkp, ECPair.fromPrivateKey(ourKeys.privateKey!), randomBytes(32), [
ourKeys.publicKey,
theirPublicKey,
]);

export const tweakMusig = (
type: CurrencyType,
network: Network,
): string | undefined => {
return isBitcoin(type) ? undefined : (network as LiquidNetwork).assetHash;
musig: Musig,
swapTree: Types.SwapTree,
) =>
(isBitcoin(type) ? TaprootUtils : TaprootUtilsLiquid).tweakMusig(
musig,
swapTree.tree,
);

export const hashForWitnessV1 = async (
currency: Currency,
tx: Transaction | LiquidTransaction,
index: number,
leafHash?: Buffer,
hashType: number = Transaction.SIGHASH_DEFAULT,
): Promise<Buffer> => {
const inputs = await Promise.all(
tx.ins.map(async (input) => {
const inTx = parseTransaction(
currency.type,
await currency.chainClient!.getRawTransaction(
getHexString(reverseBuffer(input.hash)),
),
);
return inTx.outs[input.index];
}),
);

if (isBitcoin(currency.type)) {
return (tx as Transaction).hashForWitnessV1(
index,
inputs.map((input) => input.script),
inputs.map((input) => input.value as number),
hashType,
leafHash,
);
}

return (tx as LiquidTransaction).hashForWitnessV1(
index,
inputs.map((input) => input.script),
inputs.map((input) => ({
asset: (input as LiquidTxOutput).asset,
value: (input as LiquidTxOutput).value,
})),
hashType,
(currency.network as LiquidNetwork).genesisBlockHash,
leafHash,
);
};

const isBitcoin = (type: CurrencyType) => type === CurrencyType.BitcoinLike;
Expand Down
2 changes: 1 addition & 1 deletion lib/ECPairHelper.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as ecc from 'tiny-secp256k1';
import { ECPairFactory } from 'ecpair';
import * as ecc from 'tiny-secp256k1';

export const ECPair = ECPairFactory(ecc);
Loading

0 comments on commit c47927e

Please sign in to comment.