Skip to content

Commit

Permalink
refactor: Discount CT on mainnet
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 committed Mar 4, 2025
1 parent c02dfdb commit aa291b3
Show file tree
Hide file tree
Showing 17 changed files with 39 additions and 212 deletions.
6 changes: 0 additions & 6 deletions docker/regtest/data/elements/elements.conf
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,6 @@ con_nrulechangeactivationthreshold=1
## Taproot signaling
con_taproot_signal_start=0

# Lowball
mintxfee=0.0000001
fallbackfee=0.0000001
blockmintxfee=0.0000001
minrelaytxfee=0.00000009

# Discount CT
acceptdiscountct=1
creatediscountct=1
4 changes: 2 additions & 2 deletions lib/Core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ export const constructClaimTransaction = (
wallet.network as LiquidNetwork,
decodedAddress.blindingKey,
),
walletLiquid.supportsDiscountCT,
true,
);
});
} catch (e) {
Expand Down Expand Up @@ -355,7 +355,7 @@ export const constructRefundTransaction = (
wallet.network as LiquidNetwork,
decodedAddress.blindingKey,
),
walletLiquid.supportsDiscountCT,
true,
);
});
} catch (e) {
Expand Down
15 changes: 5 additions & 10 deletions lib/chain/ElementsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
LiquidBalances,
liquidSymbol,
} from '../consts/LiquidTypes';
import type WalletLiquid from '../wallet/WalletLiquid';
import ChainClient, { AddressType, IChainClient } from './ChainClient';

enum LiquidAddressType {
Expand All @@ -30,32 +29,28 @@ class ElementsClient
implements IElementsClient
{
public static readonly symbol = liquidSymbol;

private static readonly minNoLowBallFee = 0.1;
private static readonly feeFloor = 0.1;

constructor(
logger: Logger,
config: ChainConfig,
public readonly isLowball = false,
) {
super(logger, config, ElementsClient.symbol);
this.feeFloor = ElementsClient.feeFloor;
this.currencyType = CurrencyType.Liquid;
this.feeFloor = isLowball ? 0.01 : ElementsClient.minNoLowBallFee;
}

public static needsLowball = (
wallet: WalletLiquid,
tx: Transaction,
): boolean => {
public static needsLowball = (tx: Transaction): boolean => {
const feeOutput = tx.outs.find((out) => out.script.length === 0);
if (feeOutput === undefined) {
return false;
}

return (
confidential.confidentialValueToSatoshi(feeOutput.value) /
tx.virtualSize(wallet.supportsDiscountCT) <
ElementsClient.minNoLowBallFee
tx.virtualSize(true) <
ElementsClient.feeFloor
);
};

Expand Down
5 changes: 0 additions & 5 deletions lib/cli/BuilderComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,4 @@ export default {
describe: 'preimage of the swap',
type: 'string',
},
discountCT: {
describe: 'whether discount CT should be used',
type: 'boolean',
default: false,
},
};
3 changes: 0 additions & 3 deletions lib/cli/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export const prepareTx = async (
network,
argv.destinationAddress,
argv.blindingKey,
argv.discountCT,
),
destinationAddress: argv.destinationAddress,
keys: ECPair.fromPrivateKey(getHexBuffer(argv.privateKey)),
Expand Down Expand Up @@ -150,12 +149,10 @@ export const getWalletStub = (
network: Network | LiquidNetwork,
destinationAddress: string,
blindingKey?: string,
discountCT?: boolean,
) =>
({
type,
network,
supportsDiscountCT: discountCT || false,
decodeAddress: () => toOutputScript(type, destinationAddress, network),
deriveBlindingKeyFromScript: () => {
const key = {
Expand Down
3 changes: 1 addition & 2 deletions lib/cli/commands/Claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import BuilderComponents from '../BuilderComponents';
import { prepareTx } from '../Command';

export const command =
'claim <network> <preimage> <privateKey> <redeemScript> <rawTransaction> <destinationAddress> [feePerVbyte] [blindingKey] [discountCT]';
'claim <network> <preimage> <privateKey> <redeemScript> <rawTransaction> <destinationAddress> [feePerVbyte] [blindingKey]';

export const describe = 'claims reverse submarine or chain to chain swaps';

Expand All @@ -22,7 +22,6 @@ export const builder = {
destinationAddress: BuilderComponents.destinationAddress,
feePerVbyte: BuilderComponents.feePerVbyte,
blindingKey: BuilderComponents.blindingKey,
discountCT: BuilderComponents.discountCT,
};

export const handler = async (argv: Arguments<any>): Promise<void> => {
Expand Down
3 changes: 1 addition & 2 deletions lib/cli/commands/Refund.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import BuilderComponents from '../BuilderComponents';
import { prepareTx } from '../Command';

export const command =
'refund <network> <privateKey> <timeoutBlockHeight> <redeemScript> <rawTransaction> <destinationAddress> [feePerVbyte] [blindingKey] [discountCT]';
'refund <network> <privateKey> <timeoutBlockHeight> <redeemScript> <rawTransaction> <destinationAddress> [feePerVbyte] [blindingKey]';

export const describe = 'refunds submarine or chain to chain swaps';

Expand All @@ -25,7 +25,6 @@ export const builder = {
destinationAddress: BuilderComponents.destinationAddress,
feePerVbyte: BuilderComponents.feePerVbyte,
blindingKey: BuilderComponents.blindingKey,
discountCT: BuilderComponents.discountCT,
};

export const handler = async (argv: Arguments<any>): Promise<void> => {
Expand Down
26 changes: 1 addition & 25 deletions lib/rates/FeeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
import { PairConfig } from '../consts/Types';
import Referral from '../db/models/Referral';
import { ExtraFees } from '../service/Service';
import WalletLiquid from '../wallet/WalletLiquid';
import WalletManager from '../wallet/WalletManager';
import { Ethereum, Rsk } from '../wallet/ethereum/EvmNetworks';
import DataAggregator from './data/DataAggregator';
Expand Down Expand Up @@ -73,7 +72,6 @@ class FeeProvider {
public static transactionSizes: {
[CurrencyType.BitcoinLike]: TransactionSizes;
[CurrencyType.Liquid]: TransactionSizes;
['DiscountCT']: TransactionSizes;
} = {
[CurrencyType.BitcoinLike]: {
[SwapVersion.Taproot]: {
Expand All @@ -96,18 +94,6 @@ class FeeProvider {
},
},
[CurrencyType.Liquid]: {
[SwapVersion.Taproot]: {
normalClaim: 1337,
reverseLockup: 2503,
reverseClaim: 1309,
},
[SwapVersion.Legacy]: {
normalClaim: 1333,
reverseLockup: 2503,
reverseClaim: 1378,
},
},
['DiscountCT']: {
[SwapVersion.Taproot]: {
normalClaim: 181,
reverseLockup: 269,
Expand Down Expand Up @@ -383,17 +369,7 @@ class FeeProvider {
let sizes: TransactionSizes;

if (chainCurrency === ElementsClient.symbol) {
if (
(
this.walletManager.wallets.get(
ElementsClient.symbol,
) as WalletLiquid
).supportsDiscountCT
) {
sizes = FeeProvider.transactionSizes['DiscountCT'];
} else {
sizes = FeeProvider.transactionSizes[CurrencyType.Liquid];
}
sizes = FeeProvider.transactionSizes[CurrencyType.Liquid];
} else {
sizes = FeeProvider.transactionSizes[CurrencyType.BitcoinLike];
}
Expand Down
9 changes: 2 additions & 7 deletions lib/service/Service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ import NodeSwitch from '../swap/NodeSwitch';
import { SwapNurseryEvents } from '../swap/PaymentHandler';
import SwapManager, { ChannelCreationInfo } from '../swap/SwapManager';
import SwapOutputType from '../swap/SwapOutputType';
import type WalletLiquid from '../wallet/WalletLiquid';
import WalletManager, { Currency } from '../wallet/WalletManager';
import BalanceCheck from './BalanceCheck';
import Blocks from './Blocks';
Expand Down Expand Up @@ -496,7 +495,6 @@ class Service {
}

case CurrencyType.Liquid: {
const wallet = this.walletManager.wallets.get(symbol)! as WalletLiquid;
const tx = parseTransaction(
currency.type,
await currency.chainClient!.getRawTransaction(transactionId),
Expand All @@ -505,7 +503,7 @@ class Service {

return {
absolute,
satPerVbyte: absolute / tx.virtualSize(wallet.supportsDiscountCT),
satPerVbyte: absolute / tx.virtualSize(true),
};
}

Expand Down Expand Up @@ -856,10 +854,7 @@ class Service {
const isSwapRelated = swapsFunded.length > 0 || swapsSpent.length > 0;
const needsLowball =
currency.type === CurrencyType.Liquid &&
ElementsClient.needsLowball(
wallet as WalletLiquid,
transaction as LiquidTransaction,
);
ElementsClient.needsLowball(transaction as LiquidTransaction);

const relevantSwapIds = swapsSpent.concat(swapsFunded).map((r) => r.id);

Expand Down
15 changes: 2 additions & 13 deletions lib/swap/UtxoNursery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ class UtxoNursery extends TypedEventEmitter<{
if (!confirmed) {
const zeroConfRejectedReason = await this.acceptsZeroConf(
swap,
wallet,
chainClient,
transaction,
);
Expand Down Expand Up @@ -815,7 +814,6 @@ class UtxoNursery extends TypedEventEmitter<{
if (!confirmed) {
const zeroConfRejectedReason = await this.acceptsZeroConf(
updatedSwap,
wallet,
chainClient,
transaction,
);
Expand Down Expand Up @@ -870,7 +868,6 @@ class UtxoNursery extends TypedEventEmitter<{

private acceptsZeroConf = async (
swap: Swap | ChainSwapInfo,
wallet: Wallet,
chainClient: IChainClient,
transaction: Transaction | LiquidTransaction,
) => {
Expand All @@ -892,12 +889,7 @@ class UtxoNursery extends TypedEventEmitter<{
]);

const transactionFeePerVbyte =
absoluteTransactionFee /
transaction.virtualSize(
wallet.symbol === ElementsClient.symbol
? (wallet as WalletLiquid).supportsDiscountCT
: undefined,
);
absoluteTransactionFee / transaction.virtualSize(true);

// If the transaction fee is less than 80% of the estimation, Boltz will wait for a confirmation
//
Expand All @@ -910,10 +902,7 @@ class UtxoNursery extends TypedEventEmitter<{
// Make sure all clients accept the transaction
if (
chainClient.symbol === ElementsClient.symbol &&
!ElementsClient.needsLowball(
wallet as WalletLiquid,
transaction as LiquidTransaction,
)
!ElementsClient.needsLowball(transaction as LiquidTransaction)
) {
if (chainClient instanceof ElementsWrapper) {
const wrapper = chainClient as ElementsWrapper;
Expand Down
10 changes: 0 additions & 10 deletions lib/wallet/WalletLiquid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,6 @@ class WalletLiquid extends Wallet {
network: Network,
) {
super(logger, CurrencyType.Liquid, walletProvider, network);

if (this.supportsDiscountCT) {
this.logger.info(`${this.serviceName()} wallet supports Discount CT`);
}
}

public get supportsDiscountCT(): boolean {
return !(this.network as Network).genesisBlockHash.equals(
networks.liquid.genesisBlockHash,
);
}

public deriveBlindingKeyFromScript = (
Expand Down
4 changes: 0 additions & 4 deletions test/integration/chain/ElementsWrapper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,4 @@ describe('ElementsWrapper', () => {
test('should prefer lowball over public client for wallet', () => {
expect(wrapper['walletClient']().isLowball).toEqual(true);
});

test('should prefer lowball over public client for fee estimations', async () => {
await expect(wrapper.estimateFee()).resolves.toEqual(0.01);
});
});
11 changes: 3 additions & 8 deletions test/unit/chain/ElementsClient.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ describe('ElementsClient', () => {
test.each`
lowball | expected
${false} | ${0.1}
${true} | ${0.01}
${true} | ${0.1}
`(
'should set estimate sat/vbyte fee of $expected for lowball ($lowball)',
async ({ lowball, expected }) => {
Expand Down Expand Up @@ -34,18 +34,13 @@ describe('ElementsClient', () => {
'should determine if transaction needs lowball',
({ transactionHex, expected }) => {
expect(
ElementsClient.needsLowball(
{ supportsDiscountCT: false } as any,
Transaction.fromHex(transactionHex),
),
ElementsClient.needsLowball(Transaction.fromHex(transactionHex)),
).toEqual(expected);
},
);

test('should return false when no fee output can be found', () => {
expect(ElementsClient.needsLowball({} as any, new Transaction())).toEqual(
false,
);
expect(ElementsClient.needsLowball(new Transaction())).toEqual(false);
});
});
});
27 changes: 0 additions & 27 deletions test/unit/rates/FeeProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Referral from '../../../lib/db/models/Referral';
import FeeProvider from '../../../lib/rates/FeeProvider';
import DataAggregator from '../../../lib/rates/data/DataAggregator';
import { ExtraFees } from '../../../lib/service/Service';
import WalletLiquid from '../../../lib/wallet/WalletLiquid';
import WalletManager from '../../../lib/wallet/WalletManager';
import { Ethereum } from '../../../lib/wallet/ethereum/EvmNetworks';

Expand Down Expand Up @@ -38,14 +37,6 @@ const MockedDataAggregator = <jest.Mock<DataAggregator>>DataAggregator;

jest.mock('../../../lib/wallet/WalletManager', () => {
return jest.fn().mockImplementation(() => ({
wallets: new Map([
[
'L-BTC',
{
supportsDiscountCT: false,
},
],
]),
ethereumManagers: [
{
networkDetails: Ethereum,
Expand Down Expand Up @@ -414,24 +405,6 @@ describe('FeeProvider', () => {
});
});

test('should honor discount CT flag of wallet', async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
(walletManager.wallets.get('L-BTC')! as WalletLiquid).supportsDiscountCT =
false;

await feeProvider.updateMinerFees('L-BTC');
expect(feeProvider.minerFees.get('L-BTC')).toMatchSnapshot();

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
(walletManager.wallets.get('L-BTC')! as WalletLiquid).supportsDiscountCT =
true;

await feeProvider.updateMinerFees('L-BTC');
expect(feeProvider.minerFees.get('L-BTC')).toMatchSnapshot();
});

describe('getFees', () => {
test('should get fees of a Swap', () => {
const amount = 100000000;
Expand Down
Loading

0 comments on commit aa291b3

Please sign in to comment.