remove: @solana/spl-token

This commit is contained in:
g1nt0ki
2022-11-28 01:33:03 +01:00
parent 9572aff530
commit 603524510c
14 changed files with 513 additions and 809 deletions

52
package-lock.json generated
View File

@@ -12,7 +12,6 @@
"dependencies": {
"@defillama/sdk": "latest",
"@project-serum/anchor": "^0.25.0",
"@solana/spl-token": "^0.3.0",
"@solana/web3.js": "^1.36.0",
"@solendprotocol/solend-sdk": "^0.6.2",
"@supercharge/promise-pool": "^2.1.0",
@@ -1081,36 +1080,6 @@
"node": ">=5.10"
}
},
"node_modules/@solana/buffer-layout-utils": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz",
"integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==",
"dependencies": {
"@solana/buffer-layout": "^4.0.0",
"@solana/web3.js": "^1.32.0",
"bigint-buffer": "^1.1.5",
"bignumber.js": "^9.0.1"
},
"engines": {
"node": ">= 10"
}
},
"node_modules/@solana/spl-token": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.5.tgz",
"integrity": "sha512-0bGC6n415lGjKu02gkLOIpP1wzndSP0SHwN9PefJ+wKAhmfU1rl3AV1Pa41uap2kzSCD6F9642ngNO8KXPvh/g==",
"dependencies": {
"@solana/buffer-layout": "^4.0.0",
"@solana/buffer-layout-utils": "^0.2.0",
"buffer": "^6.0.3"
},
"engines": {
"node": ">=16"
},
"peerDependencies": {
"@solana/web3.js": "^1.47.4"
}
},
"node_modules/@solana/web3.js": {
"version": "1.63.1",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.63.1.tgz",
@@ -3399,27 +3368,6 @@
"buffer": "~6.0.3"
}
},
"@solana/buffer-layout-utils": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz",
"integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==",
"requires": {
"@solana/buffer-layout": "^4.0.0",
"@solana/web3.js": "^1.32.0",
"bigint-buffer": "^1.1.5",
"bignumber.js": "^9.0.1"
}
},
"@solana/spl-token": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.5.tgz",
"integrity": "sha512-0bGC6n415lGjKu02gkLOIpP1wzndSP0SHwN9PefJ+wKAhmfU1rl3AV1Pa41uap2kzSCD6F9642ngNO8KXPvh/g==",
"requires": {
"@solana/buffer-layout": "^4.0.0",
"@solana/buffer-layout-utils": "^0.2.0",
"buffer": "^6.0.3"
}
},
"@solana/web3.js": {
"version": "1.63.1",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.63.1.tgz",

View File

@@ -15,7 +15,6 @@
"dependencies": {
"@defillama/sdk": "latest",
"@project-serum/anchor": "^0.25.0",
"@solana/spl-token": "^0.3.0",
"@solana/web3.js": "^1.36.0",
"@solendprotocol/solend-sdk": "^0.6.2",
"@supercharge/promise-pool": "^2.1.0",

View File

@@ -1,21 +1,14 @@
const BigNumber = require("bignumber.js");
const { PublicKey } = require("@solana/web3.js");
const { Program, utils } = require("@project-serum/anchor");
const {
getAssociatedTokenAddress,
AccountLayout,
u64,
} = require("@solana/spl-token");
const { toUSDTBalances } = require("../helper/balances");
const { getProvider } = require("../helper/solana");
const { getProvider, sumTokens2 } = require("../helper/solana");
const MAX_NUMBER_OF_ACCOUNT_INFOS = 99;
const USDC_DECIMALS = 1_000_000;
const MARKET_SEED = "credix-marketplace";
const IDL = require("./credix.json");
const USDC = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'
const programId = new PublicKey("CRDx2YkdtYtGZXGHZ59wNv1EwKHQndnRc1gT4p8i2vPX");
const encodeSeedString = (seedString) =>
Buffer.from(utils.bytes.utf8.encode(seedString));
const encodeSeedString = (seedString) => Buffer.from(utils.bytes.utf8.encode(seedString));
const constructProgram = (provider) => {
return new Program(IDL, programId, provider);
@@ -36,26 +29,6 @@ const findSigningAuthorityPDA = async (globalMarketSeed) => {
return findPDA(seeds);
};
const getAssociatedBaseTokenAddressPK = async (publicKey) => {
const baseMintPK = new PublicKey(
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
); //USDC
return await getAssociatedTokenAddress(baseMintPK, publicKey, true);
};
async function fetchLiquidityPoolBalance() {
const provider = getProvider();
const signingAuthorityKey = await findSigningAuthorityPDA(MARKET_SEED);
const liquidityPoolKey = await getAssociatedBaseTokenAddressPK(
signingAuthorityKey[0]
);
const liquidityPool = await provider.connection.getTokenAccountBalance(
liquidityPoolKey
);
return new BigNumber(liquidityPool.value.amount.toString());
}
async function generateRepaymentSchedulePDA(deal) {
const marketAdress = await findGlobalMarketStatePDA(MARKET_SEED);
const seed = [
@@ -150,23 +123,6 @@ function chunk(inputArray, perChunk) {
return result;
}
async function asyncMap(arr, map) {
return Promise.all(arr.map(map));
}
async function baseTokenAccount(deal) {
const dealTokenAccount = encodeSeedString("deal-token-account");
const marketAddress = await findGlobalMarketStatePDA(MARKET_SEED);
const seeds = [
marketAddress[0].toBuffer(),
deal.publicKey.toBuffer(),
dealTokenAccount,
];
// TODO: just ignore the bump and return the public key
return PublicKey.findProgramAddress(seeds, programId);
}
async function fetchRepaymentScheduleForDeals(program, provider, deals) {
const pdaPromises = deals.map((d) => generateRepaymentSchedulePDA(d));
const pdas = await Promise.all(pdaPromises);
@@ -189,87 +145,9 @@ async function fetchRepaymentScheduleForDeals(program, provider, deals) {
return programVersions;
}
// TODO: clean up
async function tvl() {
const provider = getProvider();
const program = constructProgram(provider);
const liquidityPoolBalanceTokenAmount = await fetchLiquidityPoolBalance();
const allDeals = await program.account.deal.all();
const allRepaymentSchedules = await fetchRepaymentScheduleForDeals(
program,
provider,
allDeals
);
const tvlDealSchedulePairs = (
await allDeals.map((deal, index) => {
const schedule = allRepaymentSchedules[index];
// Return early so we don't try to get the status of a deal without a schedule
if (schedule === null) {
return null;
}
const dealStatus = status(deal.account, schedule);
switch (dealStatus) {
case "OPEN_FOR_FUNDING":
case "IN_PROGRESS":
case "CLOSED":
return [deal, schedule, dealStatus];
default:
return null;
}
})
).filter((pair) => pair !== null);
const tvlDeals = tvlDealSchedulePairs.map((p) => p[0]);
let dealsTokenAccountBalance = new BigNumber(0);
let dealsAmountWithdrawn = new BigNumber(0);
const schedulesPrincipal = tvlDealSchedulePairs.reduce(
(principalSum, pair) => {
if (pair[2] === "OPEN_FOR_FUNDING") {
return principalSum;
}
return principalSum.plus(totalPrincipal(pair[1]));
},
new BigNumber(0)
);
//////// Temp solution
// TODO: cleanup
const tokenAccountAddresses = (
await asyncMap(tvlDeals, (deal) => baseTokenAccount(deal))
).map((pda) => pda[0]);
const chunks = chunk(tokenAccountAddresses, MAX_NUMBER_OF_ACCOUNT_INFOS - 1);
const tokenAccountInfos = (
await asyncMap(chunks, (chunk) =>
provider.connection.getMultipleAccountsInfo(chunk)
)
)
.flat()
.filter((info) => info !== null);
dealsTokenAccountBalance = tokenAccountInfos
.map((info) => AccountLayout.decode(info.data))
.reduce(
(total, info) => total.plus(new BigNumber(info.amount.toString())),
new BigNumber(0)
);
/////////
for (const deal of tvlDeals) {
dealsAmountWithdrawn = dealsAmountWithdrawn.plus(
new BigNumber(deal.account.amountWithdrawn.toString())
);
}
const dealsLiquidity = dealsTokenAccountBalance.minus(
schedulesPrincipal.minus(dealsAmountWithdrawn)
);
const tvl = liquidityPoolBalanceTokenAmount.plus(dealsLiquidity);
return toUSDTBalances(tvl.dividedBy(USDC_DECIMALS));
const [signingAuthorityKey] = await findSigningAuthorityPDA(MARKET_SEED);
return sumTokens2({ tokensAndOwners: [[USDC, signingAuthorityKey]] });
}
async function borrowed() {
@@ -295,7 +173,9 @@ async function borrowed() {
.minus(principalRepaid(schedule));
}, new BigNumber(0));
return toUSDTBalances(totalOutstandingCredit.dividedBy(USDC_DECIMALS));
return {
['solana:' + USDC]: totalOutstandingCredit.toString()
};
}
module.exports = {

View File

@@ -1,5 +1,4 @@
const { getProvider, getConnection, sumTokens2, } = require("../helper/solana");
const { parseReserve } = require("../solend/utils");
const { getProvider, getConnection, sumTokens2, decodeAccount, } = require("../helper/solana");
const { Program, } = require("@project-serum/anchor");
const { PublicKey, } = require("@solana/web3.js");
const sdk = require('@defillama/sdk');
@@ -17,7 +16,7 @@ async function tvl() {
const reserveInfo = {}
for (const reserve of Object.values(reserves)) {
const [info] = await connection.getMultipleAccountsInfo([new PublicKey(reserve)])
const { info: { liquidity: { mintPubkey, marketPrice, }, collateral }} = parseReserve(info)
const { info: { liquidity: { mintPubkey, marketPrice, }, collateral }} = decodeAccount('reserve', info)
reserveInfo[collateral.mintPubkey.toString()] = { price: marketPrice/1e18, key: mintPubkey.toString(), }
}
const idl = await Program.fetchIdl(programId, provider)

View File

@@ -6,6 +6,8 @@ const { Connection, PublicKey, Keypair } = require("@solana/web3.js")
const { AnchorProvider: Provider, Wallet, } = require("@project-serum/anchor");
const BufferLayout = require("@solana/buffer-layout")
const { sleep, sliceIntoChunks, log, } = require('./utils')
const { decodeAccount } = require('./utils/solana/layout')
const sdk = require('@defillama/sdk')
const tokenMapping = tokens
@@ -416,4 +418,5 @@ module.exports = {
getTokenList,
getSolTokenMap,
readBigUInt64LE,
decodeAccount,
};

View File

@@ -0,0 +1,485 @@
const { deserializeUnchecked } = require('borsh');
const BufferLayout = require("buffer-layout");
const { PublicKey } = require("@solana/web3.js");
const BN = require("bn.js");
const publicKey = (property = "publicKey") => {
const publicKeyLayout = BufferLayout.blob(32, property);
const _decode = publicKeyLayout.decode.bind(publicKeyLayout);
const _encode = publicKeyLayout.encode.bind(publicKeyLayout);
publicKeyLayout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new PublicKey(data);
};
publicKeyLayout.encode = (key, buffer, offset) =>
_encode(key.toBuffer(), buffer, offset);
return publicKeyLayout;
};
/**
* Layout for a 64bit unsigned value
*/
const uint64 = (property = "uint64") => {
const layout = BufferLayout.blob(8, property);
const _decode = layout.decode.bind(layout);
const _encode = layout.encode.bind(layout);
layout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new BN(
[...data]
.reverse()
.map((i) => `00${i.toString(16)}`.slice(-2))
.join(""),
16
);
};
layout.encode = (num, buffer, offset) => {
const a = num.toArray().reverse();
let b = Buffer.from(a);
if (b.length !== 8) {
const zeroPad = Buffer.alloc(8);
b.copy(zeroPad);
b = zeroPad;
}
return _encode(b, buffer, offset);
};
return layout;
};
const uint128 = (property = "uint128") => {
const layout = BufferLayout.blob(16, property);
const _decode = layout.decode.bind(layout);
const _encode = layout.encode.bind(layout);
layout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new BN(
[...data]
.reverse()
.map((i) => `00${i.toString(16)}`.slice(-2))
.join(""),
16
);
};
layout.encode = (num, buffer, offset) => {
const a = num.toArray().reverse();
let b = Buffer.from(a);
if (b.length !== 16) {
const zeroPad = Buffer.alloc(16);
b.copy(zeroPad);
b = zeroPad;
}
return _encode(b, buffer, offset);
};
return layout;
};
const LastUpdateLayout = BufferLayout.struct(
[uint64("slot"), BufferLayout.u8("stale")],
"lastUpdate"
);
const ReserveLayout = BufferLayout.struct([
BufferLayout.u8("version"),
LastUpdateLayout,
publicKey("lendingMarket"),
BufferLayout.struct(
[
publicKey("mintPubkey"),
BufferLayout.u8("mintDecimals"),
publicKey("supplyPubkey"),
// @FIXME: oracle option
// TODO: replace u32 option with generic equivalent
// BufferLayout.u32('oracleOption'),
publicKey("pythOracle"),
publicKey("switchboardOracle"),
uint64("availableAmount"),
uint128("borrowedAmountWads"),
uint128("cumulativeBorrowRateWads"),
uint128("marketPrice"),
],
"liquidity"
),
BufferLayout.struct(
[
publicKey("mintPubkey"),
uint64("mintTotalSupply"),
publicKey("supplyPubkey"),
],
"collateral"
),
BufferLayout.struct(
[
BufferLayout.u8("optimalUtilizationRate"),
BufferLayout.u8("loanToValueRatio"),
BufferLayout.u8("liquidationBonus"),
BufferLayout.u8("liquidationThreshold"),
BufferLayout.u8("minBorrowRate"),
BufferLayout.u8("optimalBorrowRate"),
BufferLayout.u8("maxBorrowRate"),
BufferLayout.struct(
[
uint64("borrowFeeWad"),
uint64("flashLoanFeeWad"),
BufferLayout.u8("hostFeePercentage"),
],
"fees"
),
uint64("depositLimit"),
uint64("borrowLimit"),
publicKey("feeReceiver"),
],
"config"
),
BufferLayout.blob(256, "padding"),
]);
const MintLayout = BufferLayout.struct([
BufferLayout.u32('mintAuthorityOption'),
publicKey("mintAuthority"),
uint64('supply'),
BufferLayout.u8("decimals"),
BufferLayout.u8("isInitialized"),
BufferLayout.u32("freezeAuthorityOption"),
publicKey("freezeAuthority"),
]);
const AccountLayout = BufferLayout.struct([
publicKey('mint'),
publicKey('owner'),
uint64('amount'),
BufferLayout.u32('delegateOption'),
publicKey('delegate'),
BufferLayout.u8('state'),
BufferLayout.u32('isNativeOption'),
uint64('isNative'),
uint64('delegatedAmount'),
BufferLayout.u32('closeAuthorityOption'),
publicKey('closeAuthority'),
]);
const parseReserve = (info) => {
const pubkey = PublicKey.default
const { data } = info;
const buffer = Buffer.from(data);
const reserve = ReserveLayout.decode(buffer);
if (reserve.lastUpdate.slot.isZero()) {
return null;
}
const details = {
pubkey,
account: {
...info,
},
info: reserve,
};
return details;
}
const defaultParseLayout = Layout => info => {
const { data } = info;
const buffer = Buffer.from(data);
return Layout.decode(buffer);
}
class Lido {
constructor(data) {
Object.assign(this, data);
}
}
class SeedRange {
constructor(data) {
Object.assign(this, data);
}
}
class Validator {
constructor(data) {
Object.assign(this, data);
}
}
class PubKeyAndEntry {
constructor(data) {
Object.assign(this, data);
}
}
class PubKeyAndEntryMaintainer {
constructor(data) {
Object.assign(this, data);
}
}
class RewardDistribution {
constructor(data) {
Object.assign(this, data);
}
}
class FeeRecipients {
constructor(data) {
Object.assign(this, data);
}
}
class Validators {
constructor(data) {
Object.assign(this, data);
}
}
class Maintainers {
constructor(data) {
Object.assign(this, data);
}
}
class ExchangeRate {
constructor(data) {
Object.assign(this, data);
}
}
class Metrics {
constructor(data) {
Object.assign(this, data);
}
}
class LamportsHistogram {
constructor(data) {
Object.assign(this, data);
}
}
class WithdrawMetric {
constructor(data) {
Object.assign(this, data);
}
}
const schema = new Map([
[
ExchangeRate,
{
kind: 'struct',
fields: [
['computed_in_epoch', 'u64'],
['st_sol_supply', 'u64'],
['sol_balance', 'u64'],
],
},
],
[
LamportsHistogram,
{
kind: 'struct',
fields: [
['counts1', 'u64'],
['counts2', 'u64'],
['counts3', 'u64'],
['counts4', 'u64'],
['counts5', 'u64'],
['counts6', 'u64'],
['counts7', 'u64'],
['counts8', 'u64'],
['counts9', 'u64'],
['counts10', 'u64'],
['counts11', 'u64'],
['counts12', 'u64'],
['total', 'u64'],
],
},
],
[
WithdrawMetric,
{
kind: 'struct',
fields: [
['total_st_sol_amount', 'u64'],
['total_sol_amount', 'u64'],
['count', 'u64'],
],
},
],
[
Metrics,
{
kind: 'struct',
fields: [
['fee_treasury_sol_total', 'u64'],
['fee_validation_sol_total', 'u64'],
['fee_developer_sol_total', 'u64'],
['st_sol_appreciation_sol_total', 'u64'],
['fee_treasury_st_sol_total', 'u64'],
['fee_validation_st_sol_total', 'u64'],
['fee_developer_st_sol_total', 'u64'],
['deposit_amount', LamportsHistogram],
['withdraw_amount', WithdrawMetric],
],
},
],
[
SeedRange,
{
kind: 'struct',
fields: [
['begin', 'u64'],
['end', 'u64'],
],
},
],
[
Validator,
{
kind: 'struct',
fields: [
['fee_credit', 'u64'],
['fee_address', 'u256'],
['stake_seeds', SeedRange],
['unstake_seeds', SeedRange],
['stake_accounts_balance', 'u64'],
['unstake_accounts_balance', 'u64'],
['active', 'u8'],
],
},
],
[
PubKeyAndEntry,
{
kind: 'struct',
fields: [
['pubkey', 'u256'],
['entry', Validator],
],
},
],
[
PubKeyAndEntryMaintainer,
{
kind: 'struct',
fields: [
['pubkey', 'u256'],
['entry', [0]],
],
},
],
[
RewardDistribution,
{
kind: 'struct',
fields: [
['treasury_fee', 'u32'],
['validation_fee', 'u32'],
['developer_fee', 'u32'],
['st_sol_appreciation', 'u32'],
],
},
],
[
FeeRecipients,
{
kind: 'struct',
fields: [
['treasury_account', 'u256'],
['developer_account', 'u256'],
],
},
],
[
Validators,
{
kind: 'struct',
fields: [
['entries', [PubKeyAndEntry]],
['maximum_entries', 'u32'],
],
},
],
[
Maintainers,
{
kind: 'struct',
fields: [
['entries', [PubKeyAndEntryMaintainer]],
['maximum_entries', 'u32'],
],
},
],
[
Lido,
{
kind: 'struct',
fields: [
['lido_version', 'u8'],
['manager', 'u256'],
['st_sol_mint', 'u256'],
['exchange_rate', ExchangeRate],
['sol_reserve_authority_bump_seed', 'u8'],
['stake_authority_bump_seed', 'u8'],
['mint_authority_bump_seed', 'u8'],
['rewards_withdraw_authority_bump_seed', 'u8'],
['reward_distribution', RewardDistribution],
['fee_recipients', FeeRecipients],
['metrics', Metrics],
['validators', Validators],
['maintainers', Maintainers],
],
},
],
]);
const Layouts = {
lido: Lido,
}
const customDecoders = {
reserve: parseReserve,
mint: defaultParseLayout(MintLayout),
account: defaultParseLayout(AccountLayout),
}
function decodeAccount(layout, accountInfo) {
if (!accountInfo.data) throw new Error('Missing account data')
if (customDecoders[layout]) return customDecoders[layout](accountInfo)
if (!Layouts[layout]) throw new Error('Layout not found')
return deserializeUnchecked(schema, Layouts[layout], accountInfo.data);
}
module.exports = {
Layouts,
schema,
decodeAccount,
}

View File

@@ -1,262 +0,0 @@
class Lido {
constructor(data) {
Object.assign(this, data);
}
}
class SeedRange {
constructor(data) {
Object.assign(this, data);
}
}
class Validator {
constructor(data) {
Object.assign(this, data);
}
}
class PubKeyAndEntry {
constructor(data) {
Object.assign(this, data);
}
}
class PubKeyAndEntryMaintainer {
constructor(data) {
Object.assign(this, data);
}
}
class RewardDistribution {
constructor(data) {
Object.assign(this, data);
}
}
class FeeRecipients {
constructor(data) {
Object.assign(this, data);
}
}
class Validators {
constructor(data) {
Object.assign(this, data);
}
}
class Maintainers {
constructor(data) {
Object.assign(this, data);
}
}
class ExchangeRate {
constructor(data) {
Object.assign(this, data);
}
}
class Metrics {
constructor(data) {
Object.assign(this, data);
}
}
class LamportsHistogram {
constructor(data) {
Object.assign(this, data);
}
}
class WithdrawMetric {
constructor(data) {
Object.assign(this, data);
}
}
const schema = new Map([
[
ExchangeRate,
{
kind: 'struct',
fields: [
['computed_in_epoch', 'u64'],
['st_sol_supply', 'u64'],
['sol_balance', 'u64'],
],
},
],
[
LamportsHistogram,
{
kind: 'struct',
fields: [
['counts1', 'u64'],
['counts2', 'u64'],
['counts3', 'u64'],
['counts4', 'u64'],
['counts5', 'u64'],
['counts6', 'u64'],
['counts7', 'u64'],
['counts8', 'u64'],
['counts9', 'u64'],
['counts10', 'u64'],
['counts11', 'u64'],
['counts12', 'u64'],
['total', 'u64'],
],
},
],
[
WithdrawMetric,
{
kind: 'struct',
fields: [
['total_st_sol_amount', 'u64'],
['total_sol_amount', 'u64'],
['count', 'u64'],
],
},
],
[
Metrics,
{
kind: 'struct',
fields: [
['fee_treasury_sol_total', 'u64'],
['fee_validation_sol_total', 'u64'],
['fee_developer_sol_total', 'u64'],
['st_sol_appreciation_sol_total', 'u64'],
['fee_treasury_st_sol_total', 'u64'],
['fee_validation_st_sol_total', 'u64'],
['fee_developer_st_sol_total', 'u64'],
['deposit_amount', LamportsHistogram],
['withdraw_amount', WithdrawMetric],
],
},
],
[
SeedRange,
{
kind: 'struct',
fields: [
['begin', 'u64'],
['end', 'u64'],
],
},
],
[
Validator,
{
kind: 'struct',
fields: [
['fee_credit', 'u64'],
['fee_address', 'u256'],
['stake_seeds', SeedRange],
['unstake_seeds', SeedRange],
['stake_accounts_balance', 'u64'],
['unstake_accounts_balance', 'u64'],
['active', 'u8'],
],
},
],
[
PubKeyAndEntry,
{
kind: 'struct',
fields: [
['pubkey', 'u256'],
['entry', Validator],
],
},
],
[
PubKeyAndEntryMaintainer,
{
kind: 'struct',
fields: [
['pubkey', 'u256'],
['entry', [0]],
],
},
],
[
RewardDistribution,
{
kind: 'struct',
fields: [
['treasury_fee', 'u32'],
['validation_fee', 'u32'],
['developer_fee', 'u32'],
['st_sol_appreciation', 'u32'],
],
},
],
[
FeeRecipients,
{
kind: 'struct',
fields: [
['treasury_account', 'u256'],
['developer_account', 'u256'],
],
},
],
[
Validators,
{
kind: 'struct',
fields: [
['entries', [PubKeyAndEntry]],
['maximum_entries', 'u32'],
],
},
],
[
Maintainers,
{
kind: 'struct',
fields: [
['entries', [PubKeyAndEntryMaintainer]],
['maximum_entries', 'u32'],
],
},
],
[
Lido,
{
kind: 'struct',
fields: [
['lido_version', 'u8'],
['manager', 'u256'],
['st_sol_mint', 'u256'],
['exchange_rate', ExchangeRate],
['sol_reserve_authority_bump_seed', 'u8'],
['stake_authority_bump_seed', 'u8'],
['mint_authority_bump_seed', 'u8'],
['rewards_withdraw_authority_bump_seed', 'u8'],
['reward_distribution', RewardDistribution],
['fee_recipients', FeeRecipients],
['metrics', Metrics],
['validators', Validators],
['maintainers', Maintainers],
],
},
],
]);
module.exports = {
Lido,
schema
}

View File

@@ -1,17 +1,12 @@
const { Connection, PublicKey } = require('@solana/web3.js');
const { deserializeUnchecked } = require('borsh');
const { Lido, schema } = require('./Lido')
const { PublicKey } = require('@solana/web3.js');
const { decodeAccount } = require('../helper/solana')
const SOLIDO_ADDRESS = "49Yi1TKkNyYjPAFdR9LBvoHcUjuPX4Df5T5yv39w2XTn";
const RESERVE_ACCOUNT_ADDRESS = "3Kwv3pEAuoe4WevPB4rgMBTZndGDb53XT7qwQKnvHPfX";
async function retrieveValidatorsBalance(connection) {
const accountInfo = await connection.getAccountInfo(new PublicKey(SOLIDO_ADDRESS));
const deserializedAccountInfo = deserializeUnchecked(
schema,
Lido,
accountInfo.data,
);
const deserializedAccountInfo = decodeAccount('lido', accountInfo)
return deserializedAccountInfo.validators.entries
.map(pubKeyAndEntry => pubKeyAndEntry.entry)
.map(validator => validator.stake_accounts_balance.toNumber())

View File

@@ -1,155 +0,0 @@
const { PublicKey } =require("@solana/web3.js");
const { AccountLayout, MintLayout } = require("@solana/spl-token")
const getAccountInfo = async (connection, pubKey) => {
const info = await connection.getAccountInfo(pubKey);
if (info === null) {
throw new Error("Failed to find mint account");
}
const buffer = Buffer.from(info.data);
const data = deserializeAccount(buffer);
const details = {
pubkey: pubKey,
account: {
...info,
},
info: data,
};
return details;
};
const getMultipleAccountInfo = async (connection, pubKeys) => {
let array = [];
var pubList = pubKeys.reduce((resultArray, item, index) => {
const chunkIndex = Math.floor(index/100)
if(!resultArray[chunkIndex]) {
resultArray[chunkIndex] = [] // start a new chunk
}
resultArray[chunkIndex].push(item)
return resultArray
}, [])
for await (const subPubList of pubList) {
const info = await connection.getMultipleAccountsInfo(subPubList);
if (info === null) {
throw new Error("Failed to find mint account");
}
info.forEach(buf => {
if (buf != null) {
const buffer = Buffer.from(buf.data);
const data = deserializeAccount(buffer);
const details = {
pubkey: subPubList[info.indexOf(buf)],
account: {
...buf,
},
info: data,
};
array.push(details);
}
});
}
return array;
};
// TODO: expose in spl package
const deserializeAccount = (data) => {
const accountInfo = AccountLayout.decode(data);
accountInfo.mint = new PublicKey(accountInfo.mint);
accountInfo.owner = new PublicKey(accountInfo.owner);
if (accountInfo.delegateOption === 0) {
accountInfo.delegate = null;
} else {
accountInfo.delegate = new PublicKey(accountInfo.delegate);
}
accountInfo.isInitialized = accountInfo.state !== 0;
accountInfo.isFrozen = accountInfo.state === 2;
if (accountInfo.isNativeOption === 1) {
accountInfo.rentExemptReserve = accountInfo.isNative;
accountInfo.isNative = true;
} else {
accountInfo.rentExemptReserve = null;
accountInfo.isNative = false;
}
if (accountInfo.closeAuthorityOption === 0) {
accountInfo.closeAuthority = null;
} else {
accountInfo.closeAuthority = new PublicKey(accountInfo.closeAuthority);
}
return accountInfo;
};
const getMintInfo = async (connection, pubKey) => {
const info = await connection.getAccountInfo(pubKey);
if (info === null) {
throw new Error("Failed to find mint account");
}
const data = Buffer.from(info.data);
return deserializeMint(data);
};
const getMultipleMintInfo = async (connection, pubKeys) => {
const info = await connection.getMultipleAccountsInfo(pubKeys);
if (info === null) {
throw new Error("Failed to find mint account");
}
return info.map(v => {
if (v != null) {
const data = Buffer.from(v.data);
return {
key: pubKeys[info.indexOf(v)].toBase58(),
data: deserializeMint(data)
};
}
return null;
})
};
// TODO: expose in spl package
const deserializeMint = (data) => {
if (data.length !== MintLayout.span) {
throw new Error("Not a valid Mint");
}
const mintInfo = MintLayout.decode(data);
if (mintInfo.mintAuthorityOption === 0) {
mintInfo.mintAuthority = null;
} else {
mintInfo.mintAuthority = new PublicKey(mintInfo.mintAuthority);
}
mintInfo.isInitialized = mintInfo.isInitialized !== 0;
if (mintInfo.freezeAuthorityOption === 0) {
mintInfo.freezeAuthority = null;
} else {
mintInfo.freezeAuthority = new PublicKey(mintInfo.freezeAuthority);
}
return mintInfo;
};
module.exports={ getMultipleAccountInfo, getMultipleMintInfo, deserializeAccount }

View File

@@ -1,7 +1,6 @@
const {
PublicKey,
} = require("@solana/web3.js");
const { deserializeAccount } = require("./accounts");
const { Program } = require("@project-serum/anchor");
const PsyAmericanIdl = require("./idl.json");
const { getProvider, sumTokens2, } = require("../helper/solana");
@@ -30,7 +29,7 @@ async function getPsyAmericanTokenAccounts(anchorProvider) {
tokensAndOwners.push([market.underlyingAssetMint.toBase58(), market.key])
tokensAndOwners.push([market.quoteAssetMint.toBase58(), market.key])
});
return { tokensAndOwners };
return tokensAndOwners
}
async function getTokenizedEurosControlledAccounts(anchorProvider) {
@@ -45,25 +44,16 @@ async function getTokenizedEurosControlledAccounts(anchorProvider) {
await anchorProvider.connection.getTokenAccountsByOwner(poolAuthority, {
programId: TOKEN_PROGRAM_ID,
});
const tokensAndOwners = []
tokenProgramAccounts.value.forEach((tokenProgramAccount) => {
// Decode the account data buffer
const dataBuffer = tokenProgramAccount.account.data;
const decoded = deserializeAccount(dataBuffer);
const mintAddress = decoded.mint.toBase58();
tokensAndOwners.push([mintAddress, decoded.owner])
});
return { tokensAndOwners, };
return tokenProgramAccounts.value.map(i => i.pubkey.toString())
}
async function tvl() {
const anchorProvider = getProvider();
const responses = await Promise.all([
const [ tokensAndOwners, tokenAccounts, ] = await Promise.all([
getPsyAmericanTokenAccounts(anchorProvider),
getTokenizedEurosControlledAccounts(anchorProvider),
]);
return sumTokens2({ tokensAndOwners: responses.map(i => i.tokensAndOwners).flat()})
return sumTokens2({ tokenAccounts, tokensAndOwners, })
}
module.exports = {

View File

@@ -1,8 +1,7 @@
const anchor = require("@project-serum/anchor");
const { PublicKey } = require("@solana/web3.js");
const activePoolBases = require("./active-pools.json");
const { getConnection } = require("../helper/solana");
const { MintLayout } = require("@solana/spl-token");
const { getConnection, decodeAccount } = require("../helper/solana");
const sdk = require('@defillama/sdk')
const SCALLOP_PROGRAM_ID = new PublicKey("SCPv1LabixHirZbX6s7Zj3oiBogadWZvGUKRvXD3Zec");
@@ -43,10 +42,10 @@ async function tvl() {
if (curr === null)
return;
if (curr.data.length !== MintLayout.span) // invalid mint
if (curr.data.length !== 82) // invalid mint
return;
const mintInfo = MintLayout.decode(curr.data);
const mintInfo = decodeAccount('mint', curr);
const geckoId = getTokenGeckoId(mintInfo.mintAuthority)
if (!geckoId) return;
const amount = (mintInfo.supply.toString() / Math.pow(10, mintInfo.decimals))

View File

@@ -1,9 +1,8 @@
const BigNumber = require("bignumber.js");
const { PublicKey, } = require("@solana/web3.js");
const { parseReserve } = require("./utils");
const { sliceIntoChunks, } = require('../helper/utils')
const { transformBalances, } = require('../helper/portedTokens')
const { sumTokens, getConnection, } = require("../helper/solana");
const { sumTokens, getConnection, decodeAccount, } = require("../helper/solana");
const { fetchURL } = require('../helper/utils')
const sdk = require('@defillama/sdk')
@@ -23,7 +22,7 @@ async function borrowed() {
for (const chunk of chunks) {
const infos = await connection.getMultipleAccountsInfo(chunk)
infos.forEach(i => {
const { info: { liquidity } } = parseReserve(i)
const { info: { liquidity } } = decodeAccount('reserve', i)
const amount = new BigNumber(liquidity.borrowedAmountWads.toString() / 1e18).toFixed(0);
sdk.util.sumSingleBalance(balances, liquidity.mintPubkey.toString(), amount)
})

View File

@@ -1,175 +0,0 @@
const BufferLayout = require("buffer-layout");
const { PublicKey } = require("@solana/web3.js");
const BN = require("bn.js");
const publicKey = (property = "publicKey") => {
const publicKeyLayout = BufferLayout.blob(32, property);
const _decode = publicKeyLayout.decode.bind(publicKeyLayout);
const _encode = publicKeyLayout.encode.bind(publicKeyLayout);
publicKeyLayout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new PublicKey(data);
};
publicKeyLayout.encode = (key, buffer, offset) =>
_encode(key.toBuffer(), buffer, offset);
return publicKeyLayout;
};
/**
* Layout for a 64bit unsigned value
*/
const uint64 = (property = "uint64") => {
const layout = BufferLayout.blob(8, property);
const _decode = layout.decode.bind(layout);
const _encode = layout.encode.bind(layout);
layout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new BN(
[...data]
.reverse()
.map((i) => `00${i.toString(16)}`.slice(-2))
.join(""),
16
);
};
layout.encode = (num, buffer, offset) => {
const a = num.toArray().reverse();
let b = Buffer.from(a);
if (b.length !== 8) {
const zeroPad = Buffer.alloc(8);
b.copy(zeroPad);
b = zeroPad;
}
return _encode(b, buffer, offset);
};
return layout;
};
const uint128 = (property = "uint128") => {
const layout = BufferLayout.blob(16, property);
const _decode = layout.decode.bind(layout);
const _encode = layout.encode.bind(layout);
layout.decode = (buffer, offset) => {
const data = _decode(buffer, offset);
return new BN(
[...data]
.reverse()
.map((i) => `00${i.toString(16)}`.slice(-2))
.join(""),
16
);
};
layout.encode = (num, buffer, offset) => {
const a = num.toArray().reverse();
let b = Buffer.from(a);
if (b.length !== 16) {
const zeroPad = Buffer.alloc(16);
b.copy(zeroPad);
b = zeroPad;
}
return _encode(b, buffer, offset);
};
return layout;
};
const LastUpdateLayout = BufferLayout.struct(
[uint64("slot"), BufferLayout.u8("stale")],
"lastUpdate"
);
const ReserveLayout = BufferLayout.struct([
BufferLayout.u8("version"),
LastUpdateLayout,
publicKey("lendingMarket"),
BufferLayout.struct(
[
publicKey("mintPubkey"),
BufferLayout.u8("mintDecimals"),
publicKey("supplyPubkey"),
// @FIXME: oracle option
// TODO: replace u32 option with generic equivalent
// BufferLayout.u32('oracleOption'),
publicKey("pythOracle"),
publicKey("switchboardOracle"),
uint64("availableAmount"),
uint128("borrowedAmountWads"),
uint128("cumulativeBorrowRateWads"),
uint128("marketPrice"),
],
"liquidity"
),
BufferLayout.struct(
[
publicKey("mintPubkey"),
uint64("mintTotalSupply"),
publicKey("supplyPubkey"),
],
"collateral"
),
BufferLayout.struct(
[
BufferLayout.u8("optimalUtilizationRate"),
BufferLayout.u8("loanToValueRatio"),
BufferLayout.u8("liquidationBonus"),
BufferLayout.u8("liquidationThreshold"),
BufferLayout.u8("minBorrowRate"),
BufferLayout.u8("optimalBorrowRate"),
BufferLayout.u8("maxBorrowRate"),
BufferLayout.struct(
[
uint64("borrowFeeWad"),
uint64("flashLoanFeeWad"),
BufferLayout.u8("hostFeePercentage"),
],
"fees"
),
uint64("depositLimit"),
uint64("borrowLimit"),
publicKey("feeReceiver"),
],
"config"
),
BufferLayout.blob(256, "padding"),
]);
const parseReserve = (info) => {
const pubkey = PublicKey.default
const { data } = info;
const buffer = Buffer.from(data);
const reserve = ReserveLayout.decode(buffer);
if (reserve.lastUpdate.slot.isZero()) {
return null;
}
const details = {
pubkey,
account: {
...info,
},
info: reserve,
};
return details;
};
module.exports = {
parseReserve,
};

View File

@@ -1,13 +1,12 @@
const { PublicKey } = require("@solana/web3.js");
const { getConnection } = require("../helper/solana");
const { MintLayout } = require("@solana/spl-token");
const { getConnection, decodeAccount, } = require("../helper/solana");
async function tvl() {
const connection = getConnection()
const mint = await connection.getAccountInfo(new PublicKey('7kbnvuGBxxj8AG9qp8Scn56muWGaRaFqxg1FsRp3PaFT'));
const mintInfo = MintLayout.decode(mint.data);
const mintInfo = decodeAccount('mint', mint)
return {
'uxd-stablecoin': mintInfo.supply.toString()/ (10**mintInfo.decimals)
'uxd-stablecoin': mintInfo.supply.toString() / (10 ** mintInfo.decimals)
};
}