Skip to content

Commit 0b9fd5c

Browse files
committed
progress
1 parent 8e1b892 commit 0b9fd5c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1732
-4475
lines changed

solend-lite/src/stores/metadata.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DEBUG_MODE } from 'common/config';
2-
import { fetchTokensInfo, TokenMetadata } from '@solendprotocol/solend-sdk';
2+
import { getTokenInfosFromMetadata, TokenInfo, TokenMetadata } from '@solendprotocol/solend-sdk';
33
import { atom } from 'jotai';
44
import { unqiueAssetsAtom } from './pools';
55
import { connectionAtom } from './settings';
@@ -15,7 +15,12 @@ export const loadMetadataAtom = atom(
1515
const connection = get(connectionAtom);
1616

1717
if (mints.length) {
18-
set(metadataAtom, await fetchTokensInfo(mints, connection, DEBUG_MODE));
18+
const tokenInfoArray = await getTokenInfosFromMetadata(mints, connection, DEBUG_MODE)
19+
const tokenInfo = tokenInfoArray.reduce((acc, t) => {
20+
acc[t.address] = t;
21+
return acc;
22+
}, {} as Record<string, TokenInfo>);
23+
set(metadataAtom, tokenInfo);
1924
}
2025
},
2126
);

solend-lite/src/stores/pools.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import { configAtom } from './config';
1414
import BigNumber from 'bignumber.js';
1515
import {
1616
createObligationAddress,
17-
ReserveType,
1817
fetchPools,
1918
getReservesOfPool,
2019
parseLendingMarket,
2120
parseRateLimiter,
2221
PoolType,
22+
ReserveType
2323
} from '@solendprotocol/solend-sdk';
2424
import { DEBUG_MODE, PROGRAM_ID } from 'common/config';
2525
import { atomWithRefresh } from './shared';
@@ -118,6 +118,7 @@ export const poolsWithMetaDataAtom = atom((get) => {
118118
const metadata = get(metadataAtom);
119119
const pools = get(poolsAtom);
120120

121+
console.log(metadata);
121122
return Object.fromEntries(
122123
Object.values(pools).map((p) => [
123124
p.address,
@@ -130,7 +131,7 @@ export const poolsWithMetaDataAtom = atom((get) => {
130131
reserves: p.reserves.map((r) => ({
131132
...r,
132133
symbol: metadata[r.mintAddress]?.symbol,
133-
logo: metadata[r.mintAddress]?.logoUri,
134+
logo: metadata[r.mintAddress]?.logoURI,
134135
})),
135136
},
136137
]),
@@ -183,11 +184,11 @@ export const selectedPoolAtom = atom(
183184
reserves: selectedPool.reserves.map((r) => {
184185
const addressString = r.mintAddress;
185186
const tokenMetadata = metadata[addressString];
186-
187+
console.log(tokenMetadata);
187188
return {
188189
...r,
189190
symbol: tokenMetadata?.symbol,
190-
logo: tokenMetadata?.logoUri,
191+
logo: tokenMetadata?.logoURI,
191192
};
192193
}),
193194
};
@@ -216,9 +217,9 @@ export const selectedPoolAtom = atom(
216217
getReservesOfPool(
217218
new PublicKey(newSelectedPoolAddress),
218219
connection,
219-
switchboardProgram,
220220
PROGRAM_ID,
221221
currentSlot,
222+
switchboardProgram,
222223
DEBUG_MODE,
223224
);
224225

solend-sdk/README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ const { wallet } = useWallet();
7575
const solendWallet = await SolendWallet.initialize(wallet, connection);
7676

7777
// Claim rewards
78-
const mndeRewards = solendWallet.rewards["MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey"];
78+
const mndeRewards =
79+
solendWallet.rewards["MNDEFzGvMt87ueuHvVU9VcTqsAP5b3fTGPsHuuPA5ey"];
7980
console.log(
8081
"Claimable rewards:",
8182
mndeRewards.claimableAmount / 10 ** mndeRewards.decimals
@@ -118,6 +119,7 @@ Due to transaction size limits of Solana, a user with a high amount of positions
118119
Partner rewards and liquidity mining are not present on devnet.
119120

120121
## Publishing
122+
121123
`package.json` is configured for monorepo development alongside other packages. To publish the sdk, use `yarn release` to run scripts optimizing for release. Package has been marked private to prevent accidently publish with `yarn publish`.
122124

123125
```

solend-sdk/__tests__/market.test.ts

+33-174
Original file line numberDiff line numberDiff line change
@@ -1,191 +1,50 @@
1-
import { Connection, Keypair, Transaction, LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js';
2-
import BN from 'bn.js';
3-
import * as anchor from '@project-serum/anchor';
4-
import { parseReserve, SolendAction, SolendMarket, SolendWallet } from "../src";
1+
import {
2+
Connection,
3+
PublicKey,
4+
} from "@solana/web3.js";
5+
import { parseObligation } from "../src";
56

67
jest.setTimeout(50_000);
78

8-
describe("calculate", function () {
9-
it ('parses reserves', async function() {
10-
11-
const connection = new Connection('https://api.mainnet-beta.solana.com', {
12-
commitment: "finalized",
13-
});
14-
15-
const reserve = await connection.getAccountInfo(new PublicKey('CCpirWrgNuBVLdkP2haxLTbD6XqEgaYuVXixbbpxUB6'));
16-
17-
const parsedReserveData = parseReserve(new PublicKey('CCpirWrgNuBVLdkP2haxLTbD6XqEgaYuVXixbbpxUB6'), reserve!);
18-
expect(parsedReserveData!.info.liquidity.pythOracle).not.toBeUndefined();
19-
expect(parsedReserveData!.info.liquidity.switchboardOracle).not.toBeUndefined();
20-
});
21-
22-
it("reads wallet", async function () {
23-
const connection = new Connection('https://api.mainnet-beta.solana.com', {
24-
commitment: "finalized",
25-
});
26-
27-
const keypair = Keypair.generate();
28-
const wallet = new anchor.Wallet(keypair);
29-
const solendWallet = await SolendWallet.initialize(
30-
wallet,
31-
connection,
32-
);
33-
34-
const [setupIxs, claimIxs] = await solendWallet.getClaimAllIxs();
35-
36-
expect([...setupIxs, ...claimIxs].length).toEqual(0);
37-
});
38-
39-
it("reads solend main market", async function () {
40-
const connection = new Connection('https://api.mainnet-beta.solana.com', {
41-
commitment: "finalized",
42-
});
43-
44-
const market = await SolendMarket.initialize(
45-
connection
46-
);
47-
await market.loadReserves();
48-
await market.loadRewards();
49-
const reserve = market.reserves.find(res => res.config.liquidityToken.symbol === 'USDC');
50-
51-
expect(reserve!.stats!.decimals).toEqual(6);
52-
expect(reserve!.stats!.protocolTakeRate).toBeLessThanOrEqual(1);
53-
});
54-
55-
it("reads solend devnet", async function () {
56-
const connection = new Connection('https://api.devnet.solana.com', {
57-
commitment: "finalized",
58-
});
59-
60-
const market = await SolendMarket.initialize(
61-
connection,
62-
'devnet'
63-
);
64-
await market.loadReserves();
65-
await market.loadRewards();
66-
const reserve = market.reserves.find(res => res.config.liquidityToken.symbol === 'USDC');
67-
68-
expect(reserve!.stats!.decimals).toEqual(6);
69-
expect(reserve!.stats!.protocolTakeRate).toBeLessThanOrEqual(1);
70-
});
71-
72-
it("reads solend invictus market", async function () {
73-
const connection = new Connection('https://api.mainnet-beta.solana.com', {
74-
commitment: "finalized",
75-
});
76-
77-
const market = await SolendMarket.initialize(
78-
connection,
79-
'production',
80-
'5i8SzwX2LjpGUxLZRJ8EiYohpuKgW2FYDFhVjhGj66P1',
9+
describe("check", function () {
10+
it("parses obligation in both formats", async function () {
11+
const zstdEncodedObligationData = Buffer.from(
12+
"KLUv/QBYLQoAdBEBWZHIBwAAAAABM7MexO/4+iia6oyVTAFjLi12SQjOVE1oZb3vERv/YSsChcZ+Ktz1mRBrkyRk1BwBK+MRLDs2kN6sQJrkE/068ae2QKj1GoAIagEAUiLO4HOtZQD9iDA+OBRghg/ZNGo1t+NsujMBAQFsp+C1qN6toMtzc12/wVf8DODwcnh4K7b1j6DEElE6V8esAGvgw8KAVqMAbcvwdUngHTQhP3KK2EcTtbcXhy+sOBPKuWOvMSyN283/9ZTFWnxCDgDvyiK06ZHhKd04ANAh+wRuI+ENjqkOBTFIeS9ID9NTKr93sO+769EA4idmIqc8x1Enq7K/tz3DwaHWY5RMvzQOIJZ5G4lBjXXPHRJX7vzRwA8SAM1yFQDEt5APgChdqyVY2VtAAS80LATg+oCsBCUWCFQgLRhoqHwAcXWBMw==",
13+
"base64"
8114
);
82-
await market.loadReserves();
83-
await market.loadRewards();
84-
const reserve = market.reserves.find(res => res.config.liquidityToken.symbol === 'USDC');
85-
expect((await reserve!.totalBorrowAPY()).rewards).toEqual([]);
86-
expect(reserve!.stats!.optimalUtilizationRate).toEqual(0.8);
87-
});
88-
89-
it("reads permissionless", async function () {
90-
const connection = new Connection('https://api.mainnet-beta.solana.com', {
91-
commitment: "finalized",
92-
});
93-
94-
const market = await SolendMarket.initialize(
95-
connection,
96-
'production',
97-
'Ckya2fwCXDqTUg9fnWbajR6YLcSfQmPxxy5MyAoZXgyb',
15+
const base64EncodedObligationData = Buffer.from(
16+
"AVmRyAcAAAAAATOzHsTv+PoomuqMlUwBYy4tdkkIzlRNaGW97xEb/2ErAoXGfirc9ZkQa5MkZNQcASvjESw7NpDerECa5BP9OvGntkCo9RqACGoBAAAAAAAAUiLO4HOtZQAAAAAAAAAAAP2IMD44FGCGDwEAAAAAAADZNGo1t+NsujMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBbKfgtajeraDLc3Ndv8FX/Azg8HJ4eCu29Y+gxBJROlfHrAAAAAAAAGvgw8KAVqMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG3L8HVJ4B00IT9yithHE7W3F4cvrDgTyrljrzEsjdvN//WUxVp8Qg4AAAAAAAAAAO/KIrTpkeEp3TgAAAAAAABSIs7gc61lAAAAAAAAAAAAAAAAAAAAAABty/B1SeAdNCE/corYRxO1txeHL6w4E8q5Y68xLI3bzf/1lMVafEIOAAAAAAAAAADvyiK06ZHhKd04AAAAAAAAUiLO4HOtZQAAAAAAAAAAANAh+wQAAAAAbiPhDY6pDgUxAQAAAAAAAAAAAAAAAAAASHkvSA/TUyq/d7Dvu+vRAOInZiKnPMdRJ6uyv7c9w8Gh1mOUTL80DgAAAAAAAAAAIJZ5G4lBjXXPIfsEAAAAAB0SV+780cAPMQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
17+
"base64"
9818
);
99-
await market.loadReserves();
100-
await market.loadRewards();
101-
const reserve = market.reserves.find(res => res.config.liquidityToken.symbol === 'SLND');
102-
expect((await reserve!.totalBorrowAPY()).rewards).toEqual([]);
103-
expect(reserve!.stats!.optimalUtilizationRate).toEqual(0.8);
104-
});
10519

106-
it("performs a deposit", async function () {
107-
const connection = new Connection('https://api.devnet.solana.com', {
20+
const obligationPubkey = new PublicKey(
21+
"FfRLBU1gHm3MyqJ3KX6dBnsxxJtwVGCwKFwJrfDnceWN"
22+
);
23+
const connection = new Connection("https://api.mainnet-beta.solana.com", {
10824
commitment: "finalized",
10925
});
11026

111-
const depositAmount = new BN("1000");
112-
113-
const account = Keypair.generate();
114-
115-
const signature = await connection.requestAirdrop(account.publicKey, LAMPORTS_PER_SOL);
116-
await connection.confirmTransaction(signature);
117-
118-
const solendAction = await SolendAction.buildDepositTxns(
119-
connection,
120-
depositAmount,
121-
"SOL",
122-
account.publicKey,
123-
"devnet"
27+
const zstdEncodedObligation = await connection.getAccountInfo(
28+
obligationPubkey
12429
);
125-
126-
const sendTransaction = async (txn: Transaction, connection: Connection) => {
127-
const { blockhash } = await connection.getRecentBlockhash();
128-
txn.recentBlockhash = blockhash;
129-
txn.feePayer = account.publicKey;
130-
txn.sign(account);
131-
return connection.sendRawTransaction(txn.serialize());
132-
}
133-
134-
const txHash = await solendAction.sendTransactions(sendTransaction);
135-
136-
await connection.confirmTransaction(txHash, 'finalized');
137-
138-
const market = await SolendMarket.initialize(
139-
connection,
140-
'devnet',
30+
zstdEncodedObligation!.data = zstdEncodedObligationData;
31+
const base64EncodedObligation = await connection.getAccountInfo(
32+
obligationPubkey
14133
);
34+
base64EncodedObligation!.data = base64EncodedObligationData;
14235

143-
const obligation = await market.fetchObligationByWallet(account.publicKey);
144-
145-
expect(obligation!.deposits[0].amount === depositAmount)
146-
});
147-
148-
// TODO update to a non-primary pool after another pool deployed to devnet
149-
it("performs a deposit to specific pool", async function () {
150-
const connection = new Connection('https://api.devnet.solana.com', {
151-
commitment: "finalized",
152-
});
153-
154-
const depositAmount = new BN("1000");
155-
156-
const account = Keypair.generate();
157-
158-
const signature = await connection.requestAirdrop(account.publicKey, LAMPORTS_PER_SOL);
159-
await connection.confirmTransaction(signature);
160-
161-
const solendAction = await SolendAction.buildDepositTxns(
162-
connection,
163-
depositAmount,
164-
"SOL",
165-
account.publicKey,
166-
"devnet",
167-
new PublicKey("GvjoVKNjBvQcFaSKUW1gTE7DxhSpjHbE69umVR5nPuQp"),
36+
const parsedzstdEncodedObligation = parseObligation(
37+
obligationPubkey,
38+
zstdEncodedObligation!,
39+
"base64+zstd"
16840
);
169-
170-
const sendTransaction = async (txn: Transaction, connection: Connection) => {
171-
const { blockhash } = await connection.getRecentBlockhash();
172-
txn.recentBlockhash = blockhash;
173-
txn.feePayer = account.publicKey;
174-
txn.sign(account);
175-
return connection.sendRawTransaction(txn.serialize());
176-
}
177-
178-
const txHash = await solendAction.sendTransactions(sendTransaction);
179-
180-
await connection.confirmTransaction(txHash, 'finalized');
181-
182-
const market = await SolendMarket.initialize(
183-
connection,
184-
'devnet',
41+
const parsedbase64EncodedObligation = parseObligation(
42+
obligationPubkey,
43+
base64EncodedObligation!
18544
);
18645

187-
const obligation = await market.fetchObligationByWallet(account.publicKey);
188-
189-
expect(obligation!.deposits[0].amount === depositAmount)
46+
expect(parsedzstdEncodedObligation!).toMatchObject(
47+
parsedbase64EncodedObligation!
48+
);
19049
});
19150
});
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import {
2+
Connection,
3+
PublicKey,
4+
} from "@solana/web3.js";
5+
import { getTokenInfosFromMetadata } from "../src";
6+
7+
jest.setTimeout(50_000);
8+
9+
describe("check", function () {
10+
it("parses obligation in both formats", async function () {
11+
const connection = new Connection("https://api.mainnet-beta.solana.com", {
12+
commitment: "finalized",
13+
});
14+
const tokens = await getTokenInfosFromMetadata([
15+
'n54ZwXEcLnc3o7zK48nhrLV4KTU5wWD4iq7Gvdt5tik',
16+
'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263'
17+
], connection)
18+
19+
console.log(tokens);
20+
});
21+
});
22+

solend-sdk/package.json

+5-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@solendprotocol/solend-sdk",
3-
"version": "0.8.8",
3+
"version": "1.0.0",
44
"private": true,
55
"main": "src/index.ts",
66
"module": "src/index.ts",
@@ -20,34 +20,28 @@
2020
"release": "yarn build; ts-node ./prepublish.ts; yarn --cwd ./dist publish"
2121
},
2222
"dependencies": {
23-
"@marinade.finance/marinade-ts-sdk": "^3.1.1",
24-
"@mithraic-labs/psy-american": "^0.2.1",
23+
"@metaplex-foundation/mpl-token-metadata": "^3.2.1",
24+
"@metaplex-foundation/umi": "^0.9.1",
25+
"@metaplex-foundation/umi-bundle-defaults": "^0.9.1",
2526
"@project-serum/anchor": "^0.24.2",
2627
"@pythnetwork/client": "^2.5.1",
2728
"@solana/buffer-layout": "^4.0.0",
2829
"@solana/spl-token": "^0.3.6",
2930
"@solana/web3.js": "^1.78.7",
30-
"@solflare-wallet/utl-sdk": "^1.4.0",
3131
"@switchboard-xyz/sbv2-lite": "^0.2.4",
32-
"@types/bn.js": "^5.1.1",
3332
"axios": "^0.24.0",
3433
"bignumber.js": "^9.0.2",
3534
"bn.js": "^5.2.0",
3635
"buffer": "^6.0.3",
3736
"buffer-layout": "^1.2.0",
3837
"fzstd": "^0.1.0",
39-
"hot-shots": "^9.3.0",
4038
"isomorphic-fetch": "^3.0.0",
4139
"jsbi": "^4.3.0",
4240
"typedoc-plugin-cname": "^1.0.1"
4341
},
4442
"devDependencies": {
45-
"@jup-ag/core": "^2.0.0-beta.3",
46-
"@orca-so/sdk": "^1.2.25",
47-
"@types/bs58": "^4.0.1",
43+
"@types/bn.js": "^5.1.1",
4844
"@types/jest": "^29.2.3",
49-
"@types/node": "^20.8.6",
50-
"@types/node-fetch": "^2.6.2",
5145
"@typescript-eslint/eslint-plugin": "^6.7.4",
5246
"@typescript-eslint/parser": "^6.7.4",
5347
"eslint": "^8.50.0",

0 commit comments

Comments
 (0)