# orda TypeScript SDK

TypeScript SDK for the Orda API - cross-chain crypto payments, on/off-ramp, prices, balances, and server-side smart-wallet auto-generation. Zero runtime dependencies.

## Installation

```bash
npm install @ordanetwork/sdk
# or
yarn add @ordanetwork/sdk
# or
pnpm add @ordanetwork/sdk
```

### Requirements

- **Node.js**: Version 18.0.0 or higher
- **TypeScript**: Version 5.0.0 or higher (if using TypeScript)

## Features

- **Dual Authentication**: HMAC (server-side) and JWT (client-side) authentication
- **Multi-chain Support**: Cross-chain transfers, off-ramp, and on-ramp operations
- **Prices & Balances**: USD price lookups and multi-chain wallet balances via `orda.prices` / `orda.balances`
- **Smart-Wallet Auto-Generation**: ERC-4337 wallets generated server-side for recipients created without `toAddress`
- **Zero Runtime Dependencies**: Uses Fetch and Web Crypto / `node:crypto` only
- **Module Formats**: ESM, CommonJS, and browser builds
- **TypeScript**: Full type definitions included


## Quick Start

### Server-Side (HMAC Authentication)

```typescript
import { OrdaSDK } from '@ordanetwork/sdk';

const orda = new OrdaSDK({
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret'
});
```

### Client-Side (JWT Authentication)

```typescript
import { OrdaSDK } from '@ordanetwork/sdk';

const orda = new OrdaSDK({
  token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
});

// Create a recipient with smart wallet (no toAddress)
const recipientWithSmartWallet = await orda.recipients.create({
  name: 'Test Recipient',
  cryptoSettlementDetails: {
    toChain: '8453',
    toToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
    // No toAddress - will generate smart wallet
  }
});
console.log('Smart wallet:', recipientWithSmartWallet.smartWallet?.address);

// Create a recipient with specific address
const recipientWithAddress = await orda.recipients.create({
  name: 'Test Recipient',
  cryptoSettlementDetails: {
    toChain: '8453',
    toToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
    toAddress: '0xYourRecipientAddress'
  }
});

// Request a quote
const quote = await orda.quote.request({
  fromChain: '1', // Ethereum mainnet
  fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
  fromAddress: '0xYourAddress',
  intent: {
    method: 'usd',
    value: '100'
  },
  recipientId: recipientWithSmartWallet.recipientId
});
```

## Module Formats

The SDK supports multiple module formats for maximum compatibility:

### CommonJS
```javascript
const { OrdaSDK } = require('@ordanetwork/sdk');
```

### ES Modules
```javascript
import { OrdaSDK } from '@ordanetwork/sdk';
```

## Authentication Methods

### HMAC Authentication (Server-Side)

Use HMAC authentication for server-to-server communication. This method should only be used in secure backend environments.

```javascript
const { OrdaSDK } = require('@ordanetwork/sdk');

const orda = new OrdaSDK({
  clientId: process.env.ORDA_CLIENT_ID,
  clientSecret: process.env.ORDA_CLIENT_SECRET
});
```

**CRITICAL**: Never expose `clientSecret` in frontend code.

### JWT Authentication (Client-Side)

Use JWT authentication for client-side applications. Generate tokens on your backend and pass them to your frontend.

**Backend (Node.js):**
```typescript
import { OrdaSDK } from '@ordanetwork/sdk';

const orda = new OrdaSDK({
  clientId: process.env.ORDA_CLIENT_ID,
  clientSecret: process.env.ORDA_CLIENT_SECRET
});

const { token, expiresAt } = await orda.jwt.generate({
  clientId: process.env.ORDA_CLIENT_ID,
  clientSecret: process.env.ORDA_CLIENT_SECRET,
  expiresIn: 3600,
  permissions: ['quotes:read', 'offramp:read', 'onramp:read', 'transactions:read']
});

res.json({ token, expiresAt });
```

**Frontend (React/Vue/etc):**
```typescript
import { OrdaSDK } from '@ordanetwork/sdk';

const response = await fetch('/api/auth/token');
const { token } = await response.json();

const orda = new OrdaSDK({ token });

const quote = await orda.quote.request({
  fromChain: '1',
  fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
  fromAddress: userWalletAddress,
  intent: { method: 'usd', value: '100' },
  recipientId: 'recipient-id'
});
```

## API Documentation

### Initialize SDK

**HMAC Mode (Server-Side):**
```typescript
const orda = new OrdaSDK({
  clientId: 'your-client-id',
  clientSecret: 'your-client-secret',
  requestTimeout: 30000,
  debug: false
});
```

**JWT Mode (Client-Side):**
```typescript
const orda = new OrdaSDK({
  token: 'your-jwt-token',
  requestTimeout: 30000,
  debug: false
});
```

### JWT API

Generate JWT tokens for client-side authentication.

```typescript
const { token, expiresAt } = await orda.jwt.generate({
  clientId: string,
  clientSecret: string,
  expiresIn?: number,
  permissions?: JWTPermission[]
});
```

**Available Permissions:**
- `quotes:read`
- `offramp:read`
- `onramp:read`
- `transactions:read`
- `recipients:read`
- `recipients:write`

**Default Permissions:**
`['quotes:read', 'offramp:read', 'onramp:read', 'transactions:read', 'recipients:read']`

**Note:** HMAC authentication bypasses permission checks and has full access to all operations.

### Recipients API

```typescript
// Create recipient
await orda.recipients.create({
  name: string,
  cryptoSettlementDetails?: CryptoSettlementDetails,
  fiatSettlementDetails?: FiatSettlementDetails,
  kycInformation?: KYCInformation
});

// List recipients with pagination and filters
await orda.recipients.list({
  page?: number,              // Page number (default: 1)
  limit?: number,             // Items per page (default: 50, max: 100)
  filters?: {
    toAddress?: string,       // Filter by crypto settlement address
    name?: string,            // Filter by recipient name (partial match)
    pixKey?: string,          // Filter by PIX key (partial match)
    taxId?: string,           // Filter by Tax ID (partial match)
    chainIds?: string | string[] // Filter by Chain IDs (comma-separated or array)
  }
});

// Update recipient
await orda.recipients.updateSettlement({
  recipientId: string,
  cryptoSettlementDetails?: CryptoSettlementDetails,
  fiatSettlementDetails?: FiatSettlementDetails,
  kycInformation?: KYCInformation
});

// Deactivate recipient
await orda.recipients.deactivate({
  recipientId: string
});
```

**List Recipients Examples:**

```typescript
// List all recipients (first page)
const response = await orda.recipients.list();
console.log(`Total: ${response.pagination.totalCount}`);

// With pagination
const response = await orda.recipients.list({
  page: 2,
  limit: 20
});

// Filter by name
const response = await orda.recipients.list({
  filters: {
    name: 'John'
  }
});

// Filter by chain IDs
const response = await orda.recipients.list({
  filters: {
    chainIds: ['1', '8453', '42161'] // Ethereum, Base, Arbitrum
  }
});

// Multiple filters
const response = await orda.recipients.list({
  page: 1,
  limit: 10,
  filters: {
    name: 'John',
    chainIds: ['8453'],
    toAddress: '0x123...'
  }
});
```

### Quote API

```typescript
// Request quote with recipient
await orda.quote.request({
  fromChain: string,
  fromToken: string,
  fromAddress: string,
  intent: {
    method: 'usd' | 'fromAmount' | 'toAmount',
    value: string
  },
  recipientId: string,
  timeout?: number
});

// OR request quote with inline settlement (no recipient needed)
await orda.quote.request({
  fromChain: string,
  fromToken: string,
  fromAddress: string,
  intent: {
    method: 'usd' | 'fromAmount' | 'toAmount',
    value: string
  },
  settlementDetails: {
    toChain: string,
    toToken: string,
    toAddress: string
  },
  timeout?: number
});
```

### Transaction API

```typescript
// Get transaction status
await orda.transactions.getStatus({
  transactionId?: string,
  sourceHash?: string,
  destinationHash?: string
});

// Get successful transactions
await orda.transactions.getSuccessfulTransactions();

// Wait for transaction completion with polling
await orda.transactions.waitForCompletion(transactionId, {
  intervalMs: 5000,
  timeoutMs: 600000,
  onStatusUpdate: (status) => console.log(status)
});
```

### Off-Ramp API (Crypto to Fiat)

```typescript
// Request off-ramp quote with recipient
await orda.offRamp.requestQuote({
  fromChain: string,
  fromToken: string,
  fromAddress: string,
  intent: Intent,
  recipientId: string
});

// OR request off-ramp quote with inline KYC/settlement (no recipient needed)
await orda.offRamp.requestQuote({
  fromChain: string,
  fromToken: string,
  fromAddress: string,
  intent: Intent,
  kycInformation: {
    taxId: string,
    taxIdCountry: string,
    email: string,
    name: string
  },
  fiatSettlementDetails: {
    toCurrency: string,
    pixKey?: string,
    bankAccount?: string,
    bankBranch?: string,
    bankAccountType?: string,
    iban?: string,
    cbuCvu?: string
  }
});

// Get off-ramp status
await orda.offRamp.getStatus(transactionId);

// Wait for completion
await orda.offRamp.waitForCompletion(transactionId, options);
```

### On-Ramp API (Fiat to Crypto)

```typescript
// Request on-ramp quote with recipient
await orda.onRamp.requestQuote({
  fromCurrency: string,
  intent: Intent,
  recipientId: string,
  taxId: string,        // required: payer CPF/CNPJ
  taxIdCountry: string  // required: ISO 3166-1 alpha-3, e.g. 'BRA'
});

// OR request on-ramp quote with inline settlement (no recipient needed)
await orda.onRamp.requestQuote({
  fromCurrency: string,
  intent: Intent,
  settlementDetails: {
    toChain: string,
    toToken: string,
    toAddress: string
  },
  taxId: string,        // required: payer CPF/CNPJ
  taxIdCountry: string  // required: ISO 3166-1 alpha-3, e.g. 'BRA'
});

// Get on-ramp status
await orda.onRamp.getStatus(transactionId);

// Wait for completion
await orda.onRamp.waitForCompletion(transactionId, options);
```


## TypeScript Support

The SDK is written in TypeScript and provides full type definitions out of the box.

```typescript
import {
  OrdaSDK,
  QuoteRequestParams,
  TransactionStatus,
  OrdaError,
  JWTPermission,
  GenerateJWTRequest,
  GenerateJWTResponse
} from '@ordanetwork/sdk';
```

## Error Handling

```typescript
try {
  const quote = await orda.quote.request({...});
} catch (error) {
  if (error instanceof OrdaError) {
    console.error('Status Code:', error.statusCode);
    console.error('Error Code:', error.code);
    console.error('Details:', error.details);
  }
}
```

## Smart Wallets

The SDK no longer ships a client-side smart-wallet wrapper. Recipient
auto-generation continues to work server-side — create a recipient
without `toAddress` and the response includes a fresh ERC-4337 wallet:

```typescript
const recipient = await orda.recipients.create({
  name: 'My Recipient',
  cryptoSettlementDetails: {
    toChain: '8453', // Base
    toToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913' // USDC
    // toAddress omitted → smart wallet generated server-side
  }
});

if (recipient.smartWallet) {
  console.log('Address:', recipient.smartWallet.address);
  // Save recipient.smartWallet.privateKey to a secure secret store (vault/KMS) — never log it.
}
```

For client-side operations (UserOperations, batching, etc.) use any
ERC-4337-compatible library: Alchemy Account Kit, ZeroDev, Biconomy, or
`viem`'s account-abstraction utilities.

> Looking for the drop-in React widget? It moved to
> [`@ordanetwork/widget`](https://www.npmjs.com/package/@ordanetwork/widget).
> Install it alongside `@ordanetwork/sdk@^2.0.0`.

## Complete Example

```javascript
const { OrdaSDK } = require('@ordanetwork/sdk');

async function main() {
  const orda = new OrdaSDK({
    clientId: process.env.ORDA_CLIENT_ID,
    clientSecret: process.env.ORDA_CLIENT_SECRET,
    debug: true,
  });

  // List recipients
  const recipientsList = await orda.recipients.list({
    page: 1,
    limit: 10,
    filters: {
      chainIds: ['8453'] // Filter by Base chain
    }
  });
  console.log(`Found ${recipientsList.pagination.totalCount} recipients`);

  // Create recipient with smart wallet
  const recipient = await orda.recipients.create({
    name: 'Test Recipient',
    cryptoSettlementDetails: {
      toChain: '8453', // Base
      toToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC
    },
  });
  console.log('Smart wallet:', recipient.smartWallet?.address);

  // Request cross-chain quote with recipient
  const quote = await orda.quote.request({
    fromChain: '1', // Ethereum
    fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
    fromAddress: '0xYourAddress',
    intent: {
      method: 'usd',
      value: '100',
    },
    recipientId: recipient.recipientId,
  });

  // OR request cross-chain quote with inline settlement (no recipient needed)
  const inlineQuote = await orda.quote.request({
    fromChain: '1', // Ethereum
    fromToken: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC
    fromAddress: '0xYourAddress',
    intent: {
      method: 'fromAmount',
      value: '100000000', // 100 USDC (6 decimals)
    },
    settlementDetails: {
      toChain: '137', // Polygon
      toToken: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', // USDC on Polygon
      toAddress: '0xRecipientAddress',
    },
  });

  // Monitor transaction
  await orda.transactions.waitForCompletion(quote.transactionId, {
    intervalMs: 10000,
    timeoutMs: 600000,
    onStatusUpdate: (status) => console.log('Status:', status),
  });

  // Off-ramp example (Crypto to Fiat)
  const offRampRecipient = await orda.recipients.create({
    name: 'Fiat Recipient',
    fiatSettlementDetails: {
      toCurrency: 'BRL',
      pixKey: 'user@example.com',
    },
    kycInformation: {
      taxId: '12345678901',
      taxIdCountry: 'BRA',
      email: 'user@example.com',
      name: 'User Name',
    },
  });

  const offRampQuote = await orda.offRamp.requestQuote({
    fromChain: '8453',
    fromToken: '0xE9185Ee218cae427aF7B9764A011bb89FeA761B4', // BRZ
    fromAddress: '0xYourAddress',
    intent: {
      method: 'fromAmount',
      value: '10000000000000000000', // 10 BRZ
    },
    recipientId: offRampRecipient.recipientId,
  });

  // OR off-ramp with inline KYC/settlement (no recipient needed)
  const inlineOffRampQuote = await orda.offRamp.requestQuote({
    fromChain: '8453',
    fromToken: '0xE9185Ee218cae427aF7B9764A011bb89FeA761B4', // BRZ
    fromAddress: '0xYourAddress',
    intent: {
      method: 'fromAmount',
      value: '10000000000000000000', // 10 BRZ
    },
    kycInformation: {
      taxId: '12345678901',
      taxIdCountry: 'BRA',
      email: 'user@example.com',
      name: 'User Name',
    },
    fiatSettlementDetails: {
      toCurrency: 'BRL',
      pixKey: 'user@example.com',
    },
  });

  // On-ramp example (Fiat to Crypto)
  const onRampQuote = await orda.onRamp.requestQuote({
    fromCurrency: 'BRL',
    intent: {
      method: 'fromAmount',
      value: '100.00',
    },
    recipientId: recipient.recipientId,
    taxId: '11144477735',
    taxIdCountry: 'BRA',
  });
  console.log('PIX payment key:', onRampQuote.depositInstructions.pixKey);

  // OR on-ramp with inline settlement (no recipient needed)
  const inlineOnRampQuote = await orda.onRamp.requestQuote({
    fromCurrency: 'BRL',
    intent: {
      method: 'fromAmount',
      value: '100.00',
    },
    settlementDetails: {
      toChain: '8453', // Base
      toToken: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913', // USDC
      toAddress: '0xRecipientAddress',
    },
    taxId: '11144477735',
    taxIdCountry: 'BRA',
  });
  console.log('PIX payment key:', inlineOnRampQuote.depositInstructions.pixKey);
}

main().catch(console.error);
```

## Dependencies

`@ordanetwork/sdk@2.0.0` ships with **zero runtime dependencies**. It
uses only the Fetch API (Node 18+ / browser native) and Web Crypto /
`node:crypto` for HMAC signing. Account-abstraction libraries are no
longer bundled — bring your own (Alchemy Account Kit, ZeroDev,
Biconomy, viem AA tooling). See the
[v2.0.0 CHANGELOG](./CHANGELOG.md) for the full list of removed exports
and dropped dependencies.

## License

MIT