# Developer Docs

A comprehensive guide for developers to integrate StableFlow’s cross-chain transfers into your applications.

## Table of Contents

* [Getting Started](#getting-started)
* [API Configuration](#api-configuration)
* [Core Functions](#core-functions)
* [Working Examples](#working-examples)
* [Best Practices](#best-practices)
* [Common Use Cases](#common-use-cases)
* [Troubleshooting](#troubleshooting)
* [Additional Recourses](#additional-resources)
* [Summary](#summary)

***

## Getting Started

#### Installation

```bash
npm install stableflow-ai-sdk
```

#### Prerequisites

1. **Node.js**: Version 16 or higher
2. **JWT Token**: Required for API access

   [![Apply for API Access](https://img.shields.io/badge/Apply_for_API_Access-4285F4?style=for-the-badge\&logo=google\&logoColor=white)](https://docs.google.com/forms/u/3/d/e/1FAIpQLSdTeV7UaZ1MiFxdJ2jH_PU60PIN3iqYJ1WXEOFY45TsAy6O5g/viewform)
3. **TypeScript** (recommended): For full type safety

***

## API Configuration

#### Basic Setup

```typescript
import { OpenAPI, SFA } from 'stableflow-ai-sdk';

// Configure API endpoint
OpenAPI.BASE = 'https://api.stableflow.ai';

// Set your JWT token
OpenAPI.TOKEN = 'your-jwt-token-here';
```

#### Configuration Options

| Option                     | Type    | Description                     | Required |
| -------------------------- | ------- | ------------------------------- | -------- |
| `OpenAPI.BASE`             | string  | API endpoint URL                | Yes      |
| `OpenAPI.TOKEN`            | string  | JWT authentication token        | Yes      |
| `OpenAPI.WITH_CREDENTIALS` | boolean | Include credentials in requests | No       |
| `OpenAPI.HEADERS`          | object  | Additional request headers      | No       |

***

## Core Functions

#### 1. `getTokens()`

Retrieves the list of all supported tokens across different blockchains.

**Signature**

```typescript
SFA.getTokens(): Promise<TokenResponse[]>
```

**Returns**

Array of `TokenResponse` objects containing:

```typescript
interface TokenResponse {
  assetId: string;        // Unique asset identifier
  blockchain: string;     // Network ID (e.g., 'eth', 'arb', 'pol')
  symbol: string;         // Token symbol (e.g., 'USDT', 'USDC')
  decimals: number;       // Token decimals (e.g., 6, 18)
  address?: string;       // Contract address
  price?: string;         // Current price in USD
}
```

**Example Usage**

```typescript
// Fetch all supported tokens
const tokens = await SFA.getTokens();

// Filter USDT tokens
const usdtTokens = tokens.filter(t => t.symbol === 'USDT');

// Get tokens for specific network
const ethTokens = tokens.filter(t => t.blockchain === 'eth');

// Find specific token
const arbUsdc = tokens.find(
  t => t.blockchain === 'arb' && t.symbol === 'USDC'
);
```

**Use Cases**

* Building token selection UI
* Validating supported tokens
* Getting current token prices
* Discovering available networks

***

#### 2. `getQuote()`

Requests a quote for cross-chain token swap, including fees, estimated time, and deposit address.

**Signature**

```typescript
SFA.getQuote(request: QuoteRequest): Promise<QuoteResponse>
```

**Request Parameters**

```typescript
interface QuoteRequest {
  // Testing mode (true = no real deposit address)
  dry: boolean;
  
  // Swap calculation type
  swapType: 'EXACT_INPUT' | 'EXACT_OUTPUT';
  
  // Slippage tolerance in basis points (100 = 1%)
  slippageTolerance: number;
  
  // Source token asset ID
  originAsset: string;
  
  // Where user deposits funds
  depositType: 'ORIGIN_CHAIN' | 'NEAR';
  
  // Destination token asset ID
  destinationAsset: string;
  
  // Amount in token's smallest unit
  amount: string;
  
  // Refund address if swap fails
  refundTo: string;
  
  // Refund location
  refundType: 'ORIGIN_CHAIN' | 'NEAR';
  
  // Recipient address for destination tokens
  recipient: string;
  
  // Recipient location
  recipientType: 'DESTINATION_CHAIN' | 'NEAR';
  
  // Quote expiration time (ISO 8601)
  deadline: string;
  
  // Optional: max wait time for quote in milliseconds
  quoteWaitingTimeMs?: number;
}
```

**Response**

```typescript
interface QuoteResponse {
  quote: {
    depositAddress: string;      // Address to send tokens to
    amountIn: string;             // Input amount (smallest unit)
    amountInFormatted: string;    // Input amount (human-readable)
    amountOut: string;            // Output amount (smallest unit)
    amountOutFormatted: string;   // Output amount (human-readable)
    minAmountOut: string;         // Minimum output after slippage
    amountInUsd: string;          // Input value in USD
    amountOutUsd: string;         // Output value in USD
    timeEstimate: number;         // Estimated completion time (seconds)
    appFee?: AppFee;              // Fee breakdown
  };
  swapDetails: SwapDetails;       // Detailed swap information
  transactionDetails: TransactionDetails;  // Transaction parameters
}
```

**Example Usage**

```typescript
import { QuoteRequest } from 'stableflow-ai-sdk';

const quoteRequest: QuoteRequest = {
  dry: false,  // Get real deposit address
  swapType: QuoteRequest.swapType.EXACT_INPUT,
  slippageTolerance: 100,  // 1%
  
  // Swap from Arbitrum USDT to Ethereum USDT
  originAsset: 'nep141:arb-0xfd086bc7cd5c481dcc9c85ebe478a1c0b69fcbb9.omft.near',
  destinationAsset: 'nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near',
  
  amount: '1000000',  // 1 USDT (6 decimals)
  
  depositType: QuoteRequest.depositType.ORIGIN_CHAIN,
  refundTo: '0xYourArbitrumAddress',
  refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
  
  recipient: '0xYourEthereumAddress',
  recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
  
  deadline: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
};

const quote = await SFA.getQuote(quoteRequest);

console.log('Deposit to:', quote.quote.depositAddress);
console.log('You will receive:', quote.quote.amountOutFormatted);
console.log('Estimated time:', quote.quote.timeEstimate, 'seconds');
```

**Important Notes**

* **`dry: true`**: Testing mode, no real deposit address
* **`dry: false`**: Production mode, returns real deposit address
* **Amount Format**: Always use smallest token unit (e.g., 1 USDT = 1000000 for 6 decimals)
* **Deadline**: Must be a future timestamp in ISO 8601 format
* **Address Validation**: Ensure addresses match the respective network format

***

#### 3. `submitDepositTx()`

Notifies StableFlow that you've sent tokens to the deposit address.

**Signature**

```typescript
SFA.submitDepositTx(request: SubmitDepositTxRequest): Promise<SubmitDepositTxResponse>
```

**Request Parameters**

```typescript
interface SubmitDepositTxRequest {
  txHash: string;           // Transaction hash from blockchain
  depositAddress: string;   // Deposit address from quote
}
```

**Response**

```typescript
interface SubmitDepositTxResponse {
  success: boolean;
  message?: string;
}
```

**Example Usage**

```typescript
// After sending tokens to deposit address
const txHash = '0x123...abc';  // From blockchain transaction
const depositAddress = quote.quote.depositAddress;

const result = await SFA.submitDepositTx({
  txHash,
  depositAddress,
});

if (result.success) {
  console.log('Transaction submitted successfully!');
}
```

**When to Call**

1. **After** sending tokens to `depositAddress`
2. **After** transaction is confirmed on blockchain
3. **Before** checking execution status

***

#### 4. `getExecutionStatus()`

Checks the current status of a cross-chain swap.

**Signature**

```typescript
SFA.getExecutionStatus(depositAddress: string): Promise<GetExecutionStatusResponse>
```

**Parameters**

| Parameter        | Type   | Description                |
| ---------------- | ------ | -------------------------- |
| `depositAddress` | string | Deposit address from quote |

**Response**

```typescript
interface GetExecutionStatusResponse {
  status: 'pending' | 'processing' | 'completed' | 'failed';
  depositTxHash?: string;
  destinationTxHash?: string;
  message?: string;
  updatedAt: string;
}
```

**Example Usage**

```typescript
const status = await SFA.getExecutionStatus(depositAddress);

switch (status.status) {
  case 'pending':
    console.log('Waiting for deposit confirmation...');
    break;
  case 'processing':
    console.log('Swap in progress...');
    break;
  case 'completed':
    console.log('Swap completed!');
    console.log('Destination tx:', status.destinationTxHash);
    break;
  case 'failed':
    console.log('Swap failed:', status.message);
    break;
}
```

**Polling Example**

```typescript
async function waitForCompletion(depositAddress: string) {
  const maxAttempts = 60;  // 5 minutes with 5s interval
  
  for (let i = 0; i < maxAttempts; i++) {
    const status = await SFA.getExecutionStatus(depositAddress);
    
    if (status.status === 'completed') {
      return status;
    }
    
    if (status.status === 'failed') {
      throw new Error(status.message);
    }
    
    // Wait 5 seconds before next check
    await new Promise(resolve => setTimeout(resolve, 5000));
  }
  
  throw new Error('Timeout waiting for swap completion');
}
```

***

## Working Examples

The SDK includes a complete web application example demonstrating real-world usage.

#### Web Demo Application

Location: `examples/web-demo/`

**Features**

* â Real wallet connection (MetaMask)
* â Network switching
* â Token balance checking
* â Quote generation
* â Transaction execution
* â Status tracking

**Running the Example**

```bash
cd examples/web-demo
npm install
npm run dev
```

**Key Files to Study**

1. **`app.ts`** - Main application logic
   * Wallet connection: `connectWallet()`
   * Network switching: `switchNetwork()`
   * Getting quotes: `handleGetQuote()`
   * Executing swaps: `executeBridge()`
2. **Network Configuration**

   ```typescript
   const SUPPORTED_NETWORKS = [
     {
       id: 'eth',
       name: 'Ethereum',
       chainId: 1,
       usdtContract: '0xdac17f958d2ee523a2206206994597c13d831ec7',
       usdtAssetId: 'nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near',
       decimals: 6
     },
     // ... more networks
   ];
   ```
3. **ERC20 Token Transfer**

   ```typescript
   // Create contract instance
   const erc20Abi = ['function transfer(address to, uint256 amount) returns (bool)'];
   const usdtContract = new ethers.Contract(
     fromNetwork.usdtContract,
     erc20Abi,
     signer
   );

   // Execute transfer
   const tx = await usdtContract.transfer(depositAddress, amount);
   await tx.wait();
   ```

**Learning Path**

1. **Start with**: Understanding the flow in `app.ts`
2. **Study**: Network configuration and asset IDs
3. **Review**: Error handling patterns
4. **Examine**: UI/UX best practices
5. **Customize**: Adapt for your use case

***

## Best Practices

#### 1. Error Handling

Always wrap SDK calls in try-catch blocks:

```typescript
import { ApiError } from 'stableflow-ai-sdk';

try {
  const quote = await SFA.getQuote(request);
} catch (error) {
  if (error instanceof ApiError) {
    switch (error.status) {
      case 400:
        // Invalid request parameters
        console.error('Bad request:', error.body);
        break;
      case 401:
        // Authentication failed
        console.error('Invalid JWT token');
        break;
      case 404:
        // Resource not found
        console.error('Endpoint not found');
        break;
      default:
        console.error('API error:', error.message);
    }
  } else {
    // Network or other errors
    console.error('Unexpected error:', error);
  }
}
```

#### 2. Token Amount Conversion

Always convert human-readable amounts to smallest units:

```typescript
import { ethers } from 'ethers';

// Human-readable to smallest unit
const decimals = 6;  // USDT decimals
const humanAmount = '100.5';  // 100.5 USDT
const smallestUnit = ethers.parseUnits(humanAmount, decimals);
// Result: 100500000n

// Smallest unit to human-readable
const formatted = ethers.formatUnits(smallestUnit, decimals);
// Result: '100.5'
```

#### 3. Deadline Management

Set reasonable deadlines:

```typescript
// Good: 24 hours from now
const deadline = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();

// Bad: Past timestamp
const badDeadline = new Date('2020-01-01').toISOString();  // â

// Bad: Too short
const tooShort = new Date(Date.now() + 60 * 1000).toISOString();  // â
```

#### 4. Network Validation

Validate network compatibility:

```typescript
async function validateNetworks(fromNetwork: string, toNetwork: string) {
  if (fromNetwork === toNetwork) {
    throw new Error('Source and destination networks must be different');
  }
  
  const tokens = await SFA.getTokens();
  const fromTokens = tokens.filter(t => t.blockchain === fromNetwork);
  const toTokens = tokens.filter(t => t.blockchain === toNetwork);
  
  if (fromTokens.length === 0) {
    throw new Error(`Network ${fromNetwork} not supported`);
  }
  
  if (toTokens.length === 0) {
    throw new Error(`Network ${toNetwork} not supported`);
  }
}
```

#### 5. Status Polling

Implement exponential backoff:

```typescript
async function pollStatus(depositAddress: string) {
  let delay = 2000;  // Start with 2 seconds
  const maxDelay = 30000;  // Max 30 seconds
  const maxAttempts = 100;
  
  for (let i = 0; i < maxAttempts; i++) {
    const status = await SFA.getExecutionStatus(depositAddress);
    
    if (status.status === 'completed' || status.status === 'failed') {
      return status;
    }
    
    await new Promise(resolve => setTimeout(resolve, delay));
    
    // Exponential backoff
    delay = Math.min(delay * 1.5, maxDelay);
  }
  
  throw new Error('Polling timeout');
}
```

***

## Common Use Cases

#### Use Case 1: Simple USDT Bridge

Bridge USDT from Ethereum to Arbitrum:

```typescript
// 1. Get tokens to find asset IDs
const tokens = await SFA.getTokens();
const ethUsdt = tokens.find(t => t.blockchain === 'eth' && t.symbol === 'USDT');
const arbUsdt = tokens.find(t => t.blockchain === 'arb' && t.symbol === 'USDT');

// 2. Create quote request
const quoteRequest: QuoteRequest = {
  dry: false,
  swapType: QuoteRequest.swapType.EXACT_INPUT,
  slippageTolerance: 100,
  originAsset: ethUsdt.assetId,
  destinationAsset: arbUsdt.assetId,
  amount: ethers.parseUnits('100', 6).toString(),  // 100 USDT
  depositType: QuoteRequest.depositType.ORIGIN_CHAIN,
  refundTo: userEthAddress,
  refundType: QuoteRequest.refundType.ORIGIN_CHAIN,
  recipient: userArbAddress,
  recipientType: QuoteRequest.recipientType.DESTINATION_CHAIN,
  deadline: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
};

// 3. Get quote
const quote = await SFA.getQuote(quoteRequest);

// 4. Transfer USDT to deposit address
const usdtContract = new ethers.Contract(
  '0xdac17f958d2ee523a2206206994597c13d831ec7',
  ['function transfer(address to, uint256 amount) returns (bool)'],
  signer
);
const tx = await usdtContract.transfer(
  quote.quote.depositAddress,
  ethers.parseUnits('100', 6)
);
await tx.wait();

// 5. Submit transaction
await SFA.submitDepositTx({
  txHash: tx.hash,
  depositAddress: quote.quote.depositAddress,
});

// 6. Monitor status
const finalStatus = await pollStatus(quote.quote.depositAddress);
console.log('Bridge completed!', finalStatus.destinationTxHash);
```

#### Use Case 2: Dynamic Token Selection

Let users choose any supported token pair:

```typescript
async function buildTokenPairSelector() {
  const tokens = await SFA.getTokens();
  
  // Group by network
  const byNetwork = tokens.reduce((acc, token) => {
    if (!acc[token.blockchain]) {
      acc[token.blockchain] = [];
    }
    acc[token.blockchain].push(token);
    return acc;
  }, {} as Record<string, TokenResponse[]>);
  
  // Build UI options
  const networks = Object.keys(byNetwork);
  
  return {
    networks,
    getTokensForNetwork: (network: string) => byNetwork[network],
    findToken: (network: string, symbol: string) =>
      byNetwork[network]?.find(t => t.symbol === symbol),
  };
}
```

#### Use Case 3: Fee Calculator

Calculate bridge fees before execution:

```typescript
async function calculateFees(
  fromToken: TokenResponse,
  toToken: TokenResponse,
  amount: string
) {
  const quoteRequest: QuoteRequest = {
    dry: true,  // Testing mode
    swapType: QuoteRequest.swapType.EXACT_INPUT,
    slippageTolerance: 100,
    originAsset: fromToken.assetId,
    destinationAsset: toToken.assetId,
    amount,
    // ... other required fields
  };
  
  const quote = await SFA.getQuote(quoteRequest);
  
  const feeUsd = parseFloat(quote.quote.amountInUsd) - 
                 parseFloat(quote.quote.amountOutUsd);
  const feePercent = (feeUsd / parseFloat(quote.quote.amountInUsd)) * 100;
  
  return {
    feeUsd: feeUsd.toFixed(4),
    feePercent: feePercent.toFixed(2),
    estimatedTime: quote.quote.timeEstimate,
    minimumReceived: quote.quote.amountOutFormatted,
  };
}
```

***

## Troubleshooting

#### Common Issues

**1. "Invalid token" Error**

**Cause**: Using incorrect `assetId` format

**Solution**: Always get asset IDs from `getTokens()`:

```typescript
const tokens = await SFA.getTokens();
const token = tokens.find(t => 
  t.blockchain === 'eth' && t.symbol === 'USDT'
);
// Use: token.assetId
```

**2. "Deadline is not valid" Error**

**Cause**: Deadline is in the past or incorrect format

**Solution**: Use ISO 8601 format with future timestamp:

```typescript
const deadline = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
```

**3. Authentication Errors**

**Cause**: Missing or invalid JWT token

**Solution**:

**ð** [**Apply for JWT Token Here**](https://docs.google.com/forms/u/3/d/e/1FAIpQLSdTeV7UaZ1MiFxdJ2jH_PU60PIN3iqYJ1WXEOFY45TsAy6O5g/viewform)

After receiving your token, set it before any API calls:

```typescript
OpenAPI.TOKEN = 'your-valid-token';
```

**4. Network Mismatch**

**Cause**: Wallet on wrong network when sending transaction

**Solution**: Check and switch network before transaction:

```typescript
const currentChainId = await window.ethereum.request({ 
  method: 'eth_chainId' 
});

if (currentChainId !== expectedChainId) {
  await window.ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: expectedChainId }],
  });
}
```

**5. Transaction Stuck**

**Cause**: Transaction not confirmed on blockchain

**Solution**: Wait for confirmation before submitting:

```typescript
const tx = await usdtContract.transfer(depositAddress, amount);
const receipt = await tx.wait();  // Wait for confirmation
console.log('Confirmed in block:', receipt.blockNumber);

// Now submit to StableFlow
await SFA.submitDepositTx({ txHash: tx.hash, depositAddress });
```

***

## Additional Resources

#### SDK Repository

* GitHub: [stableflow-ai/stableflow-ai-sdk](https://github.com/stableflow-ai/stableflow-ai-sdk)
* Examples: `examples/` directory
* Issues: Report bugs via GitHub Issues

#### StableFlow Platform

* Website: <https://app.stableflow.ai/>
* API Access: Apply for JWT token
* Documentation: Latest API specs

#### Community

* Discord: [Join our community](https://discord.gg/stableflow)
* Twitter: [@StableFlowAI](https://twitter.com/stableflowai)

***

## Summary

#### Quick Reference

| Function               | Purpose               | Required Fields                   |
| ---------------------- | --------------------- | --------------------------------- |
| `getTokens()`          | List supported tokens | JWT Token                         |
| `getQuote()`           | Get swap quote        | JWT Token, QuoteRequest           |
| `submitDepositTx()`    | Notify deposit        | JWT Token, txHash, depositAddress |
| `getExecutionStatus()` | Check swap status     | JWT Token, depositAddress         |

#### Integration Checklist

* [ ] Install SDK via npm
* [ ] Obtain JWT token from StableFlow
* [ ] Configure `OpenAPI.BASE` and `OpenAPI.TOKEN`
* [ ] Study web demo example
* [ ] Implement error handling
* [ ] Test with `dry: true` mode first
* [ ] Handle network switching
* [ ] Implement status polling
* [ ] Add user notifications
* [ ] Test with real transactions

***

#### **Happy Building!**

For questions or support, visit our [GitHub repository](https://github.com/stableflow-ai/stableflow-ai-sdk) or join our [Discord community](https://discord.gg/stableflow).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dapdap.net/apps/stableflow/developer-docs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
