Revert (Recovery)
Recover funds from a failed or stuck deposit
Revert (Recovery)
Section titled “Revert (Recovery)”If a deposit transaction succeeds on-chain but fails to be indexed, you can revert it to recover your funds. This is a safety mechanism for edge cases.
When to Use Revert
Section titled “When to Use Revert”Revert is needed when:
- Deposit transaction confirmed but not indexed
- Indexer missed your deposit
- Network issues prevented indexing
Revert is NOT needed when:
- Transaction failed (funds never left your wallet)
- You successfully withdrew (nullifier spent)
- Deposit is indexed but you haven’t withdrawn yet
How Revert Works
Section titled “How Revert Works”- You prove you made the original deposit
- You prove the nullifier hasn’t been spent
- Program returns your funds minus fees
Step-by-Step Guide
Section titled “Step-by-Step Guide”-
Check Deposit Status
First, verify your deposit wasn’t indexed:
async function checkDepositIndexed(mint: string,commitment: Uint8Array,network: string = 'mainnet'): Promise<boolean> {// Try to get the leaf index for your commitment// If not found, deposit wasn't indexedtry {const response = await fetch(`${API_BASE}/get_merkle/${mint}/32/${network}`,{ method: 'POST' });const data = await response.json();// Search for commitment in tree// Implementation depends on indexer APIreturn commitmentExistsInTree(data, commitment);} catch {return false;}} -
Check Nullifier Not Spent
Ensure you haven’t already withdrawn:
const nullifierHash = poseidon([nullifier]);const isSpent = await isNullifierSpent(mint, nullifierHash, network);if (isSpent) {throw new Error('Already withdrawn - cannot revert');} -
Sign Revert Message
Create and sign the revert authorization:
async function signRevertMessage(wallet: { publicKey: PublicKey; signMessage: Function },txSignature: string): Promise<{ signature: string; message: string }> {const message = `Revert deposit: ${txSignature}`;const messageBytes = new TextEncoder().encode(message);const signatureBytes = await wallet.signMessage(messageBytes);const signature = bs58.encode(signatureBytes);return { signature, message };} -
Call Revert Endpoint
interface RevertRequest {wallet: string;signature: string;message: string;}async function revertDeposit(authToken: string,txSignature: string,wallet: string,signature: string,message: string,network: string = 'mainnet'): Promise<string> {const response = await fetch(`${API_BASE}/revert/${network}/${authToken}/${txSignature}`,{method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({wallet,signature,message,}),});if (!response.ok) {const error = await response.text();throw new Error(`Revert failed: ${error}`);}return response.text(); // Returns tx signature}
Complete Example
Section titled “Complete Example”async function performRevert( deposit: DepositSecrets, originalTxSignature: string, wallet: { publicKey: PublicKey; signMessage: Function }, authToken: string, network: string = 'mainnet'): Promise<string> { // 1. Verify deposit wasn't indexed const isIndexed = await checkDepositIndexed( deposit.mint, deposit.commitment, network );
if (isIndexed) { throw new Error('Deposit is indexed - use normal withdraw'); }
// 2. Verify not already spent const nullifierHash = poseidon([deposit.nullifier]); const isSpent = await isNullifierSpent(deposit.mint, nullifierHash, network);
if (isSpent) { throw new Error('Already withdrawn'); }
// 3. Sign revert message const { signature, message } = await signRevertMessage( wallet, originalTxSignature );
// 4. Call revert const revertTxSig = await revertDeposit( authToken, originalTxSignature, wallet.publicKey.toBase58(), signature, message, network );
// 5. Clean up local storage deleteDepositRecord(originalTxSignature);
return revertTxSig;}Revert returns your deposit minus fees:
| Fee | Amount |
|---|---|
| Revert Fee | Same as deposit fee |
You receive: originalDeposit - revertFee
Error Handling
Section titled “Error Handling”| Error | Cause | Solution |
|---|---|---|
DepositNotFound | Tx doesn’t exist | Check transaction signature |
AlreadyIndexed | Deposit was indexed | Use normal withdraw |
NullifierSpent | Already withdrawn | No action needed |
InvalidSignature | Wrong wallet | Sign with depositing wallet |
NotDepositor | Wallet didn’t make deposit | Can only revert own deposits |
Important Considerations
Section titled “Important Considerations”Privacy Impact
Section titled “Privacy Impact”Revert breaks privacy for that specific deposit:
- On-chain link between your wallet and the deposit
- Anyone can see you made that deposit and reverted it
Time Limits
Section titled “Time Limits”Revert may have time limits:
- Must be done before the deposit is indexed
- Once indexed, use normal withdrawal
Wallet Requirement
Section titled “Wallet Requirement”You must sign with the same wallet that made the original deposit. The program verifies ownership.
Diagnostic Checklist
Section titled “Diagnostic Checklist”Before reverting, check:
- Transaction confirmed on-chain?
- Deposit not in Merkle tree?
- Nullifier not spent?
- Have original transaction signature?
- Have access to depositing wallet?
Next Steps
Section titled “Next Steps”- Address Lookup Tables - Transaction optimization
- Error Reference - Full error codes