diff --git a/apps/airdrop/package.json b/apps/airdrop/package.json index 3590bd6741..079ee5afcf 100644 --- a/apps/airdrop/package.json +++ b/apps/airdrop/package.json @@ -18,9 +18,9 @@ "lint:fix": "npx yarn lint -- --fix" }, "dependencies": { - "@namada/components": "0.1.0", - "@namada/hooks": "0.1.0", - "@namada/utils": "0.1.0", + "@namada/components": "0.2.1", + "@namada/hooks": "0.2.1", + "@namada/utils": "0.2.1", "buffer": "^6.0.3", "dompurify": "^3.0.2", "gsap": "^3.12.2", diff --git a/apps/extension/package.json b/apps/extension/package.json index ccaedfa72f..997a13b172 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -1,6 +1,6 @@ { "name": "@namada/extension", - "version": "0.2.0", + "version": "0.2.1", "description": "Namada Browser Extension", "repository": "https://github.com/anoma/namada-interface/", "author": "Heliax Dev ", @@ -36,13 +36,13 @@ "@ledgerhq/hw-transport": "^6.30.0", "@ledgerhq/hw-transport-webhid": "^6.28.0", "@ledgerhq/hw-transport-webusb": "^6.28.0", - "@namada/chains": "0.1.0", - "@namada/components": "0.1.0", - "@namada/crypto": "0.1.0", - "@namada/shared": "0.1.0", - "@namada/storage": "0.1.0", - "@namada/types": "0.1.0", - "@namada/utils": "0.1.0", + "@namada/chains": "0.2.1", + "@namada/components": "0.2.1", + "@namada/crypto": "0.2.1", + "@namada/shared": "0.2.1", + "@namada/storage": "0.2.1", + "@namada/types": "0.2.1", + "@namada/utils": "0.2.1", "@zondax/ledger-namada": "^0.0.3", "bignumber.js": "^9.1.1", "buffer": "^6.0.3", diff --git a/apps/extension/src/App/Accounts/AddAccount.tsx b/apps/extension/src/App/Accounts/AddAccount.tsx index 58c015098d..d89ca24664 100644 --- a/apps/extension/src/App/Accounts/AddAccount.tsx +++ b/apps/extension/src/App/Accounts/AddAccount.tsx @@ -1,7 +1,7 @@ import React, { useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { ActionButton, Input, Toggle } from "@namada/components"; import { AccountType, DerivedAccount } from "@namada/types"; import { makeBip44Path } from "@namada/utils"; @@ -147,7 +147,7 @@ const AddAccount: React.FC = ({ const bip44Prefix = "m/44"; const zip32Prefix = "m/32"; - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; const authorize = useAuth(requester); @@ -207,7 +207,7 @@ const AddAccount: React.FC = ({ index, }; const bip44PathString = makeBip44Path( - chains[defaultChainId].bip44.coinType, + chains.namada.bip44.coinType, bip44Path ); @@ -383,9 +383,8 @@ const AddAccount: React.FC = ({
Derivation path:{" "} - {`${parentDerivationPath}${ - isTransparent ? `${change}/` : "" - }${index}`} + {`${parentDerivationPath}${isTransparent ? `${change}/` : "" + }${index}`}
{validation}
diff --git a/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx b/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx index daa4c583dd..234781a8c7 100644 --- a/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx +++ b/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx @@ -2,7 +2,6 @@ import { toBase64 } from "@cosmjs/encoding"; import BigNumber from "bignumber.js"; import { useCallback, useEffect, useState } from "react"; -import { defaultChainId as chainId } from "@namada/chains"; import { ActionButton, Alert, Stack } from "@namada/components"; import { TxType, TxTypeLabel } from "@namada/shared"; import { Message, Tokens, TxMsgValue, TxProps } from "@namada/types"; @@ -19,6 +18,7 @@ import { SubmitSignedTxMsg, } from "background/ledger"; import { useRequester } from "hooks/useRequester"; +import { GetChainMsg } from "provider"; import { Ports } from "router"; import { closeCurrentTab } from "utils"; @@ -44,11 +44,16 @@ export const ConfirmLedgerTx: React.FC = ({ details }) => { "Public key not found! Review and approve reveal pk on your Ledger" ); + const chain = await requester.sendMessage( + Ports.Background, + new GetChainMsg() + ); + const txArgs: TxProps = { token: Tokens.NAM.address || "", feeAmount: new BigNumber(0), gasLimit: new BigNumber(20_000), - chainId, + chainId: chain.chainId, publicKey, }; diff --git a/apps/extension/src/background/chains/service.ts b/apps/extension/src/background/chains/service.ts index 36926136b2..5b6f7c1369 100644 --- a/apps/extension/src/background/chains/service.ts +++ b/apps/extension/src/background/chains/service.ts @@ -1,4 +1,4 @@ -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { KVStore } from "@namada/storage"; import { Chain } from "@namada/types"; import { ExtensionBroadcaster } from "extension"; @@ -9,13 +9,13 @@ export class ChainsService { constructor( protected readonly chainsStore: KVStore, protected readonly broadcaster: ExtensionBroadcaster - ) {} + ) { } - async getChain(): Promise { + async getChain(): Promise { const chain = await this.chainsStore.get(CHAINS_KEY); if (!chain) { // Initialize default chain in storage - const defaultChain = chains[defaultChainId]; + const defaultChain = chains.namada; await this.chainsStore.set(CHAINS_KEY, defaultChain); return defaultChain; } diff --git a/apps/extension/src/background/keyring/keyring.ts b/apps/extension/src/background/keyring/keyring.ts index 75672d2467..b0d0e84dc4 100644 --- a/apps/extension/src/background/keyring/keyring.ts +++ b/apps/extension/src/background/keyring/keyring.ts @@ -1,6 +1,6 @@ import { deserialize } from "@dao-xyz/borsh"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { HDWallet, Mnemonic, @@ -191,7 +191,7 @@ export class KeyRing { const phrase = accountSecret.seedPhrase.join(" "); const mnemonic = Mnemonic.from_phrase(phrase); const seed = mnemonic.to_seed(); - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; const bip44Path = makeBip44PathArray(coinType, path); const hdWallet = new HDWallet(seed); const key = hdWallet.derive(new Uint32Array(bip44Path)); @@ -262,7 +262,7 @@ export class KeyRing { path: Bip44Path, parentId: string ): DerivedAccountInfo { - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; const derivationPath = makeBip44PathArray(coinType, path); const hdWallet = new HDWallet(seed); const key = hdWallet.derive(new Uint32Array(derivationPath)); @@ -619,7 +619,7 @@ export class KeyRing { throw new Error(`Account for ${address} not found!`); } const { path } = accountStore; - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; const bip44Path = makeBip44PathArray(coinType, path); const sensitiveProps = diff --git a/apps/extension/src/background/keyring/service.ts b/apps/extension/src/background/keyring/service.ts index 01e214ee16..d90fb10970 100644 --- a/apps/extension/src/background/keyring/service.ts +++ b/apps/extension/src/background/keyring/service.ts @@ -259,6 +259,7 @@ export class KeyRingService { ): Promise { const offscreenDocumentPath = "offscreen.html"; const routerId = await getNamadaRouterId(this.extensionStore); + const rpc = await this.sdkService.getRpc(); if (!(await hasOffscreenDocument(offscreenDocumentPath))) { await createOffscreenWithTxWorker(offscreenDocumentPath); @@ -268,7 +269,7 @@ export class KeyRingService { type: SUBMIT_TRANSFER_MSG_TYPE, target: OFFSCREEN_TARGET, routerId, - data: { transferMsg, txMsg, msgId, signingKey }, + data: { transferMsg, txMsg, msgId, signingKey, rpc }, }); if (result?.error) { @@ -284,12 +285,14 @@ export class KeyRingService { msgId: string, signingKey: SigningKey ): Promise { + const rpc = await this.sdkService.getRpc(); initSubmitTransferWebWorker( { transferMsg, txMsg, msgId, signingKey, + rpc, }, this.handleTransferCompleted.bind(this) ); diff --git a/apps/extension/src/background/ledger/ledger.ts b/apps/extension/src/background/ledger/ledger.ts index 0338cd5eed..60589725d2 100644 --- a/apps/extension/src/background/ledger/ledger.ts +++ b/apps/extension/src/background/ledger/ledger.ts @@ -1,20 +1,19 @@ -import TransportUSB from "@ledgerhq/hw-transport-webusb"; -import TransportHID from "@ledgerhq/hw-transport-webhid"; import Transport from "@ledgerhq/hw-transport"; +import TransportHID from "@ledgerhq/hw-transport-webhid"; +import TransportUSB from "@ledgerhq/hw-transport-webusb"; +import { toHex } from "@cosmjs/encoding"; +import { chains } from "@namada/chains"; +import { makeBip44Path } from "@namada/utils"; import { + LedgerError, NamadaApp, ResponseAppInfo, ResponseSign, ResponseVersion, - LedgerError, } from "@zondax/ledger-namada"; -import { defaultChainId, chains } from "@namada/chains"; -import { makeBip44Path } from "@namada/utils"; -import { toHex } from "@cosmjs/encoding"; -const namadaChain = chains[defaultChainId]; -const { coinType } = namadaChain.bip44; +const { coinType } = chains.namada.bip44; export const initLedgerUSBTransport = async (): Promise => { return await TransportUSB.create(); @@ -31,7 +30,7 @@ export const DEFAULT_LEDGER_BIP44_PATH = makeBip44Path(coinType, { }); export class Ledger { - constructor(public readonly namadaApp: NamadaApp | undefined = undefined) {} + constructor(public readonly namadaApp: NamadaApp | undefined = undefined) { } /** * Returns an initialized Ledger class instance with initialized Transport @@ -78,9 +77,8 @@ export class Ledger { } const path = bip44Path || DEFAULT_LEDGER_BIP44_PATH; - const { address, publicKey } = await this.namadaApp.getAddressAndPubKey( - path - ); + const { address, publicKey } = + await this.namadaApp.getAddressAndPubKey(path); return { // Return address as bech32-encoded string @@ -100,9 +98,8 @@ export class Ledger { const path = bip44Path || DEFAULT_LEDGER_BIP44_PATH; try { - const { address, publicKey } = await this.namadaApp.showAddressAndPubKey( - path - ); + const { address, publicKey } = + await this.namadaApp.showAddressAndPubKey(path); return { // Return address as bech32-encoded string diff --git a/apps/extension/src/background/ledger/service.ts b/apps/extension/src/background/ledger/service.ts index 938931578b..adff8f1cf8 100644 --- a/apps/extension/src/background/ledger/service.ts +++ b/apps/extension/src/background/ledger/service.ts @@ -1,7 +1,7 @@ import { fromBase64 } from "@cosmjs/encoding"; import { deserialize } from "@dao-xyz/borsh"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { TxType } from "@namada/shared"; import { KVStore } from "@namada/storage"; import { AccountType, TxMsgValue } from "@namada/types"; @@ -31,7 +31,7 @@ export class LedgerService { async getRevealPKBytes( txMsg: string ): Promise<{ bytes: Uint8Array; path: string }> { - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; try { // Deserialize txMsg to retrieve source @@ -154,7 +154,7 @@ export class LedgerService { const { txMsg, specificMsg } = storeResult; - const { coinType } = chains[defaultChainId].bip44; + const { coinType } = chains.namada.bip44; try { // Query account from Ledger storage to determine path for signer diff --git a/apps/extension/src/background/offscreen/offscreen.ts b/apps/extension/src/background/offscreen/offscreen.ts index 3d49face1c..9cf2f14dbf 100644 --- a/apps/extension/src/background/offscreen/offscreen.ts +++ b/apps/extension/src/background/offscreen/offscreen.ts @@ -22,7 +22,7 @@ const SW_TTL = 20000; // sent using sendResponse; false otherwise. function handleMessages( submitTransferMessage: SubmitTransferMessage, - sender: unknown, + _sender: unknown, sendResponse: (response?: unknown) => void ): boolean { const { data, type, routerId, target } = submitTransferMessage; diff --git a/apps/extension/src/background/sdk/service.ts b/apps/extension/src/background/sdk/service.ts index 1e1a0fffc7..edc0d40911 100644 --- a/apps/extension/src/background/sdk/service.ts +++ b/apps/extension/src/background/sdk/service.ts @@ -4,7 +4,7 @@ import { ChainsService } from "background/chains"; export class SdkService { constructor(protected readonly chainsService: ChainsService) {} - private async _getRpc(): Promise { + public async getRpc(): Promise { // Pull chain config from store, as the RPC value may have changed: const chain = await this.chainsService.getChain(); @@ -16,12 +16,12 @@ export class SdkService { } async getSdk(): Promise { - const rpc = await this._getRpc(); + const rpc = await this.getRpc(); return new Sdk(rpc); } async getQuery(): Promise { - const rpc = await this._getRpc(); + const rpc = await this.getRpc(); return new Query(rpc); } } diff --git a/apps/extension/src/background/web-workers/submit-transfer-web-worker.ts b/apps/extension/src/background/web-workers/submit-transfer-web-worker.ts index c8ae13ea12..b40fca2d01 100644 --- a/apps/extension/src/background/web-workers/submit-transfer-web-worker.ts +++ b/apps/extension/src/background/web-workers/submit-transfer-web-worker.ts @@ -1,6 +1,5 @@ import { fromBase64 } from "@cosmjs/encoding"; import { deserialize, serialize } from "@dao-xyz/borsh"; -import { chains, defaultChainId } from "@namada/chains"; import { Sdk } from "@namada/shared"; import { initMulticore as initShared } from "@namada/shared/src/init"; import { TxMsgValue } from "@namada/types"; @@ -17,16 +16,19 @@ import { wasm.arrayBuffer() ); await initShared(sharedWasm); - const sdk = new Sdk(chains[defaultChainId].rpc); - await sdk.load_masp_params(); addEventListener( "message", async ({ data }: { data: SubmitTransferMessageData }) => { try { - const { privateKey, xsk } = data.signingKey; + const { + signingKey: { privateKey, xsk }, + rpc, + } = data; let txMsg = fromBase64(data.txMsg); + const sdk = new Sdk(rpc); + await sdk.load_masp_params(); // For transparent transactions we have to reveal the public key. if (privateKey) { await sdk.reveal_pk(privateKey, txMsg); diff --git a/apps/extension/src/background/web-workers/types.ts b/apps/extension/src/background/web-workers/types.ts index 2679eb82f6..6e4f6b11ac 100644 --- a/apps/extension/src/background/web-workers/types.ts +++ b/apps/extension/src/background/web-workers/types.ts @@ -12,6 +12,7 @@ export type SubmitTransferMessageData = { txMsg: string; msgId: string; signingKey: SigningKey; + rpc: string; }; export const INIT_MSG = "init"; diff --git a/apps/extension/src/provider/Signer.ts b/apps/extension/src/provider/Signer.ts index 8057285d2f..348a595804 100644 --- a/apps/extension/src/provider/Signer.ts +++ b/apps/extension/src/provider/Signer.ts @@ -1,5 +1,5 @@ import { toBase64 } from "@cosmjs/encoding"; -import { defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { SupportedTx, TxType } from "@namada/shared"; import { Account, @@ -35,10 +35,11 @@ export class Signer implements ISigner { ({ alias, address, type, publicKey }) => ({ alias, address, - chainId: defaultChainId, + chainId: chains.namada.chainId, type, publicKey, isShielded: type === AccountType.ShieldedKeys, + chainKey: "namada", }) ); } @@ -52,10 +53,11 @@ export class Signer implements ISigner { return { alias, address, - chainId: defaultChainId, + chainId: chains.namada.chainId, type, publicKey, isShielded: type === AccountType.ShieldedKeys, + chainKey: "namada", }; } } diff --git a/apps/extension/src/provider/data.mock.ts b/apps/extension/src/provider/data.mock.ts index 96ae94e8dc..1d572f2802 100644 --- a/apps/extension/src/provider/data.mock.ts +++ b/apps/extension/src/provider/data.mock.ts @@ -14,6 +14,7 @@ export const ACTIVE_ACCOUNT: ActiveAccountStore = { }; export const chain: Chain = { + id: "namada", alias: "Namada Testnet", bech32Prefix: "atest", bip44: { diff --git a/apps/extension/src/provider/messages.ts b/apps/extension/src/provider/messages.ts index a9be86e9a7..f48dd29262 100644 --- a/apps/extension/src/provider/messages.ts +++ b/apps/extension/src/provider/messages.ts @@ -64,7 +64,7 @@ export class ApproveConnectInterfaceMsg extends Message { } } -export class GetChainMsg extends Message { +export class GetChainMsg extends Message { public static type(): MessageType { return MessageType.GetChain; } diff --git a/apps/faucet/package.json b/apps/faucet/package.json index 358bbaa865..5cd7c9be23 100644 --- a/apps/faucet/package.json +++ b/apps/faucet/package.json @@ -17,8 +17,8 @@ }, "dependencies": { "@cosmjs/encoding": "^0.29.0", - "@namada/components": "0.1.0", - "@namada/utils": "0.1.0", + "@namada/components": "0.2.1", + "@namada/utils": "0.2.1", "buffer": "^6.0.3", "dompurify": "^3.0.2", "node-forge": "^1.3.1", diff --git a/apps/namada-interface/package.json b/apps/namada-interface/package.json index d402cbd351..919fbd7be6 100644 --- a/apps/namada-interface/package.json +++ b/apps/namada-interface/package.json @@ -1,16 +1,16 @@ { "name": "@namada/namada-interface", - "version": "0.1.0", + "version": "0.2.1", "description": "Namada Browser Extension", "repository": "https://github.com/anoma/namada-interface/", "author": "Heliax Dev ", "license": "MIT", "private": true, "dependencies": { - "@namada/components": "0.1.0", - "@namada/hooks": "0.1.0", - "@namada/integrations": "0.1.0", - "@namada/utils": "0.1.0", + "@namada/components": "0.2.1", + "@namada/hooks": "0.2.1", + "@namada/integrations": "0.2.1", + "@namada/utils": "0.2.1", "@reduxjs/toolkit": "^1.8.0", "@types/react-paginate": "^7.1.2", "bignumber.js": "^9.1.1", diff --git a/apps/namada-interface/src/App/AccountOverview/AccountOverview.components.ts b/apps/namada-interface/src/App/AccountOverview/AccountOverview.components.ts index ed2331c048..9bedb78d69 100644 --- a/apps/namada-interface/src/App/AccountOverview/AccountOverview.components.ts +++ b/apps/namada-interface/src/App/AccountOverview/AccountOverview.components.ts @@ -1,5 +1,5 @@ +import { ColorMode, DesignConfiguration } from "@namada/utils"; import styled from "styled-components"; -import { DesignConfiguration, ColorMode } from "@namada/utils"; enum ComponentColor { TabLabelActive, @@ -74,22 +74,6 @@ export const InputContainer = styled.div` } `; -export const ButtonsContainer = styled.div` - display: flex; - flex-direction: row; - justify-content: center; -`; - -export const ButtonsWrapper = styled.div` - display: flex; - width: 70%; - - & > button { - flex: 1; - padding: 8px; - } -`; - export const TotalContainer = styled.div` display: flex; justify-content: space-between; diff --git a/apps/namada-interface/src/App/AccountOverview/AccountOverview.tsx b/apps/namada-interface/src/App/AccountOverview/AccountOverview.tsx index d550eee52e..451fb61772 100644 --- a/apps/namada-interface/src/App/AccountOverview/AccountOverview.tsx +++ b/apps/namada-interface/src/App/AccountOverview/AccountOverview.tsx @@ -2,13 +2,13 @@ import BigNumber from "bignumber.js"; import { useState } from "react"; import { useNavigate } from "react-router-dom"; -import { chains, defaultChainId as chainId } from "@namada/chains"; -import { ActionButton, Heading } from "@namada/components"; +import { chains } from "@namada/chains"; +import { ActionButton, Heading, Stack } from "@namada/components"; import { useIntegrationConnection, useUntilIntegrationAttached, } from "@namada/integrations"; -import { Account, ExtensionKey, Extensions } from "@namada/types"; +import { Account, Chain, ExtensionKey, Extensions } from "@namada/types"; import { formatCurrency } from "@namada/utils"; import { TopLevelRoute } from "App/types"; import { AccountsState, addAccounts, fetchBalances } from "slices/accounts"; @@ -17,8 +17,6 @@ import { useAppDispatch, useAppSelector } from "store"; import { AccountOverviewContainer, AccountOverviewContent, - ButtonsContainer, - ButtonsWrapper, HeadingContainer, NoAccountsContainer, TotalAmount, @@ -31,12 +29,13 @@ import { DerivedAccounts } from "./DerivedAccounts"; //TODO: move to utils when we have one const isEmptyObject = (object: Record): boolean => { - return Object.keys(object).length === 0; + return object ? Object.keys(object).length === 0 : true; }; export const AccountOverview = (): JSX.Element => { const navigate = useNavigate(); const dispatch = useAppDispatch(); + const chain = useAppSelector((state) => state.chain.config); const [isExtensionConnected, setIsExtensionConnected] = useState< Record >({ @@ -46,14 +45,12 @@ export const AccountOverview = (): JSX.Element => { }); const { derived } = useAppSelector((state) => state.accounts); - const { fiatCurrency } = useAppSelector( (state) => state.settings ); const [integration, isConnectingToExtension, withConnection] = - useIntegrationConnection(chainId); - const chain = chains[chainId]; + useIntegrationConnection(chains.namada.id); const extensionAlias = Extensions[chain.extension.id].alias; const extensionAttachStatus = useUntilIntegrationAttached(chain); @@ -73,7 +70,7 @@ export const AccountOverview = (): JSX.Element => { if (accounts) { dispatch(addAccounts(accounts as Account[])); dispatch(fetchBalances()); - dispatch(setIsConnected(chainId)); + dispatch(setIsConnected(chain.id)); } setIsExtensionConnected({ @@ -100,7 +97,7 @@ export const AccountOverview = (): JSX.Element => { - {!isEmptyObject(derived[chainId]) && ( + {!isEmptyObject(derived[chain.id]) && ( {fiatCurrency} @@ -111,23 +108,21 @@ export const AccountOverview = (): JSX.Element => { - {!isEmptyObject(derived[chainId]) ? ( - - - navigate(TopLevelRoute.TokenSend)}> - Send - - navigate(TopLevelRoute.TokenReceive)} - > - Receive - - - + {!isEmptyObject(derived[chain.id]) ? ( + + navigate(TopLevelRoute.TokenSend)}> + Send + + navigate(TopLevelRoute.TokenReceive)} + > + Receive + + ) : (
)} - {isEmptyObject(derived[chainId]) && ( + {isEmptyObject(derived[chain.id]) && ( {!isExtensionConnected[chain.extension.id] && ( { } style={ currentExtensionAttachStatus === "pending" || - isConnectingToExtension + isConnectingToExtension ? { color: "transparent" } : {} } diff --git a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/DerivedAccounts.tsx b/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/DerivedAccounts.tsx index bf2f5be9a3..4b3a735aea 100644 --- a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/DerivedAccounts.tsx +++ b/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/DerivedAccounts.tsx @@ -2,7 +2,7 @@ import { useContext, useEffect, useState } from "react"; import { ThemeContext } from "styled-components"; import BigNumber from "bignumber.js"; -import { chains, defaultChainId as chainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { TokenType, Tokens } from "@namada/types"; import { formatCurrency } from "@namada/utils"; @@ -85,10 +85,10 @@ const DerivedAccounts = ({ setTotal }: Props): JSX.Element => { (state) => state.coins ); const { api } = Config; - const chain = chains[chainId]; + const chain = chains.namada; const { alias } = chain || {}; - const accounts = Object.values(derived[chainId]); + const accounts = derived[chain.id] ? Object.values(derived[chain.id]) : []; const { colorMode } = themeContext.themeConfigurations; const getAssetIconByTheme = (symbol: TokenType): string => { @@ -118,7 +118,7 @@ const DerivedAccounts = ({ setTotal }: Props): JSX.Element => { }, new BigNumber(0)); setTotal(total); setActiveAccountAddress(accounts[0]?.details.address); - }, [derived[chainId], chainId]); + }, [derived[chain.id]]); useEffect(() => { const currentTimestamp = Math.floor(Date.now() / 1000); diff --git a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.components.ts b/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.components.ts deleted file mode 100644 index ff6eac61f8..0000000000 --- a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.components.ts +++ /dev/null @@ -1,31 +0,0 @@ -import styled from "styled-components"; - -export const FaucetTransferContainer = styled.div` - display: flex; - flex-direction: column; - box-sizing: border-box; - width: 100%; - height: 100%; - justify-content: center; - align-items: center; - margin: 0 20px; - padding: 20px 0; - color: ${(props) => props.theme.colors.utility2.main80}; -`; - -export const FaucetTransferContent = styled.div` - display: flex; - flex-direction: column; - justify-content: flex-start; - width: 100%; - height: 100%; - color: ${(props) => props.theme.colors.utility2.main80}; -`; - -export const FaucetButtonsContainer = styled.div` - display: flex; - flex-direction: row; - width: 100%; - justify-content: center; - align-items: center; -`; diff --git a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.tsx b/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.tsx deleted file mode 100644 index fdf00d6d9d..0000000000 --- a/apps/namada-interface/src/App/AccountOverview/DerivedAccounts/FaucetTransferForm.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import { useCallback, useState } from "react"; - -import { ActionButton, Heading, Input, Select } from "@namada/components"; -import { Account, Symbols, TokenType, Tokens } from "@namada/types"; -import { shortenAddress } from "@namada/utils"; - -import { defaultChainId } from "@namada/chains"; -import { submitTransferTransaction } from "App/Token/TokenSend/TokenSendForm"; -import { InputContainer } from "App/Token/TokenSend/TokenSendForm.components"; -import BigNumber from "bignumber.js"; -import { - FaucetButtonsContainer, - FaucetTransferContainer, - FaucetTransferContent, -} from "./FaucetTransferForm.components"; - -const { NAMADA_INTERFACE_NAMADA_FAUCET_LIMIT: faucetLimit = "1000" } = - process.env; - -type Props = { - account: Account; - faucetAddress: string; - cancelCallback?: () => void; -}; - -export const FaucetTransferForm = ({ - account, - faucetAddress, - cancelCallback, -}: Props): JSX.Element => { - const [amount, setAmount] = useState(0); - const { address, alias } = account; - const [tokenType, setTokenType] = useState("NAM"); - - const handleFocus = (e: React.ChangeEvent): void => - e.target.select(); - - const validateAmount = (): string => { - // Ignore empty input - if (amount === 0 || !amount) { - return ""; - } - - return isAmountValid(amount) - ? "" - : `Maximum faucet transfer is ${faucetLimit}`; - }; - - const isAmountValid = (amount: number): boolean => { - return amount > 0 && amount <= parseInt(faucetLimit); - }; - - const handleSubmit = useCallback(() => { - const transferArgs = { - account, - amount: new BigNumber(`${amount}`), - chainId: defaultChainId, - faucet: faucetAddress, - feeAmount: new BigNumber("0"), - target: account.address, - token: tokenType as TokenType, - notify: true, - }; - submitTransferTransaction(transferArgs); - cancelCallback && cancelCallback(); - }, [account, amount]); - - return ( - - Transfer testnet tokens - - {alias} -

From: {shortenAddress(faucetAddress)}

-

To: {shortenAddress(address)}

- - { - const { value } = e.target; - setAmount(parseFloat(value)); - }} - onFocus={handleFocus} - error={validateAmount()} - /> - - - - Submit - - {cancelCallback && ( - cancelCallback()}>Cancel - )} - -
-
- ); -}; diff --git a/apps/namada-interface/src/App/App.tsx b/apps/namada-interface/src/App/App.tsx index 0b23e1a47b..3d1a1c7901 100644 --- a/apps/namada-interface/src/App/App.tsx +++ b/apps/namada-interface/src/App/App.tsx @@ -25,14 +25,13 @@ import { import { persistor, store, useAppDispatch, useAppSelector } from "store"; import { Toasts } from "App/Toast"; import { SettingsState } from "slices/settings"; -import { chains, defaultChainId } from "@namada/chains"; import { useIntegration, useUntilIntegrationAttached, } from "@namada/integrations"; import { Outlet } from "react-router-dom"; import { addAccounts, fetchBalances } from "slices/accounts"; -import { Account } from "@namada/types"; +import { Account, Chain } from "@namada/types"; import { setChain } from "slices/chain"; export const history = createBrowserHistory({ window }); @@ -65,18 +64,18 @@ function App(): JSX.Element { setColorMode((currentMode) => (currentMode === "dark" ? "light" : "dark")); }; + const chain = useAppSelector((state) => state.chain.config); const { connectedChains } = useAppSelector( (state) => state.settings ); - const defaultChain = chains[defaultChainId]; - const integration = useIntegration(defaultChainId); + const integration = useIntegration(chain.id); useEffect(() => storeColorMode(colorMode), [colorMode]); - const extensionAttachStatus = useUntilIntegrationAttached(defaultChain); + const extensionAttachStatus = useUntilIntegrationAttached(chain); const currentExtensionAttachStatus = - extensionAttachStatus[defaultChain.extension.id]; + extensionAttachStatus[chain.extension.id]; useEffect(() => { const fetchAccounts = async (): Promise => { @@ -88,11 +87,11 @@ function App(): JSX.Element { }; if ( currentExtensionAttachStatus === "attached" && - connectedChains.includes(defaultChainId) + connectedChains.includes(chain.id) ) { fetchAccounts(); } - }); + }, [chain]); useEffect(() => { (async () => { diff --git a/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx b/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx index 53996e1d14..4787f1b589 100644 --- a/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx +++ b/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx @@ -2,11 +2,11 @@ import BigNumber from "bignumber.js"; import * as A from "fp-ts/Array"; import * as O from "fp-ts/Option"; -import { defaultChainId as chainId, chains } from "@namada/chains"; +import { chains } from "@namada/chains"; import { Select } from "@namada/components"; import { getIntegration } from "@namada/integrations"; import { Query } from "@namada/shared"; -import { AccountType, Signer, Tokens } from "@namada/types"; +import { AccountType, Chain, Signer, Tokens } from "@namada/types"; import { shortenAddress } from "@namada/utils"; import { useAppSelector } from "store"; @@ -46,7 +46,8 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { const { onClose, maybeProposal } = props; const { derived } = useAppSelector((state) => state.accounts); - const addresses = Object.keys(derived[chainId]); + const { rpc } = useAppSelector((state) => state.chain.config); + const addresses = Object.keys(derived[chains.namada.id]); const [activeProposalVotes, setActiveProposalVotes] = useState< Map @@ -72,7 +73,7 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { const vote = useCallback( async (vote: boolean) => { const voteStr = vote ? "yay" : "nay"; - const integration = getIntegration(chainId); + const integration = getIntegration(chains.namada.id); const signer = integration.signer() as Signer; if (O.isNone(maybeProposal)) { @@ -94,7 +95,7 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { token: Tokens.NAM.address || "", feeAmount: new BigNumber(0), gasLimit: new BigNumber(20_000), - chainId, + chainId: chains.namada.chainId, }, AccountType.Mnemonic ); @@ -104,7 +105,6 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { useEffect(() => { const fetchData = async (proposal: Proposal): Promise => { - const { rpc } = chains[chainId]; const query = new Query(rpc); try { const votes = await query.delegators_votes(BigInt(proposal.id)); diff --git a/apps/namada-interface/src/App/Staking/Staking.tsx b/apps/namada-interface/src/App/Staking/Staking.tsx index 242fad5f16..fa14d75d4c 100644 --- a/apps/namada-interface/src/App/Staking/Staking.tsx +++ b/apps/namada-interface/src/App/Staking/Staking.tsx @@ -4,6 +4,7 @@ import BigNumber from "bignumber.js"; import { truncateInMiddle } from "@namada/utils"; import { Modal } from "@namada/components"; +import { useSanitizedLocation } from "@namada/hooks"; import { MainContainerNavigation } from "App/StakingAndGovernance/MainContainerNavigation"; import { StakingContainer } from "./Staking.components"; @@ -18,7 +19,6 @@ import { import { NewBondingPosition } from "./NewBondingPosition"; import { UnbondPosition } from "./UnbondPosition"; import { Account } from "slices/accounts"; -import { useSanitizedLocation } from "@namada/hooks"; const initialTitle = "Staking"; diff --git a/apps/namada-interface/src/App/Staking/StakingOverview/StakingBalancesList/StakingBalancesList.tsx b/apps/namada-interface/src/App/Staking/StakingOverview/StakingBalancesList/StakingBalancesList.tsx index 69963cff79..a050bef87b 100644 --- a/apps/namada-interface/src/App/Staking/StakingOverview/StakingBalancesList/StakingBalancesList.tsx +++ b/apps/namada-interface/src/App/Staking/StakingOverview/StakingBalancesList/StakingBalancesList.tsx @@ -1,4 +1,4 @@ -import { defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { mapUndefined, showMaybeNam } from "@namada/utils"; import BigNumber from "bignumber.js"; import { RootState, useAppSelector } from "store"; @@ -43,7 +43,7 @@ const selectStakingTotals = (state: RootState): Totals | undefined => { const selectTotalNamBalance = (state: RootState): BigNumber => { const { derived } = state.accounts; - const accounts = Object.values(derived[defaultChainId]); + const accounts = Object.values(derived[chains.namada.id]); return accounts.reduce((acc, curr) => { return acc.plus(curr.balance["NAM"] ?? new BigNumber(0)); diff --git a/apps/namada-interface/src/App/StakingAndGovernance/StakingAndGovernance.tsx b/apps/namada-interface/src/App/StakingAndGovernance/StakingAndGovernance.tsx index 4cc1578882..484c82effc 100644 --- a/apps/namada-interface/src/App/StakingAndGovernance/StakingAndGovernance.tsx +++ b/apps/namada-interface/src/App/StakingAndGovernance/StakingAndGovernance.tsx @@ -2,7 +2,6 @@ import { useEffect } from "react"; import { Route, Routes, useNavigate } from "react-router-dom"; import { RootState, useAppDispatch, useAppSelector } from "store"; -import { defaultChainId as chainId } from "@namada/chains"; import { useSanitizedLocation } from "@namada/hooks"; import { useIntegrationConnection } from "@namada/integrations"; import { Staking } from "App/Staking"; @@ -13,6 +12,7 @@ import { } from "App/types"; import { StakingAndGovernanceContainer } from "./StakingAndGovernance.components"; +import { Chain } from "@namada/types"; import { ChangeInStakingPosition, fetchValidatorDetails, @@ -31,16 +31,17 @@ export const StakingAndGovernance = (): JSX.Element => { const location = useSanitizedLocation(); const navigate = useNavigate(); const dispatch = useAppDispatch(); + const chain = useAppSelector((state: RootState) => state.chain.config); + const { id } = chain; const stakingAndGovernance = useAppSelector( (state: RootState) => state.stakingAndGovernance ); const derivedAccounts = useAppSelector( (state: RootState) => state.accounts - ).derived[chainId]; + ).derived[id]; const accounts = Object.values(derivedAccounts); - const [_integration, _status, withConnection] = - useIntegrationConnection(chainId); + const [_integration, _status, withConnection] = useIntegrationConnection(id); const { validators, selectedValidatorId, myStakingPositions } = stakingAndGovernance; diff --git a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx index f065a9519d..78c79499a5 100644 --- a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx +++ b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx @@ -4,7 +4,7 @@ import { Option, Select, } from "@namada/components"; -import { chains, defaultChainId as chainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { TokenType, Tokens } from "@namada/types"; import BigNumber from "bignumber.js"; import { useState } from "react"; @@ -49,7 +49,7 @@ export const EthereumBridge = (): JSX.Element => { const [amount, setAmount] = useState(new BigNumber(0)); const [feeAmount, setFeeAmount] = useState(new BigNumber(0)); - const accounts = Object.values(derived[chainId]).filter( + const accounts = Object.values(derived[chains.namada.id]).filter( ({ details }) => !details.isShielded ); @@ -75,7 +75,7 @@ export const EthereumBridge = (): JSX.Element => { (account) => account?.details?.address === accountId ) as Account; - const integration = getIntegration(chainId); + const integration = getIntegration(chains.namada.id); await integration.submitBridgeTransfer( { bridgeProps: { @@ -92,14 +92,14 @@ export const EthereumBridge = (): JSX.Element => { feeAmount: new BigNumber(0), gasLimit: new BigNumber(20_000), publicKey: account.details.publicKey, - chainId, + chainId: chains.namada.chainId, }, }, account.details.type ); }; - const extensionKey = chains[chainId].extension.id; + const extensionKey = chains.namada.extension.id; // Validate form const recipientValid = recipient.length > 0; diff --git a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridgeTransfer.tsx b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridgeTransfer.tsx index 7503d40ca8..d5a043bcfa 100644 --- a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridgeTransfer.tsx +++ b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridgeTransfer.tsx @@ -1,8 +1,9 @@ -import { chains } from "@namada/chains"; import { Query, TransferToEthereum } from "@namada/shared"; +import { Chain } from "@namada/types"; import { shortenAddress } from "@namada/utils"; import { useEffect, useState } from "react"; import { Account } from "slices/accounts"; +import { useAppSelector } from "store"; import { TransferCol, TransferRow, @@ -11,12 +12,12 @@ import { type EthereumBridgeTransfersProps = { accounts: Account[]; - chainId: string; }; export const EthereumBridgeTransfers = ( - { accounts, chainId }: EthereumBridgeTransfersProps + { accounts }: EthereumBridgeTransfersProps ): JSX.Element => { + const { rpc } = useAppSelector((state) => state.chain.config); const [pendingTransfers, setPendingTransfers] = useState< TransferToEthereum[] >([]); @@ -24,7 +25,6 @@ export const EthereumBridgeTransfers = ( useEffect(() => { (async () => { - const { rpc } = chains[chainId]; const query = new Query(rpc); const addresses = accounts.map(({ details }) => details.address); const bridgePool: TransferToEthereum[] = diff --git a/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx b/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx index 3c0ac7a55b..2d97f10703 100644 --- a/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx +++ b/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx @@ -1,7 +1,7 @@ import { useCallback, useEffect, useState } from "react"; import BigNumber from "bignumber.js"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { Account as AccountType, BridgeType, @@ -12,6 +12,7 @@ import { Extensions, TokenType, Tokens, + ChainKey, } from "@namada/types"; import { Alert, @@ -20,6 +21,7 @@ import { Input, Option, Select, + Stack, } from "@namada/components"; import { getIntegration, @@ -42,6 +44,7 @@ import { } from "./IBCTransfer.components"; export const submitIbcTransfer = async ( + chainKey: ChainKey, ibcArgs: TxIbcTransferArgs ): Promise => { const { @@ -52,7 +55,7 @@ export const submitIbcTransfer = async ( portId, channelId, } = ibcArgs; - const integration = getIntegration(chainId); + const integration = getIntegration(chainKey); return await integration.submitBridgeTransfer( { @@ -69,7 +72,7 @@ export const submitIbcTransfer = async ( feeAmount: new BigNumber(0), gasLimit: new BigNumber(20_000), publicKey, - chainId: chainId || defaultChainId, + chainId, }, }, type @@ -81,7 +84,6 @@ const IBCTransfer = (): JSX.Element => { const { derived } = useAppSelector((state) => state.accounts); const [error, setError] = useState(); const [currentBalance, setCurrentBalance] = useState(new BigNumber(0)); - const [chainId, setChainId] = useState(defaultChainId) const { channelsByChain = {} } = useAppSelector( (state) => state.channels ); @@ -94,27 +96,34 @@ const IBCTransfer = (): JSX.Element => { }); const [isFormValid, setIsFormValid] = useState(false); - const bridgedChains = Object.values(chains).filter( - (chain: Chain) => chain.chainId !== chainId + const [sourceChainId, setSourceChainId] = useState(chains.namada.chainId) + const sourceChain: Chain = Object.values(chains) + .find((chain: Chain) => chain.chainId === sourceChainId) || chains.namada; + + const ibcChains = Object.values(chains).filter( + (chain: Chain) => chain.chainId !== sourceChainId && chain.bridgeType.includes(BridgeType.IBC) ); - const sourceChain = chains[chainId] || null; - const [selectedChainId, setSelectedChainId] = useState(defaultChainId); - const destinationChain = bridgedChains[0]; + const [destinationChainId, setDestinationChainId] = useState(ibcChains[0].chainId); + const destinationChain = ibcChains[0]; - const selectDestinationChainData = bridgedChains.map((chain) => ({ + const selectDestinationChainData = ibcChains.map((chain) => ({ value: chain.chainId, label: chain.alias, })); - const [destinationIntegration, _isDestinationConnectingToExtension, withDestinationConnection] = - useIntegrationConnection(destinationChain.chainId); - const [sourceIntegration, _isSourceConnectingToExtension, withSourceConnection] = - useIntegrationConnection(sourceChain.chainId); + useIntegrationConnection(sourceChain.id); + + const [destinationIntegration, _isDestinationConnectingToExtension, withDestinationConnection] = + useIntegrationConnection(destinationChain.id); const [amount, setAmount] = useState(new BigNumber(0)); - const [selectedChannelId, setSelectedChannelId] = useState(""); + // TODO: Clean this up: + const defaultChannelId = channelsByChain[sourceChain.id] + && channelsByChain[sourceChain.id][destinationChain.id].length > 0 + ? channelsByChain[sourceChain.id][destinationChain.id][0] : "" + const [selectedChannelId, setSelectedChannelId] = useState(defaultChannelId); const [showAddChannelForm, setShowAddChannelForm] = useState(false); const [channelId, setChannelId] = useState(); const [recipient, setRecipient] = useState(""); @@ -124,19 +133,15 @@ const IBCTransfer = (): JSX.Element => { >([]); const [sourceAccount, setSourceAccount] = useState(); - const [token, setToken] = useState(chains[defaultChainId].currency.symbol as TokenType); - - const chain = chains[chainId]; - const sourceExtensionAlias = Extensions[sourceChain.extension.id].alias; - const destinationExtensionAlias = Extensions[destinationChain.extension.id].alias; + const [token, setToken] = useState(chains.namada.currency.symbol as TokenType); - const extensionAttachStatus = useUntilIntegrationAttached(chain); + const extensionAttachStatus = useUntilIntegrationAttached(sourceChain); const currentExtensionAttachStatus = - extensionAttachStatus[chain.extension.id]; + extensionAttachStatus[sourceChain.extension.id]; const channels = - channelsByChain[chainId] && channelsByChain[chainId][selectedChainId] - ? [...channelsByChain[chainId][selectedChainId]].reverse() + channelsByChain[sourceChain.id] && channelsByChain[sourceChain.id][destinationChain.id] + ? [...channelsByChain[sourceChain.id][destinationChain.id]].reverse() : []; const selectChannelsData = channels.map((channel: string) => ({ @@ -144,7 +149,7 @@ const IBCTransfer = (): JSX.Element => { label: channel, })); - const accounts = Object.values(derived[chainId]); + const accounts = Object.values(derived[sourceChain.id]); const sourceAccounts = accounts.filter(({ details }) => !details.isShielded); const tokenData: Option[] = sourceAccounts.flatMap( @@ -176,7 +181,10 @@ const IBCTransfer = (): JSX.Element => { }, [sourceAccount, token]); useEffect(() => { - const destinationAccounts = Object.values(derived[selectedChainId]).filter( + const chain = Object.values(chains).find((chain) => chain.chainId === destinationChainId); + if (!chain) return; + + const destinationAccounts = Object.values(derived[chain.id]).filter( (account) => !account.details.isShielded ); setDestinationAccounts(destinationAccounts); @@ -187,49 +195,39 @@ const IBCTransfer = (): JSX.Element => { }) ); setDestinationAccountData(destinationAccountsData); - }, [derived, selectedChainId]); + }, [derived, destinationChainId]); useEffect(() => { // Set recipient to first destination account if (destinationAccounts?.length > 0) { setRecipient(destinationAccounts[0].details.address); } - }, [selectedChainId, destinationAccounts]); + }, [destinationChainId, destinationAccounts]); useEffect(() => { - if (bridgedChains.length > 0) { - const selectedChain = bridgedChains[0].chainId; - setSelectedChainId(selectedChain); + if (ibcChains.length > 0) { + setDestinationChainId(ibcChains[0].chainId); setSourceAccount(sourceAccounts[0]); } - }, [chainId]); - - useEffect(() => { - // Set a default selectedChannelId if none are selected, but channels are available - if (selectedChainId && !selectedChannelId) { - const chains = channelsByChain[chainId] || {}; - const channels = chains[selectedChainId] || []; - if (channels && channels.length > 0) { - setSelectedChannelId(channels[channels.length - 1]); - } - } - }, [selectedChainId, channelsByChain]); + }, [sourceChainId]); const handleFocus = (e: React.ChangeEvent): void => e.target.select(); // transform for select component - const networks = Object.values(chains).map(({ chainId, alias }: Chain) => ({ - label: alias, - value: chainId, - })); + const networks = Object.values(chains) + .filter((chain) => chain.bridgeType.includes(BridgeType.IBC)) + .map(({ chainId, alias }: Chain) => ({ + label: alias, + value: chainId, + })); const handleNetworkSelect = ( event: React.ChangeEvent ): void => { const { value: chainId } = event.target; - setChainId(chainId) - setToken(chains[chainId].currency.symbol as TokenType) + setSourceChainId(chainId) + setToken(sourceChain.currency.symbol as TokenType) }; const { portId = "transfer" } = sourceChain.ibc || {}; @@ -237,8 +235,8 @@ const IBCTransfer = (): JSX.Element => { if (channelId) { dispatch( addChannel({ - chainId, - destinationChainId: selectedChainId, + sourceChainKey: sourceChain.id, + destinationChainKey: destinationChain.id, channelId, }) ); @@ -262,13 +260,13 @@ const IBCTransfer = (): JSX.Element => { const handleSubmit = (): void => { setError(undefined) - const tokens = sourceChain.chainId === defaultChainId ? Tokens : CosmosTokens; + const tokens = sourceChain.id === "namada" ? Tokens : CosmosTokens; if (sourceAccount && token) { - submitIbcTransfer({ + submitIbcTransfer(sourceChain.id, { account: sourceAccount.details, token: tokens[token as TokenType & CosmosTokenType], amount, - chainId, + chainId: sourceChainId, target: recipient, channelId: selectedChannelId, portId, @@ -284,22 +282,22 @@ const IBCTransfer = (): JSX.Element => { const accounts = await sourceIntegration?.accounts(); if (accounts) { dispatch(addAccounts(accounts as AccountType[])); - dispatch(setIsConnected(chain.chainId)); + dispatch(setIsConnected(sourceChain.id)); } setIsExtensionConnected({ ...isExtensionConnected, - [chain.extension.id]: true, + [sourceChain.extension.id]: true, }); }, async () => { setIsExtensionConnected({ ...isExtensionConnected, - [chain.extension.id]: false, + [sourceChain.extension.id]: false, }); } ); - }, [chain]); + }, [sourceChain]); const handleConnectDestinationExtension = useCallback(async (): Promise => { withDestinationConnection( @@ -307,22 +305,22 @@ const IBCTransfer = (): JSX.Element => { const accounts = await destinationIntegration?.accounts(); if (accounts) { dispatch(addAccounts(accounts as AccountType[])); - dispatch(setIsConnected(chainId)); + dispatch(setIsConnected(destinationChain.id)); } setIsExtensionConnected({ ...isExtensionConnected, - [chain.extension.id]: true, + [destinationChain.extension.id]: true, }); }, async () => { setIsExtensionConnected({ ...isExtensionConnected, - [chain.extension.id]: false, + [destinationChain.extension.id]: false, }); } ); - }, [chain]); + }, [sourceChain]); const handleDownloadExtension = (url: string): void => { window.open(url, "_blank", "noopener,noreferrer"); @@ -361,7 +359,8 @@ const IBCTransfer = (): JSX.Element => { currentBalance, destinationChain, recipient, - selectedChainId, + sourceChainId, + destinationChainId, selectedChannelId, sourceAccount, ]); @@ -373,7 +372,7 @@ const IBCTransfer = (): JSX.Element => { {error && {error}} { }} onFocus={handleFocus} error={ - channels.indexOf(`${channelId}`) > -1 + channels.includes(`${channelId}`) ? "Channel exists!" : undefined } /> - - Add - - setShowAddChannelForm(false)} - > - Cancel - - + + + Add + + setShowAddChannelForm(false)} + > + Cancel + + + + )} - {!isExtensionConnected[chain.extension.id] && + {!isExtensionConnected[destinationChain.extension.id] && destinationAccounts.length === 0 && ( { > {currentExtensionAttachStatus === "attached" || currentExtensionAttachStatus === "pending" - ? `Load accounts from ${destinationExtensionAlias} Extension` + ? `Load accounts from ${Extensions[destinationChain.extension.id].alias} Extension` : "Click to download the extension"} )} @@ -549,8 +549,9 @@ const IBCTransfer = (): JSX.Element => {
- )} - + ) + } + ); }; diff --git a/apps/namada-interface/src/App/Token/TokenReceive/TokenReceive.tsx b/apps/namada-interface/src/App/Token/TokenReceive/TokenReceive.tsx index 6b29fdde7e..a050384e42 100644 --- a/apps/namada-interface/src/App/Token/TokenReceive/TokenReceive.tsx +++ b/apps/namada-interface/src/App/Token/TokenReceive/TokenReceive.tsx @@ -1,4 +1,4 @@ -import { defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { Heading, Icon, NavigationContainer, Select } from "@namada/components"; import { formatRoute } from "@namada/utils"; import { TopLevelRoute } from "App/types"; @@ -24,13 +24,12 @@ const TokenReceive = (): JSX.Element => { string | undefined >(); - const accounts = Object.values(derived[defaultChainId]); + const accounts = Object.values(derived[chains.namada.id]); const accountsData = accounts.map(({ details }) => ({ value: details.address, - label: `${details.alias} - ${ - details.isShielded ? "Shielded" : "Transparent" - }`, + label: `${details.alias} - ${details.isShielded ? "Shielded" : "Transparent" + }`, })); useEffect(() => { diff --git a/apps/namada-interface/src/App/Token/TokenSend/TokenSend.tsx b/apps/namada-interface/src/App/Token/TokenSend/TokenSend.tsx index 5f953f2ae4..d83b6d8551 100644 --- a/apps/namada-interface/src/App/Token/TokenSend/TokenSend.tsx +++ b/apps/namada-interface/src/App/Token/TokenSend/TokenSend.tsx @@ -5,7 +5,6 @@ import { TransferType } from "App/Token/types"; import { Account, AccountsState } from "slices/accounts"; import { useAppSelector } from "store"; -import { defaultChainId as chainId, chains } from "@namada/chains"; import { Heading, NavigationContainer, @@ -16,8 +15,9 @@ import { } from "@namada/components"; import { useSanitizedParams } from "@namada/hooks"; import { Query } from "@namada/shared"; -import { TokenType, Tokens } from "@namada/types"; +import { Chain, TokenType, Tokens } from "@namada/types"; import TokenSendForm from "./TokenSendForm"; +import { chains } from "@namada/chains"; import { TokenSendContainer, TokenSendContent } from "./TokenSend.components"; import { @@ -65,9 +65,10 @@ const accountsWithBalanceIntoSelectData = ( const TokenSend = (): JSX.Element => { const { derived } = useAppSelector((state) => state.accounts); + const { rpc } = useAppSelector((state) => state.chain.config); const { target } = useSanitizedParams(); - const accounts = Object.values(derived[chainId]); + const accounts = Object.values(derived[chains.namada.id]); const shieldedAccountsWithBalance = accounts.filter( ({ details }) => details.isShielded @@ -98,7 +99,7 @@ const TokenSend = (): JSX.Element => { setSelectedTransparentAccountAddress( transparentAccountsWithBalance?.[0]?.details.address ); - }, [derived[chainId]]); + }, [derived[chains.namada.id]]); const tabs = ["Shielded", "Transparent"]; let defaultTab = 0; @@ -110,24 +111,23 @@ const TokenSend = (): JSX.Element => { const [activeTab, setActiveTab] = useState(tabs[defaultTab]); const [token, setToken] = useState( - chains[chainId].currency.symbol as TokenType + chains.namada.currency.symbol as TokenType ); const handleTokenChange = (selectAccountFn: (accId: string) => void) => - (e: React.ChangeEvent): void => { - const { value } = e.target; - const [accountId, tokenSymbol] = value.split("|"); + (e: React.ChangeEvent): void => { + const { value } = e.target; + const [accountId, tokenSymbol] = value.split("|"); - selectAccountFn(accountId); - setToken(tokenSymbol as TokenType); - }; + selectAccountFn(accountId); + setToken(tokenSymbol as TokenType); + }; const [minimumGasPrice, setMinimumGasPrice] = useState(); useEffect(() => { (async () => { - const { rpc } = chains[chainId]; const query = new Query(rpc); const result = (await query.query_gas_costs()) as [string, string][]; diff --git a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx index 0f63eac6b3..f93cf7e9a3 100644 --- a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx +++ b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx @@ -2,12 +2,13 @@ import BigNumber from "bignumber.js"; import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { ActionButton, AmountInput, Icon, Input } from "@namada/components"; import { getIntegration } from "@namada/integrations"; import { Query } from "@namada/shared"; import { Chain, Signer, TokenType, Tokens } from "@namada/types"; import { mapUndefined } from "@namada/utils"; + import { TopLevelRoute } from "App/types"; import { AccountsState } from "slices/accounts"; import { useAppSelector } from "store"; @@ -41,15 +42,15 @@ export const submitTransferTransaction = async ( return; } - const integration = getIntegration(defaultChainId); + const integration = getIntegration(chains.namada.id); const signer = integration.signer() as Signer; const transferArgs = { source: faucet || address, target, - token: Tokens[token].address || Tokens.NAM.address || "", + token: Tokens[token].address, amount, - nativeToken: Tokens.NAM.address || "", + nativeToken: Tokens.NAM.address, }; const txArgs = { @@ -103,10 +104,12 @@ const getIsFormInvalid = ( * gives the description above submit button to make it move obvious for the user * that the transfer might be a shielding/unshielding transfer */ -const AccountSourceTargetDescription = (props: { - isShieldedSource: boolean; - isShieldedTarget: boolean; -}): React.ReactElement => { +const AccountSourceTargetDescription = ( + props: { + isShieldedSource: boolean; + isShieldedTarget: boolean; + } +): React.ReactElement => { const { isShieldedSource, isShieldedTarget } = props; const source = isShieldedSource ? Shielded : Transparent; const target = isShieldedTarget ? Shielded : Transparent; @@ -148,7 +151,7 @@ const TokenSendForm = ({ ); const { derived } = useAppSelector((state) => state.accounts); - const derivedAccounts = derived[defaultChainId]; + const derivedAccounts = derived[chains.namada.id]; const { details, balance } = derivedAccounts[address]; const isShieldedSource = details.isShielded; @@ -213,8 +216,7 @@ const TokenSendForm = ({ if (isShieldedSource) { setIsRevealPkNeeded(false); } else { - const { rpc } = chains[defaultChainId]; - const query = new Query(rpc); + const query = new Query(chain.rpc); const result = await query.query_public_key(address); setIsRevealPkNeeded(!result); diff --git a/apps/namada-interface/src/App/Token/index.ts b/apps/namada-interface/src/App/Token/index.ts index e343897483..9d93ef4a1f 100644 --- a/apps/namada-interface/src/App/Token/index.ts +++ b/apps/namada-interface/src/App/Token/index.ts @@ -1,5 +1,4 @@ -export * from "./TokenSend"; -export * from "./TokenReceive"; export * from "./IBCTransfer"; -export * from "./EthereumBridge"; +export * from "./TokenReceive"; +export * from "./TokenSend"; export * from "./types"; diff --git a/apps/namada-interface/src/services/extensionEvents/provider.tsx b/apps/namada-interface/src/services/extensionEvents/provider.tsx index af382a232e..5f2c92d6e8 100644 --- a/apps/namada-interface/src/services/extensionEvents/provider.tsx +++ b/apps/namada-interface/src/services/extensionEvents/provider.tsx @@ -1,10 +1,5 @@ import { createContext } from "react"; -import { - defaultChainId, - defaultCosmosChainId, - defaultEthereumChainId, -} from "@namada/chains"; import { useEventListenerOnce } from "@namada/hooks"; import { Keplr, Metamask, Namada, useIntegration } from "@namada/integrations"; import { Events, KeplrEvents, MetamaskEvents } from "@namada/types"; @@ -27,9 +22,9 @@ export const ExtensionEventsContext = createContext({}); export const ExtensionEventsProvider: React.FC = (props): JSX.Element => { const dispatch = useAppDispatch(); - const namadaIntegration = useIntegration(defaultChainId); - const keplrIntegration = useIntegration(defaultCosmosChainId); - const metamaskIntegration = useIntegration(defaultEthereumChainId); + const namadaIntegration = useIntegration("namada"); + const keplrIntegration = useIntegration("cosmos"); + const metamaskIntegration = useIntegration("ethereum"); // Instantiate handlers: const namadaAccountChangedHandler = NamadaAccountChangedHandler( diff --git a/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts b/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts index 136d2ac824..bbf9396af0 100644 --- a/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts +++ b/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts @@ -3,7 +3,7 @@ import BigNumber from "bignumber.js"; import { Query } from "@namada/shared"; import { Signer, Tokens } from "@namada/types"; -import { chains, defaultChainId as chainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { getIntegration } from "@namada/integrations"; import { @@ -113,8 +113,8 @@ export const fetchTotalBonds = createAsyncThunk< { address: string; totalBonds: number }, string, { state: RootState } ->(FETCH_TOTAL_BONDS, async (address: string) => { - const { rpc } = chains[chainId]; +>(FETCH_TOTAL_BONDS, async (address: string, thunkApi) => { + const { rpc } = thunkApi.getState().chain.config; const query = new Query(rpc); const result = await query.query_total_bonds(address); @@ -126,7 +126,7 @@ export const fetchValidators = createAsyncThunk< void, { state: RootState } >(FETCH_VALIDATORS, async (_, thunkApi) => { - const { rpc } = chains[chainId]; + const { rpc } = thunkApi.getState().chain.config; const query = new Query(rpc); const queryResult = (await query.query_all_validator_addresses()) as string[]; @@ -164,10 +164,10 @@ export const fetchMyValidators = createAsyncThunk< { state: RootState } >(FETCH_MY_VALIDATORS, async (_, thunkApi) => { try { - const { rpc } = chains[chainId]; + const { rpc, id } = thunkApi.getState().chain.config; const accounts: Account[] = Object.values( - thunkApi.getState().accounts.derived[chainId] + thunkApi.getState().accounts.derived[id] ); const addresses = accounts .filter(({ details }) => !details.isShielded) @@ -190,10 +190,10 @@ export const fetchMyStakingPositions = createAsyncThunk< { state: RootState } >(FETCH_MY_STAKING_POSITIONS, async (_, thunkApi) => { try { - const { rpc } = chains[chainId]; + const { id, rpc } = thunkApi.getState().chain.config; const accounts: Account[] = Object.values( - thunkApi.getState().accounts.derived[chainId] + thunkApi.getState().accounts.derived[id] ); const addresses = accounts .filter(({ details }) => !details.isShielded) @@ -215,8 +215,8 @@ export const fetchEpoch = createAsyncThunk< { epoch: BigNumber }, void, { state: RootState } ->(FETCH_EPOCH, async () => { - const { rpc } = chains[chainId]; +>(FETCH_EPOCH, async (_, thunkApi) => { + const { rpc } = thunkApi.getState().chain.config; const query = new Query(rpc); const epochString = await query.query_epoch(); @@ -236,10 +236,11 @@ export const postNewBonding = createAsyncThunk< { state: RootState } >(POST_NEW_STAKING, async (change, thunkApi) => { const { derived } = thunkApi.getState().accounts; - const integration = getIntegration(chainId); + const integration = getIntegration(chains.namada.id); const signer = integration.signer() as Signer; const { owner: source, validatorId: validator, amount } = change; - const account = derived[chainId][source]; + const { id, chainId } = chains.namada; + const account = derived[id][source]; const { type, publicKey } = account.details; await signer.submitBond( @@ -271,12 +272,13 @@ export const postNewUnbonding = createAsyncThunk< { state: RootState } >(POST_UNSTAKING, async (change, thunkApi) => { const { derived } = thunkApi.getState().accounts; - const integration = getIntegration(chainId); + const { chainId, id } = chains.namada + const integration = getIntegration(id); const signer = integration.signer() as Signer; const { owner: source, validatorId: validator, amount } = change; const { details: { type, publicKey }, - } = derived[chainId][source]; + } = derived[id][source]; await signer.submitUnbond( { @@ -301,11 +303,12 @@ export const postNewWithdraw = createAsyncThunk< { state: RootState } >(POST_UNSTAKING, async ({ owner, validatorId }, thunkApi) => { const { derived } = thunkApi.getState().accounts; - const integration = getIntegration(chainId); + const { id, chainId } = chains.namada + const integration = getIntegration(id); const signer = integration.signer() as Signer; const { details: { type, publicKey }, - } = derived[chainId][owner]; + } = derived[id][owner]; await signer.submitWithdraw( { diff --git a/apps/namada-interface/src/slices/accounts.ts b/apps/namada-interface/src/slices/accounts.ts index 945da54359..ffb8593bb0 100644 --- a/apps/namada-interface/src/slices/accounts.ts +++ b/apps/namada-interface/src/slices/accounts.ts @@ -1,13 +1,12 @@ import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import BigNumber from "bignumber.js"; -import { defaultChainId as chainId, chains } from "@namada/chains"; +import { Account as AccountDetails, ChainKey, TokenType } from "@namada/types"; +import { chains } from "@namada/chains"; import { getIntegration } from "@namada/integrations"; -import { Account as AccountDetails, TokenType } from "@namada/types"; import { RootState } from "store"; -type ChainId = string; type Address = string; type Details = AccountDetails; @@ -15,16 +14,17 @@ export type Balance = Partial>; export type Account = { details: Details; balance: Balance }; export type AccountsState = { - derived: Record>; + derived: Record>; }; const ACCOUNTS_ACTIONS_BASE = "accounts"; const INITIAL_STATE = { - derived: Object.keys(chains).reduce( - (acc, curr) => ({ ...acc, [curr]: {} }), - {} - ), + derived: { + namada: {}, + cosmos: {}, + ethereum: {}, + } }; enum AccountsThunkActions { @@ -37,8 +37,9 @@ const initialState: AccountsState = INITIAL_STATE; export const fetchBalances = createAsyncThunk( `${ACCOUNTS_ACTIONS_BASE}/${AccountsThunkActions.FetchBalances}`, async (_, thunkApi) => { + const { id } = chains.namada const accounts: Account[] = Object.values( - thunkApi.getState().accounts.derived[chainId] + thunkApi.getState().accounts.derived[id] ); accounts.forEach((account) => thunkApi.dispatch(fetchBalance(account))); @@ -47,7 +48,7 @@ export const fetchBalances = createAsyncThunk( export const fetchBalance = createAsyncThunk< { - chainId: string; + chainKey: ChainKey; address: string; balance: Balance; }, @@ -56,18 +57,15 @@ export const fetchBalance = createAsyncThunk< >( `${ACCOUNTS_ACTIONS_BASE}/${AccountsThunkActions.FetchBalance}`, async (account) => { - const integration = getIntegration(chainId); - - const { address, chainId: accountChainId } = account.details; - + const { address, chainKey } = account.details; + const integration = getIntegration(chainKey); const results = await integration.queryBalances(address); - const balance = results.reduce( (acc, curr) => ({ ...acc, [curr.token]: new BigNumber(curr.amount) }), {} as Balance ); - return { chainId: accountChainId, address, balance }; + return { chainKey, address, balance }; } ); @@ -78,20 +76,22 @@ const accountsSlice = createSlice({ addAccounts: (state, action: PayloadAction) => { const accounts = action.payload; - // Remove old accounts under this chainId if present: - if (accounts[0] && state.derived[accounts[0].chainId]) { - state.derived[accounts[0].chainId] = {}; + const id = accounts[0]?.chainKey || chains.namada.id; + + // Remove old accounts under this chain config id if present: + if (state.derived[id]) { + state.derived[id] = {}; } accounts.forEach((account) => { - const { address, alias, isShielded, chainId, type, publicKey } = + const { address, alias, isShielded, chainId, type, publicKey, chainKey } = account; - const currencySymbol = chains[chainId].currency.symbol; - if (!state.derived[chainId]) { - state.derived[chainId] = {}; + const currencySymbol = chains.namada.currency.symbol; + if (!state.derived[id]) { + state.derived[id] = {}; } - state.derived[chainId][address] = { + state.derived[id][address] = { details: { address, alias, @@ -99,6 +99,7 @@ const accountsSlice = createSlice({ type, publicKey, isShielded, + chainKey, }, balance: { [currencySymbol]: new BigNumber(0), @@ -113,17 +114,18 @@ const accountsSlice = createSlice({ ( state, action: PayloadAction<{ - chainId: string; + chainKey: ChainKey; address: string; balance: Balance; }> ) => { - const { chainId, address, balance } = action.payload; - if (state.derived[chainId][address]?.balance) { - state.derived[chainId][address].balance = balance; + const { address, balance, chainKey } = action.payload; + if (state.derived[chainKey][address]?.balance) { + state.derived[chainKey][address].balance = balance; } else { - delete state.derived[chainId][address]; + delete state.derived[chainKey][address]; } + } ); }, diff --git a/apps/namada-interface/src/slices/chain.ts b/apps/namada-interface/src/slices/chain.ts index dd3010d26d..9f0fb8f7c9 100644 --- a/apps/namada-interface/src/slices/chain.ts +++ b/apps/namada-interface/src/slices/chain.ts @@ -1,4 +1,4 @@ -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { Chain } from "@namada/types"; import { PayloadAction, createSlice } from "@reduxjs/toolkit"; @@ -6,7 +6,7 @@ export type ChainState = { config: Chain; }; -const initialState: ChainState = { config: chains[defaultChainId] }; +const initialState: ChainState = { config: chains.namada }; const CHAIN_ACTIONS_BASE = "chain"; const chainSlice = createSlice({ diff --git a/apps/namada-interface/src/slices/channels.ts b/apps/namada-interface/src/slices/channels.ts index dbbc0ce8cb..ee9acf8eaa 100644 --- a/apps/namada-interface/src/slices/channels.ts +++ b/apps/namada-interface/src/slices/channels.ts @@ -22,26 +22,27 @@ const channelsSlice = createSlice({ addChannel: ( state, action: PayloadAction<{ - chainId: string; + sourceChainKey: string; channelId: string; - destinationChainId: string; + destinationChainKey: string; }> ) => { - const { chainId, channelId, destinationChainId } = action.payload; + const { sourceChainKey, channelId, destinationChainKey } = action.payload; - if (!state.channelsByChain[chainId]) { - state.channelsByChain[chainId] = {}; + if (!state.channelsByChain[sourceChainKey]) { + state.channelsByChain[sourceChainKey] = {}; } - if (!state.channelsByChain[chainId][destinationChainId]) { - state.channelsByChain[chainId][destinationChainId] = []; + if (!state.channelsByChain[sourceChainKey][destinationChainKey]) { + state.channelsByChain[sourceChainKey][destinationChainKey] = []; } - const channels = state.channelsByChain[chainId][destinationChainId]; + const channels = + state.channelsByChain[sourceChainKey][destinationChainKey]; if (channels.indexOf(channelId) === -1) { channels.push(channelId); - state.channelsByChain[chainId][destinationChainId] = channels; + state.channelsByChain[sourceChainKey][destinationChainKey] = channels; } }, }, diff --git a/apps/namada-interface/src/slices/proposals.ts b/apps/namada-interface/src/slices/proposals.ts index 619f272eba..2694592aaf 100644 --- a/apps/namada-interface/src/slices/proposals.ts +++ b/apps/namada-interface/src/slices/proposals.ts @@ -1,4 +1,3 @@ -import { chains, defaultChainId } from "@namada/chains"; import { Query } from "@namada/shared"; import { PayloadAction, createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import BigNumber from "bignumber.js"; @@ -34,24 +33,27 @@ export const fetchProposals = createAsyncThunk< Proposal[], void, { state: RootState } ->(`${PROPOSALS_ACTIONS_BASE}/${ProposalsActions.FetchProposals}`, async () => { - const { rpc } = chains[defaultChainId]; - const query = new Query(rpc); - let proposals: Proposal[] = []; +>( + `${PROPOSALS_ACTIONS_BASE}/${ProposalsActions.FetchProposals}`, + async (_, thunkApi) => { + const { rpc } = thunkApi.getState().chain.config; + const query = new Query(rpc); + let proposals: Proposal[] = []; - try { - const sdkProposals = await query.queryProposals(); + try { + const sdkProposals = await query.queryProposals(); - proposals = sdkProposals.map((proposal) => ({ - ...proposal, - content: JSON.parse(proposal.contentJSON) as Record, - })); - } catch (e) { - console.error(e); - } + proposals = sdkProposals.map((proposal) => ({ + ...proposal, + content: JSON.parse(proposal.contentJSON) as Record, + })); + } catch (e) { + console.error(e); + } - return proposals; -}); + return proposals; + } +); const proposalsSlice = createSlice({ name: PROPOSALS_ACTIONS_BASE, diff --git a/apps/namada-interface/src/slices/settings.ts b/apps/namada-interface/src/slices/settings.ts index 76f654c28f..575c1bd959 100644 --- a/apps/namada-interface/src/slices/settings.ts +++ b/apps/namada-interface/src/slices/settings.ts @@ -1,3 +1,4 @@ +import { ChainKey } from "@namada/types"; import { createSlice, PayloadAction } from "@reduxjs/toolkit"; const SETTINGS_ACTIONS_BASE = "settings"; @@ -19,7 +20,7 @@ const settingsSlice = createSlice({ setFiatCurrency: (state, action: PayloadAction) => { state.fiatCurrency = action.payload; }, - setIsConnected: (state, action: PayloadAction) => { + setIsConnected: (state, action: PayloadAction) => { state.connectedChains = state.connectedChains.includes(action.payload) ? state.connectedChains : [...state.connectedChains, action.payload]; diff --git a/apps/namada-interface/src/store/mocks.ts b/apps/namada-interface/src/store/mocks.ts index fbcc337985..d9de47a866 100644 --- a/apps/namada-interface/src/store/mocks.ts +++ b/apps/namada-interface/src/store/mocks.ts @@ -1,6 +1,6 @@ import BigNumber from "bignumber.js"; -import { chains, defaultChainId } from "@namada/chains"; +import { chains } from "@namada/chains"; import { AccountType } from "@namada/types"; import { StakingOrUnstakingState } from "slices/StakingAndGovernance"; import { RootState } from "./store"; @@ -8,7 +8,7 @@ import { RootState } from "./store"; export const mockAppState: RootState = { accounts: { derived: { - "namada-masp-1.5.32ccad5356012a7": { + namada: { tnam1q8gpzlamqksqjagt2xs3p6tnfcldy0fcd53fs4jh: { details: { chainId: "namada-masp-1.5.32ccad5356012a7", @@ -16,6 +16,7 @@ export const mockAppState: RootState = { address: "tnam1q8gpzlamqksqjagt2xs3p6tnfcldy0fcd53fs4jh", isShielded: false, type: AccountType.PrivateKey, + chainKey: "namada", }, balance: { NAM: new BigNumber(1000), @@ -24,41 +25,11 @@ export const mockAppState: RootState = { }, }, }, - "namada-test.1e670ba91369ec891fc": { - "39UL18": { - details: { - chainId: "namada-test.1e670ba91369ec891fc", - alias: "Namada", - address: "tnam1qz4sdx5jlh909j44uz46pf29ty0ztftfzc98s8dx", - type: AccountType.PrivateKey, - isShielded: false, - }, - balance: { - NAM: new BigNumber(1000), - DOT: new BigNumber(1000), - ETH: new BigNumber(1000), - }, - }, - }, - "namada-test.89060614ce340f4baae": { - "2MLGVA": { - details: { - chainId: "namada-test.89060614ce340f4baae", - alias: "Namada", - address: "L1qDtV8TRwYLSHdMDW518hgRw9nWnRjFTenkcBYNJruyYoLjaj8F", - type: AccountType.PrivateKey, - isShielded: false, - }, - balance: { - NAM: new BigNumber(1000), - DOT: new BigNumber(1000), - ETH: new BigNumber(1000), - }, - }, - }, + cosmos: {}, + ethereum: {}, }, }, - chain: { config: chains[defaultChainId] }, + chain: { config: chains.namada }, channels: { channelsByChain: { "namada-test.1e670ba91369ec891fc": { diff --git a/package.json b/package.json index db25ca6a95..b0a5f86146 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "namada", - "version": "0.1.0", + "version": "0.2.0", "private": true, "workspaces": [ "apps/*", diff --git a/packages/chains/package.json b/packages/chains/package.json index 1a5087298f..1b7fff5277 100644 --- a/packages/chains/package.json +++ b/packages/chains/package.json @@ -1,13 +1,13 @@ { "name": "@namada/chains", - "version": "0.1.0", + "version": "0.2.1", "description": "Chain configurations for Namada", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface", "author": "Heliax AG ", "license": "MIT", "dependencies": { - "@namada/types": "0.1.0", + "@namada/types": "0.2.1", "typescript": "^5.1.3" }, "devDependencies": { diff --git a/packages/chains/src/chains/cosmos.ts b/packages/chains/src/chains/cosmos.ts index b68146a80c..f2ed3792ce 100644 --- a/packages/chains/src/chains/cosmos.ts +++ b/packages/chains/src/chains/cosmos.ts @@ -13,6 +13,7 @@ const { } = process.env; const cosmos: Chain = { + id: "cosmos", alias, bech32Prefix: "cosmos", bip44: { diff --git a/packages/chains/src/chains/ethereum.ts b/packages/chains/src/chains/ethereum.ts index bfba0eca2e..af446d69cf 100644 --- a/packages/chains/src/chains/ethereum.ts +++ b/packages/chains/src/chains/ethereum.ts @@ -13,6 +13,7 @@ const { } = process.env; const ethereum: Chain = { + id: "ethereum", alias, bech32Prefix: "eth", bip44: { diff --git a/packages/chains/src/chains/namada.ts b/packages/chains/src/chains/namada.ts index f6be90f493..e261609b3e 100644 --- a/packages/chains/src/chains/namada.ts +++ b/packages/chains/src/chains/namada.ts @@ -15,6 +15,7 @@ const { } = process.env; const namada: Chain = { + id: "namada", alias, bech32Prefix, bip44: { diff --git a/packages/chains/src/index.ts b/packages/chains/src/index.ts index e415bce3e2..782363ef91 100644 --- a/packages/chains/src/index.ts +++ b/packages/chains/src/index.ts @@ -1,15 +1,12 @@ +import { Chain, ChainKey } from "@namada/types"; import cosmos from "./chains/cosmos"; import ethereum from "./chains/ethereum"; import namada from "./chains/namada"; -export const defaultChainId = namada.chainId; -export const defaultCosmosChainId = cosmos.chainId; -export const defaultEthereumChainId = ethereum.chainId; - -export const chains = { - [cosmos.chainId]: cosmos, - [namada.chainId]: namada, - // [ethereum.chainId]: ethereum, +export const chains: Record = { + cosmos, + namada, + ethereum, }; export * from "./types"; diff --git a/packages/chains/src/types.ts b/packages/chains/src/types.ts index 6a627eccd6..79d207f81f 100644 --- a/packages/chains/src/types.ts +++ b/packages/chains/src/types.ts @@ -1,9 +1,9 @@ -const getProxyURL = (port: number): string => `http://localhost:${port}/proxy`; +import { ChainKey } from "@namada/types"; -type ProxiedChains = "namada" | "cosmos" | "ethereum"; +const getProxyURL = (port: number): string => `http://localhost:${port}/proxy`; // Define unique Proxy URLs for each chain: -export const ProxyMappings: Record = { +export const ProxyMappings: Record = { namada: getProxyURL(8010), cosmos: getProxyURL(8011), ethereum: getProxyURL(8012), diff --git a/packages/components/package.json b/packages/components/package.json index 5cbf765f5f..31d14e1723 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@namada/components", - "version": "0.1.0", + "version": "0.2.1", "description": "A collection of components for use with the Namada ecosystem", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface", @@ -12,7 +12,7 @@ "lint:ci": "yarn lint --max-warnings 0" }, "dependencies": { - "@namada/utils": "0.1.0", + "@namada/utils": "0.2.1", "clsx": "^2.0.0", "react": "^17.0.2", "react-icons": "^4.12.0", diff --git a/packages/crypto/package.json b/packages/crypto/package.json index 38b49600ec..8fa696b7e3 100644 --- a/packages/crypto/package.json +++ b/packages/crypto/package.json @@ -1,6 +1,6 @@ { "name": "@namada/crypto", - "version": "0.1.0", + "version": "0.2.1", "description": "Crypto functions related to Namada", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface/", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index f67549fefa..b226cd42ed 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@namada/hooks", - "version": "0.1.0", + "version": "0.2.1", "description": "A collection of React hooks", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface", @@ -12,9 +12,9 @@ "lint:ci": "yarn lint --max-warnings 0" }, "dependencies": { - "@namada/chains": "0.1.0", - "@namada/types": "0.1.0", - "@namada/utils": "0.1.0", + "@namada/chains": "0.2.1", + "@namada/types": "0.2.1", + "@namada/utils": "0.2.1", "react": "^17.0.2", "typescript": "^5.1.3" }, diff --git a/packages/integrations/package.json b/packages/integrations/package.json index a55105be19..b726fbb5fb 100644 --- a/packages/integrations/package.json +++ b/packages/integrations/package.json @@ -1,6 +1,6 @@ { "name": "@namada/integrations", - "version": "0.1.0", + "version": "0.2.1", "description": "Namada Wallet third-party integrations", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface", @@ -37,7 +37,7 @@ "@cosmjs/stargate": "^0.29.5", "@keplr-wallet/types": "^0.10.19", "@metamask/providers": "^10.2.1", - "@namada/types": "0.1.0", - "@namada/utils": "0.1.0" + "@namada/types": "0.2.1", + "@namada/utils": "0.2.1" } } diff --git a/packages/integrations/src/Keplr.test.ts b/packages/integrations/src/Keplr.test.ts index cfc0760a2f..f9047906df 100644 --- a/packages/integrations/src/Keplr.test.ts +++ b/packages/integrations/src/Keplr.test.ts @@ -1,15 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { mock } from "jest-mock-extended"; +import { Keplr as IKeplr, Key } from "@keplr-wallet/types"; import { AccountType, Chain } from "@namada/types"; -import { Key, Keplr as IKeplr } from "@keplr-wallet/types"; -import Keplr from "./Keplr"; import { AccountData, OfflineDirectSigner, OfflineSigner, } from "@cosmjs/proto-signing"; +import Keplr from "./Keplr"; /** * Mock Chain configuration data @@ -133,6 +133,7 @@ describe("Keplr class", () => { address: a, type: AccountType.PrivateKey, isShielded: false, + chainKey: mockChain.id, })) ); }); diff --git a/packages/integrations/src/Keplr.ts b/packages/integrations/src/Keplr.ts index 4c568da672..25f17e1283 100644 --- a/packages/integrations/src/Keplr.ts +++ b/packages/integrations/src/Keplr.ts @@ -133,6 +133,7 @@ class Keplr implements Integration { address: account.address, type: AccountType.PrivateKey, isShielded: false, + chainKey: this.chain.id, }) ); } diff --git a/packages/integrations/src/Metamask.ts b/packages/integrations/src/Metamask.ts index ad83e4461f..c729e654df 100644 --- a/packages/integrations/src/Metamask.ts +++ b/packages/integrations/src/Metamask.ts @@ -64,6 +64,7 @@ class Metamask implements Integration { chainId: this.chain.chainId, type: AccountType.PrivateKey, isShielded: false, + chainKey: this.chain.id, })); return accounts; diff --git a/packages/integrations/src/hooks/useIntegration.ts b/packages/integrations/src/hooks/useIntegration.ts index fa2f6af41b..7406252363 100644 --- a/packages/integrations/src/hooks/useIntegration.ts +++ b/packages/integrations/src/hooks/useIntegration.ts @@ -7,13 +7,13 @@ import { } from "react"; import { chains } from "@namada/chains"; -import { Namada, Keplr, Metamask } from "@namada/integrations"; -import { Chain, ExtensionKey } from "@namada/types"; import { useUntil } from "@namada/hooks"; +import { Keplr, Metamask, Namada } from "@namada/integrations"; +import { Chain, ChainKey, ExtensionKey } from "@namada/types"; type Integration = typeof Namada | typeof Keplr | typeof Metamask; type ChainId = string; -type IntegrationsMap = Record; +type IntegrationsMap = Record; export type Integrations = Record>; type ExtensionConnection = ( onSuccess: () => T, @@ -27,12 +27,12 @@ const extensionMap: IntegrationsMap = { }; export const integrations = Object.entries(chains).reduce( - (acc, [chainId, chain]) => { + (acc, [chainKey, chain]) => { const extensionId = chain.extension.id; if (Object.keys(extensionMap).includes(extensionId)) { const Ext = extensionMap[extensionId]; - acc[chainId] = new Ext(chain); + acc[chainKey] = new Ext(chain); } return acc; @@ -43,13 +43,15 @@ export const integrations = Object.entries(chains).reduce( export const IntegrationsContext = createContext({}); /** - * Hook for accessing integration by ChainId. + * Hook for accessing integration by ChainIndex. * - * @param {ChainId} chainId - Id of the chain as a string. + * @param {ChainIndex} chainKey - Index of chain integration * @returns {InstanceType} Integration API */ -export const useIntegration = (chainId: ChainId): InstanceType => { - return useContext(IntegrationsContext)[chainId]; +export const useIntegration = ( + chainKey: ChainKey +): InstanceType => { + return useContext(IntegrationsContext)[chainKey]; }; /** @@ -57,18 +59,18 @@ export const useIntegration = (chainId: ChainId): InstanceType => { * * @template TSuccess - Success return type. * @template TFail - Fail return type. - * @param {string} chainId - Id of a chain + * @param {ChainKey} chainKey - Index of a chain integration * @returns {[InstanceType, boolean, ExtensionConnection]} * Tuple of integration, connection status and connection function. */ export const useIntegrationConnection = ( - chainId: string + chainKey: ChainKey ): [ - InstanceType, - boolean, - ExtensionConnection -] => { - const integration = useIntegration(chainId); + InstanceType, + boolean, + ExtensionConnection, + ] => { + const integration = useIntegration(chainKey); const [isConnectingToExtension, setIsConnectingToExtension] = useState(false); const connect: ExtensionConnection = useCallback( @@ -86,7 +88,7 @@ export const useIntegrationConnection = ( } setIsConnectingToExtension(false); }, - [chainId] + [chainKey] ); return [integration, isConnectingToExtension, connect]; @@ -102,8 +104,8 @@ type AttachStatusMap = { [key in ExtensionKey]: AttachStatus }; * @returns {AttachStatusMap} Map of extension -> status */ export const useUntilIntegrationAttached = (chain: Chain): AttachStatusMap => { - const { chainId, extension } = chain; - const integration = useIntegration(chainId); + const { id, extension } = chain; + const integration = useIntegration(id); const [attachStatusMap, setAttachStatus] = useState({ namada: "pending", @@ -113,7 +115,7 @@ export const useUntilIntegrationAttached = (chain: Chain): AttachStatusMap => { useEffect(() => { setAttachStatus((v) => ({ ...v, [extension.id]: "pending" })); - }, [chainId]); + }, [id]); useUntil( { @@ -137,7 +139,7 @@ export const useUntilIntegrationAttached = (chain: Chain): AttachStatusMap => { /** * Returns integrations map. To be used outside react components. * - * @returns {[Integrations]} Map of chainId -> Integration. + * @returns {[Integrations]} Map of chainKey -> Integration. */ export const getIntegrations = (): Integrations => { return integrations; @@ -146,9 +148,11 @@ export const getIntegrations = (): Integrations => { /** * Returns integration by chainId. To be used outside react components. * - * @param {ChainId} chainId - Id of the chain as a string. + * @param {Chainkey} chainKey - Key of the chain * @returns {InstanceType} Integration API */ -export const getIntegration = (chainId: ChainId): InstanceType => { - return integrations[chainId]; +export const getIntegration = ( + chainKey: ChainKey +): InstanceType => { + return integrations[chainKey]; }; diff --git a/packages/shared/package.json b/packages/shared/package.json index 4c91122e02..8f63fb9a6b 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@namada/shared", - "version": "0.1.0", + "version": "0.2.1", "description": "Namada shared functionality", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/shared/scripts/build.js b/packages/shared/scripts/build.js index 6c029f06f9..35af96e619 100644 --- a/packages/shared/scripts/build.js +++ b/packages/shared/scripts/build.js @@ -66,7 +66,7 @@ if (status !== 0) { process.exit(status); } -execSync("mkdir dist && mkdir dist/shared"); +execSync("rm -rf dist && mkdir dist && mkdir dist/shared"); // Remove the .gitignore so we can publish generated files execSync(`rm -rf ${outDir}.gitignore`); diff --git a/packages/storage/package.json b/packages/storage/package.json index f0a33bd8bd..8cea330ace 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -1,6 +1,6 @@ { "name": "@namada/storage", - "version": "0.1.0", + "version": "0.2.1", "description": "Browser storage for Namada apps", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface", diff --git a/packages/types/package.json b/packages/types/package.json index e89fa2cad0..0fa083fb15 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@namada/types", - "version": "0.1.0", + "version": "0.2.1", "description": "Types related to the Namada Extension", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/types/src/account.ts b/packages/types/src/account.ts index aba18de359..350227b7e8 100644 --- a/packages/types/src/account.ts +++ b/packages/types/src/account.ts @@ -1,3 +1,5 @@ +import { ChainKey } from "./chain"; + export type Bip44Path = { account: number; change: number; @@ -33,4 +35,5 @@ export type Account = Pick< > & { chainId: string; isShielded: boolean; + chainKey: ChainKey; }; diff --git a/packages/types/src/chain.ts b/packages/types/src/chain.ts index 2933f7a395..6eac328baa 100644 --- a/packages/types/src/chain.ts +++ b/packages/types/src/chain.ts @@ -1,8 +1,3 @@ -// const { -// // Load extension download URL from env -// REACT_APP_EXTENSION_URL: extensionUrl, -// } = process.env; - export type Currency = { token: string; symbol: string; @@ -21,6 +16,9 @@ export enum BridgeType { // Define keys for supported extensions export type ExtensionKey = "namada" | "keplr" | "metamask"; +// Define keys for supported chains +export type ChainKey = "namada" | "cosmos" | "ethereum"; + export type ExtensionInfo = { alias: string; id: ExtensionKey; @@ -48,6 +46,7 @@ export const Extensions: Record = { }; export type Chain = { + id: ChainKey; alias: string; bech32Prefix: string; bip44: { diff --git a/packages/utils/package.json b/packages/utils/package.json index f40a44bfb3..59f06a4219 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@namada/utils", - "version": "0.1.0", + "version": "0.2.1", "description": "Namada Wallet Utilities", "main": "src/index.ts", "repository": "https://github.com/anoma/namada-interface/", diff --git a/yarn.lock b/yarn.lock index bc22232d5b..fb43e264f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7470,9 +7470,9 @@ __metadata: dependencies: "@babel/plugin-transform-modules-commonjs": "npm:^7.20.11" "@keplr-wallet/types": "npm:^0.10.19" - "@namada/components": "npm:0.1.0" - "@namada/hooks": "npm:0.1.0" - "@namada/utils": "npm:0.1.0" + "@namada/components": "npm:0.2.1" + "@namada/hooks": "npm:0.2.1" + "@namada/utils": "npm:0.2.1" "@svgr/webpack": "npm:^6.3.1" "@types/dompurify": "npm:^3.0.2" "@types/lodash.groupby": "npm:^4.6.9" @@ -7504,12 +7504,12 @@ __metadata: languageName: unknown linkType: soft -"@namada/chains@npm:0.1.0, @namada/chains@workspace:packages/chains": +"@namada/chains@npm:0.2.1, @namada/chains@workspace:packages/chains": version: 0.0.0-use.local resolution: "@namada/chains@workspace:packages/chains" dependencies: "@namada/config": "workspace:^" - "@namada/types": "npm:0.1.0" + "@namada/types": "npm:0.2.1" eslint: "npm:^8.49.0" eslint-config-prettier: "npm:^8.8.0" eslint-import-resolver-typescript: "npm:^3.5.2" @@ -7520,12 +7520,12 @@ __metadata: languageName: unknown linkType: soft -"@namada/components@npm:0.1.0, @namada/components@workspace:packages/components": +"@namada/components@npm:0.2.1, @namada/components@workspace:packages/components": version: 0.0.0-use.local resolution: "@namada/components@workspace:packages/components" dependencies: "@namada/config": "workspace:^" - "@namada/utils": "npm:0.1.0" + "@namada/utils": "npm:0.2.1" "@types/react": "npm:^17.0.39" "@types/styled-components": "npm:^5.1.26" autoprefixer: "npm:^10.4.16" @@ -7559,7 +7559,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/crypto@npm:0.1.0, @namada/crypto@workspace:packages/crypto": +"@namada/crypto@npm:0.2.1, @namada/crypto@workspace:packages/crypto": version: 0.0.0-use.local resolution: "@namada/crypto@workspace:packages/crypto" dependencies: @@ -7586,14 +7586,14 @@ __metadata: "@ledgerhq/hw-transport": "npm:^6.30.0" "@ledgerhq/hw-transport-webhid": "npm:^6.28.0" "@ledgerhq/hw-transport-webusb": "npm:^6.28.0" - "@namada/chains": "npm:0.1.0" - "@namada/components": "npm:0.1.0" + "@namada/chains": "npm:0.2.1" + "@namada/components": "npm:0.2.1" "@namada/config": "workspace:^" - "@namada/crypto": "npm:0.1.0" - "@namada/shared": "npm:0.1.0" - "@namada/storage": "npm:0.1.0" - "@namada/types": "npm:0.1.0" - "@namada/utils": "npm:0.1.0" + "@namada/crypto": "npm:0.2.1" + "@namada/shared": "npm:0.2.1" + "@namada/storage": "npm:0.2.1" + "@namada/types": "npm:0.2.1" + "@namada/utils": "npm:0.2.1" "@svgr/webpack": "npm:^6.3.1" "@types/chrome": "npm:^0.0.237" "@types/dompurify": "npm:^3.0.2" @@ -7659,9 +7659,9 @@ __metadata: dependencies: "@babel/plugin-transform-modules-commonjs": "npm:^7.20.11" "@cosmjs/encoding": "npm:^0.29.0" - "@namada/components": "npm:0.1.0" + "@namada/components": "npm:0.2.1" "@namada/config": "workspace:^" - "@namada/utils": "npm:0.1.0" + "@namada/utils": "npm:0.2.1" "@svgr/webpack": "npm:^6.3.1" "@types/dompurify": "npm:^3.0.2" "@types/node-forge": "npm:^1.3.6" @@ -7692,14 +7692,14 @@ __metadata: languageName: unknown linkType: soft -"@namada/hooks@npm:0.1.0, @namada/hooks@workspace:packages/hooks": +"@namada/hooks@npm:0.2.1, @namada/hooks@workspace:packages/hooks": version: 0.0.0-use.local resolution: "@namada/hooks@workspace:packages/hooks" dependencies: - "@namada/chains": "npm:0.1.0" + "@namada/chains": "npm:0.2.1" "@namada/config": "workspace:^" - "@namada/types": "npm:0.1.0" - "@namada/utils": "npm:0.1.0" + "@namada/types": "npm:0.2.1" + "@namada/utils": "npm:0.2.1" "@types/react": "npm:^17.0.39" eslint: "npm:^8.49.0" eslint-config-prettier: "npm:^8.8.0" @@ -7711,7 +7711,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/integrations@npm:0.1.0, @namada/integrations@workspace:packages/integrations": +"@namada/integrations@npm:0.2.1, @namada/integrations@workspace:packages/integrations": version: 0.0.0-use.local resolution: "@namada/integrations@workspace:packages/integrations" dependencies: @@ -7721,8 +7721,8 @@ __metadata: "@keplr-wallet/types": "npm:^0.10.19" "@metamask/providers": "npm:^10.2.1" "@namada/config": "workspace:^" - "@namada/types": "npm:0.1.0" - "@namada/utils": "npm:0.1.0" + "@namada/types": "npm:0.2.1" + "@namada/utils": "npm:0.2.1" "@types/jest": "npm:^28.1.8" "@types/node": "npm:^18.7.13" eslint: "npm:^8.49.0" @@ -7742,11 +7742,11 @@ __metadata: version: 0.0.0-use.local resolution: "@namada/namada-interface@workspace:apps/namada-interface" dependencies: - "@namada/components": "npm:0.1.0" + "@namada/components": "npm:0.2.1" "@namada/config": "workspace:^" - "@namada/hooks": "npm:0.1.0" - "@namada/integrations": "npm:0.1.0" - "@namada/utils": "npm:0.1.0" + "@namada/hooks": "npm:0.2.1" + "@namada/integrations": "npm:0.2.1" + "@namada/utils": "npm:0.2.1" "@playwright/test": "npm:^1.24.1" "@reduxjs/toolkit": "npm:^1.8.0" "@svgr/webpack": "npm:^6.5.1" @@ -7819,7 +7819,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/shared@npm:0.1.0, @namada/shared@workspace:packages/shared": +"@namada/shared@npm:0.2.1, @namada/shared@workspace:packages/shared": version: 0.0.0-use.local resolution: "@namada/shared@workspace:packages/shared" dependencies: @@ -7843,7 +7843,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/storage@npm:0.1.0, @namada/storage@workspace:packages/storage": +"@namada/storage@npm:0.2.1, @namada/storage@workspace:packages/storage": version: 0.0.0-use.local resolution: "@namada/storage@workspace:packages/storage" dependencies: @@ -7862,7 +7862,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/types@npm:0.1.0, @namada/types@workspace:packages/types": +"@namada/types@npm:0.2.1, @namada/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@namada/types@workspace:packages/types" dependencies: @@ -7885,7 +7885,7 @@ __metadata: languageName: unknown linkType: soft -"@namada/utils@npm:0.1.0, @namada/utils@workspace:packages/utils": +"@namada/utils@npm:0.2.1, @namada/utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "@namada/utils@workspace:packages/utils" dependencies: