@kamino-finance/klend-sdk 7.3.2 → 7.3.4
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.
- package/dist/classes/manager.d.ts +21 -0
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +31 -2
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/market.d.ts.map +1 -1
- package/dist/classes/market.js +16 -6
- package/dist/classes/market.js.map +1 -1
- package/dist/classes/reserve.d.ts +2 -1
- package/dist/classes/reserve.d.ts.map +1 -1
- package/dist/classes/reserve.js +11 -5
- package/dist/classes/reserve.js.map +1 -1
- package/dist/classes/shared.d.ts +1 -0
- package/dist/classes/shared.d.ts.map +1 -1
- package/dist/classes/shared.js.map +1 -1
- package/dist/classes/vault.d.ts +16 -1
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +154 -44
- package/dist/classes/vault.js.map +1 -1
- package/dist/utils/readCdnData.d.ts +25 -0
- package/dist/utils/readCdnData.d.ts.map +1 -0
- package/dist/utils/readCdnData.js +29 -0
- package/dist/utils/readCdnData.js.map +1 -0
- package/package.json +1 -1
- package/src/classes/manager.ts +47 -2
- package/src/classes/market.ts +24 -6
- package/src/classes/reserve.ts +13 -5
- package/src/classes/shared.ts +1 -0
- package/src/classes/vault.ts +258 -67
- package/src/utils/readCdnData.ts +50 -0
package/src/classes/vault.ts
CHANGED
|
@@ -49,6 +49,9 @@ import {
|
|
|
49
49
|
buy,
|
|
50
50
|
BuyAccounts,
|
|
51
51
|
BuyArgs,
|
|
52
|
+
deposit,
|
|
53
|
+
DepositAccounts,
|
|
54
|
+
DepositArgs,
|
|
52
55
|
giveUpPendingFees,
|
|
53
56
|
GiveUpPendingFeesAccounts,
|
|
54
57
|
GiveUpPendingFeesArgs,
|
|
@@ -70,6 +73,9 @@ import {
|
|
|
70
73
|
updateVaultConfig,
|
|
71
74
|
UpdateVaultConfigAccounts,
|
|
72
75
|
UpdateVaultConfigArgs,
|
|
76
|
+
withdraw,
|
|
77
|
+
WithdrawAccounts,
|
|
78
|
+
WithdrawArgs,
|
|
73
79
|
withdrawFromAvailable,
|
|
74
80
|
WithdrawFromAvailableAccounts,
|
|
75
81
|
WithdrawFromAvailableArgs,
|
|
@@ -139,6 +145,7 @@ import { Farms } from '@kamino-finance/farms-sdk';
|
|
|
139
145
|
import { getFarmIncentives } from '@kamino-finance/farms-sdk/dist/utils/apy';
|
|
140
146
|
import { computeReservesAllocation } from '../utils/vaultAllocation';
|
|
141
147
|
import { getReserveFarmRewardsAPY } from '../utils/farmUtils';
|
|
148
|
+
import { fetchKaminoCdnData } from '../utils/readCdnData';
|
|
142
149
|
|
|
143
150
|
export const kaminoVaultId = address('KvauGMspG5k6rtzrqqn7WNn3oZdyKqLKwK2XWQ8FLjd');
|
|
144
151
|
export const kaminoVaultStagingId = address('stKvQfwRsQiKnLtMNVLHKS3exFJmZFsgfzBPWHECUYK');
|
|
@@ -1191,6 +1198,27 @@ export class KaminoVaultClient {
|
|
|
1191
1198
|
tokenAmount: Decimal,
|
|
1192
1199
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1193
1200
|
farmState?: FarmState
|
|
1201
|
+
): Promise<DepositIxs> {
|
|
1202
|
+
return this.buildShareEntryIxs('deposit', user, vault, tokenAmount, vaultReservesMap, farmState);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
async buySharesIxs(
|
|
1206
|
+
user: TransactionSigner,
|
|
1207
|
+
vault: KaminoVault,
|
|
1208
|
+
tokenAmount: Decimal,
|
|
1209
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1210
|
+
farmState?: FarmState
|
|
1211
|
+
): Promise<DepositIxs> {
|
|
1212
|
+
return this.buildShareEntryIxs('buy', user, vault, tokenAmount, vaultReservesMap, farmState);
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
private async buildShareEntryIxs(
|
|
1216
|
+
mode: 'deposit' | 'buy',
|
|
1217
|
+
user: TransactionSigner,
|
|
1218
|
+
vault: KaminoVault,
|
|
1219
|
+
tokenAmount: Decimal,
|
|
1220
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1221
|
+
farmState?: FarmState
|
|
1194
1222
|
): Promise<DepositIxs> {
|
|
1195
1223
|
const vaultState = await vault.getState();
|
|
1196
1224
|
|
|
@@ -1225,49 +1253,66 @@ export class KaminoVaultClient {
|
|
|
1225
1253
|
createAtasIxs.push(createSharesAtaIxs);
|
|
1226
1254
|
|
|
1227
1255
|
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1228
|
-
const
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1256
|
+
const tokenAmountLamports = numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).floor();
|
|
1257
|
+
let entryIx: Instruction;
|
|
1258
|
+
if (mode === 'deposit') {
|
|
1259
|
+
const depositAccounts: DepositAccounts = {
|
|
1260
|
+
user,
|
|
1261
|
+
vaultState: vault.address,
|
|
1262
|
+
tokenVault: vaultState.tokenVault,
|
|
1263
|
+
tokenMint: vaultState.tokenMint,
|
|
1264
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1265
|
+
sharesMint: vaultState.sharesMint,
|
|
1266
|
+
userTokenAta,
|
|
1267
|
+
userSharesAta,
|
|
1268
|
+
tokenProgram: tokenProgramID,
|
|
1269
|
+
klendProgram: this._kaminoLendProgramId,
|
|
1270
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1271
|
+
eventAuthority,
|
|
1272
|
+
program: this._kaminoVaultProgramId,
|
|
1273
|
+
};
|
|
1274
|
+
const depositArgs: DepositArgs = {
|
|
1275
|
+
maxAmount: new BN(tokenAmountLamports.toString()),
|
|
1276
|
+
};
|
|
1277
|
+
entryIx = deposit(depositArgs, depositAccounts, undefined, this._kaminoVaultProgramId);
|
|
1278
|
+
} else {
|
|
1279
|
+
const buyAccounts: BuyAccounts = {
|
|
1280
|
+
user,
|
|
1281
|
+
vaultState: vault.address,
|
|
1282
|
+
tokenVault: vaultState.tokenVault,
|
|
1283
|
+
tokenMint: vaultState.tokenMint,
|
|
1284
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1285
|
+
sharesMint: vaultState.sharesMint,
|
|
1286
|
+
userTokenAta,
|
|
1287
|
+
userSharesAta,
|
|
1288
|
+
tokenProgram: tokenProgramID,
|
|
1289
|
+
klendProgram: this._kaminoLendProgramId,
|
|
1290
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1291
|
+
eventAuthority,
|
|
1292
|
+
program: this._kaminoVaultProgramId,
|
|
1293
|
+
};
|
|
1294
|
+
const buyArgs: BuyArgs = {
|
|
1295
|
+
maxAmount: new BN(tokenAmountLamports.toString()),
|
|
1296
|
+
};
|
|
1297
|
+
entryIx = buy(buyArgs, buyAccounts, undefined, this._kaminoVaultProgramId);
|
|
1298
|
+
}
|
|
1251
1299
|
|
|
1252
1300
|
const vaultReserves = this.getVaultReserves(vaultState);
|
|
1253
|
-
|
|
1254
1301
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1255
|
-
|
|
1302
|
+
entryIx = this.appendRemainingAccountsForVaultReserves(entryIx, vaultReserves, vaultReservesState);
|
|
1256
1303
|
|
|
1257
|
-
const
|
|
1258
|
-
depositIxs: [...createAtasIxs,
|
|
1304
|
+
const result: DepositIxs = {
|
|
1305
|
+
depositIxs: [...createAtasIxs, entryIx, ...closeAtasIxs],
|
|
1259
1306
|
stakeInFarmIfNeededIxs: [],
|
|
1260
1307
|
};
|
|
1261
1308
|
|
|
1262
|
-
// if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
|
|
1263
1309
|
if (!(await vault.hasFarm())) {
|
|
1264
|
-
return
|
|
1310
|
+
return result;
|
|
1265
1311
|
}
|
|
1266
1312
|
|
|
1267
|
-
// if there is a farm, stake the shares
|
|
1268
1313
|
const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
|
|
1269
|
-
|
|
1270
|
-
return
|
|
1314
|
+
result.stakeInFarmIfNeededIxs = stakeSharesIxs;
|
|
1315
|
+
return result;
|
|
1271
1316
|
}
|
|
1272
1317
|
|
|
1273
1318
|
/**
|
|
@@ -1317,6 +1362,39 @@ export class KaminoVaultClient {
|
|
|
1317
1362
|
slot: Slot,
|
|
1318
1363
|
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1319
1364
|
farmState?: FarmState
|
|
1365
|
+
): Promise<WithdrawIxs> {
|
|
1366
|
+
return this.buildShareExitIxs('withdraw', user, vault, shareAmountToWithdraw, slot, vaultReservesMap, farmState);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
/**
|
|
1370
|
+
* This function will return the missing ATA creation instructions, as well as one or multiple withdraw instructions, based on how many reserves it's needed to withdraw from. This might have to be split in multiple transactions
|
|
1371
|
+
* @param user - user to sell shares for vault tokens
|
|
1372
|
+
* @param vault - vault to sell shares from
|
|
1373
|
+
* @param shareAmount - share amount to sell (in tokens, not lamports), in order to withdraw everything, any value > user share amount
|
|
1374
|
+
* @param slot - current slot, used to estimate the interest earned in the different reserves with allocation from the vault
|
|
1375
|
+
* @param [vaultReservesMap] - optional parameter; a hashmap from each reserve pubkey to the reserve state. If provided the function will be significantly faster as it will not have to fetch the reserves
|
|
1376
|
+
* @param [farmState] - the state of the vault farm, if the vault has a farm. Optional. If not provided, it will be fetched
|
|
1377
|
+
* @returns an array of instructions to create missing ATAs if needed and the withdraw instructions
|
|
1378
|
+
*/
|
|
1379
|
+
async sellSharesIxs(
|
|
1380
|
+
user: TransactionSigner,
|
|
1381
|
+
vault: KaminoVault,
|
|
1382
|
+
shareAmountToWithdraw: Decimal,
|
|
1383
|
+
slot: Slot,
|
|
1384
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1385
|
+
farmState?: FarmState
|
|
1386
|
+
): Promise<WithdrawIxs> {
|
|
1387
|
+
return this.buildShareExitIxs('sell', user, vault, shareAmountToWithdraw, slot, vaultReservesMap, farmState);
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
private async buildShareExitIxs(
|
|
1391
|
+
mode: 'withdraw' | 'sell',
|
|
1392
|
+
user: TransactionSigner,
|
|
1393
|
+
vault: KaminoVault,
|
|
1394
|
+
shareAmountToWithdraw: Decimal,
|
|
1395
|
+
slot: Slot,
|
|
1396
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1397
|
+
farmState?: FarmState
|
|
1320
1398
|
): Promise<WithdrawIxs> {
|
|
1321
1399
|
const vaultState = await vault.getState();
|
|
1322
1400
|
const hasFarm = await vault.hasFarm();
|
|
@@ -1388,20 +1466,47 @@ export class KaminoVaultClient {
|
|
|
1388
1466
|
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
|
|
1389
1467
|
}
|
|
1390
1468
|
|
|
1391
|
-
|
|
1392
|
-
const vaultAllocation = vaultState.vaultAllocationStrategy.find(
|
|
1469
|
+
const hasAllocatedReserves = vaultState.vaultAllocationStrategy.some(
|
|
1393
1470
|
(allocation) => allocation.reserve !== DEFAULT_PUBLIC_KEY
|
|
1394
1471
|
);
|
|
1395
1472
|
|
|
1396
|
-
if (
|
|
1397
|
-
const
|
|
1473
|
+
if (hasAllocatedReserves) {
|
|
1474
|
+
const reserveExitBuilder: ReserveExitInstructionBuilder =
|
|
1475
|
+
mode === 'withdraw'
|
|
1476
|
+
? (params) =>
|
|
1477
|
+
this.withdrawIx(
|
|
1478
|
+
params.user,
|
|
1479
|
+
params.vault,
|
|
1480
|
+
params.vaultState,
|
|
1481
|
+
params.marketAddress,
|
|
1482
|
+
params.reserve,
|
|
1483
|
+
params.userSharesAta,
|
|
1484
|
+
params.userTokenAta,
|
|
1485
|
+
params.shareAmountLamports,
|
|
1486
|
+
params.vaultReservesState
|
|
1487
|
+
)
|
|
1488
|
+
: (params) =>
|
|
1489
|
+
this.sellIx(
|
|
1490
|
+
params.user,
|
|
1491
|
+
params.vault,
|
|
1492
|
+
params.vaultState,
|
|
1493
|
+
params.marketAddress,
|
|
1494
|
+
params.reserve,
|
|
1495
|
+
params.userSharesAta,
|
|
1496
|
+
params.userTokenAta,
|
|
1497
|
+
params.shareAmountLamports,
|
|
1498
|
+
params.vaultReservesState
|
|
1499
|
+
);
|
|
1500
|
+
const withdrawFromVaultIxs = await this.buildReserveExitIxs({
|
|
1398
1501
|
user,
|
|
1399
1502
|
vault,
|
|
1400
|
-
|
|
1401
|
-
|
|
1503
|
+
vaultState,
|
|
1504
|
+
shareAmount: sharesToWithdraw,
|
|
1505
|
+
allUserShares: totalUserShares,
|
|
1402
1506
|
slot,
|
|
1403
|
-
vaultReservesMap
|
|
1404
|
-
|
|
1507
|
+
vaultReservesMap,
|
|
1508
|
+
builder: reserveExitBuilder,
|
|
1509
|
+
});
|
|
1405
1510
|
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1406
1511
|
} else {
|
|
1407
1512
|
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
|
|
@@ -1467,16 +1572,16 @@ export class KaminoVaultClient {
|
|
|
1467
1572
|
return [createAtaIx, withdrawFromAvailableIxn];
|
|
1468
1573
|
}
|
|
1469
1574
|
|
|
1470
|
-
private async
|
|
1471
|
-
user
|
|
1472
|
-
vault
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1575
|
+
private async buildReserveExitIxs({
|
|
1576
|
+
user,
|
|
1577
|
+
vault,
|
|
1578
|
+
vaultState,
|
|
1579
|
+
shareAmount,
|
|
1580
|
+
allUserShares,
|
|
1581
|
+
slot,
|
|
1582
|
+
vaultReservesMap,
|
|
1583
|
+
builder,
|
|
1584
|
+
}: BuildReserveExitIxsParams): Promise<Instruction[]> {
|
|
1480
1585
|
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1481
1586
|
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1482
1587
|
const [{ ata: userTokenAta, createAtaIx }] = await createAtasIdempotent(user, [
|
|
@@ -1505,32 +1610,32 @@ export class KaminoVaultClient {
|
|
|
1505
1610
|
let isFirstWithdraw = true;
|
|
1506
1611
|
|
|
1507
1612
|
if (tokenLeftToWithdraw.lte(0)) {
|
|
1508
|
-
// Availabe enough to withdraw all - using the first existent reserve
|
|
1509
1613
|
const firstReserve = vaultState.vaultAllocationStrategy.find((reserve) => reserve.reserve !== DEFAULT_PUBLIC_KEY);
|
|
1614
|
+
if (!firstReserve) {
|
|
1615
|
+
throw new Error('No reserve available to satisfy withdraw request');
|
|
1616
|
+
}
|
|
1510
1617
|
if (withdrawAllShares) {
|
|
1511
1618
|
reserveWithSharesAmountToWithdraw.push({
|
|
1512
|
-
reserve: firstReserve
|
|
1619
|
+
reserve: firstReserve.reserve,
|
|
1513
1620
|
shares: new Decimal(U64_MAX.toString()),
|
|
1514
1621
|
});
|
|
1515
1622
|
} else {
|
|
1516
1623
|
reserveWithSharesAmountToWithdraw.push({
|
|
1517
|
-
reserve: firstReserve
|
|
1624
|
+
reserve: firstReserve.reserve,
|
|
1518
1625
|
shares: shareLamportsToWithdraw,
|
|
1519
1626
|
});
|
|
1520
1627
|
}
|
|
1521
1628
|
} else {
|
|
1522
|
-
// Get decreasing order sorted available liquidity to withdraw from each reserve allocated to
|
|
1523
1629
|
const reserveAllocationAvailableLiquidityToWithdraw = await this.getReserveAllocationAvailableLiquidityToWithdraw(
|
|
1524
1630
|
vault,
|
|
1525
1631
|
slot,
|
|
1526
1632
|
vaultReservesState
|
|
1527
1633
|
);
|
|
1528
|
-
// sort
|
|
1529
1634
|
const reserveAllocationAvailableLiquidityToWithdrawSorted = [
|
|
1530
1635
|
...reserveAllocationAvailableLiquidityToWithdraw.entries(),
|
|
1531
1636
|
].sort((a, b) => b[1].sub(a[1]).toNumber());
|
|
1532
1637
|
|
|
1533
|
-
reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw]
|
|
1638
|
+
reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw]) => {
|
|
1534
1639
|
if (tokenLeftToWithdraw.gt(0)) {
|
|
1535
1640
|
let tokensToWithdrawFromReserve = Decimal.min(tokenLeftToWithdraw, availableLiquidityToWithdraw);
|
|
1536
1641
|
if (isFirstWithdraw) {
|
|
@@ -1540,7 +1645,6 @@ export class KaminoVaultClient {
|
|
|
1540
1645
|
if (withdrawAllShares) {
|
|
1541
1646
|
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: new Decimal(U64_MAX.toString()) });
|
|
1542
1647
|
} else {
|
|
1543
|
-
// round up to the nearest integer the shares to withdraw
|
|
1544
1648
|
const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).floor();
|
|
1545
1649
|
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: sharesToWithdrawFromReserve });
|
|
1546
1650
|
}
|
|
@@ -1552,26 +1656,25 @@ export class KaminoVaultClient {
|
|
|
1552
1656
|
|
|
1553
1657
|
const withdrawIxs: Instruction[] = [];
|
|
1554
1658
|
withdrawIxs.push(createAtaIx);
|
|
1555
|
-
for (
|
|
1556
|
-
const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
|
|
1659
|
+
for (const reserveWithTokens of reserveWithSharesAmountToWithdraw) {
|
|
1557
1660
|
const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
|
|
1558
1661
|
if (reserveState === undefined) {
|
|
1559
1662
|
throw new Error(`Reserve ${reserveWithTokens.reserve} not found in vault reserves map`);
|
|
1560
1663
|
}
|
|
1561
1664
|
const marketAddress = reserveState.state.lendingMarket;
|
|
1562
1665
|
|
|
1563
|
-
const
|
|
1666
|
+
const exitIx = await builder({
|
|
1564
1667
|
user,
|
|
1565
1668
|
vault,
|
|
1566
1669
|
vaultState,
|
|
1567
1670
|
marketAddress,
|
|
1568
|
-
{ address: reserveWithTokens.reserve, state: reserveState.state },
|
|
1671
|
+
reserve: { address: reserveWithTokens.reserve, state: reserveState.state },
|
|
1569
1672
|
userSharesAta,
|
|
1570
1673
|
userTokenAta,
|
|
1571
|
-
reserveWithTokens.shares,
|
|
1572
|
-
vaultReservesState
|
|
1573
|
-
);
|
|
1574
|
-
withdrawIxs.push(
|
|
1674
|
+
shareAmountLamports: reserveWithTokens.shares,
|
|
1675
|
+
vaultReservesState,
|
|
1676
|
+
});
|
|
1677
|
+
withdrawIxs.push(exitIx);
|
|
1575
1678
|
}
|
|
1576
1679
|
|
|
1577
1680
|
return withdrawIxs;
|
|
@@ -1847,6 +1950,65 @@ export class KaminoVaultClient {
|
|
|
1847
1950
|
return sellIxn;
|
|
1848
1951
|
}
|
|
1849
1952
|
|
|
1953
|
+
private async withdrawIx(
|
|
1954
|
+
user: TransactionSigner,
|
|
1955
|
+
vault: KaminoVault,
|
|
1956
|
+
vaultState: VaultState,
|
|
1957
|
+
marketAddress: Address,
|
|
1958
|
+
reserve: ReserveWithAddress,
|
|
1959
|
+
userSharesAta: Address,
|
|
1960
|
+
userTokenAta: Address,
|
|
1961
|
+
shareAmountLamports: Decimal,
|
|
1962
|
+
vaultReservesState: Map<Address, KaminoReserve>
|
|
1963
|
+
): Promise<Instruction> {
|
|
1964
|
+
const [lendingMarketAuth] = await lendingMarketAuthPda(marketAddress, this._kaminoLendProgramId);
|
|
1965
|
+
|
|
1966
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
1967
|
+
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1968
|
+
const withdrawAccounts: WithdrawAccounts = {
|
|
1969
|
+
withdrawFromAvailable: {
|
|
1970
|
+
user,
|
|
1971
|
+
vaultState: vault.address,
|
|
1972
|
+
globalConfig: globalConfig,
|
|
1973
|
+
tokenVault: vaultState.tokenVault,
|
|
1974
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1975
|
+
userTokenAta: userTokenAta,
|
|
1976
|
+
tokenMint: vaultState.tokenMint,
|
|
1977
|
+
userSharesAta: userSharesAta,
|
|
1978
|
+
sharesMint: vaultState.sharesMint,
|
|
1979
|
+
tokenProgram: vaultState.tokenProgram,
|
|
1980
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1981
|
+
klendProgram: this._kaminoLendProgramId,
|
|
1982
|
+
eventAuthority: eventAuthority,
|
|
1983
|
+
program: this._kaminoVaultProgramId,
|
|
1984
|
+
},
|
|
1985
|
+
withdrawFromReserveAccounts: {
|
|
1986
|
+
vaultState: vault.address,
|
|
1987
|
+
reserve: reserve.address,
|
|
1988
|
+
ctokenVault: await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId),
|
|
1989
|
+
lendingMarket: marketAddress,
|
|
1990
|
+
lendingMarketAuthority: lendingMarketAuth,
|
|
1991
|
+
reserveLiquiditySupply: reserve.state.liquidity.supplyVault,
|
|
1992
|
+
reserveCollateralMint: reserve.state.collateral.mintPubkey,
|
|
1993
|
+
reserveCollateralTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1994
|
+
instructionSysvarAccount: SYSVAR_INSTRUCTIONS_ADDRESS,
|
|
1995
|
+
},
|
|
1996
|
+
eventAuthority: eventAuthority,
|
|
1997
|
+
program: this._kaminoVaultProgramId,
|
|
1998
|
+
};
|
|
1999
|
+
|
|
2000
|
+
const withdrawArgs: WithdrawArgs = {
|
|
2001
|
+
sharesAmount: new BN(shareAmountLamports.floor().toString()),
|
|
2002
|
+
};
|
|
2003
|
+
|
|
2004
|
+
let withdrawIxn = withdraw(withdrawArgs, withdrawAccounts, undefined, this._kaminoVaultProgramId);
|
|
2005
|
+
|
|
2006
|
+
const vaultReserves = this.getVaultReserves(vaultState);
|
|
2007
|
+
withdrawIxn = this.appendRemainingAccountsForVaultReserves(withdrawIxn, vaultReserves, vaultReservesState);
|
|
2008
|
+
|
|
2009
|
+
return withdrawIxn;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
1850
2012
|
private async withdrawFromAvailableIx(
|
|
1851
2013
|
user: TransactionSigner,
|
|
1852
2014
|
vault: KaminoVault,
|
|
@@ -2581,7 +2743,10 @@ export class KaminoVaultClient {
|
|
|
2581
2743
|
const deserializedReserves = await batchFetch(vaultReservesAddresses, (chunk) =>
|
|
2582
2744
|
this.loadReserializedReserves(chunk)
|
|
2583
2745
|
);
|
|
2584
|
-
const reservesAndOracles = await
|
|
2746
|
+
const [reservesAndOracles, cdnResourcesData] = await Promise.all([
|
|
2747
|
+
getTokenOracleData(this.getConnection(), deserializedReserves, oracleAccounts),
|
|
2748
|
+
fetchKaminoCdnData(),
|
|
2749
|
+
]);
|
|
2585
2750
|
const kaminoReserves = new Map<Address, KaminoReserve>();
|
|
2586
2751
|
reservesAndOracles.forEach(([reserve, oracle], index) => {
|
|
2587
2752
|
if (!oracle) {
|
|
@@ -2596,7 +2761,8 @@ export class KaminoVaultClient {
|
|
|
2596
2761
|
reserve,
|
|
2597
2762
|
oracle,
|
|
2598
2763
|
this.getConnection(),
|
|
2599
|
-
this.recentSlotDurationMs
|
|
2764
|
+
this.recentSlotDurationMs,
|
|
2765
|
+
cdnResourcesData
|
|
2600
2766
|
);
|
|
2601
2767
|
kaminoReserves.set(kaminoReserve.address, kaminoReserve);
|
|
2602
2768
|
});
|
|
@@ -4432,3 +4598,28 @@ export type PendingRewardsForUserInVault = {
|
|
|
4432
4598
|
pendingRewardsInVaultReservesFarms: Map<Address, Decimal>;
|
|
4433
4599
|
totalPendingRewards: Map<Address, Decimal>;
|
|
4434
4600
|
};
|
|
4601
|
+
|
|
4602
|
+
type ReserveExitBuilderParams = {
|
|
4603
|
+
user: TransactionSigner;
|
|
4604
|
+
vault: KaminoVault;
|
|
4605
|
+
vaultState: VaultState;
|
|
4606
|
+
marketAddress: Address;
|
|
4607
|
+
reserve: ReserveWithAddress;
|
|
4608
|
+
userSharesAta: Address;
|
|
4609
|
+
userTokenAta: Address;
|
|
4610
|
+
shareAmountLamports: Decimal;
|
|
4611
|
+
vaultReservesState: Map<Address, KaminoReserve>;
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
type ReserveExitInstructionBuilder = (params: ReserveExitBuilderParams) => Promise<Instruction>;
|
|
4615
|
+
|
|
4616
|
+
type BuildReserveExitIxsParams = {
|
|
4617
|
+
user: TransactionSigner;
|
|
4618
|
+
vault: KaminoVault;
|
|
4619
|
+
vaultState: VaultState;
|
|
4620
|
+
shareAmount: Decimal;
|
|
4621
|
+
allUserShares: Decimal;
|
|
4622
|
+
slot: Slot;
|
|
4623
|
+
vaultReservesMap?: Map<Address, KaminoReserve>;
|
|
4624
|
+
builder: ReserveExitInstructionBuilder;
|
|
4625
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CDN_ENDPOINT } from './constants';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CDN data structure containing Kamino resources for different networks
|
|
5
|
+
*/
|
|
6
|
+
export interface AllKaminoCdnData {
|
|
7
|
+
'mainnet-beta': KaminoCdnData;
|
|
8
|
+
devnet: KaminoCdnData;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Kamino CDN data structure
|
|
13
|
+
* This type can be extended with additional fields as needed
|
|
14
|
+
*/
|
|
15
|
+
export interface KaminoCdnData {
|
|
16
|
+
/**
|
|
17
|
+
* List of deprecated reserve addresses (pubkeys as strings)
|
|
18
|
+
* Note: This field is named 'deprecatedAssets' in the CDN but represents deprecated reserves
|
|
19
|
+
*/
|
|
20
|
+
deprecatedAssets: string[];
|
|
21
|
+
// Additional fields can be added here as they become relevant
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Fetches Kamino CDN data from the resources endpoint
|
|
27
|
+
* @returns Promise resolving to the CDN data for the specified cluster or undefined if fetching/parsing fails
|
|
28
|
+
*/
|
|
29
|
+
export async function fetchKaminoCdnData(): Promise<KaminoCdnData | undefined> {
|
|
30
|
+
const url = `${CDN_ENDPOINT}/resources.json`;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(url);
|
|
34
|
+
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const text = await response.text();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const data: AllKaminoCdnData = JSON.parse(text);
|
|
43
|
+
return data['mainnet-beta'];
|
|
44
|
+
} catch (parseError) {
|
|
45
|
+
throw new Error('Invalid JSON in response');
|
|
46
|
+
}
|
|
47
|
+
} catch (error) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
}
|