Skip to content

Commit

Permalink
Fix merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
dgca committed Apr 24, 2024
2 parents c526ffa + 81765cc commit ce43882
Show file tree
Hide file tree
Showing 27 changed files with 5,478 additions and 8,809 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13,740 changes: 5,035 additions & 8,705 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions packages/data-facade/src/facade.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ZodTypeAny, z } from "zod";
import { useQuery, useMutation } from "@tanstack/react-query";
import { useQuery, useMutation, UseMutationOptions } from "@tanstack/react-query";
import { buildQueryKey } from "./utils";
import type {
ResolverFunc,
Expand Down Expand Up @@ -32,13 +32,14 @@ function handlerQueryBuilder<TResolver extends ResolverFunc>(

function buildUseMutation() {
return <TResolver extends ResolverFunc>(resolver: TResolver) => ({
useMutation: () => {
useMutation: (opts?: UseMutationOptions<Awaited<ReturnType<TResolver>>, Error, unknown, unknown>) => {
return useMutation<
Awaited<ReturnType<TResolver>>,
Error,
unknown,
unknown
>({
...opts,
mutationFn: resolver,
});
},
Expand Down
2 changes: 1 addition & 1 deletion packages/data-facade/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type HandlerQueryBuilderReturn<TResolver extends ResolverFunc> = (
type UseMutationType<
TResolver extends ResolverFunc,
TReturn = Awaited<ReturnType<TResolver>>,
> = (opts?: UseMutationOptions) => UseMutationResult<TReturn>;
> = (opts?: UseMutationOptions<TReturn, Error, unknown, unknown>) => UseMutationResult<TReturn>;

export type HandlerMutationBuilderReturn<TResolver extends ResolverFunc> =
() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ class IronfishNativeModule : Module() {
)
}

Function("spendingKeyToWords") { privateKey: String, languageCode: Long ->
try {
return spendingKeyToWords(privateKey: privateKey, languageCode: languageCode)
} catch (error: Exception) {
error.printStackTrace()
throw error
}
}

Function("wordsToSpendingKey") { words: String, languageCode: Long ->
try {
return wordsToSpendingKey(words: words, languageCode: languageCode)
} catch (error: Exception) {
error.printStackTrace()
throw error
}
}

AsyncFunction("generateKeyFromPrivateKey") { privateKey: String ->
val k = uniffi.rust_lib.generateKeyFromPrivateKey(privateKey)

Expand All @@ -53,5 +71,14 @@ class IronfishNativeModule : Module() {
k.proofAuthorizingKey
)
}

Function("isValidPublicAddress") { hexAddress: String ->
try {
uniffi.rust_lib.isValidPublicAddress(hexAddress: hexAddress)
} catch (error: Exception) {
error.printStackTrace()
throw error
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ public class IronfishNativeModule: Module {
)
}

Function("spendingKeyToWords") { (privateKey: String, languageCode: Int32) throws -> String in
let phrase = try spendingKeyToWords(privateKey: privateKey, languageCode: languageCode)
return phrase
}

Function("wordsToSpendingKey") { (words: String, languageCode: Int32) throws -> String in
let k = try wordsToSpendingKey(words: words, languageCode: languageCode)
return k
Expand Down
13 changes: 13 additions & 0 deletions packages/ironfish-native-module/rust_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ fn generate_key() -> Key {
}
}

#[uniffi::export]
pub fn spending_key_to_words(
private_key: String,
language_code: i32,
) -> Result<String, EnumError> {
let key = SaplingKey::from_hex(&private_key).map_err(|e| EnumError::Error { msg: e.to_string() })?;
let language_code_enum: LanguageCode = LanguageCode::from_i32(language_code).ok_or_else(|| EnumError::Error { msg: "Invalid language code".to_string() })?;
let language = Language::from(language_code_enum);

let mnemonic = key.to_words(language).map_err(|e| EnumError::Error { msg: e.to_string() })?;
Ok(mnemonic.into_phrase())
}

#[uniffi::export]
pub fn words_to_spending_key(
words: String,
Expand Down
7 changes: 7 additions & 0 deletions packages/ironfish-native-module/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ export function generateKey(): Key {
return IronfishNativeModule.generateKey();
}

export function spendingKeyToWords(
privateKey: string,
languageCode: number,
): string {
return IronfishNativeModule.spendingKeyToWords(privateKey, languageCode);
}

export function wordsToSpendingKey(
words: string,
languageCode: number,
Expand Down
3 changes: 2 additions & 1 deletion packages/mobile-app/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"package": "com.ironfish.mobileapp"
},
"plugins": [
"expo-router"
"expo-router",
"expo-secure-store"
]
}
}
50 changes: 32 additions & 18 deletions packages/mobile-app/app/(tabs)/transact.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
import { View, Text } from "react-native";
import { useFacade } from "../../data";
import { View, Text, ScrollView, TextInput } from "react-native";
import { useFacade } from "../../data/facades";
import { Button } from "@ironfish/ui";
import { useState } from "react";
import { useQueryClient } from "@tanstack/react-query";

export default function Transact() {
const [facadeResult, setFacadeResult] = useState([""]);
const facade = useFacade();
const qc = useQueryClient();

const getAccountsResult = facade.getAccounts.useQuery(123);
const getAccountsWithZodResult = facade.getAccountsWithZod.useQuery({
limit: 2,
const getAccountsResult = facade.getAccounts.useQuery();
const createAccount = facade.createAccount.useMutation({
onSuccess: () => {
qc.invalidateQueries({
queryKey: ["getAccounts"],
});
},
});
const getAllAccountsResult = facade.getAllAccounts.useQuery();
const createAccount = facade.createAccount.useMutation();
const exportAccount = facade.exportAccount.useMutation();

return (
<View>
<ScrollView>
<Text>Accounts</Text>
<Text>{JSON.stringify(getAccountsResult.data)}</Text>
<Text>{JSON.stringify(getAccountsWithZodResult.data)}</Text>
<Text>{JSON.stringify(getAllAccountsResult.data)}</Text>
<Text>Mutation: {facadeResult}</Text>
{(getAccountsResult.data ?? []).map((account) => (
<View key={account.id}>
<Text>{account.name}</Text>
<Button
onPress={async () => {
const otherResult = await exportAccount.mutateAsync({
name: account.name,
});
console.log("Exported Account:", otherResult);
}}
>
Export Account
</Button>
</View>
))}
<Button
onPress={async () => {
const otherResult = await createAccount.mutateAsync("dave");
setFacadeResult(otherResult);
const otherResult = await createAccount.mutateAsync({ name: "dave" });
console.log("Created Account:", otherResult);
}}
>
Click me
Create Account
</Button>
</View>
</ScrollView>
);
}
50 changes: 41 additions & 9 deletions packages/mobile-app/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,61 @@ import {
ThemeProvider,
} from "@react-navigation/native";
import { Stack } from "expo-router";
import { Text } from "react-native";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

import { FacadeProvider } from "../data";
import { useColorScheme } from "react-native";
import { UIKitProvider } from "@ironfish/ui";
import { FacadeProvider, useFacade } from "../data/facades";
import React, { useEffect } from "react";

const queryClient = new QueryClient();

function DatabaseLoader({
loading,
children,
}: {
loading: React.ReactNode;
children?: React.ReactNode;
}) {
const facade = useFacade();
const [status, setStatus] = React.useState<string>("loading");
const loadDatabases = facade.loadDatabases.useMutation();

useEffect(() => {
const fn = async () => {
const result = await loadDatabases.mutateAsync(undefined);
setStatus(result);
};
fn();
}, []);

if (status === "loading") {
return loading;
} else if (status === "loaded") {
return children;
} else {
throw new Error(`Unknown status ${status}`);
}
}

export default function Layout() {
const scheme = useColorScheme();
return (
<ThemeProvider value={scheme === "dark" ? DarkTheme : DefaultTheme}>
<UIKitProvider colorScheme={scheme || "light"}>
<QueryClientProvider client={queryClient}>
<FacadeProvider>
<Stack>
<Stack.Screen
name="(tabs)"
options={{
headerShown: false,
}}
/>
</Stack>
<DatabaseLoader loading={<Text>Loading databases...</Text>}>
<Stack>
<Stack.Screen
name="(tabs)"
options={{
headerShown: false,
}}
/>
</Stack>
</DatabaseLoader>
</FacadeProvider>
</QueryClientProvider>
</UIKitProvider>
Expand Down
50 changes: 0 additions & 50 deletions packages/mobile-app/data/accounts/handlers.ts

This file was deleted.

9 changes: 0 additions & 9 deletions packages/mobile-app/data/accounts/types.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/mobile-app/data/facades/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# facades

Facades use the `data-facade` package to provide a `tanstack/react-query` interface between the wallet code in the `data` folder and the Expo frontend in the `app` folder.

The facade routes are intended to be similar to the [Iron Fish RPC routes](https://github.com/iron-fish/ironfish/tree/master/ironfish/src/rpc/routes). Our goal is that in the future, we could implement a facade that connects directly to an Iron Fish node with minimal changes to the frontend code.
51 changes: 51 additions & 0 deletions packages/mobile-app/data/facades/accounts/demoHandlers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { f } from "data-facade";
import { z } from "zod";
import { AccountsMethods } from "./types";

let ACCOUNTS = [
{ id: 0, name: "alice", viewOnlyAccount: "alice" },
{ id: 1, name: "bob", viewOnlyAccount: "bob"},
{ id: 2, name: "carol", viewOnlyAccount: "carol"}
];

async function getAccounts(limit: number) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return ACCOUNTS.slice(0, limit);
}

export const accountsHandlers = f.facade<AccountsMethods>({
getAccounts: f.handler.query(async () => {
const accounts = await getAccounts(ACCOUNTS.length);
console.log("getAccounts", accounts);
return accounts;
}),
createAccount: f.handler
.input(
z.object({
name: z.string(),
}),
)
.mutation(async ({ name }) => {
const existingId = ACCOUNTS.at(-1)?.id
if (existingId === undefined) {
throw new Error("No accounts found");
}
const account = { id: existingId + 1, name, viewOnlyAccount: name }
console.log("createAccount", account);
ACCOUNTS.push(account);
return account;
}),
exportAccount: f.handler
.input(
z.object({
name: z.string(),
}),
)
.mutation(async ({ name }) => {
const account = ACCOUNTS.find((a) => a.name === name)
if (account === undefined) {
throw new Error("No accounts found");
}
return JSON.stringify(account);
}),
});
Loading

0 comments on commit ce43882

Please sign in to comment.