MagnifyCash

MagnifyCash is an onchain protocol that facilitates lending and borrowing of ERC20 tokens using NFTs as collateral. The protocol introduces a novel AMM-style architecture called "LAMM" (Lending Automated Market Maker) for lending markets.

The protocol provides a simple but powerful DeFi primitive where any NFT can be lent against any fungible token. All lending parameters are fully customizable - duration, interest, and loan value - offering liquidity providers a full range of capital utilization.

In contrast to many lending markets, the MagnifyCash protocol supports lending for any type of fungible or non-fungible asset. This approach targets the long-tail of asset distribution, where there are tens and thousands of assets without any suitable markets.

Additionally, the MagnifyCash protocol is entirely dependency-free. All transactions are between a lender and borrower exclusively, free of any external third parties. By doing so, users are able to manage risk on their own accord, without worrying about mass liqudiation events, flash crashes, and the like.

Going a step further, lender and borrower positions in the protocol are tokenized. The goal here is a composable base layer where developers can steadily build on top of for years to come.

Table of Contents

Interfaces

The MagnifyCash protocol utilizes two main interface files.

  • IMagnifyCashV1: Interface for core protocol module.
  • IMagnifyERC721V1: Interface for ERC721 tokenization, used in both the lending keys and the obligation notes

IMagnifyCashV1

Git Source

Functions

initializeNewLendingDesk

Creates a new lending desk

Emits an {NewLendingDeskInitialized} event.

function initializeNewLendingDesk(address _erc20, uint256 _depositAmount, LoanConfig[] calldata _loanConfigs)
    external;

Parameters

NameTypeDescription
_erc20addressThe ERC20 that will be accepted for loans in this lending desk
_depositAmountuint256The initial balance of this lending desk
_loanConfigsLoanConfig[]Loan config for each NFT collection this lending desk will support

setLendingDeskLoanConfigs

Creates a new lending configuration

Emits an {LendingDeskLoanConfigsSet} event.

function setLendingDeskLoanConfigs(uint256 _lendingDeskId, LoanConfig[] calldata _loanConfigs) external;

Parameters

NameTypeDescription
_lendingDeskIduint256Identifier for the lending desk
_loanConfigsLoanConfig[]Loan config for each NFT collection this lending desk will support

removeLendingDeskLoanConfig

Removes a new lending configuration

Emits an {LendingDeskLoanConfigsSet} event.

function removeLendingDeskLoanConfig(uint256 _lendingDeskId, address _nftCollection) external;

Parameters

NameTypeDescription
_lendingDeskIduint256Identifier for the lending desk
_nftCollectionaddressAddress for the NFT collection to remove supported config for

depositLendingDeskLiquidity

This function is called to add liquidity to a lending desk

Emits an {LendingDeskLiquidityDeposited} event.

function depositLendingDeskLiquidity(uint256 _lendingDeskId, uint256 _amount) external;

Parameters

NameTypeDescription
_lendingDeskIduint256The id of the lending desk
_amountuint256The balance to be transferred

withdrawLendingDeskLiquidity

This function is called to cash out a lending desk

Emits an {LendingDeskLiquidityWithdrawn} event.

function withdrawLendingDeskLiquidity(uint256 _lendingDeskId, uint256 _amount) external;

Parameters

NameTypeDescription
_lendingDeskIduint256The id of the lending desk to be cashout
_amountuint256Amount to withdraw from the lending desk

setLendingDeskState

This function can be called by the lending desk owner in order to freeze it

Emits an {LendingDeskStateSet} event.

function setLendingDeskState(uint256 _lendingDeskId, bool _freezed) external;

Parameters

NameTypeDescription
_lendingDeskIduint256ID of the lending desk to be frozen
_freezedboolWhether to freeze or unfreeze

initializeNewLoan

This function can be called by a borrower to create a loan

Emits an {NewLoanInitialized} event

function initializeNewLoan(
    uint64 _lendingDeskId,
    address _nftCollection,
    uint64 _nftId,
    uint32 _duration,
    uint256 _amount,
    uint32 _maxInterestAllowed
) external;

Parameters

NameTypeDescription
_lendingDeskIduint64ID of the lending desk related to this offer
_nftCollectionaddressThe NFT collection address to be used as collateral
_nftIduint64ID of the NFT to be used as collateral
_durationuint32Loan duration in hours
_amountuint256Amount to ask on this loan in ERC20
_maxInterestAlloweduint32

getLoanAmountDue

This function can be called by anyone to get the remaining due amount of a loan

function getLoanAmountDue(uint256 _loanId) external view returns (uint256 amount);

Parameters

NameTypeDescription
_loanIduint256ID of the loan

makeLoanPayment

This function can be called by the obligation note holder to pay a loan and get the collateral back

Emits an {LoanPaymentMade} event.

function makeLoanPayment(uint256 _loanId, uint256 _amount, bool _resolve) external;

Parameters

NameTypeDescription
_loanIduint256ID of the loan
_amountuint256The amount to be paid, in erc20 tokens
_resolveboolWhether to resolve the loan or not. If true, _amount is ignored.

liquidateDefaultedLoan

This function is called by the desk owner in order to liquidate a loan and claim the NFT collateral

Emits an {LiquidatedOverdueLoan} event.

function liquidateDefaultedLoan(uint256 _loanId) external;

Parameters

NameTypeDescription
_loanIduint256ID of the loan

setLoanOriginationFee

Allows the admin of the contract to modify loan origination fee.

Emits an {LoanOriginationFeeSet} event.

function setLoanOriginationFee(uint256 _loanOriginationFee) external;

Parameters

NameTypeDescription
_loanOriginationFeeuint256Basis points fee the borrower will have to pay to the platform when borrowing loan

setPlatformWallet

Allows the admin of the contract to set the platform wallet where platform fees will be sent to

Emits an {PlatformWalletSet} event.

function setPlatformWallet(address _platformWallet) external;

Parameters

NameTypeDescription
_platformWalletaddressWallet where platform fees will be sent to

setPaused

Allows the admin of the contract to pause the contract as an emergency response.

Emits either a {Paused} or {Unpaused} event.

function setPaused(bool _paused) external;

Parameters

NameTypeDescription
_pausedboolWhether to pause or unpause

Structs

Loan

Struct used to store loans

struct Loan {
    uint256 amount;
    uint256 amountPaidBack;
    address nftCollection;
    uint64 startTime;
    uint64 nftId;
    uint64 lendingDeskId;
    uint32 duration;
    uint32 interest;
    LoanStatus status;
    bool nftCollectionIsErc1155;
}

LoanConfig

Struct used to store loan config set by the shop owner for an NFT collection

struct LoanConfig {
    address nftCollection;
    bool nftCollectionIsErc1155;
    uint256 minAmount;
    uint256 maxAmount;
    uint32 minInterest;
    uint32 maxInterest;
    uint32 minDuration;
    uint32 maxDuration;
}

LendingDesk

Struct used to store lending desks on this contract

struct LendingDesk {
    address erc20;
    uint256 balance;
    LendingDeskStatus status;
}

Enums

LendingDeskStatus

LendingDeskStatus used to store lending desk status

Active Default status when a lending desk is created

Frozen Used when a lender pauses or 'freezes' their desk

enum LendingDeskStatus {
    Active,
    Frozen
}

LoanStatus

LoanStatus used to store loan status

Active Default status when a loan is issued

Resolved Used when a loan is fully paid back by borrower

Defaulted Used when a loan is liquidated by lender

enum LoanStatus {
    Active,
    Resolved,
    Defaulted
}

IMagnifyERC721V1

Git Source

Inherits: IERC721

Functions

mint

function mint(address to, uint256 tokenId) external;

burn

function burn(uint256 tokenId) external;

Contracts

The MagnifyCash protocol consists of a single core contract and several peripheral contracts. Below is the contract structure:

MagnifyCashV1

Git Source

Inherits: IMagnifyCashV1, Ownable, Pausable, ERC721Holder, ERC1155Holder

State Variables

lendingDeskIdCounter

Unique identifier for lending desks

uint256 public lendingDeskIdCounter;

loanIdCounter

Unique identifier for loans

uint256 public loanIdCounter;

lendingDesks

Mapping to store lending desks

mapping(uint256 => LendingDesk) public lendingDesks;

lendingDeskLoanConfigs

Mapping to store loan configs of lending desks

mapping(uint256 => mapping(address => LoanConfig)) public lendingDeskLoanConfigs;

loans

Mapping to store loans

mapping(uint256 => Loan) public loans;

obligationNotes

The address of the ERC721 to generate obligation notes for borrowers

address public immutable obligationNotes;

lendingKeys

The address of the lending desk ownership ERC721

address public immutable lendingKeys;

loanOriginationFee

The basis points of fees that the borrower will pay for each loan

uint256 public loanOriginationFee;

platformWallet

The address of the platform wallet

address public platformWallet;

Functions

constructor

constructor(
    address _obligationNotes,
    address _lendingKeys,
    uint256 _loanOriginationFee,
    address _platformWallet,
    address _initialOwner
);

initializeNewLendingDesk

Creates a new lending desk

Emits an {NewLendingDeskInitialized} event.

function initializeNewLendingDesk(address _erc20, uint256 _depositAmount, LoanConfig[] calldata _loanConfigs)
    external
    whenNotPaused;

Parameters

NameTypeDescription
_erc20addressThe ERC20 that will be accepted for loans in this lending desk
_depositAmountuint256The initial balance of this lending desk
_loanConfigsLoanConfig[]Loan config for each NFT collection this lending desk will support

setLendingDeskLoanConfigs

Creates a new lending configuration

Emits an {LendingDeskLoanConfigsSet} event.

function setLendingDeskLoanConfigs(uint256 _lendingDeskId, LoanConfig[] calldata _loanConfigs) public whenNotPaused;

Parameters

NameTypeDescription
_lendingDeskIduint256Identifier for the lending desk
_loanConfigsLoanConfig[]Loan config for each NFT collection this lending desk will support

_setLendingDeskLoanConfigs

function _setLendingDeskLoanConfigs(uint256 _lendingDeskId, LoanConfig[] calldata _loanConfigs) internal;

removeLendingDeskLoanConfig

Removes a new lending configuration

Emits an {LendingDeskLoanConfigsSet} event.

function removeLendingDeskLoanConfig(uint256 _lendingDeskId, address _nftCollection) external whenNotPaused;

Parameters

NameTypeDescription
_lendingDeskIduint256Identifier for the lending desk
_nftCollectionaddressAddress for the NFT collection to remove supported config for

depositLendingDeskLiquidity

This function is called to add liquidity to a lending desk

Emits an {LendingDeskLiquidityDeposited} event.

function depositLendingDeskLiquidity(uint256 _lendingDeskId, uint256 _amount) public whenNotPaused;

Parameters

NameTypeDescription
_lendingDeskIduint256The id of the lending desk
_amountuint256The balance to be transferred

_depositLendingDeskLiquidity

function _depositLendingDeskLiquidity(uint256 _lendingDeskId, uint256 _amount) internal;

withdrawLendingDeskLiquidity

This function is called to cash out a lending desk

Emits an {LendingDeskLiquidityWithdrawn} event.

function withdrawLendingDeskLiquidity(uint256 _lendingDeskId, uint256 _amount) external;

Parameters

NameTypeDescription
_lendingDeskIduint256The id of the lending desk to be cashout
_amountuint256Amount to withdraw from the lending desk

setLendingDeskState

This function can be called by the lending desk owner in order to freeze it

Emits an {LendingDeskStateSet} event.

function setLendingDeskState(uint256 _lendingDeskId, bool _freeze) external whenNotPaused;

Parameters

NameTypeDescription
_lendingDeskIduint256ID of the lending desk to be frozen
_freezeboolWhether to freeze or unfreeze

initializeNewLoan

This function can be called by a borrower to create a loan

Emits an {NewLoanInitialized} event

function initializeNewLoan(
    uint64 _lendingDeskId,
    address _nftCollection,
    uint64 _nftId,
    uint32 _duration,
    uint256 _amount,
    uint32 _maxInterestAllowed
) external whenNotPaused;

Parameters

NameTypeDescription
_lendingDeskIduint64ID of the lending desk related to this offer
_nftCollectionaddressThe NFT collection address to be used as collateral
_nftIduint64ID of the NFT to be used as collateral
_durationuint32Loan duration in hours
_amountuint256Amount to ask on this loan in ERC20
_maxInterestAlloweduint32

getLoanAmountDue

This function can be called by anyone to get the remaining due amount of a loan

function getLoanAmountDue(uint256 _loanId) public view returns (uint256 amount);

Parameters

NameTypeDescription
_loanIduint256ID of the loan

makeLoanPayment

This function can be called by the obligation note holder to pay a loan and get the collateral back

Emits an {LoanPaymentMade} event.

function makeLoanPayment(uint256 _loanId, uint256 _amount, bool _resolve) external;

Parameters

NameTypeDescription
_loanIduint256ID of the loan
_amountuint256The amount to be paid, in erc20 tokens
_resolveboolWhether to resolve the loan or not. If true, _amount is ignored.

liquidateDefaultedLoan

This function is called by the lending desk key owner in order to liquidate a loan and claim the NFT collateral

Emits an {LiquidatedOverdueLoan} event.

function liquidateDefaultedLoan(uint256 _loanId) external;

Parameters

NameTypeDescription
_loanIduint256ID of the loan

setLoanOriginationFee

Allows the admin of the contract to modify loan origination fee.

Emits an {LoanOriginationFeeSet} event.

function setLoanOriginationFee(uint256 _loanOriginationFee) public onlyOwner;

Parameters

NameTypeDescription
_loanOriginationFeeuint256Basis points fee the borrower will have to pay to the platform when borrowing loan

setPlatformWallet

Allows the admin of the contract to set the platform wallet where platform fees will be sent to

Emits an {PlatformWalletSet} event.

function setPlatformWallet(address _platformWallet) public onlyOwner;

Parameters

NameTypeDescription
_platformWalletaddressWallet where platform fees will be sent to

setPaused

Allows the admin of the contract to pause the contract as an emergency response.

Emits either a {Paused} or {Unpaused} event.

function setPaused(bool _paused) external onlyOwner;

Parameters

NameTypeDescription
_pausedboolWhether to pause or unpause

Events

NewLendingDeskInitialized

Event that will be emitted every time a lending desk is created

event NewLendingDeskInitialized(
    uint256 lendingDeskId, address owner, address erc20, uint256 initialBalance, LoanConfig[] loanConfigs
);

LendingDeskLoanConfigsSet

Event that will be emitted every time a lending desk config is created

event LendingDeskLoanConfigsSet(uint256 lendingDeskId, LoanConfig[] loanConfigs);

LendingDeskLoanConfigRemoved

Event that will be emitted every time a lending desk config is removed

event LendingDeskLoanConfigRemoved(uint256 lendingDeskId, address nftCollection);

LendingDeskLiquidityDeposited

Event that will be emitted every time liquidity is added to a lending desk

event LendingDeskLiquidityDeposited(uint256 lendingDeskId, uint256 amountDeposited);

LendingDeskLiquidityWithdrawn

Event that will be emitted every time there is a cash out on a lending desk

event LendingDeskLiquidityWithdrawn(uint256 lendingDeskId, uint256 amountWithdrawn);

LendingDeskStateSet

Event that will be emitted every time a lending desk is frozen// unfrozen

event LendingDeskStateSet(uint256 lendingDeskId, bool freeze);

NewLoanInitialized

Event that will be emitted every time a new offer is accepted

event NewLoanInitialized(
    uint256 lendingDeskId,
    uint256 loanId,
    address borrower,
    address nftCollection,
    uint256 nftId,
    uint256 amount,
    uint256 duration,
    uint256 interest,
    uint256 platformFee
);

LoanPaymentMade

Event that will be emitted every time a borrower pays back a loan

event LoanPaymentMade(uint256 loanId, uint256 amountPaid, bool resolved);

DefaultedLoanLiquidated

Event that will be emitted every time a loan is liquidated when the obligation note holder did not pay it back in time

event DefaultedLoanLiquidated(uint256 loanId);

ProtocolInitialized

Event that will be when the contract is deployed

event ProtocolInitialized(address obligationNotes, address lendingKeys);

LoanOriginationFeeSet

Event that will be emitted every time an admin updates loan origination fee

event LoanOriginationFeeSet(uint256 loanOriginationFee);

PlatformWalletSet

Event that will be emitted every time an admin updates the platform wallet

event PlatformWalletSet(address platformWallet);

Errors

ObligationNotesIsZeroAddr

error ObligationNotesIsZeroAddr();

LendingKeysIsZeroAddr

error LendingKeysIsZeroAddr();

ERC20IsZeroAddr

error ERC20IsZeroAddr();

InvalidLendingDeskId

error InvalidLendingDeskId();

CallerIsNotLendingDeskOwner

error CallerIsNotLendingDeskOwner();

MinAmountIsZero

error MinAmountIsZero();

MaxAmountIsLessThanMin

error MaxAmountIsLessThanMin();

MinInterestIsZero

error MinInterestIsZero();

MaxInterestIsLessThanMin

error MaxInterestIsLessThanMin();

MinDurationIsZero

error MinDurationIsZero();

MaxDurationIsLessThanMin

error MaxDurationIsLessThanMin();

InvalidInterest

error InvalidInterest();

InvalidNFTCollection

error InvalidNFTCollection();

LendingDeskIsNotActive

error LendingDeskIsNotActive();

InsufficientLendingDeskBalance

error InsufficientLendingDeskBalance();

UnsupportedNFTCollection

error UnsupportedNFTCollection();

AmountIsZero

error AmountIsZero();

LendingDeskIsNotFrozen

error LendingDeskIsNotFrozen();

InvalidLoanId

error InvalidLoanId();

LendingDeskIsNotEmpty

error LendingDeskIsNotEmpty();

LoanAmountTooLow

error LoanAmountTooLow();

LoanAmountTooHigh

error LoanAmountTooHigh();

LoanDurationTooLow

error LoanDurationTooLow();

LoanDurationTooHigh

error LoanDurationTooHigh();

LoanIsNotActive

error LoanIsNotActive();

CallerIsNotBorrower

error CallerIsNotBorrower();

CallerIsNotLender

error CallerIsNotLender();

LoanHasNotDefaulted

error LoanHasNotDefaulted();

LoanHasDefaulted

error LoanHasDefaulted();

PlatformWalletIsZeroAddr

error PlatformWalletIsZeroAddr();

LoanMustBeActiveForMin1Hour

error LoanMustBeActiveForMin1Hour();

LoanPaymentExceedsDebt

error LoanPaymentExceedsDebt();

InterestRateTooHigh

error InterestRateTooHigh();

MagnifyERC721V1

Git Source

Inherits: ERC721, Ownable

State Variables

baseURI

string public baseURI;

magnifyCash

address public magnifyCash;

_name

string private _name;

_symbol

string private _symbol;

Functions

onlyMagnifyCash

Requires caller to be the Magnify Cash contract

modifier onlyMagnifyCash();

constructor

constructor(string memory name, string memory symbol, string memory _baseURI, address initialOwner);

name

function name() public view override returns (string memory);

symbol

function symbol() public view override returns (string memory);

tokenURI

function tokenURI(uint256 tokenId) public view override returns (string memory);

setMagnifyCash

Set Magnify Cash contract address, requires caller to be owner

function setMagnifyCash(address _magnifyCash) external onlyOwner;

setBaseURI

Update base URI but requires caller to be owner

function setBaseURI(string memory _baseURI) external onlyOwner;

mint

Call _mint but requires caller to be the Magnify Cash contract

function mint(address to, uint256 tokenId) external onlyMagnifyCash;

burn

Call _burn but requires caller to be the Magnify Cash contract

function burn(uint256 tokenId) external onlyMagnifyCash;

Events

Initialized

event Initialized(address owner, string name, string symbol, string baseURI);

BaseURISet

event BaseURISet(string indexed baseURI);

MagnifyCashSet

event MagnifyCashSet(address indexed magnifyCash);

Errors

NameIsEmpty

error NameIsEmpty();

SymbolIsEmpty

error SymbolIsEmpty();

BaseURIIsEmpty

error BaseURIIsEmpty();

CallerIsNotMagnifyCash

error CallerIsNotMagnifyCash();

MintToZeroAddress

error MintToZeroAddress();

MagnifyCashIsZeroAddress

error MagnifyCashIsZeroAddress();

MagnifyLendingKeysV1

Git Source

Inherits: MagnifyERC721V1

Functions

constructor

constructor(string memory _name, string memory _symbol, string memory _baseURI, address _initialOwner)
    MagnifyERC721V1(_name, _symbol, _baseURI, _initialOwner);

MagnifyObligationNotesV1

Git Source

Inherits: MagnifyERC721V1

Functions

constructor

constructor(string memory _name, string memory _symbol, string memory _baseURI, address _initialOwner)
    MagnifyERC721V1(_name, _symbol, _baseURI, _initialOwner);

Contents

  • Basic Integration (Ethers)
  • Basic Integration (WAGMI): Coming soon
  • Basic Integration (Web3Py): Coming soon
  • Advanced Integration (Ethers): Coming soon
  • Advanced Integration (WAGMI): Coming soon
  • Advanced Integration (Web3Py): Coming soon
  • GraphQL Integration: Coming soon

Introduction

The MagnifyCashV1 contract is a decentralized lending platform that allows users to lend and borrow against their NFT assets. This integration guide will walk you through the process of interacting with the MagnifyCashV1 contract using the Ethers.js library. You'll learn how to initialize new lending desks, set loan configurations, deposit and withdraw liquidity, and initiate new loans.

Integration Steps

This guide covers the following key functionalities:

  • Initializing a new lending desk
  • Setting new loan configs for a lending desk
  • Depositing liquidity into a lending desk
  • Withdrawing liquidity from a lending desk
  • Initializing a new loan

You'll need to replace the following placeholders with your actual values:

  • your-ethereum-node-url: The URL of your Ethereum node (e.g., Infura, Alchemy, or your own node)
  • your-private-key: The private key of the Ethereum account you'll be using to interact with the contract
  • contract-address: The address of the deployed MagnifyCashV1 contract
  • 0x...: The addresses of the ERC20 token, NFT collection, and other contract-specific addresses

Code

// Import the necessary Ethers.js modules
const { ethers } = require('ethers');

// Set up the provider and signer
const provider = new ethers.providers.JsonRpcProvider('https://your-ethereum-node-url');
const signer = new ethers.Wallet('your-private-key', provider);

// Load the contract ABI
const contractABI = [
  // Contract ABI goes here
];

// Create the contract instance
const contract = new ethers.Contract('contract-address', contractABI, signer);

// Example usage: Initialize a new lending desk
const erc20 = '0x...'; // Address of the ERC20 token to be used
const depositAmount = ethers.utils.parseEther('1000'); // Initial balance of the lending desk
const loanConfigs = [
  {
    nftCollection: '0x...', // Address of the NFT collection
    minAmount: ethers.utils.parseEther('0.1'), // Minimum loan amount
    maxAmount: ethers.utils.parseEther('1'), // Maximum loan amount
    minInterest: 500, // Minimum interest rate (in basis points)
    maxInterest: 2000, // Maximum interest rate (in basis points)
    minDuration: 24, // Minimum loan duration (in hours)
    maxDuration: 720 // Maximum loan duration (in hours)
  }
];

async function initializeNewLendingDesk() {
  try {
    const tx = await contract.initializeNewLendingDesk(erc20, depositAmount, loanConfigs);
    await tx.wait(); // Wait for the transaction to be mined
    console.log('New lending desk initialized');
  } catch (error) {
    console.error('Error initializing new lending desk:', error);
  }
}

// Example usage: Set new loan configs for a lending desk
const lendingDeskId = 1;
const newLoanConfigs = [
  // New loan config details
];

async function setLendingDeskLoanConfigs() {
  try {
    const tx = await contract.setLendingDeskLoanConfigs(lendingDeskId, newLoanConfigs);
    await tx.wait(); // Wait for the transaction to be mined
    console.log('Lending desk loan configs updated');
  } catch (error) {
    console.error('Error updating lending desk loan configs:', error);
  }
}

// Example usage: Deposit liquidity into a lending desk
const lendingDeskId = 1;
const depositAmount = ethers.utils.parseEther('100');

async function depositLendingDeskLiquidity() {
  try {
    const tx = await contract.depositLendingDeskLiquidity(lendingDeskId, depositAmount);
    await tx.wait(); // Wait for the transaction to be mined
    console.log('Liquidity deposited into lending desk');
  } catch (error) {
    console.error('Error depositing liquidity into lending desk:', error);
  }
}

// Example usage: Withdraw liquidity from a lending desk
const lendingDeskId = 1;
const withdrawalAmount = ethers.utils.parseEther('50');

async function withdrawLendingDeskLiquidity() {
  try {
    const tx = await contract.withdrawLendingDeskLiquidity(lendingDeskId, withdrawalAmount);
    await tx.wait(); // Wait for the transaction to be mined
    console.log('Liquidity withdrawn from lending desk');
  } catch (error) {
    console.error('Error withdrawing liquidity from lending desk:', error);
  }
}

// Example usage: Initialize a new loan
const lendingDeskId = 1;
const nftCollection = '0x...'; // Address of the NFT collection
const nftId = 123; // ID of the NFT to be used as collateral
const loanAmount = ethers.utils.parseEther('0.5');
const loanDuration = 72; // Duration in hours
const maxInterestAllowed = 1500; // Maximum interest rate (in basis points)

async function initializeNewLoan() {
  try {
    const tx = await contract.initializeNewLoan(
      lendingDeskId,
      nftCollection,
      nftId,
      loanDuration,
      loanAmount,
      maxInterestAllowed
    );
    await tx.wait(); // Wait for the transaction to be mined
    console.log('New loan initialized');
  } catch (error) {
    console.error('Error initializing new loan:', error);
  }
}