@drift-labs/sdk 0.1.36-master.3 → 0.1.36-master.6
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/lib/accounts/bulkAccountLoader.d.ts +1 -0
- package/lib/accounts/bulkAccountLoader.js +4 -0
- package/lib/admin.js +1 -1
- package/lib/clearingHouse.d.ts +6 -4
- package/lib/clearingHouse.js +46 -8
- package/lib/examples/makeTradeExample.js +1 -1
- package/lib/factory/clearingHouse.js +4 -4
- package/lib/idl/clearing_house.json +72 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/math/oracles.d.ts +3 -0
- package/lib/math/oracles.js +26 -0
- package/lib/math/trade.d.ts +10 -6
- package/lib/math/trade.js +68 -13
- package/lib/mockUSDCFaucet.d.ts +2 -2
- package/lib/mockUSDCFaucet.js +3 -3
- package/lib/oracles/pythClient.js +1 -0
- package/lib/oracles/switchboardClient.js +4 -1
- package/lib/oracles/types.d.ts +1 -0
- package/lib/tx/defaultTxSender.d.ts +3 -3
- package/lib/tx/defaultTxSender.js +1 -1
- package/lib/tx/retryTxSender.d.ts +3 -3
- package/package.json +2 -2
- package/src/accounts/bulkAccountLoader.ts +5 -0
- package/src/accounts/webSocketAccountSubscriber.ts +3 -3
- package/src/admin.ts +2 -2
- package/src/clearingHouse.ts +81 -10
- package/src/examples/makeTradeExample.ts +6 -2
- package/src/factory/clearingHouse.ts +13 -5
- package/src/idl/clearing_house.json +72 -1
- package/src/index.ts +1 -0
- package/src/math/oracles.ts +36 -0
- package/src/math/trade.ts +84 -16
- package/src/mockUSDCFaucet.ts +5 -5
- package/src/oracles/pythClient.ts +1 -0
- package/src/oracles/switchboardClient.ts +7 -2
- package/src/oracles/types.ts +1 -0
- package/src/tx/defaultTxSender.ts +4 -4
- package/src/tx/retryTxSender.ts +3 -3
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { TxSender } from './types';
|
|
3
3
|
import { Commitment, ConfirmOptions, RpcResponseAndContext, Signer, SignatureResult, Transaction, TransactionSignature, Connection } from '@solana/web3.js';
|
|
4
|
-
import {
|
|
4
|
+
import { AnchorProvider } from '@project-serum/anchor';
|
|
5
5
|
declare type ResolveReference = {
|
|
6
6
|
resolve?: () => void;
|
|
7
7
|
};
|
|
8
8
|
export declare class RetryTxSender implements TxSender {
|
|
9
|
-
provider:
|
|
9
|
+
provider: AnchorProvider;
|
|
10
10
|
timeout: number;
|
|
11
11
|
retrySleep: number;
|
|
12
12
|
additionalConnections: Connection[];
|
|
13
|
-
constructor(provider:
|
|
13
|
+
constructor(provider: AnchorProvider, timeout?: number, retrySleep?: number, additionalConnections?: Connection[]);
|
|
14
14
|
send(tx: Transaction, additionalSigners?: Array<Signer>, opts?: ConfirmOptions): Promise<TransactionSignature>;
|
|
15
15
|
prepareTx(tx: Transaction, additionalSigners: Array<Signer>, opts: ConfirmOptions): Promise<Transaction>;
|
|
16
16
|
confirmTransaction(signature: TransactionSignature, commitment?: Commitment): Promise<RpcResponseAndContext<SignatureResult>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drift-labs/sdk",
|
|
3
|
-
"version": "0.1.36-master.
|
|
3
|
+
"version": "0.1.36-master.6",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"author": "crispheaney",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"access": "public"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@project-serum/anchor": "0.
|
|
31
|
+
"@project-serum/anchor": "0.24.2",
|
|
32
32
|
"@pythnetwork/client": "^2.5.1",
|
|
33
33
|
"@solana/spl-token": "^0.1.6",
|
|
34
34
|
"@solana/web3.js": "^1.22.0",
|
|
@@ -24,6 +24,7 @@ export class BulkAccountLoader {
|
|
|
24
24
|
loadPromise?: Promise<void>;
|
|
25
25
|
loadPromiseResolver: () => void;
|
|
26
26
|
lastTimeLoadingPromiseCleared = Date.now();
|
|
27
|
+
mostRecentSlot = 0;
|
|
27
28
|
|
|
28
29
|
public constructor(
|
|
29
30
|
connection: Connection,
|
|
@@ -159,6 +160,10 @@ export class BulkAccountLoader {
|
|
|
159
160
|
|
|
160
161
|
const newSlot = rpcResponse.result.context.slot;
|
|
161
162
|
|
|
163
|
+
if (newSlot > this.mostRecentSlot) {
|
|
164
|
+
this.mostRecentSlot = newSlot;
|
|
165
|
+
}
|
|
166
|
+
|
|
162
167
|
for (const i in accountsToLoad) {
|
|
163
168
|
const accountToLoad = accountsToLoad[i];
|
|
164
169
|
const key = accountToLoad.publicKey.toString();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AccountData, AccountSubscriber } from './types';
|
|
2
|
-
import { Program } from '@project-serum/anchor';
|
|
2
|
+
import { AnchorProvider, Program } from '@project-serum/anchor';
|
|
3
3
|
import { AccountInfo, Context, PublicKey } from '@solana/web3.js';
|
|
4
4
|
import { capitalize } from './utils';
|
|
5
5
|
import * as Buffer from 'buffer';
|
|
@@ -36,7 +36,7 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
36
36
|
(accountInfo, context) => {
|
|
37
37
|
this.handleRpcResponse(context, accountInfo);
|
|
38
38
|
},
|
|
39
|
-
this.program.provider.opts.commitment
|
|
39
|
+
(this.program.provider as AnchorProvider).opts.commitment
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ export class WebSocketAccountSubscriber<T> implements AccountSubscriber<T> {
|
|
|
44
44
|
const rpcResponse =
|
|
45
45
|
await this.program.provider.connection.getAccountInfoAndContext(
|
|
46
46
|
this.accountPublicKey,
|
|
47
|
-
this.program.provider.opts.commitment
|
|
47
|
+
(this.program.provider as AnchorProvider).opts.commitment
|
|
48
48
|
);
|
|
49
49
|
this.handleRpcResponse(rpcResponse.context, rpcResponse?.value);
|
|
50
50
|
}
|
package/src/admin.ts
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
OracleSource,
|
|
13
13
|
OrderFillerRewardStructure,
|
|
14
14
|
} from './types';
|
|
15
|
-
import { BN,
|
|
15
|
+
import { BN, AnchorProvider } from '@project-serum/anchor';
|
|
16
16
|
import * as anchor from '@project-serum/anchor';
|
|
17
17
|
import {
|
|
18
18
|
getClearingHouseStateAccountPublicKey,
|
|
@@ -34,7 +34,7 @@ export class Admin extends ClearingHouse {
|
|
|
34
34
|
connection: Connection,
|
|
35
35
|
wallet: IWallet,
|
|
36
36
|
clearingHouseProgramId: PublicKey,
|
|
37
|
-
opts: ConfirmOptions =
|
|
37
|
+
opts: ConfirmOptions = AnchorProvider.defaultOptions()
|
|
38
38
|
): Admin {
|
|
39
39
|
const config = getWebSocketClearingHouseConfig(
|
|
40
40
|
connection,
|
package/src/clearingHouse.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BN, Idl, Program
|
|
1
|
+
import { AnchorProvider, BN, Idl, Program } from '@project-serum/anchor';
|
|
2
2
|
import {
|
|
3
3
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
4
4
|
Token,
|
|
@@ -71,7 +71,7 @@ export class ClearingHouse {
|
|
|
71
71
|
connection: Connection;
|
|
72
72
|
wallet: IWallet;
|
|
73
73
|
public program: Program;
|
|
74
|
-
provider:
|
|
74
|
+
provider: AnchorProvider;
|
|
75
75
|
opts?: ConfirmOptions;
|
|
76
76
|
accountSubscriber: ClearingHouseAccountSubscriber;
|
|
77
77
|
eventEmitter: StrictEventEmitter<EventEmitter, ClearingHouseAccountEvents>;
|
|
@@ -98,7 +98,7 @@ export class ClearingHouse {
|
|
|
98
98
|
connection: Connection,
|
|
99
99
|
wallet: IWallet,
|
|
100
100
|
clearingHouseProgramId: PublicKey,
|
|
101
|
-
opts: ConfirmOptions =
|
|
101
|
+
opts: ConfirmOptions = AnchorProvider.defaultOptions()
|
|
102
102
|
): ClearingHouse {
|
|
103
103
|
const config = getWebSocketClearingHouseConfig(
|
|
104
104
|
connection,
|
|
@@ -245,7 +245,11 @@ export class ClearingHouse {
|
|
|
245
245
|
* @param newWallet
|
|
246
246
|
*/
|
|
247
247
|
public updateWallet(newWallet: IWallet): void {
|
|
248
|
-
const newProvider = new
|
|
248
|
+
const newProvider = new AnchorProvider(
|
|
249
|
+
this.connection,
|
|
250
|
+
newWallet,
|
|
251
|
+
this.opts
|
|
252
|
+
);
|
|
249
253
|
const newProgram = new Program(
|
|
250
254
|
clearingHouseIDL as Idl,
|
|
251
255
|
this.program.programId,
|
|
@@ -503,7 +507,7 @@ export class ClearingHouse {
|
|
|
503
507
|
.add(initializeUserOrdersAccountIx)
|
|
504
508
|
.add(depositCollateralIx);
|
|
505
509
|
|
|
506
|
-
const txSig = await this.
|
|
510
|
+
const txSig = await this.txSender.send(tx, [userPositionsAccount]);
|
|
507
511
|
|
|
508
512
|
return [txSig, userAccountPublicKey];
|
|
509
513
|
}
|
|
@@ -538,7 +542,9 @@ export class ClearingHouse {
|
|
|
538
542
|
.add(initializeUserOrdersAccountIx)
|
|
539
543
|
.add(depositCollateralIx);
|
|
540
544
|
|
|
541
|
-
const txSig = await this.program.provider.
|
|
545
|
+
const txSig = await this.program.provider.sendAndConfirm(tx, [
|
|
546
|
+
userPositionsAccount,
|
|
547
|
+
]);
|
|
542
548
|
|
|
543
549
|
return [txSig, userAccountPublicKey];
|
|
544
550
|
}
|
|
@@ -911,17 +917,19 @@ export class ClearingHouse {
|
|
|
911
917
|
}
|
|
912
918
|
|
|
913
919
|
public async cancelAllOrders(
|
|
914
|
-
oracles?: PublicKey[]
|
|
920
|
+
oracles?: PublicKey[],
|
|
921
|
+
bestEffort?: boolean
|
|
915
922
|
): Promise<TransactionSignature> {
|
|
916
923
|
return await this.txSender.send(
|
|
917
|
-
wrapInTx(await this.getCancelAllOrdersIx(oracles)),
|
|
924
|
+
wrapInTx(await this.getCancelAllOrdersIx(oracles, bestEffort)),
|
|
918
925
|
[],
|
|
919
926
|
this.opts
|
|
920
927
|
);
|
|
921
928
|
}
|
|
922
929
|
|
|
923
930
|
public async getCancelAllOrdersIx(
|
|
924
|
-
oracles: PublicKey[]
|
|
931
|
+
oracles: PublicKey[],
|
|
932
|
+
bestEffort?: boolean
|
|
925
933
|
): Promise<TransactionInstruction> {
|
|
926
934
|
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
927
935
|
const userAccount = await this.getUserAccount();
|
|
@@ -938,7 +946,7 @@ export class ClearingHouse {
|
|
|
938
946
|
});
|
|
939
947
|
}
|
|
940
948
|
|
|
941
|
-
return await this.program.instruction.cancelAllOrders({
|
|
949
|
+
return await this.program.instruction.cancelAllOrders(bestEffort, {
|
|
942
950
|
accounts: {
|
|
943
951
|
state: await this.getStatePublicKey(),
|
|
944
952
|
user: userAccountPublicKey,
|
|
@@ -955,6 +963,69 @@ export class ClearingHouse {
|
|
|
955
963
|
});
|
|
956
964
|
}
|
|
957
965
|
|
|
966
|
+
public async cancelOrdersByMarketAndSide(
|
|
967
|
+
oracles?: PublicKey[],
|
|
968
|
+
bestEffort?: boolean,
|
|
969
|
+
marketIndexOnly?: BN,
|
|
970
|
+
directionOnly?: PositionDirection
|
|
971
|
+
): Promise<TransactionSignature> {
|
|
972
|
+
return await this.txSender.send(
|
|
973
|
+
wrapInTx(
|
|
974
|
+
await this.getCancelOrdersByMarketAndSideIx(
|
|
975
|
+
oracles,
|
|
976
|
+
bestEffort,
|
|
977
|
+
marketIndexOnly,
|
|
978
|
+
directionOnly
|
|
979
|
+
)
|
|
980
|
+
),
|
|
981
|
+
[],
|
|
982
|
+
this.opts
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
public async getCancelOrdersByMarketAndSideIx(
|
|
987
|
+
oracles: PublicKey[],
|
|
988
|
+
bestEffort?: boolean,
|
|
989
|
+
marketIndexOnly?: BN,
|
|
990
|
+
directionOnly?: PositionDirection
|
|
991
|
+
): Promise<TransactionInstruction> {
|
|
992
|
+
const userAccountPublicKey = await this.getUserAccountPublicKey();
|
|
993
|
+
const userAccount = await this.getUserAccount();
|
|
994
|
+
|
|
995
|
+
const state = this.getStateAccount();
|
|
996
|
+
const orderState = this.getOrderStateAccount();
|
|
997
|
+
|
|
998
|
+
const remainingAccounts = [];
|
|
999
|
+
for (const oracle of oracles) {
|
|
1000
|
+
remainingAccounts.push({
|
|
1001
|
+
pubkey: oracle,
|
|
1002
|
+
isWritable: false,
|
|
1003
|
+
isSigner: false,
|
|
1004
|
+
});
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
return await this.program.instruction.cancelOrdersByMarketAndSide(
|
|
1008
|
+
bestEffort,
|
|
1009
|
+
marketIndexOnly,
|
|
1010
|
+
directionOnly,
|
|
1011
|
+
{
|
|
1012
|
+
accounts: {
|
|
1013
|
+
state: await this.getStatePublicKey(),
|
|
1014
|
+
user: userAccountPublicKey,
|
|
1015
|
+
authority: this.wallet.publicKey,
|
|
1016
|
+
markets: state.markets,
|
|
1017
|
+
userOrders: await this.getUserOrdersAccountPublicKey(),
|
|
1018
|
+
userPositions: userAccount.positions,
|
|
1019
|
+
fundingPaymentHistory: state.fundingPaymentHistory,
|
|
1020
|
+
fundingRateHistory: state.fundingRateHistory,
|
|
1021
|
+
orderState: await this.getOrderStatePublicKey(),
|
|
1022
|
+
orderHistory: orderState.orderHistory,
|
|
1023
|
+
},
|
|
1024
|
+
remainingAccounts,
|
|
1025
|
+
}
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
958
1029
|
public async fillOrder(
|
|
959
1030
|
userAccountPublicKey: PublicKey,
|
|
960
1031
|
userOrdersAccountPublicKey: PublicKey,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnchorProvider, BN } from '@project-serum/anchor';
|
|
2
2
|
import { Wallet } from '..';
|
|
3
3
|
import { Token, TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
|
4
4
|
import { Connection, Keypair, PublicKey } from '@solana/web3.js';
|
|
@@ -43,7 +43,11 @@ const main = async () => {
|
|
|
43
43
|
const connection = new Connection(rpcAddress);
|
|
44
44
|
|
|
45
45
|
// Set up the Provider
|
|
46
|
-
const provider = new
|
|
46
|
+
const provider = new AnchorProvider(
|
|
47
|
+
connection,
|
|
48
|
+
wallet,
|
|
49
|
+
AnchorProvider.defaultOptions()
|
|
50
|
+
);
|
|
47
51
|
|
|
48
52
|
// Check SOL Balance
|
|
49
53
|
const lamportsBalance = await connection.getBalance(wallet.publicKey);
|
|
@@ -2,7 +2,7 @@ import { ConfirmOptions, Connection, PublicKey } from '@solana/web3.js';
|
|
|
2
2
|
import { IWallet } from '../types';
|
|
3
3
|
import { BulkAccountLoader } from '../accounts/bulkAccountLoader';
|
|
4
4
|
import { TxSender } from '../tx/types';
|
|
5
|
-
import { Idl, Program
|
|
5
|
+
import { AnchorProvider, Idl, Program } from '@project-serum/anchor';
|
|
6
6
|
import { ClearingHouse } from '../clearingHouse';
|
|
7
7
|
import clearingHouseIDL from '../idl/clearing_house.json';
|
|
8
8
|
import { WebSocketClearingHouseAccountSubscriber } from '../accounts/webSocketClearingHouseAccountSubscriber';
|
|
@@ -53,7 +53,7 @@ export function getWebSocketClearingHouseConfig(
|
|
|
53
53
|
connection: Connection,
|
|
54
54
|
wallet: IWallet,
|
|
55
55
|
programID: PublicKey,
|
|
56
|
-
opts: ConfirmOptions =
|
|
56
|
+
opts: ConfirmOptions = AnchorProvider.defaultOptions(),
|
|
57
57
|
txSenderConfig?: TxSenderConfig
|
|
58
58
|
): WebSocketClearingHouseConfiguration {
|
|
59
59
|
return {
|
|
@@ -71,7 +71,7 @@ export function getPollingClearingHouseConfig(
|
|
|
71
71
|
wallet: IWallet,
|
|
72
72
|
programID: PublicKey,
|
|
73
73
|
accountLoader: BulkAccountLoader,
|
|
74
|
-
opts: ConfirmOptions =
|
|
74
|
+
opts: ConfirmOptions = AnchorProvider.defaultOptions(),
|
|
75
75
|
txSenderConfig?: TxSenderConfig
|
|
76
76
|
): PollingClearingHouseConfiguration {
|
|
77
77
|
return {
|
|
@@ -86,7 +86,11 @@ export function getPollingClearingHouseConfig(
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export function getClearingHouse(config: ClearingHouseConfig): ClearingHouse {
|
|
89
|
-
const provider = new
|
|
89
|
+
const provider = new AnchorProvider(
|
|
90
|
+
config.connection,
|
|
91
|
+
config.wallet,
|
|
92
|
+
config.opts
|
|
93
|
+
);
|
|
90
94
|
const program = new Program(
|
|
91
95
|
clearingHouseIDL as Idl,
|
|
92
96
|
config.programID,
|
|
@@ -126,7 +130,11 @@ export function getClearingHouse(config: ClearingHouseConfig): ClearingHouse {
|
|
|
126
130
|
}
|
|
127
131
|
|
|
128
132
|
export function getAdmin(config: ClearingHouseConfig): Admin {
|
|
129
|
-
const provider = new
|
|
133
|
+
const provider = new AnchorProvider(
|
|
134
|
+
config.connection,
|
|
135
|
+
config.wallet,
|
|
136
|
+
config.opts
|
|
137
|
+
);
|
|
130
138
|
const program = new Program(
|
|
131
139
|
clearingHouseIDL as Idl,
|
|
132
140
|
config.programID,
|
|
@@ -726,7 +726,78 @@
|
|
|
726
726
|
"isSigner": false
|
|
727
727
|
}
|
|
728
728
|
],
|
|
729
|
-
"args": [
|
|
729
|
+
"args": [
|
|
730
|
+
{
|
|
731
|
+
"name": "bestEffort",
|
|
732
|
+
"type": "bool"
|
|
733
|
+
}
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
"name": "cancelOrdersByMarketAndSide",
|
|
738
|
+
"accounts": [
|
|
739
|
+
{
|
|
740
|
+
"name": "state",
|
|
741
|
+
"isMut": false,
|
|
742
|
+
"isSigner": false
|
|
743
|
+
},
|
|
744
|
+
{
|
|
745
|
+
"name": "orderState",
|
|
746
|
+
"isMut": false,
|
|
747
|
+
"isSigner": false
|
|
748
|
+
},
|
|
749
|
+
{
|
|
750
|
+
"name": "user",
|
|
751
|
+
"isMut": false,
|
|
752
|
+
"isSigner": false
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"name": "authority",
|
|
756
|
+
"isMut": false,
|
|
757
|
+
"isSigner": true
|
|
758
|
+
},
|
|
759
|
+
{
|
|
760
|
+
"name": "markets",
|
|
761
|
+
"isMut": false,
|
|
762
|
+
"isSigner": false
|
|
763
|
+
},
|
|
764
|
+
{
|
|
765
|
+
"name": "userPositions",
|
|
766
|
+
"isMut": true,
|
|
767
|
+
"isSigner": false
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
"name": "userOrders",
|
|
771
|
+
"isMut": true,
|
|
772
|
+
"isSigner": false
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
"name": "fundingPaymentHistory",
|
|
776
|
+
"isMut": true,
|
|
777
|
+
"isSigner": false
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
"name": "orderHistory",
|
|
781
|
+
"isMut": true,
|
|
782
|
+
"isSigner": false
|
|
783
|
+
}
|
|
784
|
+
],
|
|
785
|
+
"args": [
|
|
786
|
+
{
|
|
787
|
+
"name": "bestEffort",
|
|
788
|
+
"type": "bool"
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"name": "marketIndexOnly",
|
|
792
|
+
"type": "u64"
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
"name": "directionOnly",
|
|
796
|
+
"type": {
|
|
797
|
+
"defined": "PositionDirection"
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
]
|
|
730
801
|
},
|
|
731
802
|
{
|
|
732
803
|
"name": "expireOrders",
|
package/src/index.ts
CHANGED
|
@@ -26,6 +26,7 @@ export * from './math/funding';
|
|
|
26
26
|
export * from './math/insuranceFund';
|
|
27
27
|
export * from './math/market';
|
|
28
28
|
export * from './math/position';
|
|
29
|
+
export * from './math/oracles';
|
|
29
30
|
export * from './math/amm';
|
|
30
31
|
export * from './math/trade';
|
|
31
32
|
export * from './math/orders';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AMM, OracleGuardRails } from '../types';
|
|
2
|
+
import { OraclePriceData } from '../oracles/types';
|
|
3
|
+
import { ONE, ZERO } from '../constants/numericConstants';
|
|
4
|
+
import { BN } from '../index';
|
|
5
|
+
|
|
6
|
+
export function isOracleValid(
|
|
7
|
+
amm: AMM,
|
|
8
|
+
oraclePriceData: OraclePriceData,
|
|
9
|
+
oracleGuardRails: OracleGuardRails,
|
|
10
|
+
slot: number
|
|
11
|
+
): boolean {
|
|
12
|
+
const isOraclePriceNonPositive = oraclePriceData.price.lt(ZERO);
|
|
13
|
+
const isOraclePriceTooVolatile =
|
|
14
|
+
oraclePriceData.price
|
|
15
|
+
.div(BN.max(ONE, amm.lastOraclePriceTwap))
|
|
16
|
+
.gt(oracleGuardRails.validity.tooVolatileRatio) ||
|
|
17
|
+
amm.lastOraclePriceTwap
|
|
18
|
+
.div(BN.max(ONE, oraclePriceData.price))
|
|
19
|
+
.gt(oracleGuardRails.validity.tooVolatileRatio);
|
|
20
|
+
|
|
21
|
+
const isConfidenceTooLarge = oraclePriceData.price
|
|
22
|
+
.div(BN.max(ONE, oraclePriceData.confidence))
|
|
23
|
+
.lt(oracleGuardRails.validity.confidenceIntervalMaxSize);
|
|
24
|
+
|
|
25
|
+
const oracleIsStale = oraclePriceData.slot
|
|
26
|
+
.sub(new BN(slot))
|
|
27
|
+
.gt(oracleGuardRails.validity.slotsBeforeStale);
|
|
28
|
+
|
|
29
|
+
return !(
|
|
30
|
+
!oraclePriceData.hasSufficientNumberOfDataPoints ||
|
|
31
|
+
oracleIsStale ||
|
|
32
|
+
isOraclePriceNonPositive ||
|
|
33
|
+
isOraclePriceTooVolatile ||
|
|
34
|
+
isConfidenceTooLarge
|
|
35
|
+
);
|
|
36
|
+
}
|
package/src/math/trade.ts
CHANGED
|
@@ -7,7 +7,11 @@ import {
|
|
|
7
7
|
AMM_TO_QUOTE_PRECISION_RATIO,
|
|
8
8
|
ZERO,
|
|
9
9
|
} from '../constants/numericConstants';
|
|
10
|
-
import {
|
|
10
|
+
import {
|
|
11
|
+
calculateBidPrice,
|
|
12
|
+
calculateAskPrice,
|
|
13
|
+
calculateMarkPrice,
|
|
14
|
+
} from './market';
|
|
11
15
|
import {
|
|
12
16
|
calculateAmmReservesAfterSwap,
|
|
13
17
|
calculatePrice,
|
|
@@ -16,6 +20,7 @@ import {
|
|
|
16
20
|
calculateSpreadReserves,
|
|
17
21
|
} from './amm';
|
|
18
22
|
import { squareRootBN } from './utils';
|
|
23
|
+
import { isVariant } from '../types';
|
|
19
24
|
|
|
20
25
|
const MAXPCT = new BN(1000); //percentage units are [0,1000] => [0,1]
|
|
21
26
|
|
|
@@ -37,6 +42,8 @@ export type PriceImpactUnit =
|
|
|
37
42
|
* @param direction
|
|
38
43
|
* @param amount
|
|
39
44
|
* @param market
|
|
45
|
+
* @param inputAssetType which asset is being traded
|
|
46
|
+
* @param useSpread whether to consider spread with calculating slippage
|
|
40
47
|
* @return [pctAvgSlippage, pctMaxSlippage, entryPrice, newPrice]
|
|
41
48
|
*
|
|
42
49
|
* 'pctAvgSlippage' => the percentage change to entryPrice (average est slippage in execution) : Precision MARK_PRICE_PRECISION
|
|
@@ -51,9 +58,20 @@ export function calculateTradeSlippage(
|
|
|
51
58
|
direction: PositionDirection,
|
|
52
59
|
amount: BN,
|
|
53
60
|
market: Market,
|
|
54
|
-
inputAssetType: AssetType = 'quote'
|
|
61
|
+
inputAssetType: AssetType = 'quote',
|
|
62
|
+
useSpread = true
|
|
55
63
|
): [BN, BN, BN, BN] {
|
|
56
|
-
|
|
64
|
+
let oldPrice: BN;
|
|
65
|
+
|
|
66
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
67
|
+
if (isVariant(direction, 'long')) {
|
|
68
|
+
oldPrice = calculateAskPrice(market);
|
|
69
|
+
} else {
|
|
70
|
+
oldPrice = calculateBidPrice(market);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
oldPrice = calculateMarkPrice(market);
|
|
74
|
+
}
|
|
57
75
|
if (amount.eq(ZERO)) {
|
|
58
76
|
return [ZERO, ZERO, oldPrice, oldPrice];
|
|
59
77
|
}
|
|
@@ -61,7 +79,8 @@ export function calculateTradeSlippage(
|
|
|
61
79
|
direction,
|
|
62
80
|
amount,
|
|
63
81
|
market,
|
|
64
|
-
inputAssetType
|
|
82
|
+
inputAssetType,
|
|
83
|
+
useSpread
|
|
65
84
|
);
|
|
66
85
|
|
|
67
86
|
const entryPrice = calculatePrice(
|
|
@@ -70,10 +89,26 @@ export function calculateTradeSlippage(
|
|
|
70
89
|
market.amm.pegMultiplier
|
|
71
90
|
).mul(new BN(-1));
|
|
72
91
|
|
|
92
|
+
let amm: Parameters<typeof calculateAmmReservesAfterSwap>[0];
|
|
93
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
94
|
+
const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
|
|
95
|
+
market.amm,
|
|
96
|
+
direction
|
|
97
|
+
);
|
|
98
|
+
amm = {
|
|
99
|
+
baseAssetReserve,
|
|
100
|
+
quoteAssetReserve,
|
|
101
|
+
sqrtK: market.amm.sqrtK,
|
|
102
|
+
pegMultiplier: market.amm.pegMultiplier,
|
|
103
|
+
};
|
|
104
|
+
} else {
|
|
105
|
+
amm = market.amm;
|
|
106
|
+
}
|
|
107
|
+
|
|
73
108
|
const newPrice = calculatePrice(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
109
|
+
amm.baseAssetReserve.sub(acquiredBase),
|
|
110
|
+
amm.quoteAssetReserve.sub(acquiredQuote),
|
|
111
|
+
amm.pegMultiplier
|
|
77
112
|
);
|
|
78
113
|
|
|
79
114
|
if (direction == PositionDirection.SHORT) {
|
|
@@ -104,7 +139,7 @@ export function calculateTradeSlippage(
|
|
|
104
139
|
* @param inputAssetType
|
|
105
140
|
* @param useSpread
|
|
106
141
|
* @return
|
|
107
|
-
* | 'acquiredBase' => positive/negative change in user's base : BN
|
|
142
|
+
* | 'acquiredBase' => positive/negative change in user's base : BN AMM_RESERVE_PRECISION
|
|
108
143
|
* | 'acquiredQuote' => positive/negative change in user's quote : BN TODO-PRECISION
|
|
109
144
|
*/
|
|
110
145
|
export function calculateTradeAcquiredAmounts(
|
|
@@ -150,43 +185,63 @@ export function calculateTradeAcquiredAmounts(
|
|
|
150
185
|
* @param market
|
|
151
186
|
* @param targetPrice
|
|
152
187
|
* @param pct optional default is 100% gap filling, can set smaller.
|
|
188
|
+
* @param outputAssetType which asset to trade.
|
|
189
|
+
* @param useSpread whether or not to consider the spread when calculating the trade size
|
|
153
190
|
* @returns trade direction/size in order to push price to a targetPrice,
|
|
154
191
|
*
|
|
155
192
|
* [
|
|
156
|
-
* direction => direction of trade required,
|
|
193
|
+
* direction => direction of trade required, PositionDirection
|
|
157
194
|
* tradeSize => size of trade required, TODO-PRECISION
|
|
158
|
-
* entryPrice => the entry price for the trade,
|
|
159
|
-
* targetPrice => the target price
|
|
195
|
+
* entryPrice => the entry price for the trade, MARK_PRICE_PRECISION
|
|
196
|
+
* targetPrice => the target price MARK_PRICE_PRECISION
|
|
160
197
|
* ]
|
|
161
198
|
*/
|
|
162
199
|
export function calculateTargetPriceTrade(
|
|
163
200
|
market: Market,
|
|
164
201
|
targetPrice: BN,
|
|
165
202
|
pct: BN = MAXPCT,
|
|
166
|
-
outputAssetType: AssetType = 'quote'
|
|
203
|
+
outputAssetType: AssetType = 'quote',
|
|
204
|
+
useSpread = true
|
|
167
205
|
): [PositionDirection, BN, BN, BN] {
|
|
168
206
|
assert(market.amm.baseAssetReserve.gt(ZERO));
|
|
169
207
|
assert(targetPrice.gt(ZERO));
|
|
170
208
|
assert(pct.lte(MAXPCT) && pct.gt(ZERO));
|
|
171
209
|
|
|
172
210
|
const markPriceBefore = calculateMarkPrice(market);
|
|
211
|
+
const bidPriceBefore = calculateBidPrice(market);
|
|
212
|
+
const askPriceBefore = calculateAskPrice(market);
|
|
173
213
|
|
|
214
|
+
let direction;
|
|
174
215
|
if (targetPrice.gt(markPriceBefore)) {
|
|
175
216
|
const priceGap = targetPrice.sub(markPriceBefore);
|
|
176
217
|
const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
|
|
177
218
|
targetPrice = markPriceBefore.add(priceGapScaled);
|
|
219
|
+
direction = PositionDirection.LONG;
|
|
178
220
|
} else {
|
|
179
221
|
const priceGap = markPriceBefore.sub(targetPrice);
|
|
180
222
|
const priceGapScaled = priceGap.mul(pct).div(MAXPCT);
|
|
181
223
|
targetPrice = markPriceBefore.sub(priceGapScaled);
|
|
224
|
+
direction = PositionDirection.SHORT;
|
|
182
225
|
}
|
|
183
226
|
|
|
184
|
-
let direction;
|
|
185
227
|
let tradeSize;
|
|
186
228
|
let baseSize;
|
|
187
229
|
|
|
188
|
-
|
|
189
|
-
|
|
230
|
+
let baseAssetReserveBefore: BN;
|
|
231
|
+
let quoteAssetReserveBefore: BN;
|
|
232
|
+
|
|
233
|
+
if (useSpread && market.amm.baseSpread > 0) {
|
|
234
|
+
const { baseAssetReserve, quoteAssetReserve } = calculateSpreadReserves(
|
|
235
|
+
market.amm,
|
|
236
|
+
direction
|
|
237
|
+
);
|
|
238
|
+
baseAssetReserveBefore = baseAssetReserve;
|
|
239
|
+
quoteAssetReserveBefore = quoteAssetReserve;
|
|
240
|
+
} else {
|
|
241
|
+
baseAssetReserveBefore = market.amm.baseAssetReserve;
|
|
242
|
+
quoteAssetReserveBefore = market.amm.quoteAssetReserve;
|
|
243
|
+
}
|
|
244
|
+
|
|
190
245
|
const peg = market.amm.pegMultiplier;
|
|
191
246
|
const invariant = market.amm.sqrtK.mul(market.amm.sqrtK);
|
|
192
247
|
const k = invariant.mul(MARK_PRICE_PRECISION);
|
|
@@ -196,7 +251,20 @@ export function calculateTargetPriceTrade(
|
|
|
196
251
|
const biasModifier = new BN(1);
|
|
197
252
|
let markPriceAfter;
|
|
198
253
|
|
|
199
|
-
if (
|
|
254
|
+
if (
|
|
255
|
+
useSpread &&
|
|
256
|
+
targetPrice.lt(askPriceBefore) &&
|
|
257
|
+
targetPrice.gt(bidPriceBefore)
|
|
258
|
+
) {
|
|
259
|
+
// no trade, market is at target
|
|
260
|
+
if (markPriceBefore.gt(targetPrice)) {
|
|
261
|
+
direction = PositionDirection.SHORT;
|
|
262
|
+
} else {
|
|
263
|
+
direction = PositionDirection.LONG;
|
|
264
|
+
}
|
|
265
|
+
tradeSize = ZERO;
|
|
266
|
+
return [direction, tradeSize, targetPrice, targetPrice];
|
|
267
|
+
} else if (markPriceBefore.gt(targetPrice)) {
|
|
200
268
|
// overestimate y2
|
|
201
269
|
baseAssetReserveAfter = squareRootBN(
|
|
202
270
|
k.div(targetPrice).mul(peg).div(PEG_PRECISION).sub(biasModifier)
|
package/src/mockUSDCFaucet.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as anchor from '@project-serum/anchor';
|
|
2
|
-
import { Idl, Program
|
|
2
|
+
import { AnchorProvider, Idl, Program } from '@project-serum/anchor';
|
|
3
3
|
import {
|
|
4
4
|
AccountInfo,
|
|
5
5
|
ASSOCIATED_TOKEN_PROGRAM_ID,
|
|
@@ -25,7 +25,7 @@ export class MockUSDCFaucet {
|
|
|
25
25
|
connection: Connection;
|
|
26
26
|
wallet: IWallet;
|
|
27
27
|
public program: Program;
|
|
28
|
-
provider:
|
|
28
|
+
provider: AnchorProvider;
|
|
29
29
|
opts?: ConfirmOptions;
|
|
30
30
|
|
|
31
31
|
public constructor(
|
|
@@ -36,8 +36,8 @@ export class MockUSDCFaucet {
|
|
|
36
36
|
) {
|
|
37
37
|
this.connection = connection;
|
|
38
38
|
this.wallet = wallet;
|
|
39
|
-
this.opts = opts ||
|
|
40
|
-
const provider = new
|
|
39
|
+
this.opts = opts || AnchorProvider.defaultOptions();
|
|
40
|
+
const provider = new AnchorProvider(connection, wallet, this.opts);
|
|
41
41
|
this.provider = provider;
|
|
42
42
|
this.program = new Program(mockUSDCFaucetIDL as Idl, programId, provider);
|
|
43
43
|
}
|
|
@@ -140,7 +140,7 @@ export class MockUSDCFaucet {
|
|
|
140
140
|
amount
|
|
141
141
|
);
|
|
142
142
|
const tx = new Transaction().add(createAssociatedAccountIx).add(mintToTx);
|
|
143
|
-
const txSig = await this.program.provider.
|
|
143
|
+
const txSig = await this.program.provider.sendAndConfirm(tx, [], this.opts);
|
|
144
144
|
return [associatedTokenPublicKey, txSig];
|
|
145
145
|
}
|
|
146
146
|
|