From cf99636e738a582efd216cdf31eed1b4c5b17208 Mon Sep 17 00:00:00 2001 From: Jeff Thompson Date: Thu, 10 Oct 2024 10:17:20 +0200 Subject: [PATCH] chore: Remove getActiveAccount usage (#183) Similar to PR https://github.com/gnolang/dsocial/pull/130, we update gnoboard to use the new Gno Native Kit API which removes `selectAccount` and requires passing the account address to `setPassword`, etc. This PR has five commits: 1. The app needs to keep track of the active account, so add `GnoboardProvider`. 2. Instead of calling Gno Native Kit `selectAccount`, call `GnoboardProvider` `setAccount` to remember the active account. 3. `setPassword` needs the account address, so in `ReenterPassword` add param `accountAddress`. 4. In wallet/home: Pass in the account instead of calling `getActiveAccount`. Use the account address to call `queryAccount`. 5. As in a [similar dsocial PR](https://github.com/gnolang/dsocial/pull/134), fix the Makefile to call ts_check after node_modules. With this PR, all known apps have been updated to remove `selectAcount` and to pass the account address to the methods of Gno Native Kit, which can be updated to remove deprecated functions and to make the address not optional. --------- Signed-off-by: Jeff Thompson --- examples/js/expo/gnoboard/App.tsx | 5 ++- examples/js/expo/gnoboard/Makefile | 6 ++-- .../src/provider/gnoboard-provider.tsx | 35 +++++++++++++++++++ .../screens/certify/create-password/index.tsx | 8 +++-- .../src/screens/certify/enter-seed/index.tsx | 7 ++-- .../gnoboard/src/screens/devmode/index.tsx | 15 +++++--- .../switch-accounts/ReenterPassword.tsx | 5 +-- .../src/screens/switch-accounts/index.tsx | 9 +++-- .../src/screens/wallet/home/index.tsx | 12 +++---- 9 files changed, 78 insertions(+), 24 deletions(-) create mode 100644 examples/js/expo/gnoboard/src/provider/gnoboard-provider.tsx diff --git a/examples/js/expo/gnoboard/App.tsx b/examples/js/expo/gnoboard/App.tsx index da1fda81..5693a0cf 100644 --- a/examples/js/expo/gnoboard/App.tsx +++ b/examples/js/expo/gnoboard/App.tsx @@ -2,6 +2,7 @@ import 'react-native-polyfill-globals/auto'; import { GnoNativeProvider } from '@gnolang/gnonative'; +import { GnoboardProvider } from '@gno/provider/gnoboard-provider'; import CustomRouter from '@gno/router/custom-router'; // Polyfill async.Iterator. For some reason, the Babel presets and plugins are not doing the trick. @@ -16,7 +17,9 @@ function App() { return ( - + + + ); } diff --git a/examples/js/expo/gnoboard/Makefile b/examples/js/expo/gnoboard/Makefile index 12c96070..390b8173 100644 --- a/examples/js/expo/gnoboard/Makefile +++ b/examples/js/expo/gnoboard/Makefile @@ -29,14 +29,14 @@ ts_check: # - Node: Handle node_modules -node_modules: ts_check package.json package-lock.json +node_modules: package.json package-lock.json $(call check-program, npm) (npm install && touch $@) || true .PHONY: node_modules ######### ANDROID ######### -android: node_modules $(ANDROID_FRAMEWORK_SRC) +android: node_modules ts_check $(ANDROID_FRAMEWORK_SRC) $(call check-program, npx) npx expo run:android .PHONY: build.android @@ -46,7 +46,7 @@ $(ANDROID_FRAMEWORK_SRC): $(go_deps) ######### IOS ######### -ios: node_modules $(IOS_FRAMEWORK_SRC) +ios: node_modules ts_check $(IOS_FRAMEWORK_SRC) $(call check-program, npx) npx expo run:ios .PHONY: build.ios diff --git a/examples/js/expo/gnoboard/src/provider/gnoboard-provider.tsx b/examples/js/expo/gnoboard/src/provider/gnoboard-provider.tsx new file mode 100644 index 00000000..9db95a33 --- /dev/null +++ b/examples/js/expo/gnoboard/src/provider/gnoboard-provider.tsx @@ -0,0 +1,35 @@ +import { createContext, useContext, useState, useCallback } from 'react'; + +import { KeyInfo } from '@gnolang/gnonative'; + +interface GnoboardProviderProps { + children: React.ReactNode; +} +interface GnoboardContextType { + account: KeyInfo | undefined; + setAccount: (keyInfo : KeyInfo | undefined) => void; +} + +const GnoboardContext = createContext(null); + +const GnoboardProvider: React.FC = ({ children }) => { + const [account, setAccount] = useState(undefined) + + const value = { + account, + setAccount + }; + + return {children}; +}; + +function useGnoboardContext() { + const context = useContext(GnoboardContext) as GnoboardContextType; + + if (context === undefined) { + throw new Error('useGnoboardContext must be used within a GnoboardProvider'); + } + return context; +} + +export { GnoboardProvider, useGnoboardContext }; diff --git a/examples/js/expo/gnoboard/src/screens/certify/create-password/index.tsx b/examples/js/expo/gnoboard/src/screens/certify/create-password/index.tsx index 654f447b..4db64214 100644 --- a/examples/js/expo/gnoboard/src/screens/certify/create-password/index.tsx +++ b/examples/js/expo/gnoboard/src/screens/certify/create-password/index.tsx @@ -12,6 +12,7 @@ import SeedBox from '@gno/components/seedbox'; import Alert from '@gno/components/alert'; import { Spacer } from '@gno/components/row'; import { ModalConfirm } from '@gno/components/modal'; +import { useGnoboardContext } from '@gno/provider/gnoboard-provider'; const text = { title: 'Create\na Password', @@ -27,7 +28,7 @@ const CreatePassword: React.FC = ({ route }) => { const [confirmPassword, setConfirmPassword] = useState(''); const [error, setError] = useState(undefined); const [showModal, setShowModal] = useState(false); - + const { setAccount } = useGnoboardContext(); const { gnonative } = useGnoNativeContext(); const navigation = useNavigation(); @@ -51,8 +52,9 @@ const CreatePassword: React.FC = ({ route }) => { const response = await gnonative.createAccount(name, phrase, password); console.log('createAccount response: ' + response); - await gnonative.selectAccount(name); - await gnonative.setPassword(password); + await gnonative.activateAccount(name); + setAccount(response); + await gnonative.setPassword(password, response!.address); navigation.navigate(RoutePath.Home); } catch (error) { setError(JSON.stringify(error)); diff --git a/examples/js/expo/gnoboard/src/screens/certify/enter-seed/index.tsx b/examples/js/expo/gnoboard/src/screens/certify/enter-seed/index.tsx index a49ec283..3b78e3a8 100644 --- a/examples/js/expo/gnoboard/src/screens/certify/enter-seed/index.tsx +++ b/examples/js/expo/gnoboard/src/screens/certify/enter-seed/index.tsx @@ -11,6 +11,7 @@ import TextInput from '@gno/components/textinput'; import Alert from '@gno/components/alert'; import { Spacer } from '@gno/components/row'; import { ModalConfirm } from '@gno/components/modal'; +import { useGnoboardContext } from '@gno/provider/gnoboard-provider'; const walletContent = { title: 'Import with Seed Phrase', @@ -27,6 +28,7 @@ const EnterSeedPhrase = () => { const [showModal, setShowModal] = useState(false); const { gnonative } = useGnoNativeContext(); const navigation = useNavigation(); + const { setAccount } = useGnoboardContext(); const recoverAccount = async (override: boolean = false) => { if (!recoveryPhrase || !name || !password || !confirmPassword) return; @@ -47,8 +49,9 @@ const EnterSeedPhrase = () => { } const response = await gnonative.createAccount(name, recoveryPhrase, password); - await gnonative.selectAccount(name); - await gnonative.setPassword(password); + await gnonative.activateAccount(name); + await gnonative.setPassword(password, response!.address); + setAccount(response); console.log('createAccount response: ' + response); navigation.navigate(RoutePath.Home); } catch (error) { diff --git a/examples/js/expo/gnoboard/src/screens/devmode/index.tsx b/examples/js/expo/gnoboard/src/screens/devmode/index.tsx index 01e69401..2e3ab72e 100644 --- a/examples/js/expo/gnoboard/src/screens/devmode/index.tsx +++ b/examples/js/expo/gnoboard/src/screens/devmode/index.tsx @@ -14,24 +14,31 @@ import { ConnectError } from '@connectrpc/connect'; import { useNavigation } from '@react-navigation/native'; import { RouterWelcomeStackProp } from '@gno/router/custom-router'; import { RoutePath } from '@gno/router/path'; +import { useGnoboardContext } from '@gno/provider/gnoboard-provider'; function DevMode() { const [postContent, setPostContent] = useState(''); const [appConsole, setAppConsole] = useState(''); const [loading, setLoading] = useState(undefined); const [reenterPassword, setReenterPassword] = useState(undefined); + const [reenterPasswordAddress, setReenterPasswordAddress] = useState(undefined); const navigate = useNavigation(); const { gnonative } = useGnoNativeContext(); + const { account } = useGnoboardContext(); const onPostPress = async () => { + if (!account) + // shouldn't happen, but just in case + throw new Error("No active account"); + setLoading('Replying to a post...'); setAppConsole('replying to a post...'); const gasFee = '1000000ugnot'; const gasWanted = BigInt(2000000); const args: Array = ['1', '1', '1', postContent]; try { - for await (const response of await gnonative.call('gno.land/r/demo/boards', 'CreateReply', args, gasFee, gasWanted)) { + for await (const response of await gnonative.call('gno.land/r/demo/boards', 'CreateReply', args, gasFee, gasWanted, account.address)) { console.log('response: ', response); setAppConsole(Buffer.from(response.result).toString()); } @@ -39,8 +46,8 @@ function DevMode() { if (error instanceof ConnectError) { const err = new GRPCError(error); if (err.errCode() === ErrCode.ErrDecryptionFailed) { - const account = await gnonative.getActiveAccount(); - setReenterPassword(account.key?.name); + setReenterPassword(account.name); + setReenterPasswordAddress(account.address); return; } } @@ -86,7 +93,7 @@ function DevMode() { {reenterPassword ? ( - + ) : null} ); diff --git a/examples/js/expo/gnoboard/src/screens/switch-accounts/ReenterPassword.tsx b/examples/js/expo/gnoboard/src/screens/switch-accounts/ReenterPassword.tsx index c82fa132..8651911c 100644 --- a/examples/js/expo/gnoboard/src/screens/switch-accounts/ReenterPassword.tsx +++ b/examples/js/expo/gnoboard/src/screens/switch-accounts/ReenterPassword.tsx @@ -12,10 +12,11 @@ import { ConnectError } from '@connectrpc/connect'; export type Props = { visible: boolean; accountName: string; + accountAddress: Uint8Array; onClose: (sucess: boolean) => void; }; -const ReenterPassword = ({ visible, accountName, onClose }: Props) => { +const ReenterPassword = ({ visible, accountName, accountAddress, onClose }: Props) => { const { gnonative } = useGnoNativeContext(); const [password, setPassword] = useState(''); const [error, setError] = useState(undefined); @@ -25,7 +26,7 @@ const ReenterPassword = ({ visible, accountName, onClose }: Props) => { try { setError(undefined); - await gnonative.setPassword(password); + await gnonative.setPassword(password, accountAddress); onClose(true); } catch (error) { if (error instanceof ConnectError) { diff --git a/examples/js/expo/gnoboard/src/screens/switch-accounts/index.tsx b/examples/js/expo/gnoboard/src/screens/switch-accounts/index.tsx index 9b830461..a572ed2e 100644 --- a/examples/js/expo/gnoboard/src/screens/switch-accounts/index.tsx +++ b/examples/js/expo/gnoboard/src/screens/switch-accounts/index.tsx @@ -4,6 +4,7 @@ import { KeyInfo, useGnoNativeContext } from '@gnolang/gnonative'; import { RouterWelcomeStackProp } from '@gno/router/custom-router'; import { useNavigation } from '@react-navigation/native'; import { useEffect, useState } from 'react'; +import { useGnoboardContext } from '@gno/provider/gnoboard-provider'; import Loading from '../loading'; import SideMenuAccountList from '@gno/components/common/side-menu-account-list/side-menu-account-list'; import { RoutePath } from '@gno/router/path'; @@ -15,6 +16,8 @@ const SwitchAccounts = () => { const [loading, setLoading] = useState(undefined); const [accounts, setAccounts] = useState([]); const [reenterPassword, setReenterPassword] = useState(undefined); + const [reenterPasswordAddress, setReenterPasswordAddress] = useState(undefined); + const { setAccount } = useGnoboardContext(); useEffect(() => { const unsubscribe = navigation.addListener('focus', async () => { @@ -35,10 +38,12 @@ const SwitchAccounts = () => { const onChangeAccountHandler = async (value: KeyInfo) => { try { setLoading('Changing account...'); - const response = await gnonative.selectAccount(value.name); + const response = await gnonative.activateAccount(value.name); + setAccount(value); setLoading(undefined); if (!response.hasPassword) { setReenterPassword(value.name); + setReenterPasswordAddress(value.address); return; } navigation.navigate(RoutePath.Home); @@ -68,7 +73,7 @@ const SwitchAccounts = () => { {reenterPassword ? ( - + ) : null} ); diff --git a/examples/js/expo/gnoboard/src/screens/wallet/home/index.tsx b/examples/js/expo/gnoboard/src/screens/wallet/home/index.tsx index 68dfd056..acd6d06d 100644 --- a/examples/js/expo/gnoboard/src/screens/wallet/home/index.tsx +++ b/examples/js/expo/gnoboard/src/screens/wallet/home/index.tsx @@ -12,27 +12,25 @@ import { AccountBalance } from '@gno/components/account'; import { Spacer } from '@gno/components/row'; import { ConnectError } from '@connectrpc/connect'; import { ErrCode, GRPCError, useGnoNativeContext, KeyInfo, QueryAccountResponse } from '@gnolang/gnonative'; +import { useGnoboardContext } from '@gno/provider/gnoboard-provider'; export const Home: React.FC = () => { const navigation = useNavigation(); const { gnonative } = useGnoNativeContext(); + const { account } = useGnoboardContext(); const [loading, setLoading] = React.useState(undefined); - const [account, setAccount] = React.useState(undefined); const [balance, setBalance] = React.useState(undefined); const [unknownAddress, setUnknownAddress] = React.useState(false); useEffect(() => { const unsubscribe = navigation.addListener('focus', async () => { setUnknownAddress(false); - setAccount(undefined); setBalance(undefined); try { - const response = await gnonative.getActiveAccount(); - setAccount(response.key); - if (response.key) { - const balance = await gnonative.queryAccount(response.key.address); + if (account) { + const balance = await gnonative.queryAccount(account.address); setBalance(balance); } } catch (error) { @@ -47,7 +45,7 @@ export const Home: React.FC = () => { } }); return unsubscribe; - }, [navigation]); + }, [navigation, account]); if (loading) { return ;