diff --git a/apps/extension/src/App/Accounts/AddAccount.tsx b/apps/extension/src/App/Accounts/AddAccount.tsx index 02bca349a..f54407dd6 100644 --- a/apps/extension/src/App/Accounts/AddAccount.tsx +++ b/apps/extension/src/App/Accounts/AddAccount.tsx @@ -2,14 +2,13 @@ import { LedgerError } from "@zondax/ledger-namada"; import React, { useCallback, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; -import { makeBip44Path } from "@heliax/namada-sdk/web"; +import { Ledger, makeBip44Path } from "@heliax/namada-sdk/web"; import { chains } from "@namada/chains"; import { ActionButton, Input, Toggle } from "@namada/components"; import { AccountType, DerivedAccount } from "@namada/types"; import { TopLevelRoute } from "App/types"; import { AddLedgerAccountMsg, DeriveAccountMsg } from "background/keyring"; -import { Ledger } from "background/ledger"; import { ExtensionRequester } from "extension"; import { useAuth } from "hooks"; import { isKeyChainLocked, redirectToLogin } from "hooks/useAuth"; diff --git a/apps/extension/src/App/AppContent.tsx b/apps/extension/src/App/AppContent.tsx index 549c0d3bb..0b64a8fcb 100644 --- a/apps/extension/src/App/AppContent.tsx +++ b/apps/extension/src/App/AppContent.tsx @@ -6,11 +6,7 @@ import { DerivedAccount } from "@namada/types"; import { useAccountContext, useVaultContext } from "context"; import { useQuery } from "hooks"; import { useRequester } from "hooks/useRequester"; -import { - CheckDurabilityMsg, - FetchAndStoreMaspParamsMsg, - HasMaspParamsMsg, -} from "provider/messages"; +import { CheckDurabilityMsg } from "provider/messages"; import { Ports } from "router"; import { openSetupTab } from "utils"; import { @@ -39,51 +35,11 @@ export const AppContent = (): JSX.Element => { const requester = useRequester(); const [isDurable, setIsDurable] = useState(); - const [maspStatus, setMaspStatus] = useState<{ - status: LoadingStatus; - info: string; - }>({ status: LoadingStatus.Completed, info: "" }); - - // Fetch Masp params if they don't exist - const fetchMaspParams = async (): Promise => { - const hasMaspParams = await requester.sendMessage( - Ports.Background, - new HasMaspParamsMsg() - ); - - if (!hasMaspParams) { - setMaspStatus({ - status: LoadingStatus.Pending, - info: "Fetching MASP parameters...", - }); - try { - await requester.sendMessage( - Ports.Background, - new FetchAndStoreMaspParamsMsg() - ); - setMaspStatus({ - status: LoadingStatus.Completed, - info: "", - }); - } catch (e) { - setMaspStatus({ - status: LoadingStatus.Failed, - info: `Fetching MASP parameters failed: ${e}`, - }); - //TODO: Notify user in a better way - console.error(e); - } - } - }; const getStartPage = (accounts: DerivedAccount[]): string => { return accounts.length === 0 ? routes.setup() : routes.viewAccountList(); }; - useEffect(() => { - void fetchMaspParams(); - }, []); - // Provide a redirect in the case of transaction/connection approvals useEffect(() => { if (redirect) { @@ -121,12 +77,6 @@ export const AppContent = (): JSX.Element => { {STORE_DURABILITY_INFO} )} - {maspStatus.status === LoadingStatus.Completed && maspStatus.info && ( - - {maspStatus.info} - - )} - } /> } /> diff --git a/apps/extension/src/App/Settings/Network.tsx b/apps/extension/src/App/Settings/Network.tsx index 8181a27f2..d77f4f17d 100644 --- a/apps/extension/src/App/Settings/Network.tsx +++ b/apps/extension/src/App/Settings/Network.tsx @@ -7,7 +7,6 @@ import { Input, Stack, } from "@namada/components"; -import { isUrlValid } from "@namada/utils"; import { PageHeader } from "App/Common"; import { UpdateChainMsg } from "background/chains"; import { useRequester } from "hooks/useRequester"; @@ -25,12 +24,10 @@ enum Status { export const Network = (): JSX.Element => { const requester = useRequester(); const [chainId, setChainId] = useState(""); - const [url, setUrl] = useState(""); const [status, setStatus] = useState(Status.Unsubmitted); const [errorMessage, setErrorMessage] = useState(""); - // TODO: Validate URL and sanitize inputs! - const shouldDisableSubmit = status === Status.Pending || !chainId || !url; + const shouldDisableSubmit = status === Status.Pending || !chainId; useEffect(() => { void (async () => { @@ -42,9 +39,9 @@ export const Network = (): JSX.Element => { if (!chain) { throw new Error("Chain not found!"); } - const { chainId, rpc } = chain; - setUrl(rpc); - setChainId(chainId); + const { chainId } = chain; + const santizedChainId = sanitize(chainId); + setChainId(santizedChainId); } catch (e) { setErrorMessage(`${e}`); } @@ -57,7 +54,6 @@ export const Network = (): JSX.Element => { setStatus(Status.Pending); setErrorMessage(""); const sanitizedChainId = sanitize(chainId); - const sanitizedUrl = sanitize(url); // Validate sanitized chain ID if (!sanitizedChainId) { @@ -66,18 +62,10 @@ export const Network = (): JSX.Element => { return; } - // Validate sanitized URL - const isValidUrl = isUrlValid(sanitizedUrl); - if (!isValidUrl) { - setErrorMessage("Invalid URL!"); - setStatus(Status.Failed); - return; - } - try { await requester.sendMessage( Ports.Background, - new UpdateChainMsg(sanitizedChainId, sanitizedUrl) + new UpdateChainMsg(sanitizedChainId) ); setStatus(Status.Complete); } catch (err) { @@ -85,7 +73,7 @@ export const Network = (): JSX.Element => { setErrorMessage(`${err}`); } }, - [chainId, url] + [chainId] ); return ( @@ -105,13 +93,6 @@ export const Network = (): JSX.Element => { onChange={(e) => setChainId(e.target.value)} error={chainId.length === 0 ? "Chain ID required!" : ""} /> - setUrl(e.target.value)} - error={url.length === 0 ? "URL is required!" : ""} - /> {errorMessage && {errorMessage}} {status === Status.Complete && ( Successfully updated network! diff --git a/apps/extension/src/Approvals/Approvals.tsx b/apps/extension/src/Approvals/Approvals.tsx index 47bedc60f..b6d4c7f18 100644 --- a/apps/extension/src/Approvals/Approvals.tsx +++ b/apps/extension/src/Approvals/Approvals.tsx @@ -1,18 +1,19 @@ import React, { useState } from "react"; import { Route, Routes } from "react-router-dom"; -import { TxType } from "@heliax/namada-sdk/web"; import { Container } from "@namada/components"; +import { AccountType } from "@namada/types"; import { AppHeader } from "App/Common/AppHeader"; import { TopLevelRoute } from "Approvals/types"; -import { PendingTxDetails } from "background/approvals"; import { ApproveConnection } from "./ApproveConnection"; -import { ApproveSignature } from "./ApproveSignature"; -import { ApproveTx } from "./ApproveTx/ApproveTx"; -import { ConfirmLedgerTx } from "./ApproveTx/ConfirmLedgerTx"; -import { ConfirmTx } from "./ApproveTx/ConfirmTx"; -import { ConfirmSignature } from "./ConfirmSignature"; +import { ApproveSignArbitrary } from "./ApproveSignArbitrary"; +import { + ApproveSignTx, + ConfirmSignLedgerTx, + ConfirmSignTx, +} from "./ApproveSignTx"; +import { ConfirmSignature } from "./ConfirmSignArbitrary"; export enum Status { Completed, @@ -21,19 +22,20 @@ export enum Status { } export type ApprovalDetails = { + signer: string; + accountType: AccountType; msgId: string; - txType: TxType; - tx: PendingTxDetails[]; }; -export type SignatureDetails = { +export type SignArbitraryDetails = { msgId: string; signer: string; }; export const Approvals: React.FC = () => { const [details, setDetails] = useState(); - const [signatureDetails, setSignatureDetails] = useState(); + const [signArbitraryDetails, setSignArbitraryDetails] = + useState(); return ( { > } + path={`${TopLevelRoute.ApproveSignTx}/:msgId/:accountType/:signer`} + element={} /> } + path={TopLevelRoute.ConfirmSignTx} + element={} /> } + element={} /> } /> + } /> } + path={TopLevelRoute.ConfirmSignArbitrary} + element={} /> diff --git a/apps/extension/src/Approvals/ApproveSignature.tsx b/apps/extension/src/Approvals/ApproveSignArbitrary.tsx similarity index 79% rename from apps/extension/src/Approvals/ApproveSignature.tsx rename to apps/extension/src/Approvals/ApproveSignArbitrary.tsx index 8aba29ac0..ba84e81c1 100644 --- a/apps/extension/src/Approvals/ApproveSignature.tsx +++ b/apps/extension/src/Approvals/ApproveSignArbitrary.tsx @@ -5,19 +5,21 @@ import { ActionButton, Alert, GapPatterns, Stack } from "@namada/components"; import { useSanitizedParams } from "@namada/hooks"; import { shortenAddress } from "@namada/utils"; import { PageHeader } from "App/Common"; -import { SignatureDetails } from "Approvals/Approvals"; +import { SignArbitraryDetails } from "Approvals/Approvals"; import { TopLevelRoute } from "Approvals/types"; -import { RejectSignatureMsg } from "background/approvals"; +import { RejectSignArbitraryMsg } from "background/approvals"; import { useQuery } from "hooks"; import { useRequester } from "hooks/useRequester"; import { Ports } from "router"; import { closeCurrentTab } from "utils"; type Props = { - setSignatureDetails: (details: SignatureDetails) => void; + setSignArbitraryDetails: (details: SignArbitraryDetails) => void; }; -export const ApproveSignature: React.FC = ({ setSignatureDetails }) => { +export const ApproveSignArbitrary: React.FC = ({ + setSignArbitraryDetails, +}) => { const navigate = useNavigate(); const params = useSanitizedParams(); const requester = useRequester(); @@ -27,8 +29,8 @@ export const ApproveSignature: React.FC = ({ setSignatureDetails }) => { const handleApproveClick = useCallback((): void => { if (signer) { - setSignatureDetails({ msgId, signer }); - navigate(TopLevelRoute.ConfirmSignature); + setSignArbitraryDetails({ msgId, signer }); + navigate(TopLevelRoute.ConfirmSignArbitrary); } }, [signer]); @@ -37,7 +39,7 @@ export const ApproveSignature: React.FC = ({ setSignatureDetails }) => { if (msgId) { await requester.sendMessage( Ports.Background, - new RejectSignatureMsg(msgId) + new RejectSignArbitraryMsg(msgId) ); // Close tab return await closeCurrentTab(); @@ -50,7 +52,7 @@ export const ApproveSignature: React.FC = ({ setSignatureDetails }) => { return ( - + {signer && ( diff --git a/apps/extension/src/Approvals/ApproveSignTx/ApproveSignTx.tsx b/apps/extension/src/Approvals/ApproveSignTx/ApproveSignTx.tsx new file mode 100644 index 000000000..571cb185e --- /dev/null +++ b/apps/extension/src/Approvals/ApproveSignTx/ApproveSignTx.tsx @@ -0,0 +1,91 @@ +import { useCallback, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; + +import { ActionButton, Alert, Stack } from "@namada/components"; +import { useSanitizedParams } from "@namada/hooks"; +import { AccountType } from "@namada/types"; +import { shortenAddress } from "@namada/utils"; +import { ApprovalDetails } from "Approvals/Approvals"; +import { TopLevelRoute } from "Approvals/types"; +import { RejectSignTxMsg } from "background/approvals"; +import { useRequester } from "hooks/useRequester"; +import { Ports } from "router"; +import { closeCurrentTab } from "utils"; + +type Props = { + setDetails: (details: ApprovalDetails) => void; +}; + +export const ApproveSignTx: React.FC = ({ setDetails }) => { + const navigate = useNavigate(); + const requester = useRequester(); + const params = useSanitizedParams(); + const accountType = + (params?.accountType as AccountType) || AccountType.PrivateKey; + const msgId = params?.msgId || "0"; + const signer = params?.signer; + + useEffect(() => { + if (signer && msgId) { + setDetails({ + msgId, + signer, + accountType, + }); + } + }, []); + + const handleApproveSubmit = useCallback( + (e: React.FormEvent): void => { + e.preventDefault(); + if (accountType === AccountType.Ledger) { + return navigate(`${TopLevelRoute.ConfirmLedgerTx}`); + } + navigate(TopLevelRoute.ConfirmSignTx); + }, + [accountType] + ); + + const handleReject = useCallback( + async (e: React.FormEvent): Promise => { + e.preventDefault(); + try { + if (msgId) { + await requester.sendMessage( + Ports.Background, + new RejectSignTxMsg(msgId) + ); + // Close tab + return await closeCurrentTab(); + } + throw new Error("msgId was not provided!"); + } catch (e) { + console.warn(e); + } + return; + }, + [msgId] + ); + + return ( + + + Sign this {accountType === AccountType.Ledger ? "Ledger " : ""} + transaction? + + +
+ {signer && ( +

+ Signer: {shortenAddress(signer)} +

+ )} +
+ + Approve + Reject + +
+
+ ); +}; diff --git a/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignLedgerTx.tsx b/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignLedgerTx.tsx new file mode 100644 index 000000000..b162a7654 --- /dev/null +++ b/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignLedgerTx.tsx @@ -0,0 +1,120 @@ +import { useCallback, useEffect, useState } from "react"; + +import { Ledger } from "@heliax/namada-sdk/web"; +import { ActionButton, Alert, Stack } from "@namada/components"; +import { LedgerError } from "@zondax/ledger-namada"; + +import { ApprovalDetails, Status } from "Approvals/Approvals"; +import { closeCurrentTab } from "utils"; + +type Props = { + details?: ApprovalDetails; +}; + +export const ConfirmSignLedgerTx: React.FC = ({ details }) => { + const [error, setError] = useState(); + const [status, setStatus] = useState(); + const [statusInfo, setStatusInfo] = useState(""); + const { msgId } = details || {}; + + useEffect(() => { + if (status === Status.Completed) { + void closeCurrentTab(); + } + }, [status]); + + const signLedgerTx = async ( + ledger: Ledger, + bytes: Uint8Array, + path: string + ): Promise => { + // Open ledger transport + if (!msgId) { + throw new Error("msgId was not provided!"); + } + + setStatusInfo(`Review and approve transaction on your Ledger`); + + try { + // Sign with Ledger + const signatures = await ledger.sign(bytes, path); + const { errorMessage, returnCode } = signatures; + + if (returnCode !== LedgerError.NoErrors) { + throw new Error(`Signing error encountered: ${errorMessage}`); + } + setStatus(Status.Completed); + } catch (e) { + await ledger.closeTransport(); + setError(`${e}`); + setStatus(Status.Failed); + } + }; + + const handleApproveLedgerSignTx = useCallback( + async (e: React.FormEvent): Promise => { + e.preventDefault(); + const ledger = await Ledger.init().catch((e) => { + setError(`${e}`); + setStatus(Status.Failed); + }); + + if (!ledger) { + return; + } + + const { + version: { returnCode, errorMessage }, + } = await ledger.status(); + + // Validate Ledger state first + if (returnCode !== LedgerError.NoErrors) { + await ledger.closeTransport(); + setError(errorMessage); + return setStatus(Status.Failed); + } + + setStatusInfo("Preparing transaction..."); + setStatus(Status.Pending); + + try { + // TODO: Bytes and Path will now be provided by interface when submitted for approval, + // which is now responsible for building Tx! + await signLedgerTx(ledger, new Uint8Array([]), ""); + } catch (e) { + await ledger.closeTransport(); + setError(`${e}`); + setStatus(Status.Failed); + } + }, + [] + ); + + return ( + + {status !== Status.Pending && status !== Status.Completed && ( + + Make sure your Ledger is unlocked, and click "Submit" + + )} + {status === Status.Failed && ( + + {error} +
+ Try again +
+ )} + {status === Status.Pending && {statusInfo}} + {status !== Status.Pending && status !== Status.Completed && ( + <> +

+ Make sure your Ledger is unlocked, and click "Submit" +

+
+ Submit +
+ + )} +
+ ); +}; diff --git a/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignTx.tsx b/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignTx.tsx new file mode 100644 index 000000000..6214a7d7e --- /dev/null +++ b/apps/extension/src/Approvals/ApproveSignTx/ConfirmSignTx.tsx @@ -0,0 +1,96 @@ +import { useCallback, useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; + +import { ActionButton, Alert, Input, Stack } from "@namada/components"; +import { ApprovalDetails, Status } from "Approvals/Approvals"; +import { SubmitApprovedSignTxMsg } from "background/approvals"; +import { UnlockVaultMsg } from "background/vault"; +import { useRequester } from "hooks/useRequester"; +import { Ports } from "router"; +import { closeCurrentTab } from "utils"; + +type Props = { + details?: ApprovalDetails; +}; + +export const ConfirmSignTx: React.FC = ({ details }) => { + const { msgId, signer } = details || {}; + + const navigate = useNavigate(); + const requester = useRequester(); + const [password, setPassword] = useState(""); + const [error, setError] = useState(); + const [status, setStatus] = useState(); + const [statusInfo, setStatusInfo] = useState(""); + + const handleApproveSignTx = useCallback( + async (e: React.FormEvent): Promise => { + e.preventDefault(); + setStatus(Status.Pending); + setStatusInfo(`Decrypting keys and signing transaction...`); + + try { + if (!msgId) { + throw new Error("msgId was not provided!"); + } + if (!signer) { + throw new Error("signer not provided!"); + } + + const isAuthenticated = await requester.sendMessage( + Ports.Background, + new UnlockVaultMsg(password) + ); + + if (!isAuthenticated) { + throw new Error("Invalid password!"); + } + + await requester.sendMessage( + Ports.Background, + new SubmitApprovedSignTxMsg(msgId, signer) + ); + + setStatus(Status.Completed); + } catch (e) { + console.info(e); + setError(`${e}`); + setStatus(Status.Failed); + } + }, + [password] + ); + + useEffect(() => { + if (status === Status.Completed) { + void closeCurrentTab(); + } + }, [status]); + + return ( + + {status === Status.Pending && {statusInfo}} + {status === Status.Failed && ( + + {error} +
+ Try again +
+ )} + {status !== (Status.Pending || Status.Completed) && ( + <> + Verify your password to continue + setPassword(e.target.value)} + /> + + Authenticate + navigate(-1)}>Back + + + )} +
+ ); +}; diff --git a/apps/extension/src/Approvals/ApproveSignTx/index.ts b/apps/extension/src/Approvals/ApproveSignTx/index.ts new file mode 100644 index 000000000..95a7cf6f6 --- /dev/null +++ b/apps/extension/src/Approvals/ApproveSignTx/index.ts @@ -0,0 +1,3 @@ +export * from "./ApproveSignTx"; +export * from "./ConfirmSignLedgerTx"; +export * from "./ConfirmSignTx"; diff --git a/apps/extension/src/Approvals/ApproveTx/ApproveTx.tsx b/apps/extension/src/Approvals/ApproveTx/ApproveTx.tsx deleted file mode 100644 index 887e21583..000000000 --- a/apps/extension/src/Approvals/ApproveTx/ApproveTx.tsx +++ /dev/null @@ -1,159 +0,0 @@ -import { useCallback, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; - -import { TxType, TxTypeLabel } from "@heliax/namada-sdk/web"; -import { ActionButton, Alert, Stack } from "@namada/components"; -import { useSanitizedParams } from "@namada/hooks"; -import { AccountType, Tokens } from "@namada/types"; -import { shortenAddress } from "@namada/utils"; -import { ApprovalDetails } from "Approvals/Approvals"; -import { TopLevelRoute } from "Approvals/types"; -import { - PendingTxDetails, - QueryPendingTxMsg, - RejectTxMsg, -} from "background/approvals"; -import { ExtensionRequester } from "extension"; -import { useRequester } from "hooks/useRequester"; -import { Ports } from "router"; -import { closeCurrentTab } from "utils"; - -type Props = { - setDetails: (details: ApprovalDetails) => void; - details?: ApprovalDetails; -}; - -const fetchPendingTxDetails = async ( - requester: ExtensionRequester, - msgId: string -): Promise => { - return await requester.sendMessage( - Ports.Background, - new QueryPendingTxMsg(msgId) - ); -}; - -export const ApproveTx: React.FC = ({ details, setDetails }) => { - const navigate = useNavigate(); - const requester = useRequester(); - // Parse URL params - const params = useSanitizedParams(); - const txType = parseInt(params?.type || "0"); - const accountType = - (params?.accountType as AccountType) || AccountType.PrivateKey; - const msgId = params?.msgId || "0"; - - useEffect(() => { - fetchPendingTxDetails(requester, msgId) - .then((details) => { - if (!details) { - throw new Error( - `Failed to fetch Tx details - no transactions exists for ${msgId}` - ); - } - // TODO: Handle array of approval details - setDetails({ - txType, - msgId, - tx: details, - }); - }) - .catch((e) => { - console.error(`Could not fetch pending Tx with msgId = ${msgId}: ${e}`); - }); - }, [txType, msgId]); - - const handleApproveClick = useCallback((): void => { - if (accountType === AccountType.Ledger) { - return navigate(`${TopLevelRoute.ConfirmLedgerTx}`); - } - navigate(TopLevelRoute.ConfirmTx); - }, [accountType]); - - const handleReject = useCallback(async (): Promise => { - try { - if (msgId) { - await requester.sendMessage(Ports.Background, new RejectTxMsg(msgId)); - // Close tab - return await closeCurrentTab(); - } - throw new Error("msgId was not provided!"); - } catch (e) { - console.warn(e); - } - return; - }, [msgId]); - - return ( - - - Approve this {accountType === AccountType.Ledger ? "Ledger " : ""} - {TxTypeLabel[txType as TxType]} transaction? - - - {details?.tx.map((txDetails, i) => { - const { - amount, - source, - target, - publicKey, - tokenAddress, - validator, - sourceValidator, - destinationValidator, - } = txDetails || {}; - - const tokenType = - Object.values(Tokens).find( - (token) => token.address === tokenAddress - )?.symbol || "NAM"; - - return ( -
- {source && ( -

- Source: {shortenAddress(source)} -

- )} - {target && ( -

- Target: - {shortenAddress(target)} -

- )} - {amount && ( -

- Amount: {amount} {tokenType} -

- )} - {publicKey && ( -

- Public key: {shortenAddress(publicKey)} -

- )} - {validator && ( -

- Validator: {shortenAddress(validator)} -

- )} - {sourceValidator && ( -

- Source Validator: {shortenAddress(sourceValidator)} -

- )} - {destinationValidator && ( -

- Destination Validator: {shortenAddress(destinationValidator)} -

- )} -
- ); - })} -
- - Approve - Reject - -
- ); -}; diff --git a/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx b/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx deleted file mode 100644 index 851bec8ef..000000000 --- a/apps/extension/src/Approvals/ApproveTx/ConfirmLedgerTx.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { toBase64 } from "@cosmjs/encoding"; -import BigNumber from "bignumber.js"; -import { useCallback, useEffect, useState } from "react"; - -import { TxType, TxTypeLabel } from "@heliax/namada-sdk/web"; -import { ActionButton, Alert, Stack } from "@namada/components"; -import { Message, TxMsgValue, TxProps } from "@namada/types"; -import { LedgerError } from "@zondax/ledger-namada"; -import { ApprovalDetails, Status } from "Approvals/Approvals"; -import { QueryPublicKeyMsg } from "background/keyring"; -import { - GetRevealPKBytesMsg, - GetTxBytesMsg, - Ledger, - QueryStoredPK, - StoreRevealedPK, - SubmitSignedRevealPKMsg, - SubmitSignedTxMsg, -} from "background/ledger"; -import { useRequester } from "hooks/useRequester"; -import { GetChainMsg } from "provider"; -import { Ports } from "router"; -import { closeCurrentTab } from "utils"; - -type Props = { - details?: ApprovalDetails; -}; - -export const ConfirmLedgerTx: React.FC = ({ details }) => { - const requester = useRequester(); - const [error, setError] = useState(); - const [status, setStatus] = useState(); - const [statusInfo, setStatusInfo] = useState(""); - const { msgId, txType } = details || {}; - const { source, publicKey, nativeToken } = details?.tx[0] || {}; - - useEffect(() => { - if (status === Status.Completed) { - void closeCurrentTab(); - } - }, [status]); - - const revealPk = async (ledger: Ledger, publicKey: string): Promise => { - setStatusInfo( - "Public key not found! Review and approve reveal pk on your Ledger" - ); - - const chain = await requester.sendMessage( - Ports.Background, - new GetChainMsg() - ); - - if (!nativeToken) { - throw new Error("Native token is required!"); - } - - const txArgs: TxProps = { - token: nativeToken, - feeAmount: new BigNumber(0), - gasLimit: new BigNumber(20_000), - chainId: chain.chainId, - publicKey, - }; - - const msgValue = new TxMsgValue(txArgs); - const msg = new Message(); - const encoded = msg.encode(msgValue); - - // Open Ledger transport - const { bytes, path } = await requester - .sendMessage(Ports.Background, new GetRevealPKBytesMsg(toBase64(encoded))) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }); - - try { - // Sign with Ledger - const signatures = await ledger.sign(bytes, path); - - const { returnCode, errorMessage } = signatures; - - if (returnCode !== LedgerError.NoErrors) { - throw new Error(`Reveal PK error encountered: ${errorMessage}`); - } - - // Submit signatures for tx - setStatusInfo("Revealing public key on chain..."); - - await requester - .sendMessage( - Ports.Background, - new SubmitSignedRevealPKMsg( - toBase64(encoded), - toBase64(bytes), - signatures - ) - ) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }); - } catch (e) { - throw new Error(`Unable to parse tx on Ledger: ${e}`); - } - }; - - const queryPublicKey = async ( - address: string - ): Promise => { - return await requester - .sendMessage(Ports.Background, new QueryPublicKeyMsg(address)) - .catch((e) => { - throw new Error(`Query Public Key error: ${e}`); - }); - }; - - const storePublicKey = async (publicKey: string): Promise => { - return await requester - .sendMessage(Ports.Background, new StoreRevealedPK(publicKey)) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }); - }; - - const submitTx = async (ledger: Ledger): Promise => { - // Open ledger transport - const txLabel = TxTypeLabel[txType as TxType]; - - // Construct tx bytes from SDK - if (!txType) { - throw new Error("txType was not provided!"); - } - if (!source) { - throw new Error("source was not provided!"); - } - if (!msgId) { - throw new Error("msgId was not provided!"); - } - - const { bytes, path } = ( - await requester - .sendMessage(Ports.Background, new GetTxBytesMsg(txType, msgId, source)) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }) - )[0]; - - setStatusInfo(`Review and approve ${txLabel} transaction on your Ledger`); - - try { - // Sign with Ledger - const signatures = await ledger.sign(bytes, path); - const { errorMessage, returnCode } = signatures; - - if (returnCode !== LedgerError.NoErrors) { - throw new Error(`Signing error encountered: ${errorMessage}`); - } - - // Submit signatures for tx - requester - .sendMessage( - Ports.Background, - new SubmitSignedTxMsg(txType, msgId, toBase64(bytes), signatures) - ) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }); - - setStatus(Status.Completed); - } catch (e) { - await ledger.closeTransport(); - setError(`${e}`); - setStatus(Status.Failed); - } - }; - - const handleSubmitTx = useCallback(async (): Promise => { - const ledger = await Ledger.init().catch((e) => { - setError(`${e}`); - setStatus(Status.Failed); - }); - - if (!ledger) { - return; - } - - const { - version: { returnCode, errorMessage }, - } = await ledger.status(); - - // Validate Ledger state first - if (returnCode !== LedgerError.NoErrors) { - await ledger.closeTransport(); - setError(errorMessage); - return setStatus(Status.Failed); - } - - setStatusInfo("Preparing transaction..."); - setStatus(Status.Pending); - - try { - if (!source) { - throw new Error("Source was not provided and is required!"); - } - - // If the source is the faucet address, this is a testnet faucet transfer, and - // we do not need to reveal the public key, as it is an Established Address - if (!publicKey) { - throw new Error("Public key was not provided and is required!"); - } - - // Query extension storage for revealed public key - const isPkRevealed = await requester - .sendMessage(Ports.Background, new QueryStoredPK(publicKey)) - .catch((e) => { - throw new Error(`Requester error: ${e}`); - }); - - if (!isPkRevealed) { - setStatusInfo("Querying for public key on chain..."); - const pk = await queryPublicKey(source); - - if (pk) { - // If found on chain, but not in storage, commit to storage - await storePublicKey(publicKey); - } else { - // Submit RevealPK Tx - await revealPk(ledger, publicKey); - - // Follow up with a query to ensure that PK Reveal was successful - setStatusInfo("Querying for public key status on chain..."); - const wasPkRevealed = !!(await queryPublicKey(source)); - - if (!wasPkRevealed) { - throw new Error("Public key was not revealed!"); - } - - // Commit newly revealed public key to storage - await storePublicKey(publicKey); - } - } - await submitTx(ledger); - } catch (e) { - await ledger.closeTransport(); - setError(`${e}`); - setStatus(Status.Failed); - } - }, [source, publicKey]); - - return ( - - {status !== Status.Pending && status !== Status.Completed && ( - - Make sure your Ledger is unlocked, and click "Submit" - - )} - {status === Status.Failed && ( - - {error} -
- Try again -
- )} - {status === Status.Pending && {statusInfo}} - {status !== Status.Pending && status !== Status.Completed && ( - <> -

- Make sure your Ledger is unlocked, and click "Submit" -

-
- Submit -
- - )} -
- ); -}; diff --git a/apps/extension/src/Approvals/ApproveTx/ConfirmTx.tsx b/apps/extension/src/Approvals/ApproveTx/ConfirmTx.tsx deleted file mode 100644 index 826f27cff..000000000 --- a/apps/extension/src/Approvals/ApproveTx/ConfirmTx.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { useCallback, useEffect, useState } from "react"; -import { useNavigate } from "react-router-dom"; - -import { SupportedTx, TxTypeLabel } from "@heliax/namada-sdk/web"; -import { ActionButton, Alert, Input, Stack } from "@namada/components"; -import { ApprovalDetails, Status } from "Approvals/Approvals"; -import { SubmitApprovedTxMsg } from "background/approvals"; -import { UnlockVaultMsg } from "background/vault"; -import { useRequester } from "hooks/useRequester"; -import { FetchAndStoreMaspParamsMsg, HasMaspParamsMsg } from "provider"; -import { Ports } from "router"; -import { closeCurrentTab } from "utils"; - -type Props = { - details?: ApprovalDetails; -}; - -export const ConfirmTx: React.FC = ({ details }) => { - const { msgId, txType } = details || {}; - - const navigate = useNavigate(); - const requester = useRequester(); - const [password, setPassword] = useState(""); - const [error, setError] = useState(); - const [status, setStatus] = useState(); - const [statusInfo, setStatusInfo] = useState(""); - - const handleApproveTx = useCallback(async (): Promise => { - if (!txType) { - // TODO: What would be a better handling of this? txType should be defined - throw new Error("txType should be defined"); - } - setStatus(Status.Pending); - setStatusInfo(`Decrypting keys and submitting ${TxTypeLabel[txType]}...`); - - try { - if (!msgId) { - throw new Error("msgId was not provided!"); - } - - const isAuthenticated = await requester.sendMessage( - Ports.Background, - new UnlockVaultMsg(password) - ); - - if (!isAuthenticated) { - throw new Error("Invalid password!"); - } - - const hasMaspParams = await requester.sendMessage( - Ports.Background, - new HasMaspParamsMsg() - ); - - if (!hasMaspParams) { - setStatusInfo("Fetching MASP parameters..."); - try { - await requester.sendMessage( - Ports.Background, - new FetchAndStoreMaspParamsMsg() - ); - } catch (e) { - setError(`Fetching MASP parameters failed: ${e}`); - setStatus(Status.Failed); - } - } - - requester - .sendMessage( - Ports.Background, - new SubmitApprovedTxMsg(txType as SupportedTx, msgId) - ) - .catch((e) => { - throw new Error(e); - }); - setStatus(Status.Completed); - } catch (e) { - console.info(e); - setError(`${e}`); - setStatus(Status.Failed); - } - }, [password]); - - useEffect(() => { - if (status === Status.Completed) { - void closeCurrentTab(); - } - }, [status]); - - return ( - - {status === Status.Pending && {statusInfo}} - {status === Status.Failed && ( - - {error} -
- Try again -
- )} - {status !== (Status.Pending || Status.Completed) && ( - <> - Verify your password to continue - setPassword(e.target.value)} - /> - - - Authenticate - - navigate(-1)}>Back - - - )} -
- ); -}; diff --git a/apps/extension/src/Approvals/ApproveTx/index.ts b/apps/extension/src/Approvals/ApproveTx/index.ts deleted file mode 100644 index b5936e7f7..000000000 --- a/apps/extension/src/Approvals/ApproveTx/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from "./ApproveTx"; -export * from "./ConfirmTx"; -export * from "./ConfirmLedgerTx"; diff --git a/apps/extension/src/Approvals/ConfirmSignature.tsx b/apps/extension/src/Approvals/ConfirmSignArbitrary.tsx similarity index 93% rename from apps/extension/src/Approvals/ConfirmSignature.tsx rename to apps/extension/src/Approvals/ConfirmSignArbitrary.tsx index cba6ed16f..875b2d7c5 100644 --- a/apps/extension/src/Approvals/ConfirmSignature.tsx +++ b/apps/extension/src/Approvals/ConfirmSignArbitrary.tsx @@ -10,15 +10,15 @@ import { } from "@namada/components"; import { shortenAddress } from "@namada/utils"; import { PageHeader } from "App/Common"; -import { SignatureDetails, Status } from "Approvals/Approvals"; -import { SubmitApprovedSignatureMsg } from "background/approvals"; +import { SignArbitraryDetails, Status } from "Approvals/Approvals"; +import { SubmitApprovedSignArbitraryMsg } from "background/approvals"; import { UnlockVaultMsg } from "background/vault"; import { useRequester } from "hooks/useRequester"; import { Ports } from "router"; import { closeCurrentTab } from "utils"; type Props = { - details?: SignatureDetails; + details?: SignArbitraryDetails; }; export const ConfirmSignature: React.FC = ({ details }) => { @@ -55,7 +55,7 @@ export const ConfirmSignature: React.FC = ({ details }) => { await requester .sendMessage( Ports.Background, - new SubmitApprovedSignatureMsg(msgId, signer) + new SubmitApprovedSignArbitraryMsg(msgId, signer) ) .catch((e) => { throw new Error(e); diff --git a/apps/extension/src/Approvals/types.ts b/apps/extension/src/Approvals/types.ts index 65ca86b59..1edc4584b 100644 --- a/apps/extension/src/Approvals/types.ts +++ b/apps/extension/src/Approvals/types.ts @@ -6,14 +6,14 @@ export enum TopLevelRoute { // Connection approval ApproveConnection = "/approve-connection", - // Transaction approval - ApproveTx = "/approve-tx", - ConfirmTx = "/confirm-tx", + // Sign Tx approval + ApproveSignTx = "/approve-sign-tx", + ConfirmSignTx = "/confirm-sign-tx", ConfirmLedgerTx = "/confirm-ledger-tx", - // Signing approval - ApproveSignature = "/approve-signature", - ConfirmSignature = "/confirm-signature", + // Sign arbitrary approval + ApproveSignArbitrary = "/approve-sign-arbitrary", + ConfirmSignArbitrary = "/confirm-sign-arbitrary", } export type ApproveMsg = new ( diff --git a/apps/extension/src/Setup/Common/Completion.tsx b/apps/extension/src/Setup/Common/Completion.tsx index 76ab1df58..39fb4f0ff 100644 --- a/apps/extension/src/Setup/Common/Completion.tsx +++ b/apps/extension/src/Setup/Common/Completion.tsx @@ -9,7 +9,6 @@ import { AccountStore, DeriveAccountMsg, SaveAccountSecretMsg, - ScanAccountsMsg, } from "background/keyring"; import { CreatePasswordMsg } from "background/vault"; import { useRequester } from "hooks/useRequester"; @@ -19,7 +18,6 @@ import { Ports } from "router"; type Props = { alias: string; accountSecret?: AccountSecret; - scanAccounts: boolean; password?: string; passwordRequired: boolean | undefined; }; @@ -31,8 +29,7 @@ enum Status { } export const Completion: React.FC = (props) => { - const { alias, accountSecret, password, scanAccounts, passwordRequired } = - props; + const { alias, accountSecret, password, passwordRequired } = props; const [mnemonicStatus, setMnemonicStatus] = useState(Status.Pending); const [statusInfo, setStatusInfo] = useState(""); @@ -74,11 +71,9 @@ export const Completion: React.FC = (props) => { } const prettyAccountSecret = - accountSecret.t === "Mnemonic" - ? "mnemonic" - : accountSecret.t === "PrivateKey" - ? "private key" - : assertNever(accountSecret); + accountSecret.t === "Mnemonic" ? "mnemonic" + : accountSecret.t === "PrivateKey" ? "private key" + : assertNever(accountSecret); setStatusInfo(`Encrypting and storing ${prettyAccountSecret}.`); const account = (await requester.sendMessage( @@ -106,13 +101,6 @@ export const Completion: React.FC = (props) => { setShieldedAccountAddress(shieldedAccount.address); } - if (scanAccounts) { - setStatusInfo("Scanning accounts."); - await requester.sendMessage( - Ports.Background, - new ScanAccountsMsg() - ); - } setMnemonicStatus(Status.Completed); setStatusInfo("Done!"); } catch (e) { diff --git a/apps/extension/src/Setup/Ledger/LedgerConnect.tsx b/apps/extension/src/Setup/Ledger/LedgerConnect.tsx index 5df3c3dbb..d3ef2efcf 100644 --- a/apps/extension/src/Setup/Ledger/LedgerConnect.tsx +++ b/apps/extension/src/Setup/Ledger/LedgerConnect.tsx @@ -1,8 +1,8 @@ +import { Ledger as LedgerApp } from "@heliax/namada-sdk/web"; import { ActionButton, Alert, Image, Stack } from "@namada/components"; import { LedgerError } from "@zondax/ledger-namada"; import { LedgerStep } from "Setup/Common"; import routes from "Setup/routes"; -import { Ledger as LedgerApp } from "background/ledger"; import React, { useState } from "react"; import { useNavigate } from "react-router-dom"; diff --git a/apps/extension/src/Setup/Setup.tsx b/apps/extension/src/Setup/Setup.tsx index 033900a33..a673ab861 100644 --- a/apps/extension/src/Setup/Setup.tsx +++ b/apps/extension/src/Setup/Setup.tsx @@ -201,7 +201,6 @@ export const Setup: React.FC = () => { alias={accountCreationDetails.alias || ""} accountSecret={selectedAccountSecret} password={accountCreationDetails.password || ""} - scanAccounts={false} /> } @@ -264,7 +263,6 @@ export const Setup: React.FC = () => { alias={accountCreationDetails.alias || ""} accountSecret={selectedAccountSecret} password={accountCreationDetails.password || ""} - scanAccounts={false} /> } diff --git a/apps/extension/src/background/approvals/handler.test.ts b/apps/extension/src/background/approvals/handler.test.ts index 171d22c20..6c20e7df6 100644 --- a/apps/extension/src/background/approvals/handler.test.ts +++ b/apps/extension/src/background/approvals/handler.test.ts @@ -1,22 +1,20 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { TxType } from "@heliax/namada-sdk/web"; import { AccountType } from "@namada/types"; import createMockInstance from "jest-create-mock-instance"; import { ApproveConnectInterfaceMsg, ApproveSignArbitraryMsg, - ApproveTxMsg, + ApproveSignTxMsg, IsConnectionApprovedMsg, } from "provider"; import { Message } from "router"; import { getHandler } from "./handler"; import { ConnectInterfaceResponseMsg, - RejectSignatureMsg, - RejectTxMsg, + RejectSignArbitraryMsg, + RejectSignTxMsg, RevokeConnectionMsg, - SubmitApprovedSignatureMsg, - SubmitApprovedTxMsg, + SubmitApprovedSignArbitraryMsg, } from "./messages"; import { ApprovalsService } from "./service"; @@ -48,26 +46,17 @@ describe("approvals handler", () => { requestInteraction: () => {}, }; - const approveTxMsg = new ApproveTxMsg( - TxType.Bond, - [ - { - txMsg: "txMsg", - specificMsg: "specificMsg", - }, - ], - AccountType.Mnemonic + const approveTxMsg = new ApproveSignTxMsg( + AccountType.PrivateKey, + "test", + [] ); handler(env, approveTxMsg); - expect(service.approveTx).toBeCalled(); + expect(service.approveSignTx).toBeCalled(); - const rejectTxMsg = new RejectTxMsg("msgId"); + const rejectTxMsg = new RejectSignTxMsg("msgId"); handler(env, rejectTxMsg); - expect(service.rejectTx).toBeCalled(); - - const submitApprovedTxMsg = new SubmitApprovedTxMsg(TxType.Bond, "msgId"); - handler(env, submitApprovedTxMsg); - expect(service.submitTx).toBeCalled(); + expect(service.rejectSignTx).toBeCalled(); const isConnectionApprovedMsg = new IsConnectionApprovedMsg(); handler(env, isConnectionApprovedMsg); @@ -91,15 +80,18 @@ describe("approvals handler", () => { const approveSignArbitraryMsg = new ApproveSignArbitraryMsg("", ""); handler(env, approveSignArbitraryMsg); - expect(service.approveSignature).toBeCalled(); + expect(service.approveSignArbitrary).toBeCalled(); - const rejectSignatureMsg = new RejectSignatureMsg(""); - handler(env, rejectSignatureMsg); + const rejectSignArbitraryMsg = new RejectSignArbitraryMsg(""); + handler(env, rejectSignArbitraryMsg); expect(service.rejectSignature).toBeCalled(); - const submitApprovedSignatureMsg = new SubmitApprovedSignatureMsg("", ""); - handler(env, submitApprovedSignatureMsg); - expect(service.submitSignature).toBeCalled(); + const submitApprovedSignArbitrartyMsg = new SubmitApprovedSignArbitraryMsg( + "", + "" + ); + handler(env, submitApprovedSignArbitrartyMsg); + expect(service.submitSignArbitrary).toBeCalled(); const unknownMsg = new UnknownMsg(); expect(() => handler(env, unknownMsg)).toThrow(); diff --git a/apps/extension/src/background/approvals/handler.ts b/apps/extension/src/background/approvals/handler.ts index 558eb0253..126aafc30 100644 --- a/apps/extension/src/background/approvals/handler.ts +++ b/apps/extension/src/background/approvals/handler.ts @@ -1,35 +1,23 @@ import { ApproveConnectInterfaceMsg, ApproveSignArbitraryMsg, - ApproveTxMsg, + ApproveSignTxMsg, IsConnectionApprovedMsg, } from "provider"; import { Env, Handler, InternalHandler, Message } from "router"; import { ConnectInterfaceResponseMsg, - QueryPendingTxMsg, - RejectSignatureMsg, - RejectTxMsg, + RejectSignArbitraryMsg, + RejectSignTxMsg, RevokeConnectionMsg, - SubmitApprovedSignatureMsg, - SubmitApprovedTxMsg, + SubmitApprovedSignArbitraryMsg, + SubmitApprovedSignTxMsg, } from "./messages"; import { ApprovalsService } from "./service"; export const getHandler: (service: ApprovalsService) => Handler = (service) => { return (env: Env, msg: Message) => { switch (msg.constructor) { - case ApproveTxMsg: - return handleApproveTxMsg(service)(env, msg as ApproveTxMsg); - case RejectTxMsg: - return handleRejectTxMsg(service)(env, msg as RejectTxMsg); - case SubmitApprovedTxMsg: - return handleSubmitApprovedTxMsg(service)( - env, - msg as SubmitApprovedTxMsg - ); - case QueryPendingTxMsg: - return handleQueryPendingTxMsg(service)(env, msg as QueryPendingTxMsg); case IsConnectionApprovedMsg: return handleIsConnectionApprovedMsg(service)( env, @@ -50,20 +38,29 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => { env, msg as RevokeConnectionMsg ); + case ApproveSignTxMsg: + return handleApproveSignTxMsg(service)(env, msg as ApproveSignTxMsg); + case RejectSignTxMsg: + return handleRejectSignTxMsg(service)(env, msg as RejectSignTxMsg); + case SubmitApprovedSignTxMsg: + return handleSubmitApprovedSignTxMsg(service)( + env, + msg as SubmitApprovedSignTxMsg + ); case ApproveSignArbitraryMsg: return handleApproveSignArbitraryMsg(service)( env, msg as ApproveSignArbitraryMsg ); - case RejectSignatureMsg: - return handleRejectSignatureMsg(service)( + case RejectSignArbitraryMsg: + return handleRejectSignArbitraryMsg(service)( env, - msg as RejectSignatureMsg + msg as RejectSignArbitraryMsg ); - case SubmitApprovedSignatureMsg: - return handleSubmitApprovedSignatureMsg(service)( + case SubmitApprovedSignArbitraryMsg: + return handleSubmitApprovedSignArbitraryMsg(service)( env, - msg as SubmitApprovedSignatureMsg + msg as SubmitApprovedSignArbitraryMsg ); default: @@ -72,38 +69,6 @@ export const getHandler: (service: ApprovalsService) => Handler = (service) => { }; }; -const handleApproveTxMsg: ( - service: ApprovalsService -) => InternalHandler = (service) => { - return async (_, { txType, tx, accountType }) => { - return await service.approveTx(txType, tx, accountType); - }; -}; - -const handleRejectTxMsg: ( - service: ApprovalsService -) => InternalHandler = (service) => { - return async (_, { msgId }) => { - return await service.rejectTx(msgId); - }; -}; - -const handleSubmitApprovedTxMsg: ( - service: ApprovalsService -) => InternalHandler = (service) => { - return async (_, { msgId }) => { - return await service.submitTx(msgId); - }; -}; - -const handleQueryPendingTxMsg: ( - service: ApprovalsService -) => InternalHandler = (service) => { - return async (_, { msgId }) => { - return await service.queryPendingTx(msgId); - }; -}; - const handleIsConnectionApprovedMsg: ( service: ApprovalsService ) => InternalHandler = (service) => { @@ -144,26 +109,50 @@ const handleRevokeConnectionMsg: ( }; }; +const handleApproveSignTxMsg: ( + service: ApprovalsService +) => InternalHandler = (service) => { + return async (_, { accountType, signer, tx }) => { + return await service.approveSignTx(accountType, signer, tx); + }; +}; + +const handleRejectSignTxMsg: ( + service: ApprovalsService +) => InternalHandler = (service) => { + return async (_, { msgId }) => { + return await service.rejectSignTx(msgId); + }; +}; + +const handleSubmitApprovedSignTxMsg: ( + service: ApprovalsService +) => InternalHandler = (service) => { + return async ({ senderTabId: popupTabId }, { msgId, signer }) => { + return await service.submitSignTx(popupTabId, msgId, signer); + }; +}; + const handleApproveSignArbitraryMsg: ( service: ApprovalsService ) => InternalHandler = (service) => { return async (_, { signer, data }) => { - return await service.approveSignature(signer, data); + return await service.approveSignArbitrary(signer, data); }; }; -const handleRejectSignatureMsg: ( +const handleRejectSignArbitraryMsg: ( service: ApprovalsService -) => InternalHandler = (service) => { +) => InternalHandler = (service) => { return async ({ senderTabId: popupTabId }, { msgId }) => { return await service.rejectSignature(popupTabId, msgId); }; }; -const handleSubmitApprovedSignatureMsg: ( +const handleSubmitApprovedSignArbitraryMsg: ( service: ApprovalsService -) => InternalHandler = (service) => { +) => InternalHandler = (service) => { return async ({ senderTabId: popupTabId }, { msgId, signer }) => { - return await service.submitSignature(popupTabId, msgId, signer); + return await service.submitSignArbitrary(popupTabId, msgId, signer); }; }; diff --git a/apps/extension/src/background/approvals/init.ts b/apps/extension/src/background/approvals/init.ts index 82addab53..af1fcae5f 100644 --- a/apps/extension/src/background/approvals/init.ts +++ b/apps/extension/src/background/approvals/init.ts @@ -1,18 +1,17 @@ import { ApproveConnectInterfaceMsg, ApproveSignArbitraryMsg, - ApproveTxMsg, + ApproveSignTxMsg, IsConnectionApprovedMsg, } from "provider"; import { Router } from "router"; import { ConnectInterfaceResponseMsg, - QueryPendingTxMsg, - RejectSignatureMsg, - RejectTxMsg, + RejectSignArbitraryMsg, + RejectSignTxMsg, RevokeConnectionMsg, - SubmitApprovedSignatureMsg, - SubmitApprovedTxMsg, + SubmitApprovedSignArbitraryMsg, + SubmitApprovedSignTxMsg, } from "./messages"; import { ROUTE } from "./constants"; @@ -20,13 +19,12 @@ import { getHandler } from "./handler"; import { ApprovalsService } from "./service"; export function init(router: Router, service: ApprovalsService): void { - router.registerMessage(ApproveTxMsg); - router.registerMessage(RejectTxMsg); - router.registerMessage(QueryPendingTxMsg); - router.registerMessage(SubmitApprovedTxMsg); + router.registerMessage(ApproveSignTxMsg); router.registerMessage(ApproveSignArbitraryMsg); - router.registerMessage(RejectSignatureMsg); - router.registerMessage(SubmitApprovedSignatureMsg); + router.registerMessage(RejectSignTxMsg); + router.registerMessage(RejectSignArbitraryMsg); + router.registerMessage(SubmitApprovedSignTxMsg); + router.registerMessage(SubmitApprovedSignArbitraryMsg); router.registerMessage(IsConnectionApprovedMsg); router.registerMessage(ApproveConnectInterfaceMsg); router.registerMessage(ConnectInterfaceResponseMsg); diff --git a/apps/extension/src/background/approvals/messages.test.ts b/apps/extension/src/background/approvals/messages.test.ts index 687217b33..ab6cbe770 100644 --- a/apps/extension/src/background/approvals/messages.test.ts +++ b/apps/extension/src/background/approvals/messages.test.ts @@ -1,84 +1,62 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { TxType } from "@heliax/namada-sdk/web"; import { ROUTE } from "./constants"; import { ConnectInterfaceResponseMsg, MessageType, - RejectSignatureMsg, - RejectTxMsg, + RejectSignArbitraryMsg, + RejectSignTxMsg, RevokeConnectionMsg, - SubmitApprovedSignatureMsg, - SubmitApprovedTxMsg, + SubmitApprovedSignArbitraryMsg, } from "./messages"; jest.mock("webextension-polyfill", () => ({})); describe("approvals messages", () => { - test("valid RejectTxMsg", () => { - const msg = new RejectTxMsg("msgId"); + test("valid RejectSignTxMsg", () => { + const msg = new RejectSignTxMsg("msgId"); - expect(msg.type()).toBe(MessageType.RejectTx); + expect(msg.type()).toBe(MessageType.RejectSignTx); expect(msg.route()).toBe(ROUTE); expect(msg.validate()).toBeUndefined(); }); - test("invalid RejectTxMsg", () => { - const msg = new RejectTxMsg("msgId"); + test("invalid RejectSignTxMsg", () => { + const msg = new RejectSignTxMsg("msgId"); (msg as any).msgId = undefined; expect(() => msg.validate()).toThrow(); }); - test("valid SubmitApprovedTxMsg", () => { - const msg = new SubmitApprovedTxMsg(TxType.Bond, "msgId"); + test("valid RejectSignArbitraryMsg", () => { + const msg = new RejectSignArbitraryMsg("msgId"); - expect(msg.type()).toBe(MessageType.SubmitApprovedTx); + expect(msg.type()).toBe(MessageType.RejectSignArbitrary); expect(msg.route()).toBe(ROUTE); expect(msg.validate()).toBeUndefined(); }); - test("invalid SubmitApprovedTxMsg", () => { - const msg = new SubmitApprovedTxMsg(TxType.Bond, "msgId"); - (msg as any).msgId = undefined; - - expect(() => msg.validate()).toThrow(); - - const msg2 = new SubmitApprovedTxMsg(TxType.Bond, "msgId"); - (msg2 as any).txType = undefined; - - expect(() => msg2.validate()).toThrow(); - }); - - test("valid RejectSignatureMsg", () => { - const msg = new RejectSignatureMsg("msgId"); - - expect(msg.type()).toBe(MessageType.RejectSignature); - expect(msg.route()).toBe(ROUTE); - expect(msg.validate()).toBeUndefined(); - }); - - test("invalid RejectSignatureMsg", () => { - const msg = new RejectSignatureMsg("msgId"); + test("invalid RejectSignArbitraryMsg", () => { + const msg = new RejectSignArbitraryMsg("msgId"); (msg as any).msgId = undefined; expect(() => msg.validate()).toThrow(); }); test("valid SubmitApprovedSignatureMsg", () => { - const msg = new SubmitApprovedSignatureMsg("msgId", "signer"); + const msg = new SubmitApprovedSignArbitraryMsg("msgId", "signer"); - expect(msg.type()).toBe(MessageType.SubmitApprovedSignature); + expect(msg.type()).toBe(MessageType.SubmitApprovedSignArbitrary); expect(msg.route()).toBe(ROUTE); expect(msg.validate()).toBeUndefined(); }); - test("invalid SubmitApprovedSignatureMsg", () => { - const msg = new SubmitApprovedSignatureMsg("msgId", "signer"); + test("invalid SubmitApprovedSignArbitraryMsg", () => { + const msg = new SubmitApprovedSignArbitraryMsg("msgId", "signer"); (msg as any).msgId = undefined; expect(() => msg.validate()).toThrow(); - const msg2 = new SubmitApprovedSignatureMsg("msgId", "signer"); + const msg2 = new SubmitApprovedSignArbitraryMsg("msgId", "signer"); (msg2 as any).signer = undefined; expect(() => msg2.validate()).toThrow(); diff --git a/apps/extension/src/background/approvals/messages.ts b/apps/extension/src/background/approvals/messages.ts index acd0069fd..4983d1573 100644 --- a/apps/extension/src/background/approvals/messages.ts +++ b/apps/extension/src/background/approvals/messages.ts @@ -1,56 +1,31 @@ -import { SupportedTx } from "@heliax/namada-sdk/web"; import { Message } from "router"; import { ROUTE } from "./constants"; import { validateProps } from "utils"; -import { PendingTxDetails } from "./types"; export enum MessageType { - RejectTx = "reject-tx", - SubmitApprovedTx = "submit-approved-tx", - QueryPendingTx = "query-pending-tx", - SubmitApprovedSignature = "submit-approved-signature", - RejectSignature = "reject-signature", + RejectSignTx = "reject-sign-tx", + SubmitApprovedSignTx = "submit-approved-sign-tx", + SubmitApprovedSignArbitrary = "submit-approved-sign-arbitrary", + RejectSignArbitrary = "reject-sign-arbitrary", ConnectInterfaceResponse = "connect-interface-response", RevokeConnection = "revoke-connection", } -export class RejectTxMsg extends Message { +export class SubmitApprovedSignTxMsg extends Message { public static type(): MessageType { - return MessageType.RejectTx; - } - - constructor(public readonly msgId: string) { - super(); - } - - validate(): void { - validateProps(this, ["msgId"]); - } - - route(): string { - return ROUTE; - } - - type(): string { - return RejectTxMsg.type(); - } -} - -export class SubmitApprovedTxMsg extends Message { - public static type(): MessageType { - return MessageType.SubmitApprovedTx; + return MessageType.SubmitApprovedSignTx; } constructor( - public readonly txType: SupportedTx, - public readonly msgId: string + public readonly msgId: string, + public readonly signer: string ) { super(); } validate(): void { - validateProps(this, ["txType", "msgId"]); + validateProps(this, ["msgId", "signer"]); } route(): string { @@ -58,13 +33,13 @@ export class SubmitApprovedTxMsg extends Message { } type(): string { - return SubmitApprovedTxMsg.type(); + return SubmitApprovedSignTxMsg.type(); } } -export class QueryPendingTxMsg extends Message { +export class RejectSignTxMsg extends Message { public static type(): MessageType { - return MessageType.QueryPendingTx; + return MessageType.RejectSignTx; } constructor(public readonly msgId: string) { @@ -80,13 +55,13 @@ export class QueryPendingTxMsg extends Message { } type(): string { - return QueryPendingTxMsg.type(); + return RejectSignTxMsg.type(); } } -export class SubmitApprovedSignatureMsg extends Message { +export class SubmitApprovedSignArbitraryMsg extends Message { public static type(): MessageType { - return MessageType.SubmitApprovedSignature; + return MessageType.SubmitApprovedSignArbitrary; } constructor( @@ -105,13 +80,13 @@ export class SubmitApprovedSignatureMsg extends Message { } type(): string { - return SubmitApprovedSignatureMsg.type(); + return SubmitApprovedSignArbitraryMsg.type(); } } -export class RejectSignatureMsg extends Message { +export class RejectSignArbitraryMsg extends Message { public static type(): MessageType { - return MessageType.RejectSignature; + return MessageType.RejectSignArbitrary; } constructor(public readonly msgId: string) { @@ -128,7 +103,7 @@ export class RejectSignatureMsg extends Message { } type(): string { - return RejectSignatureMsg.type(); + return RejectSignArbitraryMsg.type(); } } diff --git a/apps/extension/src/background/approvals/service.test.ts b/apps/extension/src/background/approvals/service.test.ts index f8a6681e4..21c461b67 100644 --- a/apps/extension/src/background/approvals/service.test.ts +++ b/apps/extension/src/background/approvals/service.test.ts @@ -1,29 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as borsh from "@dao-xyz/borsh"; -import { TxType } from "@heliax/namada-sdk/web"; -import { - AccountType, - BondMsgValue, - EthBridgeTransferMsgValue, - IbcTransferMsgValue, - TokenInfo, - TransferMsgValue, - UnbondMsgValue, - VoteProposalMsgValue, - WithdrawMsgValue, -} from "@namada/types"; import { paramsToUrl } from "@namada/utils"; import { KeyRingService } from "background/keyring"; -import { LedgerService } from "background/ledger"; import { VaultService } from "background/vault"; -import BigNumber from "bignumber.js"; import { ExtensionBroadcaster } from "extension"; import createMockInstance from "jest-create-mock-instance"; import { LocalStorage } from "storage"; import { KVStoreMock } from "test/init"; import * as webextensionPolyfill from "webextension-polyfill"; import { ApprovalsService } from "./service"; -import { TxStore } from "./types"; +import { PendingTx } from "./types"; jest.mock("webextension-polyfill", () => ({ runtime: { @@ -55,7 +40,7 @@ describe("approvals service", () => { let service: ApprovalsService; let keyRingService: jest.Mocked; let dataStore: KVStoreMock; - let txStore: KVStoreMock; + let txStore: KVStoreMock; let localStorage: LocalStorage; afterEach(() => { @@ -64,12 +49,9 @@ describe("approvals service", () => { beforeEach(() => { jest.clearAllMocks(); - txStore = new KVStoreMock("TxStore"); + txStore = new KVStoreMock("PendingTx"); dataStore = new KVStoreMock("DataStore"); keyRingService = createMockInstance(KeyRingService as any); - const ledgerService: jest.Mocked = createMockInstance( - LedgerService as any - ); const vaultService: jest.Mocked = createMockInstance( VaultService as any ); @@ -82,7 +64,6 @@ describe("approvals service", () => { dataStore, localStorage, keyRingService, - ledgerService, vaultService, broadcaster ); @@ -96,7 +77,7 @@ describe("approvals service", () => { signature: "sig", }; - const signaturePromise = service.approveSignature("signer", "data"); + const signaturePromise = service.approveSignArbitrary("signer", "data"); await new Promise((resolve) => setTimeout(() => { @@ -116,7 +97,7 @@ describe("approvals service", () => { }); await expect( - service.approveSignature("signer", "data") + service.approveSignArbitrary("signer", "data") ).rejects.toBeDefined(); }); @@ -132,7 +113,7 @@ describe("approvals service", () => { (service as any).resolverMap[tabId] = sigResponse; await expect( - service.approveSignature("signer", "data") + service.approveSignArbitrary("signer", "data") ).rejects.toBeDefined(); }); }); @@ -153,14 +134,14 @@ describe("approvals service", () => { .spyOn(keyRingService, "signArbitrary") .mockResolvedValue(sigResponse); const signer = "signer"; - const signaturePromise = service.approveSignature(signer, "data"); + const signaturePromise = service.approveSignArbitrary(signer, "data"); await new Promise((resolve) => setTimeout(() => { resolve(true); }) ); - await service.submitSignature(tabId, "msgId", signer); + await service.submitSignArbitrary(tabId, "msgId", signer); expect(await signaturePromise).toEqual(sigResponse); }); @@ -171,7 +152,7 @@ describe("approvals service", () => { jest.spyOn(dataStore, "get").mockResolvedValueOnce("data"); await expect( - service.submitSignature(tabId, "msgId", signer) + service.submitSignArbitrary(tabId, "msgId", signer) ).rejects.toBeDefined(); }); @@ -186,7 +167,7 @@ describe("approvals service", () => { jest.spyOn(dataStore, "get").mockResolvedValueOnce(undefined); await expect( - service.submitSignature(tabId, "msgId", signer) + service.submitSignArbitrary(tabId, "msgId", signer) ).rejects.toBeDefined(); }); @@ -212,7 +193,7 @@ describe("approvals service", () => { ); await expect( - service.submitSignature(tabId, "msgId", signer) + service.submitSignArbitrary(tabId, "msgId", signer) ).resolves.toBeUndefined(); expect(service["resolverMap"][tabId].reject).toHaveBeenCalled(); @@ -223,7 +204,7 @@ describe("approvals service", () => { it("should reject resolver", async () => { const tabId = 1; const signer = "signer"; - const signaturePromise = service.approveSignature(signer, "data"); + const signaturePromise = service.approveSignArbitrary(signer, "data"); (webextensionPolyfill.windows.create as any).mockResolvedValue({ tabs: [{ id: tabId }], @@ -247,364 +228,30 @@ describe("approvals service", () => { }); }); - const txTypes = [ - [TxType.Bond, "getParamsBond"], - [TxType.Unbond, "getParamsUnbond"], - [TxType.Withdraw, "getParamsWithdraw"], - [TxType.Transfer, "getParamsTransfer"], - [TxType.IBCTransfer, "getParamsIbcTransfer"], - [TxType.EthBridgeTransfer, "getParamsEthBridgeTransfer"], - [TxType.VoteProposal, "getParamsVoteProposal"], - ] as const; - - describe("approveTx", () => { - it.each(txTypes)("%i txType fn: %s", async (type, paramsFn) => { - jest.spyOn(ApprovalsService, paramsFn).mockImplementation(() => ({})); - jest.spyOn(borsh, "deserialize").mockReturnValue({}); - jest.spyOn(service as any, "_launchApprovalWindow"); - - try { - const res = await service.approveTx( - type, - [{ specificMsg: "", txMsg: "" }], - AccountType.Mnemonic - ); - expect(res).toBeUndefined(); - } catch (e) {} - }); - }); - - describe("getParamsTransfer", () => { - it("should return transfer params", () => { - const transferMsgValue = new TransferMsgValue({ - source: "source", - target: "target", - token: "token", - amount: BigNumber(100), - nativeToken: "nativeToken", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); - - const params = ApprovalsService.getParamsTransfer( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: transferMsgValue.source, - target: transferMsgValue.target, - tokenAddress: transferMsgValue.token, - amount: transferMsgValue.amount.toString(), - publicKey: txMsgValue.publicKey, - nativeToken: transferMsgValue.token, - }); - }); - }); - - describe("getParamsIbcTransfer", () => { - it("should return transfer params", () => { - const token: TokenInfo = { - symbol: "symbol", - type: 0, - path: 0, - coin: "coin", - url: "url", - address: "address", - minDenom: "minDenom", - decimals: 0, - }; - - const transferMsgValue = new IbcTransferMsgValue({ - source: "source", - receiver: "target", - token: token.address, - amount: BigNumber(100), - portId: "portId", - channelId: "channelId", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); - - const params = ApprovalsService.getParamsIbcTransfer( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: transferMsgValue.source, - target: transferMsgValue.receiver, - tokenAddress: transferMsgValue.token, - amount: transferMsgValue.amount.toString(), - publicKey: txMsgValue.publicKey, - nativeToken: txMsgValue.token, - }); - }); - }); - - describe("getParamsEthBridgeTransfer", () => { - it("should return transfer params", () => { - const transferMsgValue = new EthBridgeTransferMsgValue({ - nut: false, - asset: "asset", - recipient: "recipient", - sender: "sender", - amount: BigNumber(100), - feeAmount: BigNumber(0.5), - feeToken: "feeToken", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(transferMsgValue); - - const params = ApprovalsService.getParamsEthBridgeTransfer( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: transferMsgValue.sender, - target: transferMsgValue.recipient, - tokenAddress: transferMsgValue.asset, - amount: transferMsgValue.amount.toString(), - publicKey: txMsgValue.publicKey, - nativeToken: txMsgValue.token, - }); - }); - }); - - describe("getParamsBond", () => { - it("should return bond params", () => { - const bondMsgValue = new BondMsgValue({ - source: "source", - validator: "validator", - amount: BigNumber(100), - nativeToken: "nativeToken", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(bondMsgValue); - - const params = ApprovalsService.getParamsBond( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: bondMsgValue.source, - tokenAddress: bondMsgValue.nativeToken, - amount: bondMsgValue.amount.toString(), - publicKey: txMsgValue.publicKey, - nativeToken: bondMsgValue.nativeToken, - validator: bondMsgValue.validator, - }); - }); - }); - - describe("getParamsUnbond", () => { - it("should return unbond params", () => { - const unbondMsgValue = new UnbondMsgValue({ - source: "source", - validator: "validator", - amount: BigNumber(100), - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(unbondMsgValue); - - const params = ApprovalsService.getParamsUnbond( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: unbondMsgValue.source, - amount: unbondMsgValue.amount.toString(), - validator: unbondMsgValue.validator, - publicKey: txMsgValue.publicKey, - nativeToken: txMsgValue.token, - }); - }); - }); - - describe("getParamsWithdraw", () => { - it("should return withdraw params", () => { - const withdrawMsgValue = new WithdrawMsgValue({ - source: "source", - validator: "validator", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(withdrawMsgValue); - - const params = ApprovalsService.getParamsWithdraw( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: withdrawMsgValue.source, - validator: withdrawMsgValue.validator, - publicKey: txMsgValue.publicKey, - nativeToken: txMsgValue.token, - }); - }); - }); - - describe("getParamsVoteProposal", () => { - it("should return vote proposal params", () => { - const voteProposalMsgValue = new VoteProposalMsgValue({ - signer: "singer", - proposalId: BigInt(0), - vote: "yay", - }); - - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - jest.spyOn(borsh, "deserialize").mockReturnValue(voteProposalMsgValue); - - const params = ApprovalsService.getParamsVoteProposal( - new Uint8Array([]), - txMsgValue - ); - - expect(params).toEqual({ - source: voteProposalMsgValue.signer, - publicKey: txMsgValue.publicKey, - nativeToken: txMsgValue.token, - }); - }); - }); - - describe("rejectTx", () => { + // describe("approveTx", () => { + // it.each(txTypes)("%i txType fn: %s", async (type, paramsFn) => { + // jest.spyOn(service as any, "_launchApprovalWindow"); + // + // try { + // const res = await service.approveTx( + // type, + // tx, + // AccountType.Mnemonic + // ); + // expect(res).toBeUndefined(); + // } catch (e) {} + // }); + // }); + + describe("rejectSignTx", () => { it("should clear pending tx", async () => { jest.spyOn(service as any, "_clearPendingTx"); - await service.rejectTx("msgId"); + await service.rejectSignTx("msgId"); expect((service as any)._clearPendingTx).toHaveBeenCalledWith("msgId"); }); }); - const submitTxTypes = [ - [TxType.Bond, "submitBond"], - [TxType.Unbond, "submitUnbond"], - [TxType.Withdraw, "submitWithdraw"], - [TxType.Transfer, "submitTransfer"], - [TxType.IBCTransfer, "submitIbcTransfer"], - [TxType.EthBridgeTransfer, "submitEthBridgeTransfer"], - [TxType.VoteProposal, "submitVoteProposal"], - ] as const; - - describe("submitTx", () => { - it.each(submitTxTypes)("%i txType fn: %s", async (txType, paramsFn) => { - const msgId = "msgId"; - const txMsg = "txMsg"; - const specificMsg = "specificMsg"; - - jest.spyOn(service["txStore"], "get").mockImplementation(() => { - return Promise.resolve({ - txType, - tx: [ - { - txMsg, - specificMsg, - }, - ], - }); - }); - - jest.spyOn(keyRingService, paramsFn).mockResolvedValue(); - jest.spyOn(service as any, "_clearPendingTx"); - - await service.submitTx(msgId); - expect(service["_clearPendingTx"]).toHaveBeenCalledWith(msgId); - expect(keyRingService[paramsFn]).toHaveBeenCalledWith( - specificMsg, - txMsg, - msgId - ); - }); - - it("should throw an error if txType is not found", async () => { - const msgId = "msgId"; - const txMsg = "txMsg"; - const specificMsg = "specificMsg"; - const txType: any = 999; - - jest.spyOn(service["txStore"], "get").mockImplementation(() => { - return Promise.resolve({ - txType, - tx: [ - { - txMsg, - specificMsg, - }, - ], - }); - }); - - await expect(service.submitTx(msgId)).rejects.toBeDefined(); - }); - - it("should throw an error if tx is not found", async () => { - jest.spyOn(service["txStore"], "get").mockImplementation(() => { - return Promise.resolve(undefined); - }); - - await expect(service.submitTx("msgId")).rejects.toBeDefined(); - }); - }); - describe("approveConnection", () => { it("should approve connection if it's not already approved", async () => { const url = "url-with-params"; @@ -801,41 +448,6 @@ describe("approvals service", () => { }); }); - describe("getTxDetails", () => { - it("should return tx details", () => { - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - publicKey: "publicKey", - }; - - const { publicKey, nativeToken } = (ApprovalsService as any).getTxDetails( - txMsgValue - ); - - expect(publicKey).toEqual(txMsgValue.publicKey); - expect(nativeToken).toEqual(txMsgValue.token); - }); - - it("should return tx details with empty publicKey when missing", () => { - const txMsgValue = { - token: "token", - feeAmount: BigNumber(0.5), - gasLimit: BigNumber(0.5), - chainId: "chainId", - }; - - const { publicKey, nativeToken } = (ApprovalsService as any).getTxDetails( - txMsgValue - ); - - expect(publicKey).toEqual(""); - expect(nativeToken).toEqual(txMsgValue.token); - }); - }); - describe("isConnectionApproved", () => { it("should return true if origin is approved", async () => { const origin = "origin"; diff --git a/apps/extension/src/background/approvals/service.ts b/apps/extension/src/background/approvals/service.ts index 16659c03b..3676e3ee6 100644 --- a/apps/extension/src/background/approvals/service.ts +++ b/apps/extension/src/background/approvals/service.ts @@ -1,50 +1,17 @@ import { fromBase64 } from "@cosmjs/encoding"; -import { deserialize } from "@dao-xyz/borsh"; -import BigNumber from "bignumber.js"; import { v4 as uuid } from "uuid"; import browser, { Windows } from "webextension-polyfill"; -import { SupportedTx, TxType } from "@heliax/namada-sdk/web"; +import { BuiltTx } from "@namada/shared"; import { KVStore } from "@namada/storage"; -import { - AccountType, - BondMsgValue, - EthBridgeTransferMsgValue, - IbcTransferMsgValue, - RedelegateMsgValue, - SignatureResponse, - TransferMsgValue, - TxMsgValue, - UnbondMsgValue, - VoteProposalMsgValue, - WithdrawMsgValue, -} from "@namada/types"; - -import { assertNever, paramsToUrl } from "@namada/utils"; -import { KeyRingService } from "background/keyring"; -import { LedgerService } from "background/ledger"; +import { AccountType, SignArbitraryResponse } from "@namada/types"; +import { paramsToUrl } from "@namada/utils"; +import { KeyRingService } from "background/keyring"; import { VaultService } from "background/vault"; import { ExtensionBroadcaster } from "extension"; import { LocalStorage } from "storage"; -import { PendingTx, PendingTxDetails, TxStore } from "./types"; - -type GetParams = ( - specificMsg: Uint8Array, - txDetails: TxMsgValue -) => Record; - -const getParamsMethod = (txType: SupportedTx): GetParams => - txType === TxType.Bond ? ApprovalsService.getParamsBond - : txType === TxType.Unbond ? ApprovalsService.getParamsUnbond - : txType === TxType.Withdraw ? ApprovalsService.getParamsWithdraw - : txType === TxType.Transfer ? ApprovalsService.getParamsTransfer - : txType === TxType.IBCTransfer ? ApprovalsService.getParamsIbcTransfer - : txType === TxType.EthBridgeTransfer ? - ApprovalsService.getParamsEthBridgeTransfer - : txType === TxType.VoteProposal ? ApprovalsService.getParamsVoteProposal - : txType === TxType.Redelegate ? ApprovalsService.getParamsRedelegate - : assertNever(txType); +import { PendingTx } from "./types"; export class ApprovalsService { // holds promises which can be resolved with a message from a pop-up window @@ -56,44 +23,61 @@ export class ApprovalsService { > = {}; constructor( - protected readonly txStore: KVStore, + protected readonly txStore: KVStore, protected readonly dataStore: KVStore, protected readonly localStorage: LocalStorage, protected readonly keyRingService: KeyRingService, - protected readonly ledgerService: LedgerService, protected readonly vaultService: VaultService, protected readonly broadcaster: ExtensionBroadcaster ) {} - async queryPendingTx(msgId: string): Promise { - const storedTx = await this.txStore.get(msgId); + async approveSignTx( + accountType: AccountType, + signer: string, + // TODO: Pass serialized BuiltTxMsgValue instead of these: + tx: string[][] + ): Promise { + const msgId = uuid(); + + const pendingTx = tx.map(([txBytes, signingDataBytes]) => ({ + txBytes: fromBase64(txBytes), + signingDataBytes: fromBase64(signingDataBytes), + })); + + await this.txStore.set(msgId, { + tx: pendingTx, + signer, + }); + + const url = `${browser.runtime.getURL( + "approvals.html" + )}#/approve-sign-tx/${msgId}/${accountType}/${signer}`; + + const popupTabId = await this.getPopupTabId(url); - if (!storedTx) { - throw new Error("Pending tx not found!"); + if (!popupTabId) { + throw new Error("no popup tab ID"); } - const { txType } = storedTx; + if (popupTabId in this.resolverMap) { + throw new Error(`tab ID ${popupTabId} already exists in promise map`); + } - return storedTx.tx.map((pendingTx: PendingTx) => { - const { specificMsg, txMsg } = pendingTx; - const specificMsgBuffer = Buffer.from(fromBase64(specificMsg)); - const txMsgBuffer = Buffer.from(fromBase64(txMsg)); - const txDetails = deserialize(txMsgBuffer, TxMsgValue); - const details = getParamsMethod(txType)(specificMsgBuffer, txDetails); - return details; + return await new Promise((resolve, reject) => { + this.resolverMap[popupTabId] = { resolve, reject }; }); } - async approveSignature( + async approveSignArbitrary( signer: string, data: string - ): Promise { + ): Promise { const msgId = uuid(); await this.dataStore.set(msgId, data); const baseUrl = `${browser.runtime.getURL( "approvals.html" - )}#/approve-signature/${signer}`; + )}#/approve-sign-arbitrary/${signer}`; const url = paramsToUrl(baseUrl, { msgId, @@ -114,7 +98,38 @@ export class ApprovalsService { }); } - async submitSignature( + async submitSignTx( + popupTabId: number, + msgId: string, + signer: string + ): Promise { + const pendingTx = await this.txStore.get(msgId); + console.log("encodedTx", pendingTx); + const resolvers = this.resolverMap[popupTabId]; + + if (!resolvers) { + throw new Error(`no resolvers found for tab ID ${popupTabId}`); + } + + if (!pendingTx) { + throw new Error(`Signing data for ${msgId} not found!`); + } + + const builtTx = pendingTx.tx.map(({ txBytes, signingDataBytes }) => + BuiltTx.from_stored_tx(txBytes, signingDataBytes) + ); + + try { + const signature = await this.keyRingService.sign(builtTx, signer); + resolvers.resolve(signature); + } catch (e) { + resolvers.reject(e); + } + + await this._clearPendingSignature(msgId); + } + + async submitSignArbitrary( popupTabId: number, msgId: string, signer: string @@ -152,215 +167,11 @@ export class ApprovalsService { resolvers.reject(); } - async approveTx( - txType: SupportedTx, - tx: PendingTx[], - type: AccountType - ): Promise { - const msgId = uuid(); - await this.txStore.set(msgId, { txType, tx }); - - const url = `${browser.runtime.getURL( - "approvals.html" - )}#/approve-tx/${msgId}/${txType}/${type}`; - - await this._launchApprovalWindow(url); - } - - static getParamsTransfer: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, TransferMsgValue); - - const { - source, - target, - token: tokenAddress, - amount: amountBN, - } = specificDetails; - const amount = new BigNumber(amountBN.toString()); - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - target, - tokenAddress, - amount: amount.toString(), - publicKey, - nativeToken, - }; - }; - - static getParamsIbcTransfer: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, IbcTransferMsgValue); - - const { - source, - receiver: target, - token: tokenAddress, - amount: amountBN, - } = specificDetails; - const amount = new BigNumber(amountBN.toString()); - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - target, - tokenAddress, - amount: amount.toString(), - publicKey, - nativeToken, - }; - }; - - static getParamsEthBridgeTransfer: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, EthBridgeTransferMsgValue); - - const { - asset: tokenAddress, - recipient: target, - sender: source, - amount, - } = specificDetails; - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - target, - tokenAddress, - amount: amount.toString(), - publicKey, - nativeToken, - }; - }; - - static getParamsBond: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, BondMsgValue); - - const { - source, - nativeToken: tokenAddress, - amount: amountBN, - validator, - } = specificDetails; - const amount = new BigNumber(amountBN.toString()); - - const { publicKey } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - tokenAddress, - amount: amount.toString(), - publicKey, - nativeToken: tokenAddress, - validator, - }; - }; - - static getParamsUnbond: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, UnbondMsgValue); - - const { source, amount: amountBN, validator } = specificDetails; - const amount = new BigNumber(amountBN.toString()); - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - amount: amount.toString(), - publicKey, - nativeToken, - validator, - }; - }; - - static getParamsWithdraw: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, WithdrawMsgValue); - - const { source, validator } = specificDetails; - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source, - validator, - publicKey, - nativeToken, - }; - }; - - static getParamsVoteProposal: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, VoteProposalMsgValue); - - const { signer } = specificDetails; - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - //TODO: check this - return { - source: signer, - publicKey, - nativeToken, - }; - }; - - static getParamsRedelegate: GetParams = (specificMsg, txDetails) => { - const specificDetails = deserialize(specificMsg, RedelegateMsgValue); - - const { owner, sourceValidator, destinationValidator } = specificDetails; - - const { publicKey, nativeToken } = ApprovalsService.getTxDetails(txDetails); - - return { - source: owner, - sourceValidator, - destinationValidator, - publicKey, - nativeToken, - }; - }; - // Remove pending transaction from storage - async rejectTx(msgId: string): Promise { + async rejectSignTx(msgId: string): Promise { await this._clearPendingTx(msgId); } - // Authenticate keyring and submit approved transaction from storage - async submitTx(msgId: string): Promise { - // Fetch pending transfer tx - const storedTx = await this.txStore.get(msgId); - - if (!storedTx) { - throw new Error("Pending tx not found!"); - } - - const { txType } = storedTx; - - await Promise.all( - storedTx.tx.map(async (pendingTx: PendingTx) => { - const { specificMsg, txMsg } = pendingTx; - const submitFn = - txType === TxType.Bond ? this.keyRingService.submitBond - : txType === TxType.Unbond ? this.keyRingService.submitUnbond - : txType === TxType.Transfer ? this.keyRingService.submitTransfer - : txType === TxType.IBCTransfer ? - this.keyRingService.submitIbcTransfer - : txType === TxType.EthBridgeTransfer ? - this.keyRingService.submitEthBridgeTransfer - : txType === TxType.Withdraw ? this.keyRingService.submitWithdraw - : txType === TxType.VoteProposal ? - this.keyRingService.submitVoteProposal - : txType === TxType.Redelegate ? this.keyRingService.submitRedelegate - : assertNever(txType); - - await submitFn.call(this.keyRingService, specificMsg, txMsg, msgId); - }) - ); - - return await this._clearPendingTx(msgId); - } - async isConnectionApproved(interfaceOrigin: string): Promise { const approvedOrigins = (await this.localStorage.getApprovedOrigins()) || []; @@ -455,11 +266,4 @@ export class ApprovalsService { return popupTabId; }; - - private static getTxDetails = ( - txDetails: TxMsgValue - ): { publicKey: string; nativeToken: string } => { - const { publicKey = "", token: nativeToken } = txDetails; - return { publicKey, nativeToken }; - }; } diff --git a/apps/extension/src/background/approvals/types.ts b/apps/extension/src/background/approvals/types.ts index 40ad2887f..ce7110796 100644 --- a/apps/extension/src/background/approvals/types.ts +++ b/apps/extension/src/background/approvals/types.ts @@ -3,14 +3,14 @@ import { SupportedTx } from "@heliax/namada-sdk/web"; export type ApprovedOriginsStore = string[]; export type PendingTx = { - txMsg: string; - specificMsg: string; + tx: { + txBytes: Uint8Array; + signingDataBytes: Uint8Array; + }[]; + signer: string; }; export type TxStore = { txType: SupportedTx; tx: PendingTx[]; }; - -// TODO: Add specific types here! -export type PendingTxDetails = Record; diff --git a/apps/extension/src/background/chains/handler.ts b/apps/extension/src/background/chains/handler.ts index 40d84ae17..bf70cec80 100644 --- a/apps/extension/src/background/chains/handler.ts +++ b/apps/extension/src/background/chains/handler.ts @@ -27,7 +27,7 @@ const handleGetChainMsg: ( const handleUpdateChainMsg: ( service: ChainsService ) => InternalHandler = (service) => { - return async (_, { chainId, url }) => { - return await service.updateChain(chainId, url); + return async (_, { chainId }) => { + return await service.updateChain(chainId); }; }; diff --git a/apps/extension/src/background/chains/messages.ts b/apps/extension/src/background/chains/messages.ts index 265e1ccc5..e47afcb64 100644 --- a/apps/extension/src/background/chains/messages.ts +++ b/apps/extension/src/background/chains/messages.ts @@ -10,10 +10,7 @@ export class UpdateChainMsg extends Message { return MessageType.UpdateChain; } - constructor( - public readonly chainId: string, - public readonly url: string - ) { + constructor(public readonly chainId: string) { super(); } @@ -21,9 +18,6 @@ export class UpdateChainMsg extends Message { if (!this.chainId) { throw new Error("Chain ID not provided!"); } - if (!this.url) { - throw new Error("URL not provided!"); - } } route(): string { diff --git a/apps/extension/src/background/chains/service.ts b/apps/extension/src/background/chains/service.ts index 3c043d0f8..8b673847e 100644 --- a/apps/extension/src/background/chains/service.ts +++ b/apps/extension/src/background/chains/service.ts @@ -11,58 +11,24 @@ export class ChainsService { protected readonly sdkService: SdkService, protected readonly localStorage: LocalStorage, protected readonly broadcaster: ExtensionBroadcaster - ) { - //TODO: maybe we should call init after constructor - void this._initChain(); - } - - private async _queryNativeToken(chain: Chain): Promise { - try { - const nativeToken = await this.sdkService.getSdk().rpc.queryNativeToken(); - - if (nativeToken) { - chain.currency.address = nativeToken; - } - } catch (e) { - console.warn(`Chain is unreachable: ${e}`); - } - - await this.localStorage.setChain(chain); - return chain; - } - - private async _initChain(): Promise { - // Initialize default chain in storage - const chain: Chain = (await this.localStorage.getChain()) || chains.namada; - // Default chain config does not have a token address, so we query: - if (!chain.currency.address) { - await this._queryNativeToken(chain); - } - } + ) {} async getChain(): Promise { - let chain: Chain = (await this.localStorage.getChain()) || chains.namada; - // If a previous query for native token failed, attempt again: - if (!chain.currency.address) { - chain = await this._queryNativeToken(chain); - } - return chain; + return (await this.localStorage.getChain()) || chains.namada; } - async updateChain(chainId: string, url: string): Promise { + async updateChain(chainId: string): Promise { let chain = await this.getChain(); if (!chain) { throw new Error("No chain found!"); } - // Update RPC & Chain ID, then query for native token + // Update chain ID chain = { ...chain, chainId, - rpc: url, }; - this.sdkService.syncChain(chain); - await this.localStorage.setChain(await this._queryNativeToken(chain)); + await this.localStorage.setChain(chain); await this.broadcaster.updateNetwork(); } } diff --git a/apps/extension/src/background/index.ts b/apps/extension/src/background/index.ts index d0c57856f..93afa8da5 100644 --- a/apps/extension/src/background/index.ts +++ b/apps/extension/src/background/index.ts @@ -16,11 +16,10 @@ import { getNamadaRouterId, } from "extension"; import { KVPrefix, Ports } from "router"; -import { LocalStorage, RevealedPKStorage, VaultStorage } from "storage"; +import { LocalStorage, VaultStorage } from "storage"; import { ApprovalsService, init as initApprovals } from "./approvals"; import { ChainsService, init as initChains } from "./chains"; import { KeyRingService, UtilityStore, init as initKeyRing } from "./keyring"; -import { LedgerService, init as initLedger } from "./ledger"; import { SdkService } from "./sdk/service"; import { VaultService, init as initVault } from "./vault"; @@ -28,9 +27,6 @@ import { VaultService, init as initVault } from "./vault"; const localStorage = new LocalStorage( new ExtensionKVStore(KVPrefix.LocalStorage, browser.storage.local) ); -const revealedPKStorage = new RevealedPKStorage( - new ExtensionKVStore(KVPrefix.RevealedPK, browser.storage.local) -); //IDB storages const vaultStorage = new VaultStorage(new IndexedDBKVStore(KVPrefix.IndexedDB)); @@ -79,21 +75,11 @@ const init = new Promise(async (resolve) => { requester, broadcaster ); - const ledgerService = new LedgerService( - keyRingService, - sdkService, - vaultStorage, - txStore, - revealedPKStorage, - requester, - broadcaster - ); const approvalsService = new ApprovalsService( txStore, dataStore, localStorage, keyRingService, - ledgerService, vaultService, broadcaster ); @@ -102,7 +88,6 @@ const init = new Promise(async (resolve) => { initApprovals(router, approvalsService); initChains(router, chainsService); initKeyRing(router, keyRingService); - initLedger(router, ledgerService); initVault(router, vaultService); resolve(); }); diff --git a/apps/extension/src/background/keyring/handler.ts b/apps/extension/src/background/keyring/handler.ts index 48c53b8da..cd7f80520 100644 --- a/apps/extension/src/background/keyring/handler.ts +++ b/apps/extension/src/background/keyring/handler.ts @@ -1,29 +1,21 @@ import { CheckDurabilityMsg, - FetchAndStoreMaspParamsMsg, - HasMaspParamsMsg, QueryAccountsMsg, - QueryBalancesMsg, QueryDefaultAccountMsg, - ShieldedSyncMsg, VerifyArbitraryMsg, } from "provider/messages"; import { Env, Handler, InternalHandler, Message } from "router"; import { AddLedgerAccountMsg, - CloseOffscreenDocumentMsg, DeleteAccountMsg, DeriveAccountMsg, GenerateMnemonicMsg, GetActiveAccountMsg, QueryParentAccountsMsg, - QueryPublicKeyMsg, RenameAccountMsg, RevealAccountMnemonicMsg, SaveAccountSecretMsg, - ScanAccountsMsg, SetActiveAccountMsg, - TransferCompletedEvent, ValidateMnemonicMsg, } from "./messages"; import { KeyRingService } from "./service"; @@ -31,8 +23,6 @@ import { KeyRingService } from "./service"; export const getHandler: (service: KeyRingService) => Handler = (service) => { return (env: Env, msg: Message) => { switch (msg.constructor) { - case QueryPublicKeyMsg: - return handleQueryPublicKey(service)(env, msg as QueryPublicKeyMsg); case GenerateMnemonicMsg: return handleGenerateMnemonicMsg(service)( env, @@ -53,16 +43,10 @@ export const getHandler: (service: KeyRingService) => Handler = (service) => { env, msg as SaveAccountSecretMsg ); - case ScanAccountsMsg: - return handleScanAccountsMsg(service)(env, msg as ScanAccountsMsg); case DeriveAccountMsg: return handleDeriveAccountMsg(service)(env, msg as DeriveAccountMsg); case QueryAccountsMsg: return handleQueryAccountsMsg(service)(env, msg as QueryAccountsMsg); - case QueryBalancesMsg: - return handleQueryBalancesMsg(service)(env, msg as QueryBalancesMsg); - case ShieldedSyncMsg: - return handleShieldedSyncMsg(service)(env, msg as ShieldedSyncMsg); case SetActiveAccountMsg: return handleSetActiveAccountMsg(service)( env, @@ -83,27 +67,10 @@ export const getHandler: (service: KeyRingService) => Handler = (service) => { env, msg as QueryParentAccountsMsg ); - case CloseOffscreenDocumentMsg: - return handleCloseOffscreenDocumentMsg(service)( - env, - msg as CloseOffscreenDocumentMsg - ); - case TransferCompletedEvent: - return handleTransferCompletedEvent(service)( - env, - msg as TransferCompletedEvent - ); case RenameAccountMsg: return handleRenameAccountMsg(service)(env, msg as RenameAccountMsg); case DeleteAccountMsg: return handleDeleteAccountMsg(service)(env, msg as DeleteAccountMsg); - case FetchAndStoreMaspParamsMsg: - return handleFetchAndStoreMaspParamsMsg(service)( - env, - msg as FetchAndStoreMaspParamsMsg - ); - case HasMaspParamsMsg: - return handleHasMaspParamsMsg(service)(env, msg as HasMaspParamsMsg); case CheckDurabilityMsg: return handleCheckDurabilityMsg(service)( env, @@ -131,15 +98,6 @@ const handleAddLedgerAccountMsg: ( }; }; -const handleQueryPublicKey: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { address } = msg; - return await service.queryPublicKey(address); - }; -}; - const handleGenerateMnemonicMsg: ( service: KeyRingService ) => InternalHandler = (service) => { @@ -185,14 +143,6 @@ const handleRenameAccountMsg: ( }; }; -const handleScanAccountsMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async () => { - await service.scanAccounts(); - }; -}; - const handleDeriveAccountMsg: ( service: KeyRingService ) => InternalHandler = (service) => { @@ -209,9 +159,9 @@ const handleQueryAccountsMsg: ( const { query } = msg; const output = - query && query.accountId - ? await service.queryAccountById(query.accountId) - : await service.queryAccounts(); + query && query.accountId ? + await service.queryAccountById(query.accountId) + : await service.queryAccounts(); return output; }; @@ -225,22 +175,6 @@ const handleQueryDefaultAccountMsg: ( }; }; -const handleQueryBalancesMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, { owner, tokens }) => { - return await service.queryBalances(owner, tokens); - }; -}; - -const handleShieldedSyncMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async () => { - return await service.shieldedSync(); - }; -}; - const handleQueryParentAccountsMsg: ( service: KeyRingService ) => InternalHandler = (service) => { @@ -266,23 +200,6 @@ const handleGetActiveAccountMsg: ( }; }; -const handleTransferCompletedEvent: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { msgId, success, payload } = msg; - return await service.handleTransferCompleted(msgId, success, payload); - }; -}; - -const handleCloseOffscreenDocumentMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async () => { - return await service.closeOffscreenDocument(); - }; -}; - const handleDeleteAccountMsg: ( service: KeyRingService ) => InternalHandler = (service) => { @@ -291,22 +208,6 @@ const handleDeleteAccountMsg: ( }; }; -const handleFetchAndStoreMaspParamsMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, _msg) => { - return await service.fetchAndStoreMaspParams(); - }; -}; - -const handleHasMaspParamsMsg: ( - service: KeyRingService -) => InternalHandler = (service) => { - return async (_, _msg) => { - return await service.hasMaspParams(); - }; -}; - const handleCheckDurabilityMsg: ( service: KeyRingService ) => InternalHandler = (service) => { diff --git a/apps/extension/src/background/keyring/init.ts b/apps/extension/src/background/keyring/init.ts index d36e14013..63af79247 100644 --- a/apps/extension/src/background/keyring/init.ts +++ b/apps/extension/src/background/keyring/init.ts @@ -1,11 +1,7 @@ import { CheckDurabilityMsg, - FetchAndStoreMaspParamsMsg, - HasMaspParamsMsg, QueryAccountsMsg, - QueryBalancesMsg, QueryDefaultAccountMsg, - ShieldedSyncMsg, VerifyArbitraryMsg, } from "provider/messages"; import { Router } from "router"; @@ -13,41 +9,29 @@ import { ROUTE } from "./constants"; import { getHandler } from "./handler"; import { AddLedgerAccountMsg, - CloseOffscreenDocumentMsg, DeleteAccountMsg, DeriveAccountMsg, GenerateMnemonicMsg, GetActiveAccountMsg, QueryParentAccountsMsg, - QueryPublicKeyMsg, RenameAccountMsg, RevealAccountMnemonicMsg, SaveAccountSecretMsg, - ScanAccountsMsg, SetActiveAccountMsg, - TransferCompletedEvent, ValidateMnemonicMsg, } from "./messages"; import { KeyRingService } from "./service"; export function init(router: Router, service: KeyRingService): void { - router.registerMessage(QueryPublicKeyMsg); - router.registerMessage(CloseOffscreenDocumentMsg); router.registerMessage(DeriveAccountMsg); router.registerMessage(GenerateMnemonicMsg); router.registerMessage(GetActiveAccountMsg); router.registerMessage(QueryAccountsMsg); router.registerMessage(QueryDefaultAccountMsg); - router.registerMessage(QueryBalancesMsg); - router.registerMessage(ShieldedSyncMsg); router.registerMessage(QueryParentAccountsMsg); router.registerMessage(SaveAccountSecretMsg); - router.registerMessage(ScanAccountsMsg); router.registerMessage(SetActiveAccountMsg); - router.registerMessage(TransferCompletedEvent); router.registerMessage(DeleteAccountMsg); - router.registerMessage(FetchAndStoreMaspParamsMsg); - router.registerMessage(HasMaspParamsMsg); router.registerMessage(ValidateMnemonicMsg); router.registerMessage(CheckDurabilityMsg); router.registerMessage(AddLedgerAccountMsg); diff --git a/apps/extension/src/background/keyring/keyring.ts b/apps/extension/src/background/keyring/keyring.ts index 5426f0a09..19d0c9b58 100644 --- a/apps/extension/src/background/keyring/keyring.ts +++ b/apps/extension/src/background/keyring/keyring.ts @@ -1,21 +1,10 @@ -import { deserialize } from "@dao-xyz/borsh"; - import { PhraseSize } from "@heliax/namada-sdk/web"; import { KVStore } from "@namada/storage"; import { AccountType, Bip44Path, - BondMsgValue, DerivedAccount, - EthBridgeTransferMsgValue, - IbcTransferMsgValue, - RedelegateMsgValue, - SignatureResponse, - TransferMsgValue, - TxMsgValue, - UnbondMsgValue, - VoteProposalMsgValue, - WithdrawMsgValue, + SignArbitraryResponse, } from "@namada/types"; import { Result, assertNever, truncateInMiddle } from "@namada/utils"; @@ -27,10 +16,10 @@ import { KeyRingStatus, MnemonicValidationResponse, SensitiveAccountStoreData, - SigningKey, UtilityStore, } from "./types"; +import { BuiltTx } from "@namada/shared"; import { SdkService } from "background/sdk"; import { VaultService } from "background/vault"; import { KeyStore, KeyStoreType, SensitiveType, VaultStorage } from "storage"; @@ -280,101 +269,6 @@ export class KeyRing { }; } - // private async *getAddressWithBalance( - // seed: VecU8Pointer, - // parentId: string, - // type: AccountType - // ): AsyncGenerator< - // { - // path: Bip44Path; - // info: DerivedAccountInfo; - // }, - // void, - // void - // > { - // let index = 0; - // let emptyBalanceCount = 0; - // const deriveFn = ( - // type === AccountType.PrivateKey - // ? this.deriveTransparentAccount - // : this.deriveShieldedAccount - // ).bind(this); - // - // const get = async ( - // index: number - // ): Promise<{ - // path: Bip44Path; - // info: DerivedAccountInfo; - // balances: [string, string][]; - // }> => { - // // Cloning the seed, otherwise it gets zeroized in deriveTransparentAccount - // const seedClone = seed.clone(); - // const path = { account: 0, change: 0, index }; - // const accountInfo = deriveFn(seedClone, path, parentId); - // const balances: [string, string][] = await this.query.query_balance( - // accountInfo.owner - // ); - // - // return { path, info: accountInfo, balances }; - // }; - // - // while (index < 999999999 && emptyBalanceCount < 20) { - // const { path, info, balances } = await get(index++); - // const hasBalance = balances.some(([, value]) => { - // return !new BigNumber(value).isZero(); - // }); - // - // if (hasBalance) { - // emptyBalanceCount = 0; - // yield { path, info }; - // } else { - // emptyBalanceCount++; - // } - // } - // } - - public async scanAddresses(): Promise { - // if (!this._password) { - // throw new Error("No password is set!"); - // } - // const { seed, parentId } = await this.getParentSeed(this._password); - // for await (const value of this.getAddressWithBalance( - // seed, - // parentId, - // AccountType.PrivateKey - // )) { - // const alias = `Address - ${value.path.index}`; - // const { info, path } = value; - // await this.persistAccount( - // this._password, - // path, - // parentId, - // AccountType.PrivateKey, - // alias, - // info - // ); - // await this.addSecretKey(info.text, this._password, alias, parentId); - // } - // for await (const value of this.getAddressWithBalance( - // seed, - // parentId, - // AccountType.ShieldedKeys - // )) { - // const alias = `Shielded Address - ${value.path.index}`; - // const { info, path } = value; - // await this.persistAccount( - // this._password, - // path, - // parentId, - // AccountType.ShieldedKeys, - // alias, - // info - // ); - // await this.addSpendingKey(info.text, this._password, alias, parentId); - // } - // seed.free(); - } - private async getParentSeed(): Promise<{ parentId: string; seed: Uint8Array; @@ -597,26 +491,6 @@ export class KeyRing { return privateKey; } - async submitBond(bondMsg: BondMsgValue, txMsg: TxMsgValue): Promise { - await this.vaultService.assertIsUnlocked(); - try { - const { source } = bondMsg; - const signingKey = await this.getSigningKey(source); - const sdk = this.sdkService.getSdk(); - const sdkTx = sdk.tx; - - await sdkTx.revealPk(signingKey, txMsg); - - const builtTx = await sdkTx.buildBond(txMsg, bondMsg); - const signedTx = await sdkTx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit bond tx: ${e}`); - } - } - public async queryAccountByAddress( address: string ): Promise { @@ -625,176 +499,6 @@ export class KeyRing { ); } - async submitUnbond( - unbondMsg: UnbondMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { source } = unbondMsg; - const signingKey = await this.getSigningKey(source); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildUnbond(txMsg, unbondMsg); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit unbond tx: ${e}`); - } - } - - async submitWithdraw( - withdrawMsg: WithdrawMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { source } = withdrawMsg; - const signingKey = await this.getSigningKey(source); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildWithdraw(txMsg, withdrawMsg); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit withdraw tx: ${e}`); - } - } - - async submitRedelegate( - redelegateMsg: RedelegateMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { owner } = redelegateMsg; - const signingKey = await this.getSigningKey(owner); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildRedelegate(txMsg, redelegateMsg); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit redelegate tx: ${e}`); - } - } - - async submitVoteProposal( - voteProposalMsg: VoteProposalMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { signer } = voteProposalMsg; - const signingKey = await this.getSigningKey(signer); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildVoteProposal(txMsg, voteProposalMsg); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - await sdk.rpc.broadcastTx(signedTx); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit vote proposal tx: ${e}`); - } - } - - async submitTransfer( - transferMsg: Uint8Array, - submit: (signingKey: SigningKey) => Promise - ): Promise { - await this.vaultService.assertIsUnlocked(); - - // We need to get the source address to find either the private key or spending key - const { source } = deserialize(Buffer.from(transferMsg), TransferMsgValue); - - const account = await this.vaultStorage.findOneOrFail( - KeyStore, - "address", - source - ); - const sensitiveProps = - await this.vaultService.reveal( - account.sensitive - ); - - if (!sensitiveProps) { - throw new Error("Error decrypting AccountStore data"); - } - - if (account.public.type === AccountType.ShieldedKeys) { - const xsk = JSON.parse(sensitiveProps.text).spendingKey; - - await submit({ - xsk, - }); - } else { - await submit({ privateKey: await this.getSigningKey(source) }); - } - } - - async submitIbcTransfer( - ibcTransferMsg: IbcTransferMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { source } = ibcTransferMsg; - const signingKey = await this.getSigningKey(source); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildIbcTransfer(txMsg, ibcTransferMsg); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit ibc transfer tx: ${e}`); - } - } - - async submitEthBridgeTransfer( - ethBridgeTransferMsg: EthBridgeTransferMsgValue, - txMsg: TxMsgValue - ): Promise { - await this.vaultService.assertIsUnlocked(); - const sdk = this.sdkService.getSdk(); - try { - const { sender } = ethBridgeTransferMsg; - const signingKey = await this.getSigningKey(sender); - - await sdk.tx.revealPk(signingKey, txMsg); - - const builtTx = await sdk.tx.buildEthBridgeTransfer( - txMsg, - ethBridgeTransferMsg - ); - const signedTx = await sdk.tx.signTx(builtTx, signingKey); - const innerTxHash: string = await sdk.rpc.broadcastTx(signedTx); - - return innerTxHash; - } catch (e) { - throw new Error(`Could not submit submit_eth_bridge_transfer tx: ${e}`); - } - } - private async findAllChildAccounts( accountId: string ): Promise<{ public: KeyStoreType; sensitive?: SensitiveType }[]> { @@ -839,36 +543,23 @@ export class KeyRing { return Result.ok(null); } - async queryBalances( - owner: string, - tokens: string[] - ): Promise<{ token: string; amount: string }[]> { - const query = this.sdkService.getSdk().rpc; - - try { - return (await query.queryBalance(owner, tokens)).map( - ([token, amount]: [string, string]) => { - return { - token, - amount, - }; - } - ); - } catch (e) { - console.error(e); - return []; - } - } - - async queryPublicKey(address: string): Promise { - const query = this.sdkService.getSdk().rpc; - return await query.queryPublicKey(address); + async sign( + builtTx: BuiltTx[], + signer: string, + chainId: string + ): Promise { + await this.vaultService.assertIsUnlocked(); + const key = await this.getSigningKey(signer); + const { signing } = this.sdkService.getSdk(); + return await Promise.all( + builtTx.map(async (tx) => await signing.sign(tx, key, chainId)) + ); } async signArbitrary( signer: string, data: string - ): Promise { + ): Promise { await this.vaultService.assertIsUnlocked(); const key = await this.getSigningKey(signer); diff --git a/apps/extension/src/background/keyring/messages.ts b/apps/extension/src/background/keyring/messages.ts index 18a88805a..462b5b571 100644 --- a/apps/extension/src/background/keyring/messages.ts +++ b/apps/extension/src/background/keyring/messages.ts @@ -13,17 +13,13 @@ import { } from "./types"; enum MessageType { - QueryPublicKey = "query-public-key", - CloseOffscreenDocument = "close-offscreen-document", DeriveAccount = "derive-account", DeriveShieldedAccount = "derive-shielded-account", GenerateMnemonic = "generate-mnemonic", GetActiveAccount = "get-active-account", QueryParentAccounts = "query-parent-accounts", SaveAccountSecret = "save-account-secret", - ScanAccounts = "scan-accounts", SetActiveAccount = "set-active-account", - TransferCompletedEvent = "transfer-completed-event", DeleteAccount = "delete-account", ValidateMnemonic = "validate-mnemonic", AddLedgerAccount = "add-ledger-account", @@ -31,30 +27,6 @@ enum MessageType { RenameAccount = "rename-account", } -export class QueryPublicKeyMsg extends Message { - public static type(): MessageType { - return MessageType.QueryPublicKey; - } - - constructor(public readonly address: string) { - super(); - } - - validate(): void { - if (!this.address) { - throw new Error("address not set"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return QueryPublicKeyMsg.type(); - } -} - export class GenerateMnemonicMsg extends Message { public static type(): MessageType { return MessageType.GenerateMnemonic; @@ -236,26 +208,6 @@ export class AddLedgerAccountMsg extends Message { return AddLedgerAccountMsg.type(); } } -export class ScanAccountsMsg extends Message { - public static type(): MessageType { - return MessageType.ScanAccounts; - } - - constructor() { - super(); - } - - // eslint-disable-next-line @typescript-eslint/no-empty-function - validate(): void {} - - route(): string { - return ROUTE; - } - - type(): string { - return ScanAccountsMsg.type(); - } -} export class DeriveAccountMsg extends Message { public static type(): MessageType { @@ -375,56 +327,6 @@ export class QueryParentAccountsMsg extends Message { } } -export class CloseOffscreenDocumentMsg extends Message { - public static type(): MessageType { - return MessageType.CloseOffscreenDocument; - } - - constructor() { - super(); - } - - validate(): void { - return; - } - - route(): string { - return ROUTE; - } - - type(): string { - return CloseOffscreenDocumentMsg.type(); - } -} - -export class TransferCompletedEvent extends Message { - public static type(): MessageType { - return MessageType.TransferCompletedEvent; - } - - constructor( - public readonly success: boolean, - public readonly msgId: string, - public readonly payload?: string - ) { - super(); - } - - validate(): void { - if (this.success === undefined) { - throw new Error("Success is undefined"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return TransferCompletedEvent.type(); - } -} - export class DeleteAccountMsg extends Message< Result > { diff --git a/apps/extension/src/background/keyring/service.ts b/apps/extension/src/background/keyring/service.ts index 34eaf77a1..8010bfda7 100644 --- a/apps/extension/src/background/keyring/service.ts +++ b/apps/extension/src/background/keyring/service.ts @@ -1,40 +1,20 @@ -import { fromBase64, fromHex } from "@cosmjs/encoding"; +import { fromHex } from "@cosmjs/encoding"; -import { PhraseSize, publicKeyToBech32, TxType } from "@heliax/namada-sdk/web"; +import { PhraseSize, publicKeyToBech32 } from "@heliax/namada-sdk/web"; import { IndexedDBKVStore, KVStore } from "@namada/storage"; import { AccountType, Bip44Path, - BondMsgValue, DerivedAccount, - EthBridgeTransferMsgValue, - IbcTransferMsgValue, - Message, - RedelegateMsgValue, - SignatureResponse, - TransferMsgValue, - TxMsgValue, - UnbondMsgValue, - VoteProposalMsgValue, - WithdrawMsgValue, + SignArbitraryResponse, } from "@namada/types"; import { Result, truncateInMiddle } from "@namada/utils"; +import { BuiltTx } from "@namada/shared"; import { ChainsService } from "background/chains"; -import { - createOffscreenWithTxWorker, - hasOffscreenDocument, - OFFSCREEN_TARGET, - SUBMIT_TRANSFER_MSG_TYPE, -} from "background/offscreen"; import { SdkService } from "background/sdk/service"; import { VaultService } from "background/vault"; -import { init as initSubmitTransferWebWorker } from "background/web-workers"; -import { - ExtensionBroadcaster, - ExtensionRequester, - getNamadaRouterId, -} from "extension"; +import { ExtensionBroadcaster, ExtensionRequester } from "extension"; import { KeyStore, LocalStorage, VaultStorage } from "storage"; import { KeyRing } from "./keyring"; import { @@ -44,15 +24,9 @@ import { DeleteAccountError, MnemonicValidationResponse, ParentAccount, - SigningKey, UtilityStore, } from "./types"; -const { - NAMADA_INTERFACE_NAMADA_TOKEN: - tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", -} = process.env; - export class KeyRingService { private _keyRing: KeyRing; @@ -125,11 +99,6 @@ export class KeyRingService { return response; } - async scanAccounts(): Promise { - await this._keyRing.scanAddresses(); - await this.broadcaster.updateAccounts(); - } - async deriveAccount( path: Bip44Path, type: AccountType, @@ -177,355 +146,6 @@ export class KeyRingService { return account?.public ?? null; } - async submitBond( - bondMsg: string, - txMsg: string, - msgId: string - ): Promise { - await this.broadcaster.startTx(msgId, TxType.Bond); - try { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const bondMsgValue = Message.decode(fromBase64(bondMsg), BondMsgValue); - - const innerTxHash = await this._keyRing.submitBond( - bondMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx(msgId, TxType.Bond, true, innerTxHash); - await this.broadcaster.updateStaking(); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx(msgId, TxType.Bond, false, `${e}`); - throw new Error(`Unable to submit bond tx! ${e}`); - } - } - - async submitUnbond( - unbondMsg: string, - txMsg: string, - msgId: string - ): Promise { - await this.broadcaster.startTx(msgId, TxType.Unbond); - try { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const unbondMsgValue = Message.decode( - fromBase64(unbondMsg), - UnbondMsgValue - ); - - const innerTxHash = await this._keyRing.submitUnbond( - unbondMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.Unbond, - true, - innerTxHash - ); - await this.broadcaster.updateStaking(); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx(msgId, TxType.Unbond, false, `${e}`); - throw new Error(`Unable to submit unbond tx! ${e}`); - } - } - - async submitWithdraw( - withdrawMsg: string, - txMsg: string, - msgId: string - ): Promise { - await this.broadcaster.startTx(msgId, TxType.Withdraw); - try { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const withdrawMsgValue = Message.decode( - fromBase64(withdrawMsg), - WithdrawMsgValue - ); - - const innerTxHash = await this._keyRing.submitWithdraw( - withdrawMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.Withdraw, - true, - innerTxHash - ); - await this.broadcaster.updateStaking(); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx(msgId, TxType.Withdraw, false, `${e}`); - throw new Error(`Unable to submit withdraw tx! ${e}`); - } - } - - async submitRedelegate( - redelegateMsg: string, - txMsg: string, - msgId: string - ): Promise { - await this.broadcaster.startTx(msgId, TxType.Redelegate); - try { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const redelegateMsgValue = Message.decode( - fromBase64(redelegateMsg), - RedelegateMsgValue - ); - - const innerTxHash = await this._keyRing.submitRedelegate( - redelegateMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.Redelegate, - true, - innerTxHash - ); - await this.broadcaster.updateStaking(); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx( - msgId, - TxType.Redelegate, - false, - `${e}` - ); - throw new Error(`Unable to submit redelegate tx! ${e}`); - } - } - - async submitVoteProposal( - voteProposalMsg: string, - txMsg: string, - msgId: string - ): Promise { - await this.broadcaster.startTx(msgId, TxType.VoteProposal); - try { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const voteProposalMsgValue = Message.decode( - fromBase64(voteProposalMsg), - VoteProposalMsgValue - ); - const innerTxHash = await this._keyRing.submitVoteProposal( - voteProposalMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.VoteProposal, - true, - innerTxHash - ); - await this.broadcaster.updateProposals(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx( - msgId, - TxType.VoteProposal, - false, - `${e}` - ); - throw new Error(`Unable to submit vote proposal tx! ${e}`); - } - } - - private async submitTransferChrome( - transferMsg: string, - txMsg: string, - msgId: string, - signingKey: SigningKey - ): Promise { - const offscreenDocumentPath = "offscreen.html"; - const routerId = await getNamadaRouterId(this.localStorage); - const { url: rpc } = this.sdkService.getSdk(); - const { - currency: { address: nativeToken = tokenAddress }, - } = await this.chainsService.getChain(); - - if (!(await hasOffscreenDocument(offscreenDocumentPath))) { - await createOffscreenWithTxWorker(offscreenDocumentPath); - } - - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const transferMsgValue = Message.decode( - fromBase64(transferMsg), - TransferMsgValue - ); - - const result = await chrome.runtime.sendMessage({ - type: SUBMIT_TRANSFER_MSG_TYPE, - target: OFFSCREEN_TARGET, - routerId, - data: { - transferMsg: transferMsgValue, - txMsg: txMsgValue, - msgId, - signingKey, - rpc, - nativeToken, - }, - }); - - if (result?.error) { - const error = new Error(result.error?.message || "Error in web worker"); - error.stack = result.error.stack; - throw error; - } - } - - private async submitTransferFirefox( - transferMsg: string, - txMsg: string, - msgId: string, - signingKey: SigningKey - ): Promise { - const { url: rpc } = this.sdkService.getSdk(); - const { - currency: { address: nativeToken = tokenAddress }, - } = await this.chainsService.getChain(); - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const transferMsgValue = Message.decode( - fromBase64(transferMsg), - TransferMsgValue - ); - - initSubmitTransferWebWorker( - { - transferMsg: transferMsgValue, - txMsg: txMsgValue, - msgId, - signingKey, - rpc, - nativeToken, - }, - this.handleTransferCompleted.bind(this) - ); - } - - /** - * Submits a transfer transaction to the chain. - * Handles both Shielded and Transparent transfers. - * - * @async - * @param {string} txMsg - borsh serialized transfer transaction - * @param {string} msgId - id of a tx if originating from approval process - * @throws {Error} - if unable to submit transfer - * @returns {Promise} - resolves when transfer is successful (resolves for failed VPs) - */ - async submitTransfer( - transferMsg: string, - txMsg: string, - msgId: string - ): Promise { - // Passing submit handler simplifies worker code when using Firefox - const submit = async (signingKey: SigningKey): Promise => { - const { TARGET } = process.env; - if (TARGET === "chrome") { - await this.submitTransferChrome(transferMsg, txMsg, msgId, signingKey); - } else if (TARGET === "firefox") { - await this.submitTransferFirefox(transferMsg, txMsg, msgId, signingKey); - } else { - console.warn( - "Submitting transfers is not supported with your browser." - ); - } - }; - - await this.broadcaster.startTx(msgId, TxType.Transfer); - - try { - await this._keyRing.submitTransfer( - fromBase64(transferMsg), - submit.bind(this) - ); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - throw new Error(`Unable to submit the transfer! ${e}`); - } - } - - async submitIbcTransfer( - ibcTransferMsg: string, - txMsg: string, - msgId: string - ): Promise { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const ibcTransferMsgValue = Message.decode( - fromBase64(ibcTransferMsg), - IbcTransferMsgValue - ); - - await this.broadcaster.startTx(msgId, TxType.IBCTransfer); - - try { - const innerTxHash = await this._keyRing.submitIbcTransfer( - ibcTransferMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.IBCTransfer, - true, - innerTxHash - ); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx( - msgId, - TxType.IBCTransfer, - false, - `${e}` - ); - throw new Error(`Unable to encode IBC transfer! ${e}`); - } - } - - async submitEthBridgeTransfer( - ethBridgeTransferMsg: string, - txMsg: string, - msgId: string - ): Promise { - const txMsgValue = Message.decode(fromBase64(txMsg), TxMsgValue); - const ethBridgeTransferMsgValue = Message.decode( - fromBase64(ethBridgeTransferMsg), - EthBridgeTransferMsgValue - ); - await this.broadcaster.startTx(msgId, TxType.EthBridgeTransfer); - - try { - const innerTxHash = await this._keyRing.submitEthBridgeTransfer( - ethBridgeTransferMsgValue, - txMsgValue - ); - await this.broadcaster.completeTx( - msgId, - TxType.EthBridgeTransfer, - true, - innerTxHash - ); - await this.broadcaster.updateBalance(); - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx( - msgId, - TxType.EthBridgeTransfer, - false, - `${e}` - ); - throw new Error(`Unable to encode Eth Bridge transfer! ${e}`); - } - } - async setActiveAccount(id: string, type: ParentAccount): Promise { await this._keyRing.setActiveAccount(id, type); await this.broadcaster.updateAccounts(); @@ -535,25 +155,6 @@ export class KeyRingService { return await this._keyRing.getActiveAccount(); } - async handleTransferCompleted( - msgId: string, - success: boolean, - payload?: string - ): Promise { - await this.broadcaster.completeTx(msgId, TxType.Transfer, success, payload); - await this.broadcaster.updateBalance(); - } - - closeOffscreenDocument(): Promise { - if (chrome) { - return chrome.offscreen.closeDocument(); - } else { - return Promise.reject( - "Trying to close offscreen document for nor supported browser" - ); - } - } - async deleteAccount( accountId: string ): Promise> { @@ -567,46 +168,19 @@ export class KeyRingService { return await this._keyRing.renameAccount(accountId, alias); } - async fetchAndStoreMaspParams(): Promise { - await this.sdkService.getSdk().masp.fetchAndStoreMaspParams(); - } - - async hasMaspParams(): Promise { - return await this.sdkService.getSdk().masp.hasMaspParams(); - } - - async shieldedSync(): Promise { - const vks = (await this.vaultStorage.findAll(KeyStore)) - .filter((a) => a.public.type === AccountType.ShieldedKeys) - .map((a) => a.public.owner); - - await this.sdkService.getSdk().rpc.shieldedSync(vks); - } - - async queryBalances( - owner: string, - tokens: string[] - ): Promise<{ token: string; amount: string }[]> { - const account = await this.vaultStorage.findOneOrFail( - KeyStore, - "address", - owner - ); - return this._keyRing.queryBalances(account.public.owner, tokens); - } - - async queryPublicKey(address: string): Promise { - return await this._keyRing.queryPublicKey(address); - } - async checkDurability(): Promise { return await IndexedDBKVStore.durabilityCheck(); } + async sign(builtTx: BuiltTx[], signer: string): Promise { + const { chainId } = await this.chainsService.getChain(); + return await this._keyRing.sign(builtTx, signer, chainId); + } + async signArbitrary( signer: string, data: string - ): Promise { + ): Promise { return await this._keyRing.signArbitrary(signer, data); } diff --git a/apps/extension/src/background/ledger/constants.ts b/apps/extension/src/background/ledger/constants.ts deleted file mode 100644 index 57854a916..000000000 --- a/apps/extension/src/background/ledger/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const ROUTE = "ledger-route"; diff --git a/apps/extension/src/background/ledger/handler.ts b/apps/extension/src/background/ledger/handler.ts deleted file mode 100644 index dedd80ca3..000000000 --- a/apps/extension/src/background/ledger/handler.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Env, Handler, InternalHandler, Message } from "router"; -import { - GetRevealPKBytesMsg, - GetTxBytesMsg, - QueryStoredPK, - StoreRevealedPK, - SubmitSignedRevealPKMsg, - SubmitSignedTxMsg, -} from "./messages"; -import { LedgerService } from "./service"; - -export const getHandler: (service: LedgerService) => Handler = (service) => { - return (env: Env, msg: Message) => { - switch (msg.constructor) { - case GetTxBytesMsg: - return handleGetTxBytesMsg(service)(env, msg as GetTxBytesMsg); - case GetRevealPKBytesMsg: - return handleGetRevealPKBytesMsg(service)( - env, - msg as GetRevealPKBytesMsg - ); - case SubmitSignedRevealPKMsg: - return handleSubmitSignedRevealPKMsg(service)( - env, - msg as SubmitSignedRevealPKMsg - ); - case SubmitSignedTxMsg: - return handleSubmitSignedTxMsg(service)(env, msg as SubmitSignedTxMsg); - case QueryStoredPK: - return handleQueryStoredPKMsg(service)(env, msg as QueryStoredPK); - case StoreRevealedPK: - return handleStoreRevealedPK(service)(env, msg as StoreRevealedPK); - default: - throw new Error("Unknown msg type"); - } - }; -}; - -const handleGetTxBytesMsg: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { address, txType, txMsg } = msg; - return await service.getTxBytes(txType, txMsg, address); - }; -}; - -const handleGetRevealPKBytesMsg: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { txMsg } = msg; - return await service.getRevealPKBytes(txMsg); - }; -}; - -const handleSubmitSignedRevealPKMsg: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { txMsg, bytes, signatures } = msg; - return await service.submitRevealPk(txMsg, bytes, signatures); - }; -}; - -const handleSubmitSignedTxMsg: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { txType, bytes, msgId, signatures } = msg; - return await service.submitTx(txType, msgId, bytes, signatures); - }; -}; - -const handleQueryStoredPKMsg: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { publicKey } = msg; - return await service.queryStoredRevealedPK(publicKey); - }; -}; - -const handleStoreRevealedPK: ( - service: LedgerService -) => InternalHandler = (service) => { - return async (_, msg) => { - const { publicKey } = msg; - return await service.storeRevealedPK(publicKey); - }; -}; diff --git a/apps/extension/src/background/ledger/index.ts b/apps/extension/src/background/ledger/index.ts deleted file mode 100644 index 06d5e6384..000000000 --- a/apps/extension/src/background/ledger/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./constants"; -export * from "./init"; -export * from "./ledger"; -export * from "./service"; -export * from "./messages"; diff --git a/apps/extension/src/background/ledger/init.ts b/apps/extension/src/background/ledger/init.ts deleted file mode 100644 index d03e3b76b..000000000 --- a/apps/extension/src/background/ledger/init.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Router } from "router"; -import { ROUTE } from "./constants"; -import { - GetTxBytesMsg, - GetRevealPKBytesMsg, - SubmitSignedTxMsg, - SubmitSignedRevealPKMsg, - QueryStoredPK, - StoreRevealedPK, -} from "./messages"; -import { getHandler } from "./handler"; -import { LedgerService } from "./service"; - -export function init(router: Router, service: LedgerService): void { - router.registerMessage(GetTxBytesMsg); - router.registerMessage(GetRevealPKBytesMsg); - router.registerMessage(SubmitSignedTxMsg); - router.registerMessage(SubmitSignedRevealPKMsg); - router.registerMessage(QueryStoredPK); - router.registerMessage(StoreRevealedPK); - - router.addHandler(ROUTE, getHandler(service)); -} diff --git a/apps/extension/src/background/ledger/ledger.ts b/apps/extension/src/background/ledger/ledger.ts deleted file mode 100644 index ae7107a49..000000000 --- a/apps/extension/src/background/ledger/ledger.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { toHex } from "@cosmjs/encoding"; -import { makeBip44Path } from "@heliax/namada-sdk/web"; -import Transport from "@ledgerhq/hw-transport"; -import TransportHID from "@ledgerhq/hw-transport-webhid"; -import TransportUSB from "@ledgerhq/hw-transport-webusb"; -import { chains } from "@namada/chains"; -import { - LedgerError, - NamadaApp, - ResponseAppInfo, - ResponseSign, - ResponseVersion, -} from "@zondax/ledger-namada"; - -const { coinType } = chains.namada.bip44; - -export const initLedgerUSBTransport = async (): Promise => { - return await TransportUSB.create(); -}; - -export const initLedgerHIDTransport = async (): Promise => { - return await TransportHID.create(); -}; - -export const DEFAULT_LEDGER_BIP44_PATH = makeBip44Path(coinType, { - account: 0, - change: 0, - index: 0, -}); - -export class Ledger { - constructor(public readonly namadaApp: NamadaApp | undefined = undefined) {} - - /** - * Returns an initialized Ledger class instance with initialized Transport - */ - static async init(transport?: Transport): Promise { - const initializedTransport = transport ?? (await initLedgerUSBTransport()); - - try { - const namadaApp = new NamadaApp(initializedTransport); - const ledger = new Ledger(namadaApp); - return ledger; - } catch (e) { - throw new Error(`${e}`); - } - } - - /** - * Return status and version info of initialized NamadaApp - */ - public async status(): Promise<{ - version: ResponseVersion; - info: ResponseAppInfo; - }> { - if (!this.namadaApp) { - throw new Error("NamadaApp is not initialized!"); - } - const version = await this.namadaApp.getVersion(); - const info = await this.namadaApp.getAppInfo(); - - return { - version, - info, - }; - } - - /** - * Get address and public key associated with optional path, otherwise, use default path - */ - public async getAddressAndPublicKey( - bip44Path?: string - ): Promise<{ address: string; publicKey: string }> { - if (!this.namadaApp) { - throw new Error("NamadaApp is not initialized!"); - } - - const path = bip44Path || DEFAULT_LEDGER_BIP44_PATH; - const { address, publicKey } = - await this.namadaApp.getAddressAndPubKey(path); - - return { - // Return address as bech32-encoded string - address: address.toString(), - // Return public key as hex-encoded string - publicKey: toHex(publicKey), - }; - } - - public async showAddressAndPublicKey( - bip44Path?: string - ): Promise<{ address: string; publicKey: string }> { - if (!this.namadaApp) { - throw new Error("NamadaApp is not initialized!"); - } - - const path = bip44Path || DEFAULT_LEDGER_BIP44_PATH; - - try { - const { address, publicKey } = - await this.namadaApp.showAddressAndPubKey(path); - - return { - // Return address as bech32-encoded string - address: address.toString(), - // Return public key as hex-encoded string - publicKey: toHex(publicKey), - }; - } catch (e) { - throw new Error("Connect Ledger rejected by user"); - } - } - /** - * Sign tx bytes with the key associated with provided (or default) path - * - * @async - * @param {Uint8Array} tx - tx data blob to sign - * @param {string} bip44Path (optional) - Bip44 path for signing account - * - * @returns {ResponseSign} - */ - public async sign(tx: Uint8Array, bip44Path?: string): Promise { - if (!this.namadaApp) { - throw new Error("NamadaApp is not initialized!"); - } - const buffer = Buffer.from(tx); - const path = bip44Path || DEFAULT_LEDGER_BIP44_PATH; - - return await this.namadaApp.sign(path, buffer); - } - - /** - * Query status to determine if device has thrown an error - */ - public async queryErrors(): Promise { - const { - info: { returnCode, errorMessage }, - } = await this.status(); - - if (returnCode !== LedgerError.NoErrors) { - return errorMessage; - } - return ""; - } - - /** - * Close the initialized transport, which may be needed if Ledger needs to be reinitialized due to error state - */ - public async closeTransport(): Promise { - if (!this.namadaApp) { - throw new Error("NamadaApp is not initialized!"); - } - - return await this.namadaApp.transport.close(); - } -} diff --git a/apps/extension/src/background/ledger/messages.ts b/apps/extension/src/background/ledger/messages.ts deleted file mode 100644 index 080bc215f..000000000 --- a/apps/extension/src/background/ledger/messages.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { TxType } from "@heliax/namada-sdk/web"; -import { ResponseSign } from "@zondax/ledger-namada"; -import { Message } from "router"; -import { ROUTE } from "./constants"; - -enum MessageType { - GetTxBytes = "get-tx-bytes", - GetRevealPKBytes = "get-reveal-pk-bytes", - SubmitSignedTx = "submit-signed-tx", - SubmitSignedRevealPK = "submit-signed-reveal-pk", - QueryStoredPK = "query-stored-pk", - StoreRevealedPK = "store-revealed-pk", -} - -export class GetTxBytesMsg extends Message< - { - bytes: Uint8Array; - path: string; - }[] -> { - public static type(): MessageType { - return MessageType.GetTxBytes; - } - - constructor( - public readonly txType: TxType, - public readonly txMsg: string, - public readonly address: string - ) { - super(); - } - - validate(): void { - if (!this.txType) { - throw new Error("txType is required!"); - } - if (!this.txMsg) { - throw new Error("txMsg was not provided!"); - } - if (!this.address) { - throw new Error("address was not provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return GetTxBytesMsg.type(); - } -} - -export class GetRevealPKBytesMsg extends Message<{ - bytes: Uint8Array; - path: string; -}> { - public static type(): MessageType { - return MessageType.GetRevealPKBytes; - } - - constructor(public readonly txMsg: string) { - super(); - } - - validate(): void { - if (!this.txMsg) { - throw new Error("txMsg was not provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return GetRevealPKBytesMsg.type(); - } -} - -export class SubmitSignedRevealPKMsg extends Message { - public static type(): MessageType { - return MessageType.SubmitSignedRevealPK; - } - - constructor( - public readonly txMsg: string, - public readonly bytes: string, - public readonly signatures: ResponseSign - ) { - super(); - } - - validate(): void { - if (!this.txMsg) { - throw new Error("txMsg was not provided!"); - } - - if (!this.bytes) { - throw new Error("bytes were not provided!"); - } - - if (!this.signatures) { - throw new Error("No signatures were provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return SubmitSignedRevealPKMsg.type(); - } -} - -export class SubmitSignedTxMsg extends Message { - public static type(): MessageType { - return MessageType.SubmitSignedTx; - } - - constructor( - public readonly txType: TxType, - public readonly msgId: string, - public readonly bytes: string, - public readonly signatures: ResponseSign - ) { - super(); - } - - validate(): void { - if (!this.txType) { - throw new Error("txType was not provided!"); - } - - if (!this.msgId) { - throw new Error("msgId was not provided!"); - } - - if (!this.bytes) { - throw new Error("bytes were not provided!"); - } - - if (!this.signatures) { - throw new Error("No signatures were provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return SubmitSignedTxMsg.type(); - } -} - -export class QueryStoredPK extends Message { - public static type(): MessageType { - return MessageType.QueryStoredPK; - } - - constructor(public publicKey: string) { - super(); - } - - validate(): void { - if (!this.publicKey) { - throw new Error("publicKey not provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return QueryStoredPK.type(); - } -} - -export class StoreRevealedPK extends Message { - public static type(): MessageType { - return MessageType.StoreRevealedPK; - } - - constructor(public publicKey: string) { - super(); - } - - validate(): void { - if (!this.publicKey) { - throw new Error("publicKey not provided!"); - } - } - - route(): string { - return ROUTE; - } - - type(): string { - return StoreRevealedPK.type(); - } -} diff --git a/apps/extension/src/background/ledger/service.ts b/apps/extension/src/background/ledger/service.ts deleted file mode 100644 index e91ff8d24..000000000 --- a/apps/extension/src/background/ledger/service.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { fromBase64 } from "@cosmjs/encoding"; -import { deserialize } from "@dao-xyz/borsh"; -import { ResponseSign } from "@zondax/ledger-namada"; - -import { TxType, makeBip44Path } from "@heliax/namada-sdk/web"; -import { chains } from "@namada/chains"; -import { KVStore } from "@namada/storage"; -import { AccountType, TxMsgValue } from "@namada/types"; -import { PendingTx, TxStore } from "background/approvals"; -import { KeyRingService } from "background/keyring"; -import { SdkService } from "background/sdk"; -import { ExtensionBroadcaster, ExtensionRequester } from "extension"; -import { RevealedPKStorage, VaultStorage } from "storage"; - -export const LEDGERSTORE_KEY = "ledger-store"; - -export class LedgerService { - constructor( - protected readonly keyringService: KeyRingService, - protected readonly sdkService: SdkService, - protected readonly vaultStorage: VaultStorage, - protected readonly txStore: KVStore, - protected readonly revealedPKStorage: RevealedPKStorage, - protected readonly requester: ExtensionRequester, - protected readonly broadcaster: ExtensionBroadcaster - ) { } - - async getRevealPKBytes( - txMsg: string - ): Promise<{ bytes: Uint8Array; path: string }> { - const { coinType } = chains.namada.bip44; - - try { - // Deserialize txMsg to retrieve source - const { publicKey } = deserialize( - Buffer.from(fromBase64(txMsg)), - TxMsgValue - ); - - if (!publicKey) { - throw new Error("Public key not found in txMsg"); - } - - // Query account from Ledger storage to determine path for signer - const account = - await this.keyringService.findParentByPublicKey(publicKey); - - if (!account) { - throw new Error(`Ledger account not found for ${publicKey}`); - } - - if (account.type !== AccountType.Ledger) { - throw new Error(`Returned Account is not a Ledger`); - } - - const sdk = this.sdkService.getSdk(); - const builtTx = await sdk.tx.buildTxFromSerializedArgs( - TxType.RevealPK, - new Uint8Array(), // TODO: this is a dummy value. Is there a cleaner way? - fromBase64(txMsg), - publicKey - ); - const path = makeBip44Path(coinType, account.path); - - return { bytes: builtTx.toBytes(), path }; - } catch (e) { - console.warn(e); - throw new Error(`${e}`); - } - } - - async submitRevealPk( - txMsg: string, - bytes: string, - signatures: ResponseSign - ): Promise { - try { - const sdk = this.sdkService.getSdk(); - const signedTxBytes = sdk.tx.appendSignature( - fromBase64(bytes), - signatures - ); - const signedTx = { - txMsg: fromBase64(txMsg), - tx: signedTxBytes, - }; - await sdk.rpc.broadcastTx(signedTx); - } catch (e) { - console.warn(e); - } - } - - async submitTx( - txType: TxType, - msgId: string, - bytes: string, - signatures: ResponseSign - ): Promise { - const storedTx = await this.txStore.get(msgId); - - if (!storedTx) { - throw new Error(`Transaction ${msgId} not found!`); - } - - storedTx.tx.forEach(async (pendingTx: PendingTx) => { - const { txMsg } = pendingTx; - - await this.broadcaster.startTx(msgId, txType); - const sdk = this.sdkService.getSdk(); - try { - const signedTxBytes = sdk.tx.appendSignature( - fromBase64(bytes), - signatures - ); - const signedTx = { - txMsg: fromBase64(txMsg), - tx: signedTxBytes, - }; - const innerTxHash = await sdk.rpc.broadcastTx(signedTx); - - // Clear pending tx if successful - await this.txStore.set(msgId, null); - - // Broadcast update events - await this.broadcaster.completeTx(msgId, txType, true, innerTxHash); - await this.broadcaster.updateBalance(); - - if ([TxType.Bond, TxType.Unbond, TxType.Withdraw].includes(txType)) { - await this.broadcaster.updateStaking(); - } - } catch (e) { - console.warn(e); - await this.broadcaster.completeTx(msgId, txType, false, `${e}`); - } - }); - } - - async getTxBytes( - txType: TxType, - msgId: string, - address: string - ): Promise<{ bytes: Uint8Array; path: string }[]> { - const storedTx = await this.txStore.get(msgId); - - if (!storedTx) { - console.warn(`txMsg not found for msgId: ${msgId}`); - throw new Error(`Transfer Transaction ${msgId} not found!`); - } - - const { coinType } = chains.namada.bip44; - - return Promise.all( - storedTx.tx.map(async (pendingTx: PendingTx) => { - const { txMsg, specificMsg } = pendingTx; - try { - // Query account from Ledger storage to determine path for signer - const account = await this.keyringService.findByAddress(address); - - if (!account) { - throw new Error(`Ledger account not found for ${address}`); - } - - if (!account.publicKey) { - throw new Error(`Ledger account missing public key for ${address}`); - } - - if (account.type !== AccountType.Ledger) { - throw new Error(`Ledger account not found for ${address}`); - } - - const sdk = this.sdkService.getSdk(); - const builtTx = await sdk.tx.buildTxFromSerializedArgs( - txType, - fromBase64(specificMsg), - fromBase64(txMsg), - account.publicKey - ); - const path = makeBip44Path(coinType, account.path); - - return { bytes: builtTx.toBytes(), path }; - } catch (e) { - console.warn(e); - throw new Error(`${e}`); - } - }) - ); - } - - async queryStoredRevealedPK(publicKey: string): Promise { - const pks = await this.revealedPKStorage.getRevealedPKs(); - return pks?.includes(publicKey) || false; - } - - async storeRevealedPK(publicKey: string): Promise { - await this.revealedPKStorage.addRevealedPK(publicKey); - } -} diff --git a/apps/extension/src/background/offscreen/index.ts b/apps/extension/src/background/offscreen/index.ts deleted file mode 100644 index 178cd64f8..000000000 --- a/apps/extension/src/background/offscreen/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./utils"; diff --git a/apps/extension/src/background/offscreen/offscreen.html b/apps/extension/src/background/offscreen/offscreen.html deleted file mode 100644 index be7cc97bb..000000000 --- a/apps/extension/src/background/offscreen/offscreen.html +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/apps/extension/src/background/offscreen/offscreen.ts b/apps/extension/src/background/offscreen/offscreen.ts deleted file mode 100644 index 094bdb301..000000000 --- a/apps/extension/src/background/offscreen/offscreen.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - CloseOffscreenDocumentMsg, - TransferCompletedEvent, -} from "background/keyring"; -import { init as initSubmitTransferWebWorker } from "background/web-workers"; -import { SubmitTransferMessage } from "background/web-workers/types"; -import { ExtensionMessenger, ExtensionRequester } from "extension"; -import { Ports } from "router"; -import { OFFSCREEN_TARGET, SUBMIT_TRANSFER_MSG_TYPE } from "./utils"; - -const SW_TTL = 20000; - -void (async function init() { - let ww_count = 0; - chrome.runtime.onMessage.addListener(handleMessages); - - const pingSw = setInterval(() => { - // We do not have to "await" as this is fire and forget - void chrome.runtime.sendMessage({ keepAlive: true }); - }, SW_TTL); - - // Return value of true indicates response will be asynchronously - // sent using sendResponse; false otherwise. - function handleMessages( - submitTransferMessage: SubmitTransferMessage, - _sender: unknown, - sendResponse: (response?: unknown) => void - ): boolean { - const { data, type, routerId, target } = submitTransferMessage; - - if (target !== OFFSCREEN_TARGET) { - return false; - } - - const messenger = new ExtensionMessenger(); - const requester = new ExtensionRequester(messenger, routerId); - - const transferCompletedHandler = async ( - msgId: string, - success: boolean, - payload?: string - ): Promise => { - // We are sending the message to the background script - await requester.sendMessage( - Ports.Background, - new TransferCompletedEvent(success, msgId, payload) - ); - - // Reducing a number of tracked web workers - ww_count--; - - // If number of trached web workers is 0, we are - // closing the offscreen document and stopping the - // service worker ping. - if (ww_count === 0) { - // We do not have to wait for the response - void requester.sendMessage( - Ports.Background, - new CloseOffscreenDocumentMsg() - ); - clearInterval(pingSw); - // send blank response since returning true requires we send a response - sendResponse(); - } - }; - - if (type == SUBMIT_TRANSFER_MSG_TYPE) { - initSubmitTransferWebWorker(data, transferCompletedHandler, sendResponse); - ww_count++; - } else { - console.warn(`Unexpected message type received: '${type}'.`); - return false; - } - - return true; - } -})(); diff --git a/apps/extension/src/background/offscreen/utils.ts b/apps/extension/src/background/offscreen/utils.ts deleted file mode 100644 index a974e31b0..000000000 --- a/apps/extension/src/background/offscreen/utils.ts +++ /dev/null @@ -1,27 +0,0 @@ -declare let self: ServiceWorkerGlobalScope; - -export const hasOffscreenDocument = async (path: string): Promise => { - const offscreenUrl = chrome.runtime.getURL(path); - const matchedClients = await self.clients.matchAll(); - for (const client of matchedClients) { - if (client.url === offscreenUrl) { - return true; - } - } - return false; -}; - -export const createOffscreenWithTxWorker = async ( - offscreenDocumentPath: string -): Promise => { - await chrome.offscreen.createDocument({ - url: chrome.runtime.getURL(offscreenDocumentPath), - //TODO: change to WORKER with new version of chrome typings - reasons: [chrome.offscreen.Reason.IFRAME_SCRIPTING], - justification: - "We need to spawn WebWorkers to submit transfers in non-blocking way.", - }); -}; - -export const SUBMIT_TRANSFER_MSG_TYPE = "submit-transfer-offscreen"; -export const OFFSCREEN_TARGET = "offscreen.namada"; diff --git a/apps/extension/src/background/sdk/service.ts b/apps/extension/src/background/sdk/service.ts index 9d50297de..9686c45d6 100644 --- a/apps/extension/src/background/sdk/service.ts +++ b/apps/extension/src/background/sdk/service.ts @@ -1,7 +1,6 @@ -import { Sdk, getNativeToken, getSdk } from "@heliax/namada-sdk/web"; +import { Sdk, getSdk } from "@heliax/namada-sdk/web"; import sdkInit from "@heliax/namada-sdk/web-init"; import { chains } from "@namada/chains"; -import { Chain } from "@namada/types"; import { LocalStorage } from "storage"; const { @@ -24,32 +23,9 @@ export class SdkService { const { cryptoMemory } = await sdkInit(); - let tokenAddress = chain?.currency.address; - - if (!tokenAddress) { - try { - tokenAddress = await getNativeToken(rpc); - } catch (error) { - console.warn( - "Unable to query native token. Falling back to the default.", - error - ); - tokenAddress = defaultTokenAddress; - } - } - return new SdkService(rpc, defaultTokenAddress, cryptoMemory); } - /** - * Sync the chain information after a network update - * - * @param {Chain} chain - Chain information - */ - syncChain(chain: Chain): void { - this.rpc = chain.rpc; - } - getSdk(): Sdk { return getSdk(this.cryptoMemory, this.rpc, "NOT USED DB NAME", this.token); } diff --git a/apps/extension/src/background/web-workers/index.ts b/apps/extension/src/background/web-workers/index.ts deleted file mode 100644 index 93abbd297..000000000 --- a/apps/extension/src/background/web-workers/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - INIT_MSG, - Msg, - SubmitTransferMessageData, - TRANSFER_FAILED_MSG, - TRANSFER_SUCCESSFUL_MSG, - WEB_WORKER_ERROR_MSG, -} from "./types"; - -export const init = ( - data: SubmitTransferMessageData, - transferCompletedHandler: ( - msgId: string, - success: boolean, - payload?: string - ) => Promise, - sendResponse?: (response?: unknown) => void -): void => { - const w = new Worker("submit-transfer-web-worker.namada.js"); - - w.onmessage = (e: MessageEvent) => { - const { msgName, payload } = e.data; - if (msgName === INIT_MSG) { - w.postMessage(data); - } else if (msgName === TRANSFER_SUCCESSFUL_MSG) { - transferCompletedHandler(data.msgId, true, payload) - .then(() => w.terminate()) - .catch((e) => console.error(e)); - } else if (msgName === TRANSFER_FAILED_MSG) { - transferCompletedHandler(data.msgId, false, payload) - .then(() => w.terminate()) - .catch((e) => console.error(e)); - } else if (msgName === WEB_WORKER_ERROR_MSG) { - sendResponse?.({ error: payload }); - } else { - console.warn("Not supported msg type."); - } - }; -}; 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 deleted file mode 100644 index 24b998b08..000000000 --- a/apps/extension/src/background/web-workers/submit-transfer-web-worker.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { getSdk } from "@heliax/namada-sdk/web"; -import { initMulticore } from "@heliax/namada-sdk/web-init"; -import { - INIT_MSG, - SubmitTransferMessageData, - TRANSFER_FAILED_MSG, - TRANSFER_SUCCESSFUL_MSG, - WEB_WORKER_ERROR_MSG, -} from "./types"; - -(async function init() { - const { cryptoMemory } = await initMulticore(); - addEventListener( - "message", - async ({ data }: { data: SubmitTransferMessageData }) => { - try { - const { - signingKey: { privateKey, xsk }, - rpc, - nativeToken, - } = data; - const { txMsg, transferMsg } = data; - - const sdk = getSdk(cryptoMemory, rpc, "NOT USED DB NAME", nativeToken); - await sdk.masp.loadMaspParams("TODO: not used for time being"); - // For transparent transactions we have to reveal the public key. - if (privateKey) { - await sdk.tx.revealPk(privateKey, txMsg); - // For transfers from masp source we unshield to pay the fee. - // Because of that we have to pass spending key. - } else if (xsk) { - txMsg.feeUnshield = xsk; - transferMsg.source = xsk; - } - - const builtTx = await sdk.tx.buildTransfer(txMsg, data.transferMsg); - const signedTx = await sdk.tx.signTx(builtTx, privateKey); - const innerTxHash = await sdk.rpc.broadcastTx(signedTx); - - postMessage({ - msgName: TRANSFER_SUCCESSFUL_MSG, - payload: innerTxHash, - }); - } catch (error) { - console.error(error); - postMessage({ - msgName: TRANSFER_FAILED_MSG, - payload: error instanceof Error ? error.message : error, - }); - } - }, - false - ); - - postMessage({ msgName: INIT_MSG }); -})().catch((error) => { - const { message, stack } = error; - postMessage({ - msgName: WEB_WORKER_ERROR_MSG, - payload: { message, stack }, - }); -}); diff --git a/apps/extension/src/background/web-workers/types.ts b/apps/extension/src/background/web-workers/types.ts deleted file mode 100644 index 04cd0357a..000000000 --- a/apps/extension/src/background/web-workers/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { TransferMsgValue, TxMsgValue } from "@namada/types"; -import { SigningKey } from "background/keyring"; - -export type SubmitTransferMessage = { - type: string; - target: string; - routerId: number; - data: SubmitTransferMessageData; -}; - -export type SubmitTransferMessageData = { - transferMsg: TransferMsgValue; - txMsg: TxMsgValue; - msgId: string; - signingKey: SigningKey; - rpc: string; - nativeToken: string; -}; - -export const INIT_MSG = "init"; -export const TRANSFER_SUCCESSFUL_MSG = "transfer-successful"; -export const TRANSFER_FAILED_MSG = "transfer-failed"; -export const WEB_WORKER_ERROR_MSG = "web-worker-error"; -export type MsgName = - | typeof INIT_MSG - | typeof TRANSFER_FAILED_MSG - | typeof TRANSFER_SUCCESSFUL_MSG - | typeof WEB_WORKER_ERROR_MSG; - -export type Msg = { msgName: MsgName; payload?: string }; diff --git a/apps/extension/src/content/events.ts b/apps/extension/src/content/events.ts index 4bd0c8321..4ddb51518 100644 --- a/apps/extension/src/content/events.ts +++ b/apps/extension/src/content/events.ts @@ -1,4 +1,3 @@ -import { TxType } from "@heliax/namada-sdk/web"; import { Events } from "@namada/types"; import { LocalStorage } from "storage"; import { Message, Router, Routes } from "../router"; @@ -29,28 +28,6 @@ export class AccountChangedEventMsg extends Message { } } -export class UpdatedBalancesEventMsg extends Message { - public static type(): Events { - return Events.UpdatedBalances; - } - - constructor() { - super(); - } - - validate(): void { - return; - } - - route(): string { - return Routes.InteractionForeground; - } - - type(): string { - return UpdatedBalancesEventMsg.type(); - } -} - export class NetworkChangedEventMsg extends Message { public static type(): Events { return Events.NetworkChanged; @@ -73,114 +50,6 @@ export class NetworkChangedEventMsg extends Message { } } -export class UpdatedStakingEventMsg extends Message { - public static type(): Events { - return Events.UpdatedStaking; - } - - constructor() { - super(); - } - - validate(): void { - return; - } - - route(): string { - return Routes.InteractionForeground; - } - - type(): string { - return UpdatedStakingEventMsg.type(); - } -} - -export class TxStartedEvent extends Message { - public static type(): Events { - return Events.TxStarted; - } - - constructor( - public readonly msgId: string, - public readonly txType: TxType - ) { - super(); - } - - validate(): void { - if (!this.msgId) { - throw new Error("msgId should not be empty"); - } - - if (!this.txType) { - throw new Error("txType should not be empty"); - } - } - - route(): string { - return Routes.InteractionForeground; - } - - type(): string { - return TxStartedEvent.type(); - } -} - -export class TxCompletedEvent extends Message { - public static type(): Events { - return Events.TxCompleted; - } - - constructor( - public readonly msgId: string, - public readonly txType: TxType, - public readonly success?: boolean, - public readonly payload?: string - ) { - super(); - } - - validate(): void { - if (!this.msgId) { - throw new Error("msgId should not be empty"); - } - - if (!this.txType) { - throw new Error("txType should not be empty"); - } - } - - route(): string { - return Routes.InteractionForeground; - } - - type(): string { - return TxCompletedEvent.type(); - } -} - -export class ProposalsUpdatedEventMsg extends Message { - public static type(): Events { - return Events.ProposalsUpdated; - } - - constructor() { - super(); - } - - validate(): void { - return; - } - - route(): string { - return Routes.InteractionForeground; - } - - type(): string { - return ProposalsUpdatedEventMsg.type(); - } -} - export class VaultLockedEventMsg extends Message { public static type(): Events { return Events.ExtensionLocked; @@ -224,11 +93,6 @@ export class ConnectionRevokedEventMsg extends Message { export function initEvents(router: Router, localStorage: LocalStorage): void { router.registerMessage(AccountChangedEventMsg); router.registerMessage(NetworkChangedEventMsg); - router.registerMessage(UpdatedBalancesEventMsg); - router.registerMessage(UpdatedStakingEventMsg); - router.registerMessage(ProposalsUpdatedEventMsg); - router.registerMessage(TxStartedEvent); - router.registerMessage(TxCompletedEvent); router.registerMessage(VaultLockedEventMsg); router.registerMessage(ConnectionRevokedEventMsg); @@ -254,25 +118,6 @@ export function initEvents(router: Router, localStorage: LocalStorage): void { case NetworkChangedEventMsg: window.dispatchEvent(new CustomEvent(Events.NetworkChanged)); break; - case TxStartedEvent: - window.dispatchEvent( - new CustomEvent(Events.TxStarted, { detail: clonedMsg }) - ); - break; - case TxCompletedEvent: - window.dispatchEvent( - new CustomEvent(Events.TxCompleted, { detail: clonedMsg }) - ); - break; - case UpdatedBalancesEventMsg: - window.dispatchEvent(new CustomEvent(Events.UpdatedBalances)); - break; - case UpdatedStakingEventMsg: - window.dispatchEvent(new CustomEvent(Events.UpdatedStaking)); - break; - case ProposalsUpdatedEventMsg: - window.dispatchEvent(new CustomEvent(Events.ProposalsUpdated)); - break; case VaultLockedEventMsg: window.dispatchEvent(new CustomEvent(Events.ExtensionLocked)); break; diff --git a/apps/extension/src/extension/ExtensionBroadcaster.ts b/apps/extension/src/extension/ExtensionBroadcaster.ts index ed6e7c9d1..728e14e6c 100644 --- a/apps/extension/src/extension/ExtensionBroadcaster.ts +++ b/apps/extension/src/extension/ExtensionBroadcaster.ts @@ -1,13 +1,7 @@ -import { TxType } from "@heliax/namada-sdk/web"; import { AccountChangedEventMsg, ConnectionRevokedEventMsg, NetworkChangedEventMsg, - ProposalsUpdatedEventMsg, - TxCompletedEvent, - TxStartedEvent, - UpdatedBalancesEventMsg, - UpdatedStakingEventMsg, VaultLockedEventMsg, } from "content/events"; import { ExtensionRequester } from "extension"; @@ -20,29 +14,6 @@ export class ExtensionBroadcaster { protected readonly requester: ExtensionRequester ) {} - async startTx(msgId: string, txType: TxType): Promise { - await this.sendMsgToTabs(new TxStartedEvent(msgId, txType)); - } - - async completeTx( - msgId: string, - txType: TxType, - success: boolean, - payload?: string - ): Promise { - await this.sendMsgToTabs( - new TxCompletedEvent(msgId, txType, success, payload) - ); - } - - async updateBalance(): Promise { - await this.sendMsgToTabs(new UpdatedBalancesEventMsg()); - } - - async updateStaking(): Promise { - await this.sendMsgToTabs(new UpdatedStakingEventMsg()); - } - async updateAccounts(): Promise { await this.sendMsgToTabs(new AccountChangedEventMsg()); } @@ -51,10 +22,6 @@ export class ExtensionBroadcaster { await this.sendMsgToTabs(new NetworkChangedEventMsg()); } - async updateProposals(): Promise { - await this.sendMsgToTabs(new ProposalsUpdatedEventMsg()); - } - async lockExtension(): Promise { await this.sendMsgToTabs(new VaultLockedEventMsg()); } diff --git a/apps/extension/src/provider/InjectedNamada.ts b/apps/extension/src/provider/InjectedNamada.ts index b3cc90073..b5e878cc8 100644 --- a/apps/extension/src/provider/InjectedNamada.ts +++ b/apps/extension/src/provider/InjectedNamada.ts @@ -1,12 +1,11 @@ import { - BalancesProps, Chain, DerivedAccount, Namada as INamada, Signer as ISigner, SignArbitraryProps, - SignatureResponse, - TxMsgProps, + SignArbitraryResponse, + SignProps, VerifyArbitraryProps, } from "@namada/types"; import { InjectedProxy } from "./InjectedProxy"; @@ -35,13 +34,27 @@ export class InjectedNamada implements INamada { ); } - public async sign( + public async sign(props: SignProps): Promise { + return await InjectedProxy.requestMethod( + "sign", + props + ); + } + + public async signLedger(props: SignProps): Promise { + return await InjectedProxy.requestMethod( + "signLedger", + props + ); + } + + public async signArbitrary( props: SignArbitraryProps - ): Promise { + ): Promise { return await InjectedProxy.requestMethod< SignArbitraryProps, - SignatureResponse | undefined - >("sign", props); + SignArbitraryResponse | undefined + >("signArbitrary", props); } public async verify(props: VerifyArbitraryProps): Promise { @@ -51,19 +64,6 @@ export class InjectedNamada implements INamada { ); } - public async balances( - props: BalancesProps - ): Promise<{ token: string; amount: string }[]> { - return await InjectedProxy.requestMethod< - BalancesProps, - { token: string; amount: string }[] - >("balances", props); - } - - public async shieldedSync(): Promise { - return await InjectedProxy.requestMethod("shieldedSync"); - } - public async getChain(): Promise { return await InjectedProxy.requestMethod("getChain"); } @@ -72,13 +72,6 @@ export class InjectedNamada implements INamada { return new Signer(this); } - public async submitTx(props: TxMsgProps): Promise { - return await InjectedProxy.requestMethod( - "submitTx", - props - ); - } - public version(): string { return this._version; } diff --git a/apps/extension/src/provider/Namada.ts b/apps/extension/src/provider/Namada.ts index c80d36b62..1f94e781a 100644 --- a/apps/extension/src/provider/Namada.ts +++ b/apps/extension/src/provider/Namada.ts @@ -1,11 +1,12 @@ +import { toBase64 } from "@cosmjs/encoding"; import { - BalancesProps, + AccountType, Chain, DerivedAccount, Namada as INamada, SignArbitraryProps, - SignatureResponse, - TxMsgProps, + SignArbitraryResponse, + SignProps, VerifyArbitraryProps, } from "@namada/types"; import { MessageRequester, Ports } from "router"; @@ -13,16 +14,12 @@ import { MessageRequester, Ports } from "router"; import { ApproveConnectInterfaceMsg, ApproveSignArbitraryMsg, - ApproveTxMsg, + ApproveSignTxMsg, CheckDurabilityMsg, - FetchAndStoreMaspParamsMsg, GetChainMsg, - HasMaspParamsMsg, IsConnectionApprovedMsg, QueryAccountsMsg, - QueryBalancesMsg, QueryDefaultAccountMsg, - ShieldedSyncMsg, VerifyArbitraryMsg, } from "./messages"; @@ -70,42 +67,52 @@ export class Namada implements INamada { ); } - public async sign( - props: SignArbitraryProps - ): Promise { - const { signer, data } = props; + public async sign(props: SignProps): Promise { + const { accountType, signer, tx } = props; return await this.requester?.sendMessage( Ports.Background, - new ApproveSignArbitraryMsg(signer, data) + new ApproveSignTxMsg( + accountType, + signer, + tx.map((t) => [toBase64(t.txData), toBase64(t.signingData)]) + ) ); } - public async verify(props: VerifyArbitraryProps): Promise { - const { publicKey, hash, signature } = props; + public async signLedger(props: SignProps): Promise { + const { signer, tx } = props; return await this.requester?.sendMessage( Ports.Background, - new VerifyArbitraryMsg(publicKey, hash, signature) + new ApproveSignTxMsg( + AccountType.Ledger, + signer, + tx.map((t) => [toBase64(t.txData), toBase64(t.signingData)]) + ) ); } - public async fetchAndStoreMaspParams(): Promise { + public async signArbitrary( + props: SignArbitraryProps + ): Promise { + const { signer, data } = props; return await this.requester?.sendMessage( Ports.Background, - new FetchAndStoreMaspParamsMsg() + new ApproveSignArbitraryMsg(signer, data) ); } - public async getChain(): Promise { + public async verify(props: VerifyArbitraryProps): Promise { + const { publicKey, hash, signature } = props; return await this.requester?.sendMessage( Ports.Background, - new GetChainMsg() + new VerifyArbitraryMsg(publicKey, hash, signature) ); } - public async hasMaspParams(): Promise { + public async getChain(): Promise { return await this.requester?.sendMessage( Ports.Background, - new HasMaspParamsMsg() + new GetChainMsg() ); } @@ -116,30 +123,6 @@ export class Namada implements INamada { ); } - public async balances( - props: BalancesProps - ): Promise<{ token: string; amount: string }[] | undefined> { - const { owner, tokens } = props; - return await this.requester?.sendMessage( - Ports.Background, - new QueryBalancesMsg(owner, tokens) - ); - } - - public async shieldedSync(): Promise { - return await this.requester?.sendMessage( - Ports.Background, - new ShieldedSyncMsg() - ); - } - - public async submitTx(props: TxMsgProps): Promise { - return await this.requester?.sendMessage( - Ports.Background, - new ApproveTxMsg(props.txType, props.tx, props.type) - ); - } - public version(): string { return this._version; } diff --git a/apps/extension/src/provider/Signer.ts b/apps/extension/src/provider/Signer.ts index 5927f96dd..fa1928b21 100644 --- a/apps/extension/src/provider/Signer.ts +++ b/apps/extension/src/provider/Signer.ts @@ -1,32 +1,11 @@ -import { toBase64 } from "@cosmjs/encoding"; -import { SupportedTx, TxType } from "@heliax/namada-sdk/web"; import { chains } from "@namada/chains"; +import { BuiltTx } from "@namada/shared"; import { Account, AccountType, - BondMsgValue, - BondProps, - EthBridgeTransferMsgValue, - EthBridgeTransferProps, Signer as ISigner, - IbcTransferMsgValue, - IbcTransferProps, - Message, Namada, - RedelegateMsgValue, - RedelegateProps, - Schema, - SignatureResponse, - TransferMsgValue, - TransferProps, - TxMsgValue, - TxProps, - UnbondMsgValue, - UnbondProps, - VoteProposalMsgValue, - VoteProposalProps, - WithdrawMsgValue, - WithdrawProps, + SignArbitraryResponse, } from "@namada/types"; export class Signer implements ISigner { @@ -65,10 +44,38 @@ export class Signer implements ISigner { } public async sign( + signer: string, + builtTx: unknown | unknown[], + accountType?: AccountType + ): Promise { + const unsignedTx: BuiltTx[] = ( + builtTx instanceof Array ? builtTx : [builtTx]) as BuiltTx[]; + return await this._namada.sign({ + accountType: accountType || AccountType.PrivateKey, + signer, + tx: unsignedTx.map((builtTx) => { + const txData = builtTx.tx_bytes(); + const signingData = builtTx.signing_data_bytes(); + return { + txData, + signingData, + }; + }), + }); + } + + public async signLedger( + signer: string, + builtTx: unknown | unknown[] + ): Promise { + return this.sign(signer, builtTx, AccountType.Ledger); + } + + public async signArbitrary( signer: string, data: string - ): Promise { - return await this._namada.sign({ signer, data }); + ): Promise { + return await this._namada.signArbitrary({ signer, data }); } public async verify( @@ -78,145 +85,4 @@ export class Signer implements ISigner { ): Promise { return await this._namada.verify({ publicKey, hash, signature }); } - - private async submitTx( - txType: SupportedTx, - constructor: new (args: Args) => T, - args: Args | Args[], - txArgs: TxProps, - type: AccountType - ): Promise { - const tx = (args instanceof Array ? args : [args]).map((arg) => { - const msgValue = new constructor(arg); - const msg = new Message(); - const encoded = msg.encode(msgValue); - - const txMsgValue = new TxMsgValue(txArgs); - const txMsg = new Message(); - const txEncoded = txMsg.encode(txMsgValue); - - return { - specificMsg: toBase64(encoded), - txMsg: toBase64(txEncoded), - }; - }); - - return await this._namada.submitTx({ - txType, - tx, - type, - }); - } - - /** - * Submit bond transaction - */ - public async submitBond( - args: BondProps | BondProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx(TxType.Bond, BondMsgValue, args, txArgs, type); - } - - /** - * Submit unbond transaction - */ - public async submitUnbond( - args: UnbondProps | UnbondProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx(TxType.Unbond, UnbondMsgValue, args, txArgs, type); - } - - /** - * Submit withdraw transaction - */ - public async submitWithdraw( - args: WithdrawProps | WithdrawProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx(TxType.Withdraw, WithdrawMsgValue, args, txArgs, type); - } - - /** - * Submit redelegate transaction - */ - public async submitRedelegate( - args: RedelegateProps | RedelegateProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx( - TxType.Redelegate, - RedelegateMsgValue, - args, - txArgs, - type - ); - } - - /** - * Submit vote proposal transaction - */ - public async submitVoteProposal( - args: VoteProposalProps | VoteProposalProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx( - TxType.VoteProposal, - VoteProposalMsgValue, - args, - txArgs, - type - ); - } - - /** - * Submit a transfer - */ - public async submitTransfer( - args: TransferProps | TransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx(TxType.Transfer, TransferMsgValue, args, txArgs, type); - } - - /** - * Submit an ibc transfer - */ - public async submitIbcTransfer( - args: IbcTransferProps | IbcTransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx( - TxType.IBCTransfer, - IbcTransferMsgValue, - args, - txArgs, - type - ); - } - - /** - * Submit an eth bridge transfer - */ - public async submitEthBridgeTransfer( - args: EthBridgeTransferProps | EthBridgeTransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise { - return this.submitTx( - TxType.EthBridgeTransfer, - EthBridgeTransferMsgValue, - args, - txArgs, - type - ); - } } diff --git a/apps/extension/src/provider/messages.ts b/apps/extension/src/provider/messages.ts index 375c06619..a3595f7a4 100644 --- a/apps/extension/src/provider/messages.ts +++ b/apps/extension/src/provider/messages.ts @@ -1,11 +1,9 @@ -import type { SupportedTx } from "@heliax/namada-sdk/web"; import { AccountType, Chain, DerivedAccount, - SignatureResponse, + SignArbitraryResponse, } from "@namada/types"; -import { PendingTx } from "background/approvals"; import { Message } from "router"; import { validateProps } from "utils"; @@ -26,16 +24,10 @@ enum MessageType { ApproveConnectInterface = "approve-connect-interface", QueryAccounts = "query-accounts", QueryDefaultAccount = "query-default-account", - ApproveTx = "approve-tx", - QueryBalances = "query-balances", - ShieldedSync = "shielded-sync", - SubmitIbcTransfer = "submit-ibc-transfer", - SubmitLedgerTransfer = "submit-ledger-transfer", + ApproveSignTx = "approve-sign-tx", EncodeRevealPublicKey = "encode-reveal-public-key", GetChain = "get-chain", GetChains = "get-chains", - FetchAndStoreMaspParams = "fetch-and-store-masp-params", - HasMaspParams = "has-masp-params", ApproveEthBridgeTransfer = "approve-eth-bridge-transfer", CheckDurability = "check-durability", ApproveSignArbitrary = "approve-sign-arbitrary", @@ -139,56 +131,6 @@ export class QueryAccountsMsg extends Message { } } -export class QueryBalancesMsg extends Message< - { - token: string; - amount: string; - }[] -> { - public static type(): MessageType { - return MessageType.QueryBalances; - } - - constructor( - public readonly owner: string, - public readonly tokens: string[] - ) { - super(); - } - - validate(): void { - validateProps(this, ["owner", "tokens"]); - } - - route(): string { - return Route.KeyRing; - } - - type(): string { - return QueryBalancesMsg.type(); - } -} - -export class ShieldedSyncMsg extends Message { - public static type(): MessageType { - return MessageType.ShieldedSync; - } - - constructor() { - super(); - } - - validate(): void {} - - route(): string { - return Route.KeyRing; - } - - type(): string { - return ShieldedSyncMsg.type(); - } -} - export class QueryDefaultAccountMsg extends Message< DerivedAccount | undefined > { @@ -213,21 +155,21 @@ export class QueryDefaultAccountMsg extends Message< } } -export class ApproveTxMsg extends Message { +export class ApproveSignTxMsg extends Message { public static type(): MessageType { - return MessageType.ApproveTx; + return MessageType.ApproveSignTx; } constructor( - public readonly txType: SupportedTx, - public readonly tx: PendingTx[], - public readonly accountType: AccountType + public readonly accountType: AccountType, + public readonly signer: string, + public readonly tx: string[][] ) { super(); } validate(): void { - validateProps(this, ["txType", "tx", "accountType"]); + validateProps(this, ["accountType", "signer", "tx"]); } route(): string { @@ -235,41 +177,7 @@ export class ApproveTxMsg extends Message { } type(): string { - return ApproveTxMsg.type(); - } -} - -export class FetchAndStoreMaspParamsMsg extends Message { - public static type(): MessageType { - return MessageType.FetchAndStoreMaspParams; - } - validate(): void { - return; - } - - route(): string { - return Route.KeyRing; - } - - type(): string { - return FetchAndStoreMaspParamsMsg.type(); - } -} - -export class HasMaspParamsMsg extends Message { - public static type(): MessageType { - return MessageType.HasMaspParams; - } - validate(): void { - return; - } - - route(): string { - return Route.KeyRing; - } - - type(): string { - return HasMaspParamsMsg.type(); + return ApproveSignTxMsg.type(); } } @@ -290,7 +198,7 @@ export class CheckDurabilityMsg extends Message { } } -export class ApproveSignArbitraryMsg extends Message { +export class ApproveSignArbitraryMsg extends Message { public static type(): MessageType { return MessageType.ApproveSignArbitrary; } diff --git a/apps/extension/src/storage/RevealPKStorage.ts b/apps/extension/src/storage/RevealPKStorage.ts deleted file mode 100644 index 933b54cc4..000000000 --- a/apps/extension/src/storage/RevealPKStorage.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { KVStore } from "@namada/storage"; -import * as E from "fp-ts/Either"; -import * as t from "io-ts"; -import { ExtStorage } from "./Storage"; - -const PKs = t.array(t.string); - -type RevealPKSchemas = typeof PKs; - -type SchemasTypes = t.TypeOf; - -type RevealPKKeys = "revealed-pk-store"; -const schemasMap = new Map([ - [PKs, "revealed-pk-store"], -]); - -export class RevealedPKStorage extends ExtStorage { - constructor(provider: KVStore) { - super(provider); - } - - async getRevealedPKs(): Promise { - const data = await this.getRaw(this.getKey(PKs)); - const decodedData = PKs.decode(data); - - if (E.isLeft(decodedData)) { - throw new Error("RevealPK is not valid"); - } - - return decodedData.right; - } - - async setRevealedPKs(publicKeys: string[]): Promise { - await this.setRaw(this.getKey(PKs), publicKeys); - } - - async addRevealedPK(publicKey: string): Promise { - const data = (await this.getRevealedPKs()) || []; - if (!data.includes(publicKey)) { - data.push(publicKey); - } - await this.setRevealedPKs(data); - } - - private getKey(schema: S): RevealPKKeys { - const key = schemasMap.get(schema); - if (!key) { - throw new Error(`Could not find key for schema: ${schema}`); - } - - return key; - } -} diff --git a/apps/extension/src/storage/index.ts b/apps/extension/src/storage/index.ts index 9d2ec7e62..2519e97b5 100644 --- a/apps/extension/src/storage/index.ts +++ b/apps/extension/src/storage/index.ts @@ -1,3 +1,2 @@ export * from "./LocalStorage"; -export * from "./RevealPKStorage"; export * from "./VaultStorage"; diff --git a/apps/extension/src/test/init.ts b/apps/extension/src/test/init.ts index fbbc0c427..83ea9ce03 100644 --- a/apps/extension/src/test/init.ts +++ b/apps/extension/src/test/init.ts @@ -18,20 +18,19 @@ import { SessionPassword, VaultService } from "background/vault"; import { ApprovalsService, - TxStore, + PendingTx, init as initApprovals, } from "../background/approvals"; import { ChainsService } from "background/chains"; -import { LedgerService } from "background/ledger"; import { SdkService } from "background/sdk"; import { Namada } from "provider"; -import { LocalStorage, RevealedPKStorage, VaultStorage } from "storage"; +import { LocalStorage, VaultStorage } from "storage"; export class KVStoreMock implements KVStore { private storage: { [key: string]: T | null } = {}; - constructor(readonly _prefix: string) {} + constructor(readonly _prefix: string) { } get(key: string): Promise { return new Promise((resolve) => { @@ -63,13 +62,10 @@ export const init = async (): Promise<{ const extStore = new KVStoreMock(KVPrefix.IndexedDB); const utilityStore = new KVStoreMock(KVPrefix.Utility); const localStorage = new LocalStorage(new KVStoreMock(KVPrefix.LocalStorage)); - const revealedPKStore = new RevealedPKStorage( - new KVStoreMock(KVPrefix.RevealedPK) - ); const vaultStorage = new VaultStorage(new KVStoreMock(KVPrefix.IndexedDB)); const namadaRouterId = await getNamadaRouterId(localStorage); const requester = new ExtensionRequester(messenger, namadaRouterId); - const txStore = new KVStoreMock(KVPrefix.LocalStorage); + const txStore = new KVStoreMock(KVPrefix.LocalStorage); const dataStore = new KVStoreMock(KVPrefix.LocalStorage); const broadcaster = new ExtensionBroadcaster(localStorage, requester); @@ -107,22 +103,11 @@ export const init = async (): Promise<{ broadcaster ); - const ledgerService = new LedgerService( - keyRingService, - sdkService, - vaultStorage, - txStore, - revealedPKStore, - requester, - broadcaster - ); - const approvalsService = new ApprovalsService( txStore, dataStore, localStorage, keyRingService, - ledgerService, vaultService, broadcaster ); diff --git a/apps/extension/webpack.config.js b/apps/extension/webpack.config.js index 1bff01ad0..96e99dbe4 100644 --- a/apps/extension/webpack.config.js +++ b/apps/extension/webpack.config.js @@ -61,10 +61,6 @@ const copyPatterns = [ from: "./src/public/images/*", to: "./assets/images/[name][ext]", }, - { - from: "./src/background/offscreen/offscreen.html", - to: "./offscreen.html", - }, // browser-polyfill expects a source-map { from: "../../node_modules/webextension-polyfill/dist/browser-polyfill.js.map", @@ -90,9 +86,9 @@ const plugins = [ GENERATED_MANIFEST, MANIFEST_BASE_VERSION_PATH, MANIFEST_PATH, - ...(NODE_ENV === "development" && TARGET === "firefox" - ? [MANIFEST_V2_DEV_ONLY_PATH] - : []), + ...(NODE_ENV === "development" && TARGET === "firefox" ? + [MANIFEST_V2_DEV_ONLY_PATH] + : []), ], output: { fileName: "./manifest.json", @@ -139,9 +135,9 @@ module.exports = { mode: NODE_ENV, target: "webworker", devtool: - NODE_ENV === "development" && TARGET === "firefox" - ? "eval-source-map" - : false, + NODE_ENV === "development" && TARGET === "firefox" ? + "eval-source-map" + : false, entry: { content: "./src/content", background: "./src/background", @@ -149,9 +145,6 @@ module.exports = { setup: "./src/Setup", approvals: "./src/Approvals", injected: "./src/content/injected.ts", - offscreen: "./src/background/offscreen/offscreen.ts", - ["submit-transfer-web-worker"]: - "./src/background/web-workers/submit-transfer-web-worker.ts", }, output: { publicPath: "", diff --git a/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx b/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx index 4787f1b58..9397b2f7e 100644 --- a/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx +++ b/apps/namada-interface/src/App/Proposals/ProposalDetails.tsx @@ -4,9 +4,8 @@ import * as O from "fp-ts/Option"; import { chains } from "@namada/chains"; import { Select } from "@namada/components"; -import { getIntegration } from "@namada/integrations"; import { Query } from "@namada/shared"; -import { AccountType, Chain, Signer, Tokens } from "@namada/types"; +import { AccountType, Chain, Tokens } from "@namada/types"; import { shortenAddress } from "@namada/utils"; import { useAppSelector } from "store"; @@ -73,8 +72,6 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { const vote = useCallback( async (vote: boolean) => { const voteStr = vote ? "yay" : "nay"; - const integration = getIntegration(chains.namada.id); - const signer = integration.signer() as Signer; if (O.isNone(maybeProposal)) { throw new Error("No proposal"); @@ -85,7 +82,8 @@ export const ProposalDetails = (props: ProposalDetailsProps): JSX.Element => { } const proposal = maybeProposal.value; - await signer.submitVoteProposal( + console.log( + "TODO: Sign & submit vote", { signer: maybeActiveDelegator.value, vote: voteStr, diff --git a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx index 6a4bbf0f5..f4f6d23a2 100644 --- a/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx +++ b/apps/namada-interface/src/App/Token/EthereumBridge/EthereumBridge.tsx @@ -10,7 +10,6 @@ import { InputContainer, } from "../TokenSend/TokenSendForm.components"; -import { getIntegration } from "@namada/integrations"; import { FeeSection, FormContainer, @@ -32,16 +31,15 @@ const toTokenData = ( .filter(filterFn) .map(([tokenType, amount]) => ({ value: `${address}|${tokenType}|${amount}`, - label: `${alias !== "Namada" ? alias + " - " : ""}${ - Tokens[tokenType as TokenType].coin - } (${amount} ${tokenType})`, + label: `${alias !== "Namada" ? alias + " - " : ""}${Tokens[tokenType as TokenType].coin + } (${amount} ${tokenType})`, })); }); }; export const EthereumBridge = (): JSX.Element => { const { derived } = useAppSelector((state) => state.accounts); - const { id, chainId } = useAppSelector((state) => state.chain.config); + const { chainId } = useAppSelector((state) => state.chain.config); const [recipient, setRecipient] = useState(""); const [amount, setAmount] = useState(new BigNumber(0)); const [feeAmount, setFeeAmount] = useState(new BigNumber(0)); @@ -72,8 +70,7 @@ export const EthereumBridge = (): JSX.Element => { (account) => account?.details?.address === accountId ) as Account; - const integration = getIntegration(id); - await integration.submitBridgeTransfer( + console.log("TODO: Sign & submit EthereumBridge Transfer", { bridgeProps: { nut: Boolean(Tokens[tokenSymbol as TokenType]?.isNut), @@ -134,7 +131,7 @@ export const EthereumBridge = (): JSX.Element => { error={ recipientValid || !dirtyFields.has("recipient") ? "" - : "Invalid recipient" + : "Invalid recipient" } /> @@ -152,7 +149,7 @@ export const EthereumBridge = (): JSX.Element => { error={ amountValid || !dirtyFields.has("amount") ? "" - : "Insufficient balance" + : "Insufficient balance" } /> @@ -184,7 +181,7 @@ export const EthereumBridge = (): JSX.Element => { error={ feeAmountValid || !dirtyFields.has("feeAmount") ? "" - : "Insufficient balance" + : "Insufficient balance" } /> diff --git a/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx b/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx index af935a9a3..e34065336 100644 --- a/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx +++ b/apps/namada-interface/src/App/Token/IBCTransfer/IBCTransfer.tsx @@ -12,7 +12,6 @@ import { Stack, } from "@namada/components"; import { - getIntegration, useIntegrationConnection, useUntilIntegrationAttached, } from "@namada/integrations"; @@ -20,7 +19,6 @@ import { Account as AccountType, BridgeType, Chain, - ChainKey, CosmosTokenType, CosmosTokens, ExtensionKey, @@ -45,11 +43,10 @@ import { const { NAMADA_INTERFACE_NAMADA_TOKEN: - tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", + tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", } = process.env; export const submitIbcTransfer = async ( - chainKey: ChainKey, ibcArgs: TxIbcTransferArgs ): Promise => { const { @@ -62,9 +59,8 @@ export const submitIbcTransfer = async ( nativeToken, memo, } = ibcArgs; - const integration = getIntegration(chainKey); - return await integration.submitBridgeTransfer( + console.log("TODO: Sign and submit IBC Trasnfer", { ibcProps: { source: address, @@ -148,7 +144,7 @@ const IBCTransfer = (): JSX.Element => { 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(); @@ -173,7 +169,7 @@ const IBCTransfer = (): JSX.Element => { channelsByChain[sourceChain.id][destinationChain.id] ) ? [...channelsByChain[sourceChain.id][destinationChain.id]].reverse() - : []; + : []; const selectChannelsData = channels.map((channel: string) => ({ value: channel, @@ -192,9 +188,8 @@ const IBCTransfer = (): JSX.Element => { .map(([tokenType, amount]) => { return { value: `${address}|${tokenType}`, - label: `${alias} (${ - Tokens[tokenType as TokenType].symbol - }): ${amount}`, + label: `${alias} (${Tokens[tokenType as TokenType].symbol + }): ${amount}`, }; }); } @@ -299,7 +294,7 @@ const IBCTransfer = (): JSX.Element => { setError(undefined); const tokens = sourceChain.id === "namada" ? Tokens : CosmosTokens; if (sourceAccount && token) { - submitIbcTransfer(sourceChain.id, { + submitIbcTransfer({ account: sourceAccount.details, token: tokens[token as TokenType & CosmosTokenType], amount, @@ -424,7 +419,7 @@ const IBCTransfer = (): JSX.Element => { onClick={ currentExtensionAttachStatus === "attached" ? handleConnectSourceExtension - : handleDownloadExtension.bind( + : handleDownloadExtension.bind( null, destinationChain.extension.url ) @@ -432,17 +427,16 @@ const IBCTransfer = (): JSX.Element => { style={ currentExtensionAttachStatus === "pending" ? { color: "transparent" } - : {} + : {} } > {( currentExtensionAttachStatus === "attached" || currentExtensionAttachStatus === "pending" ) ? - `Load accounts from ${ - Extensions[sourceChain.extension.id].alias + `Load accounts from ${Extensions[sourceChain.extension.id].alias } Extension` - : "Click to download the extension"} + : "Click to download the extension"} )} @@ -455,9 +449,9 @@ const IBCTransfer = (): JSX.Element => { onChange={handleTokenChange} /> - : sourceAccounts.length > 0 ? - You have no token balances - : null} + : sourceAccounts.length > 0 ? + You have no token balances + : null} @@ -526,7 +520,7 @@ const IBCTransfer = (): JSX.Element => { onClick={ currentExtensionAttachStatus === "attached" ? handleConnectDestinationExtension - : handleDownloadExtension.bind( + : handleDownloadExtension.bind( null, destinationChain.extension.url ) @@ -534,17 +528,16 @@ const IBCTransfer = (): JSX.Element => { style={ currentExtensionAttachStatus === "pending" ? { color: "transparent" } - : {} + : {} } > {( currentExtensionAttachStatus === "attached" || currentExtensionAttachStatus === "pending" ) ? - `Load accounts from ${ - Extensions[destinationChain.extension.id].alias + `Load accounts from ${Extensions[destinationChain.extension.id].alias } Extension` - : "Click to download the extension"} + : "Click to download the extension"} )} @@ -579,7 +572,7 @@ const IBCTransfer = (): JSX.Element => { error={ isAmountValid(amount, currentBalance) || amount.isZero() ? undefined - : "Invalid amount!" + : "Invalid amount!" } /> diff --git a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx index 05e459e4d..6c172f507 100644 --- a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx +++ b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx @@ -1,11 +1,10 @@ import BigNumber from "bignumber.js"; import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; - +import { EncodedTx, Rpc, Tx, TxType } from "@heliax/namada-sdk/web"; import { chains } from "@namada/chains"; import { ActionButton, AmountInput, Icon, Input } from "@namada/components"; -import { getIntegration } from "@namada/integrations"; -import { Chain, Signer, TokenType, Tokens } from "@namada/types"; +import { Chain, TokenType, Tokens, WrapperTxProps } from "@namada/types"; import { TopLevelRoute } from "App/types"; import { AccountsState } from "slices/accounts"; @@ -19,14 +18,16 @@ import { InputContainer, TokenSendFormContainer, } from "./TokenSendForm.components"; +import { Namada, useIntegration } from "@namada/integrations"; +import { useSdk } from "hooks/useSdk"; const { NAMADA_INTERFACE_NAMADA_TOKEN: - tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", + tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", } = process.env; export const submitTransferTransaction = async ( - txTransferArgs: TxTransferArgs + txTransferArgs: TxTransferArgs, tx: Tx, rpc: Rpc, namada: Namada ): Promise => { const { account: { address, publicKey, type }, @@ -45,30 +46,78 @@ export const submitTransferTransaction = async ( return; } - const integration = getIntegration(chains.namada.id); - const signer = integration.signer() as Signer; + try { + const signingClient = namada.signer(); - const transferArgs = { - source: address, - target, - token: nativeToken, // TODO: Update to support other tokens again! - amount, - nativeToken, - }; + if (!signingClient) { + throw new Error("Signing client failed to initialize") + } - const txArgs = { - token: nativeToken, // TODO: Update to support other tokens again! - nativeToken, - feeAmount, - gasLimit, - chainId, - publicKey: publicKey, - signer: undefined, - disposableSigningKey, - memo, - }; + const txArray: EncodedTx[] = []; + + // Determine if RevealPK is needed: + const pk = await rpc.queryPublicKey(address); + + if (!pk) { + const revealTxProps: WrapperTxProps = { + token: nativeToken, + gasLimit: BigNumber(100000), + feeAmount: BigNumber(1), + chainId, + publicKey, + }; + console.log("Revealing public key with: ", { revealTxProps }) + const revealPkTx = await tx.buildRevealPk(revealTxProps, address); + // Add to txArray to sign & broadcast below: + txArray.push(revealPkTx) + } - await signer.submitTransfer(transferArgs, txArgs, type); + // Build + const transferProps = { + source: address, + target, + token: nativeToken, + amount, + nativeToken, + }; + + const wrapperTxProps = { + token: nativeToken, + nativeToken, + feeAmount, + gasLimit, + chainId, + publicKey: publicKey, + signer: undefined, + disposableSigningKey, + memo, + }; + console.log("Building Transfer Tx", { type, transferProps, wrapperTxProps, tx, rpc, namada }) + const transferTx = await tx.buildTx(TxType.Transfer, wrapperTxProps, transferProps); + console.log("Built transfer: ", transferTx) + // Add transfer to txArray + txArray.push(transferTx) + + // Submit to extension for signing: + const signedTxArray = await signingClient.sign( + transferProps.source, + txArray.map((encodedTx) => encodedTx.tx), + ); + console.log("Signed Tx Bytes Array: ", signedTxArray); + + if (!signedTxArray) { + // Signature failed: + console.error("Failed to sign Tx", txArray) + throw new Error("Signing failed") + } + // Broadcast Tx in order: + txArray.forEach(async ({ txMsg }, i) => { + const response = await rpc.broadcastTx({ wrapperTxMsg: txMsg, tx: signedTxArray[i] }); + console.log(`Broadcast Tx results for Tx ${i + 1}: `, response) + }) + } catch (e) { + throw new Error(`Failed to sign and submit transaction: ${e}`) + } }; type Props = { @@ -132,6 +181,9 @@ const TokenSendForm = ({ isRevealPkNeededFn, }: Props): JSX.Element => { const navigate = useNavigate(); + const sdk = useSdk(); + const namada = useIntegration("namada") + const { tx, rpc } = sdk const chain = useAppSelector((state) => state.chain.config); const [target, setTarget] = useState(defaultTarget); const [amount, setAmount] = useState(new BigNumber(0)); @@ -225,7 +277,7 @@ const TokenSendForm = ({ disposableSigningKey: isShieldedSource, memo, nativeToken: chain.currency.address || tokenAddress, - }); + }, tx, rpc, namada); } }; @@ -235,8 +287,8 @@ const TokenSendForm = ({ // if the transfer target is not TransferType.Shielded we perform the validation logic const isAmountValid = ( - address: string, - token: TokenType, + _address: string, + _token: TokenType, transferAmount: BigNumber, targetAddress: string | undefined ): string | undefined => { diff --git a/apps/namada-interface/src/hooks/index.ts b/apps/namada-interface/src/hooks/index.ts new file mode 100644 index 000000000..1cc763ef0 --- /dev/null +++ b/apps/namada-interface/src/hooks/index.ts @@ -0,0 +1 @@ +export * from "./useSdk"; diff --git a/apps/namada-interface/src/hooks/useSdk.tsx b/apps/namada-interface/src/hooks/useSdk.tsx new file mode 100644 index 000000000..23054b0ca --- /dev/null +++ b/apps/namada-interface/src/hooks/useSdk.tsx @@ -0,0 +1,42 @@ +import { Sdk, getSdk } from "@heliax/namada-sdk/web"; +import initSdk from "@heliax/namada-sdk/web-init"; +import { createContext, useContext, useEffect, useState } from "react"; + +const { NAMADA_INTERFACE_NAMADA_URL: rpcUrl = "http://localhost:27657" } = + process.env; +export const SdkContext = createContext(null); + +export const SdkProvider: React.FC = ({ children }) => { + const [sdk, setSdk] = useState(); + + useEffect(() => { + (async () => { + const { cryptoMemory } = await initSdk(); + const sdk = getSdk( + cryptoMemory, + rpcUrl, + "", + "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e" + ); + setSdk(sdk); + })(); + }, []); + + return ( + <> + {sdk ? ( + {children} + ) : null} + + ); +}; + +export const useSdk = (): Sdk => { + const sdkContext = useContext(SdkContext); + + if (!sdkContext) { + throw new Error("sdkContext has to be used within "); + } + + return sdkContext; +}; diff --git a/apps/namada-interface/src/index.tsx b/apps/namada-interface/src/index.tsx index 49c3400b7..6af0474da 100644 --- a/apps/namada-interface/src/index.tsx +++ b/apps/namada-interface/src/index.tsx @@ -1,4 +1,5 @@ import { init as initShared } from "@namada/shared/src/init-inline"; +import { SdkProvider } from "hooks/useSdk"; import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux"; @@ -16,11 +17,13 @@ initShared().then(() => { ReactDOM.render( - - - - - + + + + + + + , document.getElementById("root") diff --git a/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts b/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts index 825d2cc05..59fe98ad8 100644 --- a/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts +++ b/apps/namada-interface/src/slices/StakingAndGovernance/actions.ts @@ -1,10 +1,7 @@ import { createAsyncThunk } from "@reduxjs/toolkit"; import BigNumber from "bignumber.js"; -import { chains } from "@namada/chains"; -import { getIntegration } from "@namada/integrations"; import { Query } from "@namada/shared"; -import { Signer } from "@namada/types"; import { Account } from "slices/accounts"; import { RootState } from "store"; @@ -246,8 +243,6 @@ export const postNewBonding = createAsyncThunk< chainId, currency: { address: nativeToken }, } = thunkApi.getState().chain.config; - const integration = getIntegration(chains.namada.id); - const signer = integration.signer() as Signer; const { owner: source, validatorId: validator, @@ -259,14 +254,12 @@ export const postNewBonding = createAsyncThunk< const account = derived[id][source]; const { type, publicKey } = account.details; - await signer.submitBond( - // TODO: Interface should allow multiple Bond Tx - [{ - source, - validator, - amount: new BigNumber(amount), - nativeToken: nativeToken || tokenAddress, - }], + console.log("TODO: Sign & Submit bond", [{ + source, + validator, + amount: new BigNumber(amount), + nativeToken: nativeToken || tokenAddress, + }], { token: nativeToken || tokenAddress, feeAmount: gasPrice, @@ -276,7 +269,7 @@ export const postNewBonding = createAsyncThunk< memo, }, type - ); + ) }); // we post an unstake transaction @@ -296,8 +289,6 @@ export const postNewUnbonding = createAsyncThunk< currency: { address: nativeToken }, } = thunkApi.getState().chain.config; - const integration = getIntegration(id); - const signer = integration.signer() as Signer; const { owner: source, validatorId: validator, @@ -306,18 +297,18 @@ export const postNewUnbonding = createAsyncThunk< gasPrice, gasLimit, } = change; + const { details: { type, publicKey }, } = derived[id][source]; - await signer.submitUnbond( - // TODO: Interface should allow multiple Unbond Tx - [{ + console.log("TODO: Sign and submit Unbond", { + tx: [{ source, validator, amount: new BigNumber(amount), }], - { + wrapperTx: { token: nativeToken || tokenAddress, feeAmount: gasPrice, gasLimit, @@ -326,8 +317,9 @@ export const postNewUnbonding = createAsyncThunk< memo, }, type + } ); -}); +}) export const postNewWithdraw = createAsyncThunk< void, @@ -348,14 +340,12 @@ export const postNewWithdraw = createAsyncThunk< currency: { address: nativeToken }, } = thunkApi.getState().chain.config; - const integration = getIntegration(id); - const signer = integration.signer() as Signer; const { details: { type, publicKey }, } = derived[id][owner]; - await signer.submitWithdraw( - // TODO: Interface should allow multiple Withdraw Tx + // TODO: Interface should allow multiple Withdraw Tx + console.log("TODO: Sign & submit Withdraw", [{ source: owner, validator: validatorId, @@ -370,4 +360,4 @@ export const postNewWithdraw = createAsyncThunk< type ); } -); +) diff --git a/apps/namada-interface/src/slices/accounts.ts b/apps/namada-interface/src/slices/accounts.ts index 34d8cc6c7..ebf1bc26b 100644 --- a/apps/namada-interface/src/slices/accounts.ts +++ b/apps/namada-interface/src/slices/accounts.ts @@ -2,8 +2,10 @@ import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit"; import BigNumber from "bignumber.js"; import { atom } from "jotai"; +import { getSdk } from "@heliax/namada-sdk/web"; +import init from "@heliax/namada-sdk/web-init" import { chains } from "@namada/chains"; -import { getIntegration, Namada } from "@namada/integrations"; +import { getIntegration } from "@namada/integrations"; import { Account as AccountDetails, ChainKey, @@ -17,7 +19,8 @@ import { RootState } from "store"; const { NAMADA_INTERFACE_NAMADA_TOKEN: - tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", + tokenAddress = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", + NAMADA_INTERFACE_NAMADA_URL: rpcUrl = "http://localhost:27657" } = process.env; type Address = string; @@ -79,12 +82,25 @@ export const fetchBalance = createAsyncThunk< if (chainKey !== "namada") { throw new Error("not namada"); } - const integration = getIntegration(chainKey); - const balance = await integration.queryBalances(address, [ + const { cryptoMemory } = await init(); + const { rpc } = getSdk(cryptoMemory, rpcUrl, "", tokenAddress) + + const tokens = [ nativeToken || tokenAddress, - ]); + ] + + const balances = (await rpc.queryBalance(address, tokens)).map(([token, amount]) => { + return { + token, + amount + } + }) - return { chainKey, address, balance }; + return { + chainKey, + address, + balance: { NAM: BigNumber(balances[0].amount) } + } } ); @@ -166,7 +182,7 @@ export default reducer; //////////////////////////////////////////////////////////////////////////////// const accountsAtom = (() => { - const base = atom(new Promise(() => {})); + const base = atom(new Promise(() => { })); return atom( (get) => get(base), @@ -192,7 +208,6 @@ const balancesAtom = (() => { (get) => get(base), async (get, set) => { const accounts = await get(accountsAtom); - const namada = getIntegration("namada"); const { currency: { address: nativeToken }, @@ -217,16 +232,14 @@ const balancesAtom = (() => { // We query the balances for the transparent accounts first as it's faster const transparentBalances = await Promise.all( - queryBalance(namada, transparentAccounts, token) + queryBalance(transparentAccounts, token) ); transparentBalances.forEach(([address, balance]) => { set(base, { ...get(base), [address]: balance }); }); - await namada.sync(); - const shieldedBalances = await Promise.all( - queryBalance(namada, shieldedAccounts, token) + queryBalance(shieldedAccounts, token) ); shieldedBalances.forEach(([address, balance]) => { set(base, { ...get(base), [address]: balance }); @@ -236,18 +249,32 @@ const balancesAtom = (() => { })(); const queryBalance = ( - namada: Namada, accounts: AccountDetails[], token: string ): Promise<[string, TokenBalances]>[] => { return accounts.map(async (account): Promise<[string, TokenBalances]> => { - const balances = await namada.queryBalances(account.address, [token]); - return [account.address, balances]; + const { cryptoMemory } = await init(); + const { rpc } = getSdk(cryptoMemory, rpcUrl, "", tokenAddress) + + const tokens = [ + token, + ] + + const balances = (await rpc.queryBalance(account.address, tokens)).map(([token, amount]) => { + return { + token, + amount + } + }) + + // TODO: This is for testing + return [account.address, { NAM: BigNumber(balances[0].amount) }]; + }); }; const keplrAccountsAtom = (() => { - const base = atom(new Promise(() => {})); + const base = atom(new Promise(() => { })); return atom( (get) => get(base), @@ -269,7 +296,7 @@ const keplrAccountsAtom = (() => { })(); const keplrBalancesAtom = (() => { - const base = atom(new Promise>(() => {})); + const base = atom(new Promise>(() => { })); return atom( (get) => get(base), diff --git a/apps/namada-interface/src/slices/fees.ts b/apps/namada-interface/src/slices/fees.ts index b812a1c2d..8d2804979 100644 --- a/apps/namada-interface/src/slices/fees.ts +++ b/apps/namada-interface/src/slices/fees.ts @@ -16,7 +16,10 @@ const minimumGasPriceAtom = (() => { async (get, set) => { const { rpc, - currency: { address: nativeToken }, + currency: { + address: + nativeToken = "tnam1qxgfw7myv4dh0qna4hq0xdg6lx77fzl7dcem8h7e", + }, } = get(chainAtom); const query = new Query(rpc); diff --git a/apps/namada-interface/webpack.config.js b/apps/namada-interface/webpack.config.js index 40a62edf7..0b4d53be6 100644 --- a/apps/namada-interface/webpack.config.js +++ b/apps/namada-interface/webpack.config.js @@ -16,6 +16,15 @@ const createStyledComponentsTransformer = require("typescript-plugin-styled-components").default; const copyPatterns = [ + { + from: "../../packages/shared/src/shared/shared_bg.wasm", + to: "./shared.namada.wasm", + }, + { + from: "../../packages/crypto/src/crypto/crypto_bg.wasm", + to: "./crypto.namada.wasm", + }, + { from: "./public/*.png", to: "./assets/[name].png", diff --git a/packages/integrations/src/Keplr.ts b/packages/integrations/src/Keplr.ts index b390c6062..797d45a22 100644 --- a/packages/integrations/src/Keplr.ts +++ b/packages/integrations/src/Keplr.ts @@ -38,7 +38,7 @@ export const defaultSigningClientOptions: SigningStargateClientOptions = { broadcastTimeoutMs: 8_000, }; -class Keplr implements Integration { +class Keplr implements Integration { private _keplr: IKeplr | undefined; private _offlineSigner: OfflineSigner | undefined; /** diff --git a/packages/integrations/src/Namada.ts b/packages/integrations/src/Namada.ts index 25b2b81f6..20ba55413 100644 --- a/packages/integrations/src/Namada.ts +++ b/packages/integrations/src/Namada.ts @@ -1,21 +1,17 @@ import { Account, - AccountType, Chain, Namada as INamada, Signer, - TokenBalances, WindowWithNamada, } from "@namada/types"; -import { mapUndefined } from "@namada/utils"; -import BigNumber from "bignumber.js"; -import { BridgeProps, Integration } from "./types/Integration"; +import { Integration } from "./types/Integration"; export default class Namada implements Integration { private _namada: WindowWithNamada["namada"] | undefined; - constructor(public readonly chain: Chain) { } + constructor(public readonly chain: Chain) {} public get instance(): INamada | undefined { return this._namada; @@ -59,45 +55,4 @@ export default class Namada implements Integration { public signer(): Signer | undefined { return this._namada?.getSigner(); } - - public async submitBridgeTransfer( - props: BridgeProps, - type: AccountType - ): Promise { - const signer = this._namada?.getSigner(); - if (props.ibcProps) { - return await signer?.submitIbcTransfer( - props.ibcProps, - props.txProps, - type - ); - } else if (props.bridgeProps) { - return await signer?.submitEthBridgeTransfer( - props.bridgeProps, - props.txProps, - type - ); - } - - return Promise.reject("Invalid bridge transfer props!"); - } - - public async queryBalances( - owner: string, - tokens: string[] = [] - ): Promise { - const balances = (await this._namada?.balances({ owner, tokens })) || []; - - // TODO: fix this - return { - NAM: mapUndefined( - (amount) => new BigNumber(amount), - balances[0]?.amount || "0" - ), - }; - } - - public async sync(): Promise { - await this._namada?.shieldedSync(); - } } diff --git a/packages/integrations/src/types/Integration.ts b/packages/integrations/src/types/Integration.ts index a2ef75111..614c235ff 100644 --- a/packages/integrations/src/types/Integration.ts +++ b/packages/integrations/src/types/Integration.ts @@ -1,32 +1,20 @@ import { - AccountType, Chain, EthBridgeTransferProps, IbcTransferProps, - TokenBalances, - TokenType, - TxProps, + WrapperTxProps, } from "@namada/types"; export type BridgeProps = { ibcProps?: IbcTransferProps; bridgeProps?: EthBridgeTransferProps; - txProps: TxProps; + txProps: WrapperTxProps; }; -export interface Integration { +export interface Integration { detect: () => boolean; connect: (chainId: string) => Promise; accounts: () => Promise; getChain?: () => Promise; signer: () => S | undefined; - submitBridgeTransfer: ( - props: BridgeProps, - type: AccountType - ) => Promise; - queryBalances: ( - owner: string, - tokens?: string[] - ) => Promise>; - sync: (owners: string[]) => Promise; } diff --git a/packages/sdk/docs/classes/Crypto.md b/packages/sdk/docs/classes/Crypto.md index 281e43f97..da881a36e 100644 --- a/packages/sdk/docs/classes/Crypto.md +++ b/packages/sdk/docs/classes/Crypto.md @@ -40,7 +40,7 @@ Class Crypto handles AES encryption tasks #### Defined in -[sdk/src/crypto/crypto.ts:20](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L20) +[sdk/src/crypto/crypto.ts:20](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L20) ## Properties @@ -52,7 +52,7 @@ WebAssembly Memory for crypto #### Defined in -[sdk/src/crypto/crypto.ts:20](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L20) +[sdk/src/crypto/crypto.ts:20](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L20) ## Methods @@ -75,7 +75,7 @@ decrypted text #### Defined in -[sdk/src/crypto/crypto.ts:115](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L115) +[sdk/src/crypto/crypto.ts:115](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L115) ___ @@ -100,7 +100,7 @@ crypto record #### Defined in -[sdk/src/crypto/crypto.ts:61](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L61) +[sdk/src/crypto/crypto.ts:61](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L61) ___ @@ -126,7 +126,7 @@ array of encrypted bytes #### Defined in -[sdk/src/crypto/crypto.ts:98](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L98) +[sdk/src/crypto/crypto.ts:98](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L98) ___ @@ -153,7 +153,7 @@ crypto record used for storage #### Defined in -[sdk/src/crypto/crypto.ts:30](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L30) +[sdk/src/crypto/crypto.ts:30](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L30) ___ @@ -178,4 +178,4 @@ encryption parameters #### Defined in -[sdk/src/crypto/crypto.ts:73](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/crypto.ts#L73) +[sdk/src/crypto/crypto.ts:73](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/crypto.ts#L73) diff --git a/packages/sdk/docs/classes/EncodedTx.md b/packages/sdk/docs/classes/EncodedTx.md index f1b2618fc..53d6c0f83 100644 --- a/packages/sdk/docs/classes/EncodedTx.md +++ b/packages/sdk/docs/classes/EncodedTx.md @@ -42,7 +42,7 @@ Create an EncodedTx class #### Defined in -[sdk/src/tx/types.ts:12](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L12) +[sdk/src/tx/types.ts:12](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L12) ## Properties @@ -54,7 +54,7 @@ Specific tx struct instance #### Defined in -[sdk/src/tx/types.ts:14](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L14) +[sdk/src/tx/types.ts:14](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L14) ___ @@ -66,7 +66,7 @@ Borsh-serialized transaction #### Defined in -[sdk/src/tx/types.ts:13](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L13) +[sdk/src/tx/types.ts:13](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L13) ## Methods @@ -82,25 +82,25 @@ Clear tx bytes resource #### Defined in -[sdk/src/tx/types.ts:39](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L39) +[sdk/src/tx/types.ts:39](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L39) ___ ### hash -▸ **hash**(): `String` +▸ **hash**(): `string` Return the inner Tx hash of the built Tx #### Returns -`String` +`string` string of tx hash #### Defined in -[sdk/src/tx/types.ts:32](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L32) +[sdk/src/tx/types.ts:32](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L32) ___ @@ -119,4 +119,4 @@ Serialized tx bytes #### Defined in -[sdk/src/tx/types.ts:22](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L22) +[sdk/src/tx/types.ts:22](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L22) diff --git a/packages/sdk/docs/classes/Ledger.md b/packages/sdk/docs/classes/Ledger.md index f788f67be..f26dec974 100644 --- a/packages/sdk/docs/classes/Ledger.md +++ b/packages/sdk/docs/classes/Ledger.md @@ -42,7 +42,7 @@ Functionality for interacting with NamadaApp for Ledger Hardware Wallets #### Defined in -[sdk/src/ledger.ts:54](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L54) +[sdk/src/ledger.ts:54](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L54) ## Properties @@ -54,7 +54,7 @@ Inititalized NamadaApp class from Zondax package #### Defined in -[sdk/src/ledger.ts:54](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L54) +[sdk/src/ledger.ts:54](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L54) ## Methods @@ -75,7 +75,7 @@ void #### Defined in -[sdk/src/ledger.ts:176](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L176) +[sdk/src/ledger.ts:176](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L176) ___ @@ -102,7 +102,7 @@ Address and public key #### Defined in -[sdk/src/ledger.ts:97](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L97) +[sdk/src/ledger.ts:97](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L97) ___ @@ -123,7 +123,7 @@ Error message if error is found #### Defined in -[sdk/src/ledger.ts:159](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L159) +[sdk/src/ledger.ts:159](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L159) ___ @@ -150,7 +150,7 @@ Address and public key #### Defined in -[sdk/src/ledger.ts:118](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L118) +[sdk/src/ledger.ts:118](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L118) ___ @@ -178,7 +178,7 @@ Response signature #### Defined in -[sdk/src/ledger.ts:144](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L144) +[sdk/src/ledger.ts:144](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L144) ___ @@ -199,7 +199,7 @@ Version and info of NamadaApp #### Defined in -[sdk/src/ledger.ts:80](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L80) +[sdk/src/ledger.ts:80](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L80) ___ @@ -225,4 +225,4 @@ Ledger class instance #### Defined in -[sdk/src/ledger.ts:62](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L62) +[sdk/src/ledger.ts:62](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L62) diff --git a/packages/sdk/docs/classes/Masp.md b/packages/sdk/docs/classes/Masp.md index 2fafedb09..1e744ddd3 100644 --- a/packages/sdk/docs/classes/Masp.md +++ b/packages/sdk/docs/classes/Masp.md @@ -41,7 +41,7 @@ Class representing utilities related to MASP #### Defined in -[sdk/src/masp.ts:10](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L10) +[sdk/src/masp.ts:10](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L10) ## Properties @@ -53,7 +53,7 @@ Instance of Sdk struct from wasm lib #### Defined in -[sdk/src/masp.ts:10](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L10) +[sdk/src/masp.ts:10](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L10) ## Methods @@ -80,7 +80,7 @@ void #### Defined in -[sdk/src/masp.ts:69](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L69) +[sdk/src/masp.ts:69](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L69) ___ @@ -107,7 +107,7 @@ void #### Defined in -[sdk/src/masp.ts:47](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L47) +[sdk/src/masp.ts:47](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L47) ___ @@ -134,7 +134,7 @@ void #### Defined in -[sdk/src/masp.ts:58](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L58) +[sdk/src/masp.ts:58](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L58) ___ @@ -154,7 +154,7 @@ void #### Defined in -[sdk/src/masp.ts:26](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L26) +[sdk/src/masp.ts:26](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L26) ___ @@ -174,7 +174,7 @@ True if MASP parameters are loaded #### Defined in -[sdk/src/masp.ts:17](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L17) +[sdk/src/masp.ts:17](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L17) ___ @@ -200,4 +200,4 @@ void #### Defined in -[sdk/src/masp.ts:36](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/masp.ts#L36) +[sdk/src/masp.ts:36](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/masp.ts#L36) diff --git a/packages/sdk/docs/classes/Mnemonic.md b/packages/sdk/docs/classes/Mnemonic.md index 778792976..311714a60 100644 --- a/packages/sdk/docs/classes/Mnemonic.md +++ b/packages/sdk/docs/classes/Mnemonic.md @@ -38,7 +38,7 @@ Class for accessing mnemonic functionality from wasm #### Defined in -[sdk/src/mnemonic.ts:18](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/mnemonic.ts#L18) +[sdk/src/mnemonic.ts:18](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/mnemonic.ts#L18) ## Properties @@ -50,7 +50,7 @@ Memory accessor for crypto lib #### Defined in -[sdk/src/mnemonic.ts:18](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/mnemonic.ts#L18) +[sdk/src/mnemonic.ts:18](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/mnemonic.ts#L18) ## Methods @@ -76,7 +76,7 @@ Promise that resolves to array of words #### Defined in -[sdk/src/mnemonic.ts:26](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/mnemonic.ts#L26) +[sdk/src/mnemonic.ts:26](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/mnemonic.ts#L26) ___ @@ -101,7 +101,7 @@ Seed bytes #### Defined in -[sdk/src/mnemonic.ts:44](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/mnemonic.ts#L44) +[sdk/src/mnemonic.ts:44](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/mnemonic.ts#L44) ___ @@ -131,4 +131,4 @@ Object with validation result and error message if invalid #### Defined in -[sdk/src/mnemonic.ts:62](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/mnemonic.ts#L62) +[sdk/src/mnemonic.ts:62](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/mnemonic.ts#L62) diff --git a/packages/sdk/docs/classes/Rpc.md b/packages/sdk/docs/classes/Rpc.md index 115395896..8c3433dc4 100644 --- a/packages/sdk/docs/classes/Rpc.md +++ b/packages/sdk/docs/classes/Rpc.md @@ -51,7 +51,7 @@ API for executing RPC requests with Namada #### Defined in -[sdk/src/rpc/rpc.ts:31](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L31) +[sdk/src/rpc/rpc.ts:31](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L31) ## Properties @@ -63,7 +63,7 @@ Instance of Query struct from wasm lib #### Defined in -[sdk/src/rpc/rpc.ts:33](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L33) +[sdk/src/rpc/rpc.ts:33](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L33) ___ @@ -75,7 +75,7 @@ Instance of Sdk struct from wasm lib #### Defined in -[sdk/src/rpc/rpc.ts:32](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L32) +[sdk/src/rpc/rpc.ts:32](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L32) ## Methods @@ -101,7 +101,7 @@ void #### Defined in -[sdk/src/rpc/rpc.ts:210](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L210) +[sdk/src/rpc/rpc.ts:210](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L210) ___ @@ -121,7 +121,7 @@ Array of all validator addresses #### Defined in -[sdk/src/rpc/rpc.ts:73](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L73) +[sdk/src/rpc/rpc.ts:73](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L73) ___ @@ -148,7 +148,7 @@ Query balances from chain #### Defined in -[sdk/src/rpc/rpc.ts:43](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L43) +[sdk/src/rpc/rpc.ts:43](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L43) ___ @@ -174,7 +174,7 @@ Promise resolving to delegators votes #### Defined in -[sdk/src/rpc/rpc.ts:108](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L108) +[sdk/src/rpc/rpc.ts:108](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L108) ___ @@ -194,7 +194,7 @@ Query gas costs #### Defined in -[sdk/src/rpc/rpc.ts:200](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L200) +[sdk/src/rpc/rpc.ts:200](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L200) ___ @@ -214,7 +214,7 @@ Address of native token #### Defined in -[sdk/src/rpc/rpc.ts:52](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L52) +[sdk/src/rpc/rpc.ts:52](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L52) ___ @@ -234,7 +234,7 @@ List of the proposals #### Defined in -[sdk/src/rpc/rpc.ts:82](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L82) +[sdk/src/rpc/rpc.ts:82](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L82) ___ @@ -261,7 +261,7 @@ String of public key if found #### Defined in -[sdk/src/rpc/rpc.ts:63](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L63) +[sdk/src/rpc/rpc.ts:63](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L63) ___ @@ -287,7 +287,7 @@ Promise resolving to pending ethereum transfers #### Defined in -[sdk/src/rpc/rpc.ts:191](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L191) +[sdk/src/rpc/rpc.ts:191](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L191) ___ @@ -313,7 +313,7 @@ Promise resolving to staking positions #### Defined in -[sdk/src/rpc/rpc.ts:145](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L145) +[sdk/src/rpc/rpc.ts:145](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L145) ___ @@ -339,7 +339,7 @@ Promise resolving to staking totals #### Defined in -[sdk/src/rpc/rpc.ts:118](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L118) +[sdk/src/rpc/rpc.ts:118](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L118) ___ @@ -363,7 +363,7 @@ Total bonds amount #### Defined in -[sdk/src/rpc/rpc.ts:181](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L181) +[sdk/src/rpc/rpc.ts:181](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L181) ___ @@ -390,7 +390,7 @@ Promise resolving to total delegations #### Defined in -[sdk/src/rpc/rpc.ts:95](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L95) +[sdk/src/rpc/rpc.ts:95](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L95) ___ @@ -414,4 +414,4 @@ Sync the shielded context #### Defined in -[sdk/src/rpc/rpc.ts:221](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/rpc.ts#L221) +[sdk/src/rpc/rpc.ts:221](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/rpc.ts#L221) diff --git a/packages/sdk/docs/classes/Sdk.md b/packages/sdk/docs/classes/Sdk.md index 313c563e1..25c581422 100644 --- a/packages/sdk/docs/classes/Sdk.md +++ b/packages/sdk/docs/classes/Sdk.md @@ -61,7 +61,7 @@ API for interacting with Namada SDK #### Defined in -[sdk/src/sdk.ts:23](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L23) +[sdk/src/sdk.ts:23](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L23) ## Properties @@ -73,7 +73,7 @@ Memory accessor for crypto lib #### Defined in -[sdk/src/sdk.ts:26](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L26) +[sdk/src/sdk.ts:26](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L26) ___ @@ -85,7 +85,7 @@ Address of chain's native token #### Defined in -[sdk/src/sdk.ts:28](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L28) +[sdk/src/sdk.ts:28](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L28) ___ @@ -97,7 +97,7 @@ Instance of Query struct from wasm lib #### Defined in -[sdk/src/sdk.ts:25](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L25) +[sdk/src/sdk.ts:25](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L25) ___ @@ -109,7 +109,7 @@ Instance of Sdk struct from wasm lib #### Defined in -[sdk/src/sdk.ts:24](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L24) +[sdk/src/sdk.ts:24](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L24) ___ @@ -121,7 +121,7 @@ RPC url #### Defined in -[sdk/src/sdk.ts:27](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L27) +[sdk/src/sdk.ts:27](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L27) ## Accessors @@ -139,7 +139,7 @@ Utilities for encrypting and decrypting data #### Defined in -[sdk/src/sdk.ts:148](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L148) +[sdk/src/sdk.ts:148](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L148) ___ @@ -157,7 +157,7 @@ key-related functionality #### Defined in -[sdk/src/sdk.ts:124](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L124) +[sdk/src/sdk.ts:124](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L124) ___ @@ -175,7 +175,7 @@ Masp utilities for handling params #### Defined in -[sdk/src/sdk.ts:140](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L140) +[sdk/src/sdk.ts:140](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L140) ___ @@ -193,7 +193,7 @@ mnemonic-related functionality #### Defined in -[sdk/src/sdk.ts:116](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L116) +[sdk/src/sdk.ts:116](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L116) ___ @@ -211,7 +211,7 @@ rpc client #### Defined in -[sdk/src/sdk.ts:100](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L100) +[sdk/src/sdk.ts:100](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L100) ___ @@ -229,7 +229,7 @@ Non-Tx signing functionality #### Defined in -[sdk/src/sdk.ts:132](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L132) +[sdk/src/sdk.ts:132](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L132) ___ @@ -247,7 +247,7 @@ tx-related functionality #### Defined in -[sdk/src/sdk.ts:108](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L108) +[sdk/src/sdk.ts:108](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L108) ## Methods @@ -265,7 +265,7 @@ Utilities for encrypting and decrypting data #### Defined in -[sdk/src/sdk.ts:82](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L82) +[sdk/src/sdk.ts:82](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L82) ___ @@ -283,7 +283,7 @@ key-related functionality #### Defined in -[sdk/src/sdk.ts:58](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L58) +[sdk/src/sdk.ts:58](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L58) ___ @@ -301,7 +301,7 @@ Masp utilities for handling params #### Defined in -[sdk/src/sdk.ts:74](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L74) +[sdk/src/sdk.ts:74](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L74) ___ @@ -319,7 +319,7 @@ mnemonic-related functionality #### Defined in -[sdk/src/sdk.ts:50](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L50) +[sdk/src/sdk.ts:50](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L50) ___ @@ -337,7 +337,7 @@ Namada RPC client #### Defined in -[sdk/src/sdk.ts:34](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L34) +[sdk/src/sdk.ts:34](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L34) ___ @@ -355,7 +355,7 @@ Non-Tx signing functionality #### Defined in -[sdk/src/sdk.ts:66](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L66) +[sdk/src/sdk.ts:66](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L66) ___ @@ -373,7 +373,7 @@ Tx-related functionality #### Defined in -[sdk/src/sdk.ts:42](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L42) +[sdk/src/sdk.ts:42](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L42) ___ @@ -399,4 +399,4 @@ Class for interacting with NamadaApp for Ledger Hardware Wallets #### Defined in -[sdk/src/sdk.ts:92](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/sdk.ts#L92) +[sdk/src/sdk.ts:92](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/sdk.ts#L92) diff --git a/packages/sdk/docs/classes/SignedTx.md b/packages/sdk/docs/classes/SignedTx.md index 76ed7e510..e6b108a41 100644 --- a/packages/sdk/docs/classes/SignedTx.md +++ b/packages/sdk/docs/classes/SignedTx.md @@ -13,19 +13,19 @@ Wrap results of tx signing to simplify passing between Sdk functions ### Properties - [tx](SignedTx.md#tx) -- [txMsg](SignedTx.md#txmsg) +- [wrapperTxMsg](SignedTx.md#wrappertxmsg) ## Constructors ### constructor -• **new SignedTx**(`txMsg`, `tx`): [`SignedTx`](SignedTx.md) +• **new SignedTx**(`wrapperTxMsg`, `tx`): [`SignedTx`](SignedTx.md) #### Parameters | Name | Type | Description | | :------ | :------ | :------ | -| `txMsg` | `Uint8Array` | Serialized tx msg bytes | +| `wrapperTxMsg` | `Uint8Array` | Serialized wrapper tx msg bytes | | `tx` | `Uint8Array` | Serialized tx bytes | #### Returns @@ -34,7 +34,7 @@ Wrap results of tx signing to simplify passing between Sdk functions #### Defined in -[sdk/src/tx/types.ts:52](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L52) +[sdk/src/tx/types.ts:52](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L52) ## Properties @@ -46,16 +46,16 @@ Serialized tx bytes #### Defined in -[sdk/src/tx/types.ts:56](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L56) +[sdk/src/tx/types.ts:56](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L56) ___ -### txMsg +### wrapperTxMsg -• `Readonly` **txMsg**: `Uint8Array` +• `Readonly` **wrapperTxMsg**: `Uint8Array` -Serialized tx msg bytes +Serialized wrapper tx msg bytes #### Defined in -[sdk/src/tx/types.ts:54](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/types.ts#L54) +[sdk/src/tx/types.ts:54](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/types.ts#L54) diff --git a/packages/sdk/docs/classes/Signing.md b/packages/sdk/docs/classes/Signing.md index 2f7b3717a..029766be5 100644 --- a/packages/sdk/docs/classes/Signing.md +++ b/packages/sdk/docs/classes/Signing.md @@ -16,6 +16,7 @@ Non-Tx signing functions ### Methods +- [sign](Signing.md#sign) - [signArbitrary](Signing.md#signarbitrary) - [verifyArbitrary](Signing.md#verifyarbitrary) @@ -39,7 +40,7 @@ Signing constructor #### Defined in -[sdk/src/signing.ts:13](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/signing.ts#L13) +[sdk/src/signing.ts:13](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/signing.ts#L13) ## Properties @@ -51,10 +52,36 @@ Instance of Sdk struct from wasm lib #### Defined in -[sdk/src/signing.ts:13](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/signing.ts#L13) +[sdk/src/signing.ts:13](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/signing.ts#L13) ## Methods +### sign + +▸ **sign**(`builtTx`, `signingKey`, `chainId?`): `Promise`\<`Uint8Array`\> + +Sign Namada transaction + +#### Parameters + +| Name | Type | Description | +| :------ | :------ | :------ | +| `builtTx` | `BuiltTx` | BuiltTx instance | +| `signingKey` | `string` | private key | +| `chainId?` | `string` | optional chain ID, will enforce validation if present | + +#### Returns + +`Promise`\<`Uint8Array`\> + +signed tx bytes - Promise resolving to Uint8Array + +#### Defined in + +[sdk/src/signing.ts:22](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/signing.ts#L22) + +___ + ### signArbitrary ▸ **signArbitrary**(`signingKey`, `data`): `Signature` @@ -76,7 +103,7 @@ hash and signature #### Defined in -[sdk/src/signing.ts:21](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/signing.ts#L21) +[sdk/src/signing.ts:36](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/signing.ts#L36) ___ @@ -102,4 +129,4 @@ void #### Defined in -[sdk/src/signing.ts:32](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/signing.ts#L32) +[sdk/src/signing.ts:47](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/signing.ts#L47) diff --git a/packages/sdk/docs/classes/Tx.md b/packages/sdk/docs/classes/Tx.md index ad2f0f513..b3d45f887 100644 --- a/packages/sdk/docs/classes/Tx.md +++ b/packages/sdk/docs/classes/Tx.md @@ -30,7 +30,6 @@ SDK functionality related to transactions - [buildWithdraw](Tx.md#buildwithdraw) - [encodeTxArgs](Tx.md#encodetxargs) - [revealPk](Tx.md#revealpk) -- [signTx](Tx.md#signtx) ## Constructors @@ -50,7 +49,7 @@ SDK functionality related to transactions #### Defined in -[sdk/src/tx/tx.ts:34](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L34) +[sdk/src/tx/tx.ts:34](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L34) ## Properties @@ -62,7 +61,7 @@ Instance of Sdk struct from wasm lib #### Defined in -[sdk/src/tx/tx.ts:34](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L34) +[sdk/src/tx/tx.ts:34](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L34) ## Methods @@ -87,13 +86,13 @@ Append signature for transactions signed by Ledger Hardware Wallet #### Defined in -[sdk/src/tx/tx.ts:389](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L389) +[sdk/src/tx/tx.ts:391](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L391) ___ ### buildBond -▸ **buildBond**(`txProps`, `bondProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildBond**(`wrapperTxProps`, `bondProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Bond Tx @@ -101,7 +100,7 @@ Build Bond Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `bondProps` | `BondMsgValue` | properties of the bond tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to bondProps.source | @@ -115,13 +114,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:182](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L182) +[sdk/src/tx/tx.ts:193](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L193) ___ ### buildEthBridgeTransfer -▸ **buildEthBridgeTransfer**(`txProps`, `ethBridgeTransferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildEthBridgeTransfer**(`wrapperTxProps`, `ethBridgeTransferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Ethereum Bridge Transfer Tx @@ -129,7 +128,7 @@ Build Ethereum Bridge Transfer Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `ethBridgeTransferProps` | `EthBridgeTransferMsgValue` | properties of the eth bridge transfer tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to ethBridgeTransferProps.sender | @@ -143,13 +142,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:311](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L311) +[sdk/src/tx/tx.ts:322](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L322) ___ ### buildIbcTransfer -▸ **buildIbcTransfer**(`txProps`, `ibcTransferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildIbcTransfer**(`wrapperTxProps`, `ibcTransferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Ibc Transfer Tx @@ -157,7 +156,7 @@ Build Ibc Transfer Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `ibcTransferProps` | `IbcTransferMsgValue` | properties of the ibc transfer tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to ibcTransferProps.source | @@ -171,13 +170,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:284](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L284) +[sdk/src/tx/tx.ts:295](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L295) ___ ### buildRedelegate -▸ **buildRedelegate**(`txProps`, `redelegateProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildRedelegate**(`wrapperTxProps`, `redelegateProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Redelegate Tx @@ -185,7 +184,7 @@ Build Redelegate Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `redelegateProps` | `RedelegateMsgValue` | properties of the redelegate tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to redelegateProps.owner | @@ -199,13 +198,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:257](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L257) +[sdk/src/tx/tx.ts:268](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L268) ___ ### buildRevealPk -▸ **buildRevealPk**(`txProps`, `publicKey`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildRevealPk**(`wrapperTxProps`, `gasPayer`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build RevealPK Tx @@ -213,8 +212,8 @@ Build RevealPK Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | -| `publicKey` | `string` | public key to reveal | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | +| `gasPayer` | `string` | address for gas payer | #### Returns @@ -226,13 +225,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:163](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L163) +[sdk/src/tx/tx.ts:171](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L171) ___ ### buildTransfer -▸ **buildTransfer**(`txProps`, `transferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildTransfer**(`wrapperTxProps`, `transferProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Transfer Tx @@ -240,7 +239,7 @@ Build Transfer Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `transferProps` | `TransferMsgValue` | properties of the transfer | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to transferProps.source | @@ -254,13 +253,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:136](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L136) +[sdk/src/tx/tx.ts:144](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L144) ___ ### buildTx -▸ **buildTx**(`txType`, `txProps`, `props`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildTx**(`txType`, `wrapperTxProps`, `props`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Wrapper method to handle all supported Tx @@ -269,7 +268,7 @@ Wrapper method to handle all supported Tx | Name | Type | Description | | :------ | :------ | :------ | | `txType` | [`TxType`](../enums/TxType.md) | type of the transaction | -| `txProps` | `TxMsgValue` | transaction properties | +| `wrapperTxProps` | `WrapperTxMsgValue` | transaction properties | | `props` | `unknown` | Props specific to type of Tx | | `gasPayer?` | `string` | optional gas payer, defaults to source or sender | @@ -283,7 +282,7 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:70](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L70) +[sdk/src/tx/tx.ts:70](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L70) ___ @@ -312,13 +311,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:45](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L45) +[sdk/src/tx/tx.ts:45](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L45) ___ ### buildUnbond -▸ **buildUnbond**(`txProps`, `unbondProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildUnbond**(`wrapperTxProps`, `unbondProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Unbond Tx @@ -326,7 +325,7 @@ Build Unbond Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `unbondProps` | `UnbondMsgValue` | properties of the unbond tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to unbondProps.source | @@ -340,13 +339,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:207](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L207) +[sdk/src/tx/tx.ts:218](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L218) ___ ### buildVoteProposal -▸ **buildVoteProposal**(`txProps`, `voteProposalProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildVoteProposal**(`wrapperTxProps`, `voteProposalProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Built Vote Proposal Tx @@ -354,7 +353,7 @@ Built Vote Proposal Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `voteProposalProps` | `VoteProposalMsgValue` | properties of the vote proposal tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to voteProposalProps.signer | @@ -368,13 +367,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:338](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L338) +[sdk/src/tx/tx.ts:349](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L349) ___ ### buildWithdraw -▸ **buildWithdraw**(`txProps`, `withdrawProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> +▸ **buildWithdraw**(`wrapperTxProps`, `withdrawProps`, `gasPayer?`): `Promise`\<[`EncodedTx`](EncodedTx.md)\> Build Withdraw Tx @@ -382,7 +381,7 @@ Build Withdraw Tx | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | | `withdrawProps` | `WithdrawMsgValue` | properties of the withdraw tx | | `gasPayer?` | `string` | optional gas payer, if not provided, defaults to withdrawProps.source | @@ -396,13 +395,13 @@ promise that resolves to an EncodedTx #### Defined in -[sdk/src/tx/tx.ts:232](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L232) +[sdk/src/tx/tx.ts:243](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L243) ___ ### encodeTxArgs -▸ **encodeTxArgs**(`txProps`): `Uint8Array` +▸ **encodeTxArgs**(`wrapperTxProps`): `Uint8Array` Helper to encode Tx args given TxProps @@ -410,23 +409,23 @@ Helper to encode Tx args given TxProps | Name | Type | Description | | :------ | :------ | :------ | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | #### Returns `Uint8Array` -Serialized TxMsgValue +Serialized WrapperTxMsgValue #### Defined in -[sdk/src/tx/tx.ts:430](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L430) +[sdk/src/tx/tx.ts:432](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L432) ___ ### revealPk -▸ **revealPk**(`signingKey`, `txProps`): `Promise`\<`void`\> +▸ **revealPk**(`signingKey`, `wrapperTxProps`, `chainId?`): `Promise`\<`void`\> Reveal Public Key using serialized Tx @@ -435,7 +434,8 @@ Reveal Public Key using serialized Tx | Name | Type | Description | | :------ | :------ | :------ | | `signingKey` | `string` | signing key | -| `txProps` | `TxMsgValue` | properties of the transaction | +| `wrapperTxProps` | `WrapperTxMsgValue` | properties of the transaction | +| `chainId?` | `string` | optional chain ID - will enforce validation if present | #### Returns @@ -447,31 +447,4 @@ void #### Defined in -[sdk/src/tx/tx.ts:378](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L378) - -___ - -### signTx - -▸ **signTx**(`encodedTx`, `signingKey?`): `Promise`\<[`SignedTx`](SignedTx.md)\> - -Sign transaction - -#### Parameters - -| Name | Type | Description | -| :------ | :------ | :------ | -| `encodedTx` | [`EncodedTx`](EncodedTx.md) | encoded transaction | -| `signingKey?` | `string` | optional in the case of shielded tx | - -#### Returns - -`Promise`\<[`SignedTx`](SignedTx.md)\> - -promise that resolves to a SignedTx - -**`Async`** - -#### Defined in - -[sdk/src/tx/tx.ts:364](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/tx/tx.ts#L364) +[sdk/src/tx/tx.ts:376](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/tx/tx.ts#L376) diff --git a/packages/sdk/docs/enums/KdfType.md b/packages/sdk/docs/enums/KdfType.md index 6d4902b2e..be1c59560 100644 --- a/packages/sdk/docs/enums/KdfType.md +++ b/packages/sdk/docs/enums/KdfType.md @@ -17,7 +17,7 @@ #### Defined in -[sdk/src/crypto/types.ts:38](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L38) +[sdk/src/crypto/types.ts:38](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L38) ___ @@ -27,4 +27,4 @@ ___ #### Defined in -[sdk/src/crypto/types.ts:39](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L39) +[sdk/src/crypto/types.ts:39](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L39) diff --git a/packages/sdk/docs/modules.md b/packages/sdk/docs/modules.md index f6861e71d..e30d0075d 100644 --- a/packages/sdk/docs/modules.md +++ b/packages/sdk/docs/modules.md @@ -71,7 +71,7 @@ Address and public key type #### Defined in -[sdk/src/keys/types.ts:4](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/keys/types.ts#L4) +[sdk/src/keys/types.ts:4](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/keys/types.ts#L4) ___ @@ -88,7 +88,7 @@ ___ #### Defined in -[sdk/src/ledger.ts:17](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L17) +[sdk/src/ledger.ts:17](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L17) ___ @@ -98,7 +98,7 @@ ___ #### Defined in -[sdk/src/crypto/types.ts:23](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L23) +[sdk/src/crypto/types.ts:23](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L23) ___ @@ -111,7 +111,7 @@ Balance #### Defined in -[sdk/src/rpc/types.ts:69](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L69) +[sdk/src/rpc/types.ts:69](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L69) ___ @@ -130,7 +130,7 @@ ___ #### Defined in -[sdk/src/rpc/types.ts:27](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L27) +[sdk/src/rpc/types.ts:27](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L27) ___ @@ -158,7 +158,7 @@ ___ #### Defined in -[sdk/src/crypto/types.ts:42](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L42) +[sdk/src/crypto/types.ts:42](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L42) ___ @@ -171,7 +171,7 @@ Record #### Defined in -[sdk/src/rpc/types.ts:51](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L51) +[sdk/src/rpc/types.ts:51](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L51) ___ @@ -184,7 +184,7 @@ Record #### Defined in -[sdk/src/rpc/types.ts:57](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L57) +[sdk/src/rpc/types.ts:57](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L57) ___ @@ -203,7 +203,7 @@ ___ #### Defined in -[sdk/src/crypto/types.ts:30](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L30) +[sdk/src/crypto/types.ts:30](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L30) ___ @@ -220,7 +220,7 @@ ___ #### Defined in -[sdk/src/ledger.ts:18](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L18) +[sdk/src/ledger.ts:18](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L18) ___ @@ -240,7 +240,7 @@ Shielded keys and address #### Defined in -[sdk/src/keys/types.ts:19](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/keys/types.ts#L19) +[sdk/src/keys/types.ts:19](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/keys/types.ts#L19) ___ @@ -257,7 +257,7 @@ ___ #### Defined in -[sdk/src/rpc/types.ts:42](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L42) +[sdk/src/rpc/types.ts:42](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L42) ___ @@ -277,7 +277,7 @@ ___ #### Defined in -[sdk/src/rpc/types.ts:19](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L19) +[sdk/src/rpc/types.ts:19](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L19) ___ @@ -287,7 +287,7 @@ ___ #### Defined in -[shared/src/types.ts:3](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/shared/src/types.ts#L3) +[shared/src/types.ts:3](https://github.com/anoma/namada-interface/blob/2543347c/packages/shared/src/types.ts#L3) ___ @@ -299,7 +299,7 @@ Public and private keypair with address #### Defined in -[sdk/src/keys/types.ts:12](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/keys/types.ts#L12) +[sdk/src/keys/types.ts:12](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/keys/types.ts#L12) ___ @@ -319,7 +319,7 @@ ___ #### Defined in -[sdk/src/rpc/types.ts:34](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/rpc/types.ts#L34) +[sdk/src/rpc/types.ts:34](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/rpc/types.ts#L34) ## Variables @@ -337,7 +337,7 @@ ___ #### Defined in -[sdk/src/crypto/types.ts:3](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/crypto/types.ts#L3) +[sdk/src/crypto/types.ts:3](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/crypto/types.ts#L3) ___ @@ -347,7 +347,7 @@ ___ #### Defined in -[sdk/src/ledger.ts:41](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L41) +[sdk/src/ledger.ts:41](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L41) ___ @@ -357,7 +357,7 @@ ___ #### Defined in -[shared/src/types.ts:26](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/shared/src/types.ts#L26) +[shared/src/types.ts:26](https://github.com/anoma/namada-interface/blob/2543347c/packages/shared/src/types.ts#L26) ## Functions @@ -377,7 +377,7 @@ Transport object #### Defined in -[sdk/src/ledger.ts:37](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L37) +[sdk/src/ledger.ts:37](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L37) ___ @@ -397,7 +397,7 @@ Transport object #### Defined in -[sdk/src/ledger.ts:28](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/ledger.ts#L28) +[sdk/src/ledger.ts:28](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/ledger.ts#L28) ___ @@ -417,4 +417,4 @@ ___ #### Defined in -[sdk/src/keys/keys.ts:173](https://github.com/anoma/namada-interface/blob/1ed4d128/packages/sdk/src/keys/keys.ts#L173) +[sdk/src/keys/keys.ts:173](https://github.com/anoma/namada-interface/blob/2543347c/packages/sdk/src/keys/keys.ts#L173) diff --git a/packages/sdk/examples/submitTransfer.ts b/packages/sdk/examples/submitTransfer.ts index fa25796b5..a92732b3f 100644 --- a/packages/sdk/examples/submitTransfer.ts +++ b/packages/sdk/examples/submitTransfer.ts @@ -20,7 +20,7 @@ export const submitTransfer = async ( const { chainId, publicKey } = tx; const { source, target, amount } = transfer; - const txMsgValue = { + const wrapperTxMsgValue = { token: nativeToken, feeAmount: BigNumber(5), gasLimit: BigNumber(20_000), @@ -40,16 +40,22 @@ export const submitTransfer = async ( const sdk = getSdk(cryptoMemory, nodeUrl, "storage path", nativeToken); console.log("Revealing public key..."); - await sdk.tx.revealPk(signingKey, txMsgValue); + await sdk.tx.revealPk(signingKey, wrapperTxMsgValue); console.log("Building transfer transaction..."); - const encodedTx = await sdk.tx.buildTransfer(txMsgValue, transferMsgValue); + const encodedTx = await sdk.tx.buildTransfer( + wrapperTxMsgValue, + transferMsgValue + ); console.log("Signing transaction..."); - const signedTx = await sdk.tx.signTx(encodedTx, signingKey); + const signedTx = await sdk.signing.sign(encodedTx.tx, signingKey); console.log("Broadcasting transaction..."); - await sdk.rpc.broadcastTx(signedTx); + await sdk.rpc.broadcastTx({ + wrapperTxMsg: encodedTx.txMsg, + tx: signedTx, + }); process.exit(0); } catch (error) { console.error("Error:", error); diff --git a/packages/sdk/src/rpc/rpc.ts b/packages/sdk/src/rpc/rpc.ts index aaa7430e5..1e2e9191d 100644 --- a/packages/sdk/src/rpc/rpc.ts +++ b/packages/sdk/src/rpc/rpc.ts @@ -208,8 +208,8 @@ export class Rpc { * @returns void */ async broadcastTx(signedTx: SignedTx): Promise { - const { txMsg, tx } = signedTx; - return await this.sdk.process_tx(tx, txMsg); + const { wrapperTxMsg, tx } = signedTx; + return await this.sdk.process_tx(tx, wrapperTxMsg); } /** diff --git a/packages/sdk/src/signing.ts b/packages/sdk/src/signing.ts index 9cf7d1f57..ce766889f 100644 --- a/packages/sdk/src/signing.ts +++ b/packages/sdk/src/signing.ts @@ -1,4 +1,4 @@ -import { Sdk as SdkWasm } from "@namada/shared"; +import { BuiltTx, Sdk as SdkWasm } from "@namada/shared"; type Signature = [string, string]; @@ -12,6 +12,21 @@ export class Signing { */ constructor(protected readonly sdk: SdkWasm) {} + /** + * Sign Namada transaction + * @param builtTx - BuiltTx instance + * @param signingKey - private key + * @param [chainId] - optional chain ID, will enforce validation if present + * @returns signed tx bytes - Promise resolving to Uint8Array + */ + async sign( + builtTx: BuiltTx, + signingKey: string, + chainId?: string + ): Promise { + return await this.sdk.sign_tx(builtTx, signingKey, chainId); + } + /** * Sign arbitrary data * @param signingKey - private key diff --git a/packages/sdk/src/tx/tx.ts b/packages/sdk/src/tx/tx.ts index fed9fbb4e..90167c0a0 100644 --- a/packages/sdk/src/tx/tx.ts +++ b/packages/sdk/src/tx/tx.ts @@ -12,17 +12,17 @@ import { SignatureMsgValue, TransferMsgValue, TransferProps, - TxMsgValue, - TxProps, UnbondMsgValue, UnbondProps, VoteProposalMsgValue, VoteProposalProps, WithdrawMsgValue, WithdrawProps, + WrapperTxMsgValue, + WrapperTxProps, } from "@namada/types"; import { ResponseSign } from "@zondax/ledger-namada"; -import { EncodedTx, SignedTx } from "./types"; +import { EncodedTx } from "./types"; /** * SDK functionality related to transactions @@ -62,61 +62,69 @@ export class Tx { * Wrapper method to handle all supported Tx * @async * @param txType - type of the transaction - * @param txProps - transaction properties + * @param wrapperTxProps - transaction properties * @param props - Props specific to type of Tx * @param [gasPayer] - optional gas payer, defaults to source or sender * @returns promise that resolves to an EncodedTx */ async buildTx( txType: TxType, - txProps: TxProps, + wrapperTxProps: WrapperTxProps, props: unknown, gasPayer?: string ): Promise { switch (txType) { case TxType.Bond: - return await this.buildBond(txProps, props as BondProps, gasPayer); + return await this.buildBond( + wrapperTxProps, + props as BondProps, + gasPayer + ); case TxType.Unbond: - return await this.buildUnbond(txProps, props as UnbondProps, gasPayer); + return await this.buildUnbond( + wrapperTxProps, + props as UnbondProps, + gasPayer + ); case TxType.Withdraw: return await this.buildWithdraw( - txProps, + wrapperTxProps, props as WithdrawProps, gasPayer ); case TxType.Redelegate: return await this.buildRedelegate( - txProps, + wrapperTxProps, props as RedelegateProps, gasPayer ); case TxType.RevealPK: - const { publicKey } = txProps; + const { publicKey } = wrapperTxProps; if (!publicKey) { throw new Error("For RevealPK you must provide a public key!"); } - return await this.buildRevealPk(txProps, publicKey); + return await this.buildRevealPk(wrapperTxProps, publicKey); case TxType.Transfer: return await this.buildTransfer( - txProps, + wrapperTxProps, props as TransferProps, gasPayer ); case TxType.IBCTransfer: return await this.buildIbcTransfer( - txProps, + wrapperTxProps, props as IbcTransferProps, gasPayer ); case TxType.VoteProposal: return await this.buildVoteProposal( - txProps, + wrapperTxProps, props as VoteProposalProps, gasPayer ); case TxType.EthBridgeTransfer: return await this.buildEthBridgeTransfer( - txProps, + wrapperTxProps, props as EthBridgeTransferProps, gasPayer ); @@ -128,19 +136,19 @@ export class Tx { /** * Build Transfer Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param transferProps - properties of the transfer * @param [gasPayer] - optional gas payer, if not provided, defaults to transferProps.source * @returns promise that resolves to an EncodedTx */ async buildTransfer( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, transferProps: TransferProps, gasPayer?: string ): Promise { const transferMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedTransfer = transferMsg.encode( new TransferMsgValue(transferProps) ); @@ -156,36 +164,39 @@ export class Tx { /** * Build RevealPK Tx * @async - * @param txProps - properties of the transaction - * @param publicKey - public key to reveal + * @param wrapperTxProps - properties of the transaction + * @param gasPayer - address for gas payer * @returns promise that resolves to an EncodedTx */ - async buildRevealPk(txProps: TxProps, publicKey: string): Promise { - const encodedTx = this.encodeTxArgs(txProps); + async buildRevealPk( + wrapperTxProps: WrapperTxProps, + gasPayer: string + ): Promise { + const encodedTx = this.encodeTxArgs(wrapperTxProps); return await this.buildTxFromSerializedArgs( TxType.RevealPK, new Uint8Array(), encodedTx, - publicKey + gasPayer ); } /** * Build Bond Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param bondProps - properties of the bond tx * @param [gasPayer] - optional gas payer, if not provided, defaults to bondProps.source * @returns promise that resolves to an EncodedTx */ async buildBond( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, bondProps: BondProps, gasPayer?: string ): Promise { const bondMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedBond = bondMsg.encode(new BondMsgValue(bondProps)); return await this.buildTxFromSerializedArgs( @@ -199,18 +210,18 @@ export class Tx { /** * Build Unbond Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param unbondProps - properties of the unbond tx * @param [gasPayer] - optional gas payer, if not provided, defaults to unbondProps.source * @returns promise that resolves to an EncodedTx */ async buildUnbond( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, unbondProps: UnbondProps, gasPayer?: string ): Promise { const bondMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedUnbond = bondMsg.encode(new UnbondMsgValue(unbondProps)); return await this.buildTxFromSerializedArgs( @@ -224,21 +235,21 @@ export class Tx { /** * Build Withdraw Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param withdrawProps - properties of the withdraw tx * @param [gasPayer] - optional gas payer, if not provided, defaults to withdrawProps.source * @returns promise that resolves to an EncodedTx */ async buildWithdraw( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, withdrawProps: WithdrawProps, gasPayer?: string ): Promise { const bondMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedWithdraw = bondMsg.encode(new WithdrawMsgValue(withdrawProps)); - return this.buildTxFromSerializedArgs( + return await this.buildTxFromSerializedArgs( TxType.Withdraw, encodedWithdraw, encodedTx, @@ -249,18 +260,18 @@ export class Tx { /** * Build Redelegate Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param redelegateProps - properties of the redelegate tx * @param [gasPayer] - optional gas payer, if not provided, defaults to redelegateProps.owner * @returns promise that resolves to an EncodedTx */ async buildRedelegate( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, redelegateProps: RedelegateProps, gasPayer?: string ): Promise { const redelegateMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedRedelegate = redelegateMsg.encode( new RedelegateMsgValue(redelegateProps) ); @@ -276,23 +287,23 @@ export class Tx { /** * Build Ibc Transfer Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param ibcTransferProps - properties of the ibc transfer tx * @param [gasPayer] - optional gas payer, if not provided, defaults to ibcTransferProps.source * @returns promise that resolves to an EncodedTx */ async buildIbcTransfer( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, ibcTransferProps: IbcTransferProps, gasPayer?: string ): Promise { const ibcTransferMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedIbcTransfer = ibcTransferMsg.encode( new IbcTransferMsgValue(ibcTransferProps) ); - return this.buildTxFromSerializedArgs( + return await this.buildTxFromSerializedArgs( TxType.IBCTransfer, encodedIbcTransfer, encodedTx, @@ -303,23 +314,23 @@ export class Tx { /** * Build Ethereum Bridge Transfer Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param ethBridgeTransferProps - properties of the eth bridge transfer tx * @param [gasPayer] - optional gas payer, if not provided, defaults to ethBridgeTransferProps.sender * @returns promise that resolves to an EncodedTx */ async buildEthBridgeTransfer( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, ethBridgeTransferProps: EthBridgeTransferProps, gasPayer?: string ): Promise { const ethBridgeTransferMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedEthBridgeTransfer = ethBridgeTransferMsg.encode( new EthBridgeTransferMsgValue(ethBridgeTransferProps) ); - return this.buildTxFromSerializedArgs( + return await this.buildTxFromSerializedArgs( TxType.EthBridgeTransfer, encodedEthBridgeTransfer, encodedTx, @@ -330,23 +341,23 @@ export class Tx { /** * Built Vote Proposal Tx * @async - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction * @param voteProposalProps - properties of the vote proposal tx * @param [gasPayer] - optional gas payer, if not provided, defaults to voteProposalProps.signer * @returns promise that resolves to an EncodedTx */ async buildVoteProposal( - txProps: TxProps, + wrapperTxProps: WrapperTxProps, voteProposalProps: VoteProposalProps, gasPayer?: string ): Promise { const voteProposalMsg = new Message(); - const encodedTx = this.encodeTxArgs(txProps); + const encodedTx = this.encodeTxArgs(wrapperTxProps); const encodedVoteProposal = voteProposalMsg.encode( new VoteProposalMsgValue(voteProposalProps) ); - return this.buildTxFromSerializedArgs( + return await this.buildTxFromSerializedArgs( TxType.VoteProposal, encodedVoteProposal, encodedTx, @@ -354,30 +365,21 @@ export class Tx { ); } - /** - * Sign transaction - * @async - * @param encodedTx - encoded transaction - * @param [signingKey] - optional in the case of shielded tx - * @returns promise that resolves to a SignedTx - */ - async signTx(encodedTx: EncodedTx, signingKey?: string): Promise { - const { tx, txMsg } = encodedTx; - const signedTx = await this.sdk.sign_tx(tx, txMsg, signingKey); - - return new SignedTx(txMsg, signedTx); - } - /** * Reveal Public Key using serialized Tx * @async * @param signingKey - signing key - * @param txProps - properties of the transaction + * @param wrapperTxProps - properties of the transaction + * @param [chainId] - optional chain ID - will enforce validation if present * @returns void */ - async revealPk(signingKey: string, txProps: TxProps): Promise { - const encodedTx = this.encodeTxArgs(txProps); - return await this.sdk.reveal_pk(signingKey, encodedTx); + async revealPk( + signingKey: string, + wrapperTxProps: WrapperTxProps, + chainId?: string + ): Promise { + const encodedTx = this.encodeTxArgs(wrapperTxProps); + return await this.sdk.reveal_pk(signingKey, encodedTx, chainId); } /** @@ -424,12 +426,12 @@ export class Tx { /** * Helper to encode Tx args given TxProps - * @param txProps - properties of the transaction - * @returns Serialized TxMsgValue + * @param wrapperTxProps - properties of the transaction + * @returns Serialized WrapperTxMsgValue */ - encodeTxArgs(txProps: TxProps): Uint8Array { - const txMsgValue = new TxMsgValue(txProps); - const msg = new Message(); + encodeTxArgs(wrapperTxProps: WrapperTxProps): Uint8Array { + const txMsgValue = new WrapperTxMsgValue(wrapperTxProps); + const msg = new Message(); return msg.encode(txMsgValue); } } diff --git a/packages/sdk/src/tx/types.ts b/packages/sdk/src/tx/types.ts index 5a6c3ae0e..ed781818f 100644 --- a/packages/sdk/src/tx/types.ts +++ b/packages/sdk/src/tx/types.ts @@ -46,12 +46,12 @@ export class EncodedTx { */ export class SignedTx { /** - * @param txMsg - Serialized tx msg bytes + * @param wrapperTxMsg - Serialized wrapper tx msg bytes * @param tx - Serialized tx bytes */ constructor( - // Serialized TxMsg - public readonly txMsg: Uint8Array, + // Serialized WrapperTxMsg + public readonly wrapperTxMsg: Uint8Array, // Built Tx public readonly tx: Uint8Array ) {} diff --git a/packages/shared/lib/src/sdk/mod.rs b/packages/shared/lib/src/sdk/mod.rs index 3b1ce14ae..995c4078f 100644 --- a/packages/shared/lib/src/sdk/mod.rs +++ b/packages/shared/lib/src/sdk/mod.rs @@ -14,10 +14,9 @@ use namada::core::borsh::{self, BorshDeserialize}; use namada::hash::Hash; use namada::key::{common, ed25519, SigScheme}; use namada::ledger::eth_bridge::bridge_pool::build_bridge_pool_tx; -use namada::masp::TransferSource; -use namada::sdk::masp::{DefaultLogger, ShieldedContext}; +use namada::sdk::masp::ShieldedContext; use namada::sdk::rpc::query_epoch; -use namada::sdk::signing::{find_key_by_pk, SigningTxData}; +use namada::sdk::signing::SigningTxData; use namada::sdk::tx::build_redelegation; use namada::sdk::tx::{ build_bond, build_ibc_transfer, build_reveal_pk, build_transfer, build_unbond, @@ -62,6 +61,23 @@ impl BuiltTx { pub fn tx_hash(&self) -> String { self.tx.raw_header_hash().to_string() } + + pub fn signing_data_bytes(&self) -> Result, JsError> { + let signing_data = tx::SigningData::from_signing_tx_data(self.signing_data.clone())?; + Ok(signing_data.to_bytes()?) + } + + // Return instance from serialized values + pub fn from_stored_tx( + tx_bytes: Vec, + signing_data_bytes: Vec, + ) -> Result { + let tx: Tx = borsh::from_slice(&tx_bytes)?; + let signing_data: tx::SigningData = borsh::from_slice(&signing_data_bytes)?; + let signing_data: SigningTxData = signing_data.to_signing_tx_data()?; + + Ok(BuiltTx { tx, signing_data }) + } } /// Represents the Sdk public API. @@ -184,15 +200,26 @@ impl Sdk { pub async fn sign_tx( &mut self, built_tx: BuiltTx, - tx_msg: &[u8], private_key: Option, + chain_id: Option, ) -> Result { - let args = tx::tx_args_from_slice(tx_msg)?; - - let BuiltTx { - mut tx, - signing_data, - } = built_tx; + let signing_data_bytes = built_tx.signing_data_bytes()?; + let tx_bytes = built_tx.tx_bytes()?; + let signing_data: tx::SigningData = borsh::from_slice(&signing_data_bytes)?; + let signing_data = signing_data.to_signing_tx_data()?; + + let mut tx: Tx = borsh::from_slice(&tx_bytes)?; + + // If chain_id is provided, validate this against value in Tx header + if let Some(c) = chain_id { + if c != tx.header.chain_id.to_string() { + return Err(JsError::new(&format!( + "chain_id {} does not match Tx header chain_id {}", + &c, + tx.header.chain_id.as_str() + ))); + } + } let signing_keys = match private_key.clone() { Some(private_key) => vec![common::SecretKey::Ed25519(ed25519::SecretKey::from_str( @@ -214,17 +241,9 @@ impl Sdk { } } - let key = { - let mut wallet = self.namada.wallet_mut().await; - find_key_by_pk(&mut *wallet, &args, &signing_data.fee_payer) - }; - // The key is either passed private key for transparent sources or the disposable signing // key for shielded sources - let key = match key { - Ok(k) => k, - Err(_) => signing_keys[0].clone(), - }; + let key = signing_keys[0].clone(); // Sign the fee header tx.sign_wrapper(key); @@ -232,6 +251,7 @@ impl Sdk { to_js_result(borsh::to_vec(&tx)?) } + // Broadcast Tx pub async fn process_tx(&mut self, tx_bytes: &[u8], tx_msg: &[u8]) -> Result { let args = tx::tx_args_from_slice(tx_msg)?; @@ -330,30 +350,29 @@ impl Sdk { let mut args = tx::transfer_tx_args(transfer_msg, tx_msg)?; // TODO: this might not be needed. I will test it out in future - match args.source { - TransferSource::Address(_) => {} - TransferSource::ExtendedSpendingKey(xsk) => { - self.namada - .shielded_mut() - .await - .fetch( - self.namada.client(), - &DefaultLogger::new(&WebIo), - None, - None, - 1, - &[xsk.into()], - &[], - ) - .await?; - - // It's temporary solution to add xsk to wallet as xvk is queried when unshielding - // This will change in namada in the future - self.add_spending_key(xsk.to_string(), "temp".to_string()) - .await; - } - } - + // match args.source { + // TransferSource::Address(_) => {} + // TransferSource::ExtendedSpendingKey(xsk) => { + // self.namada + // .shielded_mut() + // .await + // .fetch( + // self.namada.client(), + // &DefaultLogger::new(&WebIo), + // None, + // None, + // 1, + // &[xsk.into()], + // &[], + // ) + // .await?; + // + // // It's temporary solution to add xsk to wallet as xvk is queried when unshielding + // // This will change in namada in the future + // self.add_spending_key(xsk.to_string(), "temp".to_string()) + // .await; + // } + // } let (tx, signing_data, _) = build_transfer(&self.namada, &mut args).await?; Ok(BuiltTx { tx, signing_data }) @@ -391,7 +410,6 @@ impl Sdk { ) -> Result { let args = tx::vote_proposal_tx_args(vote_proposal_msg, tx_msg)?; let epoch = query_epoch(self.namada.client()).await?; - let (tx, signing_data) = build_vote_proposal(&self.namada, &args, epoch) .await .map_err(JsError::from)?; @@ -454,13 +472,19 @@ impl Sdk { ) -> Result { let args = tx::tx_args_from_slice(tx_msg)?; let public_key = args.signing_keys[0].clone(); + let (tx, signing_data) = build_reveal_pk(&self.namada, &args.clone(), &public_key).await?; Ok(BuiltTx { tx, signing_data }) } // Helper function to reveal public key - pub async fn reveal_pk(&mut self, signing_key: String, tx_msg: &[u8]) -> Result<(), JsError> { + pub async fn reveal_pk( + &mut self, + signing_key: String, + tx_msg: &[u8], + chain_id: Option, + ) -> Result<(), JsError> { let args = tx::tx_args_from_slice(tx_msg)?; let pk = &args .signing_keys @@ -474,7 +498,8 @@ impl Sdk { let built_tx = self.build_reveal_pk(tx_msg, String::from("")).await?; // Conversion from JsValue so we can use self.sign_tx let tx_bytes = - Uint8Array::new(&self.sign_tx(built_tx, tx_msg, Some(signing_key)).await?).to_vec(); + Uint8Array::new(&self.sign_tx(built_tx, Some(signing_key), chain_id).await?) + .to_vec(); self.process_tx(&tx_bytes, tx_msg).await?; } diff --git a/packages/shared/lib/src/sdk/tx.rs b/packages/shared/lib/src/sdk/tx.rs index 217341cfd..0627911a2 100644 --- a/packages/shared/lib/src/sdk/tx.rs +++ b/packages/shared/lib/src/sdk/tx.rs @@ -1,7 +1,8 @@ use std::{path::PathBuf, str::FromStr}; -use namada::core::borsh::{BorshDeserialize, BorshSerialize}; +use namada::core::borsh::{self, BorshDeserialize, BorshSerialize}; use namada::core::ibc::core::host::types::identifiers::{ChannelId, PortId}; +use namada::sdk::signing::SigningTxData; use namada::tendermint_rpc; use namada::tx::data::GasLimit; use namada::{ @@ -17,7 +18,68 @@ use wasm_bindgen::JsError; #[derive(BorshSerialize, BorshDeserialize)] #[borsh(crate = "namada::core::borsh")] -pub struct TxMsg { +pub struct SigningData { + owner: Option, + public_keys: Vec, + threshold: u8, + account_public_keys_map: Option>, + fee_payer: String, +} + +impl SigningData { + // Create serializable struct from Namada type + pub fn from_signing_tx_data(signing_tx_data: SigningTxData) -> Result { + let owner: Option = match signing_tx_data.owner { + Some(addr) => Some(addr.to_string()), + None => None, + }; + let public_keys = borsh::to_vec(&signing_tx_data.public_keys)?; + let fee_payer = signing_tx_data.fee_payer.to_string(); + let account_public_keys_map = match signing_tx_data.account_public_keys_map { + Some(pk_map) => Some(borsh::to_vec(&pk_map)?), + None => None, + }; + + Ok(SigningData { + owner, + public_keys, + threshold: signing_tx_data.threshold, + account_public_keys_map, + fee_payer, + }) + } + + // Create Namada type from this struct + pub fn to_signing_tx_data(&self) -> Result { + let owner: Option
= match &self.owner { + Some(addr) => Some(Address::from_str(&addr)?), + None => None, + }; + let public_keys = borsh::from_slice(&self.public_keys)?; + let fee_payer = PublicKey::from_str(&self.fee_payer)?; + let threshold = self.threshold; + let account_public_keys_map = match &self.account_public_keys_map { + Some(pk_map) => Some(borsh::from_slice(&pk_map)?), + None => None, + }; + + Ok(SigningTxData { + owner, + public_keys, + fee_payer, + threshold, + account_public_keys_map, + }) + } + + pub fn to_bytes(&self) -> Result, JsError> { + Ok(borsh::to_vec(&self)?) + } +} + +#[derive(BorshSerialize, BorshDeserialize)] +#[borsh(crate = "namada::core::borsh")] +pub struct WrapperTxMsg { token: String, fee_amount: String, gas_limit: String, @@ -467,8 +529,8 @@ pub fn tx_args_from_slice(tx_msg_bytes: &[u8]) -> Result { /// /// Returns JsError if token address is invalid. fn tx_msg_into_args(tx_msg: &[u8]) -> Result { - let tx_msg = TxMsg::try_from_slice(tx_msg)?; - let TxMsg { + let tx_msg = WrapperTxMsg::try_from_slice(tx_msg)?; + let WrapperTxMsg { token, fee_amount, gas_limit, diff --git a/packages/types/src/namada.ts b/packages/types/src/namada.ts index d45becf68..54d32a68c 100644 --- a/packages/types/src/namada.ts +++ b/packages/types/src/namada.ts @@ -1,6 +1,6 @@ import { AccountType, DerivedAccount } from "./account"; import { Chain } from "./chain"; -import { SignatureResponse, Signer } from "./signer"; +import { SignArbitraryResponse, Signer } from "./signer"; export type TxMsgProps = { //TODO: figure out if we can make it better @@ -18,6 +18,15 @@ export type SignArbitraryProps = { data: string; }; +export type SignProps = { + accountType: AccountType; + signer: string; + tx: { + txData: Uint8Array; + signingData: Uint8Array; + }[]; +}; + export type VerifyArbitraryProps = { publicKey: string; hash: string; @@ -31,16 +40,15 @@ export type BalancesProps = { export interface Namada { accounts(chainId?: string): Promise; - balances( - props: BalancesProps - ): Promise<{ token: string; amount: string }[] | undefined>; - shieldedSync(): Promise; connect(chainId?: string): Promise; isConnected(): Promise; defaultAccount(chainId?: string): Promise; - sign(props: SignArbitraryProps): Promise; + sign(props: SignProps): Promise; + signLedger(props: SignProps): Promise; + signArbitrary( + props: SignArbitraryProps + ): Promise; verify(props: VerifyArbitraryProps): Promise; - submitTx: (props: TxMsgProps) => Promise; getChain: () => Promise; version: () => string; } diff --git a/packages/types/src/signer.ts b/packages/types/src/signer.ts index 47a6d8938..b9353142d 100644 --- a/packages/types/src/signer.ts +++ b/packages/types/src/signer.ts @@ -1,16 +1,6 @@ import { Account, AccountType } from "./account"; -import { - BondProps, - EthBridgeTransferProps, - IbcTransferProps, - TransferProps, - TxProps, - UnbondProps, - VoteProposalProps, - WithdrawProps, -} from "./tx"; -export type SignatureResponse = { +export type SignArbitraryResponse = { hash: string; signature: string; }; @@ -19,43 +9,17 @@ export interface Signer { accounts: (chainId?: string) => Promise; defaultAccount: (chainId?: string) => Promise; sign: ( + signer: string, + tx: unknown | unknown[], + accountType?: AccountType + ) => Promise; + signLedger: ( + signer: string, + tx: unknown | unknown[] + ) => Promise; + signArbitrary: ( signer: string, data: string - ) => Promise; + ) => Promise; verify: (publicKey: string, hash: string, signature: string) => Promise; - submitBond( - args: BondProps | BondProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitUnbond( - args: UnbondProps | UnbondProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitWithdraw( - args: WithdrawProps | WithdrawProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitTransfer( - args: TransferProps | TransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitIbcTransfer( - args: IbcTransferProps | IbcTransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitVoteProposal( - args: VoteProposalProps | VoteProposalProps[], - txArgs: TxProps, - type: AccountType - ): Promise; - submitEthBridgeTransfer( - args: EthBridgeTransferProps | EthBridgeTransferProps[], - txArgs: TxProps, - type: AccountType - ): Promise; } diff --git a/packages/types/src/tx/schema/index.ts b/packages/types/src/tx/schema/index.ts index 375a6c9bd..93c6b8ac5 100644 --- a/packages/types/src/tx/schema/index.ts +++ b/packages/types/src/tx/schema/index.ts @@ -4,11 +4,11 @@ export * from "./ibcTransfer"; export * from "./redelegate"; export * from "./signature"; export * from "./transfer"; -export * from "./tx"; export * from "./unbond"; export * from "./utils"; export * from "./voteProposal"; export * from "./withdraw"; +export * from "./wrapperTx"; import { BondMsgValue } from "./bond"; import { EthBridgeTransferMsgValue } from "./ethBridgeTransfer"; @@ -16,10 +16,10 @@ import { IbcTransferMsgValue } from "./ibcTransfer"; import { RedelegateMsgValue } from "./redelegate"; import { SignatureMsgValue } from "./signature"; import { TransferMsgValue } from "./transfer"; -import { TxMsgValue } from "./tx"; import { UnbondMsgValue } from "./unbond"; import { VoteProposalMsgValue } from "./voteProposal"; import { WithdrawMsgValue } from "./withdraw"; +import { WrapperTxMsgValue } from "./wrapperTx"; export type Schema = | EthBridgeTransferMsgValue @@ -30,5 +30,5 @@ export type Schema = | VoteProposalMsgValue | WithdrawMsgValue | TransferMsgValue - | TxMsgValue + | WrapperTxMsgValue | RedelegateMsgValue; diff --git a/packages/types/src/tx/schema/tx.ts b/packages/types/src/tx/schema/wrapperTx.ts similarity index 85% rename from packages/types/src/tx/schema/tx.ts rename to packages/types/src/tx/schema/wrapperTx.ts index ea9d6c7f6..cfc097d82 100644 --- a/packages/types/src/tx/schema/tx.ts +++ b/packages/types/src/tx/schema/wrapperTx.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { field, option } from "@dao-xyz/borsh"; import BigNumber from "bignumber.js"; -import { TxProps } from "../types"; +import { WrapperTxProps } from "../types"; import { BigNumberSerializer } from "./utils"; -export class TxMsgValue { +export class WrapperTxMsgValue { @field({ type: "string" }) token!: string; @@ -29,7 +29,7 @@ export class TxMsgValue { @field({ type: option("string") }) memo?: string; - constructor(data: TxProps) { + constructor(data: WrapperTxProps) { Object.assign(this, data); } } diff --git a/packages/types/src/tx/types.ts b/packages/types/src/tx/types.ts index a06832025..f855f8bdc 100644 --- a/packages/types/src/tx/types.ts +++ b/packages/types/src/tx/types.ts @@ -5,13 +5,13 @@ import { RedelegateMsgValue, SignatureMsgValue, TransferMsgValue, - TxMsgValue, UnbondMsgValue, VoteProposalMsgValue, WithdrawMsgValue, + WrapperTxMsgValue, } from "./schema"; -export type TxProps = TxMsgValue; +export type WrapperTxProps = WrapperTxMsgValue; export type BondProps = BondMsgValue; export type UnbondProps = UnbondMsgValue; export type WithdrawProps = WithdrawMsgValue;