diff --git a/mobile/README.md b/mobile/README.md index 9114550..9709f23 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -125,3 +125,34 @@ make android # to start Metro Bundler: make start ``` + +## Inter App communication + +dSocial and Gnokey mobile app are using `expo-linking` to exchange data. +So that way you can signin or sign a transaction using Gnokey mobile app. + +### Sign in + +Example of dSocial asking for sign in +``` +land.gno.gnokey://tologin?callback=tech.berty.dsocial%3A%2F%2Flogin-callback +``` +- Base url: `land.gno.gnokey://tologin` +- Parameters: + - callback: the url that Gnokey mobile will call after the user selecting the account. + + +### Sign a transaction +Example of dSocial asking Gnokey Mobile to sign a transaction: +``` +land.gno.gnokey://tosign?tx=%257B%2522msg%2522%253A%255B%257B%2522%2540type%2522%253A%2522%252Fvm.m_call%2522%252C%2522caller%2522%253A%2522g1gl0hrpuegawx6pv24xjq8jjmufzp5r5mnn896w%2522%252C%2522send%2522%253A%2522%2522%252C%2522pkg_path%2522%253A%2522gno.land%252Fr%252Fberty%252Fsocial%2522%252C%2522func%2522%253A%2522PostMessage%2522%252C%2522args%2522%253A%255B%2522Test%25203%2522%255D%257D%255D%252C%2522fee%2522%253A%257B%2522gas_wanted%2522%253A%252210000000%2522%252C%2522gas_fee%2522%253A%25221000000ugnot%2522%257D%252C%2522signatures%2522%253Anull%252C%2522memo%2522%253A%2522%2522%257D&address=g1gl0hrpuegawx6pv24xjq8jjmufzp5r5mnn896w&client_name=dSocial&reason=Post%20a%20message&callback=tech.berty.dsocial%253A%252F%252Fpost +``` + +- Base url: `land.gno.gnokey://tosign` +- Parameters: + - tx: the json result of `gnonative.makeCallTx(...)` + - address: bech32 address of whoever you want to sign the transaction. + - client_name: the name of the application that is calling the Gnokey mobile application. It will be displayed to the user. + - reason: the reason behind this action. It will be displayed to the user. + - callback: the callback URL that will be called from Gnokey mobile after signing the tx. + diff --git a/mobile/app/(app)/home/home.tsx b/mobile/app/(app)/home/home.tsx index d01ca58..31118dd 100644 --- a/mobile/app/(app)/home/home.tsx +++ b/mobile/app/(app)/home/home.tsx @@ -3,7 +3,7 @@ import { FlatList, TouchableOpacity, View } from "react-native"; import { useNavigation, useRouter } from "expo-router"; import { Layout } from "@/components/index"; import Text from "@/components/text"; -import { selectMasterPassword, selectTxInput, useAppDispatch, useAppSelector } from "@/redux"; +import { selectMasterPassword, useAppDispatch, useAppSelector } from "@/redux"; import { KeyInfo, useGnoNativeContext } from "@gnolang/gnonative"; import Octicons from '@expo/vector-icons/Octicons'; import TextInput from "@/components/textinput"; @@ -22,7 +22,6 @@ export default function Page() { const { gnonative } = useGnoNativeContext(); const navigation = useNavigation(); const dispatch = useAppDispatch(); - const txInput = useAppSelector(selectTxInput); const masterPassword = useAppSelector(selectMasterPassword) useEffect(() => { diff --git a/mobile/app/(app)/tologin/index.tsx b/mobile/app/(app)/tologin/index.tsx index e162d00..5f083cb 100644 --- a/mobile/app/(app)/tologin/index.tsx +++ b/mobile/app/(app)/tologin/index.tsx @@ -3,10 +3,10 @@ import Button from "@/components/button"; import VaultListItem from "@/components/list/vault-list/VaultListItem"; import Spacer from "@/components/spacer"; import Text from "@/components/text"; -import { selectCallback, sendAddressToSoliciting, useAppDispatch, useAppSelector } from "@/redux"; +import { clearLinking, selectCallback, sendAddressToSoliciting, useAppDispatch, useAppSelector } from "@/redux"; import { KeyInfo, useGnoNativeContext } from "@gnolang/gnonative"; import { router, useNavigation } from "expo-router"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { FlatList } from "react-native"; export default function Page() { @@ -41,6 +41,11 @@ export default function Page() { router.push("/home") }, [callback]); + const onCancel = () => { + dispatch(clearLinking()) + router.push("/home") + } + return ( <> @@ -58,7 +63,7 @@ export default function Page() { ListEmptyComponent={There are no items to list.} /> )} - router.push("/home")}> + diff --git a/mobile/app/(app)/tosign/index.tsx b/mobile/app/(app)/tosign/index.tsx index 3dbad3b..3dbd978 100644 --- a/mobile/app/(app)/tosign/index.tsx +++ b/mobile/app/(app)/tosign/index.tsx @@ -2,7 +2,7 @@ import { Layout } from "@/components"; import Button from "@/components/button"; import Spacer from "@/components/spacer"; import Text from "@/components/text"; -import { selectClientName, selectBech32Address, selectTxInput, signTx, useAppDispatch, useAppSelector, reasonSelector, selectCallback, selectKeyInfo } from "@/redux"; +import { selectClientName, selectBech32Address, selectTxInput, signTx, useAppDispatch, useAppSelector, reasonSelector, selectCallback, selectKeyInfo, clearLinking } from "@/redux"; import { useGnoNativeContext } from "@gnolang/gnonative"; import { router } from "expo-router"; import { useEffect, useState } from "react"; @@ -48,6 +48,11 @@ export default function Page() { router.push("/home") } + const onCancel = () => { + dispatch(clearLinking()); + router.push("/home") + } + return ( <> @@ -66,7 +71,7 @@ export default function Page() { - router.push("/home")}> + diff --git a/mobile/app/index.tsx b/mobile/app/index.tsx index 7be6264..19d7887 100644 --- a/mobile/app/index.tsx +++ b/mobile/app/index.tsx @@ -3,7 +3,7 @@ import { ScrollView, View } from "react-native"; import { useRouter } from "expo-router"; import { Layout } from "@/components/index"; import Text from "@/components/text"; -import { getInitialState, selectInitialized, selectMasterPassword, selectPath, signIn, signUp, useAppDispatch, useAppSelector } from "@/redux"; +import { getInitialState, selectAction, selectInitialized, selectMasterPassword, signIn, signUp, useAppDispatch, useAppSelector } from "@/redux"; import * as Application from "expo-application"; import SignInView from "@/views/signin"; import SignUpView from "@/views/signup"; @@ -19,7 +19,7 @@ export default function Root() { const appInitialized = useAppSelector(selectInitialized) const hasMasterPassword = useAppSelector(selectMasterPassword) - const path = useAppSelector(selectPath); + const action = useAppSelector(selectAction); useEffect(() => { dispatch(getInitialState()) @@ -50,9 +50,8 @@ export default function Root() { }; const naviateTo = () => { - console.log("path", path); - if (path) { - route.replace(path as string); + if (action) { + route.replace(action); } else { route.replace("/home"); } diff --git a/mobile/package.json b/mobile/package.json index 52963ba..813aa4f 100644 --- a/mobile/package.json +++ b/mobile/package.json @@ -1,7 +1,7 @@ { "name": "gnokey", "version": "0.0.1", - "main": "expo-router/entry", + "main": "index.ts", "scripts": { "start": "expo start -d", "android": "expo run:android", diff --git a/mobile/redux/features/linkingSlice.ts b/mobile/redux/features/linkingSlice.ts index 4e3c9ea..9ddfd6a 100644 --- a/mobile/redux/features/linkingSlice.ts +++ b/mobile/redux/features/linkingSlice.ts @@ -14,6 +14,7 @@ interface CounterState { callback?: string; /* The path of the requested screen */ path?: string | 'tologin'; + hostname?: string; } const initialState: CounterState = { @@ -23,6 +24,7 @@ const initialState: CounterState = { txInput: undefined, callback: undefined, path: undefined, + hostname: undefined, }; /** @@ -76,6 +78,7 @@ interface SetLinkResponse { callback?: string; path: string; keyinfo?: KeyInfo; + hostname?: string; } export const setLinkingData = createAsyncThunk("linking/setLinkingData", async (parsedURL, thunkAPI) => { @@ -98,12 +101,13 @@ export const setLinkingData = createAsyncThunk { + console.log("clearing linking data"); + state = { ...initialState }; + }, + }, extraReducers: (builder) => { builder.addCase(setLinkingData.fulfilled, (state, action) => { state.reason = action.payload.reason; @@ -121,6 +130,7 @@ export const linkingSlice = createSlice({ state.callback = action.payload.callback; state.path = action.payload.path; state.keyinfo = action.payload.keyinfo; + state.hostname = action.payload.hostname; }) }, selectors: { @@ -131,7 +141,14 @@ export const linkingSlice = createSlice({ selectClientName: (state) => state.clientName, selectKeyInfo: (state) => state.keyinfo, reasonSelector: (state) => state.reason, + isToLoginSelector: (state) => state.hostname === 'tologin', + selectAction: (state) => state.hostname !== expo_default ? state.hostname : undefined, }, }); -export const { selectTxInput, selectCallback, selectPath, selectBech32Address, selectClientName, reasonSelector, selectKeyInfo } = linkingSlice.selectors; +// Expo default hostname +const expo_default = 'expo-development-client'; + +export const { clearLinking } = linkingSlice.actions; + +export const { selectTxInput, selectCallback, selectPath, selectBech32Address, selectClientName, reasonSelector, selectKeyInfo, isToLoginSelector, selectAction } = linkingSlice.selectors;