> For the complete documentation index, see [llms.txt](https://docs.fluidnft.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fluidnft.org/technical-resources/developers/contract-integration.md).

# Contract Integration

Modules[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#modules)

The FluidNFT protocol is a collection of smart contracts connected via a modular system. Each module handles a specific aspect of the protocol. Depending on your use case you may need to interact with several different contract addresses.

Some modules are global, for example:

* `ExecutionDelegate`: Grant ERC20, ERC721 & ERC1155 token access across the protocol
* `ExecutionManager`: Batch requests to save on gas
* `LendingPool`: Execute peer-to-pool transactions
* `Lending`: Execute peer-to-peer transactions

Some modules are asset-specific, for example:

* `fTokens`: Incentivised ERC-20 tokens that represent assets
* `stableDebtTokens`: Incentivised ERC-20 tokens that represent stable interest rate liabilities
* `variablDebtTokens`: Incentivised ERC-20 tokens representing variable interest rate liabilities

### Execution[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#execution) <a href="#execution" id="execution"></a>

As it may be beneficial to batch requests to save on gas all modules can be called using the optional `ExecutionManager`.

Example of depositing into a lending pool with the execution manager:

```
// Use the lending pool module:
ILendingPool lendingPool = ILendingPool(LENDING_POOL);

// Deposit asset tokens into a pool
lendingPool.deposit(amount, reserveId, onBehalfOf, referralCode);
```

Without the execution manager:

```
// Use the execution manager module
IExecutionManager executionManager = IExecutionManager(EXECUTION_MANAGER);

// Instantiate the lending pool module to access the selector:
ILendingPool lendingPool = ILendingPool(LENDING_POOL);

// Deposit asset tokens into a pool
executionManager.call(
    LENDING_POOL, 
    abi.encodeWithSelector(
        lendingPool.deposit.selector,
        amount, 
        reserveId,
        onBehalfOf,
        referralCode
    )
);
```

Note the `ExecutionManager` supports both `.call()` and `.multiCall()` functionality, for batch execution.

The remainder of this document details how to integrate without the execution module, for the sake of brevity.

### P2Pool[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#p2pool) <a href="#p2pool" id="p2pool"></a>

Core peer-to-pool operations.

#### Deposit and withdraw[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#deposit-and-withdraw) <a href="#deposit-and-withdraw" id="deposit-and-withdraw"></a>

In order to earn passive yield, you need to `deposit` into a lending pool.

```
// Approve the execution delelgate contract to pull your tokens:
IERC20(asset).approve(EXECUTION_DELEGATE, type(uint).max);

// Use the lending pool module:
ILendingPool lendingPool = ILendingPool(LENDING_POOL);

// Get the default reserve id for a given collateral-asset pair
// "collateral" is the NFT contract address, e.g. 0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7 for Meebits
// "asset" is the asset contract address, e.g. 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 for WETH (Wrapped Ether)
// "maxTokenId" is the maxTokenId for the collection, e.g. 19999 for Meebits
// "minTokenId" is the minTokenId for the collection, e.g. 0 for Meebits
lendingPool.getReserveId(collateral, asset, maxTokenId, minTokenId);

// Deposit asset tokens into the pool
// "amount" the amount of asset tokens, e.g. 12.5e18 (assuming 18 decimal places)
// "reserveId" the id of the reserve, e.g. "1" (returned in previous call)
// "onBehalfOf" enables the deposit to be initiated from a seperate account, or use address(this) for the same account
// "referralCode" is used for fee sharing with our partners, or 0 for none
lendingPool.deposit(amount, reserveId, onBehalfOf, referralCode);
```

Use the fToken reserve to check balances.

```
// Retrieve fToken address
lendingPool.getConfiguration(reserveId).fTokenAddress;

// Use the fToken
IFToken fToken = IFToken(fTokenAddress);

// Retreive the user's balance + interest 
// Grows each block, assuming there are borrowers to generate yield
fToken.balanceOf(address(this));

// Retreive the user's deposit amount
// Internal book-keeping amount that doesn't change in time
fToken.scaledBalanceOf(address(this));
```

You can `withdraw` at anytime to retrieve your funds.

```
// Withdraw asset tokens from the pool
// "amount" the amount of asset tokens, e.g. type(uint256).max to retrieve all deposits plus interest
// "reserveId" the id of the reserve, e.g. "1" 
// "to" enables withdrawing to seperate account, or use address(this) for the same account
lendingPool.withdraw(amount, reserveId, to);
```

#### Borrow and repay[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#borrow-and-repay) <a href="#borrow-and-repay" id="borrow-and-repay"></a>

To borrow an asset, you must supply collateral to be held in escrow for the duration of the loan.

```
// Approve the execution delelgate contract to pull your tokens:
IERC721(collateral).setApprovalForAll(EXECUTION_DELEGATE);

// Use the lending pool module:
ILendingPool lendingPool = ILendingPool(LENDING_POOL);

// Get the default reserve id for a given collateral-asset pair
// "collateral" is the NFT contract address, e.g. 0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7 for Meebits
// "asset" is the asset contract address, e.g. 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 for WETH (Wrapped Ether)
// "maxTokenId" is the maxTokenId for the collection, e.g. 19999 for Meebits
// "minTokenId" is the minTokenId for the collection, e.g. 0 for Meebits
lendingPool.getReserveId(collateral, asset, maxTokenId, minTokenId);

// Borrow asset tokens from the pool
// "amount" the amount of asset tokens, e.g. 12.5e18 (assuming 18 decimal places)
// "tokenId" the id of the token to be used as collateral, e.g. "1" (a tokenId held in your wallet)
// "reserveId" the id of the reserve, e.g. "1" (returned in previous call)
// "onBehalfOf" enables the borrow to be initiated from a seperate account, or use address(this) for the same account
// "referralCode" is used for fee sharing with our partners, or 0 for none
lendingPool.borrow(amount, reserveId, onBehalfOf, referralCode);
```

Use the debtToken reserve to check debt balances.

```
// Retrieve debtToken address
lendingPool.getConfiguration(reserveId).debtTokenAddress;

// Use the debtToken
IDebtToken debtToken = IDebtToken(debtTokenAddress);

// Retreive the user's debt balance + interest 
// Grows each block
debtToken.balanceOf(address(this));

// Retreive the user's borrow amount
// Internal book-keeping amount that doesn't change in time
debtToken.scaledBalanceOf(address(this));
```

You can `repay` at anytime to retrieve your collateral.

```
// Repay asset tokens to the pool
// "collateral" is the NFT contract address, e.g. 0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7 for Meebits
// "tokenId" the id of the token used as collateral, e.g. "1"
// "amount" the amount of asset tokens, e.g. type(uint256).max to repay the borrow amount plus interest
lendingPool.repay(collateral, tokenId, amount);
```

#### Liquidate[​](https://docs-fluidnft.vercel.app/docs/developers/protocol/contract-integration-guide#liquidate) <a href="#liquidate" id="liquidate"></a>

If a loan is no longer sufficiently overcollateralised, i.e. when the amount of outstanding debt exceeds the maximum loan-to-value, it can be liquidated.

The price is determined via a proprietary dynamic-Dutch auction mechanic that results in a high liquidation price when the loan is a little undercollateralised, that decays exponentially as the loan becomes more and more undercollateralised.

The liquidation price is further dependent on the asset being used to purchase the underlying collateral, with smaller and larger discounts available for their reserve's fTokens and stakedToken, respectively.

```
// Approve the execution delelgate contract to pull your tokens:
IERC20(asset).approve(EXECUTION_DELEGATE, type(uint).max);

// Use the lending pool module:
ILendingPool lendingPool = ILendingPool(LENDING_POOL);

// Liquidate an undercollateralized loan to purchase the underlying collateral at a discount
// "collateral" is the NFT contract address, e.g. 0x7bd29408f11d2bfc23c34f18275bbf23bb716bc7 for Meebits
// "tokenId" the id of the token used as collateral, e.g. "1"
// "paymentAsset" is the contract address of the amount paid to liquidate, e.g. 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 for WETH
// "paymentAmount" the amount of asset token paid to liquidate the loans, e.g. 12.5e18 (assuming 18 decimal places)
// "onBehalfOf" enables the deposit to be initiated from a seperate account, or use address(this) for the same account
lendingPool.liquidate(collateral, tokenId, paymentAsset, paymentAmount, onBehalfOf);
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.fluidnft.org/technical-resources/developers/contract-integration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
