mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-02-20 00:33:07 +01:00
chore(coinjoin): remove fast fee rate median
This commit is contained in:
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 },
|
||||
}),
|
||||
|
||||
@@ -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;
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 })),
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user