diff --git a/apps/extension/src/pages/send/amount/index.tsx b/apps/extension/src/pages/send/amount/index.tsx index 520878ba6e..2d23dceb17 100644 --- a/apps/extension/src/pages/send/amount/index.tsx +++ b/apps/extension/src/pages/send/amount/index.tsx @@ -269,7 +269,7 @@ export const SendAmountPage: FunctionComponent = observer(() => { const isERC20 = sendingDenomHelper.type === "erc20"; const isSendingNativeToken = sendingDenomHelper.type === "native" && - (chainInfo.stakeCurrency?.coinMinimalDenom ?? + (chainInfo.evm?.nativeCurrency?.coinMinimalDenom ?? chainInfo.currencies[0].coinMinimalDenom) === sendingDenomHelper.denom; const newIsEvmTx = @@ -281,7 +281,28 @@ export const SendAmountPage: FunctionComponent = observer(() => { ? account.ethereumHexAddress : account.bech32Address; + if (sendConfigs.feeConfig.type !== "manual") { + if (newIsEvmTx && chainInfo.evm?.nativeCurrency != null) { + sendConfigs.feeConfig.setSelectableFeeCurrencies([ + chainInfo.evm.nativeCurrency, + ]); + sendConfigs.feeConfig.setFee({ + type: sendConfigs.feeConfig.type, + currency: chainInfo.evm.nativeCurrency, + }); + } else { + sendConfigs.feeConfig.setSelectableFeeCurrencies( + chainInfo.feeCurrencies.slice(0, 1) + ); + sendConfigs.feeConfig.setFee({ + type: sendConfigs.feeConfig.type, + currency: sendConfigs.feeConfig.selectableFeeCurrencies[0], + }); + } + } + sendConfigs.senderConfig.setValue(newSenderAddress); + setIsEvmTx(newIsEvmTx); ethereumAccount.setIsSendingTx(false); } @@ -293,8 +314,10 @@ export const SendAmountPage: FunctionComponent = observer(() => { sendConfigs.amountConfig.currency.coinMinimalDenom, sendConfigs.recipientConfig.isRecipientEthereumHexAddress, sendConfigs.senderConfig, - chainInfo.stakeCurrency?.coinMinimalDenom, chainInfo.currencies, + sendConfigs.feeConfig, + chainInfo.evm?.nativeCurrency, + chainInfo.feeCurrencies, ]); useEffect(() => { diff --git a/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx b/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx index f4706fd41a..857df597df 100644 --- a/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx +++ b/apps/extension/src/pages/sign/components/eth-tx/render/send-token.tsx @@ -142,7 +142,7 @@ export const EthSendTokenTxPretty: React.FunctionComponent<{ const currency = erc20ContractAddress ? chainInfo.forceFindCurrency(`erc20:${erc20ContractAddress}`) - : chainInfo.currencies[0]; + : chainInfo.evm?.nativeCurrency ?? chainInfo.currencies[0]; const amountCoinPretty = new CoinPretty(currency, new Dec(Number(amount))); const theme = useTheme(); diff --git a/apps/extension/src/pages/sign/ethereum/view.tsx b/apps/extension/src/pages/sign/ethereum/view.tsx index ef9002a555..3b11c732eb 100644 --- a/apps/extension/src/pages/sign/ethereum/view.tsx +++ b/apps/extension/src/pages/sign/ethereum/view.tsx @@ -181,7 +181,7 @@ export const EthereumSigningView: FunctionComponent<{ if (gasPriceFromTx > 0) { feeConfig.setFee( new CoinPretty( - chainInfo.currencies[0], + chainInfo.evm?.nativeCurrency ?? chainInfo.currencies[0], new Dec(gasConfig.gas).mul(new Dec(gasPriceFromTx)) ) ); diff --git a/packages/chain-validator/src/schema.ts b/packages/chain-validator/src/schema.ts index 81087b5b26..40f5f3bd96 100644 --- a/packages/chain-validator/src/schema.ts +++ b/packages/chain-validator/src/schema.ts @@ -194,6 +194,7 @@ export const ChainInfoSchema = Joi.object({ evm: Joi.object({ chainId: Joi.number().required(), rpc: Joi.string() + .uri() .custom((value: string) => { if (value.includes("?")) { throw new Error("evm rpc should not have query string"); @@ -202,6 +203,16 @@ export const ChainInfoSchema = Joi.object({ return value; }) .required(), + websocket: Joi.string() + .uri() + .custom((value: string) => { + if (value.includes("?")) { + throw new Error("evm websocket should not have query string"); + } + + return value; + }), + nativeCurrency: CurrencySchema, }).unknown(true), nodeProvider: Joi.object({ name: Joi.string().min(1).max(30).required(), @@ -354,39 +365,51 @@ export const ChainInfoSchema = Joi.object({ } } - // evm only chain이 아닌 ethermint같은 경우에만 위의 밸리데이션을 수행한다. + // evm only chain이 아닌 ethermint같은 경우에만 아래의 밸리데이션을 수행한다. if (EIP155ChainIdSchema.validate(value.chainId).error) { if (value.evm) { + const evmNativeCurency = value.evm.nativeCurrency; const firstCurrency = value.currencies[0]; - if (firstCurrency.coinDecimals !== 18) { + if ( + evmNativeCurency != null && + firstCurrency.coinMinimalDenom === evmNativeCurency.coinMinimalDenom + ) { throw new Error( - "The first currency's coin decimals should be 18 for EVM chain" + "The first currency should not be same with EVM native currency" ); } - if (value.stakeCurrency) { - if (value.stakeCurrency.coinDecimals !== 18) { + + if (evmNativeCurency == null) { + if (firstCurrency.coinDecimals !== 18) { throw new Error( - "The stake currency's coin decimals should be 18 for EVM chain" + "The first currency's coin decimals should be 18 for EVM chain" ); } - const cur = value.currencies.find( - (cur) => - cur.coinMinimalDenom === value.stakeCurrency?.coinMinimalDenom - ); - if (cur) { - if (cur.coinDecimals !== 18) { + if (value.stakeCurrency) { + if (value.stakeCurrency.coinDecimals !== 18) { throw new Error( "The stake currency's coin decimals should be 18 for EVM chain" ); } + const cur = value.currencies.find( + (cur) => + cur.coinMinimalDenom === value.stakeCurrency?.coinMinimalDenom + ); + if (cur) { + if (cur.coinDecimals !== 18) { + throw new Error( + "The stake currency's coin decimals should be 18 for EVM chain" + ); + } + } } - } - const firstFeeCurrency = value.feeCurrencies[0]; - if (firstFeeCurrency.coinDecimals !== 18) { - throw new Error( - "The first fee currency's coin decimals should be 18 for EVM chain" - ); + const firstFeeCurrency = value.feeCurrencies[0]; + if (firstFeeCurrency.coinDecimals !== 18) { + throw new Error( + "The first fee currency's coin decimals should be 18 for EVM chain" + ); + } } } } diff --git a/packages/hooks/src/tx/fee.ts b/packages/hooks/src/tx/fee.ts index 9e2a47dfed..dba5914ecd 100644 --- a/packages/hooks/src/tx/fee.ts +++ b/packages/hooks/src/tx/fee.ts @@ -28,6 +28,8 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig { | CoinPretty[] | undefined = undefined; + @observable.ref + protected _selectableFeeCurrencies: FeeCurrency[] | undefined = undefined; /** * `additionAmountToNeedFee` indicated that the fee config should consider the amount config's amount * when checking that the fee is sufficient to send tx. @@ -172,8 +174,20 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig { } } + @action + setSelectableFeeCurrencies(currencies: FeeCurrency[]) { + this._selectableFeeCurrencies = currencies; + } + @computed get selectableFeeCurrencies(): FeeCurrency[] { + if ( + this._selectableFeeCurrencies && + this._selectableFeeCurrencies.length > 0 + ) { + return this._selectableFeeCurrencies; + } + if ( this.chainInfo.bip44.coinType === 60 || this.chainInfo.hasFeature("eth-address-gen") || diff --git a/packages/stores-eth/src/queries/balance.ts b/packages/stores-eth/src/queries/balance.ts index 5ed9e7d9ce..bb8b0622ac 100644 --- a/packages/stores-eth/src/queries/balance.ts +++ b/packages/stores-eth/src/queries/balance.ts @@ -39,9 +39,10 @@ export class ObservableQueryEthAccountBalanceImpl get balance(): CoinPretty { const denom = this.denomHelper.denom; const chainInfo = this.chainGetter.getChain(this.chainId); - const currency = chainInfo.currencies.find( - (cur) => cur.coinMinimalDenom === denom - ); + const currency = + chainInfo?.evm?.nativeCurrency ?? + chainInfo.currencies.find((cur) => cur.coinMinimalDenom === denom); + if (!currency) { throw new Error(`Unknown currency: ${denom}`); } diff --git a/packages/stores/src/chain/base.ts b/packages/stores/src/chain/base.ts index c2fb142d22..80bb8a6d98 100644 --- a/packages/stores/src/chain/base.ts +++ b/packages/stores/src/chain/base.ts @@ -13,6 +13,7 @@ import { BIP44, ChainInfo, Currency, + EVMInfo, FeeCurrency, } from "@keplr-wallet/types"; import { IChainInfoImpl, IChainStore, CurrencyRegistrar } from "./types"; @@ -477,7 +478,7 @@ export class ChainInfoImpl return this._embedded.chainSymbolImageUrl; } - get evm(): { chainId: number; rpc: string } | undefined { + get evm(): EVMInfo | undefined { return this._embedded.evm; } diff --git a/packages/stores/src/chain/types.ts b/packages/stores/src/chain/types.ts index 8ed80304c9..b8c4d36430 100644 --- a/packages/stores/src/chain/types.ts +++ b/packages/stores/src/chain/types.ts @@ -4,6 +4,7 @@ import { BIP44, ChainInfo, Currency, + EVMInfo, FeeCurrency, } from "@keplr-wallet/types"; @@ -62,11 +63,6 @@ export interface IChainInfoImpl { readonly walletUrl: string | undefined; readonly walletUrlForStaking: string | undefined; readonly chainSymbolImageUrl: string | undefined; - readonly evm: - | { - chainId: number; - rpc: string; - } - | undefined; + readonly evm: EVMInfo | undefined; readonly hideInUI: boolean | undefined; } diff --git a/packages/types/src/ethereum.ts b/packages/types/src/ethereum.ts index 1574d7010f..d1f205c6dd 100644 --- a/packages/types/src/ethereum.ts +++ b/packages/types/src/ethereum.ts @@ -1,3 +1,5 @@ +import { AppCurrency } from "./currency"; + export enum EthSignType { MESSAGE = "message", TRANSACTION = "transaction", @@ -45,6 +47,7 @@ export interface EVMInfo { chainId: number; rpc: string; websocket?: string; + nativeCurrency?: AppCurrency; } export interface EthereumSignResponse {