Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [[v3.3.0](https://github.com/multiversx/mx-sdk-dapp/pull/1380)] - 2025-03-11
- [Added gasPrice editing](https://github.com/multiversx/mx-sdk-dapp/pull/1377)

## [[v3.2.7](https://github.com/multiversx/mx-sdk-dapp/pull/1384)] - 2025-03-11

Expand All @@ -16,11 +18,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Fixed sign screen layout and move decoder styles inside the package](https://github.com/multiversx/mx-sdk-dapp/pull/1381)

## [[v3.2.5](https://github.com/multiversx/mx-sdk-dapp/pull/1379)] - 2025-03-11

- [Fixed websocket connection and falback mechanism](https://github.com/multiversx/mx-sdk-dapp/pull/1378)
- [Fixed websocket connection and fallback mechanism](https://github.com/multiversx/mx-sdk-dapp/pull/1378)

## [[v3.2.4](https://github.com/multiversx/mx-sdk-dapp/pull/1376)] - 2025-02-17

- [Added a warning toast when an unconfirmed guardian change took place](https://github.com/multiversx/mx-sdk-dapp/pull/1375)
- [Fixed metamask addon link to use new Chrome Web Store domain](https://github.com/multiversx/mx-sdk-dapp/pull/1374)

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-dapp",
"version": "3.2.7",
"version": "3.3.0",
"description": "A library to hold the main logic for a dapp on the MultiversX blockchain",
"author": "MultiversX",
"license": "GPL-3.0-or-later",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ const SignStepComponent = (props: SignStepType & WithStylesImportType) => {
signStepInnerClasses,
styles,
title,
waitingForDevice
waitingForDevice,
updatePPU
} = props;

const [showGuardianScreen, setShowGuardianScreen] = useState(false);

// a unique mapping between nonce + data and step to prevent signing same transaction twice
const [nonceDataStepMap, setNonceDataStepMap] = useState<
Record<number, number | undefined>
Record<string, number | undefined>
>({});

if (!currentTransaction) {
Expand Down Expand Up @@ -110,6 +111,7 @@ const SignStepComponent = (props: SignStepType & WithStylesImportType) => {

const signStepBodyProps: SignStepBodyPropsType = {
currentTransaction,
updatePPU,
error,
allTransactions,
currentStep,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const SignWithDeviceModalComponent = ({
setSignedTransactions,
currentStep,
callbackRoute,
currentTransaction
currentTransaction,
updatePPU
} = useSignTransactionsWithDevice({
onCancel: handleClose,
verifyReceiverScam,
Expand Down Expand Up @@ -69,6 +70,7 @@ const SignWithDeviceModalComponent = ({
callbackRoute={callbackRoute}
currentStep={currentStep}
currentTransaction={currentTransaction}
updatePPU={updatePPU}
error={error}
GuardianScreen={GuardianScreen}
handleClose={onAbort}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Address } from '@multiversx/sdk-core/out';
import classNames from 'classnames';

import { withStyles, WithStylesImportType } from 'hocs/withStyles';
import { UseSignTransactionsWithDeviceReturnType } from 'hooks/transactions/useSignTransactionsWithDevice';
import { ActiveLedgerTransactionType, MultiSignTransactionType } from 'types';
import { TransactionData } from 'UI/TransactionData';

Expand All @@ -25,6 +26,7 @@ export interface SignStepBodyPropsType {
callbackRoute?: string;
currentStep: number;
currentTransaction: ActiveLedgerTransactionType | null;
updatePPU: UseSignTransactionsWithDeviceReturnType['updatePPU'];
allTransactions: MultiSignTransactionType[];
signStepInnerClasses?: SignStepInnerClassesType;
isGuarded?: boolean;
Expand All @@ -34,6 +36,7 @@ const SignStepBodyComponent = ({
currentTransaction,
error,
signStepInnerClasses,
updatePPU,
globalStyles,
styles
}: SignStepBodyPropsType & WithStylesImportType) => {
Expand Down Expand Up @@ -70,7 +73,12 @@ const SignStepBodyComponent = ({
amount={amount}
/>

<ConfirmFee transaction={currentTransaction.transaction} />
<ConfirmFee
needsSigning={currentTransaction.needsSigning}
ppu={currentTransaction.ppu}
transaction={currentTransaction.transaction}
updatePPU={updatePPU}
/>

{data && (
<TransactionData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import { Transaction } from '@multiversx/sdk-core/out';
import React, { MouseEvent, useState } from 'react';
import { faGear } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import classNames from 'classnames';

import {
DataTestIdsEnum,
Expand All @@ -17,15 +19,20 @@ import {
formatAmount
} from 'utils/operations';

export interface FeePropsType {
transaction: Transaction;
}
import { GasDetails } from './components';
import { GasDetailsPropsType } from './components/GasDetails/gasDetails.types';

export type ConfirmFeePropsType = GasDetailsPropsType & WithStylesImportType;

const ConfirmFeeComponent = ({
transaction,
ppu,
needsSigning,
updatePPU,
styles
}: FeePropsType & WithStylesImportType) => {
}: ConfirmFeePropsType) => {
const { price } = useGetEgldPrice();
const [showGasDetails, setShowGasDetails] = useState(false);

const egldLabel = getEgldLabel();
const feeLimit = calculateFeeLimit({
Expand All @@ -50,39 +57,66 @@ const ConfirmFeeComponent = ({
})
: null;

return (
<div className={styles?.confirmFee}>
<div className={styles?.confirmFeeLabel}>Transaction Fee</div>
const handleToggleGasDetails = (event: MouseEvent<SVGSVGElement>) => {
event.preventDefault();
setShowGasDetails((isDetailsVisible) => !isDetailsVisible);
};

<div className={styles?.confirmFeeData}>
<Balance
className={styles?.confirmFeeDataBalance}
data-testid={DataTestIdsEnum.confirmFee}
egldIcon
showTokenLabel
showTokenLabelSup
tokenLabel={egldLabel}
amount={feeLimitFormatted}
/>
return (
<>
<div className={styles?.confirmFee}>
<div className={styles?.confirmFeeLabel}>
<span className={styles?.confirmFeeLabelText}>Transaction Fee</span>

{feeInFiatLimit ? (
<span className={styles?.confirmFeeDataPriceWrapper}>
(
<Balance
amount={feeInFiatLimit}
displayAsUsd
addEqualSign
className={styles?.confirmFeeDataPrice}
{needsSigning && (
<FontAwesomeIcon
icon={faGear}
onClick={handleToggleGasDetails}
className={classNames(styles?.confirmFeeLabelIcon, {
[styles?.toggled]: showGasDetails
})}
/>
)
</span>
) : (
<span className={styles?.confirmFeeDataPriceWrapper}>
<LoadingDots />
</span>
)}
)}
</div>

<div className={styles?.confirmFeeData}>
<Balance
className={styles?.confirmFeeDataBalance}
data-testid={DataTestIdsEnum.confirmFee}
egldIcon
showTokenLabel
showTokenLabelSup
tokenLabel={egldLabel}
amount={feeLimitFormatted}
/>

{feeInFiatLimit ? (
<span className={styles?.confirmFeeDataPriceWrapper}>
(
<Balance
amount={feeInFiatLimit}
displayAsUsd
addEqualSign
className={styles?.confirmFeeDataPrice}
/>
)
</span>
) : (
<span className={styles?.confirmFeeDataPriceWrapper}>
<LoadingDots />
</span>
)}
</div>
</div>
</div>

<GasDetails
transaction={transaction}
isVisible={showGasDetails}
needsSigning={needsSigning}
ppu={ppu}
updatePPU={updatePPU}
/>
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import React from 'react';
import classNames from 'classnames';
import { EMPTY_PPU } from 'constants/network';
import { withStyles } from 'hocs/withStyles';
import { useSelector } from 'reduxStore/DappProviderContext';
import { networkConfigSelector } from 'reduxStore/selectors';

import { ActiveLedgerTransactionType } from 'types/transactions.types';
import { Balance } from 'UI/Balance';
import { formatAmount } from 'utils';

import {
GasDetailsPropsType,
GasMultiplerOptionType
} from './gasDetails.types';

const GAS_PRICE_MODIFIER_FIELD = 'gasPriceMultiplier';

export const GasDetailsComponent = ({
transaction,
ppu,
isVisible,
needsSigning,
updatePPU,
styles
}: GasDetailsPropsType) => {
const gasPrice = transaction.getGasPrice().valueOf().toString();
const gasLimit = transaction.getGasLimit().valueOf().toString();

const {
network: { egldLabel, ppuForGasPrice }
} = useSelector(networkConfigSelector);

const formattedGasPrice = formatAmount({
input: gasPrice,
showLastNonZeroDecimal: true
});

const handleMultiplierChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
updatePPU(Number(event.target.value) as ActiveLedgerTransactionType['ppu']);
};

if (!ppuForGasPrice) {
return null;
}

const gasMultiplierOptions: GasMultiplerOptionType[] = [
{
label: 'Standard',
value: EMPTY_PPU
},
{
label: 'Fast',
value: ppuForGasPrice.fast
},
{
label: 'Faster',
value: ppuForGasPrice.faster
}
];

return (
<div
className={classNames(styles?.gasDetails, {
[styles?.visible]: isVisible
})}
>
<div className={styles?.gasDetailsWrapper}>
<div className={styles?.gasDetailsPrice}>
<div className={styles?.gasDetailsPriceLabel}>
<span className={styles?.gasDetailsPriceLabelText}>
Gas Price (per Gas Unit)
</span>

<div className={styles?.gasDetailsPriceMultipliers}>
{gasMultiplierOptions.map((gasMultiplierOption) => (
<div
key={gasMultiplierOption.label}
className={classNames(styles?.gasDetailsPriceMultiplier, {
[styles?.checked]: ppu === gasMultiplierOption.value,
[styles?.disabled]: !needsSigning
})}
>
<input
type='radio'
disabled={!needsSigning}
name={GAS_PRICE_MODIFIER_FIELD}
value={gasMultiplierOption.value}
onChange={handleMultiplierChange}
className={styles?.gasDetailsPriceMultiplierInput}
checked={ppu === gasMultiplierOption.value}
id={`${GAS_PRICE_MODIFIER_FIELD}-${gasMultiplierOption.value}`}
/>

<label
className={styles?.gasDetailsPriceMultiplierLabel}
htmlFor={`${GAS_PRICE_MODIFIER_FIELD}-${gasMultiplierOption.value}`}
>
{gasMultiplierOption.label}
</label>
</div>
))}
</div>
</div>

<Balance
className={styles?.gasDetailsPriceValue}
egldIcon
showTokenLabel
showTokenLabelSup
tokenLabel={egldLabel}
amount={formattedGasPrice}
/>
</div>

<div className={styles?.gasDetailsLimit}>
<div className={styles?.gasDetailsLimitLabel}>Gas Limit</div>

<Balance
className={styles?.gasDetailsLimitValue}
showTokenLabel={false}
amount={gasLimit}
egldIcon
/>
</div>
</div>
</div>
);
};

export const GasDetails = withStyles(GasDetailsComponent, {
ssrStyles: () =>
import(
'UI/SignTransactionsModals/SignWithDeviceModal/components/components/ConfirmFee/components/GasDetails/gasDetailsStyles.scss'
),
clientStyles: () =>
require('UI/SignTransactionsModals/SignWithDeviceModal/components/components/ConfirmFee/components/GasDetails/gasDetailsStyles.scss')
.default
});
Loading