@kamino-finance/klend-sdk 7.3.0 → 7.3.1
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 +2 -0
- package/dist/classes/manager.d.ts.map +1 -1
- package/dist/classes/manager.js +6 -0
- package/dist/classes/manager.js.map +1 -1
- package/dist/classes/vault.d.ts +4 -0
- package/dist/classes/vault.d.ts.map +1 -1
- package/dist/classes/vault.js +260 -0
- package/dist/classes/vault.js.map +1 -1
- package/package.json +1 -1
- package/src/classes/manager.ts +21 -0
- package/src/classes/vault.ts +389 -0
package/src/classes/vault.ts
CHANGED
|
@@ -46,6 +46,9 @@ import {
|
|
|
46
46
|
addUpdateWhitelistedReserve,
|
|
47
47
|
AddUpdateWhitelistedReserveAccounts,
|
|
48
48
|
AddUpdateWhitelistedReserveArgs,
|
|
49
|
+
buy,
|
|
50
|
+
BuyAccounts,
|
|
51
|
+
BuyArgs,
|
|
49
52
|
deposit,
|
|
50
53
|
DepositAccounts,
|
|
51
54
|
DepositArgs,
|
|
@@ -59,6 +62,9 @@ import {
|
|
|
59
62
|
InvestAccounts,
|
|
60
63
|
removeAllocation,
|
|
61
64
|
RemoveAllocationAccounts,
|
|
65
|
+
sell,
|
|
66
|
+
SellAccounts,
|
|
67
|
+
SellArgs,
|
|
62
68
|
updateAdmin,
|
|
63
69
|
UpdateAdminAccounts,
|
|
64
70
|
updateReserveAllocation,
|
|
@@ -1270,6 +1276,92 @@ export class KaminoVaultClient {
|
|
|
1270
1276
|
return depositIxs;
|
|
1271
1277
|
}
|
|
1272
1278
|
|
|
1279
|
+
// todo (silviu): after all tx indexing works for buy/sell ixs remove this function and use the buyIx in the deposit function above
|
|
1280
|
+
async buySharesIxs(
|
|
1281
|
+
user: TransactionSigner,
|
|
1282
|
+
vault: KaminoVault,
|
|
1283
|
+
tokenAmount: Decimal,
|
|
1284
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1285
|
+
farmState?: FarmState
|
|
1286
|
+
): Promise<DepositIxs> {
|
|
1287
|
+
const vaultState = await vault.getState();
|
|
1288
|
+
|
|
1289
|
+
const tokenProgramID = vaultState.tokenProgram;
|
|
1290
|
+
const userTokenAta = await getAssociatedTokenAddress(vaultState.tokenMint, user.address, tokenProgramID);
|
|
1291
|
+
const createAtasIxs: Instruction[] = [];
|
|
1292
|
+
const closeAtasIxs: Instruction[] = [];
|
|
1293
|
+
if (vaultState.tokenMint === WRAPPED_SOL_MINT) {
|
|
1294
|
+
const [{ ata: wsolAta, createAtaIx: createWsolAtaIxn }] = await createAtasIdempotent(user, [
|
|
1295
|
+
{
|
|
1296
|
+
mint: WRAPPED_SOL_MINT,
|
|
1297
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1298
|
+
},
|
|
1299
|
+
]);
|
|
1300
|
+
createAtasIxs.push(createWsolAtaIxn);
|
|
1301
|
+
const transferWsolIxs = getTransferWsolIxs(
|
|
1302
|
+
user,
|
|
1303
|
+
wsolAta,
|
|
1304
|
+
lamports(
|
|
1305
|
+
BigInt(numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).ceil().toString())
|
|
1306
|
+
)
|
|
1307
|
+
);
|
|
1308
|
+
createAtasIxs.push(...transferWsolIxs);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
const [{ ata: userSharesAta, createAtaIx: createSharesAtaIxs }] = await createAtasIdempotent(user, [
|
|
1312
|
+
{
|
|
1313
|
+
mint: vaultState.sharesMint,
|
|
1314
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1315
|
+
},
|
|
1316
|
+
]);
|
|
1317
|
+
createAtasIxs.push(createSharesAtaIxs);
|
|
1318
|
+
|
|
1319
|
+
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
1320
|
+
const buyAccounts: BuyAccounts = {
|
|
1321
|
+
user: user,
|
|
1322
|
+
vaultState: vault.address,
|
|
1323
|
+
tokenVault: vaultState.tokenVault,
|
|
1324
|
+
tokenMint: vaultState.tokenMint,
|
|
1325
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
1326
|
+
sharesMint: vaultState.sharesMint,
|
|
1327
|
+
userTokenAta: userTokenAta,
|
|
1328
|
+
userSharesAta: userSharesAta,
|
|
1329
|
+
tokenProgram: tokenProgramID,
|
|
1330
|
+
klendProgram: this._kaminoLendProgramId,
|
|
1331
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1332
|
+
eventAuthority: eventAuthority,
|
|
1333
|
+
program: this._kaminoVaultProgramId,
|
|
1334
|
+
};
|
|
1335
|
+
|
|
1336
|
+
const buyArgs: BuyArgs = {
|
|
1337
|
+
maxAmount: new BN(
|
|
1338
|
+
numberToLamportsDecimal(tokenAmount, vaultState.tokenMintDecimals.toNumber()).floor().toString()
|
|
1339
|
+
),
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
let buyIx = buy(buyArgs, buyAccounts, undefined, this._kaminoVaultProgramId);
|
|
1343
|
+
|
|
1344
|
+
const vaultReserves = this.getVaultReserves(vaultState);
|
|
1345
|
+
|
|
1346
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1347
|
+
buyIx = this.appendRemainingAccountsForVaultReserves(buyIx, vaultReserves, vaultReservesState);
|
|
1348
|
+
|
|
1349
|
+
const depositIxs: DepositIxs = {
|
|
1350
|
+
depositIxs: [...createAtasIxs, buyIx, ...closeAtasIxs],
|
|
1351
|
+
stakeInFarmIfNeededIxs: [],
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
// if there is no farm, we can return the deposit instructions, otherwise include the stake ix in the response
|
|
1355
|
+
if (!(await vault.hasFarm())) {
|
|
1356
|
+
return depositIxs;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// if there is a farm, stake the shares
|
|
1360
|
+
const stakeSharesIxs = await this.stakeSharesIxs(user, vault, undefined, farmState);
|
|
1361
|
+
depositIxs.stakeInFarmIfNeededIxs = stakeSharesIxs;
|
|
1362
|
+
return depositIxs;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1273
1365
|
/**
|
|
1274
1366
|
* This function creates instructions to stake the shares in the vault farm if the vault has a farm
|
|
1275
1367
|
* @param user - user to stake
|
|
@@ -1439,6 +1531,135 @@ export class KaminoVaultClient {
|
|
|
1439
1531
|
return withdrawIxs;
|
|
1440
1532
|
}
|
|
1441
1533
|
|
|
1534
|
+
async sellSharesIxs(
|
|
1535
|
+
user: TransactionSigner,
|
|
1536
|
+
vault: KaminoVault,
|
|
1537
|
+
shareAmountToWithdraw: Decimal,
|
|
1538
|
+
slot: Slot,
|
|
1539
|
+
vaultReservesMap?: Map<Address, KaminoReserve>,
|
|
1540
|
+
farmState?: FarmState
|
|
1541
|
+
): Promise<WithdrawIxs> {
|
|
1542
|
+
const vaultState = await vault.getState();
|
|
1543
|
+
const hasFarm = await vault.hasFarm();
|
|
1544
|
+
|
|
1545
|
+
const withdrawIxs: WithdrawIxs = {
|
|
1546
|
+
unstakeFromFarmIfNeededIxs: [],
|
|
1547
|
+
withdrawIxs: [],
|
|
1548
|
+
postWithdrawIxs: [],
|
|
1549
|
+
};
|
|
1550
|
+
|
|
1551
|
+
// compute the total shares the user has (in ATA + in farm) and check if they want to withdraw everything or just a part
|
|
1552
|
+
let userSharesAtaBalance = new Decimal(0);
|
|
1553
|
+
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1554
|
+
const userSharesAtaState = await fetchMaybeToken(this.getConnection(), userSharesAta);
|
|
1555
|
+
if (userSharesAtaState.exists) {
|
|
1556
|
+
const userSharesAtaBalanceInLamports = getTokenBalanceFromAccountInfoLamports(userSharesAtaState);
|
|
1557
|
+
userSharesAtaBalance = userSharesAtaBalanceInLamports.div(
|
|
1558
|
+
new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
let userSharesInFarm = new Decimal(0);
|
|
1563
|
+
if (hasFarm) {
|
|
1564
|
+
userSharesInFarm = await getUserSharesInTokensStakedInFarm(
|
|
1565
|
+
this.getConnection(),
|
|
1566
|
+
user.address,
|
|
1567
|
+
vaultState.vaultFarm,
|
|
1568
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1569
|
+
);
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
let sharesToWithdraw = shareAmountToWithdraw;
|
|
1573
|
+
const totalUserShares = userSharesAtaBalance.add(userSharesInFarm);
|
|
1574
|
+
let withdrawAllShares = false;
|
|
1575
|
+
if (sharesToWithdraw.gt(totalUserShares)) {
|
|
1576
|
+
sharesToWithdraw = new Decimal(U64_MAX.toString()).div(
|
|
1577
|
+
new Decimal(10).pow(vaultState.sharesMintDecimals.toString())
|
|
1578
|
+
);
|
|
1579
|
+
withdrawAllShares = true;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// if not enough shares in ATA unstake from farm
|
|
1583
|
+
const sharesInAtaAreEnoughForWithdraw = sharesToWithdraw.lte(userSharesAtaBalance);
|
|
1584
|
+
if (hasFarm && !sharesInAtaAreEnoughForWithdraw && userSharesInFarm.gt(0)) {
|
|
1585
|
+
// if we need to unstake we need to make sure share ata is created
|
|
1586
|
+
const [{ createAtaIx }] = await createAtasIdempotent(user, [
|
|
1587
|
+
{
|
|
1588
|
+
mint: vaultState.sharesMint,
|
|
1589
|
+
tokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
1590
|
+
},
|
|
1591
|
+
]);
|
|
1592
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(createAtaIx);
|
|
1593
|
+
let shareLamportsToWithdraw = new Decimal(U64_MAX.toString());
|
|
1594
|
+
if (!withdrawAllShares) {
|
|
1595
|
+
const sharesToWithdrawFromFarm = sharesToWithdraw.sub(userSharesAtaBalance);
|
|
1596
|
+
shareLamportsToWithdraw = collToLamportsDecimal(
|
|
1597
|
+
sharesToWithdrawFromFarm,
|
|
1598
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1599
|
+
);
|
|
1600
|
+
}
|
|
1601
|
+
const unstakeAndWithdrawFromFarmIxs = await getFarmUnstakeAndWithdrawIxs(
|
|
1602
|
+
this.getConnection(),
|
|
1603
|
+
user,
|
|
1604
|
+
shareLamportsToWithdraw,
|
|
1605
|
+
vaultState.vaultFarm,
|
|
1606
|
+
farmState
|
|
1607
|
+
);
|
|
1608
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.unstakeIx);
|
|
1609
|
+
withdrawIxs.unstakeFromFarmIfNeededIxs.push(unstakeAndWithdrawFromFarmIxs.withdrawIx);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
// if the vault has allocations withdraw otherwise wtihdraw from available ix
|
|
1613
|
+
const vaultAllocation = vaultState.vaultAllocationStrategy.find(
|
|
1614
|
+
(allocation) => allocation.reserve !== DEFAULT_PUBLIC_KEY
|
|
1615
|
+
);
|
|
1616
|
+
|
|
1617
|
+
if (vaultAllocation) {
|
|
1618
|
+
const withdrawFromVaultIxs = await this.sellSharesWithReserveIxs(
|
|
1619
|
+
user,
|
|
1620
|
+
vault,
|
|
1621
|
+
sharesToWithdraw,
|
|
1622
|
+
totalUserShares,
|
|
1623
|
+
slot,
|
|
1624
|
+
vaultReservesMap
|
|
1625
|
+
);
|
|
1626
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1627
|
+
} else {
|
|
1628
|
+
const withdrawFromVaultIxs = await this.withdrawFromAvailableIxs(user, vault, sharesToWithdraw);
|
|
1629
|
+
withdrawIxs.withdrawIxs = withdrawFromVaultIxs;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
// if the vault is for SOL return the ix to unwrap the SOL
|
|
1633
|
+
if (vaultState.tokenMint === WRAPPED_SOL_MINT) {
|
|
1634
|
+
const userWsolAta = await getAssociatedTokenAddress(WRAPPED_SOL_MINT, user.address);
|
|
1635
|
+
const unwrapIx = getCloseAccountInstruction(
|
|
1636
|
+
{
|
|
1637
|
+
account: userWsolAta,
|
|
1638
|
+
owner: user,
|
|
1639
|
+
destination: user.address,
|
|
1640
|
+
},
|
|
1641
|
+
{ programAddress: TOKEN_PROGRAM_ADDRESS }
|
|
1642
|
+
);
|
|
1643
|
+
withdrawIxs.postWithdrawIxs.push(unwrapIx);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// if we burn all of user's shares close its shares ATA
|
|
1647
|
+
const burnAllUserShares = sharesToWithdraw.gt(totalUserShares);
|
|
1648
|
+
if (burnAllUserShares) {
|
|
1649
|
+
const closeAtaIx = getCloseAccountInstruction(
|
|
1650
|
+
{
|
|
1651
|
+
account: userSharesAta,
|
|
1652
|
+
owner: user,
|
|
1653
|
+
destination: user.address,
|
|
1654
|
+
},
|
|
1655
|
+
{ programAddress: TOKEN_PROGRAM_ADDRESS }
|
|
1656
|
+
);
|
|
1657
|
+
withdrawIxs.postWithdrawIxs.push(closeAtaIx);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
return withdrawIxs;
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1442
1663
|
private async withdrawFromAvailableIxs(
|
|
1443
1664
|
user: TransactionSigner,
|
|
1444
1665
|
vault: KaminoVault,
|
|
@@ -1467,6 +1688,115 @@ export class KaminoVaultClient {
|
|
|
1467
1688
|
return [createAtaIx, withdrawFromAvailableIxn];
|
|
1468
1689
|
}
|
|
1469
1690
|
|
|
1691
|
+
private async sellSharesWithReserveIxs(
|
|
1692
|
+
user: TransactionSigner,
|
|
1693
|
+
vault: KaminoVault,
|
|
1694
|
+
shareAmount: Decimal,
|
|
1695
|
+
allUserShares: Decimal,
|
|
1696
|
+
slot: Slot,
|
|
1697
|
+
vaultReservesMap?: Map<Address, KaminoReserve>
|
|
1698
|
+
): Promise<Instruction[]> {
|
|
1699
|
+
const vaultState = await vault.getState();
|
|
1700
|
+
|
|
1701
|
+
const vaultReservesState = vaultReservesMap ? vaultReservesMap : await this.loadVaultReserves(vaultState);
|
|
1702
|
+
const userSharesAta = await getAssociatedTokenAddress(vaultState.sharesMint, user.address);
|
|
1703
|
+
const [{ ata: userTokenAta, createAtaIx }] = await createAtasIdempotent(user, [
|
|
1704
|
+
{
|
|
1705
|
+
mint: vaultState.tokenMint,
|
|
1706
|
+
tokenProgram: vaultState.tokenProgram,
|
|
1707
|
+
},
|
|
1708
|
+
]);
|
|
1709
|
+
|
|
1710
|
+
const withdrawAllShares = shareAmount.gte(allUserShares);
|
|
1711
|
+
const actualSharesToWithdraw = shareAmount.lte(allUserShares) ? shareAmount : allUserShares;
|
|
1712
|
+
const shareLamportsToWithdraw = collToLamportsDecimal(
|
|
1713
|
+
actualSharesToWithdraw,
|
|
1714
|
+
vaultState.sharesMintDecimals.toNumber()
|
|
1715
|
+
);
|
|
1716
|
+
const tokensPerShare = await this.getTokensPerShareSingleVault(vault, slot);
|
|
1717
|
+
const sharesPerToken = new Decimal(1).div(tokensPerShare);
|
|
1718
|
+
const tokensToWithdraw = shareLamportsToWithdraw.mul(tokensPerShare);
|
|
1719
|
+
let tokenLeftToWithdraw = tokensToWithdraw;
|
|
1720
|
+
const availableTokens = new Decimal(vaultState.tokenAvailable.toString());
|
|
1721
|
+
tokenLeftToWithdraw = tokenLeftToWithdraw.sub(availableTokens);
|
|
1722
|
+
|
|
1723
|
+
type ReserveWithTokensToWithdraw = { reserve: Address; shares: Decimal };
|
|
1724
|
+
|
|
1725
|
+
const reserveWithSharesAmountToWithdraw: ReserveWithTokensToWithdraw[] = [];
|
|
1726
|
+
let isFirstWithdraw = true;
|
|
1727
|
+
|
|
1728
|
+
if (tokenLeftToWithdraw.lte(0)) {
|
|
1729
|
+
// Availabe enough to withdraw all - using the first existent reserve
|
|
1730
|
+
const firstReserve = vaultState.vaultAllocationStrategy.find((reserve) => reserve.reserve !== DEFAULT_PUBLIC_KEY);
|
|
1731
|
+
if (withdrawAllShares) {
|
|
1732
|
+
reserveWithSharesAmountToWithdraw.push({
|
|
1733
|
+
reserve: firstReserve!.reserve,
|
|
1734
|
+
shares: new Decimal(U64_MAX.toString()),
|
|
1735
|
+
});
|
|
1736
|
+
} else {
|
|
1737
|
+
reserveWithSharesAmountToWithdraw.push({
|
|
1738
|
+
reserve: firstReserve!.reserve,
|
|
1739
|
+
shares: shareLamportsToWithdraw,
|
|
1740
|
+
});
|
|
1741
|
+
}
|
|
1742
|
+
} else {
|
|
1743
|
+
// Get decreasing order sorted available liquidity to withdraw from each reserve allocated to
|
|
1744
|
+
const reserveAllocationAvailableLiquidityToWithdraw = await this.getReserveAllocationAvailableLiquidityToWithdraw(
|
|
1745
|
+
vault,
|
|
1746
|
+
slot,
|
|
1747
|
+
vaultReservesState
|
|
1748
|
+
);
|
|
1749
|
+
// sort
|
|
1750
|
+
const reserveAllocationAvailableLiquidityToWithdrawSorted = [
|
|
1751
|
+
...reserveAllocationAvailableLiquidityToWithdraw.entries(),
|
|
1752
|
+
].sort((a, b) => b[1].sub(a[1]).toNumber());
|
|
1753
|
+
|
|
1754
|
+
reserveAllocationAvailableLiquidityToWithdrawSorted.forEach(([key, availableLiquidityToWithdraw], _) => {
|
|
1755
|
+
if (tokenLeftToWithdraw.gt(0)) {
|
|
1756
|
+
let tokensToWithdrawFromReserve = Decimal.min(tokenLeftToWithdraw, availableLiquidityToWithdraw);
|
|
1757
|
+
if (isFirstWithdraw) {
|
|
1758
|
+
tokensToWithdrawFromReserve = tokensToWithdrawFromReserve.add(availableTokens);
|
|
1759
|
+
isFirstWithdraw = false;
|
|
1760
|
+
}
|
|
1761
|
+
if (withdrawAllShares) {
|
|
1762
|
+
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: new Decimal(U64_MAX.toString()) });
|
|
1763
|
+
} else {
|
|
1764
|
+
// round up to the nearest integer the shares to withdraw
|
|
1765
|
+
const sharesToWithdrawFromReserve = tokensToWithdrawFromReserve.mul(sharesPerToken).floor();
|
|
1766
|
+
reserveWithSharesAmountToWithdraw.push({ reserve: key, shares: sharesToWithdrawFromReserve });
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
tokenLeftToWithdraw = tokenLeftToWithdraw.sub(tokensToWithdrawFromReserve);
|
|
1770
|
+
}
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
const withdrawIxs: Instruction[] = [];
|
|
1775
|
+
withdrawIxs.push(createAtaIx);
|
|
1776
|
+
for (let reserveIndex = 0; reserveIndex < reserveWithSharesAmountToWithdraw.length; reserveIndex++) {
|
|
1777
|
+
const reserveWithTokens = reserveWithSharesAmountToWithdraw[reserveIndex];
|
|
1778
|
+
const reserveState = vaultReservesState.get(reserveWithTokens.reserve);
|
|
1779
|
+
if (reserveState === undefined) {
|
|
1780
|
+
throw new Error(`Reserve ${reserveWithTokens.reserve} not found in vault reserves map`);
|
|
1781
|
+
}
|
|
1782
|
+
const marketAddress = reserveState.state.lendingMarket;
|
|
1783
|
+
|
|
1784
|
+
const withdrawFromReserveIx = await this.sellIx(
|
|
1785
|
+
user,
|
|
1786
|
+
vault,
|
|
1787
|
+
vaultState,
|
|
1788
|
+
marketAddress,
|
|
1789
|
+
{ address: reserveWithTokens.reserve, state: reserveState.state },
|
|
1790
|
+
userSharesAta,
|
|
1791
|
+
userTokenAta,
|
|
1792
|
+
reserveWithTokens.shares,
|
|
1793
|
+
vaultReservesState
|
|
1794
|
+
);
|
|
1795
|
+
withdrawIxs.push(withdrawFromReserveIx);
|
|
1796
|
+
}
|
|
1797
|
+
|
|
1798
|
+
return withdrawIxs;
|
|
1799
|
+
}
|
|
1470
1800
|
private async withdrawWithReserveIxs(
|
|
1471
1801
|
user: TransactionSigner,
|
|
1472
1802
|
vault: KaminoVault,
|
|
@@ -1788,6 +2118,65 @@ export class KaminoVaultClient {
|
|
|
1788
2118
|
}
|
|
1789
2119
|
}
|
|
1790
2120
|
|
|
2121
|
+
private async sellIx(
|
|
2122
|
+
user: TransactionSigner,
|
|
2123
|
+
vault: KaminoVault,
|
|
2124
|
+
vaultState: VaultState,
|
|
2125
|
+
marketAddress: Address,
|
|
2126
|
+
reserve: ReserveWithAddress,
|
|
2127
|
+
userSharesAta: Address,
|
|
2128
|
+
userTokenAta: Address,
|
|
2129
|
+
shareAmountLamports: Decimal,
|
|
2130
|
+
vaultReservesState: Map<Address, KaminoReserve>
|
|
2131
|
+
): Promise<Instruction> {
|
|
2132
|
+
const [lendingMarketAuth] = await lendingMarketAuthPda(marketAddress, this._kaminoLendProgramId);
|
|
2133
|
+
|
|
2134
|
+
const globalConfig = await getKvaultGlobalConfigPda(this._kaminoVaultProgramId);
|
|
2135
|
+
const eventAuthority = await getEventAuthorityPda(this._kaminoVaultProgramId);
|
|
2136
|
+
const sellAccounts: SellAccounts = {
|
|
2137
|
+
withdrawFromAvailable: {
|
|
2138
|
+
user,
|
|
2139
|
+
vaultState: vault.address,
|
|
2140
|
+
globalConfig: globalConfig,
|
|
2141
|
+
tokenVault: vaultState.tokenVault,
|
|
2142
|
+
baseVaultAuthority: vaultState.baseVaultAuthority,
|
|
2143
|
+
userTokenAta: userTokenAta,
|
|
2144
|
+
tokenMint: vaultState.tokenMint,
|
|
2145
|
+
userSharesAta: userSharesAta,
|
|
2146
|
+
sharesMint: vaultState.sharesMint,
|
|
2147
|
+
tokenProgram: vaultState.tokenProgram,
|
|
2148
|
+
sharesTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
2149
|
+
klendProgram: this._kaminoLendProgramId,
|
|
2150
|
+
eventAuthority: eventAuthority,
|
|
2151
|
+
program: this._kaminoVaultProgramId,
|
|
2152
|
+
},
|
|
2153
|
+
withdrawFromReserveAccounts: {
|
|
2154
|
+
vaultState: vault.address,
|
|
2155
|
+
reserve: reserve.address,
|
|
2156
|
+
ctokenVault: await getCTokenVaultPda(vault.address, reserve.address, this._kaminoVaultProgramId),
|
|
2157
|
+
lendingMarket: marketAddress,
|
|
2158
|
+
lendingMarketAuthority: lendingMarketAuth,
|
|
2159
|
+
reserveLiquiditySupply: reserve.state.liquidity.supplyVault,
|
|
2160
|
+
reserveCollateralMint: reserve.state.collateral.mintPubkey,
|
|
2161
|
+
reserveCollateralTokenProgram: TOKEN_PROGRAM_ADDRESS,
|
|
2162
|
+
instructionSysvarAccount: SYSVAR_INSTRUCTIONS_ADDRESS,
|
|
2163
|
+
},
|
|
2164
|
+
eventAuthority: eventAuthority,
|
|
2165
|
+
program: this._kaminoVaultProgramId,
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2168
|
+
const sellArgs: SellArgs = {
|
|
2169
|
+
sharesAmount: new BN(shareAmountLamports.floor().toString()),
|
|
2170
|
+
};
|
|
2171
|
+
|
|
2172
|
+
let sellIxn = sell(sellArgs, sellAccounts, undefined, this._kaminoVaultProgramId);
|
|
2173
|
+
|
|
2174
|
+
const vaultReserves = this.getVaultReserves(vaultState);
|
|
2175
|
+
sellIxn = this.appendRemainingAccountsForVaultReserves(sellIxn, vaultReserves, vaultReservesState);
|
|
2176
|
+
|
|
2177
|
+
return sellIxn;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
1791
2180
|
private async withdrawIx(
|
|
1792
2181
|
user: TransactionSigner,
|
|
1793
2182
|
vault: KaminoVault,
|