Skip to content

Commit

Permalink
chore: Remove getActiveAccount usage (#183)
Browse files Browse the repository at this point in the history
Similar to PR gnoverse/dsocial#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](gnoverse/dsocial#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 <jeff@thefirst.org>
  • Loading branch information
jefft0 authored Oct 10, 2024
1 parent 642904f commit cf99636
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 24 deletions.
5 changes: 4 additions & 1 deletion examples/js/expo/gnoboard/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -16,7 +17,9 @@ function App() {

return (
<GnoNativeProvider config={defaultConfig}>
<CustomRouter />
<GnoboardProvider>
<CustomRouter/>
</GnoboardProvider>
</GnoNativeProvider>
);
}
Expand Down
6 changes: 3 additions & 3 deletions examples/js/expo/gnoboard/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
35 changes: 35 additions & 0 deletions examples/js/expo/gnoboard/src/provider/gnoboard-provider.tsx
Original file line number Diff line number Diff line change
@@ -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<GnoboardContextType | null>(null);

const GnoboardProvider: React.FC<GnoboardProviderProps> = ({ children }) => {
const [account, setAccount] = useState<KeyInfo | undefined>(undefined)

const value = {
account,
setAccount
};

return <GnoboardContext.Provider value={value}>{children}</GnoboardContext.Provider>;
};

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 };
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -27,7 +28,7 @@ const CreatePassword: React.FC<Props> = ({ route }) => {
const [confirmPassword, setConfirmPassword] = useState('');
const [error, setError] = useState<string | undefined>(undefined);
const [showModal, setShowModal] = useState(false);

const { setAccount } = useGnoboardContext();
const { gnonative } = useGnoNativeContext();
const navigation = useNavigation<RouterWelcomeStackProp>();

Expand All @@ -51,8 +52,9 @@ const CreatePassword: React.FC<Props> = ({ 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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -27,6 +28,7 @@ const EnterSeedPhrase = () => {
const [showModal, setShowModal] = useState(false);
const { gnonative } = useGnoNativeContext();
const navigation = useNavigation<RouterWelcomeStackProp>();
const { setAccount } = useGnoboardContext();

const recoverAccount = async (override: boolean = false) => {
if (!recoveryPhrase || !name || !password || !confirmPassword) return;
Expand All @@ -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) {
Expand Down
15 changes: 11 additions & 4 deletions examples/js/expo/gnoboard/src/screens/devmode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,40 @@ 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<string>('');
const [loading, setLoading] = useState<string | undefined>(undefined);
const [reenterPassword, setReenterPassword] = useState<string | undefined>(undefined);
const [reenterPasswordAddress, setReenterPasswordAddress] = useState<Uint8Array | undefined>(undefined);
const navigate = useNavigation<RouterWelcomeStackProp>();

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<string> = ['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());
}
} catch (error) {
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;
}
}
Expand Down Expand Up @@ -86,7 +93,7 @@ function DevMode() {
</Layout.Body>
</Layout.Container>
{reenterPassword ? (
<ReenterPassword visible={Boolean(reenterPassword)} accountName={reenterPassword} onClose={onCloseReenterPassword} />
<ReenterPassword visible={Boolean(reenterPassword)} accountName={reenterPassword} accountAddress={reenterPasswordAddress!} onClose={onCloseReenterPassword} />
) : null}
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | undefined>(undefined);
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -15,6 +16,8 @@ const SwitchAccounts = () => {
const [loading, setLoading] = useState<string | undefined>(undefined);
const [accounts, setAccounts] = useState<KeyInfo[]>([]);
const [reenterPassword, setReenterPassword] = useState<string | undefined>(undefined);
const [reenterPasswordAddress, setReenterPasswordAddress] = useState<Uint8Array | undefined>(undefined);
const { setAccount } = useGnoboardContext();

useEffect(() => {
const unsubscribe = navigation.addListener('focus', async () => {
Expand All @@ -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);
Expand Down Expand Up @@ -68,7 +73,7 @@ const SwitchAccounts = () => {
</Layout.Body>
</Layout.Container>
{reenterPassword ? (
<ReenterPassword visible={Boolean(reenterPassword)} accountName={reenterPassword} onClose={onCloseReenterPassword} />
<ReenterPassword visible={Boolean(reenterPassword)} accountName={reenterPassword} accountAddress={reenterPasswordAddress!} onClose={onCloseReenterPassword} />
) : null}
</>
);
Expand Down
12 changes: 5 additions & 7 deletions examples/js/expo/gnoboard/src/screens/wallet/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<RouterWelcomeStackProp>();
const { gnonative } = useGnoNativeContext();

const { account } = useGnoboardContext();
const [loading, setLoading] = React.useState<string | undefined>(undefined);
const [account, setAccount] = React.useState<KeyInfo | undefined>(undefined);
const [balance, setBalance] = React.useState<QueryAccountResponse | undefined>(undefined);
const [unknownAddress, setUnknownAddress] = React.useState<boolean>(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) {
Expand All @@ -47,7 +45,7 @@ export const Home: React.FC = () => {
}
});
return unsubscribe;
}, [navigation]);
}, [navigation, account]);

if (loading) {
return <Loading message={loading} />;
Expand Down

0 comments on commit cf99636

Please sign in to comment.