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
2 changes: 1 addition & 1 deletion src/domains/chains/components/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type WalletContextType = {
isConnected: boolean,
disconnect: () => Promise<void>,
address?: Address,
privateKey: string | undefined,
privateKey: Address | undefined,
};

const WalletContext = createContext<WalletContextType | undefined>(undefined);
Expand Down
28 changes: 18 additions & 10 deletions src/domains/shielder/stores/getShielderIndexedDB.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ShielderTransaction } from '@cardinal-cryptography/shielder-sdk';
import { openDB, IDBPDatabase } from 'idb';
import { Address, sha256 } from 'viem';
import { z } from 'zod';

const DB_NAME = 'SHIELDER_STORAGE';
Expand All @@ -8,7 +9,7 @@ const DB_VERSION = 2;
const STORE_CLIENTS = 'clients';
const STORE_TRANSACTIONS = 'transactions';

type ShielderClientData = Record<string, string>;
type ShielderClientData = Record<string, Record<string, string>>;

const transactionSchema = z.object({
type: z.enum(['NewAccount', 'Deposit', 'Withdraw']),
Expand Down Expand Up @@ -68,27 +69,34 @@ const initDB = async (): Promise<IDBPDatabase<DBSchema>> => {
});
};

export const getShielderIndexedDB = (chainId: number) => {
const key = chainId.toString();
export const getShielderIndexedDB = (chainId: number, privateKey: Address) => {
const chainKey = chainId.toString();
const hashedPrivateKey = sha256(privateKey);
const initDbPromise = initDB();

return {
getItem: async (itemKey: string): Promise<string | null> => {
const db = await initDbPromise;
const clientData = (await db.get(STORE_CLIENTS, key)) ?? {};
return clientData[itemKey] ?? null;
const allDataForAddress = await db.get(STORE_CLIENTS, hashedPrivateKey);
const chainData = allDataForAddress?.[chainKey];
return chainData?.[itemKey] ?? null;
},

setItem: async (itemKey: string, value: string): Promise<void> => {
const db = await initDbPromise;
const existingData = (await db.get(STORE_CLIENTS, key)) ?? {};
const allDataForAddress = (await db.get(STORE_CLIENTS, hashedPrivateKey)) ?? {};
const existingChainData = allDataForAddress[chainKey] ?? {};

const updatedData = {
...existingData,
const updatedChainData = {
...existingChainData,
[itemKey]: value,
};

await db.put(STORE_CLIENTS, updatedData, key);
const updatedAllData = {
...allDataForAddress,
[chainKey]: updatedChainData,
};

await db.put(STORE_CLIENTS, updatedAllData, hashedPrivateKey);
},
};
};
Expand Down
22 changes: 10 additions & 12 deletions src/domains/shielder/utils/useShielderClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,44 +10,42 @@ import useChain from 'src/domains/chains/utils/useChain';
import getQueryKey from 'src/domains/misc/utils/getQueryKey';
import { getShielderIndexedDB } from 'src/domains/shielder/stores/getShielderIndexedDB';
import { getTransactionsIndexedDB } from 'src/domains/shielder/stores/getShielderIndexedDB';
import { useShielderStore } from 'src/domains/shielder/stores/shielder';
import { useWasm } from 'src/domains/shielder/utils/WasmProvider';

const useShielderClient = () => {
const chainConfig = useChain();
const { wasmCryptoClient, wasmLoaded } = useWasm();

const publicClient = usePublicClient({ chainId: chainConfig?.id });
const { address: account } = useWallet();
const { shielderPrivateKey } = useShielderStore(account);
const { address: accountAddress, privateKey } = useWallet();

const isQueryDisabled =
!publicClient || !chainConfig || !wasmLoaded || !account || !wasmCryptoClient || !shielderPrivateKey;
!publicClient || !chainConfig || !wasmLoaded || !accountAddress || !wasmCryptoClient || !privateKey;

return useQuery({
queryKey: chainConfig && shielderPrivateKey ? getQueryKey.shielderClient(chainConfig.id, shielderPrivateKey) : [],
queryKey: chainConfig && privateKey ? getQueryKey.shielderClient(chainConfig.id, privateKey) : [],
staleTime: Infinity,
retry: false,
queryFn: isQueryDisabled ? skipToken : async () => {
const { shielderConfig, id } = chainConfig;
const { shielderConfig, id: chainId } = chainConfig;

if (!shielderConfig) {
throw new Error('Shielder config is not available');
}

const storage = getTransactionsIndexedDB(account);
const transactionsStorage = getTransactionsIndexedDB(accountAddress);
const shielderStorage = getShielderIndexedDB(chainId, privateKey);

const client = createShielderClient({
shielderSeedPrivateKey: shielderPrivateKey,
chainId: BigInt(id),
shielderSeedPrivateKey: privateKey,
chainId: BigInt(chainId),
publicClient,
contractAddress: shielderConfig.shielderContractAddress,
relayerUrl: shielderConfig.relayerUrl,
storage: getShielderIndexedDB(id),
storage: shielderStorage,
cryptoClient: wasmCryptoClient,
callbacks: {
onNewTransaction: async (tx: ShielderTransaction) => {
await storage.addItem(
await transactionsStorage.addItem(
chainConfig.id,
tx
);
Expand Down