diff --git a/apps/extension/src/pages/main/token-detail/modal.tsx b/apps/extension/src/pages/main/token-detail/modal.tsx
index d92859d0df..db4b738505 100644
--- a/apps/extension/src/pages/main/token-detail/modal.tsx
+++ b/apps/extension/src/pages/main/token-detail/modal.tsx
@@ -673,30 +673,32 @@ export const TokenDetailModal: FunctionComponent<{
if (msgHistory.pages[0].response?.isUnsupported || !isSupported) {
// TODO: 아직 cosmos 체인이 아니면 embedded인지 아닌지 구분할 수 없다.
- if ("cosmos" in modularChainInfo) {
- const chainInfo = chainStore.getChain(chainId);
- if (chainInfo.embedded.embedded) {
- return (
-
-
-
-
- Unsupported Chain
-
-
- {`We're actively working on expanding our support for
+ if (
+ ("cosmos" in modularChainInfo &&
+ chainStore.getChain(chainId).embedded.embedded) ||
+ "starknet" in modularChainInfo
+ ) {
+ return (
+
+
+
+
+ Unsupported Chain
+
+
+ {`We're actively working on expanding our support for
native chains.`}
-
-
-
-
- );
- }
+
+
+
+
+ );
}
+
return (
diff --git a/apps/extension/src/pages/starknet/components/account-activation-modal/index.tsx b/apps/extension/src/pages/starknet/components/account-activation-modal/index.tsx
index c9cd4efe54..5e8996b673 100644
--- a/apps/extension/src/pages/starknet/components/account-activation-modal/index.tsx
+++ b/apps/extension/src/pages/starknet/components/account-activation-modal/index.tsx
@@ -61,6 +61,7 @@ export const AccountActivationModal: FunctionComponent<{
const intl = useIntl();
const account = accountStore.getAccount(chainId);
+ const starknetQueries = starknetQueriesStore.get(chainId);
const sender = account.starknetHexAddress;
const senderConfig = useSenderConfig(
@@ -102,6 +103,22 @@ export const AccountActivationModal: FunctionComponent<{
return () => clearInterval(interval);
}, [gasSimulationRefresher]);
+ useEffect(() => {
+ starknetQueries.queryAccountNonce
+ .getNonce(account.starknetHexAddress)
+ .fetch();
+ if (feeConfig.fee != null) {
+ starknetQueries.queryStarknetERC20Balance
+ .getBalance(
+ chainId,
+ chainStore,
+ account.starknetHexAddress,
+ feeConfig.fee.currency.coinMinimalDenom
+ )
+ ?.fetch();
+ }
+ }, []);
+
const gasSimulatorKey = feeConfig.type;
const gasSimulator = useGasSimulator(
new ExtensionKVStore("gas-simulator.starknet.account-activation"),
@@ -283,39 +300,38 @@ export const AccountActivationModal: FunctionComponent<{
throw new Error("Can't find fee currency");
}
+ starknetAccount.setIsDeployingAccount(true);
const { transaction_hash: txHash } =
- await starknetAccountStore
- .getAccount(senderConfig.chainId)
- .deployAccountWithFee(
- accountStore.getAccount(senderConfig.chainId)
- .starknetHexAddress,
- "0x" + Buffer.from(params.classHash).toString("hex"),
- [
- "0x" + Buffer.from(params.xLow).toString("hex"),
- "0x" + Buffer.from(params.xHigh).toString("hex"),
- "0x" + Buffer.from(params.yLow).toString("hex"),
- "0x" + Buffer.from(params.yHigh).toString("hex"),
- ],
- "0x" + Buffer.from(params.salt).toString("hex"),
- (() => {
- if (type === "ETH") {
- return {
- type: "ETH",
- maxFee: feeConfig.maxFee.toCoin().amount,
- };
- } else if (type === "STRK") {
- return {
- type: "STRK",
- gas: gasConfig.gas.toString(),
- maxGasPrice: num.toHex(
- feeConfig.maxGasPrice.toCoin().amount
- ),
- };
- } else {
- throw new Error("Invalid fee type");
- }
- })()
- );
+ await starknetAccount.deployAccountWithFee(
+ accountStore.getAccount(senderConfig.chainId)
+ .starknetHexAddress,
+ "0x" + Buffer.from(params.classHash).toString("hex"),
+ [
+ "0x" + Buffer.from(params.xLow).toString("hex"),
+ "0x" + Buffer.from(params.xHigh).toString("hex"),
+ "0x" + Buffer.from(params.yLow).toString("hex"),
+ "0x" + Buffer.from(params.yHigh).toString("hex"),
+ ],
+ "0x" + Buffer.from(params.salt).toString("hex"),
+ (() => {
+ if (type === "ETH") {
+ return {
+ type: "ETH",
+ maxFee: feeConfig.maxFee.toCoin().amount,
+ };
+ } else if (type === "STRK") {
+ return {
+ type: "STRK",
+ gas: gasConfig.gas.toString(),
+ maxGasPrice: num.toHex(
+ feeConfig.maxGasPrice.toCoin().amount
+ ),
+ };
+ } else {
+ throw new Error("Invalid fee type");
+ }
+ })()
+ );
new InExtensionMessageRequester()
.sendMessage(
@@ -330,7 +346,6 @@ export const AccountActivationModal: FunctionComponent<{
}),
""
);
-
const starknetQueries =
starknetQueriesStore.get(chainId);
@@ -343,6 +358,19 @@ export const AccountActivationModal: FunctionComponent<{
.getNonce(account.starknetHexAddress)
.waitFreshResponse();
if (res?.data) {
+ starknetAccount.setIsDeployingAccount(false);
+
+ if (feeConfig.fee != null) {
+ starknetQueries.queryStarknetERC20Balance
+ .getBalance(
+ chainId,
+ chainStore,
+ account.starknetHexAddress,
+ feeConfig.fee.currency.coinMinimalDenom
+ )
+ ?.fetch();
+ }
+ close();
break;
}
@@ -351,26 +379,15 @@ export const AccountActivationModal: FunctionComponent<{
await sleep(2000);
}
})();
-
- if (feeConfig.fee != null) {
- starknetQueries.queryStarknetERC20Balance
- .getBalance(
- chainId,
- chainStore,
- account.starknetHexAddress,
- feeConfig.fee.currency.coinMinimalDenom
- )
- ?.fetch();
- }
-
- close();
})
.catch((e) => {
- // 이 경우에는 tx가 커밋된 이후의 오류이기 때문에 이미 페이지는 sign 페이지에서부터 전환된 상태다.
- // 따로 멀 처리해줄 필요가 없다
+ starknetAccount.setIsDeployingAccount(false);
+ close();
console.log(e);
});
} catch (e) {
+ starknetAccount.setIsDeployingAccount(false);
+ goBack();
console.log(e);
}
}
diff --git a/apps/extension/src/pages/starknet/components/input/fee-control/index.tsx b/apps/extension/src/pages/starknet/components/input/fee-control/index.tsx
index 6cc28c8350..eb384469de 100644
--- a/apps/extension/src/pages/starknet/components/input/fee-control/index.tsx
+++ b/apps/extension/src/pages/starknet/components/input/fee-control/index.tsx
@@ -1,4 +1,4 @@
-import React, { FunctionComponent, useState } from "react";
+import React, { FunctionComponent, useLayoutEffect, useState } from "react";
import { observer } from "mobx-react-lite";
import {
IFeeConfig,
@@ -23,8 +23,11 @@ import { VerticalResizeTransition } from "../../../../../components/transition";
import { FormattedMessage, useIntl } from "react-intl";
import { XAxis, YAxis } from "../../../../../components/axis";
import { UIConfigStore } from "../../../../../stores/ui-config";
-import { IChainStore, IQueriesStore } from "@keplr-wallet/stores";
+import { IChainStore } from "@keplr-wallet/stores";
import { Tooltip } from "../../../../../components/tooltip";
+import { autorun } from "mobx";
+import { StarknetQueriesStore } from "@keplr-wallet/stores-starknet";
+import { Dec } from "@keplr-wallet/unit";
// 기본적으로 `FeeControl` 안에 있는 로직이였지만 `FeeControl` 말고도 다른 UI를 가진 똑같은 기능의 component가
// 여러개 생기게 되면서 공통적으로 사용하기 위해서 custom hook으로 분리함
@@ -66,112 +69,84 @@ export const useFeeOptionSelectionOnInit = (
};
export const useAutoFeeCurrencySelectionOnInit = (
- _chainStore: IChainStore,
- _queriesStore: IQueriesStore,
- _senderConfig: ISenderConfig,
- _feeConfig: IFeeConfig,
- _disableAutomaticFeeSet: boolean | undefined
+ chainStore: IChainStore,
+ starknetQueriesStore: StarknetQueriesStore,
+ senderConfig: ISenderConfig,
+ feeConfig: IFeeConfig,
+ disableAutomaticFeeSet: boolean | undefined
) => {
- // TODO
- // useLayoutEffect(() => {
- // if (disableAutomaticFeeSet) {
- // return;
- // }
- //
- // // Require to invoke effect whenever chain is changed,
- // // even though it is not used in logic.
- // noop(feeConfig.chainId);
- //
- // // Try to find other fee currency if the account doesn't have enough fee to pay.
- // // This logic can be slightly complex, so use mobx's `autorun`.
- // // This part fairly different with the approach of react's hook.
- // let skip = false;
- // // Try until 500ms to avoid the confusion to user.
- // const timeoutId = setTimeout(() => {
- // skip = true;
- // }, 2000);
- //
- // const disposer = autorun(() => {
- // if (
- // !skip &&
- // feeConfig.type !== "manual" &&
- // feeConfig.selectableFeeCurrencies.length > 1 &&
- // feeConfig.fees.length > 0
- // ) {
- // const queryBalances =
- // chainStore.getChain(feeConfig.chainId).evm != null &&
- // EthereumAccountBase.isEthereumHexAddressWithChecksum(
- // senderConfig.sender
- // )
- // ? queriesStore
- // .get(feeConfig.chainId)
- // .queryBalances.getQueryEthereumHexAddress(senderConfig.sender)
- // : queriesStore
- // .get(feeConfig.chainId)
- // .queryBalances.getQueryBech32Address(senderConfig.sender);
- //
- // const currentFeeCurrency = feeConfig.fees[0].currency;
- // const currentFeeCurrencyBal =
- // queryBalances.getBalanceFromCurrency(currentFeeCurrency);
- //
- // const currentFee = feeConfig.getFeeTypePrettyForFeeCurrency(
- // currentFeeCurrency,
- // feeConfig.type
- // );
- // if (currentFeeCurrencyBal.toDec().lt(currentFee.toDec())) {
- // const isOsmosis =
- // chainStore.hasChain(feeConfig.chainId) &&
- // chainStore.getChain(feeConfig.chainId).hasFeature("osmosis-txfees");
- //
- // // Not enough balances for fee.
- // // Try to find other fee currency to send.
- // for (const feeCurrency of feeConfig.selectableFeeCurrencies) {
- // const feeCurrencyBal =
- // queryBalances.getBalanceFromCurrency(feeCurrency);
- // const fee = feeConfig.getFeeTypePrettyForFeeCurrency(
- // feeCurrency,
- // feeConfig.type
- // );
- //
- // // Osmosis의 경우는 fee의 spot price를 알아야 fee를 계산할 수 있다.
- // // 그런데 문제는 이게 쿼리가 필요하기 때문에 비동기적이라 response를 기다려야한다.
- // // 어쨋든 스왑에 의해서만 fee 계산이 이루어지기 때문에 fee로 Osmo가 0이였다면 이 로직까지 왔을리가 없고
- // // 어떤 갯수의 Osmo던지 스왑 이후에 fee가 0이 될수는 없기 때문에
- // // 0라면 단순히 response 준비가 안된것이라 확신할 수 있다.
- // if (isOsmosis && fee.toDec().lte(new Dec(0))) {
- // continue;
- // }
- //
- // if (feeCurrencyBal.toDec().gte(fee.toDec())) {
- // feeConfig.setFee({
- // type: feeConfig.type,
- // currency: feeCurrency,
- // });
- // const uiProperties = feeConfig.uiProperties;
- // skip =
- // !uiProperties.loadingState &&
- // uiProperties.error == null &&
- // uiProperties.warning == null;
- // return;
- // }
- // }
- // }
- // }
- // });
- //
- // return () => {
- // clearTimeout(timeoutId);
- // skip = true;
- // disposer();
- // };
- // }, [
- // chainStore,
- // disableAutomaticFeeSet,
- // feeConfig,
- // feeConfig.chainId,
- // queriesStore,
- // senderConfig.sender,
- // ]);
+ useLayoutEffect(() => {
+ if (disableAutomaticFeeSet) {
+ return;
+ }
+
+ // Require to invoke effect whenever chain is changed,
+ // even though it is not used in logic.
+ noop(feeConfig.chainId);
+
+ // Try to find other fee currency if the account doesn't have enough fee to pay.
+ // This logic can be slightly complex, so use mobx's `autorun`.
+ // This part fairly different with the approach of react's hook.
+ let skip = false;
+ // Try until 500ms to avoid the confusion to user.
+ const timeoutId = setTimeout(() => {
+ skip = true;
+ }, 2000);
+
+ const disposer = autorun(() => {
+ const modularChainInfo = chainStore.getModularChain(feeConfig.chainId);
+ if (!skip && "starknet" in modularChainInfo) {
+ const queryBalances = starknetQueriesStore.get(
+ feeConfig.chainId
+ ).queryStarknetERC20Balance;
+
+ const ethCoinMinmalDenom = `erc20:${modularChainInfo.starknet.ethContractAddress}`;
+ const strkCoinMinmalDenom = `erc20:${modularChainInfo.starknet.strkContractAddress}`;
+ for (const coinMinimalDenom of [
+ ethCoinMinmalDenom,
+ strkCoinMinmalDenom,
+ ]) {
+ const feeCurrencyBal = queryBalances.getBalance(
+ feeConfig.chainId,
+ chainStore,
+ senderConfig.sender,
+ coinMinimalDenom
+ )?.balance;
+
+ if (!feeCurrencyBal) {
+ return;
+ }
+
+ if (feeCurrencyBal.toDec().gt(new Dec(0))) {
+ feeConfig.setType(
+ feeCurrencyBal.currency.coinDenom as "ETH" | "STRK"
+ );
+ const uiProperties = feeConfig.uiProperties;
+ skip =
+ !uiProperties.loadingState &&
+ uiProperties.error == null &&
+ uiProperties.warning == null;
+ return;
+ }
+
+ continue;
+ }
+ }
+ });
+
+ return () => {
+ clearTimeout(timeoutId);
+ skip = true;
+ disposer();
+ };
+ }, [
+ chainStore,
+ disableAutomaticFeeSet,
+ feeConfig,
+ feeConfig.chainId,
+ senderConfig.sender,
+ starknetQueriesStore,
+ ]);
};
export const FeeControl: FunctionComponent<{
@@ -193,7 +168,7 @@ export const FeeControl: FunctionComponent<{
}) => {
const {
analyticsStore,
- queriesStore,
+ starknetQueriesStore,
priceStore,
chainStore,
uiConfigStore,
@@ -210,7 +185,7 @@ export const FeeControl: FunctionComponent<{
useAutoFeeCurrencySelectionOnInit(
chainStore,
- queriesStore,
+ starknetQueriesStore,
senderConfig,
feeConfig,
disableAutomaticFeeSet
@@ -515,3 +490,7 @@ export const FeeControl: FunctionComponent<{
);
}
);
+
+const noop = (..._args: any[]) => {
+ // noop
+};
diff --git a/apps/extension/src/pages/starknet/send/index.tsx b/apps/extension/src/pages/starknet/send/index.tsx
index 12b2207cc1..054b0f96a5 100644
--- a/apps/extension/src/pages/starknet/send/index.tsx
+++ b/apps/extension/src/pages/starknet/send/index.tsx
@@ -142,16 +142,15 @@ export const StarknetSendPage: FunctionComponent = observer(() => {
const account = accountStore.getAccount(chainId);
const starknetAccount = starknetAccountStore.getAccount(chainId);
+ const starknetQueries = starknetQueriesStore.get(chainId);
const sender = account.starknetHexAddress;
- const balance = starknetQueriesStore
- .get(chainId)
- .queryStarknetERC20Balance.getBalance(
- chainId,
- chainStore,
- sender,
- currency.coinMinimalDenom
- );
+ const balance = starknetQueries.queryStarknetERC20Balance.getBalance(
+ chainId,
+ chainStore,
+ sender,
+ currency.coinMinimalDenom
+ );
const sendConfigs = useSendTxConfig(
chainStore,
@@ -313,9 +312,7 @@ export const StarknetSendPage: FunctionComponent = observer(() => {
const [isAccountActivationModalOpen, setIsAccountActivationModalOpen] =
useState(false);
useEffect(() => {
- if (isAccountNotDeployed) {
- setIsAccountActivationModalOpen(true);
- }
+ setIsAccountActivationModalOpen(isAccountNotDeployed);
}, [isAccountNotDeployed]);
return (
@@ -433,6 +430,28 @@ export const StarknetSendPage: FunctionComponent = observer(() => {
new SubmitStarknetTxHashMsg(chainId, txHash)
)
.then(() => {
+ starknetQueries.queryStarknetERC20Balance
+ .getBalance(
+ chainId,
+ chainStore,
+ account.starknetHexAddress,
+ sendConfigs.amountConfig.amount[0].currency.coinMinimalDenom
+ )
+ ?.fetch();
+ if (
+ sendConfigs.feeConfig.fee &&
+ sendConfigs.feeConfig.fee.currency.coinMinimalDenom !==
+ sendConfigs.amountConfig.amount[0].currency.coinMinimalDenom
+ ) {
+ starknetQueries.queryStarknetERC20Balance
+ .getBalance(
+ chainId,
+ chainStore,
+ account.starknetHexAddress,
+ sendConfigs.feeConfig.fee.currency.coinMinimalDenom
+ )
+ ?.fetch();
+ }
notification.show(
"success",
intl.formatMessage({
diff --git a/packages/stores-starknet/src/account/base.ts b/packages/stores-starknet/src/account/base.ts
index ee4c4c59cd..ae185042af 100644
--- a/packages/stores-starknet/src/account/base.ts
+++ b/packages/stores-starknet/src/account/base.ts
@@ -29,6 +29,11 @@ export class StarknetAccountBase {
return this._isSendingTx;
}
+ @action
+ setIsDeployingAccount(value: boolean) {
+ this._isDeployingAccount = value;
+ }
+
get isDeployingAccount(): boolean {
return this._isDeployingAccount;
}
@@ -91,7 +96,6 @@ export class StarknetAccountBase {
);
try {
- this._isDeployingAccount = true;
const res = await walletAccount.deployAccount(
{
classHash,
@@ -103,10 +107,8 @@ export class StarknetAccountBase {
}
);
- this._isDeployingAccount = false;
onFulfilled?.(res);
} catch (e) {
- this._isDeployingAccount = false;
onBroadcastFailed?.(e);
}
}
@@ -140,7 +142,6 @@ export class StarknetAccountBase {
);
try {
- this._isDeployingAccount = true;
const res = await walletAccount.deployAccountWithFee(
{
classHash,
@@ -150,22 +151,8 @@ export class StarknetAccountBase {
fee
);
- walletAccount
- .waitForTransaction(res.transaction_hash, {
- retryInterval: 1000,
- })
- .catch((e) => {
- // 오류 처리는 무시한다.
- console.log(e);
- })
- .finally(() => {
- this._isDeployingAccount = false;
- });
-
return res;
} catch (e) {
- this._isDeployingAccount = false;
-
throw e;
}
}