@haven-fi/solauto-sdk 1.0.400 → 1.0.401

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"solanaUtils.d.ts","sourceRoot":"","sources":["../../src/utils/solanaUtils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,GAAG,EACH,kBAAkB,EAGnB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAIL,UAAU,EACV,SAAS,EAKT,sBAAsB,EAEvB,MAAM,iBAAiB,CAAC;AAgBzB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAIlE,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,UAErD;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,UAE3D;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAgC,GAC1C,CAAC,UAAU,EAAE,GAAG,CAAC,CAQnB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,sBAAsB,GACzB,kBAAkB,CAMpB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,GACtB,kBAAkB,CAOpB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAOpB;AAED,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,GACd,kBAAkB,CAUpB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,SAAS,EACtB,QAAQ,EAAE,MAAM,GACf,kBAAkB,CASpB;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,SAAS,EACvB,SAAS,EAAE,SAAS,GACnB,kBAAkB,CAKpB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,GACb,kBAAkB,CAKpB;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,GAAG,EACR,oBAAoB,EAAE,MAAM,EAAE,GAC7B,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAkBpC;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,MAAM,sBAa1B;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,MAAM,sBA2D1B;AAuBD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,kBAAkB,EACtB,eAAe,EAAE,kBAAkB,EACnC,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwC7B;AAiDD,wBAAsB,8BAA8B,CAClD,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,kBAAkB,EACtB,MAAM,CAAC,EAAE,kBAAkB,EAC3B,eAAe,GAAE,kBAA2C,EAC5D,cAAc,CAAC,EAAE,MAAM,IAAI,GAC1B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAoEjC"}
1
+ {"version":3,"file":"solanaUtils.d.ts","sourceRoot":"","sources":["../../src/utils/solanaUtils.ts"],"names":[],"mappings":"AACA,OAAO,EACL,uBAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,GAAG,EACH,kBAAkB,EAGnB,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAIL,UAAU,EACV,SAAS,EAKT,sBAAsB,EAEvB,MAAM,iBAAiB,CAAC;AAgBzB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAIlE,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,UAErD;AAED,wBAAgB,oBAAoB,CAAC,eAAe,EAAE,MAAM,UAE3D;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAgC,GAC1C,CAAC,UAAU,EAAE,GAAG,CAAC,CAQnB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,sBAAsB,GACzB,kBAAkB,CAMpB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,MAAM,GACtB,kBAAkB,CAOpB;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAOpB;AAED,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,GACd,kBAAkB,CAUpB;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,SAAS,EACtB,QAAQ,EAAE,MAAM,GACf,kBAAkB,CASpB;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,SAAS,EACvB,SAAS,EAAE,SAAS,GACnB,kBAAkB,CAKpB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,MAAM,GACb,kBAAkB,CAKpB;AAED,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,GAAG,EACR,oBAAoB,EAAE,MAAM,EAAE,GAC7B,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAmBpC;AAED,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,MAAM,sBAa1B;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,kBAAkB,EAC/B,gBAAgB,CAAC,EAAE,MAAM,EACzB,gBAAgB,CAAC,EAAE,MAAM,sBA2D1B;AAuBD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,GAAG,EACR,EAAE,EAAE,kBAAkB,EACtB,eAAe,EAAE,kBAAkB,EACnC,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwC7B;AAiDD,wBAAsB,8BAA8B,CAClD,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,UAAU,EACtB,EAAE,EAAE,kBAAkB,EACtB,MAAM,CAAC,EAAE,kBAAkB,EAC3B,eAAe,GAAE,kBAA2C,EAC5D,cAAc,CAAC,EAAE,MAAM,IAAI,GAC1B,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAoEjC"}
@@ -79,7 +79,7 @@ function splTokenTransferUmiIx(signer, fromTa, toTa, authority, amount) {
79
79
  return getWrappedInstruction(signer, (0, spl_token_1.createTransferInstruction)(fromTa, toTa, authority, amount));
80
80
  }
81
81
  async function getAddressLookupInputs(umi, lookupTableAddresses) {
82
- const addressLookupTableAccountInfos = await umi.rpc.getAccounts(lookupTableAddresses.map((key) => (0, umi_1.publicKey)(key)));
82
+ const addressLookupTableAccountInfos = await umi.rpc.getAccounts(lookupTableAddresses.map((key) => (0, umi_1.publicKey)(key)), { commitment: "confirmed" });
83
83
  return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => {
84
84
  const addressLookupTableAddress = lookupTableAddresses[index];
85
85
  if (accountInfo.exists) {
package/local/.env ADDED
@@ -0,0 +1 @@
1
+ ADDRESS_WHITELIST=5UqsR2PGzbP8pGPbXEeXx86Gjz2N2UFBAuFZUSVydAEe,E5BBsR1sUToPc3jXVwhrK5ttSiy6xhWJDMdQLvkgNppe,DRP5cgM1JpnMySvwg3jqRP2VA2DXSWUjo6VGLkNZ2etb,5qbTgNHBo5kedvDCseLbn5vJCtjrpUyNWwZzRnx72rPT
@@ -1,21 +1,225 @@
1
+ import { publicKey } from "@metaplex-foundation/umi";
1
2
  import {
2
3
  buildHeliusApiUrl,
4
+ fetchTokenPrices,
3
5
  getSolanaRpcConnection,
4
6
  getSolautoManagedPositions,
7
+ PositionState,
8
+ positionStateWithLatestPrices,
9
+ PRICES,
10
+ retryWithExponentialBackoff,
11
+ safeFetchAllSolautoPosition,
12
+ safeGetPrice,
5
13
  SOLAUTO_PROD_PROGRAM,
14
+ TOKEN_INFO,
15
+ USD_DECIMALS,
6
16
  } from "../src";
17
+ import { PublicKey } from "@solana/web3.js";
18
+ import { NATIVE_MINT } from "@solana/spl-token";
19
+ import { toWeb3JsPublicKey } from "@metaplex-foundation/umi-web3js-adapters";
20
+ import { fromBaseUnit } from "../dist";
21
+ import path from 'path';
22
+ import { config } from 'dotenv';
7
23
 
8
- async function main() {
24
+ config({ path: path.join(__dirname, '.env') });
25
+
26
+ function getBatches<T>(items: T[], batchSize: number): T[][] {
27
+ const batches: T[][] = [];
28
+ for (let i = 0; i < items.length; i += batchSize) {
29
+ batches.push(items.slice(i, i + batchSize));
30
+ }
31
+ return batches;
32
+ }
33
+
34
+ export function tokenInfo(mint?: PublicKey) {
35
+ return TOKEN_INFO[mint ? mint.toString() : PublicKey.default.toString()];
36
+ }
37
+
38
+ type StrategyType = "Long" | "Short";
39
+
40
+ function solautoStrategyName(supplyMint?: PublicKey, debtMint?: PublicKey) {
41
+ const supplyInfo = tokenInfo(supplyMint);
42
+ const debtInfo = tokenInfo(debtMint);
43
+ const strat = strategyType(
44
+ supplyMint ?? PublicKey.default,
45
+ debtMint ?? PublicKey.default
46
+ );
47
+
48
+ if (strat === "Long") {
49
+ return debtInfo.isStableCoin
50
+ ? `${supplyInfo.ticker} Long`
51
+ : supplyInfo.ticker
52
+ ? `${supplyInfo.ticker}/${debtInfo.ticker} Long`
53
+ : "";
54
+ } else {
55
+ return `${debtInfo.ticker} Short`;
56
+ }
57
+ }
58
+
59
+ function strategyType(
60
+ supplyMint: PublicKey,
61
+ debtMint: PublicKey
62
+ ): StrategyType {
63
+ const supplyInfo = tokenInfo(supplyMint);
64
+ const debtInfo = tokenInfo(debtMint);
65
+
66
+ if (supplyInfo.isLST && debtMint.equals(NATIVE_MINT)) {
67
+ // Yield
68
+ throw new Error("Not yet supported");
69
+ } else if (debtInfo.isStableCoin) {
70
+ return "Long";
71
+ } else if (supplyInfo.isStableCoin) {
72
+ return "Short";
73
+ } else {
74
+ return "Long";
75
+ }
76
+ }
77
+
78
+ export function roundToDecimals(value: number, decimals: number = 2): number {
79
+ if (!value || isNaN(value)) {
80
+ return value;
81
+ }
82
+
83
+ let roundedValue: number | undefined;
84
+ do {
85
+ const factor = Math.pow(10, decimals ?? 2);
86
+ roundedValue = Math.round(value * factor) / factor;
87
+ decimals += 1;
88
+ } while (!roundedValue || decimals >= 10);
89
+
90
+ return roundedValue;
91
+ }
92
+
93
+ export function formatNumberToShortForm(
94
+ num: number,
95
+ decimals?: number
96
+ ): string {
97
+ if (decimals === undefined) {
98
+ decimals = 1;
99
+ }
100
+ if (num >= 1_000_000_000) {
101
+ return (
102
+ (num / 1_000_000_000)
103
+ .toFixed(decimals)
104
+ .replace(new RegExp(`\\.0{${decimals}}$`), "") + "B"
105
+ );
106
+ }
107
+ if (num >= 1_000_000) {
108
+ return (
109
+ (num / 1_000_000)
110
+ .toFixed(decimals)
111
+ .replace(new RegExp(`\\.0{${decimals}}$`), "") + "M"
112
+ );
113
+ }
114
+ if (num >= 1_000) {
115
+ return (
116
+ (num / 1_000)
117
+ .toFixed(decimals)
118
+ .replace(new RegExp(`\\.0{${decimals}}$`), "") + "K"
119
+ );
120
+ }
121
+ return num.toFixed(decimals).replace(new RegExp(`\\.0{${decimals}}$`), "");
122
+ }
123
+
124
+ export function formatNumber(
125
+ num: number,
126
+ decimals?: number,
127
+ shortFormAtThreshold?: number,
128
+ decimalsAtShortform?: number
129
+ ): string {
130
+ if (shortFormAtThreshold !== undefined && num > shortFormAtThreshold) {
131
+ return formatNumberToShortForm(num, decimalsAtShortform);
132
+ } else {
133
+ return num < 1
134
+ ? roundToDecimals(num, decimals).toString()
135
+ : new Intl.NumberFormat("en-US").format(
136
+ decimals !== undefined ? roundToDecimals(num, decimals) : num
137
+ );
138
+ }
139
+ }
140
+
141
+ async function main(filterWhitelist: boolean) {
9
142
  const [_, umi] = getSolanaRpcConnection(
10
143
  buildHeliusApiUrl(process.env.HELIUS_API_KEY!),
11
144
  SOLAUTO_PROD_PROGRAM
12
145
  );
13
- const positions = await getSolautoManagedPositions(umi);
14
- // TODO: filter out certain wallet authorities using an env variable
146
+ let positions = await getSolautoManagedPositions(umi);
147
+
148
+ if (filterWhitelist) {
149
+ const addressWhitelist = process.env.ADDRESS_WHITELIST?.split(",") ?? [];
150
+ positions = positions.filter(
151
+ (x) => !addressWhitelist.includes(x.authority.toString())
152
+ );
153
+ }
154
+
155
+ const batches = getBatches(positions, 30);
156
+
157
+ const solautoPositionsData = (
158
+ await Promise.all(
159
+ batches.map(async (pubkeys) => {
160
+ return retryWithExponentialBackoff(
161
+ async () =>
162
+ await safeFetchAllSolautoPosition(
163
+ umi,
164
+ pubkeys.map((x) => publicKey(x.publicKey!))
165
+ )
166
+ );
167
+ })
168
+ )
169
+ ).flat();
170
+
171
+ const tokensUsed = Array.from(
172
+ new Set(
173
+ positions.flatMap((x) => [
174
+ x.supplyMint!.toString(),
175
+ x.debtMint!.toString(),
176
+ ])
177
+ )
178
+ );
179
+
180
+ const tokenBatches = getBatches(tokensUsed, 15);
181
+ await Promise.all(
182
+ tokenBatches.map(async (batch) => {
183
+ await fetchTokenPrices(batch.map((x) => new PublicKey(x)));
184
+ })
185
+ );
186
+
187
+ console.log("\n\n");
188
+
189
+ const latestStates: PositionState[] = [];
190
+ for (const pos of solautoPositionsData) {
191
+ const latestState = await positionStateWithLatestPrices(
192
+ pos.state,
193
+ safeGetPrice(pos.state.supply.mint),
194
+ safeGetPrice(pos.state.debt.mint)
195
+ );
196
+ latestStates.push(latestState);
197
+
198
+ const strategy = solautoStrategyName(
199
+ toWeb3JsPublicKey(pos.state.supply.mint),
200
+ toWeb3JsPublicKey(pos.state.debt.mint)
201
+ );
202
+
203
+ console.log("Position:", pos.publicKey.toString());
204
+ console.log("Authority:", pos.authority.toString());
205
+ console.log(
206
+ `${strategy}: $${formatNumber(fromBaseUnit(latestState.netWorth.baseAmountUsdValue, USD_DECIMALS), 2, 10000, 2)}`
207
+ );
208
+ console.log("\n");
209
+ }
210
+
211
+ console.log("Total positions:", solautoPositionsData.length);
212
+ console.log(
213
+ "Total users:",
214
+ Array.from(new Set(solautoPositionsData.map((x) => x.authority.toString())))
215
+ .length
216
+ );
15
217
 
16
- console.log(positions);
17
- console.log("Total positions:", positions.length);
18
- // TODO: log net worth / balances
218
+ const tvl = latestStates
219
+ .map((x) => fromBaseUnit(x.netWorth.baseAmountUsdValue, USD_DECIMALS))
220
+ .reduce((acc, curr) => acc + curr, 0);
221
+ console.log(`Total TVL: $${formatNumber(tvl, 2, 10000, 2)}`);
19
222
  }
20
223
 
21
- main().then((x) => x);
224
+ const filterWhitelist = true;
225
+ main(filterWhitelist).then((x) => x);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haven-fi/solauto-sdk",
3
- "version": "1.0.400",
3
+ "version": "1.0.401",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "description": "Typescript SDK for the Solauto program on the Solana blockchain",
@@ -27,6 +27,7 @@
27
27
  "axios": "^1.7.8",
28
28
  "bs58": "^5.0.0",
29
29
  "cross-fetch": "^4.0.0",
30
+ "dotenv": "^16.4.7",
30
31
  "rpc-websockets": "7.11.0"
31
32
  },
32
33
  "devDependencies": {
@@ -162,7 +162,8 @@ export async function getAddressLookupInputs(
162
162
  lookupTableAddresses: string[]
163
163
  ): Promise<AddressLookupTableInput[]> {
164
164
  const addressLookupTableAccountInfos = await umi.rpc.getAccounts(
165
- lookupTableAddresses.map((key) => publicKey(key))
165
+ lookupTableAddresses.map((key) => publicKey(key)),
166
+ { commitment: "confirmed" }
166
167
  );
167
168
 
168
169
  return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => {