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

[Issue-3658] Allow customizing fee for substrate/evm transactions #3989

Open
wants to merge 10 commits into
base: subwallet-dev
Choose a base branch
from
Open
4 changes: 3 additions & 1 deletion packages/extension-base/src/background/KoniTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types';
import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types';
import { AccountJson, AccountsWithCurrentAddress, AddressJson, BalanceJson, BaseRequestSign, BuyServiceInfo, BuyTokenInfo, CommonOptimalPath, CurrentAccountInfo, EarningRewardHistoryItem, EarningRewardJson, EarningStatus, HandleYieldStepParams, InternalRequestSign, LeavePoolAdditionalData, NominationPoolInfo, OptimalYieldPath, OptimalYieldPathParams, RequestAccountBatchExportV2, RequestAccountCreateSuriV2, RequestAccountNameValidate, RequestAccountProxyEdit, RequestAccountProxyForget, RequestBatchJsonGetAccountInfo, RequestBatchRestoreV2, RequestBounceableValidate, RequestChangeTonWalletContractVersion, RequestCheckCrossChainTransfer, RequestCheckPublicAndSecretKey, RequestCheckTransfer, RequestCrossChainTransfer, RequestDeriveCreateMultiple, RequestDeriveCreateV3, RequestDeriveValidateV2, RequestEarlyValidateYield, RequestExportAccountProxyMnemonic, RequestGetAllTonWalletContractVersion, RequestGetDeriveAccounts, RequestGetDeriveSuggestion, RequestGetYieldPoolTargets, RequestInputAccountSubscribe, RequestJsonGetAccountInfo, RequestJsonRestoreV2, RequestMetadataHash, RequestMnemonicCreateV2, RequestMnemonicValidateV2, RequestPrivateKeyValidateV2, RequestShortenMetadata, RequestStakeCancelWithdrawal, RequestStakeClaimReward, RequestTransfer, RequestUnlockDotCheckCanMint, RequestUnlockDotSubscribeMintedData, RequestYieldLeave, RequestYieldStepSubmit, RequestYieldWithdrawal, ResponseAccountBatchExportV2, ResponseAccountCreateSuriV2, ResponseAccountNameValidate, ResponseBatchJsonGetAccountInfo, ResponseCheckPublicAndSecretKey, ResponseDeriveValidateV2, ResponseEarlyValidateYield, ResponseExportAccountProxyMnemonic, ResponseGetAllTonWalletContractVersion, ResponseGetDeriveAccounts, ResponseGetDeriveSuggestion, ResponseGetYieldPoolTargets, ResponseInputAccountSubscribe, ResponseJsonGetAccountInfo, ResponseMetadataHash, ResponseMnemonicCreateV2, ResponseMnemonicValidateV2, ResponsePrivateKeyValidateV2, ResponseShortenMetadata, StorageDataInterface, SubmitYieldStepData, SwapPair, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapTxData, TokenSpendingApprovalParams, UnlockDotTransactionNft, UnstakingStatus, ValidateSwapProcessParams, ValidateYieldProcessParams, YieldPoolInfo, YieldPositionInfo } from '@subwallet/extension-base/types';
import { RequestSubmitTransfer, RequestSubscribeTransfer, ResponseSubscribeTransfer } from '@subwallet/extension-base/types/balance/transfer';
import { RequestClaimBridge } from '@subwallet/extension-base/types/bridge';
import { GetNotificationParams, RequestIsClaimedPolygonBridge, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types';
Expand Down Expand Up @@ -232,13 +233,13 @@
externalUrl?: string;
rarity?: string;
description?: string;
properties?: Record<any, any> | null;

Check warning on line 236 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type

Check warning on line 236 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

interface NftItemExtraInfo {
type?: _AssetType.ERC721 | _AssetType.PSP34 | RMRK_VER; // for sending
rmrk_ver?: RMRK_VER;
onChainOption?: any; // for sending PSP-34 tokens, should be done better

Check warning on line 242 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
assetHubType?: AssetHubNftType // for sending assetHub nft. There're 2 types nft
}

Expand Down Expand Up @@ -554,7 +555,7 @@
[ExtrinsicType.STAKING_COMPOUNDING]: RequestTuringStakeCompound,
[ExtrinsicType.STAKING_CANCEL_COMPOUNDING]: RequestTuringCancelStakeCompound,
[ExtrinsicType.STAKING_CANCEL_UNSTAKE]: RequestStakeCancelWithdrawal,
[ExtrinsicType.STAKING_POOL_WITHDRAW]: any,

Check warning on line 558 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type

// Yield
[ExtrinsicType.JOIN_YIELD_POOL]: RequestYieldStepSubmit,
Expand Down Expand Up @@ -585,9 +586,9 @@
[ExtrinsicType.CLAIM_BRIDGE]: RequestClaimBridge

[ExtrinsicType.EVM_EXECUTE]: TransactionConfig,
[ExtrinsicType.CROWDLOAN]: any,

Check warning on line 589 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
[ExtrinsicType.SWAP]: SwapTxData
[ExtrinsicType.UNKNOWN]: any

Check warning on line 591 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

export enum ExtrinsicStatus {
Expand Down Expand Up @@ -686,7 +687,7 @@
// : T extends ExtrinsicType.MINT_VDOT
// ? Pick<SubmitBifrostLiquidStaking, 'rewardTokenSlug' | 'estimatedAmountReceived'>
// : undefined;
export interface TransactionHistoryItem<ET extends ExtrinsicType = ExtrinsicType.TRANSFER_BALANCE> {

Check warning on line 690 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

'ET' is defined but never used
origin?: 'app' | 'migration' | 'subsquid' | 'subscan', // 'app' or history source
callhash?: string,
signature?: string,
Expand All @@ -711,7 +712,7 @@
tip?: AmountData,
fee?: AmountData,
explorerUrl?: string,
additionalInfo?: any,

Check warning on line 715 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
startBlock?: number,
nonce?: number,
addressPrefix?: number
Expand Down Expand Up @@ -943,12 +944,12 @@
recipientAddress: string,

nftItemName?: string, // Use for confirmation view only
params: Record<string, any>,

Check warning on line 947 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
nftItem: NftItem
}

export interface EvmNftTransaction extends ValidateTransactionResponse {
tx: Record<string, any> | null;

Check warning on line 952 in packages/extension-base/src/background/KoniTypes.ts

View workflow job for this annotation

GitHub Actions / Build Development Preview

Unexpected any. Specify a different type
}

export interface ValidateNetworkResponse {
Expand Down Expand Up @@ -2151,13 +2152,14 @@
'pri(transaction.history.getSubscription)': [null, TransactionHistoryItem[], TransactionHistoryItem[]];
'pri(transaction.history.subscribe)': [RequestSubscribeHistory, ResponseSubscribeHistory, TransactionHistoryItem[]];
'pri(transfer.getMaxTransferable)': [RequestMaxTransferable, AmountData];
'pri(transfer.subscribe)': [RequestSubscribeTransfer, ResponseSubscribeTransfer, ResponseSubscribeTransfer];
'pri(subscription.cancel)': [string, boolean];
'pri(freeBalance.get)': [RequestFreeBalance, AmountData];
'pri(freeBalance.subscribe)': [RequestFreeBalance, AmountDataWithId, AmountDataWithId];

// Transfer
'pri(accounts.checkTransfer)': [RequestCheckTransfer, ValidateTransactionResponse];
'pri(accounts.transfer)': [RequestTransfer, SWTransactionResponse];
'pri(accounts.transfer)': [RequestSubmitTransfer, SWTransactionResponse];
'pri(accounts.getOptimalTransferProcess)': [RequestOptimalTransferProcess, CommonOptimalPath];
'pri(accounts.approveSpending)': [TokenSpendingApprovalParams, SWTransactionResponse];

Expand Down
33 changes: 19 additions & 14 deletions packages/extension-base/src/core/logic-validation/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { EvmProviderError } from '@subwallet/extension-base/background/errors/Ev
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
import { ConfirmationType, ErrorValidation, EvmProviderErrorType, EvmSendTransactionParams, EvmSignatureRequest, EvmTransactionData } from '@subwallet/extension-base/background/KoniTypes';
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils';
import { AuthUrlInfo } from '@subwallet/extension-base/services/request-service/types';
import { BasicTxErrorType } from '@subwallet/extension-base/types';
import { BN_ZERO, createPromiseHandler, isSameAddress, stripUrl, wait } from '@subwallet/extension-base/utils';
import { BasicTxErrorType, EvmFeeInfo } from '@subwallet/extension-base/types';
import { BN_ZERO, combineEthFee, createPromiseHandler, isSameAddress, stripUrl, wait } from '@subwallet/extension-base/utils';
import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
import { getId } from '@subwallet/extension-base/utils/getId';
import { isSubstrateAddress } from '@subwallet/keyring';
import { KeyringPair } from '@subwallet/keyring/types';
import { keyring } from '@subwallet/ui-keyring';
Expand Down Expand Up @@ -434,18 +434,23 @@ export async function validationEvmDataTransactionMiddleware (koni: KoniState, u
estimateGas = new BigN(transactionParams.gasPrice).multipliedBy(transaction.gas).toFixed(0);
} else {
try {
const priority = await calculateGasFeeParams(evmApi, networkKey || '');

if (priority.baseGasFee) {
transaction.maxPriorityFeePerGas = priority.maxPriorityFeePerGas.toString();
transaction.maxFeePerGas = priority.maxFeePerGas.toString();

const maxFee = priority.maxFeePerGas;

estimateGas = maxFee.multipliedBy(transaction.gas).toFixed(0);
const gasLimit = transaction.gas || await evmApi.api.eth.estimateGas(transaction);
const id = getId();
const feeInfo = await koni.feeService.subscribeChainFee(id, transaction.chain || '', 'evm') as EvmFeeInfo;
const feeCombine = combineEthFee(feeInfo);

if (transaction.maxFeePerGas) {
estimateGas = new BigN(transaction.maxFeePerGas.toString()).multipliedBy(gasLimit).toFixed(0);
} else if (transaction.gasPrice) {
estimateGas = new BigN(transaction.gasPrice.toString()).multipliedBy(gasLimit).toFixed(0);
} else {
transaction.gasPrice = priority.gasPrice;
estimateGas = new BigN(priority.gasPrice).multipliedBy(transaction.gas).toFixed(0);
if (feeCombine.maxFeePerGas) {
const maxFee = new BigN(feeCombine.maxFeePerGas); // TODO: Need review

estimateGas = maxFee.multipliedBy(gasLimit).toFixed(0);
} else if (feeCombine.gasPrice) {
estimateGas = new BigN((feeCombine.gasPrice || 0)).multipliedBy(gasLimit).toFixed(0);
}
}
} catch (e) {
handleError((e as Error).message);
Expand Down
21 changes: 10 additions & 11 deletions packages/extension-base/src/core/logic-validation/transfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ import { isBounceableAddress } from '@subwallet/extension-base/services/balance-
import { _TRANSFER_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
import { _EvmApi, _TonApi } from '@subwallet/extension-base/services/chain-service/types';
import { _getAssetDecimals, _getChainExistentialDeposit, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getTokenMinAmount, _isNativeToken, _isTokenEvmSmartContract, _isTokenTonSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
import { calculateGasFeeParams } from '@subwallet/extension-base/services/fee-service/utils';
import { isSubstrateTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
import { OptionalSWTransaction, SWTransactionInput, SWTransactionResponse } from '@subwallet/extension-base/services/transaction-service/types';
import { AccountSignMode, BasicTxErrorType, BasicTxWarningCode, TransferTxErrorType } from '@subwallet/extension-base/types';
import { balanceFormatter, formatNumber, pairToAccount } from '@subwallet/extension-base/utils';
import { AccountSignMode, BasicTxErrorType, BasicTxWarningCode, EvmEIP1559FeeOption, EvmFeeInfo, TransferTxErrorType } from '@subwallet/extension-base/types';
import { balanceFormatter, combineEthFee, formatNumber, pairToAccount } from '@subwallet/extension-base/utils';
import { isTonAddress } from '@subwallet/keyring';
import { KeyringPair } from '@subwallet/keyring/types';
import { keyring } from '@subwallet/ui-keyring';
Expand Down Expand Up @@ -370,7 +369,7 @@ export function checkSupportForTransaction (validationResponse: SWTransactionRes
}
}

export async function estimateFeeForTransaction (validationResponse: SWTransactionResponse, transaction: OptionalSWTransaction, chainInfo: _ChainInfo, evmApi: _EvmApi): Promise<FeeData> {
export async function estimateFeeForTransaction (validationResponse: SWTransactionResponse, transaction: OptionalSWTransaction, chainInfo: _ChainInfo, evmApi: _EvmApi, feeInfo: EvmFeeInfo): Promise<FeeData> {
const estimateFee: FeeData = {
symbol: '',
decimals: 0,
Expand All @@ -391,23 +390,23 @@ export async function estimateFeeForTransaction (validationResponse: SWTransacti
} else {
const gasLimit = transaction.gas || await evmApi.api.eth.estimateGas(transaction);

const priority = await calculateGasFeeParams(evmApi, chainInfo.slug);
const feeCombine = combineEthFee(feeInfo, validationResponse.feeOption, validationResponse.feeCustom as EvmEIP1559FeeOption);

if (transaction.maxFeePerGas) {
estimateFee.value = new BigN(transaction.maxFeePerGas.toString()).multipliedBy(gasLimit).toFixed(0);
} else if (transaction.gasPrice) {
estimateFee.value = new BigN((transaction.gasPrice || 0).toString()).multipliedBy(gasLimit).toFixed(0);
estimateFee.value = new BigN(transaction.gasPrice.toString()).multipliedBy(gasLimit).toFixed(0);
} else {
if (priority.baseGasFee) {
const maxFee = priority.maxFeePerGas; // TODO: Need review
if (feeCombine.maxFeePerGas) {
const maxFee = new BigN(feeCombine.maxFeePerGas); // TODO: Need review

estimateFee.value = maxFee.multipliedBy(gasLimit).toFixed(0);
} else {
estimateFee.value = new BigN(priority.gasPrice).multipliedBy(gasLimit).toFixed(0);
} else if (feeCombine.gasPrice) {
estimateFee.value = new BigN((feeCombine.gasPrice || 0)).multipliedBy(gasLimit).toFixed(0);
}
}

estimateFee.tooHigh = priority.busyNetwork;
estimateFee.tooHigh = feeInfo.busyNetwork;
}
} catch (e) {
const error = e as Error;
Expand Down
Loading
Loading