Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion mobile_app/context/LxmfContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ interface LxmfCtxValue {
pairNusRNode: (mac: string) => boolean;
beaconRpc: (destHashHex: string, method: string, params?: unknown) => Promise<number>;
beaconBroadcastRpc: (method: string, params?: unknown, timeoutMs?: number) => Promise<{ resultJson: string; beaconHash: string }>;
beaconRpcWait: (destHashHex: string, method: string, params?: unknown, timeoutMs?: number) => Promise<{ resultJson: string; isError: boolean }>;
blePeerCount: number;
updateDisplayName: (name: string) => Promise<void>;
isBeacon: boolean;
Expand Down Expand Up @@ -877,6 +878,7 @@ export function LxmfProvider({ children }: { readonly children: React.ReactNode
pairNusRNode: lxmf.pairNusRNode,
beaconRpc: lxmf.beaconRpc,
beaconBroadcastRpc: lxmf.beaconBroadcastRpc,
beaconRpcWait: lxmf.beaconRpcWait,
blePeerCount,
updateDisplayName: async (name: string) => {
const trimmed = name.trim();
Expand Down Expand Up @@ -909,7 +911,7 @@ export function LxmfProvider({ children }: { readonly children: React.ReactNode
lxmf.events, lxmf.error, lxmf.start, lxmf.stop,
lxmf.broadcast, lxmf.getStatus, lxmf.getBeacons,
lxmf.setLogLevel, lxmf.bleUnpairedRNodeCount,
lxmf.getNusUnpairedRNodes, lxmf.pairNusRNode, lxmf.beaconRpc, lxmf.beaconBroadcastRpc]);
lxmf.getNusUnpairedRNodes, lxmf.pairNusRNode, lxmf.beaconRpc, lxmf.beaconBroadcastRpc, lxmf.beaconRpcWait]);

return (
<LxmfCtx.Provider value={value}>
Expand Down
6 changes: 3 additions & 3 deletions mobile_app/context/NetworkModeContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export interface NetworkState {
const NetworkModeContext = createContext<NetworkState | undefined>(undefined);

export function NetworkModeProvider({ children }: { readonly children: ReactNode }) {
const { beacons, beaconBroadcastRpc, status, peers } = useLxmfContext();
const { beacons, beaconRpcWait, status, peers } = useLxmfContext();
const [internet, setInternet] = useState(true);

// Subscribe to OS-level connectivity — no polling, no HTTP spam.
Expand Down Expand Up @@ -107,9 +107,9 @@ export function NetworkModeProvider({ children }: { readonly children: ReactNode

const adapter = useMemo<IRpcAdapter>(() => {
if (mode === "online") return new DirectRpcAdapter(solanaConnection);
if (mode === "mesh") return new MeshRpcAdapter(meshHash, beaconBroadcastRpc);
if (mode === "mesh") return new MeshRpcAdapter(meshHash, beaconRpcWait);
return new IsolatedRpcAdapter();
}, [mode, meshHash, beaconBroadcastRpc]);
}, [mode, meshHash, beaconRpcWait]);

const value = useMemo<NetworkState>(
() => ({ mode, adapter, relayHash: adapter.relayHash }),
Expand Down
25 changes: 18 additions & 7 deletions mobile_app/src/infrastructure/network/MeshRpcAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,37 @@ import type { IRpcAdapter, ParsedTokenAccountsByOwner } from './types';

const MESH_RPC_TIMEOUT_MS = 30_000;

type BeaconBroadcastRpcFn = (
type BeaconRpcWaitFn = (
destHashHex: string,
method: string,
params?: unknown,
timeoutMs?: number,
) => Promise<{ resultJson: string; beaconHash: string }>;
) => Promise<{ resultJson: string; isError: boolean }>;

export class MeshRpcAdapter implements IRpcAdapter {
readonly mode = 'mesh' as const;
readonly relayHash: string;

private readonly beaconBroadcastRpc: BeaconBroadcastRpcFn;
private readonly beaconRpcWait: BeaconRpcWaitFn;

constructor(relayBeaconHash: string, beaconBroadcastRpc: BeaconBroadcastRpcFn) {
constructor(relayBeaconHash: string, beaconRpcWait: BeaconRpcWaitFn) {
this.relayHash = relayBeaconHash;
this.beaconBroadcastRpc = beaconBroadcastRpc;
this.beaconRpcWait = beaconRpcWait;
}

private async rpc<T>(method: string, params: unknown[]): Promise<T> {
const { resultJson } = await this.beaconBroadcastRpc(method, params, MESH_RPC_TIMEOUT_MS);
return JSON.parse(resultJson) as T;
const { resultJson, isError } = await this.beaconRpcWait(
this.relayHash,
method,
params,
MESH_RPC_TIMEOUT_MS,
);
const parsed = JSON.parse(resultJson) as unknown;
if (isError) {
const err = parsed as { code?: number; message?: string };
throw new Error(err.message ?? `RPC error (${err.code ?? -1})`);
}
return parsed as T;
}

async getBalance(pubkey: PublicKey): Promise<number> {
Expand Down
4 changes: 0 additions & 4 deletions mobile_app/src/services/sendTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ async function buildSplTransferTransaction({
mintAddress,
decimals,
programId,
rpcAdapter,
}: {
rpcAdapter: IRpcAdapter;
fromPubkey: PublicKey;
Expand All @@ -312,7 +311,6 @@ async function buildSplTransferTransaction({
mintAddress: string;
decimals: number;
programId?: string;
rpcAdapter: IRpcAdapter;
}): Promise<Transaction> {
// Bottom-line guard against any caller (including direct deep-links to
// /send/review with a tampered programId param) trying to build an SPL
Expand Down Expand Up @@ -476,7 +474,6 @@ export async function estimateSplTransferFeeLamports({
mintAddress,
decimals,
programId,
rpcAdapter,
});
const { blockhash } = await withTimeout(
rpcAdapter.getLatestBlockhash(),
Expand Down Expand Up @@ -546,7 +543,6 @@ export async function sendSplTransfer({
mintAddress,
decimals,
programId,
rpcAdapter,
});
return signAndSubmitTransaction({ walletAdapter, rpcAdapter, tx, expectedPubkey: fromPubkey });
}
Loading