> For the complete documentation index, see [llms.txt](https://docs.elara.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.elara.fi/protocol-reference/guides/integration-guide.md).

# Integration Guide

Developer guide for integrating with the Elara protocol on-chain and off-chain.

## Prerequisites

All mint and redeem operations require:

1. **KYC approval** — both `msg.sender` and `recipient` must be approved in `KYCRegistry`
2. **Token support** — the collateral token must be registered in `TokenRegistry` with the target operation (mint/redeem) enabled
3. **ERC20 approval** — caller must approve `Vault` to spend the input token before calling

## Reading Protocol State

{% tabs %}
{% tab title="Solidity" %}

```solidity
IVault vault = IVault(VAULT_ADDRESS);
ITokenRegistry registry = ITokenRegistry(TOKEN_REGISTRY_ADDRESS);
IKYCRegistry kyc = IKYCRegistry(KYC_REGISTRY_ADDRESS);
IElUSDStake staking = IElUSDStake(STAKING_ADDRESS);

// Check KYC
bool approved = kyc.isKycApproved(userAddress);

// Get token config
ITokenRegistry.TokenConfig memory config = registry.getTokenConfig(USDC);

// Preview mint before executing
(uint256 netAmount, uint256 fee, uint256 elUSDOut) = vault.previewMint(USDC, 1000e6);

// Preview redeem
(uint256 tokenOut, uint256 redeemFee, bool willQueue) = vault.previewRedeem(USDC, 1000e18);

// Check staking state
uint256 price    = staking.sharePrice();    // elUSD per sElUSD (1e18 scale)
uint256 totalBal = staking.totalElUSD();
```

{% endtab %}

{% tab title="ethers.js" %}

```typescript
const vault = new ethers.Contract(VAULT_ADDRESS, IVault_ABI, provider);
const kyc   = new ethers.Contract(KYC_ADDRESS, IKYCRegistry_ABI, provider);

const isApproved = await kyc.isKycApproved(userAddress);

const [netAmount, fee, elUSDOut] = await vault.previewMint(USDC_ADDRESS, parseUnits("1000", 6));
const [tokenOut, redeemFee, willQueue] = await vault.previewRedeem(USDC_ADDRESS, parseEther("1000"));
```

{% endtab %}
{% endtabs %}

## Minting elUSD

{% stepper %}
{% step %}

#### Approve Vault to spend collateral

```solidity
IERC20(USDC).approve(VAULT_ADDRESS, tokenAmount);
```

{% endstep %}

{% step %}

#### Preview the mint (optional but recommended)

```solidity
(uint256 netAmount, uint256 fee, uint256 elUSDOut) =
    vault.previewMint(USDC, tokenAmount);
```

{% endstep %}

{% step %}

#### Execute mint

```solidity
vault.mint(
    USDC,           // collateral token
    recipient,      // who receives elUSD (must be KYC-approved)
    tokenAmount     // collateral amount (token decimals)
);
```

Emits: `Minted(minter, recipient, token, tokenAmountIn, elUSDAmountOut, fee)`
{% endstep %}
{% endstepper %}

{% hint style="info" %}
`recipient` may differ from `msg.sender` — both must pass KYC. This enables custodians to mint on behalf of clients.
{% endhint %}

## Redeeming elUSD

{% stepper %}
{% step %}

#### Approve Vault to spend elUSD

```solidity
IERC20(ELUSD_ADDRESS).approve(VAULT_ADDRESS, elUSDAmount);
```

{% endstep %}

{% step %}

#### Preview the redemption

```solidity
(uint256 tokenOut, uint256 fee, bool willBeQueued) =
    vault.previewRedeem(USDC, elUSDAmount);
```

If `willBeQueued == true`, the redemption will not settle immediately. Plan accordingly.
{% endstep %}

{% step %}

#### Execute redeem

```solidity
uint256 redemptionId = vault.redeem(
    USDC,           // collateral token to receive
    elUSDAmount,    // elUSD amount to burn (18 decimals)
    recipient       // who receives collateral (must be KYC-approved)
);
```

Always emits: `RedeemQueued(redemptionId, ...)` Also emits (instant only): `RedeemSettled(redemptionId, ...)`
{% endstep %}

{% step %}

#### Settle a queued redemption (if needed)

```solidity
vault.settleRedemption(redemptionId);
```

Open to anyone (`PUBLIC_ROLE`). Reverts with `InsufficientLiquidity` if withdrawWallet still lacks funds.
{% endstep %}
{% endstepper %}

## Staking elUSD

```solidity
// Approve staking contract
IERC20(ELUSD_ADDRESS).approve(STAKING_ADDRESS, amount);

// Stake: deposit elUSD, receive sElUSD shares
uint256 shares = staking.stake(amount);

// Preview how much elUSD you'd get back for your shares
uint256 elUSDBack = staking.previewUnstake(shares);

// Unstake: burn sElUSD shares, receive elUSD
uint256 elUSDReceived = staking.unstake(shares);
```

## Monitoring Events

Key events to index for a complete protocol view:

| Event                       | Contract    | When                          |
| --------------------------- | ----------- | ----------------------------- |
| `Minted`                    | Vault       | elUSD issued                  |
| `RedeemQueued`              | Vault       | Redemption initiated (always) |
| `RedeemSettled`             | Vault       | Redemption completed          |
| `YieldMintedToStaking`      | Vault       | Yield distributed             |
| `Staked`                    | ElUSDStake  | User staked elUSD             |
| `Unstaked`                  | ElUSDStake  | User unstaked                 |
| `YieldReceived`             | ElUSDStake  | Share price update            |
| `KycGranted` / `KycRevoked` | KYCRegistry | Compliance events             |
| `AccountBlockStatusChanged` | ElUSD       | Account blocked/unblocked     |

## Checking Queued Redemptions

```solidity
// Read a queued redemption by ID
(
    address redeemer,
    address token,
    uint256 elUSDAmount,
    uint256 tokenAmount,
    uint256 fee,
    address recipient
) = vault.queuedRedemptions(redemptionId);

// If redeemer == address(0), the redemption was already settled or never existed
```

## Common Revert Reasons

| Revert                  | Cause                                           |
| ----------------------- | ----------------------------------------------- |
| `KycRequired(addr)`     | `addr` not approved in KYCRegistry              |
| `MintDisabled(token)`   | Token's `isMintEnabled` is false                |
| `RedeemDisabled(token)` | Token's `isRedeemEnabled` is false              |
| `AmountBelowMinimum`    | Passed zero amount                              |
| `InsufficientLiquidity` | Trying to settle but withdrawWallet lacks funds |
| `InvalidRedemption(id)` | Redemption ID doesn't exist or already settled  |

See [Error Reference](/protocol-reference/reference/error-reference.md) for the complete list.
