> ## Documentation Index
> Fetch the complete documentation index at: https://docs.streambird.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Step Transaction Flow

Handle complex multi-step transaction flows with proper state management, visual feedback, and error handling.

## Implementation

```tsx theme={null}
import { useSendTransaction } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

type FlowStep = 'idle' | 'approving' | 'approved' | 'swapping' | 'complete' | 'error';

export default function MultiStepTransaction() {
  const { sendTransaction } = useSendTransaction();
  const [step, setStep] = useState<FlowStep>('idle');
  const [error, setError] = useState('');

  const handleTokenSwap = async () => {
    try {
      // Step 1: Approve token spending
      setStep('approving');
      const approveTx = await sendTransaction({
        to: '0xTOKEN_ADDRESS',
        data: '0x...' // approve function call data
      });
      console.log('Approval tx:', approveTx);
      
      setStep('approved');
      
      // Wait a bit for confirmation
      await new Promise(resolve => setTimeout(resolve, 2000));
      
      // Step 2: Execute swap
      setStep('swapping');
      const swapTx = await sendTransaction({
        to: '0xSWAP_CONTRACT',
        data: '0x...' // swap function call data
      });
      console.log('Swap tx:', swapTx);
      
      setStep('complete');
    } catch (err) {
      setStep('error');
      setError(err instanceof Error ? err.message : 'Transaction failed');
      console.error(err);
    }
  };

  return (
    <div className="multi-step-container">
      <h2>Token Swap</h2>
      
      <div className="steps">
        <div className={`step ${step === 'approving' || step === 'approved' ? 'active' : ''}`}>
          <span className="step-number">1</span>
          <span className="step-label">Approve Token</span>
          {step === 'approving' && <span className="spinner" />}
          {step === 'approved' && <span className="checkmark">✓</span>}
        </div>
        
        <div className={`step ${step === 'swapping' || step === 'complete' ? 'active' : ''}`}>
          <span className="step-number">2</span>
          <span className="step-label">Execute Swap</span>
          {step === 'swapping' && <span className="spinner" />}
          {step === 'complete' && <span className="checkmark">✓</span>}
        </div>
      </div>

      {error && <div className="error-message">{error}</div>}
      {step === 'complete' && <div className="success-message">Swap completed!</div>}

      <button
        onClick={handleTokenSwap}
        disabled={step !== 'idle' && step !== 'error' && step !== 'complete'}
      >
        {step === 'idle' || step === 'error' ? 'Start Swap' : 'Processing...'}
      </button>
    </div>
  );
}
```

## Key concepts

* **State management** - Tracks progress through multiple steps
* **Visual feedback** - Shows loading indicators and checkmarks for each step
* **Error handling** - Catches errors at any step and allows retry
* **User experience** - Disables button during processing
* **Confirmation delays** - Waits for transaction confirmation before proceeding

## Common patterns

### With transaction confirmation

```tsx theme={null}
import { waitForTransaction } from 'wagmi';

const handleMultiStep = async () => {
  setStep('approving');
  const approveTx = await sendTransaction({...});
  
  // Wait for confirmation
  await waitForTransaction({ hash: approveTx });
  setStep('approved');
  
  // Continue with next step
  setStep('swapping');
  const swapTx = await sendTransaction({...});
  await waitForTransaction({ hash: swapTx });
  
  setStep('complete');
};
```

### With progress percentage

```tsx theme={null}
const [progress, setProgress] = useState(0);

const handleFlow = async () => {
  setProgress(0);
  
  setProgress(25);
  await step1();
  
  setProgress(50);
  await step2();
  
  setProgress(75);
  await step3();
  
  setProgress(100);
};
```

### With cancellation support

```tsx theme={null}
const [isCancelled, setIsCancelled] = useState(false);

const handleFlow = async () => {
  setIsCancelled(false);
  
  await step1();
  if (isCancelled) return;
  
  await step2();
  if (isCancelled) return;
  
  await step3();
};

const handleCancel = () => setIsCancelled(true);
```

## Important notes

<Warning>
  Always wait for transaction confirmation before proceeding to the next step to avoid errors from transactions not being mined yet.
</Warning>

<Info>
  Consider adding retry logic for failed steps, especially for network-related errors.
</Info>

## Styling suggestion

```css theme={null}
.steps {
  display: flex;
  gap: 2rem;
  margin: 2rem 0;
}

.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  opacity: 0.5;
  transition: opacity 0.2s;
}

.step.active {
  opacity: 1;
}

.step-number {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: bold;
}

.step.active .step-number {
  background: #6366f1;
  color: white;
}

.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid #e5e7eb;
  border-top-color: #6366f1;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.checkmark {
  color: #10b981;
  font-size: 20px;
}
```

## Next steps

<CardGroup cols={2}>
  <Card title="ERC-20 Transfers" icon="coins" href="/recipes/erc20-token-transfer-ethereum">
    Token transfer basics
  </Card>

  <Card title="Styling Examples" icon="palette" href="/recipes/styling-examples">
    Style your components
  </Card>
</CardGroup>
