Skip to content

Commit

Permalink
chore: kickoff LLD integration of wallet sync
Browse files Browse the repository at this point in the history
  • Loading branch information
gre committed Jul 9, 2024
1 parent 8d04ece commit a00f558
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 132 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from "react";
import { useWatchWalletSync } from "../hooks/useWatchWalletSync";

export default function WalletSyncProvider({ children }: { children: React.ReactNode }) {
// TODO if we want to expose to the UI the watching state / errors etc.. we could export it with a context from here.
useWatchWalletSync();
return children;
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function useDestroyTrustchain() {
onSuccess: () => {
dispatch(setFlow({ flow: Flow.ManageBackup, step: Step.BackupDeleted }));
dispatch(resetTrustchainStore());
// TODO also delete the wallet sync data
},
onError: () => dispatch(setFlow({ flow: Flow.ManageBackup, step: Step.BackupDeletionError })),
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import { getEnv } from "@ledgerhq/live-env";
import { getSdk } from "@ledgerhq/trustchain/index";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import Transport from "@ledgerhq/hw-transport";
import { trustchainLifecycle } from "@ledgerhq/live-wallet/walletsync";
import { useStore } from "react-redux";
import { walletSelector } from "~/renderer/reducers/wallet";

export function runWithDevice<T>(
deviceId: string | undefined,
Expand All @@ -28,7 +31,11 @@ export function useTrustchainSdk() {
const name = `${platformMap[platform] || platform}${hash ? " " + hash : ""}`;
return { applicationId, name };
}, []);
const sdk = getSdk(isMockEnv, defaultContext);
const store = useStore();
const lifecycle = trustchainLifecycle({
getCurrentWSState: () => walletSelector(store.getState()).wsState,
});
const sdk = getSdk(isMockEnv, defaultContext, lifecycle);

return sdk;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { useCallback, useEffect, useMemo } from "react";
import { CloudSyncSDK, UpdateEvent } from "@ledgerhq/live-wallet/cloudsync/index";
import walletsync, {
liveSlug,
DistantState,
walletSyncWatchLoop,
LocalState,
} from "@ledgerhq/live-wallet/walletsync/index";
import { getAccountBridge } from "@ledgerhq/live-common/bridge/index";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { useSelector, useStore } from "react-redux";
import { walletSelector } from "~/renderer/reducers/wallet";
import { Trustchain } from "@ledgerhq/trustchain/types";
import {
memberCredentialsSelector,
trustchainSelector,
setTrustchain,
} from "@ledgerhq/trustchain/store";
import { TrustchainEjected } from "@ledgerhq/trustchain/errors";
import { State } from "~/renderer/reducers";
import { cache as bridgeCache } from "~/renderer/bridge/cache";

function localStateSelector(state: State): LocalState {
return {
accounts: {
list: state.accounts,
},
accountNames: state.wallet.accountNames,
};
}

function latestDistantStateSelector(state: State): DistantState | null {
return walletSelector(state).wsState.data;
}

export function useWatchWalletSync() {
const memberCredentials = useSelector(memberCredentialsSelector);
const trustchain = useSelector(trustchainSelector);

const trustchainSdk = useTrustchainSdk();

const store = useStore();

const getCurrentVersion = useCallback(() => {
const state = walletSelector(store.getState());
return state.wsState.version;
}, [store]);

const onTrustchainRefreshNeeded = useCallback(
async (trustchain: Trustchain) => {
try {
const newTrustchain = await trustchainSdk.restoreTrustchain(trustchain, memberCredentials);
setTrustchain(newTrustchain);
} catch (e) {
if (e instanceof TrustchainEjected) {
// TODO: eject the trustchain
// dispatch(resetTrustchainStore());
}
}
},
[trustchainSdk, memberCredentials],
);

const saveNewUpdate = useCallback(
async (event: UpdateEvent<DistantState>) => {
switch (event.type) {
case "new-data": {
const state = store.getState();
const version = event.version;

Check failure on line 69 in apps/ledger-live-desktop/src/newArch/WalletSync/hooks/useWatchWalletSync.ts

View check run for this annotation

live-github-bot / @Desktop • Test App

@typescript-eslint/no-unused-vars

'version' is assigned a value but never used.

Check failure on line 69 in apps/ledger-live-desktop/src/newArch/WalletSync/hooks/useWatchWalletSync.ts

View check run for this annotation

live-github-bot / @Desktop • Test App

@typescript-eslint/no-unused-vars

'version' is assigned a value but never used.
const data = event.data;
const wsState = walletSelector(state).wsState;
const localState = localStateSelector(state);
const ctx = { getAccountBridge, bridgeCache, blacklistedTokenIds: [] };

console.log("<- incoming data to resolve", data);
const resolved = await walletsync.resolveIncomingDistantState(
ctx,
localState,
wsState.data,
data,
);

if (resolved.hasChanges) {
console.log("resolved as", resolved);

// TODO we need to implement this, in the context of LLD. the important part is to try to make it one atomic update for all the states
/* setState(s => {
const localState = localStateSelector(s);
const newLocalState = walletsync.applyUpdate(localState, resolved.update);
console.log("new update applied as", newLocalState);
// we now need to "reverse" the localStateSelector back into our own internal state
let walletState = s.walletState;
walletState = walletH.BULK_SET_ACCOUNT_NAMES(
walletState,
setAccountNames(newLocalState.accountNames),
);
walletState = walletH.WALLET_SYNC_UPDATE(
walletState,
walletSyncUpdate(data, version),
);
return {
accounts: newLocalState.accounts.list, // save new accounts
walletState,
};
});
*/
} else {
console.log("resolved. no changes to apply.");
}
break;
}
case "pushed-data": {
// when we push the state, we also need to implement the update on the local state
// TODO implement this in context of LLD
/*
setState(s => ({
...s,
walletState: walletH.WALLET_SYNC_UPDATE(
s.walletState,
walletSyncUpdate(event.data, event.version),
),
}));
*/
break;
}
case "deleted-data": {
console.log("deleted data");
// TODO implement this in context of LLD
/*
setState(s => ({
...s,
walletState: walletH.WALLET_SYNC_UPDATE(s.walletState, walletSyncUpdate(null, 0)),
}));
*/
break;
}
}
},
[store],
);

const walletSyncSdk = useMemo(
() =>
new CloudSyncSDK({
slug: liveSlug,
schema: walletsync.schema,
trustchainSdk,
getCurrentVersion,
saveNewUpdate,
onTrustchainRefreshNeeded,
}),
[trustchainSdk, getCurrentVersion, saveNewUpdate, onTrustchainRefreshNeeded],
);

// const [visualPending, setVisualPending] = useState(true);

// pull and push wallet sync loop
useEffect(() => {
const setVisualPending = () => {}; // NOT IMPLEMENTED. idk if we need it in the UI

if (!trustchain || !memberCredentials) {
return;
}

const { unsubscribe } = walletSyncWatchLoop({
walletSyncSdk,
trustchain,
memberCredentials,
setVisualPending,
getState: () => store.getState(),
localStateSelector,
latestDistantStateSelector,
});

return unsubscribe;
}, [store, trustchainSdk, walletSyncSdk, trustchain, memberCredentials]);

// return { visualPending };
}
Loading

0 comments on commit a00f558

Please sign in to comment.