@glamsystems/glam-sdk 0.1.18 → 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 -80
- package/index.esm.js +241 -81
- package/package.json +2 -2
- package/src/client/drift.d.ts +1 -0
- package/src/client/kamino.d.ts +38 -14
- 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) ? undefined : 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) ? undefined : 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
|
|
@@ -16265,7 +16283,6 @@ class KaminoLendingClient {
|
|
|
16265
16283
|
liquidityTokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
16266
16284
|
instructionSysvarAccount: web3_js.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
16267
16285
|
obligationFarmUserState: obligationFarm,
|
|
16268
|
-
// @ts-ignore
|
|
16269
16286
|
reserveFarmState: depositReserve.farmCollateral,
|
|
16270
16287
|
farmsProgram: KAMINO_FARM_PROGRAM
|
|
16271
16288
|
}).preInstructions(preInstructions).postInstructions(postInstructions).transaction();
|
|
@@ -16320,7 +16337,7 @@ class KaminoLendingClient {
|
|
|
16320
16337
|
lendingMarket: market,
|
|
16321
16338
|
obligation,
|
|
16322
16339
|
reserves: reservesInUse
|
|
16323
|
-
}
|
|
16340
|
+
}));
|
|
16324
16341
|
if (withdrawReserve.farmCollateral) {
|
|
16325
16342
|
const ixs = this.refreshObligationFarmsForReserveIxs(obligation, market, [
|
|
16326
16343
|
withdrawReserve
|
|
@@ -16349,7 +16366,6 @@ class KaminoLendingClient {
|
|
|
16349
16366
|
liquidityTokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
16350
16367
|
instructionSysvarAccount: web3_js.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
16351
16368
|
obligationFarmUserState: obligationFarm,
|
|
16352
|
-
// @ts-ignore
|
|
16353
16369
|
reserveFarmState: withdrawReserve.farmCollateral,
|
|
16354
16370
|
farmsProgram: KAMINO_FARM_PROGRAM
|
|
16355
16371
|
}).instruction();
|
|
@@ -16411,7 +16427,7 @@ class KaminoLendingClient {
|
|
|
16411
16427
|
lendingMarket: market,
|
|
16412
16428
|
obligation,
|
|
16413
16429
|
reserves: reservesInUse
|
|
16414
|
-
}
|
|
16430
|
+
}));
|
|
16415
16431
|
// Don't need to refresh debt farm for borrow
|
|
16416
16432
|
/*
|
|
16417
16433
|
if (borrowReserve.farmDebt) {
|
|
@@ -16440,7 +16456,6 @@ class KaminoLendingClient {
|
|
|
16440
16456
|
instructionSysvarAccount: web3_js.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
16441
16457
|
tokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
16442
16458
|
obligationFarmUserState: obligationFarm,
|
|
16443
|
-
// @ts-ignore
|
|
16444
16459
|
reserveFarmState: borrowReserve.farmDebt,
|
|
16445
16460
|
farmsProgram: KAMINO_FARM_PROGRAM
|
|
16446
16461
|
}).instruction();
|
|
@@ -16500,7 +16515,7 @@ class KaminoLendingClient {
|
|
|
16500
16515
|
lendingMarket: market,
|
|
16501
16516
|
obligation,
|
|
16502
16517
|
reserves: reservesInUse
|
|
16503
|
-
}
|
|
16518
|
+
}));
|
|
16504
16519
|
const repayIx = await this.base.program.methods.kaminoLendingRepayObligationLiquidityV2(amount).accounts({
|
|
16505
16520
|
glamState,
|
|
16506
16521
|
glamSigner,
|
|
@@ -16514,7 +16529,6 @@ class KaminoLendingClient {
|
|
|
16514
16529
|
instructionSysvarAccount: web3_js.SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
16515
16530
|
tokenProgram: splToken.TOKEN_PROGRAM_ID,
|
|
16516
16531
|
obligationFarmUserState: obligationFarm,
|
|
16517
|
-
// @ts-ignore
|
|
16518
16532
|
reserveFarmState: repayReserve.farmDebt,
|
|
16519
16533
|
farmsProgram: KAMINO_FARM_PROGRAM
|
|
16520
16534
|
}).instruction();
|
|
@@ -16545,6 +16559,135 @@ class KaminoLendingClient {
|
|
|
16545
16559
|
};
|
|
16546
16560
|
}
|
|
16547
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
|
+
}
|
|
16548
16691
|
|
|
16549
16692
|
// Pubkey::find_program_address(&[b"__event_authority"], &dlmm_interface::ID)
|
|
16550
16693
|
const EVENT_AUTHORITY = new web3_js.PublicKey("D1ZN9Wj1fRSUQfCjhvnu1hqDMT7hzjzBBpi12nVniYD6");
|
|
@@ -17021,6 +17164,28 @@ class PriceClient {
|
|
|
17021
17164
|
});
|
|
17022
17165
|
return pricedAssets.reduce((sum, p)=>new anchor.BN(p.amount).add(sum), new anchor.BN(0));
|
|
17023
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
|
+
}
|
|
17024
17189
|
async priceVaultIxs(glamState, priceDenom) {
|
|
17025
17190
|
const vault = this.base.getVaultPda(glamState);
|
|
17026
17191
|
const tickets = await fetchMarinadeTicketAccounts(this.base.provider.connection, vault);
|
|
@@ -17050,29 +17215,18 @@ class PriceClient {
|
|
|
17050
17215
|
glamState,
|
|
17051
17216
|
solOracle: SOL_ORACLE
|
|
17052
17217
|
}).remainingAccounts(await this.remainingAccountsForPricingMeteora(glamState)).instruction();
|
|
17053
|
-
const
|
|
17054
|
-
glamState,
|
|
17055
|
-
solOracle: SOL_ORACLE
|
|
17056
|
-
}).remainingAccounts(await this.remainingAccountsForPricingKamino(glamState)).instruction();
|
|
17218
|
+
const priceKaminoIxs = await this.priceKaminoIxs(glamState, priceDenom);
|
|
17057
17219
|
return [
|
|
17058
17220
|
priceTicketsIx,
|
|
17059
17221
|
priceStakesIx,
|
|
17060
17222
|
priceVaultIx,
|
|
17061
17223
|
priceMeteoraIx,
|
|
17062
|
-
|
|
17224
|
+
...priceKaminoIxs
|
|
17063
17225
|
];
|
|
17064
17226
|
}
|
|
17065
|
-
constructor(base){
|
|
17227
|
+
constructor(base, klend){
|
|
17066
17228
|
this.base = base;
|
|
17067
|
-
this.
|
|
17068
|
-
const glamVault = this.base.getVaultPda(glamState);
|
|
17069
|
-
const obligationAccounts = await fetchKaminoObligations(this.base.provider.connection, glamVault);
|
|
17070
|
-
return obligationAccounts.map((a)=>({
|
|
17071
|
-
pubkey: a,
|
|
17072
|
-
isSigner: false,
|
|
17073
|
-
isWritable: false
|
|
17074
|
-
}));
|
|
17075
|
-
};
|
|
17229
|
+
this.klend = klend;
|
|
17076
17230
|
this.remainingAccountsForPricingMeteora = async (glamState)=>{
|
|
17077
17231
|
const glamVault = this.base.getVaultPda(glamState);
|
|
17078
17232
|
const positions = await fetchMeteoraPositions(this.base.provider.connection, glamVault);
|
|
@@ -17158,7 +17312,7 @@ class PriceClient {
|
|
|
17158
17312
|
}
|
|
17159
17313
|
get price() {
|
|
17160
17314
|
if (!this._price) {
|
|
17161
|
-
this._price = new PriceClient(this);
|
|
17315
|
+
this._price = new PriceClient(this, this.kaminoLending);
|
|
17162
17316
|
}
|
|
17163
17317
|
return this._price;
|
|
17164
17318
|
}
|
|
@@ -17180,6 +17334,12 @@ class PriceClient {
|
|
|
17180
17334
|
}
|
|
17181
17335
|
return this._kaminoLending;
|
|
17182
17336
|
}
|
|
17337
|
+
get kaminoFarm() {
|
|
17338
|
+
if (!this._kaminoFarm) {
|
|
17339
|
+
this._kaminoFarm = new KaminoFarmClient(this);
|
|
17340
|
+
}
|
|
17341
|
+
return this._kaminoFarm;
|
|
17342
|
+
}
|
|
17183
17343
|
get meteoraDlmm() {
|
|
17184
17344
|
if (!this._meteoraDlmm) {
|
|
17185
17345
|
this._meteoraDlmm = new MeteoraDlmmClient(this);
|
|
@@ -17195,7 +17355,7 @@ const getPriorityFeeEstimate = async (heliusApiKey, tx, accountKeys, priorityLev
|
|
|
17195
17355
|
if (!tx && !accountKeys) {
|
|
17196
17356
|
throw new Error("Either tx or accountKeys must be provided");
|
|
17197
17357
|
}
|
|
17198
|
-
const options = priorityLevel ? {
|
|
17358
|
+
const options = priorityLevel && priorityLevel !== "Recommended" ? {
|
|
17199
17359
|
priorityLevel
|
|
17200
17360
|
} : {
|
|
17201
17361
|
recommended: true
|
|
@@ -17237,6 +17397,7 @@ exports.DRIFT_PROGRAM_ID = DRIFT_PROGRAM_ID;
|
|
|
17237
17397
|
exports.DelegateAcl = DelegateAcl;
|
|
17238
17398
|
exports.DriftClient = DriftClient;
|
|
17239
17399
|
exports.FundOpenfundsModel = FundOpenfundsModel;
|
|
17400
|
+
exports.GLAM_REFERRER = GLAM_REFERRER;
|
|
17240
17401
|
exports.GOVERNANCE_PROGRAM_ID = GOVERNANCE_PROGRAM_ID;
|
|
17241
17402
|
exports.GlamClient = GlamClient;
|
|
17242
17403
|
exports.GlamError = GlamError;
|