The marginfi TypeScript SDK
The marginfi-client-v2 and mrgn-common NPM packages are the official TypeScript SDKs for interacting with the marginfi protocol. You can use these SDKs in your Node.js frontend and backend to perform tasks like creating banks, making deposits to existing banks, and more.
Access the TypeScript SDK source code using this link.
Installation
It is recommended you use at least Node version 20.10.0
and NPM version 10.2.3
.
To get started, simply initialize your Node.js project and install the packages using your preferred package manager.
Using NPM
npm install @mrgnlabs/marginfi-client-v2 @mrgnlabs/mrgn-common
Using Yarn
yarn add @mrgnlabs/marginfi-client-v2 @mrgnlabs/mrgn-common
Getting Started
Step 1: Initialize the marginfi client
This example uses @solana/web3.js version 1.91.8
In order to interact with the marginfi SDK, we must first configure the marginfi client object using the MarginfiClient
instance:
Example
import { Connection } from "@solana/web3.js";
import { MarginfiClient, getConfig } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
const connection = new Connection(CLUSTER_CONNECTION, "confirmed");
const wallet = NodeWallet.local();
const config = getConfig("dev");
const client = await MarginfiClient.fetch(config, wallet, connection);
connection
establishes a connection to a Solana clusterwallet
creates an Anchor-compliant Node.js wallet from your local Solana keypairconfig
returns a configuration object specific to the specified environment (e.g. “production”, “development”)client
is a high-level SDK for interacting with the Marginfi protocol
Step 2: Create an Account
Accounts on marginfi are the entry point for interacting with the protocol, allowing users to deposit assets, take out loans, and manage their positions. Using the marginfi SDK, you can create an account with one line of code. With this ability, you can enable seamless user onboarding by creating dedicated accounts for each new user.
Example
const marginfiAccount = await client.createMarginfiAccount();
Step 3: Fetch a Bank
In order to interact with asset pools, or “banks,” on marginfi, you must first fetch the specific bank you want to borrow/lend from:
Example
const bankLabel = "SOL";
const bank = client.getBankByTokenSymbol(bankLabel);
if (!bank) throw Error(`${bankLabel} bank not found`);
bankLabel
holds the symbol for the bank that you will fetch. Note that you can also query banks by the token mint address (usinggetBankByMint
) or by the bank address (usinggetBankByPk
).bank1
fetches the specified bank usinggetBankByTokenSymbol
, using the bank’s token symbol “SOL” as the query parameter.
Step 4: Make a Deposit
Once you’ve fetched the bank you want to interact with, you can make a deposit:
Example
await marginfiAccount.deposit(1, bank.address);
The deposit
method on the marginfi account object allows you to make a deposit into the specified bank account using the bank's address as a parameter (second parameter). Note that the first parameter let’s you specify how much (in the denominated asset) you want to deposit into the bank.
Step 5: Borrow From a Bank
After lending liquidity on marginfi, you’re account is eligible to act as a Borrower. You can borrow liquidity from marginfi banks using one line of code:
Example
await marginfiAccount.borrow(1, bank.address);
The structure of the borrow
method is identical to the deposit
method. You specify the amount you want to borrow using the first parameter, and you specify which bank you want to interact with using the second parameter.
if you followed along with these steps, you just want through the full lending-and-borrowing lifecycle on marginfi. To execute your node, simply tun ts-node <file-path>
in your terminal. You’re code should look like this:
Example
import { Connection } from "@solana/web3.js";
import { MarginfiClient, getConfig } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
const CLUSTER_CONNECTION = <your-rpc-url>;
const main = async () => {
const connection = new Connection(CLUSTER_CONNECTION, "confirmed");
const wallet = NodeWallet.local();
const config = getConfig("dev");
const client = await MarginfiClient.fetch(config, wallet, connection); // initialize client
const marginfiAccount = await client.createMarginfiAccount(); // create an account
const bankLabel = "SOL";
const bank = client.getBankByTokenSymbol(bankLabel);
if (!bank) throw Error(`${bankLabel} bank not found`); // fetch a bank
await marginfiAccount.deposit(1, bank.address); // make a deposit
await marginfiAccount.borrow(1, bank.address); // borrow from a bank
};
main();
You’re now a mrgn mama! For more details on the marginfi SDK and use cases, refer to the sections below.
Classes
MarginfiClient
The MarginfiClient
instance is the entry point to interact with the marginfi protocol. You can setup your MarginfiClient
like so:
Example
const connection = new Connection(CLUSTER_CONNECTION, "confirmed");
const wallet = NodeWallet.local()
const config = getConfig("dev");
const client = await MarginfiClient.fetch(config, wallet, connection);
Bank
The Bank class represents a bank account on the Marginfi protocol. It encapsulates all the properties and methods related to a specific bank, such as token details, vault addresses, share values, configuration settings, and computations for asset/liability quantities, interest rates, and remaining capacities. It serves as a central point for interacting with and managing a bank within the Marginfi ecosystem.
Properties
- Name
address
- Type
- PublicKey
- Description
The public key or address of the bank.
- Name
tokenSymbol
- Type
- string | undefined
- Description
The symbol or ticker of the token associated with the bank (if available).
- Name
group
- Type
- PublicKey
- Description
The public key of the group that the bank belongs to.
- Name
mint
- Type
- PublicKey
- Description
The public key of the mint associated with the bank's token.
- Name
mintDecimals
- Type
- number
- Description
The number of decimals for the bank's token.
- Name
assetShareValue
- Type
- BigNumber
- Description
The value of one asset share in the bank.
- Name
liabilityShareValue
- Type
- BigNumber
- Description
The value of one liability share in the bank.
- Name
liquidityVault
- Type
- PublicKey
- Description
The public key of the liquidity vault associated with the bank.
- Name
liquidityVaultBump
- Type
- number
- Description
The bump seed used to derive the liquidity vault authority.
- Name
liquidityVaultAuthorityBump
- Type
- number
- Description
The bump seed used to derive the liquidity vault authority.
- Name
insuranceVault
- Type
- PublicKey
- Description
The public key of the insurance vault associated with the bank.
- Name
insuranceVaultBump
- Type
- number
- Description
The bump seed used to derive the insurance vault authority.
- Name
insuranceVaultAuthorityBump
- Type
- number
- Description
The bump seed used to derive the insurance vault authority.
- Name
collectedInsuranceFeesOutstanding
- Type
- BigNumber
- Description
The amount of outstanding collected insurance fees.
- Name
feeVault
- Type
- PublicKey
- Description
The public key of the fee vault associated with the bank.
- Name
feeVaultBump
- Type
- number
- Description
The bump seed used to derive the fee vault authority.
- Name
feeVaultAuthorityBump
- Type
- number
- Description
The bump seed used to derive the fee vault authority.
- Name
collectedGroupFeesOutstanding
- Type
- BigNumber
- Description
The amount of outstanding collected group fees.
- Name
lastUpdate
- Type
- number
- Description
The timestamp of the last update to the bank.
- Name
config
- Type
- BankConfig
- Description
The configuration settings for the bank.
- Name
totalAssetShares
- Type
- BigNumber
- Description
The total number of asset shares in the bank.
- Name
totalLiabilityShares
- Type
- BigNumber
- Description
The total number of liability shares in the bank.
- Name
emissionsActiveBorrowing
- Type
- boolean
- Description
Indicates whether emissions are active for borrowing.
- Name
emissionsActiveLending
- Type
- boolean
- Description
Indicates whether emissions are active for lending.
- Name
emissionsRate
- Type
- number
- Description
The rate of emissions for the bank.
- Name
emissionsMint
- Type
- PublicKey
- Description
The public key of the mint associated with the bank's emissions.
- Name
emissionsRemaining
- Type
- BigNumber
- Description
The amount of emissions remaining for the bank.
Methods
Method Name | Parameters | Result Type(s) | Description |
---|---|---|---|
decodeBankRaw | encoded: Buffer | BankRaw | A static method that decodes a raw bank account data buffer. |
fromBuffer | address: PublicKey, buffer: Buffer | Bank | A static method that creates a Bank instance from a public key and account data buffer. |
fromAccountParsed | address: PublicKey, accountParsed: BankRaw, bankMetadata?: BankMetadata | Bank | A static method that creates a Bank instance from a public key, parsed account data, and optional bank metadata. |
getTotalAssetQuantity | None | BigNumber | Returns the total quantity of assets in the bank. |
getTotalLiabilityQuantity | None | BigNumber | Returns the total quantity of liabilities in the bank. |
getAssetQuantity | assetShares: BigNumber | BigNumber | Computes the quantity of assets for a given number of asset shares. |
getLiabilityQuantity | liabilityShares: BigNumber | BigNumber | Computes the quantity of liabilities for a given number of liability shares. |
getAssetShares | assetQuantity: BigNumber | BigNumber | Computes the number of asset shares for a given asset quantity. |
getLiabilityShares | liabilityQuantity: BigNumber | BigNumber | Computes the number of liability shares for a given liability quantity. |
computeAssetUsdValue | oraclePrice: OraclePrice, assetShares: BigNumber, marginRequirementType: MarginRequirementType, priceBias: PriceBias | BigNumber | Computes the USD value of a given number of asset shares. |
computeLiabilityUsdValue | oraclePrice: OraclePrice, liabilityShares: BigNumber, marginRequirementType: MarginRequirementType, priceBias: PriceBias | BigNumber | Computes the USD value of a given number of liability shares. |
computeUsdValue | oraclePrice: OraclePrice, quantity: BigNumber, priceBias: PriceBias, weightedPrice: boolean, weight?: BigNumber, scaleToBase?: boolean | BigNumber | Computes the USD value of a given quantity with various configurations. |
computeQuantityFromUsdValue | oraclePrice: OraclePrice, usdValue: BigNumber, priceBias: PriceBias, weightedPrice: boolean | BigNumber | Computes the quantity from a given USD value with various configurations. |
getPrice | oraclePrice: OraclePrice, priceBias: PriceBias, weightedPrice: boolean | BigNumber | Retrieves the price of the bank's token with various configurations. |
getAssetWeight | marginRequirementType: MarginRequirementType, oraclePrice: OraclePrice, ignoreSoftLimits?: boolean | BigNumber | Retrieves the asset weight based on the margin requirement type and other factors. |
getLiabilityWeight | marginRequirementType: MarginRequirementType | BigNumber | Retrieves the liability weight based on the margin requirement type. |
computeTvl | oraclePrice: OraclePrice | BigNumber | Computes the total value locked (TVL) of the bank based on the provided oracle price. |
computeInterestRates | None | { lendingRate: BigNumber; borrowingRate: BigNumber } | Computes the lending and borrowing interest rates for the bank. |
computeBaseInterestRate | None | BigNumber | Computes the base interest rate for the bank. |
computeUtilizationRate | None | BigNumber | Computes the utilization rate of the bank. |
computeRemainingCapacity | None | { depositCapacity: BigNumber; borrowCapacity: BigNumber } | Computes the remaining deposit and borrow capacity of the bank. |
describe | oraclePrice: OraclePrice | string | Returns a string describing the bank and its configuration based on the provided oracle price. |
NodeWallet
An Anchor-compliant wallet implementation for Node.js environments.
static local(): NodeWallet
:- Description: Creates a NodeWallet instance using the
MARGINFI_WALLET
environment variable or defaults to reading your local keypair from$HOME/.config/solana/id.json
.
- Description: Creates a NodeWallet instance using the
static anchor(): NodeWallet
:- Description: Creates a NodeWallet instance using the
ANCHOR_WALLET
environment variable, throwing an error if the variable is not set.
- Description: Creates a NodeWallet instance using the
MarginfiGroup
Represents a group within the marginfi protocol, managed by an admin, and provides methods for performing administrative actions on marginfi accounts and banks. Users can create instances from raw data, enable or disable flash loans, manage account transfer authority, and configure banks within the group.
Balance
Represents the balance of a user's assets and liabilities within a specific bank in the Marginfi protocol. It includes properties for the bank's public key, asset shares, liability shares, outstanding emissions, and the last update timestamp.
Properties
- Name
active
- Type
- boolean
- Description
Indicates whether the balance is active or not.
- Name
bankPk
- Type
- PublicKey
- Description
The public key of the bank associated with the balance.
- Name
assetShares
- Type
- BigNumber
- Description
The amount of asset shares held in the balance.
- Name
liabilityShares
- Type
- BigNumber
- Description
The amount of liability shares held in the balance.
- Name
emissionsOutstanding
- Type
- BigNumber
- Description
The amount of outstanding emissions associated with the balance.
- Name
lastUpdate
- Type
- number
- Description
The timestamp of the last update to the balance.
Methods
Method Name | Parameters | Result Type(s) | Description |
---|---|---|---|
from | balanceRaw: BalanceRaw | Balance | A static method that creates a new Balance instance from a BalanceRaw object. |
createEmpty | bankPk: PublicKey | Balance | A static method that creates a new empty Balance instance with the given bank public key. |
computeUsdValue | bank: Bank, oraclePrice: OraclePrice, marginRequirementType: MarginRequirementType = MarginRequirementType.Equity | { assets: BigNumber; liabilities: BigNumber } | Computes the USD value of the assets and liabilities in the balance based on the provided bank, oracle price, and margin requirement type. |
getUsdValueWithPriceBias | bank: Bank, oraclePrice: OraclePrice, marginRequirementType: MarginRequirementType = MarginRequirementType.Equity | { assets: BigNumber; liabilities: BigNumber } | Similar to computeUsdValue , but applies a price bias when computing the USD value of assets and liabilities. |
computeQuantity | bank: Bank | { assets: BigNumber; liabilities: BigNumber } | Computes the quantity of assets and liabilities in the balance based on the provided bank. |
computeQuantityUi | bank: Bank | { assets: BigNumber; liabilities: BigNumber } | Similar to computeQuantity , but converts the quantities to the user interface format. |
computeTotalOutstandingEmissions | bank: Bank | BigNumber | Computes the total outstanding emissions associated with the balance based on the provided bank. |
computeClaimedEmissions | bank: Bank, currentTimestamp: number | BigNumber | Computes the claimed emissions associated with the balance based on the provided bank and the current timestamp. |
describe | bank: Bank, oraclePrice: OraclePrice | string | Returns a string describing the balance, including the asset and liability quantities and their USD values. |
Attributes
- Name
getAllMarginfiAccountPubkeys
- Type
- Argument(s): None
- Description
Retrieves the public keys of all marginfi accounts in the specified group.
- Name
getMultipleMarginfiAccounts
- Type
- Argument(s): pubkeys
- Description
Fetches multiple marginfi accounts based on an array of public keys.
- Name
getAllMarginfiAccountAddresses
- Type
- Argument(s): None
- Description
Retrieves the addresses of all marginfi accounts in the underlying group.
- Name
getMarginfiAccountsForAuthority
- Type
- Argument(s): authority (optional)
- Description
Retrieves all marginfi accounts under the specified authority.
- Name
getAllProgramAccountAddresses
- Type
- Argument(s): type
- Description
Retrieves the addresses of all accounts owned by the marginfi program of a specified type.
- Name
getBankByPk
- Type
- Argument(s): bankAddress
- Description
Finds a bank by its public key address.
- Name
getBankByMint
- Type
- Argument(s): mint
- Description
Finds a bank by its mint address.
- Name
getBankByTokenSymbol
- Type
- Argument(s): tokenSymbol
- Description
Finds a bank by its token symbol.
- Name
getOraclePriceByBank
- Type
- Argument(s): bankAddress
- Description
Retrieves the oracle price for a specified bank.
User actions
- Name
makeCreateMarginfiAccountIx
- Type
- Argument(s): marginfiAccountPk
- Description
Creates a transaction instruction to create a new marginfi account under the authority of the user.
- Name
createMarginfiAccount
- Type
- Argument(s): opts (optional), createOpts (optional)
- Description
Creates a new marginfi account under the authority of the user.
Helpers
- Name
processTransaction
- Type
- Argument(s): transaction, signers (optional), opts (optional)
- Description
Processes a transaction, signs it, and sends it to the network.
- Name
simulateTransaction
- Type
- Argument(s): transaction, accountsToInspect
- Description
Simulates a transaction and inspects the provided accounts.
Utilities
- Name
getBankVaultSeeds
- Type
- Argument(s): type
- Description
Returns the seed buffer for a specific bank vault type.
- Name
getBankVaultAuthoritySeeds
- Type
- Argument(s): type
- Description
Returns the authority seed buffer for a specific bank vault type.
- Name
getBankVaultAuthority
- Type
- Argument(s): bankVaultType, bankPk, programId
- Description
Computes the authority Program Derived Address (PDA) for a specific marginfi group bank vault.
- Name
makeWrapSolIxs
- Type
- Argument(s): walletAddress, amount
- Description
Creates instructions to wrap SOL into a native token account.
- Name
makeUnwrapSolIx
- Type
- Argument(s): walletAddress
- Description
Creates an instruction to unwrap SOL from a native token account.
- Name
makeVersionedTransaction
- Type
- Argument(s): blockhash, transaction, payer, addressLookupTables (optional)
- Description
Creates a versioned transaction from a given blockhash, transaction, and payer, optionally including address lookup tables.
Constants
Constant Name | Description |
---|---|
PDA_BANK_LIQUIDITY_VAULT_AUTH_SEED | Seed for the authority of the liquidity vault in a Program Derived Address (PDA). |
PDA_BANK_INSURANCE_VAULT_AUTH_SEED | Seed for the authority of the insurance vault in a PDA. |
PDA_BANK_FEE_VAULT_AUTH_SEED | Seed for the authority of the fee vault in a PDA. |
PDA_BANK_LIQUIDITY_VAULT_SEED | Seed for the liquidity vault in a PDA. |
PDA_BANK_INSURANCE_VAULT_SEED | Seed for the insurance vault in a PDA. |
PDA_BANK_FEE_VAULT_SEED | Seed for the fee vault in a PDA. |
PYTH_PRICE_CONF_INTERVALS | Confidence interval for Pyth price feeds, set to 2.12. |
SWB_PRICE_CONF_INTERVALS | Confidence interval for SWB price feeds, set to 1.96. |
MAX_CONFIDENCE_INTERVAL_RATIO | Maximum allowed ratio for confidence intervals, set to 0.05. |
USDC_DECIMALS | Number of decimal places for USDC, set to 6. |
ADDRESS_LOOKUP_TABLE_FOR_GROUP | A mapping of group identifiers to an array of public keys for address lookup tables. |
DISABLED_FLAG | Flag indicating that a feature is disabled, represented by the value 1 << 0 . |
FLASHLOAN_ENABLED_FLAG | Flag indicating that flash loans are enabled, represented by the value 1 << 2 . |
TRANSFER_ACCOUNT_AUTHORITY_FLAG | Flag indicating the transfer of account authority, represented by the value 1 << 3 . |
Errors
Error | Description | Suggestion |
---|---|---|
NotRentExempt | Lamport balance is below the rent-exempt threshold. | Increase the lamport balance of the account to meet the rent-exempt threshold. |
InsufficientFunds | There are insufficient funds to complete the operation. | Add more funds to the account before retrying the operation. |
InvalidMint | The provided mint is invalid. | Verify and provide a valid mint address. |
MintMismatch | The account is not associated with the specified mint. | Ensure the account is associated with the correct mint. |
OwnerMismatch | The owner of the account does not match the expected owner. | Confirm the account owner and use the correct owner for the operation. |
FixedSupply | The token's supply is fixed and new tokens cannot be minted. | Use a token with a flexible supply if more tokens need to be minted. |
AlreadyInUse | The account cannot be initialized because it is already in use. | Use a different account or ensure the existing account is properly closed before re-initializing. |
InvalidNumberOfProvidedSigners | The number of provided signers is invalid. | Check the required number of signers and provide the correct amount. |
InvalidNumberOfRequiredSigners | The number of required signers is invalid. | Adjust the number of required signers to match the expected count. |
UninitializedState | The state is uninitialized. | Initialize the state before performing the operation. |
NativeNotSupported | The instruction does not support native tokens. | Use a different instruction that supports native tokens or use non-native tokens. |
NonNativeHasBalance | Non-native account can only be closed if its balance is zero. | Ensure the non-native account balance is zero before attempting to close it. |
InvalidInstruction | The instruction is invalid. | Review and correct the instruction being sent. |
InvalidState | The state is invalid for the requested operation. | Verify the current state and ensure it is valid for the intended operation. |
Overflow | The operation overflowed. | Adjust the operation to avoid exceeding the maximum limit. |
AuthorityTypeNotSupported | The account does not support the specified authority type. | Use a different account that supports the required authority type. |
MintCannotFreeze | The token mint cannot freeze accounts. | Use a token mint that has the capability to freeze accounts if needed. |
AccountFrozen | The account is frozen, and all account operations will fail. | Unfreeze the account before attempting any operations. |
MintDecimalsMismatch | There is a mint decimals mismatch between the client and the mint. | Ensure the mint decimals match between the client and the token mint. |
NonNativeNotSupported | The instruction does not support non-native tokens. | Use a different instruction that supports non-native tokens or switch to using native tokens. |
Types
- Name
Environment
- Description
Defines the possible configuration environments for the Marginfi protocol.
- Name
BankVaultType
- Description
Enum for marginfi bank vault types, which includes
LiquidityVault
,InsuranceVault
, andFeeVault
.
- Name
MarginfiConfig
- Description
Configuration interface for Marginfi, including environment, cluster, program ID, and group public key.
- Name
BankAddress
- Description
Interface representing a bank address with a label and a public key address.
- Name
AccountType
- Description
Enum for on-chain account types, which includes
MarginfiGroup
,MarginfiAccount
, andBank
.
- Name
BalanceRaw
- Description
Represents the raw on-chain data structure for a user's balance in the Marginfi protocol.
- Name
MarginfiGroupRaw
- Description
Represents the raw on-chain data structure for a Marginfi group.
Examples
Kickstart your development journey with a collection of insightful examples. Explore additional helpful examples within the marginfi monorepo.
Fetching All Banks Owned by the marginfi-v2 Program
Example
import { Connection, PublicKey } from "@solana/web3.js";
import { MarginfiClient, getConfig, AccountType, Bank } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
const RPC_ENDPOINT = "<RPC-URL>";
async function main() {
const connection = new Connection(RPC_ENDPOINT, "confirmed");
const wallet = NodeWallet.local();
const config = getConfig("production");
const client = await MarginfiClient.fetch(config, wallet, connection);
// Fetch all public keys of banks owned by the mfi program
const bankPubKeys = await client.getAllProgramAccountAddresses(AccountType.Bank);
const banks = await Promise.all(
bankPubKeys.map(async (bankPubKey) => {
try {
// Fetch account data for each bank
const accountInfo = await connection.getAccountInfo(bankPubKey);
if (accountInfo === null) {
console.error(`Failed to fetch account info for ${bankPubKey.toString()}`);
return null;
}
// Parse account data using Bank.fromBuffer
const bank = Bank.fromBuffer(bankPubKey, accountInfo.data);
return bank;
} catch (error) {
console.error(`Error processing bank ${bankPubKey.toString()}:`, error);
return null;
}
})
);
// Filter out any null values (failed fetches/parses)
const validBanks = banks.filter(bank => bank !== null);
validBanks.forEach((bank, index) => {
console.log(`Bank ${index + 1}:`, bank);
});
}
main().catch((e) => console.log(e));
Fetching and Exporting Depositors for a Specific Bank
Using the marginfi SDK, fetch all Marginfi accounts that have an active deposit in a specific bank token (e.g., SOL). Then export the wallet address, user account address, and deposit amount for those accounts into a CSV file.
Example
import { PublicKey, Connection } from "@solana/web3.js";
import { MarginfiAccountWrapper, MarginfiClient, getConfig } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet, chunkedGetRawMultipleAccountInfos, chunks } from "@mrgnlabs/mrgn-common";
import fs from "fs";
const BANK_TOKEN = "SOL";
interface BankDepositor {
wallet: string;
userAccount: string;
amount: number;
}
async function main() {
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const wallet = NodeWallet.local()
const config = getConfig("dev");
const client = await MarginfiClient.fetch(config, wallet, connection);
const targetBank = client.getBankByTokenSymbol(BANK_TOKEN);
if (!targetBank) {
throw new Error(`Bank ${BANK_TOKEN} not found`);
}
console.log(`Fetching all marginfi accounts...`)
const marginfiAccountAddresses = await client.getAllMarginfiAccountAddresses();
console.log(`Found ${marginfiAccountAddresses.length} marginfi accounts`);
const addressBatches = chunks(marginfiAccountAddresses, 25_000); // To avoid blowing memory
const depositorFileName = `./marginfi_depositors_${BANK_TOKEN}_${Date.now()}.csv`;
fs.writeFileSync(depositorFileName, "wallet,user_account,amount\n");
for (let i = 0; i < addressBatches.length; i++) {
const addressBatch = addressBatches[i];
console.log(`Processing batch ${i + 1}/${addressBatches.length} of ${addressBatch.length} addresses`);
const [_, accountInfoMap] = await chunkedGetRawMultipleAccountInfos(
client.provider.connection,
addressBatch.map((pk) => pk.toBase58())
);
let depositors: BankDepositor[] = [];
for (const [address, accountInfo] of accountInfoMap) {
const marginfiAccount = MarginfiAccountWrapper.fromAccountDataRaw(new PublicKey(address), client, accountInfo.data);
const depositAmount = marginfiAccount.balances
.find((b) => b.active && b.bankPk.equals(targetBank.address) && b.assetShares.gt(0))
?.computeQuantityUi(targetBank).assets;
if (depositAmount) {
depositors.push({
wallet: marginfiAccount.authority.toString(),
userAccount: marginfiAccount.address.toString(),
amount: depositAmount.toNumber(),
});
}
}
const csvContent = depositors.map(depositor => `${depositor.wallet},${depositor.userAccount},${depositor.amount}`).join('\n');
fs.appendFileSync(depositorFileName, csvContent);
}
}
main().catch((e) => console.log(e));
Account Creation and Deposit
The following program costs (developer-network) SOL to execute.
Use the marginfi SDK to create a new account and deposit tokens from two different banks (SOL and USDC) into the account. Then retrieve the active balances for the account, calculate the USD value of the assets and liabilities for each balance, and log this information to the console.
Example
import { Connection } from "@solana/web3.js";
import { MarginfiClient } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
async function main() {
const connection = new Connection("<rpc-url>", "confirmed");
const wallet = NodeWallet.local()
const config = getConfig("<environment>");
const client = await MarginfiClient.fetch(config, wallet, connection);
console.log(`Using ${client.config.environment} environment; wallet: ${client.wallet.publicKey.toBase58()}`);
const marginfiAccount = await client.createMarginfiAccount();
const bankLabel1 = "SOL";
const bank1 = client.getBankByTokenSymbol(bankLabel1);
if (!bank1) throw Error(`${bankLabel1} bank not found`);
const bankLabel2 = "USDC";
const bank2 = client.getBankByTokenSymbol(bankLabel2);
if (!bank2) throw Error(`${bankLabel2} bank not found`);
await marginfiAccount.deposit(1, bank1.address);
await marginfiAccount.deposit(2, bank2.address);
await marginfiAccount.reload();
marginfiAccount.activeBalances.forEach((balance) => {
const bank = client.getBankByPk(balance.bankPk)!;
const oraclePrice = client.getOraclePriceByBank(bank.address)!;
const { assets, liabilities } = balance.computeUsdValue(bank, oraclePrice, MarginRequirementType.Equity);
console.log(
`Balance for ${shortenAddress(bank.mint)} (${shortenAddress(
balance.bankPk
)}) deposits: ${assets}, borrows: ${liabilities}`
);
});
}
main().catch((e) => console.log(e));
Display a Accounts
Fetch a marginfi account and display it’s data.
Example
import { Connection } from "@solana/web3.js";
import { MarginfiClient, MarginfiAccountWrapper } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
const MFI_ACCOUNT_ADDRESS = "<account-address>"; // e.g., 3oS3RJ8UYrYw7TAQEVh6u6ifrHi35o3DnvqyqGti4Gwa
async function main() {
const connection = new Connection("<rpc-url>", "confirmed");
const wallet = NodeWallet.local()
const config = getConfig("<environment>");
const client = await MarginfiClient.fetch(config, wallet, connection);
const marginfiAccount = await MarginfiAccountWrapper.fetch(MFI_ACCOUNT_ADDRESS, client);
console.log("Account state:");
console.log(marginfiAccount.describe());
}
main().catch((e) => console.log(e));
Conduct a Flash Loan
Fetch a marginfi account, get a bank via token symbol, and perform a flashloan using the bank.
Example
import { Connection } from "@solana/web3.js";
import { MarginfiClient, MarginfiAccountWrapper } from '@mrgnlabs/marginfi-client-v2';
import { NodeWallet } from "@mrgnlabs/mrgn-common";
async function main() {
const connection = new Connection("<rpc-url>", "confirmed");
const wallet = NodeWallet.local()
const config = getConfig("<environment>");
const client = await MarginfiClient.fetch(config, wallet, connection);
const marginfiAccounts = await client.getMarginfiAccountsForAuthority();
if (marginfiAccounts.length === 0) throw Error("No marginfi account found");
const marginfiAccount = marginfiAccounts[0];
const solBank = client.getBankByTokenSymbol("SOL");
if (!solBank) throw Error("SOL bank not found");
const amount = 10; // SOL
const borrowIx = await marginfiAccount.makeBorrowIx(amount, solBank.address);
const repayIx = await marginfiAccount.makeRepayIx(amount, solBank.address, true);
const flashLoanTx = await marginfiAccount.buildFlashLoanTx({
ixs: [...borrowIx.instructions, ...repayIx.instructions],
signers: [],
});
await client.processTransaction(flashLoanTx);
}
main().catch((e) => console.log(e));