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

# Asset Configuration

> Per-token NAV pricing configuration and asset management

## Overview

Asset Configuration accounts store the NAV (Net Asset Value) pricing sources and settings for each token in the protocol. Every RWA and stablecoin must have an AssetConfig account before it can be used in trading pairs.

## Account Structure

```rust theme={null}
pub struct AssetConfig {
    pub mint_address: Pubkey,               // Token mint address
    pub nav_data: Vec<NavData>,             // Up to 5 NAV pricing sources
    pub price_difference_bps: u16,          // Maximum price divergence tolerance
    pub paused: bool,                       // Asset-level pause flag
    pub version: u8,                        // Configuration version
    pub asset_type: AssetType,              // Rwa or Stable
    pub used_in_pairs_count: u16,           // Number of pairs using this asset
    pub bump: u8,                           // PDA bump seed
}
```

**PDA Seeds**: `["asset", mint_address]`

### Asset Type

```rust theme={null}
pub enum AssetType {
    Rwa,     // Real World Asset token
    Stable,  // Stablecoin token
}
```

## Instructions

### init\_asset\_config\_account

Register a new token for use in the protocol.

```rust theme={null}
pub fn init_asset_config_account(
    ctx: Context<InitAssetConfigAccount>,
    nav_data: Vec<NavData>,
    price_difference_bps: u16,
    asset_type: AssetType,
) -> Result<()>
```

#### Parameters

| Parameter              | Type           | Description                                   |
| ---------------------- | -------------- | --------------------------------------------- |
| `nav_data`             | `Vec<NavData>` | 1-5 NAV pricing sources                       |
| `price_difference_bps` | `u16`          | Maximum allowed price divergence (0-9900 BPS) |
| `asset_type`           | `AssetType`    | Whether token is RWA or Stablecoin            |

#### Required Accounts

```rust theme={null}
#[derive(Accounts)]
pub struct InitAssetConfigAccount<'info> {
    #[account(
        init,
        payer = admin,
        space = 8 + AssetConfig::INIT_SPACE,
        seeds = [ASSET_CONFIG_PREFIX, mint_address.key().as_ref()],
        bump,
    )]
    pub asset_config: Account<'info, AssetConfig>,

    pub mint_address: InterfaceAccount<'info, Mint>,

    #[account(mut)]
    pub admin: Signer<'info>,

    // Fee vault ATA owned by the global program authority
    #[account(
        init_if_needed,
        payer = admin,
        associated_token::mint = mint_address,
        associated_token::authority = program_authority,
        associated_token::token_program = token_program,
    )]
    pub fee_vault_token_account: InterfaceAccount<'info, TokenAccount>,

    /// CHECK: Global PDA used as the protocol fee-vault authority
    #[account(
        seeds = [PROGRAM_AUTHORITY_PREFIX],
        bump,
    )]
    pub program_authority: UncheckedAccount<'info>,

    #[account(
        seeds = [GLOBAL_CONFIG_PREFIX],
        bump = global_config.bump,
        has_one = admin
    )]
    pub global_config: Account<'info, GlobalConfig>,

    pub system_program: Program<'info, System>,
    pub token_program: Interface<'info, TokenInterface>,
    pub associated_token_program: Program<'info, AssociatedToken>,
}
```

#### Behavior

* Creates AssetConfig PDA for the token mint
* Creates the fee-vault ATA owned by `program_authority` for fee collection
* Validates NAV data (1-5 sources, decimals ≤ 9) and `price_difference_bps <= 9900`
* Sets `paused` to `false` by default
* Sets `used_in_pairs_count` to 0

#### Access Control

**Access**: Admin only

#### Example

```typescript theme={null}
import { BN } from "@coral-xyz/anchor";

// NAV source: Read price from a fixed account address
const navData = [{
  u64FixedAddress: {
    navAccountAddress: priceOracleAccount,
    navPriceOffset: 0,
    priceDecimals: 6,
  }
}];

await program.methods
  .initAssetConfigAccount(
    navData,
    100,  // 1% max price divergence
    { rwa: {} }  // Asset type
  )
  .accounts({
    assetConfig,
    mintAddress: rwaMint,
    admin: adminWallet.publicKey,
    feeVaultTokenAccount,
    programAuthority,
    globalConfig,
    systemProgram: SystemProgram.programId,
    tokenProgram: TOKEN_PROGRAM_ID,
    associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
  })
  .rpc();
```

***

### update\_asset\_config\_account

Update NAV sources for an existing asset.

```rust theme={null}
pub fn update_asset_config_account(
    ctx: Context<UpdateAssetConfigAccount>,
    nav_data: Vec<NavData>,
    price_difference_bps: u16,
    asset_type: AssetType,
) -> Result<()>
```

#### Parameters

| Parameter              | Type           | Description                                        |
| ---------------------- | -------------- | -------------------------------------------------- |
| `nav_data`             | `Vec<NavData>` | Updated NAV pricing sources (1-5)                  |
| `price_difference_bps` | `u16`          | Updated price divergence tolerance (0-9900 BPS)    |
| `asset_type`           | `AssetType`    | New asset type (change blocked if asset is in use) |

#### Required Accounts

```rust theme={null}
#[derive(Accounts)]
pub struct UpdateAssetConfigAccount<'info> {
    #[account(
        mut,
        seeds = [ASSET_CONFIG_PREFIX, mint_address.key().as_ref()],
        bump = asset_config.bump,
    )]
    pub asset_config: Account<'info, AssetConfig>,

    pub mint_address: InterfaceAccount<'info, Mint>,

    pub admin: Signer<'info>,

    #[account(
        seeds = [GLOBAL_CONFIG_PREFIX],
        bump = global_config.bump,
        has_one = admin
    )]
    pub global_config: Account<'info, GlobalConfig>,
}
```

#### Behavior

* Updates NAV sources and price divergence threshold after validating `price_difference_bps <= 9900`
* Can update `asset_type`, but change is blocked if `used_in_pairs_count > 0`
* Does not affect pause state or usage count

#### Access Control

**Access**: Admin only

#### Example

```typescript theme={null}
// Add a second NAV source (Pyth oracle)
const updatedNavData = [
  {
    u64FixedAddress: {
      navAccountAddress: primaryOracle,
      navPriceOffset: 0,
      priceDecimals: 6,
    }
  },
  {
    pythPush: {
      pythPushAccountAddress: pythAccount,
      feedId: Array.from(Buffer.from("40ac3329933a6b5b65cf31496018c5764ac0567316146f7d0de00095886b480d", "hex")),
      maxAgeSecs: new BN(86_400),
      maxConfBps: 100,
    }
  }
];

await program.methods
  .updateAssetConfigAccount(
    updatedNavData,
    50,  // 0.5% max divergence
    { rwa: {} }  // Asset type
  )
  .accounts({
    assetConfig,
    admin: adminWallet.publicKey,
    mintAddress: rwaMint,
    globalConfig,
  })
  .rpc();
```

***

### set\_paused\_for\_asset

Set the pause state for a specific asset.

```rust theme={null}
pub fn set_paused_for_asset(
    ctx: Context<SetPausedForAsset>,
    paused: bool,
) -> Result<()>
```

#### Parameters

| Parameter | Type   | Description     |
| --------- | ------ | --------------- |
| `paused`  | `bool` | New pause state |

#### Required Accounts

```rust theme={null}
#[derive(Accounts)]
pub struct SetPausedForAsset<'info> {
    #[account(
        seeds = [GLOBAL_CONFIG_PREFIX],
        bump = global_config.bump,
        has_one = admin,
    )]
    pub global_config: Account<'info, GlobalConfig>,

    #[account(
        mut,
        seeds = [ASSET_CONFIG_PREFIX, mint_address.key().as_ref()],
        bump = asset_config.bump,
    )]
    pub asset_config: Account<'info, AssetConfig>,

    pub mint_address: UncheckedAccount<'info>,

    #[account(mut)]
    pub admin: Signer<'info>,
}
```

#### Behavior

* Updates asset's pause state
* When paused, all swaps involving this asset are blocked
* Does not affect other assets or global state

#### Access Control

**Access**: Admin only

#### Example

```typescript theme={null}
// Pause an asset
await program.methods
  .setPausedForAsset(true)
  .accounts({
    globalConfig,
    assetConfig,
    mintAddress: rwaMint,
    admin: adminWallet.publicKey,
  })
  .rpc();
```

***

## NAV Data Types

The program supports three types of NAV pricing sources:

### U64FixedAddress

Read price from a fixed byte offset in an on-chain account.

```rust theme={null}
NavData::U64FixedAddress {
    nav_account_address: Pubkey,  // Account containing price data
    nav_price_offset: u16,        // Byte offset to read price
    price_decimals: u8,           // Decimal places (0-9)
}
```

**Use Cases**:

* Custom price oracle accounts
* RWA issuer-published NAV accounts
* Any account with a u64 price at known offset

### Hardcoded

Static price value for stable-value assets.

```rust theme={null}
NavData::Hardcoded {
    hardcoded_price: u64,   // Fixed price value
    price_decimals: u8,     // Decimal places (0-9)
}
```

**Use Cases**:

* Dollar-pegged stablecoins (price = 1.0)
* Assets with contractually fixed prices
* Testing and development

### PythPush

Pyth Network oracle integration.

```rust theme={null}
NavData::PythPush {
    pyth_push_account_address: Pubkey,  // Pyth receiver price update account
    feed_id: [u8; 32],                  // Expected Pyth feed id
    max_age_secs: u64,                  // Maximum accepted price age
    max_conf_bps: u16,                  // Maximum accepted confidence ratio
}
```

**Use Cases**:

* Market-priced assets
* Assets with Pyth price feeds
* High-frequency price updates

<Card title="View Price Source Details" icon="code" href="/svm/instructions/price-sources">
  Complete documentation on NAV pricing configuration and validation
</Card>

***

## Price Aggregation

When multiple NAV sources are configured:

1. **Read All Sources**: Each source returns a price
2. **Normalize**: All prices converted to 9 decimal places
3. **Validate Divergence**: Check all prices within `price_difference_bps`
4. **Average**: Return average of all valid prices

If any source diverges beyond threshold, the function returns 0, blocking swaps.

***

## Error Codes

| Error                                                                    | Description                                                            |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------- |
| `Unauthorized`                                                           | Caller is not admin                                                    |
| `MustProvideAtLeastOneNavData`                                           | No NAV sources provided                                                |
| `Max5NavData`                                                            | More than 5 NAV sources                                                |
| `PriceDecimalsTooLarge`                                                  | Decimals exceed 9                                                      |
| `MustProvideHardcodedPrice`                                              | Hardcoded price is zero                                                |
| `NavMustBePositive`                                                      | NAV source returned a non-positive price                               |
| `InvalidAccountPublicKey`                                                | Required NAV source account was not passed                             |
| `InvalidFeedId` / `InvalidMaxAge` / `MaxAgeTooLarge` / `ConfBpsTooLarge` | Pyth configuration failed scalar validation                            |
| `MissingPythAccount` / `FeedIdMismatch`                                  | Pyth receiver account was missing or did not match the configured feed |
| `OutOfRange`                                                             | `price_difference_bps` exceeds 9900                                    |

***

<Card title="Next: Pair Management" icon="file-code" href="/svm/instructions/pair">
  Learn about trading pair creation and configuration
</Card>
