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
182 changes: 182 additions & 0 deletions examples/swap-board-ml-btc/HTLC_FLOW_FIX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# HTLC Creation Flow Fix - ML/BTC Atomic Swaps

## Problem Summary

The original implementation assumed that ML HTLC must always be created first, which blocked the flow where the creator offers BTC and needs to create a BTC HTLC as the first HTLC in the atomic swap.

### Original Issues:
1. **BTC HTLC creation always required ML HTLC to exist** - This prevented creator from offering BTC first
2. **Secret hash was not saved to database** - Required blockchain API calls to extract secret hash every time
3. **No distinction between first and second HTLC creation** - Code didn't handle different flows properly

## Solution Overview

The fix implements proper handling for both HTLC creation orders:

### Scenario A: Creator offers ML, Taker offers BTC
1. Creator creates **ML HTLC** (FIRST) → Secret hash generated by wallet, extracted and saved
2. Taker creates **BTC HTLC** (SECOND) → Uses saved secret hash from ML HTLC
3. Creator claims BTC HTLC (reveals secret)
4. Taker claims ML HTLC (using revealed secret)

### Scenario B: Creator offers BTC, Taker offers ML
1. Creator creates **BTC HTLC** (FIRST) → Secret hash generated by wallet, returned and saved
2. Taker creates **ML HTLC** (SECOND) → Uses saved secret hash from BTC HTLC
3. Taker claims BTC HTLC (reveals secret)
4. Creator claims ML HTLC (using revealed secret)

## Changes Made

### 1. Fixed `createBTCHTLC()` Function

**Key Changes:**
- Detects if BTC HTLC is first or second in the swap flow
- Handles secret hash generation (first HTLC) vs extraction (second HTLC)
- Saves secret hash from BTC wallet response when BTC is first HTLC
- Uses saved secret hash when available (optimization)

### 2. Fixed `validateSwapForBTCHTLC()` Function

**Key Changes:**
- Removed `secretHash` validation requirement
- Added comment explaining why: wallet generates secret hash for first HTLC
- Secret hash validation now happens in the calling function for second HTLC only

**Logic Flow:**
```javascript
// Determine HTLC order
const isUserCreator = swap.offer.creatorMLAddress === userAddress
const creatorOfferedBTC = isCreatorOfferingBTC(swap.offer)
const isBTCFirstHTLC = isUserCreator && creatorOfferedBTC
const isBTCSecondHTLC = !isUserCreator && !creatorOfferedBTC

if (isBTCFirstHTLC) {
// Use placeholder - wallet generates secret hash
secretHashHex = '0000000000000000000000000000000000000000'
// Wallet returns: { htlcAddress, secretHashHex, transactionId, signedTxHex, redeemScript }
// Save response.secretHashHex to database
} else if (isBTCSecondHTLC) {
// Extract from existing ML HTLC (use saved or fetch from blockchain)
secretHashHex = swap.secretHash || extractFromBlockchain()
}
```

### 3. Updated `createHtlc()` Function (ML HTLC)

**Key Changes:**
- Extracts secret hash from broadcasted ML HTLC transaction
- Saves secret hash to database for later use
- Includes 2-second delay to allow transaction indexing

**Logic Flow:**
```javascript
// Create and broadcast ML HTLC
const signedTxHex = await client.createHtlc(htlcParams)
const broadcastResult = await client.broadcastTx(signedTxHex)
const txId = broadcastResult.tx_id

// Wait for indexing and extract secret hash
await new Promise(resolve => setTimeout(resolve, 2000))
const txData = await fetch(`${apiServer}/transaction/${txId}`)
const secretHashHex = extractSecretHashFromTxData(txData)

// Save with secret hash
await updateSwap({ creatorHtlcTxHash: txId, secretHash: secretHashHex })
```

### 4. Updated `createCounterpartyHtlc()` Function

**Key Changes:**
- Checks for both ML and BTC creator HTLCs
- Prioritizes using saved secret hash (faster, no API call)
- Falls back to blockchain extraction if secret hash not saved
- Handles case where creator created BTC HTLC first

**Logic Flow:**
```javascript
let secretHashHex: string

if (swap.secretHash) {
// Use saved secret hash (fast path)
secretHashHex = swap.secretHash
} else if (swap.creatorHtlcTxHash) {
// Extract from ML HTLC on blockchain (fallback)
secretHashHex = extractFromMLHTLC()
} else {
// Creator created BTC HTLC first but secret hash not saved
throw new Error('Secret hash not found')
}
```

## Database Schema

The `secretHash` field already exists in the Swap model:

```prisma
model Swap {
secretHash String? // Stores the secret hash for the atomic swap
// ... other fields
}
```

## Wallet Behavior

### ML HTLC Creation
- Input: Placeholder secret hash `{ hex: '0000000000000000000000000000000000000000' }`
- Wallet: Generates actual secret hash internally
- Output: `signedTxHex` (string)
- Secret hash: Embedded in transaction, must be extracted from blockchain

### BTC HTLC Creation
- Input: Secret hash (placeholder for first HTLC, actual for second HTLC)
- Wallet: Generates secret hash if placeholder provided
- Output:
```javascript
{
htlcAddress: string,
secretHashHex: string, // ✅ Returned directly
transactionId: string,
signedTxHex: string,
redeemScript: string,
}
```
- Secret hash: Returned directly in response

## Status Flow

### When Creator Offers BTC:
1. `pending` → Creator creates BTC HTLC → `btc_htlc_created`
2. `btc_htlc_created` → Taker creates ML HTLC → `both_htlcs_created` or `in_progress`
3. Claims proceed as normal

### When Creator Offers ML:
1. `pending` → Creator creates ML HTLC → `htlc_created`
2. `htlc_created` → Taker creates BTC HTLC → `both_htlcs_created`
3. Claims proceed as normal

## Benefits

1. **Supports both HTLC creation orders** - Creator can offer either BTC or ML first
2. **Optimized secret hash handling** - Saved to database, reduces blockchain API calls
3. **Faster counterparty HTLC creation** - Uses saved secret hash instead of fetching from blockchain
4. **Better error handling** - Clear messages for different failure scenarios
5. **Maintains backward compatibility** - Falls back to blockchain extraction if secret hash not saved

## Testing Checklist

- [ ] Creator offers BTC → Creates BTC HTLC first (no ML HTLC exists)
- [ ] Creator offers BTC → Taker creates ML HTLC second (uses secret hash from BTC)
- [ ] Creator offers ML → Creates ML HTLC first (secret hash saved)
- [ ] Creator offers ML → Taker creates BTC HTLC second (uses saved secret hash)
- [ ] Secret hash properly shared between both HTLCs
- [ ] Claims work correctly in both directions
- [ ] Fallback to blockchain extraction works if secret hash not saved
- [ ] Status updates correctly based on HTLC creation order

## Notes

- The 2-second delay in ML HTLC creation allows the transaction to be indexed by the blockchain API
- BTC wallet returns secret hash directly, eliminating need for extraction
- Secret hash is stored as hex string in database
- Both ML and BTC secret hashes are compatible (same format)

Loading
Loading