solana-program-library/token-lending/js/client/index.ts

157 lines
4.1 KiB
TypeScript

/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import {
Account,
Connection,
PublicKey,
SystemProgram,
Transaction,
TransactionInstruction,
SYSVAR_RENT_PUBKEY,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import * as BufferLayout from "buffer-layout";
import * as Layout from "./layout";
export const LENDING_PROGRAM_ID = new PublicKey(
"LendZqTs7gn5CTSJU1jWKhKuVpjJGom45nnwPb2AMTi"
);
/**
* @private
*/
export const LendingMarketLayout: typeof BufferLayout.Structure = BufferLayout.struct(
[
BufferLayout.u8("version"),
BufferLayout.u8("bumpSeed"),
Layout.publicKey("owner"),
Layout.publicKey("quoteTokenMint"),
Layout.publicKey("tokenProgramId"),
BufferLayout.blob(62, "padding"),
]
);
export type CreateLendingMarketParams = {
connection: Connection;
tokenProgramId?: PublicKey;
lendingProgramId: PublicKey;
lendingMarketAccount: Account;
lendingMarketOwner: PublicKey;
quoteTokenMint: PublicKey;
payer: Account;
};
export class LendingMarket {
account: Account;
connection: Connection;
owner: PublicKey;
quoteTokenMint: PublicKey;
tokenProgramId: PublicKey;
lendingProgramId: PublicKey;
payer: Account;
constructor(params: CreateLendingMarketParams) {
this.account = params.lendingMarketAccount;
this.connection = params.connection;
this.owner = params.lendingMarketOwner;
this.quoteTokenMint = params.quoteTokenMint;
this.tokenProgramId = params.tokenProgramId || TOKEN_PROGRAM_ID;
this.lendingProgramId = params.lendingProgramId;
this.payer = params.payer;
}
static async create(
params: CreateLendingMarketParams
): Promise<LendingMarket> {
const lendingMarket = new LendingMarket(params);
// Allocate memory for the account
const balanceNeeded = await LendingMarket.getMinBalanceRentForExemptTokenReserve(
lendingMarket.connection
);
const transaction = new Transaction()
.add(
SystemProgram.createAccount({
fromPubkey: params.payer.publicKey,
newAccountPubkey: lendingMarket.account.publicKey,
lamports: balanceNeeded,
space: LendingMarketLayout.span,
programId: params.lendingProgramId,
})
)
.add(LendingMarket.createInitLendingMarketInstruction(lendingMarket));
await sendAndConfirmTransaction(
lendingMarket.connection,
transaction,
[lendingMarket.payer, lendingMarket.account],
{ commitment: "singleGossip", preflightCommitment: "singleGossip" }
);
return lendingMarket;
}
/**
* Get the minimum balance for the lending market account to be rent exempt
*
* @return Number of lamports required
*/
static async getMinBalanceRentForExemptTokenReserve(
connection: Connection
): Promise<number> {
return await connection.getMinimumBalanceForRentExemption(
LendingMarketLayout.span
);
}
static createInitLendingMarketInstruction(
lendingMarket: LendingMarket
): TransactionInstruction {
const programId = lendingMarket.lendingProgramId;
const keys = [
{
pubkey: lendingMarket.account.publicKey,
isSigner: false,
isWritable: true,
},
{
pubkey: lendingMarket.quoteTokenMint,
isSigner: false,
isWritable: false,
},
{ pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false },
{
pubkey: lendingMarket.tokenProgramId,
isSigner: false,
isWritable: false,
},
];
const commandDataLayout = BufferLayout.struct([
BufferLayout.u8("instruction"),
Layout.publicKey("owner"),
]);
let data = Buffer.alloc(1024);
{
const encodeLength = commandDataLayout.encode(
{
instruction: 0, // InitLendingMarket instruction
owner: lendingMarket.owner.toBuffer(),
},
data
);
data = data.slice(0, encodeLength);
}
return new TransactionInstruction({
keys,
programId,
data,
});
}
}