Skip to main content

Overview

Confirms and submits a signed fee claim transaction to the Solana blockchain. This endpoint validates the transaction structure, adds the LP owner’s signature, and broadcasts it to the network. The transaction claims fees from a Meteora DAMM v2 pool and transfers 70% to the configured destination address.
Pool locking mechanism: This endpoint uses a mutex lock system to prevent concurrent fee claims for the same pool, ensuring transaction integrity.
curl -X POST https://api.zcombinator.io/fee-claim/confirm \
  -H "Content-Type: application/json" \
  -d '{
    "signedTransaction": "4MzR7dxJNJRVP1Q6k7Y3j8X...",
    "requestId": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
  }'

Request Parameters

signedTransaction
string
required
Base58 encoded signed transaction from the user (must match the transaction from /fee-claim/claim)
requestId
string
required
Unique identifier returned from the /fee-claim/claim endpoint

Response

success
boolean
Indicates if the transaction was submitted successfully
signature
string
Transaction signature (transaction ID) on Solana
poolAddress
string
Address of the Meteora DAMM v2 pool
tokenAMint
string
Mint address of Token A in the pool
tokenBMint
string
Mint address of Token B in the pool
destinationAddress
string
Address that received 70% of the claimed fees
positionsCount
number
Number of positions claimed from (always 1)
estimatedFees
object
Object containing the claimed fee amounts:
  • tokenA (string): Total Token A fees claimed
  • tokenB (string): Total Token B fees claimed
message
string
Success message

Success Response

{
  "success": true,
  "signature": "5J8Z9xKqH4nL2pR7vT3mB1cW6dF8yG4aS9jK2xM5nP8hQ3rV7wE1",
  "poolAddress": "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C",
  "tokenAMint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
  "tokenBMint": "So11111111111111111111111111111111111111112",
  "destinationAddress": "FeeDestinationWalletAddress123456789",
  "positionsCount": 1,
  "estimatedFees": {
    "tokenA": "1000000",
    "tokenB": "500000000"
  },
  "message": "Fee claim transaction submitted successfully"
}

Error Responses

{
  "error": "Missing required fields: signedTransaction and requestId"
}
{
  "error": "Fee claim request not found or expired. Please call /fee-claim/claim first."
}
The requestId is invalid, expired, or already used.
{
  "error": "Fee claim request expired. Please create a new request."
}
More than 10 minutes have passed since the claim request was created.
{
  "error": "Failed to deserialize transaction: Invalid transaction format"
}
The provided signedTransaction cannot be decoded.
{
  "error": "Invalid transaction: missing blockhash"
}
{
  "error": "Invalid transaction: blockhash is expired. Please create a new transaction."
}
The transaction’s blockhash is older than 150 slots (~60 seconds).
{
  "error": "Transaction fee payer mismatch"
}
The transaction’s fee payer doesn’t match the expected payer from the claim request.
{
  "error": "Transaction verification failed: LP owner signature not required"
}
Security validation failed - LP owner must be a required signer.
{
  "error": "Transaction verification failed: Fee payer has not signed"
}
The fee payer’s signature is missing from the transaction.
{
  "error": "Transaction verification failed: Invalid fee payer signature"
}
The fee payer’s signature is invalid or doesn’t match.
{
  "error": "Invalid transaction: unauthorized program instruction detected",
  "details": "Instruction 3 uses unauthorized program: 11111111111111111111111111111112"
}
The transaction contains instructions from programs that aren’t allowed.
{
  "error": "Invalid transaction: unauthorized token instruction detected",
  "details": "Instruction 2 has invalid opcode: 7. Only Transfer (3) and TransferChecked (12) allowed."
}
Token program instructions must be Transfer or TransferChecked only.
{
  "error": "Invalid transaction: transfer authority must be LP owner",
  "details": "Instruction 5 authority does not match LP owner"
}
Transfers must be signed by the LP owner.
{
  "error": "Invalid transaction: transfer destination not authorized",
  "details": "Instruction 6 destination is not in allowed list"
}
Transfers can only go to the configured destination address or LP owner’s token accounts.
{
  "error": "Invalid transaction: Token A transfer amount exceeds expected fees",
  "details": "Instruction 7 amount 2000000 exceeds Token A fees 1000000"
}
Transfer amounts cannot exceed the calculated claimable fees.
{
  "error": "Server configuration incomplete"
}
Required environment variables are not configured.
{
  "error": "Failed to confirm fee claim"
}

Process Flow

This endpoint performs extensive validation before submitting the transaction:
1

Validate Parameters

Ensures signedTransaction and requestId are provided
2

Retrieve Request Data

Looks up the fee claim request data using the requestId
3

Acquire Pool Lock

Obtains a mutex lock for the pool to prevent concurrent claims
4

Check Request Expiry

Verifies the request is not older than 10 minutes
5

Deserialize Transaction

Decodes the Base58 encoded transaction
6

Validate Blockhash

Checks that the transaction’s blockhash is recent and valid (within last 150 slots)
7

Verify Fee Payer

Ensures the fee payer matches the expected payer and has signed
8

Verify Fee Payer Signature

Cryptographically validates the fee payer’s signature using nacl
9

Validate Transaction Structure

Comprehensive security validation (see Security Validations section below)
10

Add LP Owner Signature

Protocol signs the transaction with the LP owner keypair
11

Submit Transaction

Broadcasts the fully-signed transaction to Solana with preflight checks
12

Wait for Confirmation

Attempts to wait for transaction confirmation (continues if timeout)
13

Cleanup

Removes the request data from memory and releases the pool lock

Security Validations

This endpoint implements comprehensive transaction validation to prevent attacks:
Prevents race conditions by ensuring only one fee claim can be processed per pool at a time using mutex locks.
Prevents replay attacks by verifying the blockhash is recent (within last 150 slots / ~60 seconds).
Only permits instructions from:
  • Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)
  • Associated Token Program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL)
  • Compute Budget Program
  • Lighthouse Program (for optimization)
  • Meteora CP-AMM Program (CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C)
  • System Program (for native SOL transfers)
  • Only Transfer (opcode 3) and TransferChecked (opcode 12) are allowed
  • All transfers must be signed by the LP owner
  • Transfer amounts cannot exceed calculated fees
Transfers can ONLY go to:
  • Configured destination address token accounts (70% recipient)
  • LP owner token accounts (30% remainder) Any other destination is rejected.
For native SOL transfers (when Token B is wSOL):
  • Only SystemProgram.transfer (instruction type 2) allowed
  • Must be from LP owner to configured destination address
  • Amount cannot exceed Token B fees
Only CreateAssociatedTokenAccountIdempotent (opcode 1) is allowed for ATA program.
All transfer amounts are compared against stored expected fees to prevent over-claiming.
No authorization required: Since fee destinations are hardcoded and validated, anyone can trigger fee claims. The fee payer only covers transaction costs and cannot redirect funds.

Rate Limiting

This endpoint is subject to rate limiting:
  • 10 requests per 5-minute window per IP
  • Returns HTTP 429 when limit exceeded

Transaction Confirmation

The API attempts to wait for transaction confirmation but continues even if confirmation times out:
  • Confirmation Commitment: confirmed
  • Timeout Handling: Logs warning but returns success
  • User Responsibility: Check transaction status on Solana explorer
You can view the transaction on Solscan: https://solscan.io/tx/{signature}

Pool Lock System

Mutex locks prevent concurrent processing:When a fee claim is being processed for a pool, subsequent requests for the same pool will wait for the lock to be released. This prevents:
  • Double-claiming fees
  • Transaction conflicts
  • Race conditions
The lock is automatically released when processing completes (success or error).

Request Cleanup

After successful submission:
  • Request data is immediately removed from memory
  • Pool lock is released
  • requestId cannot be reused

Logging

The endpoint logs comprehensive information for monitoring:
  • Pool address
  • Token mints and fee amounts
  • Destination address
  • Transaction signature
  • Solscan link for easy verification

Best Practices

1

Check Blockhash Age

Submit the signed transaction quickly after receiving it from /fee-claim/claim. Blockhashes expire after ~60 seconds.
2

Handle Expiry

If more than 10 minutes pass, create a new claim request instead of retrying with the old requestId.
3

Monitor Transaction

Use the returned signature to check transaction status on Solana explorers or via RPC.
4

Wait for Lock

If you receive a timeout or slow response, the pool may be locked by another concurrent request. Wait and retry.

Environment Variables

Required server configuration:
  • RPC_URL: Solana RPC endpoint
  • DAMM_POOL_ADDRESS: Meteora DAMM v2 pool address
  • PROTOCOL_PRIVATE_KEY: LP owner’s private key (Base58)
  • FEE_DESTINATION_ADDRESS: Address to receive 70% of claimed fees