# DAS API — Digital Asset Standard

## What DAS Covers

The DAS API is a unified interface for ALL Solana digital assets: NFTs, compressed NFTs (cNFTs), fungible SPL tokens, Token-2022 tokens, and inscriptions. Use it instead of parsing raw on-chain accounts — everything is indexed and queryable.

- 10 credits per request
- 2-3 second indexing latency for new assets
- Batch queries up to 1,000 assets
- Includes off-chain metadata (Arweave, IPFS) and token price data
- Pagination starts at page **1** (not 0)
- Max **1,000** results per request

## Choosing the Right Method

| You want to... | Use this method | MCP tool |
|---|---|---|
| Get one asset by mint/ID | `getAsset` | `getAsset` |
| Get many assets by IDs (up to 1000) | `getAssetBatch` | `getAsset` (with array) |
| Get all assets for a wallet | `getAssetsByOwner` | `getAssetsByOwner` |
| Browse a collection | `getAssetsByGroup` | `getAssetsByGroup` |
| Find assets by creator | `getAssetsByCreator` | (via `searchAssets`) |
| Find assets by update authority | `getAssetsByAuthority` | (via `searchAssets`) |
| Search with multiple filters | `searchAssets` | `searchAssets` |
| Get Merkle proof for cNFT | `getAssetProof` | `getAssetProof` |
| Get proofs for multiple cNFTs | `getAssetProofBatch` | `getAssetProofBatch` |
| Get tx history for a cNFT | `getSignaturesForAsset` | `getSignaturesForAsset` |
| Get editions for a master NFT | `getNftEditions` | `getNftEditions` |
| Get token accounts for a mint | `getTokenAccounts` | `getTokenAccounts` |

**Important**: `getAssetsByCreator` does NOT work for pump.fun tokens. The DAS "creator" field refers to Metaplex creators metadata, not the deployer wallet. Use the `getPumpFunGuide` MCP tool for pump.fun patterns.

## The tokenType Parameter

When using `searchAssets` or `getAssetsByOwner` with `showFungible: true`, the `tokenType` parameter controls what's returned:

| tokenType | Returns | Use case |
|---|---|---|
| `fungible` | SPL tokens and Token-2022 tokens only | Wallet balances, token-gating |
| `nonFungible` | All NFTs (compressed + regular) | Portfolio overview |
| `regularNft` | Legacy and programmable NFTs (uncompressed) | Marketplace listings |
| `compressedNft` | cNFTs only | Mass mints, compressed collections |
| `all` | Everything (tokens + NFTs) | Catch-all discovery |

Every `searchAssets` request MUST include a `tokenType`. If omitted, only NFTs and cNFTs are returned (backwards compatibility).

## Display Options

These flags add extra data to responses. Only request what you need:

| Flag | Effect |
|---|---|
| `showFungible` | Include fungible tokens (SPL + Token-2022) with balances and price data |
| `showNativeBalance` | Include SOL balance of the wallet |
| `showCollectionMetadata` | Add collection-level JSON metadata |
| `showGrandTotal` | Return total match count (slower — only use if you need the total) |
| `showInscription` | Append inscription and SPL-20 data |
| `showZeroBalance` | Include zero-balance token accounts |

## Core Query Patterns

### Get a Single Asset

```typescript
// Via MCP tool
getAsset({ id: "ASSET_MINT_ADDRESS" })

// Via API
{
  jsonrpc: '2.0',
  id: 'my-id',
  method: 'getAsset',
  params: { id: 'ASSET_MINT_ADDRESS' }
}
```

Response includes: `content` (metadata, name, symbol, image), `ownership` (owner), `compression` (compressed status), `royalty`, `creators`, `token_info` (for fungibles: balance, decimals, price_info).

### Get All Assets for a Wallet

Use `getAssetsByOwner` with `showFungible: true` to get NFTs AND tokens in one call:

```typescript
{
  jsonrpc: '2.0',
  id: 'my-id',
  method: 'getAssetsByOwner',
  params: {
    ownerAddress: 'WALLET_ADDRESS',
    page: 1,
    limit: 1000,
    displayOptions: {
      showFungible: true,
      showNativeBalance: true,
      showCollectionMetadata: true,
    }
  }
}
```

This is the best single call for building a portfolio view.

### Browse a Collection

Use `getAssetsByGroup` with `groupKey: "collection"`:

```typescript
{
  jsonrpc: '2.0',
  id: 'my-id',
  method: 'getAssetsByGroup',
  params: {
    groupKey: 'collection',
    groupValue: 'COLLECTION_ADDRESS',
    page: 1,
    limit: 1000,
  }
}
```

### Search with Filters

`searchAssets` supports complex multi-criteria queries:

```typescript
{
  jsonrpc: '2.0',
  id: 'my-id',
  method: 'searchAssets',
  params: {
    ownerAddress: 'WALLET_ADDRESS',         // optional
    grouping: ['collection', 'COLLECTION'], // optional
    creatorAddress: 'CREATOR_ADDRESS',      // optional
    creatorVerified: true,                  // optional
    compressed: true,                       // optional
    burnt: false,                           // optional
    tokenType: 'nonFungible',              // REQUIRED
    page: 1,
    limit: 100,
    sortBy: { sortBy: 'created', sortDirection: 'desc' },
  }
}
```

### Batch Lookups

Use `getAssetBatch` to fetch up to 1,000 assets in one request instead of multiple `getAsset` calls:

```typescript
{
  jsonrpc: '2.0',
  id: 'my-id',
  method: 'getAssetBatch',
  params: { ids: ['ASSET_1', 'ASSET_2', 'ASSET_3'] }
}
```

## Fungible Token Data

When `showFungible: true` is set, fungible tokens include a `token_info` field:

```json
{
  "token_info": {
    "symbol": "JitoSOL",
    "balance": 35688813508,
    "supply": 5949594702758293,
    "decimals": 9,
    "token_program": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    "associated_token_address": "H7iLu4DPFpzEx1AGN8BCN7Qg966YFndt781p6ukhgki9",
    "price_info": {
      "price_per_token": 56.47,
      "total_price": 2015.68,
      "currency": "USDC"
    }
  }
}
```

Token-2022 tokens additionally include a `mint_extensions` field with parsed extension data (transfer fees, metadata, etc.).

## Compressed NFT Operations

### Getting Merkle Proofs

Compressed NFTs live in Merkle trees. To transfer or burn a cNFT, you need its proof:

```typescript
// Single proof
{
  method: 'getAssetProof',
  params: { id: 'CNFT_ASSET_ID' }
}

// Batch proofs
{
  method: 'getAssetProofBatch',
  params: { ids: ['CNFT_1', 'CNFT_2'] }
}
```

Proof response:

```json
{
  "root": "...",
  "proof": ["...", "..."],
  "node_index": 12345,
  "leaf": "...",
  "tree_id": "MERKLE_TREE_ADDRESS"
}
```

### cNFT Transaction History

Standard `getSignaturesForAddress` does NOT work for compressed NFTs. Use `getSignaturesForAsset` instead:

```typescript
{
  method: 'getSignaturesForAsset',
  params: { id: 'CNFT_ASSET_ID', page: 1, limit: 100 }
}
```

## Pagination

DAS supports two pagination mechanisms:

### Page-Based (recommended for most use cases)

Start at `page: 1`, request up to `limit: 1000`. Loop: collect `result.items`, break when `items.length < limit`, else increment page.

### Cursor-Based (recommended for large datasets 500k+)

Avoids database scanning overhead at high page numbers. Requires `sortBy: { sortBy: 'id', sortDirection: 'asc' }`. On each iteration, pass `cursor` from the previous `result.cursor`. Break when `result.items` is empty.

Cursor pagination only works when sorting by `id`.

### Sorting Options

| sortBy | Description |
|---|---|
| `id` | Sort by asset ID in binary (default, required for cursor pagination) |
| `created` | Sort by creation date |
| `recent_action` | Sort by last update date (not recommended) |
| `none` | No sorting (fastest but inconsistent pagination) |

## SDK Usage

```typescript
// TypeScript — DAS methods are on the root namespace
const assets = await helius.getAssetsByOwner({ ownerAddress: 'ADDR', page: 1, limit: 100, displayOptions: { showFungible: true } });
const asset = await helius.getAsset({ id: 'ASSET_ID' });
const results = await helius.searchAssets({ grouping: ['collection', 'COLLECTION_ADDR'] });
```

```rust
// Rust — DAS methods via helius.rpc()
let assets = helius.rpc().get_assets_by_owner("ADDR").await?;
```

## Building Common Features

### Portfolio View
1. `getAssetsByOwner` with `showFungible: true, showNativeBalance: true` for the full picture
2. Filter `token_info.price_info` for tokens with USD prices
3. Use `getAsset` for detail views on individual assets

### NFT Marketplace / Gallery
1. `getAssetsByGroup` for collection browsing pages
2. `searchAssets` for search/filter functionality
3. `getAsset` for individual NFT detail pages
4. Set up webhooks (see Helius docs at `docs.helius.dev`) to monitor sales and listings

### Token-Gated Application
1. `searchAssets` with `ownerAddress` + `grouping: ['collection', 'REQUIRED_COLLECTION']`
2. If `result.total > 0`, the user holds the required NFT
3. For fungible gating, check `token_info.balance` against a threshold

## Common Mistakes

- Forgetting `tokenType` in `searchAssets` — returns only NFTs by default, missing fungible tokens
- Using `page: 0` — DAS pagination starts at 1, not 0
- Using `getAssetsByCreator` for pump.fun tokens — it won't work; use `getAsset` with the mint directly
- Using `getSignaturesForAddress` for cNFTs — use `getSignaturesForAsset` instead
- Not using batch methods — `getAssetBatch` is far more efficient than multiple `getAsset` calls
- Requesting `showGrandTotal` on every query — it's slower; only use when you need the count
- Using page-based pagination for huge datasets (500k+) — switch to cursor-based
