Castle Crush (Reward Share)
This is a guide on how to use reNFT's SDK to interact with the Wildlife contract directly. This tutorial was written for sdk version 5.0.4.
reNFT's SDK is written in Typescript, but we plan to add more languages in the future (Python and Golang, at the very least). You can install the SDK by running yarn add @renft/sdk.

Lend

Wildlife contract takes custody of the Castle Crush NFT. However, the NFT does not get transferred on rent. It sits inside of the Wildlife contract for as long as the lending is active. If there is no active renting, the lender may choose to terminate the lending. However, if there is an active renting, the lender must wait for it to conclude.
Because Wildlife contract takes custody of the NFT, you will need to approve the NFT you wish to lend to be operated by the contract. You can find an example of how to do it here. Once you have done that, you can lend NFT(s)
import { JsonRpcProvider } from '@ethersproject/providers';
import { parseFixed } from '@ethersproject/bignumber';
import { Wallet } from '@ethersproject/wallet';
import { Whoopi, PaymentToken, RESOLVERS, RenftContracts } from '@renft/sdk';
const provider = new JsonRpcProvider('https://api.avax-test.network/ext/bc/C/rpc');
const privKey = '';
let wallet = new Wallet(privKey);
wallet = wallet.connect(provider);
let txn;
let receipt;
const castleCrushNftAddress = "0xeA4E79F0a40A9A468a5159499b738dc6b1332447";
const whoopiAddress = "0x516775e81b0d1fC91Ec326DEd21c33728895Fc6C";
const whoopi = new Whoopi(wallet, whoopiAddress);
const tokenId = [210, 200];
// ! Note that if allowedRenters is empty, you must set upfrontRentFee to
// ! a non zero value.
const upfrontRentFee = [
parseFixed("1", RESOLVERS[RenftContracts.WHOOPI_FUJI][PaymentToken.USDC]).toString(),
parseFixed("1", RESOLVERS[RenftContracts.WHOOPI_FUJI][PaymentToken.USDC]).toString()
];
// ! you can't use SENTINEL as a payment token, even though
// ! you don't want to set an upfront rent fee. Just use any
// ! payment token in such a case.
const paymentToken = [PaymentToken.USDC, PaymentToken.USDC];
const revShareBeneficiaries = [
["0x000000045232fe75A3C7db3e5B03B0Ab6166F425", "0x465DCa9995D6c2a81A9Be80fBCeD5a770dEE3daE"],
["0x465DCa9995D6c2a81A9Be80fBCeD5a770dEE3daE", "0xeA4E79F0a40A9A468a5159499b738dc6b1332447"]
];
// ! portions sum cannot be 100 here. At lend, we don't know who will rent,
// ! and the renter is always a mandatory part in rev share. We are not setting
// ! the renter here at lend time. Therefore, 100 - sum(portions) is what
// ! gets eventually assigned to the renter.
const revSharePortions = [
[50, 40], // 10% is how much the renter will get on this lending
[90, 5] // 5% is how much ther renter will get on this lending
];
// * means 1 and 2 cycles respectively
const maxRentDuration = [1, 2];
txn = await whoopi.lend(
castleCrushNftAddress,
tokenId,
upfrontRentFee,
revShareBeneficiaries,
revSharePortions,
maxRentDuration,
paymentToken,
undefined,
// ! uncomment this if it does not allow you to execute because it predicts that
// ! the transaction will fail
// { gasLimit: 1000000 }
);
receipt = await txn.wait();

Rent

To rent, you must approve the payment token of the lending to be operated by the Wildlife contract. To do so, see an example here. Once you have done that for the amount of upfrontRentFee or more, you can proceed with the renting
const tokenId = [210, 200];
const lendingId = [3, 4];
const rentingDuration = [1, 2];
txn = await whoopi.rent(
castleCrushNftAddress,
tokenId,
lendingId,
rentingDuration
// { gasLimit: 1000000 }
);
receipt = await txn.wait();

Stop Lending

A lender can only stop the lending if there is no active renting associated with the lending. This is why it is important to set a maxRentDuration to the maximum number of cycles that the lender is happy with. For example, if maxRentDuration is set to 3 it would mean that someone can come in and rent the lending for up to 3 consecutive cycles. You do not need to approve anything from the lender's side on this step, so you are free to call the stop lending function.
const tokenId = [210, 200];
const lendingId = [3, 4];
txn = await whoopi.stopLending(
castleCrushNftAddress,
tokenId,
lendingId,
// { gasLimit: 1000000 }
)
receipt = await txn.wait();

Stop Renting

This is handled by reNFT's bot and there is no need to worry about renter's doing this themselves. In fact, only reNFT's bot is able to stop the rentals. It does so at midnight after cycle-end. The bot checks all of the rentings every hour. That means that it is possible that it will stop the renting with up to but not exceeding one hour delay. Due to the indexing solution requiring payments for every query made, one hour is a good value to stick to.

Pay Rewards

As with renting, you must ensure that the Wildlife contract is approved to operate your ERC20 reward token. Follow the link in the Rent section to see an example on how to do this. Once approved, you are able to simply send a lump sum per lending (along with the renters' addresses), the contract will then handle the reward splitting as per the conditions of the original lending (i.e. taking into account other revenue share parties and their respective shares on this particular lending)
const tokenId = [210, 200];
const lendingId = [3, 4];
const renterAddress = ["0x465DCa9995D6c2a81A9Be80fBCeD5a770dEE3daE", "0x465DCa9995D6c2a81A9Be80fBCeD5a770dEE3daE"];
const amountToPay = [
parseFixed("1", RESOLVERS[RenftContracts.WHOOPI_FUJI][PaymentToken.USDC]).toString(),
parseFixed("1", RESOLVERS[RenftContracts.WHOOPI_FUJI][PaymentToken.USDC]).toString()
];
txn = await whoopi.pay(
castleCrushNftAddress,
tokenId,
lendingId,
renterAddress,
amountToPay,
// { gasLimit: 1000000 }
);
receipt = await txn.wait();

Query On-chain data

We use The Graph's subgraph to index on-chain events. To obtain the Castle Crush subgraph URL reach out to the reNFT team directly. We shall not explore how to make GraphQL queries to the subgraph here. We will merely point out an important potential "gotcha". By default, the query will return at most 100 items in the return set. The maximum you can get is 1000. To achieve this, you must add the first: 1000 query variable and value in your query. For example,
query Query {
rentings(first: 1000, orderBy: cursor, orderDirection: asc) {
id
cursor
renterAddress
rentDuration
rentedAt
}
}
This is not all, however. If the full set of rentings exceeds 1000 items, we will miss all the other rentings. To remedy this, we must use first in conjunction with a where clause. For example,
query Query {
rentings(first: 1000, orderBy: cursor, orderDirection: asc, where: {cursor_gt: 1000}) {
id
renterAddress
rentDuration
rentedAt
}
}
The above query will now pull the next 1000 items. Note that if there are more than 2000 items we are still in trouble. To pull the next 1000 you would use first: 1000, where: {cursor_gt: 2000}.
PLEASE USE THIS TECHNIQUE ON EVERY QUERY YOU ARE MAKING TO THE SUBGRAPH (lendings, rentings, users).
Copy link
On this page
Lend
Rent
Stop Lending
Stop Renting
Pay Rewards
Query On-chain data