-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Updated lit signature logic #331
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThis pull request applies two main sets of changes. In the Invoice Dashboard component, the modifications focus on reformatting and restructuring code for improved clarity and consistency. In the Single Invoice component, the decryption logic is streamlined by simplifying control flow in the Changes
Sequence Diagram(s)sequenceDiagram
participant UI as User Interface
participant SI as SingleInvoice Component
participant LS as Local Storage
participant DS as Decryption Service
UI->>SI: Trigger ensureDecryption
SI->>SI: Check if account and cipherProvider exist
alt Missing account/cipherProvider
SI-->>UI: Early return
else
SI->>LS: Retrieve walletSignature & sessionKey
alt Signatures found
SI->>DS: Attempt to enable decryption
alt Decryption successful
DS-->>SI: Decryption enabled
else Decryption fails
SI->>LS: Clear walletSignature/sessionKey
SI-->>UI: Return decryption failure
end
else No signatures
SI-->>UI: Return without decryption
end
end
Assessment against linked issues
Possibly related PRs
Suggested reviewers
Tip 🌐 Web search-backed reviews and chat
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🔭 Outside diff range comments (1)
packages/single-invoice/src/lib/single-invoice.svelte (1)
420-435
: Fix potential race condition in account assignment.The account assignment after the early return could be stale if the wallet state changes between the check and the assignment.
Apply this diff to fix the race condition:
const handleWalletConnection = async () => { - if (!account?.address) return; + const currentAccount = getAccount(wagmiConfig); + if (!currentAccount?.address) return; - account = getAccount(wagmiConfig); + account = currentAccount; if (isDecryptionEnabled && requestId) { const isEncrypted = await isRequestEncrypted(requestId); if (isEncrypted) { await ensureDecryption(); } } if (requestId && requestNetwork) { await getOneRequest(requestId); } };
🧹 Nitpick comments (3)
packages/single-invoice/src/lib/single-invoice.svelte (2)
437-453
: Improve cleanup atomicity in wallet disconnection.The cleanup of local storage items should be atomic to prevent inconsistent states.
Apply this diff to improve the cleanup process:
const handleWalletDisconnection = () => { + // First, clean up decryption state to prevent any ongoing operations + if (cipherProvider) { + cipherProvider.disconnectWallet(); + // Clean up all storage items atomically + const storageItems = [ + 'lit-wallet-sig', + 'lit-session-key', + 'isDecryptionEnabled' + ]; + storageItems.forEach(item => { + if (item === 'isDecryptionEnabled') { + localStorage.setItem(item, 'false'); + } else { + localStorage.removeItem(item); + } + }); + } + + // Then reset all state variables account = undefined; address = undefined; request = undefined; requestData = null; signer = null; approved = false; isPayee = false; - - // Clean up decryption state - if (cipherProvider) { - cipherProvider.disconnectWallet(); - localStorage.removeItem("lit-wallet-sig"); - localStorage.removeItem("lit-session-key"); - localStorage.setItem("isDecryptionEnabled", "false"); - } };
812-821
: Address the FIXME comment by implementing proper rounding.The current implementation truncates decimal numbers without rounding, which could lead to precision loss.
Would you like me to generate an implementation that properly rounds decimal numbers? Here's a suggested implementation:
-// FIXME: Add rounding functionality function truncateNumberString( value: string, maxDecimalDigits: number ): string { const [integerPart, decimalPart] = value.split("."); - return decimalPart - ? `${integerPart}.${decimalPart.substring(0, maxDecimalDigits)}` - : value; + if (!decimalPart) return value; + + const roundedDecimal = Number(`0.${decimalPart}`) + .toFixed(maxDecimalDigits); + + // Remove leading "0." from the rounded result + return `${integerPart}.${roundedDecimal.substring(2)}`; }packages/invoice-dashboard/src/lib/view-requests.svelte (1)
501-564
: Improve error handling inloadRequests
.The function could benefit from more robust error handling and cleanup in failure cases.
Apply this diff to improve error handling:
const loadRequests = async ( sliderValue: string, currentAccount: GetAccountReturnType | undefined, currentRequestNetwork: RequestNetwork | undefined | null ) => { if (!currentAccount?.address || !currentRequestNetwork || !cipherProvider) return; loading = true; const previousNetworks = [...selectedNetworks]; try { if (sliderValue === "on") { if (localStorage?.getItem("isDecryptionEnabled") === "false") { queryClient.invalidateQueries(); } try { const signer = await getEthersSigner(wagmiConfig); if (signer && currentAccount?.address) { loadSessionSignatures = localStorage?.getItem("lit-wallet-sig") === null; const signatures = await cipherProvider?.getSessionSignatures( signer, currentAccount.address, window.location.host, "Sign in to Lit Protocol through Request Network" ); // Save both signatures localStorage?.setItem( "lit-wallet-sig", JSON.stringify({ address: currentAccount.address, timestamp: Date.now(), sig: signatures.walletSig, }) ); localStorage?.setItem("lit-session-key", signatures.sessionKey); cipherProvider?.enableDecryption(true); localStorage?.setItem("isDecryptionEnabled", JSON.stringify(true)); } } catch (error) { console.error("Failed to enable decryption:", error); toast.error("Failed to enable decryption."); + // Clean up any partial state + localStorage?.removeItem("lit-wallet-sig"); + localStorage?.removeItem("lit-session-key"); + localStorage?.setItem("isDecryptionEnabled", "false"); return; } finally { loadSessionSignatures = false; } } else { if (localStorage?.getItem("isDecryptionEnabled") === "true") { queryClient.invalidateQueries(); } cipherProvider?.enableDecryption(false); localStorage?.setItem("isDecryptionEnabled", JSON.stringify(false)); } await getRequests(currentAccount, currentRequestNetwork); selectedNetworks = previousNetworks; // Restore selection } catch (error) { + console.error("Failed to load requests:", error); + toast.error("Failed to load requests. Please try again."); + // Restore previous state + selectedNetworks = previousNetworks; } finally { loading = false; } - await getRequests(currentAccount, currentRequestNetwork); - loading = false; };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.json
is excluded by!**/package-lock.json
📒 Files selected for processing (2)
packages/invoice-dashboard/src/lib/view-requests.svelte
(5 hunks)packages/single-invoice/src/lib/single-invoice.svelte
(3 hunks)
🔇 Additional comments (1)
packages/invoice-dashboard/src/lib/view-requests.svelte (1)
197-226
: LGTM! Code formatting improvements enhance readability.The reformatting of these functions improves code readability while maintaining the same functionality.
const ensureDecryption = async () => { | ||
if (!isDecryptionEnabled || !cipherProvider || !account?.address) { | ||
return false; | ||
} | ||
|
||
try { | ||
// First check if the request is actually encrypted | ||
const encrypted = await isRequestEncrypted(requestId); | ||
if (!encrypted) { | ||
console.log("Request is not encrypted, skipping decryption setup"); | ||
return true; | ||
} | ||
|
||
console.log("Request is encrypted, setting up decryption"); | ||
const signer = await getEthersSigner(wagmiConfig); | ||
if (!signer) return false; | ||
|
||
// Check if we have a valid session first | ||
const hasExistingSession = | ||
localStorage.getItem("lit-wallet-sig") === "true"; | ||
|
||
if (hasExistingSession) { | ||
// Try to use existing session | ||
try { | ||
cipherProvider.enableDecryption(true); | ||
// Test if current session works with a request fetch | ||
const testRequest = await requestNetwork?.fromRequestId(requestId); | ||
|
||
// Only consider the session valid if we can actually decrypt the request | ||
if (testRequest?.getData()) { | ||
console.log("Using existing Lit Protocol session"); | ||
return true; | ||
} | ||
} catch (error) { | ||
// If we get a decryption error, we need a new session | ||
if ( | ||
String(error).includes("Decryption is not available") || | ||
String(error).includes("Failed to decrypt") || | ||
String(error).includes("LitNodeClient is not ready") | ||
) { | ||
console.log("Existing session invalid, clearing..."); | ||
localStorage.removeItem("lit-wallet-sig"); | ||
} else { | ||
// If it's some other error, keep the session | ||
console.log("Error fetching request, but keeping session:", error); | ||
return true; | ||
} | ||
} | ||
} | ||
if (!account?.address || !cipherProvider) return; | ||
|
||
// If we get here, we need a new session | ||
console.log("Getting new Lit Protocol session"); | ||
loadSessionSignatures = true; | ||
const walletSig = localStorage.getItem("lit-wallet-sig"); | ||
const sessionKey = localStorage.getItem("lit-session-key"); | ||
const isEnabled = localStorage.getItem("isDecryptionEnabled") === "true"; | ||
|
||
if (walletSig && sessionKey && isEnabled) { | ||
try { | ||
await cipherProvider.getSessionSignatures( | ||
signer, | ||
account.address, | ||
window.location.host, | ||
"Sign in to Lit Protocol through Request Network" | ||
); | ||
|
||
localStorage.setItem("lit-wallet-sig", "true"); | ||
// Use existing signatures | ||
cipherProvider.enableDecryption(true); | ||
return true; | ||
} catch (error) { | ||
console.error("Failed to get new session signatures:", error); | ||
return false; | ||
} finally { | ||
loadSessionSignatures = false; | ||
console.error( | ||
"Failed to enable decryption with existing signatures:", | ||
error | ||
); | ||
// Clear invalid signatures | ||
localStorage.removeItem("lit-wallet-sig"); | ||
localStorage.removeItem("lit-session-key"); | ||
localStorage.setItem("isDecryptionEnabled", "false"); | ||
} | ||
} catch (error) { | ||
console.error("Failed to ensure decryption:", error); | ||
return false; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve error handling in ensureDecryption
.
The function silently fails when the account address or cipher provider is missing. Consider:
- Returning a boolean to indicate success/failure
- Adding error logging for debugging
Apply this diff to improve error handling:
const ensureDecryption = async () => {
- if (!account?.address || !cipherProvider) return;
+ if (!account?.address || !cipherProvider) {
+ console.warn('Cannot ensure decryption: missing account address or cipher provider');
+ return false;
+ }
const walletSig = localStorage.getItem("lit-wallet-sig");
const sessionKey = localStorage.getItem("lit-session-key");
const isEnabled = localStorage.getItem("isDecryptionEnabled") === "true";
if (walletSig && sessionKey && isEnabled) {
try {
// Use existing signatures
cipherProvider.enableDecryption(true);
+ return true;
} catch (error) {
console.error(
"Failed to enable decryption with existing signatures:",
error
);
// Clear invalid signatures
localStorage.removeItem("lit-wallet-sig");
localStorage.removeItem("lit-session-key");
localStorage.setItem("isDecryptionEnabled", "false");
+ return false;
}
}
+ return false;
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const ensureDecryption = async () => { | |
if (!isDecryptionEnabled || !cipherProvider || !account?.address) { | |
return false; | |
} | |
try { | |
// First check if the request is actually encrypted | |
const encrypted = await isRequestEncrypted(requestId); | |
if (!encrypted) { | |
console.log("Request is not encrypted, skipping decryption setup"); | |
return true; | |
} | |
console.log("Request is encrypted, setting up decryption"); | |
const signer = await getEthersSigner(wagmiConfig); | |
if (!signer) return false; | |
// Check if we have a valid session first | |
const hasExistingSession = | |
localStorage.getItem("lit-wallet-sig") === "true"; | |
if (hasExistingSession) { | |
// Try to use existing session | |
try { | |
cipherProvider.enableDecryption(true); | |
// Test if current session works with a request fetch | |
const testRequest = await requestNetwork?.fromRequestId(requestId); | |
// Only consider the session valid if we can actually decrypt the request | |
if (testRequest?.getData()) { | |
console.log("Using existing Lit Protocol session"); | |
return true; | |
} | |
} catch (error) { | |
// If we get a decryption error, we need a new session | |
if ( | |
String(error).includes("Decryption is not available") || | |
String(error).includes("Failed to decrypt") || | |
String(error).includes("LitNodeClient is not ready") | |
) { | |
console.log("Existing session invalid, clearing..."); | |
localStorage.removeItem("lit-wallet-sig"); | |
} else { | |
// If it's some other error, keep the session | |
console.log("Error fetching request, but keeping session:", error); | |
return true; | |
} | |
} | |
} | |
if (!account?.address || !cipherProvider) return; | |
// If we get here, we need a new session | |
console.log("Getting new Lit Protocol session"); | |
loadSessionSignatures = true; | |
const walletSig = localStorage.getItem("lit-wallet-sig"); | |
const sessionKey = localStorage.getItem("lit-session-key"); | |
const isEnabled = localStorage.getItem("isDecryptionEnabled") === "true"; | |
if (walletSig && sessionKey && isEnabled) { | |
try { | |
await cipherProvider.getSessionSignatures( | |
signer, | |
account.address, | |
window.location.host, | |
"Sign in to Lit Protocol through Request Network" | |
); | |
localStorage.setItem("lit-wallet-sig", "true"); | |
// Use existing signatures | |
cipherProvider.enableDecryption(true); | |
return true; | |
} catch (error) { | |
console.error("Failed to get new session signatures:", error); | |
return false; | |
} finally { | |
loadSessionSignatures = false; | |
console.error( | |
"Failed to enable decryption with existing signatures:", | |
error | |
); | |
// Clear invalid signatures | |
localStorage.removeItem("lit-wallet-sig"); | |
localStorage.removeItem("lit-session-key"); | |
localStorage.setItem("isDecryptionEnabled", "false"); | |
} | |
} catch (error) { | |
console.error("Failed to ensure decryption:", error); | |
return false; | |
} | |
}; | |
const ensureDecryption = async () => { | |
if (!account?.address || !cipherProvider) { | |
console.warn('Cannot ensure decryption: missing account address or cipher provider'); | |
return false; | |
} | |
const walletSig = localStorage.getItem("lit-wallet-sig"); | |
const sessionKey = localStorage.getItem("lit-session-key"); | |
const isEnabled = localStorage.getItem("isDecryptionEnabled") === "true"; | |
if (walletSig && sessionKey && isEnabled) { | |
try { | |
// Use existing signatures | |
cipherProvider.enableDecryption(true); | |
return true; | |
} catch (error) { | |
console.error( | |
"Failed to enable decryption with existing signatures:", | |
error | |
); | |
// Clear invalid signatures | |
localStorage.removeItem("lit-wallet-sig"); | |
localStorage.removeItem("lit-session-key"); | |
localStorage.setItem("isDecryptionEnabled", "false"); | |
return false; | |
} | |
} | |
return false; | |
}; |
Fixes: #319
Fixes: #299
Problem
The Invoice Dashboard experiences issues with Lit Protocol sign-in when users switch accounts. Specifically, the sign-in process sometimes enters an infinite loop, preventing successful authentication and access.
Changes
To-do:
Summary by CodeRabbit