### Install Foundry Dependencies Source: https://github.com/instadapp/fluid-contracts-public/blob/main/README.md Installs necessary Foundry dependencies for the project. Ensure Foundry is installed first. ```bash forge install foundry-rs/forge-std --no-git forge install a16z/erc4626-tests --no-git forge install transmissions11/solmate@b5c9aed --no-git forge install OpenZeppelin/openzeppelin-contracts@v4.8.2 --no-git forge install OpenZeppelin/openzeppelin-contracts-upgradeable@v4.8.2 --no-git ``` -------------------------------- ### Example Protocol for Fluid Liquidity Layer Operations Source: https://context7.com/instadapp/fluid-contracts-public/llms.txt Demonstrates how to interact with the IFluidLiquidity.operate function for supplying assets and borrowing, or for paying back debt and withdrawing assets. Ensure the callbackData_ is correctly encoded to trigger the liquidityCallback function. ```Solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.21; import { IFluidLiquidity } from "contracts/liquidity/interfaces/iLiquidity.sol"; interface ILiquidityCallback { function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external; } contract ExampleProtocol is ILiquidityCallback { IFluidLiquidity public immutable liquidity; address constant ETH = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; constructor(address liquidity_) { liquidity = IFluidLiquidity(liquidity_); } /// @notice Supply 1 ETH and borrow 1500 USDC in one operate() call. function supplyAndBorrow(address usdcToken, address borrowTo) external payable { // callbackData encodes the from-address in last 20 bytes of last 32-byte slot bytes memory cbData = abi.encode(msg.sender); (uint256 supplyExPrice, uint256 borrowExPrice) = liquidity.operate{ value: 1 ether }( ETH, // token_ 1 ether, // supplyAmount_ (positive = supply) 1500e6, // borrowAmount_ (positive = borrow, USDC 6 decimals) address(0), // withdrawTo_ (not withdrawing) borrowTo, // borrowTo_ cbData // callbackData_ triggers liquidityCallback on this contract ); // supplyExPrice and borrowExPrice are 1e12 precision exchange prices // e.g. supplyExPrice = 1.002e12 means 1 supplied unit = 1.002 tokens } /// @notice Payback 1500 USDC (negative borrowAmount_) and withdraw 1 ETH (negative supplyAmount_) function paybackAndWithdraw(address usdcToken, address withdrawTo) external { bytes memory cbData = abi.encode(msg.sender); liquidity.operate( ETH, -1 ether, // negative = withdraw -1500e6, // negative = payback withdrawTo, // withdrawTo_ address(0), // borrowTo_ (not borrowing) cbData ); } function liquidityCallback(address token_, uint256 amount_, bytes calldata data_) external override { require(msg.sender == address(liquidity), "only liquidity"); IERC20(token_).transferFrom(abi.decode(data_, (address)), msg.sender, amount_); } } ``` -------------------------------- ### Abstract Error Contract for Lending Protocol Source: https://github.com/instadapp/fluid-contracts-public/blob/main/docs/errors.md An example of an abstract error contract specifically for the Lending protocol, defining a custom error type. ```solidity //SPDX-License-Identifier: MIT pragma solidity 0.8.21; abstract contract Error { error FluidLendingError(uint256 errorId_); } ``` -------------------------------- ### Read Vault Positions and Liquidation Data with IFluidVaultResolver Source: https://context7.com/instadapp/fluid-contracts-public/llms.txt Use `inspectVaultPosition` to get user position and vault configuration details. Simulate liquidations using `getVaultLiquidation`. ```solidity import { IFluidVaultResolver } from "contracts/periphery/resolvers/vault/iVaultResolver.sol"; import { Structs as VaultStructs } from "contracts/periphery/resolvers/vault/structs.sol"; function inspectVaultPosition(IFluidVaultResolver resolver, uint256 nftId) external view { (VaultStructs.UserPosition memory pos, VaultStructs.VaultEntireData memory vault) = resolver.positionByNftId(nftId); // pos.supply collateral amount // pos.borrow debt amount // pos.tick current tick of the position // pos.isLiquidatable whether position can be liquidated now // vault.configs.collateralFactor e.g. 8500 = 85% CF // vault.configs.liquidationThreshold // vault.configs.liquidationPenalty // Simulate liquidation VaultStructs.LiquidationStruct memory liq = resolver.getVaultLiquidation(resolver.vaultByNftId(nftId), 10_000e6); // liq.outAmt collateral received // liq.inAmt debt to repay } function getAllVaultData(IFluidVaultResolver resolver) external view { address[] memory vaults = resolver.getAllVaultsAddresses(); for (uint i = 0; i < vaults.length; i++) { VaultStructs.VaultEntireData memory vd = resolver.getVaultEntireData(vaults[i]); // vd.totalSupplyAndBorrow.totalSupplyVault // vd.totalSupplyAndBorrow.totalBorrowVault // vd.limitsAndAvailability.withdrawable // vd.limitsAndAvailability.borrowable } } ``` -------------------------------- ### Store Gas Snapshot in File Source: https://github.com/instadapp/fluid-contracts-public/blob/main/README.md Creates a gas usage snapshot and redirects the output to a file named `.gas-snapshot`. ```bash forge snapshot > .gas-snapshot ``` -------------------------------- ### Generate Documentation with Forge Source: https://github.com/instadapp/fluid-contracts-public/blob/main/README.md Generates documentation for the smart contracts using the Forge documentation tool. ```bash forge doc ``` -------------------------------- ### Get User Lending Positions Source: https://context7.com/instadapp/fluid-contracts-public/llms.txt Aggregates a user's lending positions, returning fToken metadata and balances. Requires importing `IFluidLendingResolver` and `Structs as LendingStructs`. ```solidity import { IFluidLendingResolver } from "contracts/periphery/resolvers/lending/iLendingResolver.sol"; import { Structs as LendingStructs } from "contracts/periphery/resolvers/lending/structs.sol"; function getUserLendingPositions(IFluidLendingResolver resolver, address user) external view { LendingStructs.FTokenDetailsUserPosition[] memory positions = resolver.getUserPositions(user); for (uint i = 0; i < positions.length; i++) { // positions[i].fTokenDetails.tokenExchangePrice in 1e12 // positions[i].userPosition.underlyingBalance — actual token amount claimable // positions[i].userPosition.underlyingSupply — total deposited tokens } // Preview deposit/withdraw for a specific fToken (IFToken fToken, , , , , , , , ) = // get from positions[0].fTokenDetails (uint256 pDeposit, uint256 pMint, uint256 pWithdraw, uint256 pRedeem) = resolver.getPreviews(fToken, 1000e6, 950e18); // assets=1000 USDC, shares=950 } ``` -------------------------------- ### Manage Modular Implementations with IProxy Source: https://context7.com/instadapp/fluid-contracts-public/llms.txt Use `addImplementation` to route function selectors to new modules and `removeImplementation` to deprecate them. `readFromStorage` allows off-chain access to storage slots. ```solidity import { IProxy } from "contracts/infiniteProxy/interfaces/iProxy.sol"; function addLiquidityModule(IProxy proxy, address newModuleImpl, bytes4[] memory sigs) external { // Only admin can call. Add implementation for new function selectors. proxy.addImplementation(newModuleImpl, sigs); // Verify routing address routed = proxy.getSigsImplementation(sigs[0]); assert(routed == newModuleImpl); } function upgradeModule(IProxy proxy, address oldImpl, address newImpl, bytes4[] memory sigs) external { proxy.removeImplementation(oldImpl); proxy.addImplementation(newImpl, sigs); } function readSlot(IProxy proxy, bytes32 slot) external view returns (uint256 value) { // Raw storage slot access for off-chain tooling value = proxy.readFromStorage(slot); } ```