@drift-labs/sdk 2.84.0-beta.5 → 2.84.0-beta.7
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/VERSION +1 -1
- package/lib/adminClient.d.ts +4 -2
- package/lib/adminClient.js +21 -4
- package/lib/blockhashSubscriber/BlockhashSubscriber.d.ts +7 -1
- package/lib/blockhashSubscriber/BlockhashSubscriber.js +11 -2
- package/lib/constants/spotMarkets.js +10 -0
- package/lib/driftClient.d.ts +30 -3
- package/lib/driftClient.js +108 -82
- package/lib/factory/oracleClient.js +13 -0
- package/lib/idl/drift.json +17 -0
- package/lib/math/spotBalance.js +7 -1
- package/lib/oracles/pythPullClient.d.ts +18 -0
- package/lib/oracles/pythPullClient.js +60 -0
- package/lib/tx/txHandler.d.ts +23 -20
- package/lib/tx/txHandler.js +56 -57
- package/lib/types.d.ts +17 -0
- package/lib/types.js +4 -0
- package/package.json +11 -9
- package/src/adminClient.ts +45 -3
- package/src/blockhashSubscriber/BlockhashSubscriber.ts +15 -2
- package/src/constants/spotMarkets.ts +10 -0
- package/src/driftClient.ts +308 -167
- package/src/factory/oracleClient.ts +17 -0
- package/src/idl/drift.json +17 -0
- package/src/math/spotBalance.ts +15 -1
- package/src/oracles/pythPullClient.ts +112 -0
- package/src/tx/txHandler.ts +87 -78
- package/src/types.ts +12 -0
|
@@ -7,6 +7,7 @@ import { QuoteAssetOracleClient } from '../oracles/quoteAssetOracleClient';
|
|
|
7
7
|
import { BN, Program } from '@coral-xyz/anchor';
|
|
8
8
|
import { PrelaunchOracleClient } from '../oracles/prelaunchOracleClient';
|
|
9
9
|
import { SwitchboardClient } from '../oracles/switchboardClient';
|
|
10
|
+
import { PythPullClient } from '../oracles/pythPullClient';
|
|
10
11
|
|
|
11
12
|
export function getOracleClient(
|
|
12
13
|
oracleSource: OracleSource,
|
|
@@ -17,18 +18,34 @@ export function getOracleClient(
|
|
|
17
18
|
return new PythClient(connection);
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
if (isVariant(oracleSource, 'pythPull')) {
|
|
22
|
+
return new PythPullClient(connection);
|
|
23
|
+
}
|
|
24
|
+
|
|
20
25
|
if (isVariant(oracleSource, 'pyth1K')) {
|
|
21
26
|
return new PythClient(connection, new BN(1000));
|
|
22
27
|
}
|
|
23
28
|
|
|
29
|
+
if (isVariant(oracleSource, 'pyth1KPull')) {
|
|
30
|
+
return new PythPullClient(connection, new BN(1000));
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
if (isVariant(oracleSource, 'pyth1M')) {
|
|
25
34
|
return new PythClient(connection, new BN(1000000));
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
if (isVariant(oracleSource, 'pyth1MPull')) {
|
|
38
|
+
return new PythPullClient(connection, new BN(1000000));
|
|
39
|
+
}
|
|
40
|
+
|
|
28
41
|
if (isVariant(oracleSource, 'pythStableCoin')) {
|
|
29
42
|
return new PythClient(connection, undefined, true);
|
|
30
43
|
}
|
|
31
44
|
|
|
45
|
+
if (isVariant(oracleSource, 'pythStableCoinPull')) {
|
|
46
|
+
return new PythPullClient(connection, undefined, true);
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
if (isVariant(oracleSource, 'switchboard')) {
|
|
33
50
|
return new SwitchboardClient(connection);
|
|
34
51
|
}
|
package/src/idl/drift.json
CHANGED
|
@@ -9254,6 +9254,18 @@
|
|
|
9254
9254
|
},
|
|
9255
9255
|
{
|
|
9256
9256
|
"name": "Prelaunch"
|
|
9257
|
+
},
|
|
9258
|
+
{
|
|
9259
|
+
"name": "PythPull"
|
|
9260
|
+
},
|
|
9261
|
+
{
|
|
9262
|
+
"name": "Pyth1KPull"
|
|
9263
|
+
},
|
|
9264
|
+
{
|
|
9265
|
+
"name": "Pyth1MPull"
|
|
9266
|
+
},
|
|
9267
|
+
{
|
|
9268
|
+
"name": "PythStableCoinPull"
|
|
9257
9269
|
}
|
|
9258
9270
|
]
|
|
9259
9271
|
}
|
|
@@ -11992,6 +12004,11 @@
|
|
|
11992
12004
|
"code": 6266,
|
|
11993
12005
|
"name": "OracleStaleForAMM",
|
|
11994
12006
|
"msg": "OracleStaleForAMM"
|
|
12007
|
+
},
|
|
12008
|
+
{
|
|
12009
|
+
"code": 6267,
|
|
12010
|
+
"name": "UnableToParsePullOracleMessage",
|
|
12011
|
+
"msg": "Unable to parse pull oracle message"
|
|
11995
12012
|
}
|
|
11996
12013
|
]
|
|
11997
12014
|
}
|
package/src/math/spotBalance.ts
CHANGED
|
@@ -363,6 +363,17 @@ export function calculateSpotMarketBorrowCapacity(
|
|
|
363
363
|
remainingCapacity = BN.max(ZERO, totalCapacity.sub(tokenBorrowAmount));
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
+
if (spotMarketAccount.maxTokenBorrowsFraction > 0) {
|
|
367
|
+
const maxTokenBorrows = spotMarketAccount.maxTokenDeposits
|
|
368
|
+
.mul(new BN(spotMarketAccount.maxTokenBorrowsFraction))
|
|
369
|
+
.divn(10000);
|
|
370
|
+
|
|
371
|
+
remainingCapacity = BN.min(
|
|
372
|
+
remainingCapacity,
|
|
373
|
+
BN.max(ZERO, maxTokenBorrows.sub(tokenBorrowAmount))
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
|
|
366
377
|
return { totalCapacity, remainingCapacity };
|
|
367
378
|
}
|
|
368
379
|
|
|
@@ -395,7 +406,10 @@ export function calculateInterestRate(
|
|
|
395
406
|
.div(SPOT_MARKET_UTILIZATION_PRECISION);
|
|
396
407
|
}
|
|
397
408
|
|
|
398
|
-
return
|
|
409
|
+
return BN.max(
|
|
410
|
+
interestRate,
|
|
411
|
+
new BN(bank.minBorrowRate).mul(PERCENTAGE_PRECISION.divn(200))
|
|
412
|
+
);
|
|
399
413
|
}
|
|
400
414
|
|
|
401
415
|
export function calculateDepositRate(
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
2
|
+
import { OracleClient, OraclePriceData } from './types';
|
|
3
|
+
import { AnchorProvider, BN, Program } from '@coral-xyz/anchor';
|
|
4
|
+
import {
|
|
5
|
+
ONE,
|
|
6
|
+
PRICE_PRECISION,
|
|
7
|
+
QUOTE_PRECISION,
|
|
8
|
+
TEN,
|
|
9
|
+
} from '../constants/numericConstants';
|
|
10
|
+
import {
|
|
11
|
+
PythSolanaReceiverProgram,
|
|
12
|
+
DEFAULT_RECEIVER_PROGRAM_ID,
|
|
13
|
+
pythSolanaReceiverIdl,
|
|
14
|
+
} from '@pythnetwork/pyth-solana-receiver';
|
|
15
|
+
import { PriceUpdateAccount } from '@pythnetwork/pyth-solana-receiver/lib/PythSolanaReceiver';
|
|
16
|
+
import { Wallet } from '..';
|
|
17
|
+
|
|
18
|
+
export class PythPullClient implements OracleClient {
|
|
19
|
+
private connection: Connection;
|
|
20
|
+
private multiple: BN;
|
|
21
|
+
private stableCoin: boolean;
|
|
22
|
+
readonly receiver: Program<PythSolanaReceiverProgram>;
|
|
23
|
+
readonly decodeFunc: (name: string, data: Buffer) => PriceUpdateAccount;
|
|
24
|
+
|
|
25
|
+
public constructor(
|
|
26
|
+
connection: Connection,
|
|
27
|
+
multiple = ONE,
|
|
28
|
+
stableCoin = false
|
|
29
|
+
) {
|
|
30
|
+
this.connection = connection;
|
|
31
|
+
this.multiple = multiple;
|
|
32
|
+
this.stableCoin = stableCoin;
|
|
33
|
+
const provider = new AnchorProvider(
|
|
34
|
+
this.connection,
|
|
35
|
+
//@ts-ignore
|
|
36
|
+
new Wallet(new Keypair()),
|
|
37
|
+
{
|
|
38
|
+
commitment: connection.commitment,
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
this.receiver = new Program<PythSolanaReceiverProgram>(
|
|
42
|
+
pythSolanaReceiverIdl as PythSolanaReceiverProgram,
|
|
43
|
+
DEFAULT_RECEIVER_PROGRAM_ID,
|
|
44
|
+
provider
|
|
45
|
+
);
|
|
46
|
+
this.decodeFunc =
|
|
47
|
+
this.receiver.account.priceUpdateV2.coder.accounts.decodeUnchecked.bind(
|
|
48
|
+
this.receiver.account.priceUpdateV2.coder.accounts
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public async getOraclePriceData(
|
|
53
|
+
pricePublicKey: PublicKey
|
|
54
|
+
): Promise<OraclePriceData> {
|
|
55
|
+
const accountInfo = await this.connection.getAccountInfo(pricePublicKey);
|
|
56
|
+
return this.getOraclePriceDataFromBuffer(accountInfo.data);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public getOraclePriceDataFromBuffer(buffer: Buffer): OraclePriceData {
|
|
60
|
+
const message = this.decodeFunc('priceUpdateV2', buffer);
|
|
61
|
+
const priceData = message.priceMessage;
|
|
62
|
+
const confidence = convertPythPrice(
|
|
63
|
+
priceData.conf,
|
|
64
|
+
priceData.exponent,
|
|
65
|
+
this.multiple
|
|
66
|
+
);
|
|
67
|
+
let price = convertPythPrice(
|
|
68
|
+
priceData.price,
|
|
69
|
+
priceData.exponent,
|
|
70
|
+
this.multiple
|
|
71
|
+
);
|
|
72
|
+
if (this.stableCoin) {
|
|
73
|
+
price = getStableCoinPrice(price, confidence);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
price,
|
|
78
|
+
slot: message.postedSlot,
|
|
79
|
+
confidence,
|
|
80
|
+
twap: convertPythPrice(
|
|
81
|
+
priceData.price,
|
|
82
|
+
priceData.exponent,
|
|
83
|
+
this.multiple
|
|
84
|
+
),
|
|
85
|
+
twapConfidence: convertPythPrice(
|
|
86
|
+
priceData.price,
|
|
87
|
+
priceData.exponent,
|
|
88
|
+
this.multiple
|
|
89
|
+
),
|
|
90
|
+
hasSufficientNumberOfDataPoints: true,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function convertPythPrice(
|
|
96
|
+
price: BN,
|
|
97
|
+
exponent: number,
|
|
98
|
+
multiple: BN
|
|
99
|
+
): BN {
|
|
100
|
+
exponent = Math.abs(exponent);
|
|
101
|
+
const pythPrecision = TEN.pow(new BN(exponent).abs()).div(multiple);
|
|
102
|
+
return price.mul(PRICE_PRECISION).div(pythPrecision);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const fiveBPS = new BN(500);
|
|
106
|
+
function getStableCoinPrice(price: BN, confidence: BN): BN {
|
|
107
|
+
if (price.sub(QUOTE_PRECISION).abs().lt(BN.min(confidence, fiveBPS))) {
|
|
108
|
+
return QUOTE_PRECISION;
|
|
109
|
+
} else {
|
|
110
|
+
return price;
|
|
111
|
+
}
|
|
112
|
+
}
|
package/src/tx/txHandler.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
BaseTxParams,
|
|
21
21
|
DriftClientMetricsEvents,
|
|
22
22
|
IWallet,
|
|
23
|
+
MappedRecord,
|
|
23
24
|
SignedTxData,
|
|
24
25
|
TxParams,
|
|
25
26
|
} from '../types';
|
|
@@ -160,6 +161,10 @@ export class TxHandler {
|
|
|
160
161
|
return (tx as VersionedTransaction)?.message && true;
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
private isLegacyTransaction(tx: Transaction | VersionedTransaction) {
|
|
165
|
+
return !this.isVersionedTransaction(tx);
|
|
166
|
+
}
|
|
167
|
+
|
|
163
168
|
private getTxSigFromSignedTx(signedTx: Transaction | VersionedTransaction) {
|
|
164
169
|
if (this.isVersionedTransaction(signedTx)) {
|
|
165
170
|
return bs58.encode(
|
|
@@ -266,7 +271,7 @@ export class TxHandler {
|
|
|
266
271
|
return;
|
|
267
272
|
}
|
|
268
273
|
|
|
269
|
-
const
|
|
274
|
+
const signedTxData = txData.map((tx) => {
|
|
270
275
|
const lastValidBlockHeight =
|
|
271
276
|
this.blockHashToLastValidBlockHeightLookup[tx.blockHash];
|
|
272
277
|
|
|
@@ -277,8 +282,10 @@ export class TxHandler {
|
|
|
277
282
|
});
|
|
278
283
|
|
|
279
284
|
if (this.onSignedCb) {
|
|
280
|
-
this.onSignedCb(
|
|
285
|
+
this.onSignedCb(signedTxData);
|
|
281
286
|
}
|
|
287
|
+
|
|
288
|
+
return signedTxData;
|
|
282
289
|
}
|
|
283
290
|
|
|
284
291
|
/**
|
|
@@ -373,8 +380,15 @@ export class TxHandler {
|
|
|
373
380
|
return tx;
|
|
374
381
|
}
|
|
375
382
|
|
|
376
|
-
public generateLegacyTransaction(
|
|
377
|
-
|
|
383
|
+
public generateLegacyTransaction(
|
|
384
|
+
ixs: TransactionInstruction[],
|
|
385
|
+
recentBlockhash?: BlockhashWithExpiryBlockHeight
|
|
386
|
+
) {
|
|
387
|
+
const tx = new Transaction().add(...ixs);
|
|
388
|
+
if (recentBlockhash) {
|
|
389
|
+
tx.recentBlockhash = recentBlockhash.blockhash;
|
|
390
|
+
}
|
|
391
|
+
return tx;
|
|
378
392
|
}
|
|
379
393
|
|
|
380
394
|
/**
|
|
@@ -484,7 +498,7 @@ export class TxHandler {
|
|
|
484
498
|
if (forceVersionedTransaction) {
|
|
485
499
|
return this.generateLegacyVersionedTransaction(recentBlockhash, allIx);
|
|
486
500
|
} else {
|
|
487
|
-
return this.generateLegacyTransaction(allIx);
|
|
501
|
+
return this.generateLegacyTransaction(allIx, recentBlockhash);
|
|
488
502
|
}
|
|
489
503
|
} else {
|
|
490
504
|
const marketLookupTable = await fetchMarketLookupTableAccount();
|
|
@@ -532,39 +546,6 @@ export class TxHandler {
|
|
|
532
546
|
return tx.add(instruction);
|
|
533
547
|
}
|
|
534
548
|
|
|
535
|
-
/**
|
|
536
|
-
* Build a map of transactions from an array of instructions for multiple transactions.
|
|
537
|
-
* @param txsToSign
|
|
538
|
-
* @param keys
|
|
539
|
-
* @param wallet
|
|
540
|
-
* @param commitment
|
|
541
|
-
* @returns
|
|
542
|
-
*/
|
|
543
|
-
public async buildTransactionMap(
|
|
544
|
-
txsToSign: (Transaction | undefined)[],
|
|
545
|
-
keys: string[],
|
|
546
|
-
wallet?: IWallet,
|
|
547
|
-
commitment?: Commitment,
|
|
548
|
-
recentBlockhash?: BlockhashWithExpiryBlockHeight
|
|
549
|
-
) {
|
|
550
|
-
recentBlockhash = recentBlockhash
|
|
551
|
-
? recentBlockhash
|
|
552
|
-
: await this.getLatestBlockhashForTransaction();
|
|
553
|
-
|
|
554
|
-
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
555
|
-
|
|
556
|
-
for (const tx of txsToSign) {
|
|
557
|
-
if (!tx) continue;
|
|
558
|
-
tx.recentBlockhash = recentBlockhash.blockhash;
|
|
559
|
-
tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
|
|
560
|
-
|
|
561
|
-
// @ts-ignore
|
|
562
|
-
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return this.getSignedTransactionMap(txsToSign, keys, wallet);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
549
|
/**
|
|
569
550
|
* Get a map of signed and prepared transactions from an array of legacy transactions
|
|
570
551
|
* @param txsToSign
|
|
@@ -573,9 +554,10 @@ export class TxHandler {
|
|
|
573
554
|
* @param commitment
|
|
574
555
|
* @returns
|
|
575
556
|
*/
|
|
576
|
-
public async getPreparedAndSignedLegacyTransactionMap
|
|
577
|
-
|
|
578
|
-
|
|
557
|
+
public async getPreparedAndSignedLegacyTransactionMap<
|
|
558
|
+
T extends Record<string, Transaction | undefined>,
|
|
559
|
+
>(
|
|
560
|
+
txsMap: T,
|
|
579
561
|
wallet?: IWallet,
|
|
580
562
|
commitment?: Commitment,
|
|
581
563
|
recentBlockhash?: BlockhashWithExpiryBlockHeight
|
|
@@ -586,7 +568,7 @@ export class TxHandler {
|
|
|
586
568
|
|
|
587
569
|
this.addHashAndExpiryToLookup(recentBlockhash);
|
|
588
570
|
|
|
589
|
-
for (const tx of
|
|
571
|
+
for (const tx of Object.values(txsMap)) {
|
|
590
572
|
if (!tx) continue;
|
|
591
573
|
tx.recentBlockhash = recentBlockhash.blockhash;
|
|
592
574
|
tx.feePayer = wallet?.publicKey ?? this.wallet?.publicKey;
|
|
@@ -595,7 +577,7 @@ export class TxHandler {
|
|
|
595
577
|
tx.SIGNATURE_BLOCK_AND_EXPIRY = recentBlockhash;
|
|
596
578
|
}
|
|
597
579
|
|
|
598
|
-
return this.getSignedTransactionMap(
|
|
580
|
+
return this.getSignedTransactionMap(txsMap, wallet);
|
|
599
581
|
}
|
|
600
582
|
|
|
601
583
|
/**
|
|
@@ -605,47 +587,49 @@ export class TxHandler {
|
|
|
605
587
|
* @param wallet
|
|
606
588
|
* @returns
|
|
607
589
|
*/
|
|
608
|
-
public async getSignedTransactionMap
|
|
609
|
-
|
|
610
|
-
|
|
590
|
+
public async getSignedTransactionMap<
|
|
591
|
+
T extends Record<string, Transaction | VersionedTransaction | undefined>,
|
|
592
|
+
>(
|
|
593
|
+
txsToSignMap: T,
|
|
611
594
|
wallet?: IWallet
|
|
612
595
|
): Promise<{
|
|
613
|
-
|
|
596
|
+
signedTxMap: T;
|
|
597
|
+
signedTxData: SignedTxData[];
|
|
614
598
|
}> {
|
|
615
599
|
[wallet] = this.getProps(wallet);
|
|
616
600
|
|
|
617
|
-
const
|
|
618
|
-
[key: string]: Transaction | VersionedTransaction | undefined;
|
|
619
|
-
} = {};
|
|
601
|
+
const txsToSignEntries = Object.entries(txsToSignMap);
|
|
620
602
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
603
|
+
// Create a map of the same keys as the input map, but with the values set to undefined. We'll populate the filtered (non-undefined) values with signed transactions.
|
|
604
|
+
const signedTxMap = txsToSignEntries.reduce((acc, [key]) => {
|
|
605
|
+
acc[key] = undefined;
|
|
606
|
+
return acc;
|
|
607
|
+
}, {}) as T;
|
|
608
|
+
|
|
609
|
+
const filteredTxEntries = txsToSignEntries.filter(([_, tx]) => !!tx);
|
|
610
|
+
|
|
611
|
+
// Extra handling for legacy transactions
|
|
612
|
+
for (const [_key, tx] of filteredTxEntries) {
|
|
613
|
+
if (this.isLegacyTransaction(tx)) {
|
|
614
|
+
(tx as Transaction).feePayer = wallet.publicKey;
|
|
627
615
|
}
|
|
628
|
-
}
|
|
616
|
+
}
|
|
629
617
|
|
|
630
618
|
this.preSignedCb?.();
|
|
631
619
|
|
|
632
|
-
const
|
|
633
|
-
.map((tx) =>
|
|
634
|
-
|
|
635
|
-
})
|
|
636
|
-
.filter((tx) => tx !== undefined);
|
|
637
|
-
|
|
638
|
-
const signedTxs = await wallet.signAllTransactions(filteredTxs);
|
|
620
|
+
const signedFilteredTxs = await wallet.signAllTransactions(
|
|
621
|
+
filteredTxEntries.map(([_, tx]) => tx as Transaction)
|
|
622
|
+
);
|
|
639
623
|
|
|
640
|
-
|
|
624
|
+
signedFilteredTxs.forEach((signedTx, index) => {
|
|
641
625
|
// @ts-ignore
|
|
642
626
|
signedTx.SIGNATURE_BLOCK_AND_EXPIRY =
|
|
643
627
|
// @ts-ignore
|
|
644
|
-
|
|
628
|
+
filteredTxEntries[index][1]?.SIGNATURE_BLOCK_AND_EXPIRY;
|
|
645
629
|
});
|
|
646
630
|
|
|
647
|
-
this.handleSignedTxData(
|
|
648
|
-
|
|
631
|
+
const signedTxData = this.handleSignedTxData(
|
|
632
|
+
signedFilteredTxs.map((signedTx) => {
|
|
649
633
|
return {
|
|
650
634
|
txSig: this.getTxSigFromSignedTx(signedTx),
|
|
651
635
|
signedTx,
|
|
@@ -654,11 +638,36 @@ export class TxHandler {
|
|
|
654
638
|
})
|
|
655
639
|
);
|
|
656
640
|
|
|
657
|
-
|
|
658
|
-
|
|
641
|
+
filteredTxEntries.forEach(([key], index) => {
|
|
642
|
+
const signedTx = signedFilteredTxs[index];
|
|
643
|
+
// @ts-ignore
|
|
644
|
+
signedTxMap[key] = signedTx;
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
return { signedTxMap, signedTxData };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Accepts multiple instructions and builds a transaction for each. Prevents needing to spam RPC with requests for the same blockhash.
|
|
652
|
+
* @param props
|
|
653
|
+
* @returns
|
|
654
|
+
*/
|
|
655
|
+
public async buildTransactionsMap<
|
|
656
|
+
T extends Record<string, TransactionInstruction | TransactionInstruction[]>,
|
|
657
|
+
>(
|
|
658
|
+
props: Omit<TxBuildingProps, 'instructions'> & {
|
|
659
|
+
instructionsMap: T;
|
|
660
|
+
}
|
|
661
|
+
): Promise<MappedRecord<T, Transaction | VersionedTransaction>> {
|
|
662
|
+
const builtTxs = await this.buildBulkTransactions({
|
|
663
|
+
...props,
|
|
664
|
+
instructions: Object.values(props.instructionsMap),
|
|
659
665
|
});
|
|
660
666
|
|
|
661
|
-
return
|
|
667
|
+
return Object.keys(props.instructionsMap).reduce((acc, key, index) => {
|
|
668
|
+
acc[key] = builtTxs[index];
|
|
669
|
+
return acc;
|
|
670
|
+
}, {}) as MappedRecord<T, Transaction | VersionedTransaction>;
|
|
662
671
|
}
|
|
663
672
|
|
|
664
673
|
/**
|
|
@@ -666,22 +675,22 @@ export class TxHandler {
|
|
|
666
675
|
* @param props
|
|
667
676
|
* @returns
|
|
668
677
|
*/
|
|
669
|
-
public async buildAndSignTransactionMap
|
|
678
|
+
public async buildAndSignTransactionMap<
|
|
679
|
+
T extends Record<string, TransactionInstruction | TransactionInstruction[]>,
|
|
680
|
+
>(
|
|
670
681
|
props: Omit<TxBuildingProps, 'instructions'> & {
|
|
671
|
-
|
|
672
|
-
instructions: (TransactionInstruction | TransactionInstruction[])[];
|
|
682
|
+
instructionsMap: T;
|
|
673
683
|
}
|
|
674
684
|
) {
|
|
675
|
-
const
|
|
685
|
+
const builtTxs = await this.buildTransactionsMap(props);
|
|
676
686
|
|
|
677
687
|
const preppedTransactions = await (props.txVersion === 'legacy'
|
|
678
688
|
? this.getPreparedAndSignedLegacyTransactionMap(
|
|
679
|
-
|
|
680
|
-
props.keys,
|
|
689
|
+
builtTxs as Record<string, Transaction>,
|
|
681
690
|
props.wallet,
|
|
682
691
|
props.preFlightCommitment
|
|
683
692
|
)
|
|
684
|
-
: this.getSignedTransactionMap(
|
|
693
|
+
: this.getSignedTransactionMap(builtTxs, props.wallet));
|
|
685
694
|
|
|
686
695
|
return preppedTransactions;
|
|
687
696
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { PublicKey, Transaction, VersionedTransaction } from '@solana/web3.js';
|
|
2
2
|
import { BN, ZERO } from '.';
|
|
3
3
|
|
|
4
|
+
// Utility type which lets you denote record with values of type A mapped to a record with the same keys but values of type B
|
|
5
|
+
export type MappedRecord<A extends Record<string, unknown>, B> = {
|
|
6
|
+
[K in keyof A]: B;
|
|
7
|
+
};
|
|
8
|
+
|
|
4
9
|
// # Utility Types / Enums / Constants
|
|
5
10
|
|
|
6
11
|
export enum ExchangeStatus {
|
|
@@ -103,9 +108,13 @@ export class OracleSource {
|
|
|
103
108
|
static readonly PYTH = { pyth: {} };
|
|
104
109
|
static readonly PYTH_1K = { pyth1K: {} };
|
|
105
110
|
static readonly PYTH_1M = { pyth1M: {} };
|
|
111
|
+
static readonly PYTH_PULL = { pythPull: {} };
|
|
112
|
+
static readonly PYTH_1K_PULL = { pyth1KPull: {} };
|
|
113
|
+
static readonly PYTH_1M_PULL = { pyth1MPull: {} };
|
|
106
114
|
static readonly SWITCHBOARD = { switchboard: {} };
|
|
107
115
|
static readonly QUOTE_ASSET = { quoteAsset: {} };
|
|
108
116
|
static readonly PYTH_STABLE_COIN = { pythStableCoin: {} };
|
|
117
|
+
static readonly PYTH_STABLE_COIN_PULL = { pythStableCoinPull: {} };
|
|
109
118
|
static readonly Prelaunch = { prelaunch: {} };
|
|
110
119
|
}
|
|
111
120
|
|
|
@@ -722,6 +731,9 @@ export type SpotMarketAccount = {
|
|
|
722
731
|
pausedOperations: number;
|
|
723
732
|
|
|
724
733
|
ifPausedOperations: number;
|
|
734
|
+
|
|
735
|
+
maxTokenBorrowsFraction: number;
|
|
736
|
+
minBorrowRate: number;
|
|
725
737
|
};
|
|
726
738
|
|
|
727
739
|
export type PoolBalance = {
|