@glamsystems/glam-sdk 0.1.19 → 0.1.20
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/README.md +3 -37
- package/index.cjs.js +241 -76
- package/index.esm.js +241 -77
- package/package.json +2 -2
- package/src/client/drift.d.ts +1 -0
- package/src/client/kamino.d.ts +36 -12
- package/src/client/price.d.ts +4 -6
- package/src/client.d.ts +3 -1
- package/src/constants.d.ts +4 -0
- package/src/utils/priorityfee.d.ts +1 -1
- package/target/idl/glam_protocol.json +1 -0
- package/target/types/glam_protocol.d.ts +1 -0
- package/target/types/glam_protocol.ts +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# GLAM SDK
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
|
|
3
5
|
A TypeScript SDK for interacting with the GLAM Protocol.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
@@ -11,43 +13,7 @@ npm i @glamsystems/glam-sdk
|
|
|
11
13
|
## Getting Started
|
|
12
14
|
|
|
13
15
|
- [GLAM docs](https://docs.glam.systems)
|
|
14
|
-
- [TypeScript API docs](#)
|
|
15
16
|
|
|
16
17
|
## Examples
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import * as anchor from "@coral-xyz/anchor";
|
|
22
|
-
import { GlamClient, WSOL } from "@glamsystems/glam-sdk";
|
|
23
|
-
import { PublicKey } from "@solana/web3.js";
|
|
24
|
-
|
|
25
|
-
// Need to set ANCHOR_PROVIDER_URL and ANCHOR_WALLET env variables
|
|
26
|
-
// ANCHOR_PROVIDER_URL=...
|
|
27
|
-
// ANCHOR_WALLET=...
|
|
28
|
-
const glamClient = new GlamClient();
|
|
29
|
-
const statePda = new PublicKey("FMHLPaEeCbuivqsAfHrr28FpWJ9oKHTx3jzFbb3tYhq4");
|
|
30
|
-
|
|
31
|
-
async function main() {
|
|
32
|
-
const vaultPda = glamClient.getVaultPda(statePda);
|
|
33
|
-
|
|
34
|
-
console.log("statePda:", statePda.toBase58());
|
|
35
|
-
console.log("vaultPda:", vaultPda.toBase58());
|
|
36
|
-
|
|
37
|
-
const vaultWsolBalance = await glamClient.getVaultTokenBalance(statePda, WSOL);
|
|
38
|
-
console.log("vaultWsolBalance:", vaultWsolBalance.toString());
|
|
39
|
-
|
|
40
|
-
// Wrap 0.1 SOL
|
|
41
|
-
const txSig = await glamClient.wsol.wrap(statePda, new anchor.BN(100_000_000));
|
|
42
|
-
console.log("txSig:", txSig);
|
|
43
|
-
|
|
44
|
-
// wSOL balance after wrap should increase by 0.1 SOL
|
|
45
|
-
const vaultWsolBalanceAfter = await glamClient.getVaultTokenBalance(statePda, WSOL);
|
|
46
|
-
console.log("vaultWsolBalanceAfter:", vaultWsolBalanceAfter.toString());
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
main().catch((error) => {
|
|
50
|
-
console.error("Error:", error);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
});
|
|
53
|
-
```
|
|
19
|
+
See [examples](./examples).
|
package/index.cjs.js
CHANGED
|
@@ -3251,6 +3251,7 @@ var instructions = [
|
|
|
3251
3251
|
},
|
|
3252
3252
|
{
|
|
3253
3253
|
name: "glam_vault",
|
|
3254
|
+
writable: true,
|
|
3254
3255
|
pda: {
|
|
3255
3256
|
seeds: [
|
|
3256
3257
|
{
|
|
@@ -12448,9 +12449,12 @@ const MEMO_PROGRAM = new web3_js.PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgD
|
|
|
12448
12449
|
* Stake pools
|
|
12449
12450
|
*/ const JITO_STAKE_POOL = new web3_js.PublicKey("Jito4APyf642JPZPx3hGc6WWJ8zPKtRbRs4P815Awbb");
|
|
12450
12451
|
const JUPSOL_STAKE_POOL = new web3_js.PublicKey("8VpRhuxa7sUUepdY3kQiTmX9rS5vx4WgaXiAnXq4KCtr");
|
|
12452
|
+
/**
|
|
12453
|
+
* Referrers
|
|
12454
|
+
*/ const GLAM_REFERRER = new web3_js.PublicKey("GLAMrG37ZqioqvzBNQGCfCUueDz3tsr7MwMFyRk9PS89");
|
|
12451
12455
|
|
|
12452
12456
|
const GlamIntegrations = GlamProtocolIdlJson?.types?.find((t)=>t.name === "Integration")?.type?.variants?.map((v)=>v.name) ?? [];
|
|
12453
|
-
const GlamPermissions = GlamProtocolIdlJson?.types?.find((t)=>t.name === "Permission")?.type?.variants?.map((v)=>v.name) ?? [];
|
|
12457
|
+
const GlamPermissions = GlamProtocolIdlJson?.types?.find((t)=>t.name === "Permission")?.type?.variants?.map((v)=>v.name).filter((v)=>!v.startsWith("__")) ?? [];
|
|
12454
12458
|
const GLAM_PROGRAM_ID_DEFAULT = new web3_js.PublicKey(GlamProtocolIdlJson.address);
|
|
12455
12459
|
class StateIdlModel {
|
|
12456
12460
|
constructor(data){
|
|
@@ -13660,6 +13664,12 @@ class DriftClient {
|
|
|
13660
13664
|
sdk.getUserStatsAccountPublicKey(DRIFT_PROGRAM_ID, vault)
|
|
13661
13665
|
];
|
|
13662
13666
|
}
|
|
13667
|
+
getGlamReferrer() {
|
|
13668
|
+
return [
|
|
13669
|
+
sdk.getUserAccountPublicKeySync(DRIFT_PROGRAM_ID, GLAM_REFERRER, 0),
|
|
13670
|
+
sdk.getUserStatsAccountPublicKey(DRIFT_PROGRAM_ID, GLAM_REFERRER)
|
|
13671
|
+
];
|
|
13672
|
+
}
|
|
13663
13673
|
async fetchMarketConfigs() {
|
|
13664
13674
|
const response = await fetch("https://api.glam.systems/v0/drift/market_configs/");
|
|
13665
13675
|
if (!response.ok) {
|
|
@@ -13753,15 +13763,18 @@ class DriftClient {
|
|
|
13753
13763
|
const name = `GLAM *.+ ${subAccountId}`.split("").map((char)=>char.charCodeAt(0)).concat(Array(24).fill(0));
|
|
13754
13764
|
const [user, userStats] = this.getUser(glamState, subAccountId);
|
|
13755
13765
|
const state = await sdk.getDriftStateAccountPublicKey(DRIFT_PROGRAM_ID);
|
|
13766
|
+
const remainingAccounts = this.getGlamReferrer().map((p)=>({
|
|
13767
|
+
pubkey: p,
|
|
13768
|
+
isWritable: true,
|
|
13769
|
+
isSigner: false
|
|
13770
|
+
}));
|
|
13756
13771
|
return await this.base.program.methods.driftInitializeUser(subAccountId, name).accounts({
|
|
13757
13772
|
glamState,
|
|
13758
13773
|
user,
|
|
13759
13774
|
userStats,
|
|
13760
13775
|
state,
|
|
13761
13776
|
glamSigner
|
|
13762
|
-
})
|
|
13763
|
-
// .remainingAccounts([]) TODO: set glam referral account
|
|
13764
|
-
.instruction();
|
|
13777
|
+
}).remainingAccounts(remainingAccounts).instruction();
|
|
13765
13778
|
}
|
|
13766
13779
|
async initializeTx(glamState, subAccountId = 0, txOptions = {}) {
|
|
13767
13780
|
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
@@ -13911,7 +13924,11 @@ class DriftClient {
|
|
|
13911
13924
|
}
|
|
13912
13925
|
async placeOrderTx(glamState, orderParams, subAccountId = 0, marketConfigs, txOptions = {}) {
|
|
13913
13926
|
const { marketIndex, marketType } = orderParams;
|
|
13914
|
-
const remainingAccounts = await this.composeRemainingAccounts(glamState, subAccountId, marketConfigs, marketType, marketIndex)
|
|
13927
|
+
const remainingAccounts = (await this.composeRemainingAccounts(glamState, subAccountId, marketConfigs, marketType, marketIndex)).concat(this.getGlamReferrer().map((p)=>({
|
|
13928
|
+
pubkey: p,
|
|
13929
|
+
isWritable: true,
|
|
13930
|
+
isSigner: false
|
|
13931
|
+
})));
|
|
13915
13932
|
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
13916
13933
|
const [user] = this.getUser(glamState, subAccountId);
|
|
13917
13934
|
const state = await sdk.getDriftStateAccountPublicKey(DRIFT_PROGRAM_ID);
|
|
@@ -15674,7 +15691,7 @@ const DEFAULT_OBLIGATION_ARGS = {
|
|
|
15674
15691
|
id: 0
|
|
15675
15692
|
};
|
|
15676
15693
|
const SCOPE_PRICES = new web3_js.PublicKey("3NJYftD5sjVfxSnUdZ1wVML8f3aC6mp1CXCL6L7TnU8C");
|
|
15677
|
-
function refreshObligation(accounts, programId) {
|
|
15694
|
+
function refreshObligation(accounts, programId = KAMINO_LENDING_PROGRAM) {
|
|
15678
15695
|
const keys = [
|
|
15679
15696
|
{
|
|
15680
15697
|
pubkey: accounts.lendingMarket,
|
|
@@ -15712,7 +15729,7 @@ function refreshObligation(accounts, programId) {
|
|
|
15712
15729
|
});
|
|
15713
15730
|
return ix;
|
|
15714
15731
|
}
|
|
15715
|
-
function refreshReserve(accounts, programId) {
|
|
15732
|
+
function refreshReserve(accounts, programId = KAMINO_LENDING_PROGRAM) {
|
|
15716
15733
|
const keys = [
|
|
15717
15734
|
{
|
|
15718
15735
|
pubkey: accounts.reserve,
|
|
@@ -15763,7 +15780,7 @@ function refreshReserve(accounts, programId) {
|
|
|
15763
15780
|
});
|
|
15764
15781
|
return ix;
|
|
15765
15782
|
}
|
|
15766
|
-
function refreshObligationFarmsForReserve(args, accounts, programId) {
|
|
15783
|
+
function refreshObligationFarmsForReserve(args, accounts, programId = KAMINO_LENDING_PROGRAM) {
|
|
15767
15784
|
const keys = [
|
|
15768
15785
|
{
|
|
15769
15786
|
pubkey: accounts.crank,
|
|
@@ -15854,7 +15871,7 @@ class KaminoLendingClient {
|
|
|
15854
15871
|
* @param txOptions
|
|
15855
15872
|
* @returns
|
|
15856
15873
|
*/ async initUserMetadata(statePda, referrer, txOptions = {}) {
|
|
15857
|
-
const tx = await this.initUserMetadataTx(new web3_js.PublicKey(statePda), referrer ? new web3_js.PublicKey(referrer) :
|
|
15874
|
+
const tx = await this.initUserMetadataTx(new web3_js.PublicKey(statePda), referrer ? new web3_js.PublicKey(referrer) : null, txOptions);
|
|
15858
15875
|
return await this.base.sendAndConfirm(tx);
|
|
15859
15876
|
}
|
|
15860
15877
|
/**
|
|
@@ -15940,18 +15957,17 @@ class KaminoLendingClient {
|
|
|
15940
15957
|
], KAMINO_FARM_PROGRAM);
|
|
15941
15958
|
return obligationFarm;
|
|
15942
15959
|
}
|
|
15943
|
-
async initUserMetadataTx(glamState, referrer, txOptions) {
|
|
15960
|
+
async initUserMetadataTx(glamState, referrer, txOptions = {}) {
|
|
15944
15961
|
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
15945
15962
|
const vault = this.base.getVaultPda(glamState);
|
|
15946
15963
|
const userMetadata = this.getUserMetadataPda(vault);
|
|
15947
15964
|
const lookupTable = new web3_js.PublicKey(0); // FIXME: create lookup table
|
|
15948
|
-
const referrerUserMetadata = referrer.equals(web3_js.PublicKey.default) ? KAMINO_LENDING_PROGRAM : referrer;
|
|
15949
15965
|
// @ts-ignore
|
|
15950
15966
|
const tx = await this.base.program.methods.kaminoLendingInitUserMetadata(lookupTable).accounts({
|
|
15951
15967
|
glamState,
|
|
15952
15968
|
glamSigner,
|
|
15953
15969
|
userMetadata,
|
|
15954
|
-
referrerUserMetadata
|
|
15970
|
+
referrerUserMetadata: referrer
|
|
15955
15971
|
}).transaction();
|
|
15956
15972
|
const vTx = await this.base.intoVersionedTransaction(tx, txOptions);
|
|
15957
15973
|
return vTx;
|
|
@@ -15964,7 +15980,7 @@ class KaminoLendingClient {
|
|
|
15964
15980
|
switchboardPriceOracle: KAMINO_LENDING_PROGRAM,
|
|
15965
15981
|
switchboardTwapOracle: KAMINO_LENDING_PROGRAM,
|
|
15966
15982
|
scopePrices: SCOPE_PRICES
|
|
15967
|
-
}
|
|
15983
|
+
}));
|
|
15968
15984
|
}
|
|
15969
15985
|
refreshObligationFarmsForReserveIxs(obligation, lendingMarket, parsedReserves) {
|
|
15970
15986
|
return parsedReserves.map((parsedReserve)=>{
|
|
@@ -15989,18 +16005,21 @@ class KaminoLendingClient {
|
|
|
15989
16005
|
farmsProgram: KAMINO_FARM_PROGRAM,
|
|
15990
16006
|
rent: web3_js.SYSVAR_RENT_PUBKEY,
|
|
15991
16007
|
systemProgram: web3_js.SystemProgram.programId
|
|
15992
|
-
}
|
|
16008
|
+
});
|
|
15993
16009
|
});
|
|
15994
16010
|
}).flat();
|
|
15995
16011
|
}
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
const { deposits, borrows } = await this.fetchAndParseObligation(obligation);
|
|
16012
|
+
// If obligation has deposits or borrows, we need the following refresh ixs:
|
|
16013
|
+
// - refreshReserve x N_reserves
|
|
16014
|
+
// - refreshObligation
|
|
16015
|
+
// - refreshObligationFarmsForReserve x M_farms
|
|
16016
|
+
//
|
|
16017
|
+
// For pricing purpose, we don't need to refresh farm states
|
|
16018
|
+
async getRefreshIxs(obligation, refreshFarms = true) {
|
|
16019
|
+
const { lendingMarket, deposits, borrows } = await this.fetchAndParseObligation(obligation);
|
|
16020
|
+
if (!lendingMarket) {
|
|
16021
|
+
throw new Error("Lending market not found");
|
|
16022
|
+
}
|
|
16004
16023
|
const reserves = deposits.concat(borrows).map((d)=>d.reserve);
|
|
16005
16024
|
const parsedReserves = await this.fetchAndParseReserves(reserves);
|
|
16006
16025
|
return [
|
|
@@ -16009,8 +16028,8 @@ class KaminoLendingClient {
|
|
|
16009
16028
|
lendingMarket,
|
|
16010
16029
|
obligation,
|
|
16011
16030
|
reserves
|
|
16012
|
-
}
|
|
16013
|
-
...this.refreshObligationFarmsForReserveIxs(obligation, lendingMarket, parsedReserves)
|
|
16031
|
+
}),
|
|
16032
|
+
...refreshFarms ? this.refreshObligationFarmsForReserveIxs(obligation, lendingMarket, parsedReserves) : []
|
|
16014
16033
|
];
|
|
16015
16034
|
}
|
|
16016
16035
|
getMarketAuthority(market) {
|
|
@@ -16061,11 +16080,14 @@ class KaminoLendingClient {
|
|
|
16061
16080
|
const obligationAccount = await this.base.provider.connection.getAccountInfo(obligation);
|
|
16062
16081
|
if (!obligationAccount) {
|
|
16063
16082
|
return {
|
|
16083
|
+
address: obligation,
|
|
16084
|
+
lendingMarket: null,
|
|
16064
16085
|
deposits: [],
|
|
16065
16086
|
borrows: []
|
|
16066
16087
|
};
|
|
16067
16088
|
}
|
|
16068
16089
|
const data = obligationAccount.data;
|
|
16090
|
+
const lendingMarket = new web3_js.PublicKey(data.subarray(32, 64));
|
|
16069
16091
|
// read deposits
|
|
16070
16092
|
let depositsOffset = 96;
|
|
16071
16093
|
let depositSize = 136;
|
|
@@ -16075,8 +16097,9 @@ class KaminoLendingClient {
|
|
|
16075
16097
|
length: numDeposits
|
|
16076
16098
|
}, (_, i)=>{
|
|
16077
16099
|
const depositData = depositsData.subarray(i * depositSize, (i + 1) * depositSize);
|
|
16100
|
+
const reserve = new web3_js.PublicKey(depositData.subarray(0, 32));
|
|
16078
16101
|
return {
|
|
16079
|
-
reserve
|
|
16102
|
+
reserve
|
|
16080
16103
|
};
|
|
16081
16104
|
}).filter((d)=>!d.reserve.equals(web3_js.PublicKey.default));
|
|
16082
16105
|
// read borrows
|
|
@@ -16088,24 +16111,33 @@ class KaminoLendingClient {
|
|
|
16088
16111
|
length: numBorrows
|
|
16089
16112
|
}, (_, i)=>{
|
|
16090
16113
|
const borrowData = borrowsData.subarray(i * borrowSize, (i + 1) * borrowSize);
|
|
16114
|
+
const reserve = new web3_js.PublicKey(borrowData.subarray(0, 32));
|
|
16091
16115
|
return {
|
|
16092
|
-
reserve
|
|
16116
|
+
reserve
|
|
16093
16117
|
};
|
|
16094
16118
|
}).filter((d)=>!d.reserve.equals(web3_js.PublicKey.default));
|
|
16095
16119
|
const parsedObligation = {
|
|
16120
|
+
address: obligation,
|
|
16121
|
+
lendingMarket,
|
|
16096
16122
|
deposits,
|
|
16097
16123
|
borrows
|
|
16098
16124
|
};
|
|
16099
16125
|
this.obligations.set(obligation, parsedObligation);
|
|
16100
16126
|
return parsedObligation;
|
|
16101
16127
|
}
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16108
|
-
|
|
16128
|
+
_parseReserveAccount(data) {
|
|
16129
|
+
const market = new web3_js.PublicKey(data.subarray(32, 64));
|
|
16130
|
+
const farmCollateral = new web3_js.PublicKey(data.subarray(64, 96));
|
|
16131
|
+
const farmDebt = new web3_js.PublicKey(data.subarray(96, 128));
|
|
16132
|
+
const liquidityMint = new web3_js.PublicKey(data.subarray(128, 160));
|
|
16133
|
+
return {
|
|
16134
|
+
farmCollateral: farmCollateral.equals(web3_js.PublicKey.default) ? null : farmCollateral,
|
|
16135
|
+
farmDebt: farmDebt.equals(web3_js.PublicKey.default) ? null : farmDebt,
|
|
16136
|
+
liquidityMint,
|
|
16137
|
+
...this.reservePdas(market, liquidityMint)
|
|
16138
|
+
};
|
|
16139
|
+
}
|
|
16140
|
+
async fetchAndParseReserves(reserves) {
|
|
16109
16141
|
if (this.pubkeyArraysEqual(reserves, Array.from(this.reserves.keys()))) {
|
|
16110
16142
|
return Array.from(this.reserves.values());
|
|
16111
16143
|
}
|
|
@@ -16114,20 +16146,12 @@ class KaminoLendingClient {
|
|
|
16114
16146
|
throw new Error("Not all reserves can be found");
|
|
16115
16147
|
}
|
|
16116
16148
|
return reserveAccounts.filter((a)=>!!a).map((account, i)=>{
|
|
16117
|
-
const
|
|
16118
|
-
const market = new web3_js.PublicKey(data.subarray(32, 64));
|
|
16119
|
-
const farmCollateral = new web3_js.PublicKey(data.subarray(64, 96));
|
|
16120
|
-
const farmDebt = new web3_js.PublicKey(data.subarray(96, 128));
|
|
16121
|
-
const liquidityMint = new web3_js.PublicKey(data.subarray(128, 160));
|
|
16122
|
-
const parsed = {
|
|
16149
|
+
const parsedReserve = {
|
|
16123
16150
|
address: reserves[i],
|
|
16124
|
-
|
|
16125
|
-
farmDebt: farmDebt.equals(web3_js.PublicKey.default) ? null : farmDebt,
|
|
16126
|
-
liquidityMint,
|
|
16127
|
-
...this.reservePdas(market, liquidityMint)
|
|
16151
|
+
...this._parseReserveAccount(account.data)
|
|
16128
16152
|
};
|
|
16129
|
-
this.reserves.set(reserves[i],
|
|
16130
|
-
return
|
|
16153
|
+
this.reserves.set(reserves[i], parsedReserve);
|
|
16154
|
+
return parsedReserve;
|
|
16131
16155
|
});
|
|
16132
16156
|
}
|
|
16133
16157
|
async findAndParseReserve(market, asset) {
|
|
@@ -16154,18 +16178,12 @@ class KaminoLendingClient {
|
|
|
16154
16178
|
throw new Error("Reserve not found");
|
|
16155
16179
|
}
|
|
16156
16180
|
const account = accounts[0];
|
|
16157
|
-
const
|
|
16158
|
-
const farmCollateral = new web3_js.PublicKey(data.subarray(64, 96));
|
|
16159
|
-
const farmDebt = new web3_js.PublicKey(data.subarray(96, 128));
|
|
16160
|
-
const parsed = {
|
|
16181
|
+
const parsedReserve = {
|
|
16161
16182
|
address: account.pubkey,
|
|
16162
|
-
|
|
16163
|
-
farmDebt: farmDebt.equals(web3_js.PublicKey.default) ? null : farmDebt,
|
|
16164
|
-
liquidityMint: asset,
|
|
16165
|
-
...this.reservePdas(market, asset)
|
|
16183
|
+
...this._parseReserveAccount(account.account.data)
|
|
16166
16184
|
};
|
|
16167
|
-
this.reserves.set(account.pubkey,
|
|
16168
|
-
return
|
|
16185
|
+
this.reserves.set(account.pubkey, parsedReserve);
|
|
16186
|
+
return parsedReserve;
|
|
16169
16187
|
}
|
|
16170
16188
|
async depositTx(glamState, market, asset, amount, txOptions) {
|
|
16171
16189
|
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
@@ -16223,7 +16241,7 @@ class KaminoLendingClient {
|
|
|
16223
16241
|
lendingMarket: market,
|
|
16224
16242
|
obligation,
|
|
16225
16243
|
reserves: reservesInUse
|
|
16226
|
-
}
|
|
16244
|
+
}));
|
|
16227
16245
|
if (depositReserve.farmCollateral) {
|
|
16228
16246
|
const ixs = this.refreshObligationFarmsForReserveIxs(obligation, market, [
|
|
16229
16247
|
depositReserve
|
|
@@ -16319,7 +16337,7 @@ class KaminoLendingClient {
|
|
|
16319
16337
|
lendingMarket: market,
|
|
16320
16338
|
obligation,
|
|
16321
16339
|
reserves: reservesInUse
|
|
16322
|
-
}
|
|
16340
|
+
}));
|
|
16323
16341
|
if (withdrawReserve.farmCollateral) {
|
|
16324
16342
|
const ixs = this.refreshObligationFarmsForReserveIxs(obligation, market, [
|
|
16325
16343
|
withdrawReserve
|
|
@@ -16409,7 +16427,7 @@ class KaminoLendingClient {
|
|
|
16409
16427
|
lendingMarket: market,
|
|
16410
16428
|
obligation,
|
|
16411
16429
|
reserves: reservesInUse
|
|
16412
|
-
}
|
|
16430
|
+
}));
|
|
16413
16431
|
// Don't need to refresh debt farm for borrow
|
|
16414
16432
|
/*
|
|
16415
16433
|
if (borrowReserve.farmDebt) {
|
|
@@ -16497,7 +16515,7 @@ class KaminoLendingClient {
|
|
|
16497
16515
|
lendingMarket: market,
|
|
16498
16516
|
obligation,
|
|
16499
16517
|
reserves: reservesInUse
|
|
16500
|
-
}
|
|
16518
|
+
}));
|
|
16501
16519
|
const repayIx = await this.base.program.methods.kaminoLendingRepayObligationLiquidityV2(amount).accounts({
|
|
16502
16520
|
glamState,
|
|
16503
16521
|
glamSigner,
|
|
@@ -16541,6 +16559,135 @@ class KaminoLendingClient {
|
|
|
16541
16559
|
};
|
|
16542
16560
|
}
|
|
16543
16561
|
}
|
|
16562
|
+
class KaminoFarmClient {
|
|
16563
|
+
async findAndParseFarmStates(owner) {
|
|
16564
|
+
const accounts = await this.base.provider.connection.getProgramAccounts(KAMINO_FARM_PROGRAM, {
|
|
16565
|
+
filters: [
|
|
16566
|
+
{
|
|
16567
|
+
dataSize: 920
|
|
16568
|
+
},
|
|
16569
|
+
{
|
|
16570
|
+
memcmp: {
|
|
16571
|
+
offset: 48,
|
|
16572
|
+
bytes: owner.toBase58()
|
|
16573
|
+
}
|
|
16574
|
+
}
|
|
16575
|
+
]
|
|
16576
|
+
});
|
|
16577
|
+
return accounts.map((account)=>{
|
|
16578
|
+
const data = account.account.data;
|
|
16579
|
+
const farmState = new web3_js.PublicKey(data.subarray(16, 48));
|
|
16580
|
+
return {
|
|
16581
|
+
userFarmState: account.pubkey,
|
|
16582
|
+
farmState
|
|
16583
|
+
};
|
|
16584
|
+
});
|
|
16585
|
+
}
|
|
16586
|
+
async parseFarm(data) {
|
|
16587
|
+
const globalConfig = new web3_js.PublicKey(data.subarray(40, 72));
|
|
16588
|
+
const rewardsOffset = 192;
|
|
16589
|
+
const numRewards = 10;
|
|
16590
|
+
const rewardSize = 704;
|
|
16591
|
+
const rewardsData = data.subarray(rewardsOffset, rewardsOffset + numRewards * rewardSize);
|
|
16592
|
+
const rewards = Array.from({
|
|
16593
|
+
length: numRewards
|
|
16594
|
+
}, (_, i)=>{
|
|
16595
|
+
const rewardData = rewardsData.subarray(i * rewardSize, (i + 1) * rewardSize);
|
|
16596
|
+
const mint = new web3_js.PublicKey(rewardData.subarray(0, 32));
|
|
16597
|
+
const tokenProgram = new web3_js.PublicKey(rewardData.subarray(40, 72));
|
|
16598
|
+
const rewardsVault = new web3_js.PublicKey(rewardData.subarray(120, 152));
|
|
16599
|
+
const minClaimDurationSeconds = new anchor.BN(rewardData.subarray(480, 488), "le");
|
|
16600
|
+
return {
|
|
16601
|
+
index: i,
|
|
16602
|
+
mint,
|
|
16603
|
+
minClaimDurationSeconds,
|
|
16604
|
+
tokenProgram,
|
|
16605
|
+
rewardsVault
|
|
16606
|
+
};
|
|
16607
|
+
}).filter((r)=>{
|
|
16608
|
+
if (r.mint.equals(web3_js.PublicKey.default)) {
|
|
16609
|
+
return false;
|
|
16610
|
+
}
|
|
16611
|
+
// Filter out rewards with minClaimDurationSeconds > 1 year, they are considered disabled
|
|
16612
|
+
if (r.minClaimDurationSeconds.div(new anchor.BN(365 * 24 * 60 * 60)).gt(new anchor.BN(1))) {
|
|
16613
|
+
return false;
|
|
16614
|
+
}
|
|
16615
|
+
return true;
|
|
16616
|
+
});
|
|
16617
|
+
return {
|
|
16618
|
+
globalConfig,
|
|
16619
|
+
rewards
|
|
16620
|
+
};
|
|
16621
|
+
}
|
|
16622
|
+
async fetchAndParseFarms(farms) {
|
|
16623
|
+
const farmAccounts = await this.base.provider.connection.getMultipleAccountsInfo(farms);
|
|
16624
|
+
const map = new Map();
|
|
16625
|
+
for(let i = 0; i < farmAccounts.length; i++){
|
|
16626
|
+
const account = farmAccounts[i];
|
|
16627
|
+
if (!account) {
|
|
16628
|
+
continue;
|
|
16629
|
+
}
|
|
16630
|
+
const data = account.data;
|
|
16631
|
+
const parsedFarm = await this.parseFarm(data);
|
|
16632
|
+
map.set(farms[i].toBase58(), parsedFarm);
|
|
16633
|
+
}
|
|
16634
|
+
return map;
|
|
16635
|
+
}
|
|
16636
|
+
async harvest(statePda, txOptions = {}) {
|
|
16637
|
+
const tx = await this.harvestTx(new web3_js.PublicKey(statePda), txOptions);
|
|
16638
|
+
return await this.base.sendAndConfirm(tx);
|
|
16639
|
+
}
|
|
16640
|
+
async harvestTx(glamState, txOptions = {}) {
|
|
16641
|
+
const glamSigner = txOptions.signer || this.base.getSigner();
|
|
16642
|
+
const vault = this.base.getVaultPda(glamState);
|
|
16643
|
+
const farmStates = await this.findAndParseFarmStates(vault);
|
|
16644
|
+
const parsedFarms = await this.fetchAndParseFarms(farmStates.map((f)=>f.farmState));
|
|
16645
|
+
const tx = new web3_js.Transaction();
|
|
16646
|
+
for (const { userFarmState, farmState } of farmStates){
|
|
16647
|
+
const { globalConfig, rewards } = parsedFarms.get(farmState.toBase58());
|
|
16648
|
+
for (const { index, mint, tokenProgram, rewardsVault } of rewards){
|
|
16649
|
+
console.log("Reward token:", mint.toBase58());
|
|
16650
|
+
const vaultAta = this.base.getVaultAta(glamState, mint, tokenProgram);
|
|
16651
|
+
const createAtaIx = splToken.createAssociatedTokenAccountIdempotentInstruction(glamSigner, vaultAta, vault, mint, tokenProgram);
|
|
16652
|
+
const harvestIx = await this.base.program.methods.kaminoFarmHarvestReward(new anchor.BN(index)).accounts({
|
|
16653
|
+
glamState,
|
|
16654
|
+
glamSigner,
|
|
16655
|
+
userState: userFarmState,
|
|
16656
|
+
farmState,
|
|
16657
|
+
globalConfig,
|
|
16658
|
+
rewardMint: mint,
|
|
16659
|
+
userRewardAta: vaultAta,
|
|
16660
|
+
rewardsVault,
|
|
16661
|
+
rewardsTreasuryVault: this.rewardsTreasuryVault(globalConfig, mint),
|
|
16662
|
+
farmVaultsAuthority: this.farmVaultsAuthority(farmState),
|
|
16663
|
+
scopePrices: null,
|
|
16664
|
+
tokenProgram
|
|
16665
|
+
}).instruction();
|
|
16666
|
+
tx.add(createAtaIx, harvestIx);
|
|
16667
|
+
}
|
|
16668
|
+
}
|
|
16669
|
+
const lookupTables = txOptions.lookupTables || await this.base.getAdressLookupTableAccounts([
|
|
16670
|
+
LOOKUP_TABLE
|
|
16671
|
+
]);
|
|
16672
|
+
const vTx = await this.base.intoVersionedTransaction(tx, {
|
|
16673
|
+
...txOptions,
|
|
16674
|
+
lookupTables
|
|
16675
|
+
});
|
|
16676
|
+
return vTx;
|
|
16677
|
+
}
|
|
16678
|
+
constructor(base){
|
|
16679
|
+
this.base = base;
|
|
16680
|
+
this.farmVaultsAuthority = (farm)=>web3_js.PublicKey.findProgramAddressSync([
|
|
16681
|
+
Buffer.from("authority"),
|
|
16682
|
+
farm.toBuffer()
|
|
16683
|
+
], KAMINO_FARM_PROGRAM)[0];
|
|
16684
|
+
this.rewardsTreasuryVault = (globalConfig, mint)=>web3_js.PublicKey.findProgramAddressSync([
|
|
16685
|
+
Buffer.from("tvault"),
|
|
16686
|
+
globalConfig.toBuffer(),
|
|
16687
|
+
mint.toBuffer()
|
|
16688
|
+
], KAMINO_FARM_PROGRAM)[0];
|
|
16689
|
+
}
|
|
16690
|
+
}
|
|
16544
16691
|
|
|
16545
16692
|
// Pubkey::find_program_address(&[b"__event_authority"], &dlmm_interface::ID)
|
|
16546
16693
|
const EVENT_AUTHORITY = new web3_js.PublicKey("D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6");
|
|
@@ -17017,6 +17164,28 @@ class PriceClient {
|
|
|
17017
17164
|
});
|
|
17018
17165
|
return pricedAssets.reduce((sum, p)=>new anchor.BN(p.amount).add(sum), new anchor.BN(0));
|
|
17019
17166
|
}
|
|
17167
|
+
async priceKaminoIxs(glamState, priceDenom) {
|
|
17168
|
+
const glamVault = this.base.getVaultPda(glamState);
|
|
17169
|
+
const obligations = await fetchKaminoObligations(this.base.provider.connection, glamVault);
|
|
17170
|
+
const refreshIxs = [];
|
|
17171
|
+
for (const obligation of obligations){
|
|
17172
|
+
const ixs = await this.klend.getRefreshIxs(obligation, false); // skip farms
|
|
17173
|
+
refreshIxs.push(...ixs);
|
|
17174
|
+
}
|
|
17175
|
+
// @ts-ignore
|
|
17176
|
+
const priceIx = await this.base.program.methods.priceKaminoObligations(priceDenom).accounts({
|
|
17177
|
+
glamState,
|
|
17178
|
+
solOracle: SOL_ORACLE
|
|
17179
|
+
}).remainingAccounts(obligations.map((o)=>({
|
|
17180
|
+
pubkey: o,
|
|
17181
|
+
isSigner: false,
|
|
17182
|
+
isWritable: false
|
|
17183
|
+
}))).instruction();
|
|
17184
|
+
return [
|
|
17185
|
+
...refreshIxs,
|
|
17186
|
+
priceIx
|
|
17187
|
+
];
|
|
17188
|
+
}
|
|
17020
17189
|
async priceVaultIxs(glamState, priceDenom) {
|
|
17021
17190
|
const vault = this.base.getVaultPda(glamState);
|
|
17022
17191
|
const tickets = await fetchMarinadeTicketAccounts(this.base.provider.connection, vault);
|
|
@@ -17046,29 +17215,18 @@ class PriceClient {
|
|
|
17046
17215
|
glamState,
|
|
17047
17216
|
solOracle: SOL_ORACLE
|
|
17048
17217
|
}).remainingAccounts(await this.remainingAccountsForPricingMeteora(glamState)).instruction();
|
|
17049
|
-
const
|
|
17050
|
-
glamState,
|
|
17051
|
-
solOracle: SOL_ORACLE
|
|
17052
|
-
}).remainingAccounts(await this.remainingAccountsForPricingKamino(glamState)).instruction();
|
|
17218
|
+
const priceKaminoIxs = await this.priceKaminoIxs(glamState, priceDenom);
|
|
17053
17219
|
return [
|
|
17054
17220
|
priceTicketsIx,
|
|
17055
17221
|
priceStakesIx,
|
|
17056
17222
|
priceVaultIx,
|
|
17057
17223
|
priceMeteoraIx,
|
|
17058
|
-
|
|
17224
|
+
...priceKaminoIxs
|
|
17059
17225
|
];
|
|
17060
17226
|
}
|
|
17061
|
-
constructor(base){
|
|
17227
|
+
constructor(base, klend){
|
|
17062
17228
|
this.base = base;
|
|
17063
|
-
this.
|
|
17064
|
-
const glamVault = this.base.getVaultPda(glamState);
|
|
17065
|
-
const obligationAccounts = await fetchKaminoObligations(this.base.provider.connection, glamVault);
|
|
17066
|
-
return obligationAccounts.map((a)=>({
|
|
17067
|
-
pubkey: a,
|
|
17068
|
-
isSigner: false,
|
|
17069
|
-
isWritable: false
|
|
17070
|
-
}));
|
|
17071
|
-
};
|
|
17229
|
+
this.klend = klend;
|
|
17072
17230
|
this.remainingAccountsForPricingMeteora = async (glamState)=>{
|
|
17073
17231
|
const glamVault = this.base.getVaultPda(glamState);
|
|
17074
17232
|
const positions = await fetchMeteoraPositions(this.base.provider.connection, glamVault);
|
|
@@ -17154,7 +17312,7 @@ class PriceClient {
|
|
|
17154
17312
|
}
|
|
17155
17313
|
get price() {
|
|
17156
17314
|
if (!this._price) {
|
|
17157
|
-
this._price = new PriceClient(this);
|
|
17315
|
+
this._price = new PriceClient(this, this.kaminoLending);
|
|
17158
17316
|
}
|
|
17159
17317
|
return this._price;
|
|
17160
17318
|
}
|
|
@@ -17176,6 +17334,12 @@ class PriceClient {
|
|
|
17176
17334
|
}
|
|
17177
17335
|
return this._kaminoLending;
|
|
17178
17336
|
}
|
|
17337
|
+
get kaminoFarm() {
|
|
17338
|
+
if (!this._kaminoFarm) {
|
|
17339
|
+
this._kaminoFarm = new KaminoFarmClient(this);
|
|
17340
|
+
}
|
|
17341
|
+
return this._kaminoFarm;
|
|
17342
|
+
}
|
|
17179
17343
|
get meteoraDlmm() {
|
|
17180
17344
|
if (!this._meteoraDlmm) {
|
|
17181
17345
|
this._meteoraDlmm = new MeteoraDlmmClient(this);
|
|
@@ -17191,7 +17355,7 @@ const getPriorityFeeEstimate = async (heliusApiKey, tx, accountKeys, priorityLev
|
|
|
17191
17355
|
if (!tx && !accountKeys) {
|
|
17192
17356
|
throw new Error("Either tx or accountKeys must be provided");
|
|
17193
17357
|
}
|
|
17194
|
-
const options = priorityLevel ? {
|
|
17358
|
+
const options = priorityLevel && priorityLevel !== "Recommended" ? {
|
|
17195
17359
|
priorityLevel
|
|
17196
17360
|
} : {
|
|
17197
17361
|
recommended: true
|
|
@@ -17233,6 +17397,7 @@ exports.DRIFT_PROGRAM_ID = DRIFT_PROGRAM_ID;
|
|
|
17233
17397
|
exports.DelegateAcl = DelegateAcl;
|
|
17234
17398
|
exports.DriftClient = DriftClient;
|
|
17235
17399
|
exports.FundOpenfundsModel = FundOpenfundsModel;
|
|
17400
|
+
exports.GLAM_REFERRER = GLAM_REFERRER;
|
|
17236
17401
|
exports.GOVERNANCE_PROGRAM_ID = GOVERNANCE_PROGRAM_ID;
|
|
17237
17402
|
exports.GlamClient = GlamClient;
|
|
17238
17403
|
exports.GlamError = GlamError;
|