Skip to content
Open
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
3 changes: 3 additions & 0 deletions apps/wallet/src/lib/eerc.shield.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const eercMocks = vi.hoisted(() => {
const withdraw = vi.fn();
const transfer = vi.fn();
const calculateTotalBalance = vi.fn();
const generateDecryptionKey = vi.fn(async () => `0x${"a".repeat(64)}`);

class MockEERC {
client = publicClient;
Expand All @@ -29,13 +30,15 @@ const eercMocks = vi.hoisted(() => {
withdraw = withdraw;
transfer = transfer;
calculateTotalBalance = calculateTotalBalance;
generateDecryptionKey = generateDecryptionKey;
}

return {
MockEERC,
calculateTotalBalance,
deposit,
fetchPublicKey,
generateDecryptionKey,
publicClient,
register,
transfer,
Expand Down
13 changes: 12 additions & 1 deletion apps/wallet/src/lib/eerc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export async function createEerc(account: BenzoAccount): Promise<EERC | null> {
if (!ENCRYPTED_ERC_ADDRESS || !REGISTRAR_ADDRESS) return null;
const EERCClass = await loadEERC();
const { publicClient, walletClient } = createViemClients(account);
return new EERCClass(
const eerc = new EERCClass(
publicClient,
walletClient,
ENCRYPTED_ERC_ADDRESS,
Expand All @@ -132,6 +132,17 @@ export async function createEerc(account: BenzoAccount): Promise<EERC | null> {
EERC_CIRCUIT_URLS,
account.eercDecryptionKey,
);
// The eERC SDK does NOT use the `decryptionKey` we pass to the constructor for
// anything that touches chain state: register() derives its OWN key via
// generateDecryptionKey() (a deterministic wallet signature) and binds the
// on-chain public key + ElGamal-encrypted balance to THAT key. If we then
// decrypt with our own `account.eercDecryptionKey`, calculateTotalBalance()'s
// eGCT verify fails and every private balance reads $0. So let the SDK derive
// and install its own key (and matching publicKey) up front — the signature is
// local (self-custody key) and deterministic, so it's stable across sessions
// and matches whatever key registration used.
await eerc.generateDecryptionKey();
return eerc;
}

function eercPublicClient(eerc: EERC): PublicClient {
Expand Down
Loading