diff --git a/mobile/app/(app)/add-key/captcha copy.html b/mobile/app/(app)/add-key/captcha copy.html
new file mode 100644
index 00000000..5ee01e3d
--- /dev/null
+++ b/mobile/app/(app)/add-key/captcha copy.html
@@ -0,0 +1,45 @@
+
+
+
+
+ reCAPTCHA demo: Simple page
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/app/(app)/add-key/captcha.html b/mobile/app/(app)/add-key/captcha.html
new file mode 100644
index 00000000..ab474ac1
--- /dev/null
+++ b/mobile/app/(app)/add-key/captcha.html
@@ -0,0 +1,42 @@
+
+
+
+
+ reCAPTCHA demo: Simple page
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mobile/app/(app)/add-key/index.tsx b/mobile/app/(app)/add-key/index.tsx
index f01ddcaf..e328cef4 100644
--- a/mobile/app/(app)/add-key/index.tsx
+++ b/mobile/app/(app)/add-key/index.tsx
@@ -1,4 +1,4 @@
-import { StyleSheet, Text, View, ScrollView, TextInput as RNTextInput, Alert as RNAlert } from "react-native";
+import { StyleSheet, Text, View, ScrollView, TextInput as RNTextInput, Alert as RNAlert, Modal } from "react-native";
import React, { useEffect, useRef, useState } from "react";
import { router, useNavigation } from "expo-router";
import { useGnoNativeContext } from "@gnolang/gnonative";
@@ -14,16 +14,19 @@ import {
selectKeyName,
setKeyName,
selectPhrase,
+ selectSelectedChain,
} from "@/redux";
import { ProgressViewModal, ChainSelectView } from "@/views";
-import { TextCopy, Layout, Alert, Spacer, Button, TextInput } from "@/components";
+import { TextCopy, Layout, Alert, Spacer, Button, TextInput, ModalHeader, ModalContent } from "@/components";
import { Octicons } from "@expo/vector-icons";
import { colors } from "@/assets";
+import { WebView, WebViewMessageEvent } from 'react-native-webview';
export default function Page() {
const [error, setError] = useState(undefined);
const [loading, setLoading] = useState(false);
+ const [modalVisible, setModalVisible] = useState(false);
const inputRef = useRef(null);
@@ -38,6 +41,8 @@ export default function Page() {
const existingAccount = useAppSelector(existingAccountSelector);
const keyName = useAppSelector(selectKeyName);
const phrase = useAppSelector(selectPhrase);
+ const currentNetwork = useAppSelector(selectSelectedChain)
+
useEffect(() => {
const unsubscribe = navigation.addListener("focus", async () => {
@@ -91,7 +96,7 @@ export default function Page() {
})();
}, [signUpState, newAccount]);
- const onCreate = async () => {
+ const onCreate = async (catpchaToken: string | undefined = undefined) => {
setError(undefined);
if (!keyName) {
setError("Please fill out all fields");
@@ -114,16 +119,21 @@ export default function Page() {
return;
}
+ if (currentNetwork?.hasCaptcha && !catpchaToken) {
+ setModalVisible(true);
+ return
+ }
+
if (signUpState === SignUpState.user_exists_only_on_local_storage && existingAccount) {
await gnonative.activateAccount(keyName);
await gnonative.setPassword(masterPassword, existingAccount.address);
- await dispatch(onboarding({ account: existingAccount })).unwrap();
+ await dispatch(onboarding({ account: existingAccount, captcha: catpchaToken })).unwrap();
return;
}
try {
setLoading(true);
- await dispatch(signUp({ name: keyName, password: masterPassword, phrase })).unwrap();
+ await dispatch(signUp({ name: keyName, password: masterPassword, phrase, captcha: catpchaToken })).unwrap();
} catch (error) {
RNAlert.alert("Error", "" + error);
setError("" + error);
@@ -139,6 +149,14 @@ export default function Page() {
router.back()
}
+ const handleMessage = (event: WebViewMessageEvent) => {
+ // Capture the token from the WebView
+ const { data } = event.nativeEvent;
+ console.log('Recaptcha token received:', data);
+ setModalVisible(false); // Update the token in state
+ onCreate(data); // Call the onCreate function with the token
+ };
+
return (
@@ -169,19 +187,41 @@ export default function Page() {
-
+ onCreate()} variant="primary" loading={loading} />
+
+
+ setModalVisible(false)} />
+
+
+
-
+
);
}
const styles = StyleSheet.create({
+ centeredView: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ marginTop: 22,
+ backgroundColor: "#0008",
+ },
container: {
flex: 1,
alignItems: "center",
diff --git a/mobile/app/(app)/add-key/localHtmlFile.html b/mobile/app/(app)/add-key/localHtmlFile.html
new file mode 100644
index 00000000..fbc6e2f0
--- /dev/null
+++ b/mobile/app/(app)/add-key/localHtmlFile.html
@@ -0,0 +1,13 @@
+
+
+ reCAPTCHA demo: Simple page
+
+
+
+
+
+
diff --git a/mobile/app/(app)/home/home.tsx b/mobile/app/(app)/home/home.tsx
index 9f6827c7..1e213fcb 100644
--- a/mobile/app/(app)/home/home.tsx
+++ b/mobile/app/(app)/home/home.tsx
@@ -33,7 +33,7 @@ export default function Page() {
const response = await gnonative.listKeyInfo();
setAccounts(response);
- dispatch(checkForKeyOnChains())
+ // dispatch(checkForKeyOnChains())
} catch (error: unknown | Error) {
console.error(error);
} finally {
diff --git a/mobile/assets/chains.json b/mobile/assets/chains.json
index a5b524d9..dcb692f0 100644
--- a/mobile/assets/chains.json
+++ b/mobile/assets/chains.json
@@ -3,29 +3,21 @@
"chainId": "portal-loop",
"chainName": "Portal loop",
"gnoAddress": "https://rpc.gno.land:443",
- "faucetAddress": "https://faucet-api.gno.land"
+ "faucetAddress": "https://faucet-api.gno.land",
+ "hasCaptcha": true
},
{
"chainId": "test5",
"chainName": "Testnet 5",
"gnoAddress": "http://rpc.test5.gno.land",
- "faucetAddress": "https://faucet-api.test5.gno.land"
+ "faucetAddress": "https://faucet-api.test5.gno.land",
+ "hasCaptcha": true
},
{
"chainId": "dev",
"chainName": "Berty-Dev",
"gnoAddress": "https://api.gno.berty.io:443",
- "faucetAddress": "https://faucetpass.gno.berty.io"
- },
- {
- "chainId": "teritori-1",
- "chainName": "Teritori-1",
- "gnoAddress": "testnet.gno.teritori.com:26657"
- },
- {
- "chainId": "dev",
- "chainName": "localhost",
- "gnoAddress": "localhost:26657",
- "faucetAddress": "http://localhost:8545"
+ "faucetAddress": "https://faucetpass.gno.berty.io",
+ "hasCaptcha": false
}
]
diff --git a/mobile/redux/features/signupSlice.ts b/mobile/redux/features/signupSlice.ts
index 48f85362..26ee6de9 100644
--- a/mobile/redux/features/signupSlice.ts
+++ b/mobile/redux/features/signupSlice.ts
@@ -46,6 +46,7 @@ interface SignUpParam {
name: string;
password: string;
phrase: string;
+ captcha?: string;
}
type SignUpResponse = { newAccount?: KeyInfo, existingAccount?: KeyInfo, state: SignUpState };
@@ -67,7 +68,7 @@ type SignUpResponse = { newAccount?: KeyInfo, existingAccount?: KeyInfo, state:
*/
export const signUp = createAsyncThunk("user/signUp", async (param, thunkAPI) => {
- const { name, password, phrase } = param;
+ const { name, password, phrase, captcha } = param;
const { registerAccount, selectedChain } = (thunkAPI.getState() as RootState).signUp;
const gnonative = thunkAPI.extra.gnonative as GnoNativeApi;
@@ -161,7 +162,7 @@ export const signUp = createAsyncThunk(
thunkAPI.dispatch(addProgress(`no faucetAddress set for chain "${selectedChain.chainName}"`))
} else {
thunkAPI.dispatch(addProgress(`onboarding "${name}"`))
- await onboard(gnonative, newAccount, selectedChain.faucetAddress);
+ await onboard(gnonative, newAccount, selectedChain.faucetAddress, captcha);
}
thunkAPI.dispatch(addProgress(`SignUpState.account_created`))
@@ -169,7 +170,7 @@ export const signUp = createAsyncThunk(
}
})
-export const onboarding = createAsyncThunk("user/onboarding", async (param, thunkAPI) => {
+export const onboarding = createAsyncThunk("user/onboarding", async (param, thunkAPI) => {
thunkAPI.dispatch(addProgress(`onboarding "${param.account.name}"`))
const { selectedChain } = (thunkAPI.getState() as RootState).signUp;
@@ -178,9 +179,9 @@ export const onboarding = createAsyncThunk {
+const onboard = async (gnonative: GnoNativeApi, account: KeyInfo, faucetRemote?: string, captcha?: string) => {
const { name, address } = account
const address_bech32 = await gnonative.addressToBech32(address);
- console.log("onboarding %s, with address: %s", name, address_bech32);
+ console.log("onboard %s, with address: %s", name, address_bech32);
try {
const hasBalance = await hasCoins(gnonative, address);
@@ -279,7 +280,7 @@ const onboard = async (gnonative: GnoNativeApi, account: KeyInfo, faucetRemote?:
}
if (faucetRemote) {
- const response = await sendCoins(address_bech32, faucetRemote);
+ const response = await sendCoins(address_bech32, faucetRemote, captcha);
console.log("coins sent, response: %s", response);
await registerAccount(gnonative, account);
} else {
@@ -326,14 +327,19 @@ const hasCoins = async (gnonative: GnoNativeApi, address: Uint8Array) => {
}
};
-const sendCoins = async (address: string, faucetRemote: string) => {
+const sendCoins = async (address: string, faucetRemote: string, captcha?: string) => {
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
const raw = JSON.stringify({
To: address,
+ captcha,
+ amount: 1 * 1000000 + 'ugnot'
});
+ console.log("sending coins to %s", address);
+ console.log("raw", raw);
+
const requestOptions = {
method: "POST",
headers: myHeaders,
@@ -393,7 +399,7 @@ export const signUpSlice = createSlice({
state.existingAccount = action.payload?.existingAccount;
state.signUpState = action.payload?.state;
}).addCase(initSignUpState.fulfilled, (state, action) => {
- console.log("initSignUpState.fulfilled nnnnnn", action.payload);
+ console.log("initSignUpState.fulfilled", action.payload);
state.phrase = action.payload.phrase;
state.loading = false;
state.newAccount = undefined;
@@ -420,7 +426,7 @@ export const signUpSlice = createSlice({
export const selectChainsAvailable = createSelector(
(state: RootState) => state.signUp.customChains,
- (customChains) => customChains ? chains.concat(customChains) : chains
+ (customChains) => customChains ? (chains as NetworkMetainfo[]).concat(customChains) : chains
);
export const { addProgress, signUpState, clearProgress, addCustomChain, setRegisterAccount, setKeyName,
diff --git a/mobile/types.ts b/mobile/types.ts
index ba28fd3c..1e85fbf5 100644
--- a/mobile/types.ts
+++ b/mobile/types.ts
@@ -43,5 +43,6 @@ export type NetworkMetainfo = {
chainName: string;
gnoAddress: string;
faucetAddress?: string;
+ hasCaptcha?: boolean;
};