Skip to content

Commit 6cecc59

Browse files
committed
Clean up tsconfig
2 parents ee4ccf6 + 3e95622 commit 6cecc59

File tree

25 files changed

+1145
-180
lines changed

25 files changed

+1145
-180
lines changed

.github/workflows/ci.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,7 @@ jobs:
2727
run: npm ci
2828

2929
- name: Lint
30-
run: npm run lint
30+
run: npm run lint
31+
32+
- name: Typecheck
33+
run: npm run typecheck

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"scripts": {
77
"lint": "npm run lint --workspaces --if-present -- --max-warnings=0",
88
"lint:fix": "npm run lint --workspaces --if-present -- --fix --max-warnings=0",
9+
"typecheck": "npm run typecheck --workspaces --if-present",
910
"postinstall": "git submodule update --init --recursive"
1011
},
1112
"devDependencies": {

packages/data-facade/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"main": "./src/index.ts",
77
"types": "./src/index.ts",
88
"scripts": {
9-
"test": "echo \"Error: no test specified\" && exit 1"
9+
"typecheck": "tsc --noEmit"
1010
},
1111
"devDependencies": {
1212
"@tanstack/react-query": "^5.28.14",

packages/ironfish-native-module/ios/IronfishNativeModule.swift

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,28 @@ public class IronfishNativeModule: Module {
9191
return readPartialFile(path: path, offset: offset, length: length)
9292
}
9393

94-
AsyncFunction("decryptNotesForOwner") { (noteEncrypted: [String], incomingHexKey: String, promise: Promise) in
94+
AsyncFunction("decryptNotesForOwner") { (noteEncrypteds: [String], incomingHexKey: String, promise: Promise) in
9595
Task {
96-
let decryptedNotes = try await decryptNotesForOwner(noteEncrypted: noteEncrypted, incomingHexKey: incomingHexKey)
96+
let decryptedNotes = try await decryptNotesForOwner(noteEncrypteds: noteEncrypteds, incomingHexKey: incomingHexKey)
9797
let expoOutputs = decryptedNotes.map { note in
9898
ExpoOutput(index: note.index, note: Field(wrappedValue: note.note))
9999
}
100100
promise.resolve(expoOutputs)
101101
}
102102
}
103+
104+
AsyncFunction("decryptNotesForSpender") { (noteEncrypteds: [String], outgoingHexKey: String, promise: Promise) in
105+
Task {
106+
let decryptedNotes = try await decryptNotesForSpender(noteEncrypteds: noteEncrypteds, outgoingHexKey: outgoingHexKey)
107+
let expoOutputs = decryptedNotes.map { note in
108+
ExpoOutput(index: note.index, note: Field(wrappedValue: note.note))
109+
}
110+
promise.resolve(expoOutputs)
111+
}
112+
}
113+
114+
AsyncFunction("nullifier") { (note: String, position: String, viewKey: String) throws -> String in
115+
return try nullifier(note: note, position: position, viewKey: viewKey)
116+
}
103117
}
104118
}

packages/ironfish-native-module/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"cargo-ios": "tsx scripts/cargo-ios.ts",
1818
"cargo-ios-sim": "tsx scripts/cargo-ios.ts --target=ios-sim",
1919
"cargo-android": "tsx scripts/cargo-android.ts",
20-
"build-rust": "npm run cargo-android && npm run cargo-ios -- --target=ios-sim"
20+
"build-rust": "npm run cargo-android && npm run cargo-ios -- --target=ios-sim",
21+
"typecheck": "tsc --noEmit"
2122
},
2223
"keywords": [
2324
"react-native",

packages/ironfish-native-module/rust_lib/src/lib.rs

Lines changed: 91 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tokio_rayon::rayon::iter::{
1212
use zune_inflate::DeflateDecoder;
1313

1414
use crate::num::FromPrimitive;
15-
use ironfish::{keys::Language, serializing::bytes_to_hex, PublicAddress, SaplingKey};
15+
use ironfish::{keys::Language, serializing::bytes_to_hex, Note, PublicAddress, SaplingKey};
1616

1717
uniffi::setup_scaffolding!();
1818

@@ -159,49 +159,118 @@ pub fn read_partial_file(path: String, offset: u32, length: u32) -> Vec<u8> {
159159

160160
#[uniffi::export(async_runtime = "tokio")]
161161
pub async fn decrypt_notes_for_owner(
162-
note_encrypted: Vec<String>,
162+
note_encrypteds: Vec<String>,
163163
incoming_hex_key: String,
164164
) -> Result<Vec<DecryptedNote>, EnumError> {
165165
let incoming_view_key = ironfish::IncomingViewKey::from_hex(&incoming_hex_key)
166166
.map_err(|e| EnumError::Error { msg: e.to_string() })?;
167167

168-
let idxes = note_encrypted
168+
let idxes = note_encrypteds
169169
.par_iter()
170170
.enumerate()
171171
.filter_map(|(i, output)| {
172172
let bytes = const_hex::decode(output);
173173
if bytes.is_err() {
174-
println!("error converting hex to bytes");
174+
eprintln!("error converting hex to bytes");
175175
return None;
176176
}
177177

178178
let note = ironfish::MerkleNote::read(bytes.unwrap().as_slice());
179179
if note.is_err() {
180-
println!("error reading bytes");
180+
eprintln!("error reading bytes");
181181
return None;
182182
}
183183

184184
let dec: Result<ironfish::Note, ironfish::errors::IronfishError> =
185185
note.unwrap().decrypt_note_for_owner(&incoming_view_key);
186-
if dec.is_ok() {
187-
let mut vec = vec![];
188-
if dec
189-
.unwrap()
190-
.write(&mut vec)
191-
.map_err(|e| EnumError::Error { msg: e.to_string() })
192-
.is_err()
193-
{
194-
println!("error writing bytes");
195-
return None;
196-
}
197-
198-
return Some(DecryptedNote {
199-
index: i as u32,
200-
note: const_hex::encode(&vec),
201-
});
186+
187+
if dec.is_err() {
188+
return None;
189+
}
190+
191+
let mut vec = vec![];
192+
if dec
193+
.unwrap()
194+
.write(&mut vec)
195+
.map_err(|e| EnumError::Error { msg: e.to_string() })
196+
.is_err()
197+
{
198+
eprintln!("error writing bytes");
199+
return None;
202200
}
203-
None
201+
202+
Some(DecryptedNote {
203+
index: i as u32,
204+
note: const_hex::encode(&vec),
205+
})
204206
});
205207

206208
Ok(idxes.collect())
207209
}
210+
211+
#[uniffi::export(async_runtime = "tokio")]
212+
pub async fn decrypt_notes_for_spender(
213+
note_encrypteds: Vec<String>,
214+
outgoing_hex_key: String,
215+
) -> Result<Vec<DecryptedNote>, EnumError> {
216+
let outgoing_view_key = ironfish::OutgoingViewKey::from_hex(&outgoing_hex_key)
217+
.map_err(|e| EnumError::Error { msg: e.to_string() })?;
218+
219+
let idxes = note_encrypteds
220+
.par_iter()
221+
.enumerate()
222+
.filter_map(|(i, output)| {
223+
let bytes = const_hex::decode(output);
224+
if bytes.is_err() {
225+
eprintln!("error converting hex to bytes");
226+
return None;
227+
}
228+
229+
let note = ironfish::MerkleNote::read(bytes.unwrap().as_slice());
230+
if note.is_err() {
231+
eprintln!("error reading bytes");
232+
return None;
233+
}
234+
235+
let dec: Result<ironfish::Note, ironfish::errors::IronfishError> =
236+
note.unwrap().decrypt_note_for_spender(&outgoing_view_key);
237+
238+
if dec.is_err() {
239+
return None;
240+
}
241+
242+
let mut vec = vec![];
243+
if dec
244+
.unwrap()
245+
.write(&mut vec)
246+
.map_err(|e| EnumError::Error { msg: e.to_string() })
247+
.is_err()
248+
{
249+
eprintln!("error writing bytes");
250+
return None;
251+
}
252+
253+
Some(DecryptedNote {
254+
index: i as u32,
255+
note: const_hex::encode(&vec),
256+
})
257+
});
258+
259+
Ok(idxes.collect())
260+
}
261+
262+
#[uniffi::export]
263+
pub fn nullifier(note: String, position: String, view_key: String) -> Result<String, EnumError> {
264+
let view_key = ironfish::ViewKey::from_hex(&view_key)
265+
.map_err(|e| EnumError::Error { msg: e.to_string() })?;
266+
267+
let bytes = const_hex::decode(note).map_err(|e| EnumError::Error { msg: e.to_string() })?;
268+
269+
let position_u64 = position
270+
.parse::<u64>()
271+
.map_err(|e| EnumError::Error { msg: e.to_string() })?;
272+
273+
let note = Note::read(&bytes[..]).map_err(|e| EnumError::Error { msg: e.to_string() })?;
274+
275+
Ok(const_hex::encode(note.nullifier(&view_key, position_u64).0))
276+
}

packages/ironfish-native-module/src/index.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,21 @@ export function decryptNotesForOwner(
7777
incomingHexKey,
7878
);
7979
}
80+
81+
export function decryptNotesForSpender(
82+
noteEncrypted: string[],
83+
outgoingHexKey: string,
84+
): Promise<{ index: number; note: string }[]> {
85+
return IronfishNativeModule.decryptNotesForSpender(
86+
noteEncrypted,
87+
outgoingHexKey,
88+
);
89+
}
90+
91+
export function nullifier(
92+
note: string,
93+
position: string,
94+
viewKey: string,
95+
): Promise<string> {
96+
return IronfishNativeModule.nullifier(note, position, viewKey);
97+
}

packages/mobile-app/app/(tabs)/contacts.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
11
import { View, Text, Button } from "react-native";
2-
import { wallet } from "../../data/wallet/wallet";
32

4-
import { Network } from "../../data/constants";
3+
import { useFacade } from "../../data/facades";
54

65
export default function Contacts() {
6+
const facade = useFacade();
7+
8+
const walletStatus = facade.getWalletStatus.useQuery(undefined, {
9+
refetchInterval: 1000,
10+
});
11+
12+
const pauseSyncing = facade.pauseSyncing.useMutation();
13+
const resumeSyncing = facade.resumeSyncing.useMutation();
14+
715
return (
816
<View>
9-
<Text>Contacts</Text>
17+
{walletStatus.data && (
18+
<>
19+
<Text>{`Scan status: ${walletStatus.data.status}`}</Text>
20+
<Text>{`Latest known block: ${walletStatus.data.latestKnownBlock}`}</Text>
21+
</>
22+
)}
23+
<Text>{}</Text>
24+
<Button
25+
onPress={async () => {
26+
await resumeSyncing.mutateAsync(undefined);
27+
}}
28+
title="Resume Syncing"
29+
/>
1030
<Button
11-
title="Request Blocks"
12-
onPress={() => {
13-
wallet.scan(Network.TESTNET);
31+
onPress={async () => {
32+
await pauseSyncing.mutateAsync(undefined);
1433
}}
34+
title="Pause Syncing"
1535
/>
1636
</View>
1737
);

packages/mobile-app/app/(tabs)/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ export default function Balances() {
1515
},
1616
);
1717

18+
const getAccountResult = facade.getAccount.useQuery(
19+
{ name: account },
20+
{
21+
refetchInterval: 1000,
22+
},
23+
);
24+
1825
const getAccountsResult = facade.getAccounts.useQuery();
1926

2027
useEffect(() => {
@@ -38,6 +45,13 @@ export default function Balances() {
3845
</View>
3946
))}
4047
</ScrollView>
48+
<Text style={{ fontWeight: 700, fontSize: 24 }}>Balance</Text>
49+
{getAccountResult.data && (
50+
<>
51+
<Text>{`Unconfirmed: IRON ${getAccountResult.data.balances.iron.unconfirmed}`}</Text>
52+
<Text>{`Confirmed: IRON ${getAccountResult.data.balances.iron.confirmed}`}</Text>
53+
</>
54+
)}
4155
<StatusBar style="auto" />
4256
</View>
4357
);

packages/mobile-app/data/api/walletServer.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,23 @@ const WALLET_SERVER_URLS: Record<Network, string> = {
1616
class WalletServer {
1717
transformers: WalletServerTransformer[] = [ForkTester];
1818

19+
private latestBlockCache: Map<
20+
Network,
21+
{ time: number; response: GetLatestBlockResponse }
22+
> = new Map();
23+
private LATEST_BLOCK_CACHE_MS = 5000;
24+
1925
async getLatestBlock(network: Network): Promise<GetLatestBlockResponse> {
2026
const url = WALLET_SERVER_URLS[network] + "latest-block";
27+
28+
const cached = this.latestBlockCache.get(network);
29+
if (
30+
cached &&
31+
performance.now() - cached.time < this.LATEST_BLOCK_CACHE_MS
32+
) {
33+
return cached.response;
34+
}
35+
2136
console.log("requesting latest block");
2237

2338
const fetchResult = await fetch(url);
@@ -27,6 +42,11 @@ class WalletServer {
2742
latestBlock = await transformer.getLatestBlock(network, latestBlock);
2843
}
2944

45+
this.latestBlockCache.set(network, {
46+
time: performance.now(),
47+
response: latestBlock,
48+
});
49+
3050
return latestBlock;
3151
}
3252

0 commit comments

Comments
 (0)