npm package: @perawallet/swap
Description: Algorand swap utilities and widget integration
Author: Pera Wallet
Latest version: 1.0.0-beta.4

# @perawallet/swap

Algorand swap utilities and widget integration.

## Installation

```bash
npm install @perawallet/swap
```

## Usage

### Unified API

```javascript
import { PeraSwap, WidgetController } from '@perawallet/swap'

// Create a PeraSwap instance for API operations
// Optional 2nd parameter lets you set a referrer URL for analytics/attribution
const peraSwap = new PeraSwap('mainnet', 'https://myapp.example')

// Widget functionality (now in WidgetController)
const widgetUrl = WidgetController.generateWidgetUrl({
  theme: 'dark',
  assetIn: 0, // ALGO
  assetOut: 31566704 // USDC
})

const iframe = WidgetController.createWidgetIframe({
  theme: 'dark'
})
document.body.appendChild(iframe)

// Swap API functionality
const quote = await peraSwap.createQuote({
  providers: ['tinyman', 'vestige-v4'],
  swapper_address: 'ABCDEF...',
  swap_type: 'fixed-input',
  asset_in_id: 0, // ALGO
  asset_out_id: 31566704, // USDC
  amount: '1000000', // 1 ALGO (in microAlgos)
  slippage: '0.005' // 0.5%
})

// Prepare transactions for signing
const transactions = await peraSwap.prepareTransactions(quote.results[0].quote_id_str)

// ... Sign and submit transactions with your wallet ...
// After successfully submitting to chain, report swap status:
await peraSwap.updateSwapStatus(String(transactions.swap_id), {
  status: 'in_progress',
  submitted_transaction_ids: ['<txid-1>', '<txid-2>']
})

// Asset management
const asset = await peraSwap.getAsset(31566704)
const assets = await peraSwap.searchAssets('USDC')
const availableAssets = await peraSwap.getAvailableAssets({ asset_in_id: 0 })

// Switch networks
peraSwap.updateNetwork('testnet')
const testnetAsset = await peraSwap.getAsset(31566704)
```

> **Note**: The package uses native `fetch` API and has no external dependencies for HTTP requests. The `PeraSwap` class provides a unified interface for both widget generation and swap API operations.

## Configuration

### Widget Configuration

#### PeraSwap.generateWidgetUrl() Options

| Parameter | Description | Values | Default |
|-----------|-------------|--------|---------|
| `network` | Algorand network | `'mainnet'` \| `'testnet'` | `'mainnet'` |
| `theme` | Widget theme | `'light'` \| `'dark'` | `'light'` |
| `assetIn` | Input asset ID | `number` \| `string` | `0` (ALGO) |
| `assetOut` | Output asset ID | `number` \| `string` | `31566704` (USDC) |
| `iframeBg` | Background color | Hex color string | `undefined` |
| `useParentSigner` | Use parent signer | `boolean` | `false` |
| `accountAddress` | Account address (required if useParentSigner=true) | `string` | `undefined` |



### API Methods

#### PeraSwap Class Methods (Swap API Operations)

| Method | Description | Returns |
|--------|-------------|---------|
| `createQuote(body, signal?)` | Create swap quote | `Promise<{results: SwapQuote[]}>` |
| `prepareTransactions(quoteId, depositAddress?)` | Get transaction groups | `Promise<PrepareTransactionsResponse>` |
| `updateSwapStatus(swapId, body)` | Update swap status | `Promise<any>` |
| `getAssets(params)` | Get assets by IDs or search | `Promise<GetAssetsResponse>` |
| `getAsset(assetId)` | Get single asset by ID | `Promise<Asset \| null>` |
| `searchAssets(query)` | Search assets by name | `Promise<Asset[]>` |
| `getAvailableAssets(params)` | Get available swap assets | `Promise<{results: Asset[]}>` |
| `getAlgoPrice()` | Get ALGO price in USD | `Promise<{exchange_price: string}>` |
| `updateNetwork(network)` | Switch network | `void` |
| `getNetwork()` | Get current network | `'mainnet' \| 'testnet'` |

#### WidgetController Class Methods (Widget & Communication)

| Method | Description | Returns |
|--------|-------------|---------|
| `generateWidgetUrl(config)` | Static method to generate widget URL | `string` |
| `createWidgetIframe(config, options)` | Static method to create iframe element | `HTMLIFrameElement` |
| `sendMessageToWidget(data)` | Static method to send messages to widget | `void` |
| `addWidgetEventListeners()` | Add message event listeners | `void` |
| `removeWidgetEventListeners()` | Remove message event listeners | `void` |

### Type Definitions

The package uses string literal types for better developer experience:

```typescript
type WidgetAppTheme = 'light' | 'dark'
type WidgetNetwork = 'mainnet' | 'testnet'
type SwapProvider = 'tinyman' | 'tinyman-swap-router' | 'vestige-v4'
type SwapType = 'fixed-input'
```

### Constructor

```typescript
new PeraSwap(
  network?: 'mainnet' | 'testnet',
  referrerUrl?: string
)
```

- `referrerUrl` is optional and can be used to attribute requests to your app.
  When provided, `referrer_url` is forwarded with quote requests.

### Swap Status Reporting

Call `updateSwapStatus` after you submit signed transactions to the network.

```typescript
// Success path: transactions submitted to mempool
await peraSwap.updateSwapStatus(String(prepareResponse.swap_id), {
  status: 'in_progress',
  submitted_transaction_ids: txIds // string[] of submitted tx ids
})

// Failure path: something went wrong while submitting
await peraSwap.updateSwapStatus(String(prepareResponse.swap_id), {
  status: 'failed',
  reason: 'blockchain_error' // or 'user_cancelled' | 'other'
})
```

### Parent Signer Support

The package supports parent signer functionality, allowing the parent website to handle transaction signing:

```typescript
import { WidgetController } from '@perawallet/swap'

// Generate widget URL with parent signer
const widgetUrl = WidgetController.generateWidgetUrl({
  network: 'mainnet',
  theme: 'dark',
  assetIn: 0, // ALGO
  assetOut: 31566704, // USDC
  iframeBg: '#242424',
  useParentSigner: true,
  accountAddress: 'ABCDEF...'
})

// Set up controller for handling messages
const controller = new WidgetController({
  onTxnSignRequest: async ({ txGroups }) => {
    // txGroups are already decoded Transaction[][] objects
    // Sign transactions using your wallet
    const signedTxns = await peraWallet.signTransaction(
      txGroups.map(group => group.map(txn => ({ txn })))
    )
    return signedTxns // Return Uint8Array[]
  },
  onTxnSignRequestTimeout: () => {
    console.log('Transaction signing timed out')
  },
  onSwapSuccess: (signedTxns) => {
    console.log('Swap completed with signed transactions:', signedTxns)
  }
})

// Add event listeners to handle widget messages
controller.addWidgetEventListeners()

// Don't forget to remove listeners when done
controller.removeWidgetEventListeners()
```

## Examples

This package includes comprehensive examples demonstrating different integration approaches:

### React Examples

The React examples showcase four different ways to integrate the Pera Swap Widget:

1. **Widget URL Generator** - Generate widget URLs for iframe embedding
2. **Direct Iframe Creation** - Programmatically create and manage iframes
3. **Custom UI with Swap API** - Build custom interfaces using the swap API
4. **Parent Signer Integration** - Handle transaction signing in the parent application

#### Running the React Examples

```bash
# Navigate to examples directory
cd examples/react

# Install dependencies
npm install

# Start development server
npm run dev
```

The examples are located in the `examples/react/` directory and demonstrate:
- Widget configuration and customization
- API integration patterns
- Error handling and loading states
- Parent signer functionality
- TypeScript best practices

## Development

```bash
npm install
npm run build
npm run dev
```