From eb168884005843eae64310b75bf67ec81bcba5a3 Mon Sep 17 00:00:00 2001 From: Mateusz Jasiuk Date: Wed, 14 Jun 2023 15:18:29 +0200 Subject: [PATCH] feat: async masp params loading (#305) --- apps/extension/src/App/App.components.ts | 38 +++++++++- apps/extension/src/App/App.tsx | 71 +++++++++++++------ .../src/App/Loading/Loading.components.ts | 23 +----- apps/extension/src/App/Loading/Loading.tsx | 4 +- .../ConfirmTransfer.components.ts | 43 +++++++++++ .../ApproveTransfer/ConfirmTransfer.tsx | 29 +++++++- .../src/background/keyring/handler.ts | 14 ++-- apps/extension/src/background/keyring/init.ts | 4 +- .../src/background/keyring/service.ts | 6 +- apps/extension/src/provider/Anoma.ts | 6 +- apps/extension/src/provider/messages.ts | 8 +-- .../src/App/Token/TokenSend/TokenSendForm.tsx | 2 +- packages/shared/lib/src/sdk/mod.js | 39 ++++++---- packages/shared/lib/src/sdk/mod.rs | 36 ++++++---- 14 files changed, 229 insertions(+), 94 deletions(-) create mode 100644 apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.components.ts diff --git a/apps/extension/src/App/App.components.ts b/apps/extension/src/App/App.components.ts index 0265f1c5418..faaf25432c0 100644 --- a/apps/extension/src/App/App.components.ts +++ b/apps/extension/src/App/App.components.ts @@ -1,4 +1,4 @@ -import styled, { createGlobalStyle } from "styled-components"; +import styled, { createGlobalStyle, css } from "styled-components"; export const GlobalStyles = createGlobalStyle` html, body { @@ -6,6 +6,29 @@ export const GlobalStyles = createGlobalStyle` } `; +export const Spinner = css` + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-top-color: ${(props) => props.theme.colors.primary.main}; + border-radius: 50%; + animation: button-loading-spinner 1s ease infinite; + + @keyframes button-loading-spinner { + from { + transform: rotate(0turn); + } + + to { + transform: rotate(1turn); + } + } + } +`; + export const AppContainer = styled.div` display: flex; justify-content: space-between; @@ -42,6 +65,19 @@ export const Heading = styled.h1` padding-left: 12px; `; +export const HeadingLoader = styled.div` + position: relative; + width: 20px; + height: 20px; + + &.is-loading::after { + width: 16px; + height: 16px; + border: 2px solid transparent; + ${Spinner} + } +`; + export const HeadingButtons = styled.div` display: flex; justify-content: flex-end; diff --git a/apps/extension/src/App/App.tsx b/apps/extension/src/App/App.tsx index 366c33c57b2..5bd85db9f73 100644 --- a/apps/extension/src/App/App.tsx +++ b/apps/extension/src/App/App.tsx @@ -9,7 +9,7 @@ import { useUntil } from "@anoma/hooks"; import { Ports } from "router"; import { - LoadMaspParamsMsg, + FetchAndStoreMaspParamsMsg, HasMaspParamsMsg, QueryAccountsMsg, } from "provider/messages"; @@ -24,6 +24,7 @@ import { Heading, HeadingButtons, SettingsButton, + HeadingLoader, } from "./App.components"; import { TopLevelRoute } from "./types"; import { LockWrapper } from "./LockWrapper"; @@ -47,10 +48,13 @@ export const App: React.FC = () => { const navigate = useNavigate(); const [isLocked, setIsLocked] = useState(true); const [status, setStatus] = useState(); + const [maspStatus, setMaspStatus] = useState<{ + status: Status; + info: string; + }>({ status: Status.Completed, info: "" }); const [accounts, setAccounts] = useState([]); const [parentAccount, setParentAccount] = useState(); const [error, setError] = useState(""); - const [statusInfo, setStatusInfo] = useState(""); const requester = useRequester(); const fetchAccounts = async (): Promise => { @@ -94,26 +98,11 @@ export const App: React.FC = () => { predFn: async () => { setStatus(Status.Pending); try { - setStatusInfo("Fetching accounts..."); const accounts = await requester.sendMessage( Ports.Background, new QueryAccountsMsg() ); - setStatusInfo("Checking MASP parameters..."); - const hasMaspParams = await requester.sendMessage( - Ports.Background, - new HasMaspParamsMsg() - ); - - if (!hasMaspParams) { - setStatusInfo("Fetching MASP parameters..."); - await requester.sendMessage( - Ports.Background, - new LoadMaspParamsMsg() - ); - } - setAccounts(accounts); return true; } catch (e) { @@ -122,7 +111,6 @@ export const App: React.FC = () => { } }, onSuccess: () => { - setStatusInfo(""); setStatus(Status.Completed); }, onFail: () => { @@ -134,6 +122,43 @@ export const App: React.FC = () => { [] ); + // Fetch Masp params if they don't exist + useEffect(() => { + if (status === Status.Completed) { + (async () => { + const hasMaspParams = await requester.sendMessage( + Ports.Background, + new HasMaspParamsMsg() + ); + + if (!hasMaspParams) { + setMaspStatus({ + status: Status.Pending, + info: "Fetching MASP parameters...", + }); + try { + await requester.sendMessage( + Ports.Background, + new FetchAndStoreMaspParamsMsg() + ); + + setMaspStatus({ + status: Status.Completed, + info: "", + }); + } catch (e) { + setMaspStatus({ + status: Status.Failed, + info: `Fetching MASP parameters failed: ${e}`, + }); + //TODO: Notify user in a better way + console.error(e); + } + } + })(); + } + }, [status]); + useEffect(() => { if (redirect) { // Provide a redirect in the case of transaction/connection approvals @@ -164,6 +189,12 @@ export const App: React.FC = () => { Anoma Browser Extension + {parentAccount && ( { - } + element={} /> } /> props.theme.colors.primary.main}; - border-radius: 50%; - animation: button-loading-spinner 1s ease infinite; - - @keyframes button-loading-spinner { - from { - transform: rotate(0turn); - } - - to { - transform: rotate(1turn); - } - } + margin: auto; + ${Spinner} } `; diff --git a/apps/extension/src/App/Loading/Loading.tsx b/apps/extension/src/App/Loading/Loading.tsx index c35d96f1745..59e67f03ef2 100644 --- a/apps/extension/src/App/Loading/Loading.tsx +++ b/apps/extension/src/App/Loading/Loading.tsx @@ -8,12 +8,12 @@ type Props = { error?: string; }; -const Loading: React.FC = ({ error, status, info }) => { +const Loading: React.FC = ({ error, status }) => { return ( {(status === Status.Failed && ( Error: {error} - )) ||

{info ?? "Loading..."}

} + )) ||

Fetching accounts...

}
); }; diff --git a/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.components.ts b/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.components.ts new file mode 100644 index 00000000000..9e5a44b80f5 --- /dev/null +++ b/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.components.ts @@ -0,0 +1,43 @@ +import styled, { css } from "styled-components"; + +export const Spinner = css` + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-top-color: ${(props) => props.theme.colors.primary.main}; + border-radius: 50%; + animation: button-loading-spinner 1s ease infinite; + + @keyframes button-loading-spinner { + from { + transform: rotate(0turn); + } + + to { + transform: rotate(1turn); + } + } + } +`; + +export const InfoHeader = styled.div` + display: flex; + align-items: center; + gap: 10px; +`; + +export const InfoLoader = styled.div` + position: relative; + width: 20px; + height: 20px; + + &::after { + width: 16px; + height: 16px; + border: 2px solid transparent; + ${Spinner} + } +`; diff --git a/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.tsx b/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.tsx index c4b4b421c28..7003bd54e95 100644 --- a/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.tsx +++ b/apps/extension/src/Approvals/ApproveTransfer/ConfirmTransfer.tsx @@ -14,6 +14,8 @@ import { useRequester } from "hooks/useRequester"; import { SubmitApprovedTransferMsg } from "background/approvals"; import { Address } from "App/Accounts/AccountListing.components"; import { closeCurrentTab } from "utils"; +import { FetchAndStoreMaspParamsMsg, HasMaspParamsMsg } from "provider"; +import { InfoHeader, InfoLoader } from "./ConfirmTransfer.components"; type Props = { msgId: string; @@ -26,20 +28,40 @@ export const ConfirmTransfer: React.FC = ({ msgId, address }) => { const [password, setPassword] = useState(""); const [error, setError] = useState(); const [status, setStatus] = useState(); + const [statusInfo, setStatusInfo] = useState(""); const handleApprove = async (): Promise => { setStatus(Status.Pending); + 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); + } + } try { // TODO: use executeUntil here! + setStatusInfo("Decrypting keys and submitting transfer..."); await requester.sendMessage( Ports.Background, new SubmitApprovedTransferMsg(msgId, address, password) ); - setStatus(Status.Completed); } catch (e) { setError("Unable to authenticate Tx!"); setStatus(Status.Failed); } + setStatusInfo(""); + setStatus(Status.Completed); return; }; @@ -54,7 +76,10 @@ export const ConfirmTransfer: React.FC = ({ msgId, address }) => { return ( {status === Status.Pending && ( -

Decrypting keys and submitting transfer...

+ + +

{statusInfo}

+
)} {status === Status.Failed && (

diff --git a/apps/extension/src/background/keyring/handler.ts b/apps/extension/src/background/keyring/handler.ts index 8169dd66740..486fb516c5c 100644 --- a/apps/extension/src/background/keyring/handler.ts +++ b/apps/extension/src/background/keyring/handler.ts @@ -24,7 +24,7 @@ import { SubmitBondMsg, SubmitUnbondMsg, SubmitIbcTransferMsg, - LoadMaspParamsMsg, + FetchAndStoreMaspParamsMsg, HasMaspParamsMsg, } from "provider/messages"; @@ -100,10 +100,10 @@ export const getHandler: (service: KeyRingService) => Handler = (service) => { ); case DeleteAccountMsg: return handleDeleteAccountMsg(service)(env, msg as DeleteAccountMsg); - case LoadMaspParamsMsg: - return handleLoadMaspParamsMsg(service)( + case FetchAndStoreMaspParamsMsg: + return handleFetchAndStoreMaspParamsMsg(service)( env, - msg as LoadMaspParamsMsg + msg as FetchAndStoreMaspParamsMsg ); case HasMaspParamsMsg: return handleHasMaspParamsMsg(service)(env, msg as HasMaspParamsMsg); @@ -296,11 +296,11 @@ const handleDeleteAccountMsg: ( }; }; -const handleLoadMaspParamsMsg: ( +const handleFetchAndStoreMaspParamsMsg: ( service: KeyRingService -) => InternalHandler = (service) => { +) => InternalHandler = (service) => { return async (_, _msg) => { - return await service.loadMaspParams(); + return await service.fetchAndStoreMaspParams(); }; }; diff --git a/apps/extension/src/background/keyring/init.ts b/apps/extension/src/background/keyring/init.ts index f0e3ec23d0c..878636bc61b 100644 --- a/apps/extension/src/background/keyring/init.ts +++ b/apps/extension/src/background/keyring/init.ts @@ -24,7 +24,7 @@ import { SubmitBondMsg, SubmitUnbondMsg, SubmitIbcTransferMsg, - LoadMaspParamsMsg, + FetchAndStoreMaspParamsMsg, HasMaspParamsMsg, } from "provider/messages"; import { ROUTE } from "./constants"; @@ -54,7 +54,7 @@ export function init(router: Router, service: KeyRingService): void { router.registerMessage(TransferCompletedEvent); router.registerMessage(UnlockKeyRingMsg); router.registerMessage(DeleteAccountMsg); - router.registerMessage(LoadMaspParamsMsg); + router.registerMessage(FetchAndStoreMaspParamsMsg); router.registerMessage(HasMaspParamsMsg); router.addHandler(ROUTE, getHandler(service)); diff --git a/apps/extension/src/background/keyring/service.ts b/apps/extension/src/background/keyring/service.ts index de391436b62..1ba39a290c3 100644 --- a/apps/extension/src/background/keyring/service.ts +++ b/apps/extension/src/background/keyring/service.ts @@ -344,12 +344,12 @@ export class KeyRingService { return; } - async loadMaspParams(): Promise { - await this.sdk.load_masp_params(); + async fetchAndStoreMaspParams(): Promise { + await Sdk.fetch_and_store_masp_params(); } async hasMaspParams(): Promise { - return this.sdk.has_masp_params(); + return Sdk.has_masp_params(); } private async broadcastUpdateBalance(): Promise { diff --git a/apps/extension/src/provider/Anoma.ts b/apps/extension/src/provider/Anoma.ts index 38de8ccddfe..801ee7283bd 100644 --- a/apps/extension/src/provider/Anoma.ts +++ b/apps/extension/src/provider/Anoma.ts @@ -9,7 +9,7 @@ import { SuggestChainMsg, EncodeInitAccountMsg, QueryAccountsMsg, - LoadMaspParamsMsg, + FetchAndStoreMaspParamsMsg, HasMaspParamsMsg, QueryBalancesMsg, SubmitBondMsg, @@ -53,10 +53,10 @@ export class Anoma implements IAnoma { ); } - public async fetchMaspParams(): Promise { + public async fetchAndStoreMaspParams(): Promise { return await this.requester?.sendMessage( Ports.Background, - new LoadMaspParamsMsg() + new FetchAndStoreMaspParamsMsg() ); } diff --git a/apps/extension/src/provider/messages.ts b/apps/extension/src/provider/messages.ts index f502ff26b93..efccfb145b5 100644 --- a/apps/extension/src/provider/messages.ts +++ b/apps/extension/src/provider/messages.ts @@ -26,7 +26,7 @@ enum MessageType { SuggestChain = "suggest-chain", SubmitBond = "submit-bond", SubmitUnbond = "submit-unbond", - LoadMaspParams = "load-masp-params", + FetchAndStoreMaspParams = "fetch-and-store-masp-params", HasMaspParams = "has-masp-params", } @@ -333,9 +333,9 @@ export class ApproveTransferMsg extends Message { } } -export class LoadMaspParamsMsg extends Message { +export class FetchAndStoreMaspParamsMsg extends Message { public static type(): MessageType { - return MessageType.LoadMaspParams; + return MessageType.FetchAndStoreMaspParams; } validate(): void { return; @@ -346,7 +346,7 @@ export class LoadMaspParamsMsg extends Message { } type(): string { - return LoadMaspParamsMsg.type(); + return FetchAndStoreMaspParamsMsg.type(); } } diff --git a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx index 316a0f762bd..4ee46096f17 100644 --- a/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx +++ b/apps/namada-interface/src/App/Token/TokenSend/TokenSendForm.tsx @@ -420,7 +420,7 @@ const TokenSendForm = ({