@quartz-labs/sdk 0.0.1 → 0.0.3
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 +1 -1
- package/dist/client.d.ts +19 -0
- package/dist/client.js +60 -0
- package/dist/config/constants.d.ts +9 -0
- package/{src/config/constants.ts → dist/config/constants.js} +3 -4
- package/dist/idl/quartz.json +646 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/model/driftUser.d.ts +36 -0
- package/dist/model/driftUser.js +574 -0
- package/dist/services/driftClientService.d.ts +9 -0
- package/dist/services/driftClientService.js +28 -0
- package/dist/types/quartz.d.ts +647 -0
- package/dist/types/quartz.js +646 -0
- package/dist/user.d.ts +25 -0
- package/dist/user.js +158 -0
- package/dist/utils/helpers.d.ts +12 -0
- package/dist/utils/helpers.js +39 -0
- package/dist/utils/jupiter.d.ts +7 -0
- package/dist/utils/jupiter.js +48 -0
- package/package.json +13 -4
- package/src/client.ts +0 -117
- package/src/helpers.ts +0 -33
- package/src/idl/quartz.json +0 -646
- package/src/index.ts +0 -4
- package/src/model/driftUser.ts +0 -1056
- package/src/types/quartz.ts +0 -1293
- package/src/user.ts +0 -85
- package/tsconfig.json +0 -17
package/dist/user.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { PublicKey, SystemProgram, SYSVAR_INSTRUCTIONS_PUBKEY } from "@solana/web3.js";
|
|
2
|
+
import { DriftUser } from "./model/driftUser";
|
|
3
|
+
import { BN, DRIFT_PROGRAM_ID } from "@drift-labs/sdk";
|
|
4
|
+
import { getDriftSpotMarketPublicKey, getDriftStatePublicKey, getVaultPublicKey, getVaultSplPublicKey } from "./utils/helpers";
|
|
5
|
+
import { DRIFT_MARKET_INDEX_SOL, DRIFT_MARKET_INDEX_USDC, QUARTZ_HEALTH_BUFFER, USDC_MINT, WSOL_MINT } from "./config/constants";
|
|
6
|
+
import { TOKEN_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
|
|
7
|
+
import { ASSOCIATED_TOKEN_PROGRAM_ID } from "@solana/spl-token";
|
|
8
|
+
import { SwapMode } from "@jup-ag/api";
|
|
9
|
+
import { getJupiterSwapIx } from "./utils/jupiter";
|
|
10
|
+
export class QuartzUser {
|
|
11
|
+
constructor(pubkey, connection, program, quartzLookupTable, oracles, driftClient, driftUserAccount) {
|
|
12
|
+
this.pubkey = pubkey;
|
|
13
|
+
this.vaultPubkey = getVaultPublicKey(pubkey);
|
|
14
|
+
this.connection = connection;
|
|
15
|
+
this.program = program;
|
|
16
|
+
this.quartzLookupTable = quartzLookupTable;
|
|
17
|
+
this.oracles = oracles;
|
|
18
|
+
this.driftClient = driftClient;
|
|
19
|
+
this.driftUser = new DriftUser(this.vaultPubkey, connection, driftClient, driftUserAccount);
|
|
20
|
+
}
|
|
21
|
+
convertToQuartzHealth(protocolHealth) {
|
|
22
|
+
if (protocolHealth <= 0)
|
|
23
|
+
return 0;
|
|
24
|
+
if (protocolHealth >= 100)
|
|
25
|
+
return 100;
|
|
26
|
+
return Math.floor(Math.min(100, Math.max(0, (protocolHealth - QUARTZ_HEALTH_BUFFER) / (1 - QUARTZ_HEALTH_BUFFER))));
|
|
27
|
+
}
|
|
28
|
+
getHealth() {
|
|
29
|
+
const driftHealth = this.driftUser.getHealth();
|
|
30
|
+
return this.convertToQuartzHealth(driftHealth);
|
|
31
|
+
}
|
|
32
|
+
getRepayAmountForTargetHealth(targetHealth, repayCollateralWeight) {
|
|
33
|
+
// New Quartz health after repayment is given as:
|
|
34
|
+
//
|
|
35
|
+
// loanValue - repayAmount
|
|
36
|
+
// 1 - ----------------------------------------------------------------- - quartzHealthBuffer
|
|
37
|
+
// currentWeightedCollateral - (repayAmount * repayCollateralWeight)
|
|
38
|
+
// targetHealth = -------------------------------------------------------------------------------------------
|
|
39
|
+
// 1 - quartzHealthBuffer
|
|
40
|
+
//
|
|
41
|
+
// The following is an algebraicly simplified expression of the above formula, in terms of repayAmount
|
|
42
|
+
if (targetHealth <= 0 || targetHealth >= 100)
|
|
43
|
+
throw Error(`Target health must be between 0 and 100`);
|
|
44
|
+
if (targetHealth <= this.getHealth())
|
|
45
|
+
throw Error(`Target health must be greater than current health`);
|
|
46
|
+
const currentWeightedCollateral = this.getTotalWeightedCollateral();
|
|
47
|
+
const loanValue = this.getMaintenanceMarginRequirement();
|
|
48
|
+
return Math.round((loanValue - currentWeightedCollateral * (1 - QUARTZ_HEALTH_BUFFER) * (1 - targetHealth)) / (1 - repayCollateralWeight * (1 - QUARTZ_HEALTH_BUFFER) * (1 - targetHealth)));
|
|
49
|
+
}
|
|
50
|
+
getTotalWeightedCollateral() {
|
|
51
|
+
return this.driftUser.getTotalCollateral('Maintenance').toNumber();
|
|
52
|
+
}
|
|
53
|
+
getMaintenanceMarginRequirement() {
|
|
54
|
+
return this.driftUser.getMaintenanceMarginRequirement().toNumber();
|
|
55
|
+
}
|
|
56
|
+
async makeCollateralRepayIxs(caller, callerDepositSpl, callerWithdrawSpl, callerStartingDepositBalance, jupiterExactOutRouteQuote) {
|
|
57
|
+
const depositMint = USDC_MINT;
|
|
58
|
+
const depositMarketIndex = DRIFT_MARKET_INDEX_USDC;
|
|
59
|
+
const withdrawMint = WSOL_MINT;
|
|
60
|
+
const withdrawMarketIndex = DRIFT_MARKET_INDEX_SOL;
|
|
61
|
+
if (jupiterExactOutRouteQuote.swapMode !== SwapMode.ExactOut)
|
|
62
|
+
throw Error("Jupiter quote must be ExactOutRoute");
|
|
63
|
+
if (jupiterExactOutRouteQuote.inputMint !== withdrawMint.toBase58())
|
|
64
|
+
throw Error("Jupiter quote inputMint does not match withdrawMint");
|
|
65
|
+
if (jupiterExactOutRouteQuote.outputMint !== depositMint.toBase58())
|
|
66
|
+
throw Error("Jupiter quote outputMint does not match depositMint");
|
|
67
|
+
const driftState = getDriftStatePublicKey();
|
|
68
|
+
const driftSpotMarketDeposit = getDriftSpotMarketPublicKey(depositMarketIndex);
|
|
69
|
+
const driftSpotMarketWithdraw = getDriftSpotMarketPublicKey(withdrawMarketIndex);
|
|
70
|
+
const autoRepayStartPromise = this.program.methods
|
|
71
|
+
.autoRepayStart(new BN(callerStartingDepositBalance))
|
|
72
|
+
.accounts({
|
|
73
|
+
caller: caller,
|
|
74
|
+
callerWithdrawSpl: callerWithdrawSpl,
|
|
75
|
+
withdrawMint: withdrawMint,
|
|
76
|
+
vault: this.vaultPubkey,
|
|
77
|
+
vaultWithdrawSpl: getVaultSplPublicKey(this.vaultPubkey, withdrawMint),
|
|
78
|
+
owner: this.pubkey,
|
|
79
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
80
|
+
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
81
|
+
systemProgram: SystemProgram.programId,
|
|
82
|
+
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
83
|
+
})
|
|
84
|
+
.instruction();
|
|
85
|
+
const jupiterSwapPromise = getJupiterSwapIx(caller, this.connection, jupiterExactOutRouteQuote);
|
|
86
|
+
const autoRepayDepositPromise = this.program.methods
|
|
87
|
+
.autoRepayDeposit(depositMarketIndex)
|
|
88
|
+
.accounts({
|
|
89
|
+
vault: this.vaultPubkey,
|
|
90
|
+
vaultSpl: getVaultSplPublicKey(this.vaultPubkey, depositMint),
|
|
91
|
+
owner: this.pubkey,
|
|
92
|
+
caller: caller,
|
|
93
|
+
callerSpl: callerDepositSpl,
|
|
94
|
+
splMint: depositMint,
|
|
95
|
+
driftUser: this.driftUser.pubkey,
|
|
96
|
+
driftUserStats: this.driftUser.statsPubkey,
|
|
97
|
+
driftState: driftState,
|
|
98
|
+
spotMarketVault: driftSpotMarketDeposit,
|
|
99
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
100
|
+
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
101
|
+
driftProgram: new PublicKey(DRIFT_PROGRAM_ID),
|
|
102
|
+
systemProgram: SystemProgram.programId,
|
|
103
|
+
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
104
|
+
})
|
|
105
|
+
.remainingAccounts(this.driftClient.getRemainingAccounts({
|
|
106
|
+
userAccounts: [this.driftUser.getDriftUserAccount()],
|
|
107
|
+
useMarketLastSlotCache: true,
|
|
108
|
+
writableSpotMarketIndexes: [depositMarketIndex],
|
|
109
|
+
}))
|
|
110
|
+
.instruction();
|
|
111
|
+
const autoRepayWithdrawPromise = this.program.methods
|
|
112
|
+
.autoRepayWithdraw(withdrawMarketIndex)
|
|
113
|
+
.accounts({
|
|
114
|
+
vault: this.vaultPubkey,
|
|
115
|
+
vaultSpl: getVaultSplPublicKey(this.vaultPubkey, withdrawMint),
|
|
116
|
+
owner: this.pubkey,
|
|
117
|
+
caller: caller,
|
|
118
|
+
callerSpl: callerWithdrawSpl,
|
|
119
|
+
splMint: withdrawMint,
|
|
120
|
+
driftUser: this.driftUser.pubkey,
|
|
121
|
+
driftUserStats: this.driftUser.statsPubkey,
|
|
122
|
+
driftState: driftState,
|
|
123
|
+
spotMarketVault: driftSpotMarketWithdraw,
|
|
124
|
+
driftSigner: this.driftClient.getSignerPublicKey(),
|
|
125
|
+
tokenProgram: TOKEN_PROGRAM_ID,
|
|
126
|
+
driftProgram: DRIFT_PROGRAM_ID,
|
|
127
|
+
systemProgram: SystemProgram.programId,
|
|
128
|
+
depositPriceUpdate: this.oracles.get("USDC/USD"),
|
|
129
|
+
withdrawPriceUpdate: this.oracles.get("SOL/USD"),
|
|
130
|
+
instructions: SYSVAR_INSTRUCTIONS_PUBKEY,
|
|
131
|
+
})
|
|
132
|
+
.remainingAccounts(this.driftClient.getRemainingAccounts({
|
|
133
|
+
userAccounts: [this.driftUser.getDriftUserAccount()],
|
|
134
|
+
useMarketLastSlotCache: true,
|
|
135
|
+
writableSpotMarketIndexes: [withdrawMarketIndex],
|
|
136
|
+
readableSpotMarketIndexes: [DRIFT_MARKET_INDEX_USDC], // Quote is in USDC
|
|
137
|
+
}))
|
|
138
|
+
.instruction();
|
|
139
|
+
const [ix_autoRepayStart, { ix_jupiterSwap, jupiterLookupTables }, ix_autoRepayDeposit, ix_autoRepayWithdraw] = await Promise.all([
|
|
140
|
+
autoRepayStartPromise,
|
|
141
|
+
jupiterSwapPromise,
|
|
142
|
+
autoRepayDepositPromise,
|
|
143
|
+
autoRepayWithdrawPromise
|
|
144
|
+
]);
|
|
145
|
+
return {
|
|
146
|
+
ixs: [
|
|
147
|
+
ix_autoRepayStart,
|
|
148
|
+
ix_jupiterSwap,
|
|
149
|
+
ix_autoRepayDeposit,
|
|
150
|
+
ix_autoRepayWithdraw
|
|
151
|
+
],
|
|
152
|
+
lookupTables: [
|
|
153
|
+
this.quartzLookupTable,
|
|
154
|
+
...jupiterLookupTables
|
|
155
|
+
],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
export declare const getVaultPublicKey: (user: PublicKey) => PublicKey;
|
|
3
|
+
export declare const getVaultSplPublicKey: (user: PublicKey, mint: PublicKey) => PublicKey;
|
|
4
|
+
export declare const getDriftUserPublicKey: (vaultPda: PublicKey) => PublicKey;
|
|
5
|
+
export declare const getDriftUserStatsPublicKey: (vaultPda: PublicKey) => PublicKey;
|
|
6
|
+
export declare const getDriftStatePublicKey: () => PublicKey;
|
|
7
|
+
export declare const getDriftSpotMarketPublicKey: (marketIndex: number) => PublicKey;
|
|
8
|
+
export declare const toRemainingAccount: (pubkey: PublicKey, isWritable: boolean, isSigner: boolean) => {
|
|
9
|
+
pubkey: PublicKey;
|
|
10
|
+
isWritable: boolean;
|
|
11
|
+
isSigner: boolean;
|
|
12
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { PublicKey } from "@solana/web3.js";
|
|
2
|
+
import { QUARTZ_PROGRAM_ID } from "../config/constants";
|
|
3
|
+
import { BN } from "@coral-xyz/anchor";
|
|
4
|
+
import { DRIFT_PROGRAM_ID } from "@drift-labs/sdk";
|
|
5
|
+
export const getVaultPublicKey = (user) => {
|
|
6
|
+
const [vaultPda] = PublicKey.findProgramAddressSync([Buffer.from("vault"), user.toBuffer()], QUARTZ_PROGRAM_ID);
|
|
7
|
+
return vaultPda;
|
|
8
|
+
};
|
|
9
|
+
export const getVaultSplPublicKey = (user, mint) => {
|
|
10
|
+
const vaultPda = getVaultPublicKey(user);
|
|
11
|
+
const [vaultSplPda] = PublicKey.findProgramAddressSync([vaultPda.toBuffer(), mint.toBuffer()], QUARTZ_PROGRAM_ID);
|
|
12
|
+
return vaultSplPda;
|
|
13
|
+
};
|
|
14
|
+
export const getDriftUserPublicKey = (vaultPda) => {
|
|
15
|
+
const [userPda] = PublicKey.findProgramAddressSync([
|
|
16
|
+
Buffer.from("user"),
|
|
17
|
+
vaultPda.toBuffer(),
|
|
18
|
+
new BN(0).toArrayLike(Buffer, 'le', 2),
|
|
19
|
+
], new PublicKey(DRIFT_PROGRAM_ID));
|
|
20
|
+
return userPda;
|
|
21
|
+
};
|
|
22
|
+
export const getDriftUserStatsPublicKey = (vaultPda) => {
|
|
23
|
+
const [userStatsPda] = PublicKey.findProgramAddressSync([Buffer.from("user_stats"), vaultPda.toBuffer()], new PublicKey(DRIFT_PROGRAM_ID));
|
|
24
|
+
return userStatsPda;
|
|
25
|
+
};
|
|
26
|
+
export const getDriftStatePublicKey = () => {
|
|
27
|
+
const [statePda] = PublicKey.findProgramAddressSync([Buffer.from("drift_state")], new PublicKey(DRIFT_PROGRAM_ID));
|
|
28
|
+
return statePda;
|
|
29
|
+
};
|
|
30
|
+
export const getDriftSpotMarketPublicKey = (marketIndex) => {
|
|
31
|
+
const [spotMarketVaultPda] = PublicKey.findProgramAddressSync([
|
|
32
|
+
Buffer.from("spot_market_vault"),
|
|
33
|
+
new BN(marketIndex).toArrayLike(Buffer, 'le', 2)
|
|
34
|
+
], new PublicKey(DRIFT_PROGRAM_ID));
|
|
35
|
+
return spotMarketVaultPda;
|
|
36
|
+
};
|
|
37
|
+
export const toRemainingAccount = (pubkey, isWritable, isSigner) => {
|
|
38
|
+
return { pubkey, isWritable, isSigner };
|
|
39
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { PublicKey, Connection, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import { QuoteResponse } from "@jup-ag/api";
|
|
3
|
+
import { AddressLookupTableAccount } from "@solana/web3.js";
|
|
4
|
+
export declare function getJupiterSwapIx(walletPubkey: PublicKey, connection: Connection, quoteResponse: QuoteResponse): Promise<{
|
|
5
|
+
ix_jupiterSwap: TransactionInstruction;
|
|
6
|
+
jupiterLookupTables: AddressLookupTableAccount[];
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
|
2
|
+
import { AddressLookupTableAccount } from "@solana/web3.js";
|
|
3
|
+
export async function getJupiterSwapIx(walletPubkey, connection, quoteResponse) {
|
|
4
|
+
const instructions = await (await fetch('https://quote-api.jup.ag/v6/swap-instructions', {
|
|
5
|
+
method: 'POST',
|
|
6
|
+
headers: {
|
|
7
|
+
'Content-Type': 'application/json'
|
|
8
|
+
},
|
|
9
|
+
body: JSON.stringify({
|
|
10
|
+
quoteResponse,
|
|
11
|
+
userPublicKey: walletPubkey.toBase58(),
|
|
12
|
+
useCompression: true,
|
|
13
|
+
})
|
|
14
|
+
})).json();
|
|
15
|
+
if (instructions.error) {
|
|
16
|
+
throw new Error("Failed to get swap instructions: " + instructions.error);
|
|
17
|
+
}
|
|
18
|
+
const { swapInstruction, addressLookupTableAddresses } = instructions;
|
|
19
|
+
const getAddressLookupTableAccounts = async (keys) => {
|
|
20
|
+
const addressLookupTableAccountInfos = await connection.getMultipleAccountsInfo(keys.map((key) => new PublicKey(key)));
|
|
21
|
+
return addressLookupTableAccountInfos.reduce((acc, accountInfo, index) => {
|
|
22
|
+
const addressLookupTableAddress = keys[index];
|
|
23
|
+
if (accountInfo) {
|
|
24
|
+
const addressLookupTableAccount = new AddressLookupTableAccount({
|
|
25
|
+
key: new PublicKey(addressLookupTableAddress),
|
|
26
|
+
state: AddressLookupTableAccount.deserialize(accountInfo.data),
|
|
27
|
+
});
|
|
28
|
+
acc.push(addressLookupTableAccount);
|
|
29
|
+
}
|
|
30
|
+
return acc;
|
|
31
|
+
}, new Array());
|
|
32
|
+
};
|
|
33
|
+
const addressLookupTableAccounts = [];
|
|
34
|
+
addressLookupTableAccounts.push(...(await getAddressLookupTableAccounts(addressLookupTableAddresses)));
|
|
35
|
+
const ix_jupiterSwap = new TransactionInstruction({
|
|
36
|
+
programId: new PublicKey(swapInstruction.programId),
|
|
37
|
+
keys: swapInstruction.accounts.map((key) => ({
|
|
38
|
+
pubkey: new PublicKey(key.pubkey),
|
|
39
|
+
isSigner: key.isSigner,
|
|
40
|
+
isWritable: key.isWritable,
|
|
41
|
+
})),
|
|
42
|
+
data: Buffer.from(swapInstruction.data, "base64"),
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
ix_jupiterSwap,
|
|
46
|
+
jupiterLookupTables: addressLookupTableAccounts,
|
|
47
|
+
};
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quartz-labs/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "SDK for interacting with the Quartz Protocol",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"types": "index.d.ts",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
7
10
|
"typesVersions": {
|
|
8
|
-
">=4.7": {
|
|
11
|
+
">=4.7": {
|
|
12
|
+
"*": [
|
|
13
|
+
"ts/*"
|
|
14
|
+
]
|
|
15
|
+
}
|
|
9
16
|
},
|
|
10
17
|
"scripts": {
|
|
11
18
|
"build": "tsc",
|
|
@@ -38,7 +45,9 @@
|
|
|
38
45
|
"dependencies": {
|
|
39
46
|
"@coral-xyz/anchor": "^0.29.0",
|
|
40
47
|
"@drift-labs/sdk": "^2.103.0-beta.9",
|
|
48
|
+
"@jup-ag/api": "^6.0.30",
|
|
41
49
|
"@pythnetwork/pyth-solana-receiver": "^0.8.2",
|
|
50
|
+
"@solana/spl-token": "^0.4.9",
|
|
42
51
|
"@solana/web3.js": "^1.95.8"
|
|
43
52
|
}
|
|
44
53
|
}
|
package/src/client.ts
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import { DriftClient, fetchUserAccountsUsingKeys as fetchDriftAccountsUsingKeys } from "@drift-labs/sdk";
|
|
2
|
-
import { QUARTZ_ADDRESS_TABLE, QUARTZ_PROGRAM_ID, SUPPORTED_DRIFT_MARKETS } from "./config/constants";
|
|
3
|
-
import quartzIdl from "./idl/quartz.json";
|
|
4
|
-
import { Quartz } from "./types/quartz.js";
|
|
5
|
-
import { AnchorProvider, Idl, Program, setProvider, Wallet } from "@coral-xyz/anchor";
|
|
6
|
-
import { Connection, AddressLookupTableAccount } from "@solana/web3.js";
|
|
7
|
-
import { PythSolanaReceiver } from "@pythnetwork/pyth-solana-receiver";
|
|
8
|
-
import { PublicKey } from "@solana/web3.js";
|
|
9
|
-
import { QuartzUser } from "./user";
|
|
10
|
-
import { getDriftUser, getVaultPubkey } from "./helpers";
|
|
11
|
-
|
|
12
|
-
export class QuartzClient {
|
|
13
|
-
private connection: Connection;
|
|
14
|
-
private wallet: Wallet;
|
|
15
|
-
private program: Program<Quartz>;
|
|
16
|
-
private quartzAddressTable: AddressLookupTableAccount;
|
|
17
|
-
|
|
18
|
-
private driftClient: DriftClient;
|
|
19
|
-
private oracles: Map<string, PublicKey>;
|
|
20
|
-
|
|
21
|
-
constructor(
|
|
22
|
-
connection: Connection,
|
|
23
|
-
wallet: Wallet,
|
|
24
|
-
program: Program<Quartz>,
|
|
25
|
-
quartzAddressTable: AddressLookupTableAccount,
|
|
26
|
-
driftClient: DriftClient,
|
|
27
|
-
oracles: Map<string, PublicKey>
|
|
28
|
-
) {
|
|
29
|
-
this.connection = connection;
|
|
30
|
-
this.wallet = wallet;
|
|
31
|
-
this.program = program;
|
|
32
|
-
this.quartzAddressTable = quartzAddressTable;
|
|
33
|
-
this.driftClient = driftClient;
|
|
34
|
-
this.oracles = oracles;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
static async initialize(
|
|
38
|
-
connection: Connection,
|
|
39
|
-
wallet: Wallet
|
|
40
|
-
) {
|
|
41
|
-
const provider = new AnchorProvider(connection, wallet, { commitment: "confirmed" });
|
|
42
|
-
setProvider(provider);
|
|
43
|
-
const program = new Program(quartzIdl as Idl, QUARTZ_PROGRAM_ID, provider) as unknown as Program<Quartz>;
|
|
44
|
-
|
|
45
|
-
const quartzLookupTable = await connection.getAddressLookupTable(QUARTZ_ADDRESS_TABLE).then((res) => res.value);
|
|
46
|
-
if (!quartzLookupTable) throw Error("Address Lookup Table account not found");
|
|
47
|
-
|
|
48
|
-
const driftClient = new DriftClient({
|
|
49
|
-
connection,
|
|
50
|
-
wallet,
|
|
51
|
-
env: 'mainnet-beta',
|
|
52
|
-
userStats: false,
|
|
53
|
-
perpMarketIndexes: [],
|
|
54
|
-
spotMarketIndexes: SUPPORTED_DRIFT_MARKETS,
|
|
55
|
-
accountSubscription: {
|
|
56
|
-
type: 'websocket',
|
|
57
|
-
commitment: "confirmed"
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
await driftClient.subscribe();
|
|
61
|
-
|
|
62
|
-
const pythSolanaReceiver = new PythSolanaReceiver({ connection, wallet });
|
|
63
|
-
const oracles = new Map<string, PublicKey>([
|
|
64
|
-
["SOL/USD", pythSolanaReceiver.getPriceFeedAccountAddress(0,
|
|
65
|
-
"0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d")],
|
|
66
|
-
["USDC/USD", pythSolanaReceiver.getPriceFeedAccountAddress(0,
|
|
67
|
-
"0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a")]
|
|
68
|
-
]);
|
|
69
|
-
|
|
70
|
-
return new QuartzClient(
|
|
71
|
-
connection,
|
|
72
|
-
wallet,
|
|
73
|
-
program,
|
|
74
|
-
quartzLookupTable,
|
|
75
|
-
driftClient,
|
|
76
|
-
oracles
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
public async getAllAccountPubkeys(): Promise<PublicKey[]> {
|
|
81
|
-
return (
|
|
82
|
-
await this.program.account.vault.all()
|
|
83
|
-
).map((vault) => vault.publicKey);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
public async getQuartzAccount(pubkey: PublicKey): Promise<QuartzUser> {
|
|
87
|
-
const vault = getVaultPubkey(pubkey);
|
|
88
|
-
await this.program.account.vault.fetch(vault); // Check account exists
|
|
89
|
-
return new QuartzUser(pubkey, this.connection, this.driftClient);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
public async getMultipleQuartzAccounts(pubkeys: PublicKey[]): Promise<QuartzUser[]> {
|
|
93
|
-
if (pubkeys.length === 0) return [];
|
|
94
|
-
|
|
95
|
-
const vaults = pubkeys.map((pubkey) => getVaultPubkey(pubkey));
|
|
96
|
-
const accounts = await this.program.account.vault.fetchMultiple(vaults);
|
|
97
|
-
|
|
98
|
-
accounts.forEach((account, index) => {
|
|
99
|
-
if (account === null) throw Error(`Account not found for pubkey: ${pubkeys[index].toBase58()}`)
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const driftUsers = await fetchDriftAccountsUsingKeys(
|
|
103
|
-
this.connection,
|
|
104
|
-
this.driftClient.program,
|
|
105
|
-
vaults.map((vault) => getDriftUser(vault))
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
const undefinedIndex = driftUsers.findIndex(user => !user);
|
|
109
|
-
if (undefinedIndex !== -1) {
|
|
110
|
-
throw new Error(`[${this.wallet?.publicKey}] Failed to fetch drift user for vault ${vaults[undefinedIndex].toBase58()}`);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return driftUsers.map((driftUser, index) => {
|
|
114
|
-
return new QuartzUser(pubkeys[index], this.connection, this.driftClient, driftUser)
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
}
|
package/src/helpers.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { PublicKey } from "@solana/web3.js";
|
|
2
|
-
import { QUARTZ_PROGRAM_ID } from "./config/constants";
|
|
3
|
-
import { BN } from "@coral-xyz/anchor";
|
|
4
|
-
import { DRIFT_PROGRAM_ID } from "@drift-labs/sdk";
|
|
5
|
-
|
|
6
|
-
export const getVaultPubkey = (owner: PublicKey) => {
|
|
7
|
-
const [vaultPda] = PublicKey.findProgramAddressSync(
|
|
8
|
-
[Buffer.from("vault"), owner.toBuffer()],
|
|
9
|
-
QUARTZ_PROGRAM_ID
|
|
10
|
-
)
|
|
11
|
-
return vaultPda;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const getVaultSplPubkey = (owner: PublicKey, mint: PublicKey) => {
|
|
15
|
-
const vaultPda = getVaultPubkey(owner);
|
|
16
|
-
const [vaultSplPda] = PublicKey.findProgramAddressSync(
|
|
17
|
-
[vaultPda.toBuffer(), mint.toBuffer()],
|
|
18
|
-
QUARTZ_PROGRAM_ID
|
|
19
|
-
);
|
|
20
|
-
return vaultSplPda;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const getDriftUser = (vaultPda: PublicKey) => {
|
|
24
|
-
const [userPda] = PublicKey.findProgramAddressSync(
|
|
25
|
-
[
|
|
26
|
-
Buffer.from("user"),
|
|
27
|
-
vaultPda.toBuffer(),
|
|
28
|
-
new BN(0).toArrayLike(Buffer, 'le', 2),
|
|
29
|
-
],
|
|
30
|
-
new PublicKey(DRIFT_PROGRAM_ID)
|
|
31
|
-
);
|
|
32
|
-
return userPda;
|
|
33
|
-
}
|