Skip to main content

Rain

In the Rain SDK, Rain class is the core element. Rain makes it possible to interact with the Rain on-chain program and gives you access to over 30 utility functions.

Let's look at Rain usage!

Initialization

To initialize new Rain class, use this snippet:

import {Rain} from '@rainfi/sdk';
import {Connection, clusterApiUrl, Keypair} from "@solana/web3.js";

// We will use this wallet as a placeholder.
// Normally, you would use PublicKey of your wallet
// (or your user's wallet).
const publicKey = Keypair.generate().publicKey;

// Initialize new connection to the Solana blockchain.
const connection = new Connection(
clusterApiUrl('mainnet-beta')
);

// Create new Rain class.
const rain = new Rain(
connection,
publicKey
);

As you can see, first we import Rain class from the SDK. We're also importing Connection and Keypair classes and clusterApiUrl function from the official Solana SDK.

Then, we initialize new, random address - we'll use it as placeholder. When interacting with Rain in production environment, you'll probably want to use your own address (or address owned by your user).

Then, using new Connection(), we're initializing new connection to the Solana blockchain. As the RPC endpoint, we'll use official mainnet-beta cluster run by Solana. We're getting it's address by using clusterApiUrl('mainnet-beta') function.

Now, after we have a Connection and address, we can initialize new Rain() class. As constructor parameters, we're passing connection and our placeholder address.

Usage

As we mentioned earlier, Rain class is the core element of the SDK. It basically gives you access to everything that the Rain program has to offer - utility functions, interactions, etc. To use all of them, we can destructure the Rain class - see snippet below.

// To see how to initialize new Rain class, see snippet above.
const rain = new Rain(
connection,
publicKey
);

// Utility functions
const {
utils
} = rain;

const {
getPoolFromOwnerAddress,
getMortgageForSale,
getCollection,
// and so on...
} = utils;

// Interactions
const {
borrow,
repayLoan,
createPool,
updatePool,
// and so on...
} = rain;

Utility Functions

We've dedicated whole chapter to discuss utility functions. To see all of them, their explanation and usage, click HERE.

Interactions

Interaction is special kind of function. Alone, it doesn't invoke any on-chain function. However, if it receives correct parameters, it parses and generates transaction instructions that you'll need to correctly interact with the Rain.fi program.

This functions use official Solana SDK under the hood, so they return interactions as instances of Solana-compatibile TransactionInstruction (or array of them). There's no need to parse them - they're ready to use. The only thing you need to do is to pass correct parameters, then wrap instructions in Transaction object and sign it using Keypair (or wallet adapter if your environment is browser).

Now, let's discuss all interactions that Rain provides, one by one.

borrow()

We'll start by (probably) the most important, and the most used one. As the name suggests, it will return transaction instruction(s) necessary to borrow x amount of Solana, from y Pool, against z NFT as a collateral. x, y and z is pretty much everything you need to successfully use this function:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
borrow,
utils,
} = rain;

const {
getPoolFromOwnerAddress,
getCollection,
getFeesDetailed,
} = utils;

// Fetch pool by it's owner.
const pool = await getPoolFromOwnerAddress(
connection,
new PublicKey("") // Owner of the pool
);
const { loanToValue } = pool;

// Fetch first collection supported by the above pool.
const collection = await getCollection(
connection,
pool.collections[0].collection
);
const { floorPrice } = collection;

const amount = 50 * LAMPORTS_PER_SOL;
const duration = pool.maxDuration / 60 / 60 / 24;

const { feesInSol } = getFeesDetailed(
pool,
amount,
duration,
);

const { instruction, signers } = await borrow({
nftMint: new PublicKey("<NFT Mint Address>"), // NFT you want to collateralize.
poolOwner: new PublicKey(pool.owner), // Owner of the pool you're using.
amount, // Amount of Solana you want to borrow (in lamports).
duration, // Loan duration in days.
interest: feesInSol, // Interest returned from getFeesDetailed() function.
slippage: 50 // Slippage. 500 = 5%
});

const tx = new Transaction();
tx.add(...instruction);
tx.partialSign(signers);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

We're not including code snippet for signing and sending Solana transactions here. If you're not sure how to do it, visit this tutorial on Solana Cookbook.

repayLoan()

repayLoan() function is used to generate transaction instructions for repaying ongoing loan. The function accepts two parameters - loan account address, and borrowed amount (in lamports). As a result, function returns array of Solana SDK-compatibile TransactionInstruction.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
Keypair.generate().publicKey
);

const {
repayLoan,
utils,
} = rain;

const {
getLoansFromBorrower,
} = utils;

const loans = await getLoansFromBorrower(
connection,
new PublicKey("<Your Address>")
);

const loanToBeRepaid = loans[0];
const { accountAddress, amount } = loanToBeRepaid;

const instruction = await repayLoan(
new PublicKey(accountAddress),
amount
);

const tx = new Transaction();
tx.add(...instruction);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

buyMortgage()

buyMortgage() function generates transaction instructions allowing you to buy an NFT from a marketplace with partial Rain.fi funding.

Currently supported marketplaces are Solanart, Hadeswap and Metaplex Auction House.

To start using the function, let's go through all of the parameters. Function accepts 8 of them:

  • nftMint - mint address of the NFT you want to buy.
  • marketplace - marketplace, where ^ above NFT is listed. You can find currently supported marketplaces above.
  • price - listing price of the ^ above NFT.
  • seller - address of the seller.
  • interest - fees paid by buyer.
  • slippage - price slippage. 500 = 5%
  • amount - amount (in SOL) that will be paid by the signer. Currently Rain only supports 50/50 payments, so make sure to set it to price / 2. (In coming weeks, Rain will also start supporting other payment ratio.)
  • duration - mortgage duration in days. If mortgage won't be sold/repaid on time, it will be liquidated.
  • poolOwner - owner of the pool you want to use for taking the mortgage. Each owner can only have one pool, so pool data will be fetched by owner's address.

Here's full usage code snippet:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
Keypair.generate().publicKey
);

const {
buyMortgage
} = rain;

const listing = {
seller: new PublicKey("<Seller>"), // Seller who listed the NFT
price: 200 * LAMPORTS_PER_SOL, // 200 SOL
}

const duration = 7; // Days
const poolOwner = new PublicKey("<Pool Owner Address>");
const pool = await getPoolFromOwnerAddress(connection, poolOwner);

const { feesInSol } = getMortgagesFeesDetailed(
pool,
listing.price / 2,
duration
)

const {instruction, signers} = await buyMortgage({
nftMint: new PublicKey("<NFT Mint Address>"),
interest: feesInSol,
slippage: 20,
marketplace: "hadeswap", // Marketplace where ^ above NFT is listed.
poolOwner,
amount: listing.price / 2, // Amount that you want to pay, the rest will be paid by Rain.
price: listing.price, // Price of that particular listing, don't confuse it with floor price!
seller: listing.seller, // Address of the seller who listed above ^ NFT.
duration, // Mortgage duration in days. If not repaid until that time, mortgage will be liquidated.
});

const tx = new Transaction();
tx.add(...instruction);
tx.partialSign(...signers);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

addLiquidity()

Function allows you to add liquidity to existing pool. To use this function, you have to initialize a pool first. Also, as you can see, this function doesn't accept any 'Pool' parameter. When you initialize new Rain() instance, you have to specify publicKey. This function will fetch pool by owner, where the owner is the publicKey specified during initialization. Make sure to use YOUR address, not randomly generated one / placeholder.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
new PublicKey("<Your Address>")
);

const {
addLiquidity
} = rain;

const ix = await addLiquidity(200 * LAMPORTS_PER_SOL);

const tx = new Transaction();
tx.add(...ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

repayMortgage()

As the name suggests, this function allows you to generate transaction instructions needed to repay a mortgage. To repay it, you have to pass two parameters:

  • mortgageAccount - on-chain account address of the mortgage.
  • amount - mortgage size in lamports.

To get mortgageAccount, use getMortgageFromAddress() utility function, as in the snippet below:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
repayMortgage,
utils,
} = rain;

const {
getMortgageFromAddress
} = utils;

const mortages = await getMortgageFromAddress(
connection,
new PublicKey("<Address Here>"),
"borrower",
true
);

const mortgageToBeRepaid = mortages[0];
const { accountAddress, amount } = mortgageToBeRepaid;

const ix = await repayMortgage(
new PublicKey(accountAddress),
amount
);

const tx = new Transaction();
tx.add(...ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

createPool()

createPool function generates transaction instructions allowing you to create new pool in Rain protocol.

To start, you have to initialize Rain class. The PublicKey you pass as the second parameter to Rain constructor will be owner of the pool. Set it wisely.

Creating new pool requires setting advanced parameters, like baseInterest, curveRate, etc. To understand how interest is calculated, make sure to visit this page

To create new pool, use the snippet below (and customize interest parameters).

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const { createPool } = rain;

const instructions = await createPool({
amount: 50,
loanToValue: 80,
compound: true,
collections: [{
collection: 517,
collectionLtv: 80,
}],
maxAmount: 50,
maxDuration: 7,
curveRateDay: 180,
curveRate: 100,
baseInterest: 200,
interestRate: 210,
});

const tx = new Transaction();
tx.add(...instructions);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

As you can see, we pass all parameters as an object literal. That object has x fields:

  • amount - initial pool size. Minimum 50 SOL, you can add and withdraw liquidity later on.
  • compound - specify if profits generated by the pool should be reinvested and deposited in the pool as borrowable liquidity.
  • collections - array of object literals. In the object, you have to specify collection, which is simply unique collection ID, and collectionLtv, which is max loan-to-value ratio (80 = 80%, etc).
  • maxAmount - maximum borrowable amount accepted by the pool. amount. Cannot be bigger than pool size.
  • maxDuration - maximum loan duration.
  • loanToValue - maximum offered loan-to-value ratio. If set to 80%, maximum loan size will be 80% of current floor price.

Last four parameters - baseInterest, interestRate, curveRate and curveRateDay are necessary and critical for Rain.fi formula calculating interest of your pool. To read more about them, (read more here)[../../../123]

closePool()

This function allows you to close existing pool. This function will close and delete the pool, as well as all data associated with it. Be careful, this action is not reversable. As you can see, the function doesn't require Pool argument. Pool will be automatically fetched by owner, depending on the address you've used during initialization.

Usage is very simple:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
closePool
} = rain;

const ix = await closePool(true); // Pass 'true' to confirm.

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

sellMortgage()

To get rid of mortgage, you can either repay it or sell it. Repaying will result in NFT getting unfrozen in your wallet. However, if you decide to sell the mortgage, all profits coming from the sale will be used to repay the mortgage. Everything over the mortgage size will be returned to your wallet.

Here's how to sell the mortgage using the SDK:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
sellMortgage,
utils
} = rain;

const {
getMortgageFromAddress
} = utils;

const mortgage = await getMortgageFromAddress(
connection,
new PublicKey("<Address Here>"),
"borrower",
true
);

const mortgageToBeSold = mortgage[0];
const { accountAddress, mint, price } = mortgageToBeSold;

const ix = await sellMortgage(
new PublicKey(accountAddress),
new PublicKey(mint),
price
);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

acceptLoanRequest()

Function is used to generate transaction instructions allowing you to accept loan request received from a borrower.

Function accepts one parameter - publicKey of the loan request you want to accept. To get a particular loan request, use getFiltersLoanRequest() utility function, followed by Solana SDK-native getProgramAccounts() function. This set of functions allow you to filter all loan requests to get one that you are interested in, and get its publicKey.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
acceptLoanRequest,
utils
} = rain;

const {
getPoolFromOwnerAddress,
getFiltersLoanRequest
} = utils;

const pool = await getPoolFromOwnerAddress(
connection,
new PublicKey("<Pool Owner Address>")
);

const allLoanRequests = await getFiltersLoanRequest([{
key: "pool",
value: pool.poolAddress
}]);

const loanRequestProgramAccounts = await connection.getProgramAccounts(
new PublicKey("RainEraPU5yDoJmTrHdYynK9739GkEfDsE4ffqce2BR"),
// ^ Address of official Rain.fi program deployment.
{filters: allLoanRequests}
);

const loanRequestToAccept = loanRequestProgramAccounts[0].pubkey;

const ix = await acceptLoanRequest(loanRequestToAccept);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

withdrawLiquidity()

Function allows you to withdraw liquidity to existing pool. The only parameter it requires is amount of Solana you're withdrawing. Obviously, to use this function, you have to initialize a pool first.

Also, as you can see, this function doesn't accept any 'Pool' parameter. When you initialize new Rain() instance, you have to specify publicKey. This function will fetch pool by owner, where the owner is the publicKey specified during initialization. Make sure to use YOUR address, not randomly generated one / placeholder.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
withdrawLiquidity
} = rain;

const ix = await withdrawLiquidity(
200
);

const tx = new Transaction();
tx.add(...ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

setMaxAmountUsable()

Sometimes, you don't want (or can't) withdraw liquidity from your pool. This can be caused by currently running loan, for example. setMaxAmountUsable() allows you to limit maximum amount in the pool that can be loaned, without withdrawing it.

Function accepts one parameter - maxAmountUsable. This parameter is simply amount of Solana that you want to leave in the pool as borrowable liquidity.

The rest will be locked, so no one can take loan from that amount and once the loan are over you can safely withdraw, without taking the risk of someone taking a loan in the meantime.

Usage is fairly simple:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
setMaxAmountUsable
} = rain;

const ix = await setMaxAmountUsable(200);
const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

Also, as you can see, this function doesn't accept any 'Pool' parameter. When you initialize new Rain() instance, you have to specify publicKey. This function will fetch pool by owner, where the owner is the publicKey specified during initialization. Make sure to use YOUR address, not randomly generated one / placeholder.

updatePoolStatus()

Function is used to generate transaction instruction for enabling/disabling pool. If the pool is disabled, it will enable it, if pool is enabled, will disable it - simple as that. No parameter required since function finds the pool from the address used during Rain initialization.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
updatePoolStatus
} = rain;

const ix = await updatePoolStatus();
const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

liquidateMortgage()

liquidateMortgage() function allows borrower to manually liquidate their mortgage. As a result, borrower won't have to repay the borrowed amount, but will lose both initial deposit and purchased NFT.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
liquidateMortgage,
utils,
} = rain;

const {
getMortgageFromAddress
} = utils;

const mortgages = await getMortgageFromAddress(
connection,
new PublicKey("<Your Address>"),
"borrower",
true,
);

const mortgageToLiquidate = mortgages[0];

const ix = await liquidateMortgage(
new PublicKey(mortgageToLiquidate.accountAddress)
);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

liquidateLoan()

liquidateLoan() function allows borrower to manually liquidate their loan, even before loan duration is exceeded.

This may be useful in case of big NFT floor price dump, when it's more profitable to liquidate the loan, than to repay it and sell the NFT itself.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
liquidateLoan,
utils,
} = rain;

const {
getLoansFromBorrower
} = utils

const loans = await getLoansFromBorrower(
connection,
new PublicKey("<Your Address Here>")
);

const loanToLiquidate = loans[0];

const ix = await liquidateLoan(
new PublicKey(loanToLiquidate.accountAddress)
);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

As you can see, in this code snippet we're fetching all loans taken by particular borrower (using getLoansFromBorrower()) and liquidating the first one found.

makeLoanRequest()

After you initialize new Pool instance, you can send loan requests to that pool. To do it, use makeLoanRequest() function.

Function accepts three parameters:

  • nftMint - mint address of the NFT you want to borrow Solana against.
  • duration - requested loan duration (in days).
  • amount - requested loan amount. In the snippet below, we're using 125% of the maximum amount accepted by the pool.
  • poolOwner - you have to specify which pool is the recipient of the request. Each owner can only have one pool, so pool will be fetched by owner's address.

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
makeLoanRequest,
utils,
} = rain;

const {
getPoolFromOwnerAddress,
getCollection
} = utils;

const poolOwner = new PublicKey("<Pool Owner Address>");

const { loanToValue, maxDuration, collections } = await getPoolFromOwnerAddress(
connection,
poolOwner
);

const maxDurationInDays = maxDuration / 60 / 60 / 24;
const duration = maxDurationInDays * 2; // We're requesting loan duration which is 2x longer than maximum accepted by the pool.
const { collection } = collections[0];

const { floorPrice } = await getCollection(
connection,
collection // First collection supported by the above pool.
);

const ix = await makeLoanRequest({
poolOwner,
duration,
amount: floorPrice * loanToValue * 1.25, // We're requesting loan amount which is 25% bigger than maximum accepted by the pool.
nftMint: new PublicKey("<Mint Address Of The Collateralized NFT>"),
});

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

In this case, we have a pool owner address as a constant. Then, knowing each owner can have only one pool, we're fetching the pool data (see getPoolFromOwnerAddress()).

Then, we proceed to making the loan request using makeLoanRequest() function. We pass poolOwner and floorPrice parameters.

Then, as a duration, we're taking pool's max accepted duration and multiply it by 2, so our request duration is two times longer than normally accepted by the pool. We also customize the loan amount - we multiply floorPrice by loanToValue to get maximum amount of Solana we could get from that pool, and we multiply that by 1.25, so our loan request amount is actually 25% bigger than it could be normally.

As the last parameter, function accepts nftMint, which is simply mint address of the NFT you want to collateralize.

updatePool()

This function allows you to generate transaction instructions for updating your pool's data.

Using updatePool(), you can change almost all properies of your pool - like compound, interest type, max loan duration, long/short term interest, etc.

You can use this function to adjust your pool, maximize profits and adapt to current NFT market state.

Usage is very simple:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
updatePool
} = rain;

const {
getPoolFromOwnerAddress
} = utils;

const poolOwner = new PublicKey("<Your Address>");
const poolData = await getPoolFromOwnerAddress(
connection,
poolOwner
);

// We're destructuring `poolData` object
// and passing all it's properties.
// Then, we overwrite `poolData` properties
// with new values. Everything that we don't
// overwrite will stay the same.
const ix = await updatePool({
...poolData,
compound: false, // We disable compound in our pool.
loanLiquidation: 500, // Ignore for now. Will be used in the future.
status: PoolStatus.Ready, // or PoolStatus.Disabled or PoolStatus.Pending
});

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

In above snippet, we're updating compound, and status of our pool. The rest of the pool's properties will stay the same.

buyListedMortgage()

When borrower is not able to repay the mortgage, they have to sell it (or they will be liquidated). To buy a mortgage listed for sale, you can use buyListedMortgage() function.

To get mortgages listed for sale, use getMortgageForSale() utility function, and apply custom filters to it. Then, choose mortgage you want to purchase, and pass mortgage account (returned from getMortgageForSale() function) and pool owner's address as parameters.

You can also use this snippet:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
buyListedMortgage
} = rain;

const {
getMortgageForSale,
getAllPoolAvailable
} = utils;

const mortgages = await getMortgageForSale(
connection,
517,
);

const mortgageToBuy = mortgages[0];
const { pool } = mortgageToBuy;

const allPools = await getAllPoolAvailable(connection);
const poolData = allPools.find(p => p.poolAddress === pool);

const ixs = await buyListedMortgage(
mortgageToBuy,
new PublicKey(poolData.owner)
);

const { blockhash } = await connection.getLatestBlockhash();
const msg = new TransactionMessage({
payerKey: publicKey,
instructions: ixs.map(ix => ix.ixs).flat(1),
recentBlockhash: blockhash
});

const tx = new VersionedTransaction(msg.compileToV0Message());

const signers = ixs.map(ix => ix.signers);
tx.sign(signers);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

It's very important to acknowledge that instructions returned by buyListedMortgage() function need to be sent in a VersionedTransaction (used in snippet above), or in two separate transactions. They can't be batched together in normal transaction.

deserializeLoanAccount(), deserializeCollectionAccount(), deserializePoolAccount(), deserializeLoanRequestAccount()

All four functions do pretty much the same thing - they deserialize program-owned accounts' data and return valid types, which you can use to explore Collection, Pool, Loan and LoanRequest properties. You can also use returned data as parameters for other functions.

To start, you'll need to fetch the account data, that you will deserialize later on. To do this, you can use getFiltersCollections(), getFiltersLoan(), getFiltersPool(), getFiltersLoanRequest() functions followed by Solana SDK-native getProgramAccounts() calls. Use snippet below as an example:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
deserializePoolAccount
} = rain;

const {
getFiltersPool
} = utils;

const filters = await getFiltersPool([{
key: "owner",
value: "<Your Address>"
}]);

const pools = await connection.getProgramAccounts(
new PublicKey("RainEraPU5yDoJmTrHdYynK9739GkEfDsE4ffqce2BR"),
// ^ Address of official Rain.fi program deployment.
{filters}
);

const deserialized = pools.map(pool => deserializePoolAccount(pool.account));

console.log({deserialized});

In this particular case, we're deserializing all accounts that represent pools owned by given address. In all 4 cases, usage is similar. You just have to replace get<Account>Pool() with one of the four functions above, and adjust the filter array. Then, you have to set deserialize<Account>Account() accordingly.

executeLoanRequest()

Each loan request has three steps. First, request is sent by the borrower to the pool. Then, pool can reject or accept the request. If it gets accepted, it can (but doesn't have to) be executed.

Addidional execution step is added, because between request being sent and request being accepted, market conditions could change. Floor prices fluctuate all the time, so loan can get unprofitable in the meantime.

So, after loan request is accepted by the pool, you can use executeLoanRequest() function to execute it.

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
executeLoanRequest,
deserializeLoanRequestAccount
} = rain;

const {
getPoolFromOwnerAddress,
getFiltersLoanRequest,
getCollection,
getFeesDetailed
} = utils;

// Get pool data.
const pool = await getPoolFromOwnerAddress(
connection,
new PublicKey("<Address>")
);

// Get filters for fetching all loan requests in specified pool.
const filters = await getFiltersLoanRequest([
{
key: "pool",
value: pool.poolAddress
}
]);

// Fetch all loan requests and their data.
const loanRequests = await connection.getProgramAccounts(
new PublicKey("RainEraPU5yDoJmTrHdYynK9739GkEfDsE4ffqce2BR"),
// ^ Address of official Rain.fi program deployment.
{filters}
);

// Select first loan request.
const loanRequestToExecute = loanRequests[0];

// Parse loan request from buffer to human-readble, valid object.
const { collection, amount, duration } = await deserializeLoanRequestAccount(loanRequestToExecute.account);

// Fetch floor price of the collection that item belongs to.
const { floorPrice } = await getCollection(
connection,
collection
);

// Calculate fees.
const { feesInSol } = getFeesDetailed(
pool,
amount,
duration,
);

// Get instructions for loan request execution.
const { instruction, signers } = await executeLoanRequest({
loanRequestAddress: loanRequestToExecute.pubkey,
amount,
duration,
slippage: 50,
interest: feesInSol
});

const tx = new Transaction();
tx.add(...instruction);
tx.partialSign(signers);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

cancelLoanRequest()

Use this function to cancel pending loan request. cancelLoanRequest() is useful especially in case of major collection's floor price changes, that affets profitability of the loan.

Example usage code snippet:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
cancelLoanRequest,
} = rain;

const {
getFiltersLoanRequest
} = utils;

const filters = getFiltersLoanRequest([{
key: "borrower",
value: "<Your Address Here>"
}]);

const loanRequests = await connection.getProgramAccounts(
new PublicKey("RainEraPU5yDoJmTrHdYynK9739GkEfDsE4ffqce2BR"),
// ^ Address of official Rain.fi program deployment.
{filters}
);

const loanToCancel = loanRequests[0];
const ix = await cancelLoanRequest(
loanToCancel.pubkey
);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

updatePoolCollections()

updatePoolCollections() function is used to generate transaction instructions for whitelisting new collections in a particular pool.

As you can see, function accepts one parameter - array of supported collections. It doesn't need Pool param - changes will be applied to pool owned by the address used for Rain initialization.

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
updatePoolCollections
} = rain;

const ix = await updatePoolCollections([{
collection: 517, // Bold Badgers collectionId
collectionLtv: 8000 // 80%
}]);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

poolCancelLoanProposal()

This function is used by pool owners to reject custom loan requests. The function accepts one parameter - address of the account representing loan request. To get it, use getFiltersLoanRequest() followed by getProgramAccounts() call.

Also, be aware that you can only reject loan requests that were sent to your pool! Make sure to use correct address during Rain initialization - pool will be fetched by owner's address.

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
utils,
poolCancelLoanProposal
} = rain;

const {
getPoolFromOwnerAddress,
getFiltersLoanRequest
} = utils;

// Fetch your pool.
const pool = await getPoolFromOwnerAddress(
connection,
new PublicKey("<Your Address Here>")
);

// Fetch all pending loan requests from your pool.
const filters = await getFiltersLoanRequest([{
key: "pool",
value: pool.poolAddress
}]);

// Fetch loan requests accounts & data.
const loanRequests = await connection.getProgramAccounts(
new PublicKey("RainEraPU5yDoJmTrHdYynK9739GkEfDsE4ffqce2BR"),
// ^ Address of official Rain.fi program deployment.
{filters}
);

// Select the first request to cancellation.
const loanRequestToCancel = loanRequests[0];

// Generate instructions.
const ix = await poolCancelLoanProposal(loanRequestToCancel.pubkey);

const tx = new Transaction();
tx.add(ix);

// Transaction is ready to be signed & sent to the Solana network.
// Visit https://solanacookbook.com/ to see how to sign & send transactions.

getAllUsersStats()

getAllUsersStats() function is used to fetch and explore user's stats in the Rain protocol.

As you can see below, function does not require any parameter specifying address. Address, to which returned stats belong, will be the same address you use for Rain initialization. Make sure to initialize it with real PublicKey, not randomly generated one (or placeholder).

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
getAllUsersStats
} = rain;

const stats = await getAllUsersStats();
console.log({stats});

Returned value will be represented by UserStats type:

{
owner: PublicKey;
totalLoan: number;
totalMortgage: number;
totalLiquidation: number;
currentLoan: number;
currentMortgage: number;
createdAt: number;
}

getUserStats()

getUserStats() function allows you to fetch stats for a particular address, not only yours (as in getAllUsersStats()).

As the second parameter, function accepts array of mint address to check.

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
getUserStats
} = rain;

const addressToCheck = new PublicKey("<Address>");
const stats = await getUserStats(
addressToCheck,
[
"So11111111111111111111111111111111111111112", // Solana
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", // USDC
]
);

console.log({stats});

getAllUsersMintStats()

getAllUsersMintStats() function is used to fetch and explore user's mint stats.

As you can see below, function does not require any parameter specifying address. Address, to which returned stats belong, will be the same address you use for Rain initialization. Make sure to initialize it with real PublicKey, not randomly generated one (or placeholder).

Usage:

// To see how to initialize new Rain class, see code snippet above.
const rain = new Rain(
connection,
publicKey
);

const {
getAllUsersMintStats
} = rain;

const stats = await getAllUsersMintStats();
console.log({stats});

Returned value will be represented by array of UserMintStats objects:

{
owner: PublicKey;
mint: PublicKey;
totalAmount: number;
currentAmount: number;
createdAt: number;
}