Collateral-Free Integration Guide
The official instructions on how to interact with our open Collateral-Free rental contracts.
This tutorial was written for SDK version6.0.0
.

reNFT collateral-free contract flows
To interact with our smart contracts, we always recommend using our SDK. We view the SDK as the source of truth for all of our deployments and business logic; most importantly, it versions where our smart contracts reside in the metaverse and defines objectively how they work.
To work with collateral-free lendings, we'd use the
Sylvester
contract:import {
getRenftContract,
DEPLOYMENT_SYLVESTER_ETHEREUM_MAINNET_V0,
SylvesterV0FunctionInterface,
} from "@renft/sdk";
import { ethers } from "ethers";
const signer = ethers.Wallet.createRandom(); // In practical dApps, this would be the user's wallet!
const renft: SylvesterV0FunctionInterface = getRenftContract({
deployment: DEPLOYMENT_SYLVESTER_ETHEREUM_MAINNET_V0,
signer,
});
import { NFTStandard, PaymentToken, packPrice } from "@renft/sdk";
const astroCatLendingArgs = [
NFTStandard.E1155,
"0x0db8c099b426677f575d512874d45a767e9acc3c",
"1",
1,
1,
packPrice("1"),
PaymentToken.WETH,
];
const catPlsrLendingArgs = [
NFTStandard.E1155,
"0x0db8c099b426677f575d512874d45a767e9acc3c",
"2",
1,
1,
packPrice("0.5"),
PaymentToken.WETH,
];
const lendingArgs = astroCatLendingArgs.map((value, index) =>
[value, catPlsrLendingArgs[index]]
);
await renft.lend(...lendingArgs);
dApps invoke
lend()
when they wish to create a new on-chain lending. A lending is when a market maker asserts that they wish to allow other users to temporarily have rights to the asset for the duration of the rental.Since the
lend()
function is designed to batch multiple NFTs together, you can create a single-element lending by using single-element arrays for each of the required parameters:import { NFTStandard, PaymentToken, packPrice } from "@renft/sdk";
const nftStandard = NFTStandard.E1155;
const nftAddress = "0x0db8c099b426677f575d512874d45a767e9acc3c";
const tokenID = "1";
const lendAmount = 1; // Quantity of the NFT to lend.
const maxRentDuration = 1; // Duration is measured in days.
const dailyRentPrice = packPrice("1"); // Create a properly formatted rental price.
const paymentToken = PaymentToken.WETH;
await renft.lend(
[nftStandard],
[nftAddress],
[tokenID],
[lendAmount],
[maxRentDuration],
[dailyRentPrice],
[paymentToken]
);
A renting is created when a user discovers a compelling lending on the blockchain and decides to take the maker up on their offer. In this instance, the user is the taker of the lending. Much like the previous example, we call the
rent()
function with vectorized data representing each individual token to be rented in a gas-optimized batch.import { NFTStandard } from "@renft/sdk";
const nftStandard = NFTStandard.E1155;
const nftAddress = "0x0db8c099b426677f575d512874d45a767e9acc3c";
const tokenID = "1";
const lendingID = "1"; // this information is pulled from the subgraph
const rentDuration = 1; // in days
const rentAmount = 1;
await renft.rent(
[nftStandard],
[nftAddress],
[tokenID],
[lendingID],
[rentDuration],
[rentAmount]
);
For a non-collateralized rental, even though no real possession of the NFT is given (it is a virtualized rights-to-ownership), the renter must signal that they have concluded "using" the NFT with a call to
stopRent()
.If the renter fails to make this call, the lender is permitted to invoke
claimRent()
, explained in the following section, to redeem the full amount of rent.import { NFTStandard } from "@renft/sdk";
const nftStandard = NFTStandard.E1155;
const nftAddress = "0x0db8c099b426677f575d512874d45a767e9acc3c";
const tokenID = "1";
const lendingID = "1"; // from subgraph
const rentingID = "1"; // from subgraph
await renft.stopRent(
[nftStandard],
[nftAddress],
[tokenID],
[lendingID],
[rentingID],
);
Lenders can claim rent by calling the
claimRent()
function.Remember, the smart contract enforces the rules of lending and renting; you can try to claim the rent of an ongoing lending which doesn't belong to you, but the transaction will be reverted!
import { NFTStandard } from "@renft/sdk";
const nftStandard = NFTStandard.E1155;
const nftAddress = "0x0db8c099b426677f575d512874d45a767e9acc3c";
const tokenID = "1";
const lendingID = "1";
const rentingID = "1";
await renft.claimRent(
[nftStandard],
[nftAddress],
[tokenID],
[lendingID],
[rentingID],
);
Finally, there's the
stopLend
function, which is called by the lender. This prevents the provided assets from being rented out any longer, much to the chagrin of prospective renters.import { NFTStandard } from "@renft/sdk";
const nftStandard = NFTStandard.E1155;
const nftAddress = "0x0db8c099b426677f575d512874d45a767e9acc3c";
const tokenID = "1";
const lendingID = "1";
await renft.stopLend(
[nftStandard],
[nftAddress],
[tokenID],
[lendingID],
);
To learn about more about how we determine the status of a particular lending or renting, check out this guide!
In reNFT, prices are returned in a custom format. This is a performance optimization which enables an entire lending to fit snugly inside a single storage slot, which saves gas.
To unpack them, we can use the
unpackPrice()
function:import { PaymentToken, unpackPrice } from "@renft/sdk";
// Convert a low-level representation of an ERC-20 used on
// the marketplace into a TypeScript-friendly enum.
const parsePaymentToken = (tkn: string): PaymentToken => {
switch (tkn) {
case "0":
return PaymentToken.SENTINEL;
case "1":
return PaymentToken.WETH;
case "2":
return PaymentToken.DAI;
case "3":
return PaymentToken.USDC;
case "4":
return PaymentToken.USDT;
case "5":
return PaymentToken.TUSD;
default:
return PaymentToken.DAI;
}
};
// In this example, let's imagine we've read Lending collection data
// from a Sylvester subgraph. Here's how we'd transform the low-level
// blockchain data into high-level, human (and feline) friendly types.
const lendingsDataToLendings = (
theGraphLendings: TheGraphLending[]
) => {
const theGraphToLending = (theGraphLending: TheGraphLending) => {
return {
lendingID: theGraphLending.id,
lenderAddress: theGraphLending.lenderAddress,
// Convert the price back into a BigNumber.
dailyRentPrice: unpackPrice(theGraphLending.dailyRentPrice),
maxRentDuration: Number(theGraphLending.maxRentDuration),
lendAmount: Number(theGraphLending.lendAmount),
paymentToken: parsePaymentToken(theGraphLending.paymentToken),
lentAt: Number(theGraphLending.lentAt),
};
};
return theGraphLendings.map(theGraphToLending);
};
Last modified 2mo ago