Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: use BigNumber in FeeInput & AmountInput with ux improvements #391

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
10 changes: 10 additions & 0 deletions .changeset/tricky-suns-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@cypherock/coin-support-btc': patch
'@cypherock/cysync-core': patch
'@cypherock/cysync-utils': patch
'@cypherock/cysync-ui': patch
'@cypherock/cysync-cli': patch
'@cypherock/cysync-desktop': patch
---

feat: use BigNumber in FeeInput & AmountInput with ux improvements
2 changes: 1 addition & 1 deletion apps/cli/src/services/send/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const getTxnInputs = async (params: {
throw new Error('Invalid fees');
}

txn.userInputs.feeRate = feeRate;
txn.userInputs.feeRate = feeRate.toString(10);
}

if (coin.family === coinFamiliesMap.evm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const broadcastTransaction = async (

const parsedTransaction: ITransaction = {
hash: txnHash,
fees: transaction.computedData.fee.toString(),
fees: transaction.computedData.fee,
amount: '0',
status: TransactionStatusMap.pending,
type: TransactionTypeMap.receive,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const initializeTransaction = async (
utxos,
},
computedData: {
fee: 0,
fee: '0',
inputs: [],
outputs: [],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const prepareTransaction = async (
result = coinselectSplit(
txn.staticData.utxos.map(mapUtxo),
outputList,
txn.userInputs.feeRate,
Number(txn.userInputs.feeRate),
3,
);
isNotOverDustThreshold = Boolean(result.isNotOverDustThreshold);
Expand Down Expand Up @@ -107,7 +107,7 @@ export const prepareTransaction = async (
result = coinselect(
txn.staticData.utxos.map(mapUtxo),
outputList,
txn.userInputs.feeRate,
Number(txn.userInputs.feeRate),
);
}

Expand Down Expand Up @@ -135,7 +135,7 @@ export const prepareTransaction = async (
},
computedData: {
inputs: result.inputs ?? [],
fee: result.fee,
fee: result.fee.toString(10),
outputs: (result.outputs ?? []).map((e: any) => {
if (e.address === undefined) {
return {
Expand Down
6 changes: 3 additions & 3 deletions packages/coin-support-btc/src/operations/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ export interface IPreparedBtcTransaction extends IPreparedTransaction {
};
userInputs: {
outputs: IPreparedTransactionOutput[];
feeRate: number;
feeRate: string;
isSendAll: boolean;
};
staticData: {
averageFee: number;
averageFee: string;
utxos: IUtxo[];
};
computedData: {
inputs: IPreparedBtcTransactionInput[];
outputs: IPreparedBtcTransactionOutput[];
fee: number;
fee: string;
};
}
4 changes: 2 additions & 2 deletions packages/coin-support-btc/src/services/fees.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { config } from '../config';

const baseURL = `${config.API_CYPHEROCK}/transaction`;

export const getAverageFee = async (coin: IBtcCoinInfo): Promise<number> => {
export const getAverageFee = async (coin: IBtcCoinInfo): Promise<string> => {
const url = `${baseURL}/fees`;
const response = await axios.post(url, {
coinType: coin.apiCoinType,
Expand All @@ -17,5 +17,5 @@ export const getAverageFee = async (coin: IBtcCoinInfo): Promise<number> => {
new Error('Server: Invalid fees result from server'),
);

return Math.round(response.data.medium_fee_per_kb / 1024);
return Math.round(response.data.medium_fee_per_kb / 1024).toString(10);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export interface IInitializeTransactionTestCases {
txn: IPreparedBtcTransaction;
mocks: {
account: Partial<IBtcAccount>;
averageFee: number;
averageFee: string;
utxos: IUtxo[];
};
}
Expand All @@ -16,16 +16,16 @@ export const valid: IInitializeTransactionTestCases[] = [
txn: {
accountId: '1',
computedData: {
fee: 0,
fee: '0',
inputs: [],
outputs: [],
},
staticData: {
averageFee: 150,
averageFee: '150',
utxos: [],
},
userInputs: {
feeRate: 150,
feeRate: '150',
outputs: [],
isSendAll: false,
},
Expand All @@ -42,7 +42,7 @@ export const valid: IInitializeTransactionTestCases[] = [
parentAssetId: 'bitcoin',
familyId: 'bitcoin',
},
averageFee: 150,
averageFee: '150',
utxos: [],
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const valid: IPrepareTransactionTestCases[] = [
accountId: '1',
userInputs: {
outputs: [{ address: 'kajshd', amount: '' }],
feeRate: 150,
feeRate: '150',
isSendAll: false,
},
staticData: {
averageFee: 150,
averageFee: '150',
utxos: [
{
txid: '8b1720b139daa3231455348806a6d01f53bd6cb31f6068b4b206fc5a8bf46aba',
Expand All @@ -35,7 +35,7 @@ export const valid: IPrepareTransactionTestCases[] = [
],
},
computedData: {
fee: 0,
fee: '0',
inputs: [],
outputs: [],
},
Expand All @@ -61,11 +61,11 @@ export const valid: IPrepareTransactionTestCases[] = [
accountId: '1',
userInputs: {
outputs: [{ address: 'kajshd', amount: '' }],
feeRate: 150,
feeRate: '150',
isSendAll: false,
},
staticData: {
averageFee: 150,
averageFee: '150',
utxos: [
{
txid: '8b1720b139daa3231455348806a6d01f53bd6cb31f6068b4b206fc5a8bf46aba',
Expand All @@ -79,7 +79,7 @@ export const valid: IPrepareTransactionTestCases[] = [
],
},
computedData: {
fee: 33900,
fee: '33900',
inputs: [
{
address: 'LYzVffwKeuwnqeuwVikH59gk3iLvVaeZUN',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ export const valid: IPrepareTransactionTestCases[] = [
outputs: [
{ address: 'LPMmBEMdTVpoNYDKooGWjkFyQ2YduGZpyA', amount: '10000' },
],
feeRate: 150,
feeRate: '150',
isSendAll: false,
},
staticData: {
averageFee: 150,
averageFee: '150',
utxos: [
{
txid: '8b1720b139daa3231455348806a6d01f53bd6cb31f6068b4b206fc5a8bf46aba',
Expand All @@ -42,7 +42,7 @@ export const valid: IPrepareTransactionTestCases[] = [
],
},
computedData: {
fee: 33900,
fee: '33900',
inputs: [
{
address: 'LYzVffwKeuwnqeuwVikH59gk3iLvVaeZUN',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Typography,
CustomInputSend,
} from '@cypherock/cysync-ui';
import { BigNumber } from '@cypherock/cysync-utils';
import { processNonNegativeNumericInput } from '@cypherock/cysync-utils';
import lodash from 'lodash';
import React, { useCallback, useEffect, useState } from 'react';

Expand Down Expand Up @@ -86,43 +86,30 @@ export const AmountInput: React.FC<AmountInputProps> = ({
debouncedOnSendMax(checked);
};

const filterNumericInput = (val: string) => {
let filteredValue = val.replace(/[^0-9.]/g, '');
const bigNum = new BigNumber(filteredValue);

if (filteredValue.includes('.')) {
const splitValue = filteredValue.split('.');
let firstValue = splitValue[0];
const secondValue = splitValue[1];

const firstValBigNumber = new BigNumber(firstValue);

if (firstValBigNumber.isNaN() || firstValBigNumber.isZero()) {
firstValue = '0';
}

filteredValue = `${firstValue}.${secondValue}`;
} else if (!bigNum.isNaN() && bigNum.isZero()) {
filteredValue = '0';
}

return filteredValue;
};

const updateValues = (amount: string, value: string, skipCall?: boolean) => {
setCoinAmount(amount);
setCoinValue(value);
if (!skipCall) debouncedOnValueChange(amount);
};

const handleCoinAmountChange = (val: string) => {
const filteredValue = filterNumericInput(val);
updateValues(filteredValue, converter(filteredValue));
const handleCoinAmountChange = (input: string, isPasted: boolean) => {
const result = processNonNegativeNumericInput({
input,
isBigNumber: true,
isPasted,
});
if (!result.isValid) return;
updateValues(result.inputValue, converter(result.inputValue));
};

const handleCoinValueChange = (val: string) => {
const filteredValue = filterNumericInput(val);
updateValues(converter(filteredValue, true), filteredValue);
const handleCoinValueChange = (input: string, isPasted: boolean) => {
const result = processNonNegativeNumericInput({
input,
isBigNumber: true,
isPasted,
});
if (!result.isValid) return;
updateValues(converter(result.inputValue, true), result.inputValue);
};

return (
Expand All @@ -146,7 +133,8 @@ export const AmountInput: React.FC<AmountInputProps> = ({
type="text"
name="address"
placeholder={placeholder}
onChange={handleCoinAmountChange}
onChange={val => handleCoinAmountChange(val, false)}
onPaste={val => handleCoinAmountChange(val, true)}
value={coinAmount}
disabled={isToggled || isDisabled}
$textColor="white"
Expand All @@ -166,7 +154,8 @@ export const AmountInput: React.FC<AmountInputProps> = ({
type="text"
name="address"
placeholder={placeholder}
onChange={handleCoinValueChange}
onChange={val => handleCoinValueChange(val, false)}
onPaste={val => handleCoinValueChange(val, true)}
value={coinValue}
disabled={isToggled || isDisabled}
$textColor="white"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import React, { useState } from 'react';

import { selectLanguage, useAppSelector } from '~/store';

interface BitcoinInputProps {
initialValue: number;
export interface BitcoinInputProps {
initialValue: string;
isTextInput: boolean;
unit: string;
onChange: (newValue: number) => void;
onChange: (newValue: string) => void;
}

export const BitcoinInput: React.FC<BitcoinInputProps> = ({
Expand All @@ -26,7 +26,7 @@ export const BitcoinInput: React.FC<BitcoinInputProps> = ({
const captions = lang.strings.send.fees.sliderLabels;
const [value, setValue] = useState(initialValue);

const handleChange = (val: number) => {
const handleChange = (val: string) => {
setValue(val);
onChange(val);
};
Expand All @@ -35,7 +35,7 @@ export const BitcoinInput: React.FC<BitcoinInputProps> = ({
<>
{isTextInput && (
<FeesInput
value={value.toString()}
value={value}
postfixText={unit}
onChange={handleChange}
valueType="integer"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import React, { useEffect, useState } from 'react';
import { useSendDialog } from '~/dialogs/Send/context';
import { selectLanguage, useAppSelector } from '~/store';

interface EthereumInputProps {
initialGasPrice: number;
inputGasPrice: number;
export interface EthereumInputProps {
initialGasPrice: string;
inputGasPrice: string;
isTextInput: boolean;
unit: string;
onChange: (param: { gasLimit?: number; gasPrice?: number }) => void;
onChange: (param: { gasLimit?: string; gasPrice?: string }) => void;
}

export const EthereumInput: React.FC<EthereumInputProps> = ({
Expand All @@ -35,13 +35,13 @@ export const EthereumInput: React.FC<EthereumInputProps> = ({
const transaction = useSendDialog().transaction as IPreparedEvmTransaction;
const { getDefaultGasLimit } = useSendDialog();

const handlePriceChange = (val: number) => {
const handlePriceChange = (val: string) => {
setGasPrice(val);
// on change gas price, prepare EVM fee
onChange({ gasPrice: val });
};

const handleLimitChange = (val: number) => {
const handleLimitChange = (val: string) => {
// on change gas limit, prepare EVM fee
onChange({ gasLimit: val });
};
Expand All @@ -51,7 +51,7 @@ export const EthereumInput: React.FC<EthereumInputProps> = ({
transaction.userInputs.gasPrice = initialGasPrice.toString();
transaction.userInputs.gasLimit = getDefaultGasLimit();
onChange({
gasLimit: Number(transaction.userInputs.gasLimit),
gasLimit: transaction.userInputs.gasLimit,
gasPrice: initialGasPrice,
});
}, [isTextInput, transaction.computedData.gasLimitEstimate]);
Expand Down Expand Up @@ -95,7 +95,7 @@ export const EthereumInput: React.FC<EthereumInputProps> = ({
</Flex>
</Flex>
<FeesInput
value={gasPrice.toString()}
value={gasPrice}
postfixText={unit}
onChange={handlePriceChange}
/>
Expand Down
Loading
Loading