# nCredit Vault

## Contract Addresses & Configuration

```jsx
// nCREDIT vault addresses (same on both Plume and Eth chains)
const VAULT_ADDRESS = "0xa5f78b2a0ab85429d2dfbf8b60abc70f4cec066c"
const TELLER_ADDRESS = "0x27200293aac3d04d2b305244f78d013b3c759f9d"
const ACCOUNTANT_ADDRESS = "0x486e0362b0641c0fca21cac2e317f6e21a8b19f3"

const INFRA = {
  predicateProxyAddress: "0x6104fe10ca937a086ba7AdbD0910A4733d380cB6",
  nativeFeeTokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  bridgeMessageGas: 100000,
}

const PLUME_MAINNET = {
  chainId: 98866,
  layerZeroEndpointId: 30370,
  atomicQueueAddress: "0x220dc6d4569c1f406d532f9633d5be5bc86e8264",
  depositToken: {
    address: "0xdddd73f5df1f0dc31373357beac77545dc5a6f3f",
    decimals: 6,
    symbol: "pUSD",
    defaultSlippagePercentage: 0.005,
  }
}

const ETH_MAINNET = {
  chainId: 1,
  layerZeroEndpointId: 30101,
  atomicQueueAddress: "0x220dc6d4569c1f406d532f9633d5be5bc86e8264",
  depositToken: {
    address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    decimals: 6,
    symbol: "USDC",
    defaultSlippagePercentage: 0.005,
  }
}

const VAULT_DECIMALS = 6
const PUSD_ADDRESS = PLUME_MAINNET.depositToken.address
const USDC_ADDRESS = ETH_MAINNET.depositToken.address
const PLUME_ATOMIC_QUEUE_ADDRESS = PLUME_MAINNET.atomicQueueAddress
const ETH_ATOMIC_QUEUE_ADDRESS = ETH_MAINNET.atomicQueueAddress
```

***

## Summary: 6 Distinct Paths

Deposits (3 paths):

* USDC Ethereum -> nCREDIT Plume (cross-chain; 6 ops)
* pUSD Plume -> nCREDIT Plume (same-chain; 5 ops)
* USDC Ethereum -> nCREDIT Ethereum (same-chain; 5 ops)

Redemptions (3 paths):

* nCREDIT Plume -> USDC Ethereum (cross-chain; 7 ops)
* nCREDIT Plume -> pUSD Plume (same-chain; 5 ops)
* nCREDIT Ethereum -> USDC Ethereum (same-chain; 5 ops)

***

## DEPOSIT FLOWS

### Path 1: Ethereum -> Plume (Cross-Chain Deposit)

{% stepper %}
{% step %}

### Compliance Check (isDepositAndBridge=true)

```http
GET https://api.nest.credit/v1/user/{userAddress}/compliance?chainId=1&isDepositAndBridge=true
```

Response: `{ data: { isCompliant: boolean, predicateMessage: {...} } }`
{% endstep %}

{% step %}

### Exchange Rate Query

```solidity
// Call accountant on Ethereum
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(USDC_ADDRESS) -> rateInQuote
// Returns rate in USDC decimals (6), e.g., 1050000 = 1.05 USDC per nCREDIT share
```

{% endstep %}

{% step %}

### Calculate Minimum Mint

```jsx
// Step 3a: Calculate expected vault shares
const oneShare = 10n ** BigInt(VAULT_DECIMALS) // 10^6 = 1000000n
const exchangeAmount = (depositAmount * oneShare) / rateInQuote

// Step 3b: Apply slippage protection
const slippageFactor = 1 - ETH_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const minimumMint = (exchangeAmount * slippageBigInt) / 1_000_000n

// Example: 1000 USDC deposit with 1.05 rate and 0.5% slippage
// exchangeAmount = (1000000000n * 1000000n) / 1050000n = 952380952n
// minimumMint = (952380952n * 995000n) / 1000000n = 947619047n
```

{% endstep %}

{% step %}

### Calculate Bridge Fee

```solidity
// Call teller to preview LayerZero bridge fee using expected share amount
const bridgeData = {
  chainSelector: PLUME_MAINNET.layerZeroEndpointId,
  destinationChainReceiver: userAddress,
  bridgeFeeToken: INFRA.nativeFeeTokenAddress,
  messageGas: INFRA.bridgeMessageGas,
  data: "0x"
}
Teller(TELLER_ADDRESS).previewFee(exchangeAmount, bridgeData) -> bridgeFee
```

{% endstep %}

{% step %}

### Token Approval

```solidity
// Approve USDC to predicate proxy on Ethereum
USDC.approve(INFRA.predicateProxyAddress, depositAmount)
```

{% endstep %}

{% step %}

### Cross-Chain Deposit

```solidity
// Execute deposit and bridge transaction on Ethereum
PredicateProxy(INFRA.predicateProxyAddress).depositAndBridge(
  USDC_ADDRESS,
  depositAmount,
  minimumMint,
  bridgeData,
  TELLER_ADDRESS,
  predicateMessage
) { value: bridgeFee }
```

Result: USDC deposited on Ethereum, nCREDIT minted on Plume
{% endstep %}
{% endstepper %}

***

### Path 2: Plume -> Plume (Same-Chain Deposit)

{% stepper %}
{% step %}

### Compliance Check

```http
GET https://api.nest.credit/v1/user/{userAddress}/compliance?chainId=98866&isDepositAndBridge=false
```

Response: `{ data: { isCompliant: boolean, predicateMessage: {...} } }`
{% endstep %}

{% step %}

### Exchange Rate Query

```solidity
// Call accountant on Plume
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(PUSD_ADDRESS) -> rateInQuote
// Returns rate in pUSD decimals (6), e.g., 1050000 = 1.05 pUSD per nCREDIT share
```

{% endstep %}

{% step %}

### Calculate Minimum Mint

```jsx
// Step 3a: Calculate expected vault shares
const oneShare = 10n ** BigInt(VAULT_DECIMALS) // 10^6 = 1000000n
const exchangeAmount = (depositAmount * oneShare) / rateInQuote

// Step 3b: Apply slippage protection
const slippageFactor = 1 - PLUME_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const minimumMint = (exchangeAmount * slippageBigInt) / 1_000_000n
```

{% endstep %}

{% step %}

### Token Approval

```solidity
// Approve pUSD to predicate proxy on Plume
pUSD.approve(INFRA.predicateProxyAddress, depositAmount)
```

{% endstep %}

{% step %}

### Direct Deposit

```solidity
// Execute direct deposit on Plume
PredicateProxy(INFRA.predicateProxyAddress).deposit(
  PUSD_ADDRESS,
  depositAmount,
  minimumMint,
  userAddress,
  TELLER_ADDRESS,
  predicateMessage
)
```

Result: pUSD deposited on Plume, nCREDIT minted on Plume
{% endstep %}
{% endstepper %}

***

### Path 3: Ethereum -> Ethereum (Same-Chain Deposit)

{% stepper %}
{% step %}

### Compliance Check

```http
GET https://api.nest.credit/v1/user/{userAddress}/compliance?chainId=1&isDepositAndBridge=false
```

Response: `{ data: { isCompliant: boolean, predicateMessage: {...} } }`
{% endstep %}

{% step %}

### Exchange Rate Query

```solidity
// Call accountant on Ethereum
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(USDC_ADDRESS) -> rateInQuote
// Returns rate in USDC decimals (6), e.g., 1050000 = 1.05 USDC per nCREDIT share
```

{% endstep %}

{% step %}

### Calculate Minimum Mint

```jsx
// Step 3a: Calculate expected vault shares
const oneShare = 10n ** BigInt(VAULT_DECIMALS) // 10^6 = 1000000n
const exchangeAmount = (depositAmount * oneShare) / rateInQuote

// Step 3b: Apply slippage protection
const slippageFactor = 1 - ETH_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const minimumMint = (exchangeAmount * slippageBigInt) / 1_000_000n
```

{% endstep %}

{% step %}

### Token Approval

```solidity
// Approve USDC to predicate proxy on Ethereum
USDC.approve(INFRA.predicateProxyAddress, depositAmount)
```

{% endstep %}

{% step %}

### Direct Deposit

```solidity
// Execute direct deposit on Ethereum
PredicateProxy(INFRA.predicateProxyAddress).deposit(
  USDC_ADDRESS,
  depositAmount,
  minimumMint,
  userAddress,
  TELLER_ADDRESS,
  predicateMessage
)
```

Result: USDC deposited on Ethereum, nCREDIT minted on Ethereum
{% endstep %}
{% endstepper %}

***

## REDEMPTION FLOWS

### Path 1: Plume -> Ethereum (Cross-Chain Redemption)

{% stepper %}
{% step %}

### Preview Bridge Fee

```solidity
// Quote the Plume -> Ethereum share bridge fee
const bridgeData = {
  chainSelector: ETH_MAINNET.layerZeroEndpointId,
  destinationChainReceiver: userAddress,
  bridgeFeeToken: INFRA.nativeFeeTokenAddress,
  messageGas: INFRA.bridgeMessageGas,
  data: "0x"
}
Teller(TELLER_ADDRESS).previewFee(shareAmount, bridgeData) -> bridgeFee
```

{% endstep %}

{% step %}

### Bridge Shares to Ethereum

```solidity
// Bridge nCREDIT shares from Plume to Ethereum
Teller(TELLER_ADDRESS).bridge(
  shareAmount,
  bridgeData
) { value: bridgeFee }
```

{% endstep %}

{% step %}

### Exchange Rate Query for Withdrawal

```solidity
// After the bridge completes, get the current exchange rate on Ethereum
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(USDC_ADDRESS) -> rateInQuote
```

{% endstep %}

{% step %}

### Calculate Atomic Price with Slippage

```jsx
// Calculate atomic price (exchange rate with slippage protection)
const slippageFactor = 1 - ETH_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const atomicPrice = (rateInQuote * slippageBigInt) / 1_000_000n

// Example: If rate is 1050000 (1.05 USDC per share) with 0.5% slippage
// atomicPrice = (1050000n * 995000n) / 1000000n = 1044750n
```

{% endstep %}

{% step %}

### Vault Token Approval

```solidity
// Approve nCREDIT shares to the Ethereum atomic queue
nCREDIT.approve(ETH_ATOMIC_QUEUE_ADDRESS, shareAmount)
```

{% endstep %}

{% step %}

### Create Cross-Chain Withdrawal Request

```solidity
// Create atomic request for USDC on Ethereum
AtomicQueue(ETH_ATOMIC_QUEUE_ADDRESS).updateAtomicRequest(
  VAULT_ADDRESS,
  USDC_ADDRESS,
  {
    deadline: timestamp + (10 * 24 * 60 * 60),
    atomicPrice: atomicPrice,
    offerAmount: shareAmount,
    inSolve: false
  }
)
```

{% endstep %}

{% step %}

### Monitor Cross-Chain Withdrawal

```http
GET https://api.nest.credit/v1/vaults/nest-credit-vault/pending-redemptions?chainId=1&user={userAddress}
```

Result: nCREDIT bridged from Plume to Ethereum, then queued for USDC redemption on Ethereum
{% endstep %}
{% endstepper %}

***

### Path 2: Plume -> Plume (Same-Chain Redemption)

{% stepper %}
{% step %}

### Exchange Rate Query for Withdrawal

```solidity
// Get current exchange rate on Plume
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(PUSD_ADDRESS) -> rateInQuote
```

{% endstep %}

{% step %}

### Calculate Atomic Price with Slippage

```jsx
// Calculate atomic price (exchange rate with slippage protection)
const slippageFactor = 1 - PLUME_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const atomicPrice = (rateInQuote * slippageBigInt) / 1_000_000n
```

{% endstep %}

{% step %}

### Vault Token Approval

```solidity
// Approve nCREDIT shares to the Plume atomic queue
nCREDIT.approve(PLUME_ATOMIC_QUEUE_ADDRESS, shareAmount)
```

{% endstep %}

{% step %}

### Create Same-Chain Withdrawal Request

```solidity
// Create atomic request for pUSD on Plume
AtomicQueue(PLUME_ATOMIC_QUEUE_ADDRESS).updateAtomicRequest(
  VAULT_ADDRESS,
  PUSD_ADDRESS,
  {
    deadline: timestamp + (10 * 24 * 60 * 60),
    atomicPrice: atomicPrice,
    offerAmount: shareAmount,
    inSolve: false
  }
)
```

{% endstep %}

{% step %}

### Monitor Same-Chain Withdrawal

```http
GET https://api.nest.credit/v1/vaults/nest-credit-vault/pending-redemptions?chainId=98866&user={userAddress}
```

Result: nCREDIT queued for pUSD redemption on Plume
{% endstep %}
{% endstepper %}

***

### Path 3: Ethereum -> Ethereum (Same-Chain Redemption)

{% stepper %}
{% step %}

### Exchange Rate Query for Withdrawal

```solidity
// Get current exchange rate on Ethereum
Accountant(ACCOUNTANT_ADDRESS).getRateInQuoteSafe(USDC_ADDRESS) -> rateInQuote
```

{% endstep %}

{% step %}

### Calculate Atomic Price with Slippage

```jsx
// Calculate atomic price (exchange rate with slippage protection)
const slippageFactor = 1 - ETH_MAINNET.depositToken.defaultSlippagePercentage // 0.995
const slippageBigInt = BigInt(Math.floor(slippageFactor * 1e6)) // 995000n
const atomicPrice = (rateInQuote * slippageBigInt) / 1_000_000n
```

{% endstep %}

{% step %}

### Vault Token Approval

```solidity
// Approve nCREDIT shares to the Ethereum atomic queue
nCREDIT.approve(ETH_ATOMIC_QUEUE_ADDRESS, shareAmount)
```

{% endstep %}

{% step %}

### Create Same-Chain Withdrawal Request

```solidity
// Create atomic request for USDC on Ethereum
AtomicQueue(ETH_ATOMIC_QUEUE_ADDRESS).updateAtomicRequest(
  VAULT_ADDRESS,
  USDC_ADDRESS,
  {
    deadline: timestamp + (10 * 24 * 60 * 60),
    atomicPrice: atomicPrice,
    offerAmount: shareAmount,
    inSolve: false
  }
)
```

{% endstep %}

{% step %}

### Monitor Same-Chain Withdrawal

```http
GET https://api.nest.credit/v1/vaults/nest-credit-vault/pending-redemptions?chainId=1&user={userAddress}
```

Result: nCREDIT queued for USDC redemption on Ethereum
{% endstep %}
{% endstepper %}

***

## Key Calculation Formulas

**Minimum Mint (Deposits):**

```jsx
const oneShare = 10n ** BigInt(VAULT_DECIMALS)
const exchangeAmount = (depositAmount * oneShare) / rateInQuote
const slippageMultiplier = BigInt(Math.floor((1 - slippagePercentage) * 1e6))
const minimumMint = (exchangeAmount * slippageMultiplier) / 1_000_000n
```

**Atomic Price (Withdrawals):**

```jsx
const slippageMultiplier = BigInt(Math.floor((1 - slippagePercentage) * 1e6))
const atomicPrice = (rateInQuote * slippageMultiplier) / 1_000_000n
```

Both pUSD on Plume and USDC on Ethereum use 6-decimal quote units in this guide.


---

# 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.nest.credit/developers/evm-integration-guides/ncredit-vault.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.
