Skip to main content

Overview

This example demonstrates how to use the Mirador SDK to track a complete blockchain transaction flow, from wallet connection through confirmation.

Full Example

import { Client } from '@miradorlabs/web-sdk';

// Initialize client (typically done once at app startup)
const client = new Client('your-api-key');

async function executeTokenSwap(params: {
  inputToken: string;
  outputToken: string;
  inputAmount: string;
  userAddress: string;
  slippage: number;
}) {
  // Create trace with initial context
  const trace = client.trace({ name: 'TokenSwap' })
    .addAttributes({
      inputToken: params.inputToken,
      outputToken: params.outputToken,
      inputAmount: params.inputAmount,
      userAddress: params.userAddress,
      slippage: `${params.slippage}%`
    })
    .addTags(['swap', 'dex', 'ethereum'])
    .addEvent('swap_initiated');

  try {
    // Step 1: Get quote
    trace.addEvent('fetching_quote');
    const quote = await fetchQuote(params);
    trace.addEvent('quote_received', {
      outputAmount: quote.outputAmount,
      priceImpact: quote.priceImpact,
      route: quote.route.join(' → ')
    });

    // Step 2: Check allowance and approve if needed
    const allowance = await checkAllowance(params.inputToken, params.userAddress);
    if (allowance < BigInt(params.inputAmount)) {
      trace.addEvent('approval_required');

      const approveTx = await wallet.sendTransaction(
        buildApprovalTx(params.inputToken)
      );
      trace.addEvent('approval_submitted', { txHash: approveTx.hash })
           .addTxHint(approveTx.hash, 'ethereum', 'Token approval');

      await approveTx.wait();
      trace.addEvent('approval_confirmed');
    }

    // Step 3: Execute swap
    trace.addEvent('building_swap_transaction');
    const swapTx = buildSwapTransaction(quote);

    trace.addEvent('awaiting_signature');
    const signedTx = await wallet.sendTransaction(swapTx);

    trace.addEvent('swap_submitted', {
      txHash: signedTx.hash,
      gasLimit: swapTx.gasLimit.toString()
    })
    .addTxHint(signedTx.hash, 'ethereum', 'Swap execution');

    // Step 4: Wait for confirmation
    trace.addEvent('awaiting_confirmation');
    const receipt = await signedTx.wait();

    trace.addEvent('swap_confirmed', {
      blockNumber: receipt.blockNumber,
      gasUsed: receipt.gasUsed.toString(),
      effectiveGasPrice: receipt.effectiveGasPrice.toString()
    });

    // Step 5: Verify output
    const outputBalance = await getTokenBalance(
      params.outputToken,
      params.userAddress
    );
    trace.addEvent('swap_completed', {
      outputReceived: outputBalance.toString(),
      success: true
    });

    // Close the trace when done
    await trace.close('Swap completed successfully');

    return { success: true, txHash: signedTx.hash };

  } catch (error) {
    // Record failure
    trace.addEvent('swap_failed', {
      error: error.message,
      code: error.code
    });

    // Close the trace on error
    await trace.close('Swap failed');

    return { success: false, error: error.message };
  }
}

Step-by-Step Breakdown

1. Initialize the Trace

const trace = client.trace({ name: 'TokenSwap' })
  .addAttributes({
    inputToken: params.inputToken,
    outputToken: params.outputToken,
    inputAmount: params.inputAmount,
    userAddress: params.userAddress
  })
  .addTags(['swap', 'dex', 'ethereum']);
Start with a descriptive name and include all relevant context upfront.

2. Record Milestones

trace.addEvent('fetching_quote');
// ... async operation ...
trace.addEvent('quote_received', { outputAmount: '1000.00' });
Add events at significant points in the flow.

3. Add Transaction Hints

trace.addTxHint(approveTx.hash, 'ethereum', 'Token approval');
// ...
trace.addTxHint(swapTx.hash, 'ethereum', 'Swap execution');
Link blockchain transactions to your trace for correlation.

4. Handle Errors

catch (error) {
  trace.addEvent('swap_failed', {
    error: error.message,
    code: error.code
  });
}
Always record failures with context for debugging.

Variations

Multi-Chain Swap

const trace = client.trace({ name: 'CrossChainSwap' })
  .addTags(['swap', 'cross-chain']);

// Swap on source chain
trace.addTxHint(sourceTx.hash, 'ethereum', 'Source chain swap');

// Bridge transaction
trace.addTxHint(bridgeTx.hash, 'ethereum', 'Bridge deposit');

// Receive on destination
trace.addTxHint(destTx.hash, 'polygon', 'Destination receive');

NFT Mint

const trace = client.trace({ name: 'NFTMint' })
  .addAttributes({
    collection: contractAddress,
    quantity: mintAmount,
    price: mintPrice
  })
  .addTags(['nft', 'mint', 'ethereum']);

trace.addEvent('mint_started');
trace.addTxHint(mintTx.hash, 'ethereum', 'NFT mint transaction');
trace.addEvent('mint_confirmed', { tokenIds: mintedTokenIds });

Staking Operation

const trace = client.trace({ name: 'Stake' })
  .addAttributes({
    protocol: 'lido',
    amount: stakeAmount,
    token: 'ETH'
  })
  .addTags(['stake', 'defi', 'ethereum']);

// Approval if needed
if (needsApproval) {
  trace.addTxHint(approveTx.hash, 'ethereum', 'Approval');
}

// Stake transaction
trace.addTxHint(stakeTx.hash, 'ethereum', 'Stake deposit');
trace.addEvent('stake_confirmed', {
  stTokenReceived: receivedAmount
});

Best Practices

Include identifying attributes (user, amounts, tokens) when creating the trace, not at the end.
swap_submitted is better than tx_sent. Future you will thank you.
Add gas used, block numbers, and other on-chain data for debugging.
A trace without error handling is incomplete. Record failures with context.
Don’t wait for confirmation to add the hint - add it as soon as you have the hash.

Next Steps