# Developer reference

## Abyss Vaults and ATokens

You can find the contracts repository here <https://github.com/abyss-protocol/abyss-vaults.git>

### Table of Contents

* Overview
* Architecture
* Core Components
  * Vault Registry
  * Vault
    * Vault Supply
    * Vault Withdrawal
    * Vault Incentives

### Overview

Abyss vaults allow depositors to earn interest on their assets by lending liquidity to DeepBook margin traders, while holding their share of the vault in a fungible way. Users deposit supported assets, receive yield-bearing ATokens that track their proportional claim, and benefit from automated compounding of incentives. Users can then use their ATokens freely across the DeFi ecosystem.

### Architecture

### Core Components

#### [Vault Registry](https://github.com/abyss-protocol/abyss-vaults/blob/main/sources/vault_registry.move)

Manages vault registration, package versioning, and vault-specific permissions. Enforces one vault per underlying asset type. Enables admins to enable or disable a package version. Verifies the validity of `VaultManagerCap` and `IncentiveManagerCap`.

One can retrieve the vault identifier based on the underlying asset type using the public function:

```move
public fun vault_id<Asset>(registry: &VaultRegistry): ID
```

#### [Vault](https://github.com/abyss-protocol/abyss-vaults/blob/main/sources/vault.move)

The Abyss Vault manages core user operations. It handles user deposits and withdrawals, issues ATokens, synchronizes with the underlying margin pool, and manages incentive compounding.

**Vault Supply**

```move
public fun supply<Asset, AToken>(
    vault: &mut Vault<Asset, AToken>,
    margin_pool: &mut MarginPool<Asset>,
    vault_registry: &VaultRegistry,
    margin_registry: &MarginRegistry,
    supply: Coin<Asset>,
    abyss_supplier_cap: &AbyssSupplierCap,
    referral: Option<ID>,
    clock: &Clock,
    ctx: &mut TxContext,
    ): Coin<AToken>
```

The vault supply takes assets and mints the corresponding amount of ATokens, representing shares in the total value of the vault. Yield is redistributed proportionally to the number of shares held. Integrators of Abyss vaults can set the referral parameter to their `SupplyReferral` object ID to earn referral fees.

**Vault Withdrawal**

```move
public fun withdraw<Asset, AToken>(
    vault: &mut Vault<Asset, AToken>,
    margin_pool: &mut MarginPool<Asset>,
    vault_registry: &VaultRegistry,
    margin_registry: &MarginRegistry,
    withdraw: Coin<AToken>,
    abyss_supplier_cap: &AbyssSupplierCap,
    clock: &Clock,
    ctx: &mut TxContext,
): Coin<Asset>
```

The vault withdrawal burns the given amount of ATokens and returns the corresponding amount of assets to the user. Withdrawals honor a first-in, first-out accounting model—if the vault is mid-cycle on incentive compounding, the contract checkpoints earnings before transferring funds to guarantee everyone receives their share.

### Package Addresses

#### Mainnet

**Package**

| Name         | Version | Chain       | Address                                                              |
| ------------ | ------- | ----------- | -------------------------------------------------------------------- |
| Abyss Vaults | 1       | Sui Mainnet | `0x90a75f641859f4d77a4349d67e518e1dd9ecb4fac079e220fa46b7a7f164e0a5` |

**Objects**

| Name               | Version | Chain       | Object ID                                                            |
| ------------------ | ------- | ----------- | -------------------------------------------------------------------- |
| Vault Registry     | 1       | Sui Mainnet | `0xfac1800074e8ed8eb2baf1e631e8199ccce6b0f6bfd50b5143e1ff47c438aecf` |
| Abyss Supplier Cap | 1       | Sui Mainnet | `0x3d0faab3953525d243275b39cbed465cb310fe2d4dd2c15428b8f7cf5962c2c0` |

**Vaults**

| Asset | Vault ID                                                             | Margin Pool ID                                                       |
| ----- | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
| SUI   | `0x670c12c8ea3981be65b8b11915c2ba1832b4ebde160b03cd7790021920a8ce68` | `0x53041c6f86c4782aabbfc1d4fe234a6d37160310c7ee740c915f0a01b7127344` |
| DEEP  | `0xec54bde40cf2261e0c5d9c545f51c67a9ae5a8add9969c7e4cdfe1d15d4ad92e` | `0x1d723c5cd113296868b55208f2ab5a905184950dd59c48eb7345607d6b5e6af7` |
| WAL   | `0x09b367346a0fc3709e32495e8d522093746ddd294806beff7e841c9414281456` | `0x38decd3dbb62bd4723144349bf57bc403b393aee86a51596846a824a1e0c2c01` |
| USDC  | `0x86cd17116a5c1bc95c25296a901eb5ea91531cb8ba59d01f64ee2018a14d6fa5` | `0xba473d9ae278f10af75c50a8fa341e9c6a1c087dc91a3f23e8048baf67d0754f` |

**ATokens**

| Asset  | Type                                                                                                                                                                      | Icon URL                                         |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| aSUI   | `0x90a75f641859f4d77a4349d67e518e1dd9ecb4fac079e220fa46b7a7f164e0a5::abyss_vault::AToken<0x2::sui::SUI>`                                                                  | <https://d3cny4im7ppv5.cloudfront.net/aSUI.svg>  |
| DBUSDC | `0x90a75f641859f4d77a4349d67e518e1dd9ecb4fac079e220fa46b7a7f164e0a5::abyss_vault::AToken<0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC>` | <https://d3cny4im7ppv5.cloudfront.net/aUSDC.svg> |
| aDEEP  | `0x90a75f641859f4d77a4349d67e518e1dd9ecb4fac079e220fa46b7a7f164e0a5::abyss_vault::AToken<0xdeeb7a4662eec9f2f3def03fb937a663dddaa2e215b8078a284d026b7946c270::deep::DEEP>` | <https://d3cny4im7ppv5.cloudfront.net/aDEEP.svg> |
| aWAL   | `0x90a75f641859f4d77a4349d67e518e1dd9ecb4fac079e220fa46b7a7f164e0a5::abyss_vault::AToken<0x356a26eb9e012a68958082340d4c4116e7f55615cf27affcff209cf0ae544f59::wal::WAL>`   | <https://d3cny4im7ppv5.cloudfront.net/aWAL.svg>  |

### Typescript reference

```typescript
// ============================================================================
// Transaction Building Functions
// ============================================================================

/**
 * Build deposit transaction
 *
 * @param params - Deposit parameters
 * @param userAddress - User's wallet address
 * @param env - Environment (mainnet or testnet)
 * @returns Transaction object ready to be signed
 */
export function buildDepositTransaction(
  params: DepositParams,
  userAddress: string,
  env: Environment = "mainnet",
  coinIds?: string[],
): Transaction {
  const packageId = getVaultPackageId(env);
  const vaultRegistryId = getVaultRegistryId(env);
  const marginRegistryId = getMarginRegistryId(env);
  const supplierCapId = getSupplierCapId(env);

  const tx = new Transaction();

  let depositCoin;

  // Check if this is a SUI vault or another asset
  const isSuiVault = params.assetType === "0x2::sui::SUI";

  if (isSuiVault) {
    // For SUI vaults, split from gas
    const [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(params.amount)]);
    depositCoin = coin;
  } else {
    // For non-SUI vaults, we need to use provided coin IDs
    if (!coinIds || coinIds.length === 0) {
      throw new Error("Coin IDs required for non-SUI vault deposits");
    }

    // Merge all coins if multiple
    let primaryCoin;
    if (coinIds.length === 1) {
      primaryCoin = tx.object(coinIds[0]);
    } else {
      const [firstCoin, ...restCoins] = coinIds;
      tx.mergeCoins(
        tx.object(firstCoin),
        restCoins.map((id) => tx.object(id)),
      );
      primaryCoin = tx.object(firstCoin);
    }

    // Split the exact amount needed
    const [coin] = tx.splitCoins(primaryCoin, [tx.pure.u64(params.amount)]);
    depositCoin = coin;
  }

  
  // Determine the appropriate referral address based on asset type
  let optionAddress: string;
  if (params.assetType.includes("::deep::")) {
    // DEEP token address
    optionAddress = "0x434c4d10328fe29206ae4c7a42869b07a4eb4619a48b8e502604287417fea220";
  } else if (params.assetType.includes("::wal::")) {
    // WAL token address
    optionAddress = "0xb29d0f48cacbee7be4dab1524a0f995f41f33bd5fdb05492f69af85738dc6c56";
  } else if (params.assetType.includes("::usdc::")) {
    // USDC token address
    optionAddress = "0xba436b3f0e57600e9318c2e03c51b940612d8b0d4df18ad9f31c203f95cad122";
  } else if (params.assetType === "0x2::sui::SUI") {
    // SUI token address
    optionAddress = "0x695b391423801750827e0b99792a7cd5e41bee3d90b2af03fc99197938c6c98d";
  } else {
    throw new Error("Unsupported asset type for deposit: " + params.assetType);
  }

  // Call deposit function
  const [atokenCoin] = tx.moveCall({
    target: `${packageId}::abyss_vault::supply`,
    arguments: [
      tx.object(params.vaultId),
      tx.object(params.marginPoolId),
      tx.object(vaultRegistryId),
      tx.object(marginRegistryId),
      depositCoin,
      tx.object(supplierCapId),
      tx.pure.option("id", optionAddress),
      tx.object(CLOCK_ID),
    ],
    typeArguments: [params.assetType, params.atokenType],
  });

  // Transfer ATokens to user
  tx.transferObjects([atokenCoin], userAddress);

  return tx;
}

/**
 * Build withdraw transaction
 *
 * @param params - Withdraw parameters
 * @param userAddress - User's wallet address
 * @param env - Environment (mainnet or testnet)
 * @returns Transaction object ready to be signed
 */
export function buildWithdrawTransaction(
  params: WithdrawParams,
  userAddress: string,
  env: Environment = "mainnet",
): Transaction {
  const packageId = getVaultPackageId(env);
  const vaultRegistryId = getVaultRegistryId(env);
  const marginRegistryId = getMarginRegistryId(env);
  const supplierCapId = getSupplierCapId(env);

  const tx = new Transaction();

  // If multiple AToken coins, merge them first
  let atokenCoin;
  if (params.atokenCoinIds.length === 1) {
    atokenCoin = tx.object(params.atokenCoinIds[0]);
  } else if (params.atokenCoinIds.length > 1) {
    // Merge all coins into the first one
    const [firstCoin, ...restCoins] = params.atokenCoinIds;
    tx.mergeCoins(
      tx.object(firstCoin),
      restCoins.map((id) => tx.object(id)),
    );
    atokenCoin = tx.object(firstCoin);
  } else {
    throw new Error("No AToken coins provided for withdrawal");
  }

  // Split the exact amount to withdraw
  const [withdrawCoin] = tx.splitCoins(atokenCoin, [
    tx.pure.u64(params.atokenAmount),
  ]);

  // Call withdraw function
  const [assetCoin] = tx.moveCall({
    target: `${packageId}::abyss_vault::withdraw`,
    arguments: [
      tx.object(params.vaultId),
      tx.object(params.marginPoolId),
      tx.object(vaultRegistryId),
      tx.object(marginRegistryId),
      withdrawCoin,
      tx.object(supplierCapId),
      tx.object(CLOCK_ID),
    ],
    typeArguments: [params.assetType, params.atokenType],
  });

  // Transfer withdrawn assets to user
  tx.transferObjects([assetCoin], userAddress);

  return tx;
}

```

### Resources

* [DeepBook Margin Documentation](https://docs.sui.io/standards/deepbook-margin)
* [Abyss Vaults Move Registry Reference](https://www.moveregistry.com/package/@abyssonsui/abyss-vaults)
