Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

feat(tools): updated bank config / fix account cache #1089

Merged
merged 6 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/tools/accounts/cache-accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type AccountCache = {
accounts: string[];
};

const CACHE_FILE = path.join(__dirname, "./account-cache.json");
const CACHE_FILE = path.join(__dirname, "../account-cache.json");

async function main() {
const argv = getDefaultYargsOptions().parseSync();
Expand Down
5 changes: 2 additions & 3 deletions packages/tools/accounts/get-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PublicKey } from "@solana/web3.js";
import { wrappedI80F48toBigNumber } from "@mrgnlabs/mrgn-common";
import { getDefaultYargsOptions, getMarginfiProgram } from "../lib/config";
import { Environment } from "../lib/types";
import { formatNumber } from "../lib/utils";
import { formatNumber, getBankMetadata } from "../lib/utils";

dotenv.config();

Expand All @@ -26,8 +26,7 @@ async function main() {
const program = getMarginfiProgram(argv.env as Environment);

// Fetch bank metadata
const bankMetadataResponse = await fetch("https://storage.googleapis.com/mrgn-public/mrgn-bank-metadata-cache.json");
const bankMetadata = (await bankMetadataResponse.json()) as BankMetadata[];
const bankMetadata = await getBankMetadata();

let acc = await program.account.marginfiAccount.fetch(accountPubkey);
let balances = acc.lendingAccount.balances;
Expand Down
6 changes: 2 additions & 4 deletions packages/tools/banks/get-bank-accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PublicKey } from "@solana/web3.js";
import { chunkedGetRawMultipleAccountInfos, chunks, wrappedI80F48toBigNumber } from "@mrgnlabs/mrgn-common";
import { getDefaultYargsOptions, getMarginfiProgram } from "../lib/config";
import { Environment } from "../lib/types";
import { formatNumber, getCachedAccounts } from "../lib/utils";
import { formatNumber, getCachedAccounts, getBankMetadata } from "../lib/utils";

dotenv.config();

Expand Down Expand Up @@ -55,9 +55,7 @@ async function main() {
.parseSync();

const program = getMarginfiProgram(argv.env as Environment);

const bankMetadataResponse = await fetch("https://storage.googleapis.com/mrgn-public/mrgn-bank-metadata-cache.json");
const bankMetadata = (await bankMetadataResponse.json()) as BankMetadata[];
const bankMetadata = await getBankMetadata();

let bankPubkey: PublicKey;
if (argv.address) {
Expand Down
43 changes: 36 additions & 7 deletions packages/tools/banks/get-bank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { PublicKey } from "@solana/web3.js";
import { wrappedI80F48toBigNumber } from "@mrgnlabs/mrgn-common";
import { getDefaultYargsOptions, getMarginfiProgram } from "../lib/config";
import { Environment } from "../lib/types";
import { formatNumber } from "../lib/utils";
import { formatNumber, getPythPushOracleAddresses, getBankMetadata } from "../lib/utils";

dotenv.config();

Expand Down Expand Up @@ -36,9 +36,7 @@ async function main() {
.parseSync();

const program = getMarginfiProgram(argv.env as Environment);

const bankMetadataResponse = await fetch("https://storage.googleapis.com/mrgn-public/mrgn-bank-metadata-cache.json");
const bankMetadata = (await bankMetadataResponse.json()) as BankMetadata[];
const bankMetadata = await getBankMetadata();

let bankPubkey: PublicKey;
if (argv.address) {
Expand All @@ -61,24 +59,55 @@ async function main() {
});
const oraclePriceData = await oraclePriceResponse.json();

const assetWeightInit = wrappedI80F48toBigNumber(acc.config.assetWeightInit);
const assetWeightMaint = wrappedI80F48toBigNumber(acc.config.assetWeightMaint);
const liabilityWeightInit = wrappedI80F48toBigNumber(acc.config.liabilityWeightInit);
const liabilityWeightMaint = wrappedI80F48toBigNumber(acc.config.liabilityWeightMaint);

const totalAssetShares = wrappedI80F48toBigNumber(acc.totalAssetShares);
const totalLiabilityShares = wrappedI80F48toBigNumber(acc.totalLiabilityShares);
const assetShareValue = wrappedI80F48toBigNumber(acc.assetShareValue);
const liabilityShareValue = wrappedI80F48toBigNumber(acc.liabilityShareValue);

const insuranceIrFee = wrappedI80F48toBigNumber(acc.config.interestRateConfig.insuranceIrFee);
const insiranceFixedFee = wrappedI80F48toBigNumber(acc.config.interestRateConfig.insuranceFeeFixedApr);
const protocolIrFee = wrappedI80F48toBigNumber(acc.config.interestRateConfig.protocolIrFee);
const protocolFixedFee = wrappedI80F48toBigNumber(acc.config.interestRateConfig.protocolFixedFeeApr);
const maxInterestRate = wrappedI80F48toBigNumber(acc.config.interestRateConfig.maxInterestRate);
const plateauInterestRate = wrappedI80F48toBigNumber(acc.config.interestRateConfig.plateauInterestRate);
const optimalUtilizationRate = wrappedI80F48toBigNumber(acc.config.interestRateConfig.optimalUtilizationRate);

const scaleFactor = Math.pow(10, acc.mintDecimals);
const totalAssetQuantity = totalAssetShares.times(assetShareValue).div(scaleFactor);
const totalLiabilityQuantity = totalLiabilityShares.times(liabilityShareValue).div(scaleFactor);

const oracleType = acc.config.oracleSetup.pythPushOracle !== undefined ? "Pyth" : "Switchboard";
const oracleKeys = acc.config.oracleKeys.filter((key) => !key.equals(PublicKey.default));
const pythOracleAddresses = oracleKeys.map((key) => getPythPushOracleAddresses(key.toBuffer()));

const bankData = {
Address: bankPubkey.toString(),
Mint: acc.mint.toString(),
Symbol: bankMeta?.tokenSymbol,
Decimals: acc.mintDecimals,
Price: `$${formatNumber(Number(oraclePriceData[0].priceRealtime.price))}`,
"Asset Tag": acc.config.assetTag,
"Asset Share Value": formatNumber(assetShareValue),
"Liability Share Value": formatNumber(liabilityShareValue),
"Oracle Type": oracleType,
"Oracle Keys": oracleKeys.join(", "),
...(oracleType === "Pyth" ? { "Pyth Oracle Addresses": pythOracleAddresses.join(", ") } : {}),
"Bank Type": acc.config.assetTag === 2 ? "Native Stake" : acc.config.riskTier.collateral ? "Global" : "Isolated",
"Asset Weight Init": assetWeightInit.toNumber(),
"Asset Weight Maint": assetWeightMaint.toNumber(),
"Liability Weight Init": liabilityWeightInit.toNumber(),
"Liability Weight Maint": liabilityWeightMaint.toNumber(),
"Insurance IR Fee": insuranceIrFee.toNumber(),
"Insurance Fixed Fee": insiranceFixedFee.toNumber(),
"Protocol IR Fee": protocolIrFee.toNumber(),
"Protocol Fixed Fee": protocolFixedFee.toNumber(),
"Max Interest Rate": maxInterestRate.toNumber(),
"Plateau Interest Rate": plateauInterestRate.toNumber(),
"Optimal Utilization Rate": optimalUtilizationRate.toNumber(),
"Asset Share Value": assetShareValue.toNumber(),
"Liability Share Value": liabilityShareValue.toNumber(),
"Asset Quantity": formatNumber(totalAssetQuantity),
"Asset Value (USD)": `$${formatNumber(totalAssetQuantity.times(oraclePriceData[0].priceRealtime.price))}`,
"Liability Quantity": formatNumber(totalLiabilityQuantity),
Expand Down
10 changes: 2 additions & 8 deletions packages/tools/banks/get-banks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,15 @@ import dotenv from "dotenv";
import { PublicKey } from "@solana/web3.js";
import { getDefaultYargsOptions, getMarginfiProgram } from "../lib/config";
import { Environment } from "../lib/types";
import { getBankMetadata } from "../lib/utils";

dotenv.config();

type BankMetadata = {
bankAddress: string;
tokenSymbol: string;
};

async function main() {
const argv = getDefaultYargsOptions().parseSync();
const program = getMarginfiProgram(argv.env as Environment);

const bankMetadataResponse = await fetch("https://storage.googleapis.com/mrgn-public/mrgn-bank-metadata-cache.json");
const bankMetadata = (await bankMetadataResponse.json()) as BankMetadata[];

const bankMetadata = await getBankMetadata();
const bankAddresses = bankMetadata.map((meta) => new PublicKey(meta.bankAddress));

const banks = await program.account.bank.fetchMultiple(bankAddresses);
Expand Down
5 changes: 5 additions & 0 deletions packages/tools/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PublicKey } from "@solana/web3.js";

export const PYTH_PUSH_ORACLE_ID = new PublicKey("pythWSnswVUd12oZpeFP8e9CVaEqJg25g1Vtc2biRsT");
export const PYTH_SPONSORED_SHARD_ID = 0;
export const MARGINFI_SPONSORED_SHARD_ID = 3301;
44 changes: 43 additions & 1 deletion packages/tools/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import BigNumber from "bignumber.js";
import { Keypair, PublicKey } from "@solana/web3.js";
import { groupedNumberFormatterDyn } from "@mrgnlabs/mrgn-common";
import { AccountCache } from "./types";
import { PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID, MARGINFI_SPONSORED_SHARD_ID } from "./constants";

dotenv.config();

Expand All @@ -16,17 +17,58 @@ export function loadKeypairFromFile(filePath: string): Keypair {
export function formatNumber(num: number | BigNumber): string {
const value = typeof num === "number" ? new BigNumber(num) : num;
if (value.eq(0)) return "0";
if (value.lt(1)) return value.toString();
return groupedNumberFormatterDyn.format(value.toNumber());
}

export function getCachedAccounts(): PublicKey[] {
const CACHE_FILE = path.join(__dirname, "../account-cache.json");

if (!fs.existsSync(CACHE_FILE)) {
throw new Error("Account cache not found. Please run 'yarn account:cache-all' first.");
throw new Error("Account cache not found. Please run 'pnpm accounts:cache' first.");
}

const cache: AccountCache = JSON.parse(fs.readFileSync(CACHE_FILE, "utf-8"));
const accounts = cache.accounts.map((addr) => new PublicKey(addr));
return accounts.sort(() => Math.random() - 0.5);
}

function u16ToArrayBufferLE(value: number): Uint8Array {
// Create a buffer of 2 bytes
const buffer = new ArrayBuffer(2);
const dataView = new DataView(buffer);

// Set the Uint16 value in little-endian order
dataView.setUint16(0, value, true);

// Return the buffer
return new Uint8Array(buffer);
}

function findPythPushOracleAddress(feedId: Buffer, programId: PublicKey, shardId: number): PublicKey {
const shardBytes = u16ToArrayBufferLE(shardId);
return PublicKey.findProgramAddressSync([shardBytes, feedId], programId)[0];
}

export function getPythPushOracleAddresses(feedId: Buffer): PublicKey[] {
return [
findPythPushOracleAddress(feedId, PYTH_PUSH_ORACLE_ID, PYTH_SPONSORED_SHARD_ID),
findPythPushOracleAddress(feedId, PYTH_PUSH_ORACLE_ID, MARGINFI_SPONSORED_SHARD_ID),
];
}

export async function getBankMetadata(): Promise<BankMetadata[]> {
const bankMetadataResponse = await fetch("https://storage.googleapis.com/mrgn-public/mrgn-bank-metadata-cache.json");
const stakedBankMetadataResponse = await fetch(
"https://storage.googleapis.com/mrgn-public/mrgn-staked-bank-metadata-cache.json"
);
const bankMetadata = (await bankMetadataResponse.json()) as BankMetadata[];
const stakedBankMetadata = (await stakedBankMetadataResponse.json()) as BankMetadata[];

return [...bankMetadata, ...stakedBankMetadata];
}

export type BankMetadata = {
bankAddress: string;
tokenSymbol: string;
};
5 changes: 3 additions & 2 deletions packages/tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@
"@solana/web3.js": "^1.91.3",
"bignumber.js": "^9.1.2",
"decimal.js": "^10.4.3",
"dotenv": "^16.4.7",
"mocha": "^10.2.0",
"ts-mocha": "^10.0.0",
"tsx": "^4.19.2"
},
"devDependencies": {
"@mrgnlabs/tsconfig": "workspace:*",
"@switchboard-xyz/on-demand": "^1.2.54",
"@types/bn.js": "^5.1.0",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0",
"big.js": "^6.2.1",
"chai": "^4.3.4",
"ts-node": "^10.9.1",
"typescript": "^4.3.5",
"@switchboard-xyz/on-demand": "^1.2.54"
"typescript": "^4.3.5"
}
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading