> For the complete documentation index, see [llms.txt](https://docs.curvance.com/app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.curvance.com/app/developer-docs/quick-start-guides/loans-and-collateral.md).

# Loans & Collateral

This guide demonstrates how to integrate with Curvance Protocol using JavaScript and **ethers.js v6**, with examples using **ezETH** as collateral and **WETH** as the borrowable asset. The same patterns apply to any Curvance market on any deployment chain (Monad, Ethereum mainnet); replace addresses from the deployment registry for the chain you're on.

{% hint style="info" %}
The MarketManager coordinates all cTokens **inside a single isolated market**. For a deep dive, see [Market Manager](/app/developer-docs/lending-protocol/market-manager.md).
{% endhint %}

### Setting Up Your Integration

Install ethers.js. These examples use ethers 6.x:

```bash
npm install ethers@6
```

Define your contract addresses and ABIs.

```js
const ADDRESSES = {
  EZETH:          "0x...", // underlying collateral token (ezETH)
  WETH:           "0x...", // underlying debt token (WETH)
  EZETH_CTOKEN:   "0x...", // Curvance collateral cToken wrapping ezETH
  WETH_CTOKEN:    "0x...", // Curvance borrowable cToken wrapping WETH
  MARKET_MANAGER: "0x...", // MarketManager for the ezETH | WETH market
};
```

Source these from the deployment registry for the chain you're targeting; never mix placeholders and live addresses in the same code block. If your flow borrows WETH, confirm `await marketManager.debtCaps(ADDRESSES.WETH_CTOKEN) > 0n` in that deployment.

### Important Considerations Before Depositing

**Protocol Status, verify the action you're about to take is not paused.**

Call `actionsPaused(cToken)` on the MarketManager. It returns a tuple of three booleans: `(mintPaused, collateralizationPaused, borrowingPaused)`. There is no standalone `mintPaused()` function.

```js
const marketManager = new ethers.Contract(
  ADDRESSES.MARKET_MANAGER,
  MARKET_MANAGER_ABI,
  provider
);

const postingAsCollateral = true;

const [mintPaused, collateralizationPaused] =
  await marketManager.actionsPaused(ADDRESSES.EZETH_CTOKEN);

if (mintPaused) throw new Error("Minting is paused");
if (postingAsCollateral && collateralizationPaused) {
  throw new Error("Collateralization is paused");
}
```

**Collateral Caps, if depositing as collateral.**

`collateralCaps(cToken)` lives on the MarketManager and returns a `uint256`: the maximum shares that can be posted as collateral.

`marketCollateralPosted()` lives on the **cToken** (not the MarketManager) and takes **no arguments** (it's a public state variable). It returns the current shares posted as collateral.

```js
const cToken = new ethers.Contract(
  ADDRESSES.EZETH_CTOKEN,
  CTOKEN_ABI,
  provider
);

const depositAmount = ethers.parseEther("1");
const expectedShares = await cToken.previewDeposit(depositAmount);

const cap = await marketManager.collateralCaps(ADDRESSES.EZETH_CTOKEN);
const posted = await cToken.marketCollateralPosted();

if (cap === 0n) throw new Error("Collateralization disabled for this cToken");
if (posted + expectedShares > cap) throw new Error("Collateral cap exceeded");
```

**Note:** a `collateralCaps` of `0` means collateralization is **disabled entirely** for that cToken, not "unlimited." Don't treat zero as "no cap." (Source: `MarketManagerIsolated.sol:376` reverts on `newNetCollateral > collateralCaps[collateralToken]` with a non-zero collateral amount.)

**Minimum Hold Period.**&#x41;fter an account posts collateral or borrows, a 20-minute account cooldown starts. During this window the affected account cannot:

* repay a loan,
* transfer collateralized shares,
* **redeem collateralized shares** (i.e., withdraw the underlying out of a position you've posted as collateral).
* remove collateral through paths that call the MarketManager redeem check.

Plain deposits are unaffected; the gate trips on actions that reduce a collateralized position. Enforced by `MIN_HOLD_PERIOD = 20 minutes` in `MarketManagerIsolated.sol:115`; checked by `_checkHoldPeriod` (`:1659`) reached from both `canRepayWithReview` (`:496`) and `_checkTransfersAllowed` (`:1693`). Mitigates flash-loan and multi-block oracle manipulation.

**Non-Rebasing.** cToken share balances are fixed; yield accrues by increasing the exchange rate (shares to underlying), not by minting additional shares.

### Best Practices for Production Implementations

* **Error Handling:** wrap all transactions with try/catch and surface revert reasons to users.
* **Gas Estimation:** call `contract.foo.estimateGas(args)` before sending to detect likely reverts and set safe limits.
* **Approval Checking:** read `allowance()` before submitting an `approve` tx; skip if sufficient.
* **Transaction Monitoring:** track tx status via receipts and confirmations; always `await tx.wait()` between dependent transactions (the approve-then-deposit race is real).
* **Read-Only Checks:** use `canMint(cToken)` on the MarketManager as the deposit precheck. It returns no value; success means minting is allowed, and failure reverts. If your ABI marks it as nonpayable, call `await marketManager.canMint.staticCall(cToken)` to force an `eth_call`. `canBorrow` and `canRedeemWithCollateralRemoval` are not clean UX prechecks; they mutate state or are cToken-only paths and revert on failure. For UX estimates, use the ERC4626 preview functions: `previewDeposit`, `previewMint`, `previewRedeem`, `previewWithdraw`. These preview functions are stale views; for wei-accurate fresh reads, see [Integration Cookbook: Stale vs Fresh Reads](/app/developer-docs/quick-start-guides/integration-cookbook.md).
* **Reentrancy:** every cToken deposit / redeem / borrow / repay / collateral entrypoint is `nonReentrant` (transient-storage lock). Calling back into Curvance from a callback reverts. Structure flows so Curvance calls are not nested.
* **Delegation model:** if your platform acts on behalf of users, the user must call `setDelegateApproval(yourAddress, true)` on the relevant cToken first. Use the `*For` variants: `redeemFor`, `depositAsCollateralFor`, `postCollateralFor`, `removeCollateralFor`. Plain `redeem` / `withdraw` consume ERC20 share allowance when `msg.sender != owner`. There is **no cToken `withdrawFor`**: use `redeemFor` with shares computed from `previewWithdraw(assets)` if the caller wants a specific underlying amount. Self-delegation is blocked. Users can mass-revoke delegates by calling `centralRegistry.incrementApprovalIndex()`.

By following this guide, you'll be able to integrate with Curvance's deposit functionality for both yield-optimized collateral positions and lending positions using JavaScript and ethers.js v6.

***
