chore(coinjoin): remove fast fee rate median

This commit is contained in:
Jan Komarek
2023-02-03 16:16:47 +01:00
committed by Jan Komárek
parent c38d948b6c
commit 73c848ba5a
11 changed files with 28 additions and 55 deletions

View File

@@ -11,7 +11,7 @@ const client = new CoinjoinClient(settings);
const status = await client.enable();
```
Once enabled it periodically sync with coordinator `/status` using random proxy (TOR) identities and time frequency until `client.disable();` is called.
Once enabled it periodically syncs with coordinator `/status` using random proxy (TOR) identities and time frequency until `client.disable();` is called.
Status changes are emitted as `status` event:
@@ -20,8 +20,9 @@ client.on('status', event => {});
{
rounds: Round[]; // current list of rounds
changes: Round[]: // list of changed rounds since recent update
feeRatesMedians: Array<{ timeFrame: string; medianFeeRate: number; }>, // timeFrame format: "0d 0h 0m 0s"
coordinatorFeeRate: action.status.coordinatorFeeRate, // current coordinatorFeeRate
changed: Round[]: // list of changed rounds since recent update
maxMingFee: number // max mining fee resulting from recommended fee rate median
coordinatorFeeRate: CoordinationFeeRate // current rate and plebsDontPayThreshold
allowedInputAmounts: AllowedRange; // min and max allowed input value
}
```

View File

@@ -40,6 +40,7 @@ export const PLEBS_DONT_PAY_THRESHOLD = 1000000;
export const COORDINATOR_FEE_RATE = 0.003;
export const MIN_ALLOWED_AMOUNT = 5000;
export const MAX_ALLOWED_AMOUNT = 134375000000;
export const MAX_MINING_FEE = 1;
// affiliation flag:
// - sent coordinator/ready-to-sign request **only** when Alice pays coordination fee

View File

@@ -5,7 +5,7 @@ import { CoinjoinRequestEvent, CoinjoinRoundEvent } from './round';
export interface CoinjoinStatusEvent {
rounds: Round[];
changed: Round[];
feeRatesMedians: { fast: number; recommended: number };
maxMiningFee: number;
coordinationFeeRate: CoordinationFeeRate;
allowedInputAmounts: AllowedRange;
}

View File

@@ -1,5 +1,6 @@
import {
COORDINATOR_FEE_RATE,
MAX_MINING_FEE,
MAX_ALLOWED_AMOUNT,
MIN_ALLOWED_AMOUNT,
PLEBS_DONT_PAY_THRESHOLD,
@@ -158,36 +159,26 @@ const getDataFromRounds = (rounds: Round[]) => {
};
};
/**
* Transform from coordinator format to coinjoinReducer format `CoinjoinClientFeeRatesMedians`
* array => object { name: value-in-vBytes }
*/
export const transformFeeRatesMedians = (medians: CoinjoinStatus['coinJoinFeeRateMedians']) => {
const [fast, recommended] = medians.map(m => m.medianFeeRate);
// convert from kvBytes (kilo virtual bytes) to vBytes (how the value is displayed in UI)
const kvB2vB = (v: number) => (v ? Math.round(v / 1000) : 1);
return {
fast: kvB2vB(fast) * 2, // NOTE: this calculation will be smarter once have enough data
recommended: kvB2vB(recommended),
};
};
/**
* Transform from coordinator format to coinjoinReducer format `CoinjoinClientInstance`
* - coordinatorFeeRate: multiply the amount registered for coinjoin by this value to get the total fee
* - feeRatesMedians: array => object with values in kvBytes
* - maxMiningFee: array => value in kvBytes
*/
export const transformStatus = ({
coinJoinFeeRateMedians,
roundStates: rounds,
}: CoinjoinStatus) => {
const feeRatesMedians = transformFeeRatesMedians(coinJoinFeeRateMedians);
const { allowedInputAmounts, coordinationFeeRate } = getDataFromRounds(rounds);
// coinJoinFeeRateMedians include an array of medians per day, week and month - we take the second (week) median as the recommended fee rate
const recommendedMedian = coinJoinFeeRateMedians[1];
// the value is converted from kvBytes (kilo virtual bytes) to vBytes (how the value is displayed in UI)
const maxMiningFee = recommendedMedian
? Math.round(coinJoinFeeRateMedians[1].medianFeeRate / 1000)
: MAX_MINING_FEE;
return {
rounds,
feeRatesMedians,
maxMiningFee,
coordinationFeeRate,
allowedInputAmounts,
};

View File

@@ -136,13 +136,8 @@ export const createCoinjoinRound = (
return round;
};
export const FEE_RATE_RESULTS = {
fast: 258,
recommended: 129,
};
export const STATUS_TRANSFORMED = {
feeRatesMedians: FEE_RATE_RESULTS,
maxMiningFee: 129,
allowedInputAmounts: {
max: 134375000000,
min: 5000,

View File

@@ -2,17 +2,10 @@ import {
getCommitmentData,
readTimeSpan,
estimatePhaseDeadline,
transformFeeRatesMedians,
transformStatus,
} from '../../src/utils/roundUtils';
import { ROUND_REGISTRATION_END_OFFSET } from '../../src/constants';
import {
DEFAULT_ROUND,
FEE_RATE_MEDIANS,
FEE_RATE_RESULTS,
STATUS_EVENT,
STATUS_TRANSFORMED,
} from '../fixtures/round.fixture';
import { DEFAULT_ROUND, STATUS_EVENT, STATUS_TRANSFORMED } from '../fixtures/round.fixture';
describe('roundUtils', () => {
it('getCommitmentData', () => {
@@ -89,19 +82,11 @@ describe('roundUtils', () => {
);
});
describe('transformFeeRatesMedians', () => {
it('transform correctly', () => {
const feeRatesMedians = transformFeeRatesMedians(FEE_RATE_MEDIANS);
expect(feeRatesMedians).toEqual(FEE_RATE_RESULTS);
});
});
describe('transformStatus', () => {
it('transform correctly', () => {
const feeRatesMedians = transformStatus(STATUS_EVENT);
const status = transformStatus(STATUS_EVENT);
expect(feeRatesMedians).toEqual(STATUS_TRANSFORMED);
expect(status).toEqual(STATUS_TRANSFORMED);
});
});
});

View File

@@ -22,7 +22,7 @@ jest.mock('@suite/services/coinjoin/coinjoinService', () => {
enable: jest.fn(() =>
Promise.resolve({
rounds: [{ id: '00', phase: 0 }],
feeRatesMedians: [],
maxMiningFee: 0,
coordinatorFeeRate: 0.003,
allowedInputAmounts: { min: 5000, max: 134375000000 },
}),

View File

@@ -27,7 +27,7 @@ import { AccountsRootState, selectAccountByKey } from '@suite-common/wallet-core
export interface CoinjoinClientInstance
extends Pick<
CoinjoinStatusEvent,
'coordinationFeeRate' | 'allowedInputAmounts' | 'feeRatesMedians'
'coordinationFeeRate' | 'allowedInputAmounts' | 'maxMiningFee'
> {
rounds: { id: string; phase: RoundPhase }[]; // store only slice of Round in reducer. may be extended in the future
status: 'loading' | 'loaded';
@@ -552,9 +552,8 @@ export const selectMinAllowedInputWithFee = memoizeWithArgs(
const status = coinjoinClient || DEFAULT_CLIENT_STATUS;
const minAllowedInput = status.allowedInputAmounts.min;
const txSize = getInputSize('Taproot') + getOutputSize('Taproot');
const recommendedFeeRate = status.feeRatesMedians.recommended;
return minAllowedInput + txSize * recommendedFeeRate;
return minAllowedInput + txSize * status.maxMiningFee;
},
);

View File

@@ -3,6 +3,7 @@ import {
COORDINATOR_FEE_RATE,
MIN_ALLOWED_AMOUNT,
MAX_ALLOWED_AMOUNT,
MAX_MINING_FEE,
} from '@trezor/coinjoin/src/constants';
import type { CoinjoinBackendSettings, CoinjoinClientSettings } from '@trezor/coinjoin';
import type { PartialRecord } from '@trezor/type-utils';
@@ -142,7 +143,7 @@ export const DEFAULT_TARGET_ANONYMITY = 10;
export const DEFAULT_CLIENT_STATUS = {
rounds: [],
feeRatesMedians: { fast: 0, recommended: 0 },
maxMiningFee: MAX_MINING_FEE,
coordinationFeeRate: {
rate: COORDINATOR_FEE_RATE,
plebsDontPayThreshold: PLEBS_DONT_PAY_THRESHOLD,

View File

@@ -111,12 +111,12 @@ export const calculateAnonymityProgress = ({
export const transformCoinjoinStatus = ({
coordinationFeeRate,
feeRatesMedians,
maxMiningFee,
allowedInputAmounts,
rounds,
}: CoinjoinStatusEvent) => ({
coordinationFeeRate,
feeRatesMedians,
maxMiningFee,
allowedInputAmounts,
rounds: rounds.map(({ id, phase }) => ({ id, phase })),
});

View File

@@ -162,7 +162,7 @@ export const CoinjoinConfirmation = ({ account }: CoinjoinConfirmationProps) =>
dispatch(
startCoinjoinSession(account, {
maxCoordinatorFeeRate: coordinatorData.coordinationFeeRate.rate,
maxFeePerKvbyte: coordinatorData.feeRatesMedians.recommended * 1000, // transform to kvB
maxFeePerKvbyte: coordinatorData.maxMiningFee * 1000, // transform to kvB
maxRounds,
skipRounds: RECOMMENDED_SKIP_ROUNDS,
targetAnonymity,