@drift-labs/jit-proxy 0.1.0 → 0.2.0
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/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/jitProxyClient.d.ts +13 -2
- package/lib/jitProxyClient.js +23 -3
- package/lib/jitter.d.ts +32 -0
- package/lib/jitter.js +115 -0
- package/lib/types/jit_proxy.d.ts +37 -4
- package/lib/types/jit_proxy.js +37 -4
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/jitProxyClient.ts +30 -3
- package/src/jitter.ts +192 -0
- package/src/types/jit_proxy.ts +74 -8
- package/src/index.js +0 -14
- package/src/types/jit_proxy.js +0 -116
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -12,3 +12,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
__exportStar(require("./types/jit_proxy"), exports);
|
|
14
14
|
__exportStar(require("./jitProxyClient"), exports);
|
|
15
|
+
__exportStar(require("./jitter"), exports);
|
package/lib/jitProxyClient.d.ts
CHANGED
|
@@ -8,9 +8,20 @@ export declare type JitIxParams = {
|
|
|
8
8
|
taker: UserAccount;
|
|
9
9
|
takerOrderId: number;
|
|
10
10
|
maxPosition: BN;
|
|
11
|
-
|
|
11
|
+
minPosition: BN;
|
|
12
|
+
bid: BN;
|
|
13
|
+
ask: BN;
|
|
12
14
|
postOnly: PostOnlyParams | null;
|
|
15
|
+
priceType?: PriceType;
|
|
13
16
|
};
|
|
17
|
+
export declare class PriceType {
|
|
18
|
+
static readonly LIMIT: {
|
|
19
|
+
limit: {};
|
|
20
|
+
};
|
|
21
|
+
static readonly ORACLE: {
|
|
22
|
+
oracle: {};
|
|
23
|
+
};
|
|
24
|
+
}
|
|
14
25
|
export declare class JitProxyClient {
|
|
15
26
|
private driftClient;
|
|
16
27
|
private program;
|
|
@@ -19,5 +30,5 @@ export declare class JitProxyClient {
|
|
|
19
30
|
programId: PublicKey;
|
|
20
31
|
});
|
|
21
32
|
jit(params: JitIxParams, txParams?: TxParams): Promise<TxSigAndSlot>;
|
|
22
|
-
getJitIx({ takerKey, takerStatsKey, taker, takerOrderId, maxPosition,
|
|
33
|
+
getJitIx({ takerKey, takerStatsKey, taker, takerOrderId, maxPosition, minPosition, bid, ask, postOnly, priceType, }: JitIxParams): Promise<TransactionInstruction>;
|
|
23
34
|
}
|
package/lib/jitProxyClient.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.JitProxyClient = void 0;
|
|
3
|
+
exports.JitProxyClient = exports.PriceType = void 0;
|
|
4
4
|
const sdk_1 = require("@drift-labs/sdk");
|
|
5
5
|
const jit_proxy_1 = require("./types/jit_proxy");
|
|
6
6
|
const anchor_1 = require("@coral-xyz/anchor");
|
|
7
|
+
class PriceType {
|
|
8
|
+
}
|
|
9
|
+
exports.PriceType = PriceType;
|
|
10
|
+
PriceType.LIMIT = { limit: {} };
|
|
11
|
+
PriceType.ORACLE = { oracle: {} };
|
|
7
12
|
class JitProxyClient {
|
|
8
13
|
constructor({ driftClient, programId, }) {
|
|
9
14
|
this.driftClient = driftClient;
|
|
@@ -14,7 +19,7 @@ class JitProxyClient {
|
|
|
14
19
|
const tx = await this.driftClient.buildTransaction([ix], txParams);
|
|
15
20
|
return await this.driftClient.sendTransaction(tx);
|
|
16
21
|
}
|
|
17
|
-
async getJitIx({ takerKey, takerStatsKey, taker, takerOrderId, maxPosition,
|
|
22
|
+
async getJitIx({ takerKey, takerStatsKey, taker, takerOrderId, maxPosition, minPosition, bid, ask, postOnly = null, priceType = PriceType.LIMIT, }) {
|
|
18
23
|
const order = taker.orders.find((order) => order.orderId === takerOrderId);
|
|
19
24
|
const remainingAccounts = this.driftClient.getRemainingAccounts({
|
|
20
25
|
userAccounts: [taker, this.driftClient.getUserAccount()],
|
|
@@ -25,11 +30,26 @@ class JitProxyClient {
|
|
|
25
30
|
? [order.marketIndex]
|
|
26
31
|
: [],
|
|
27
32
|
});
|
|
33
|
+
if (sdk_1.isVariant(order.marketType, 'spot')) {
|
|
34
|
+
remainingAccounts.push({
|
|
35
|
+
pubkey: this.driftClient.getSpotMarketAccount(order.marketIndex).vault,
|
|
36
|
+
isWritable: false,
|
|
37
|
+
isSigner: false,
|
|
38
|
+
});
|
|
39
|
+
remainingAccounts.push({
|
|
40
|
+
pubkey: this.driftClient.getQuoteSpotMarketAccount().vault,
|
|
41
|
+
isWritable: false,
|
|
42
|
+
isSigner: false,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
28
45
|
const jitParams = {
|
|
29
46
|
takerOrderId,
|
|
30
47
|
maxPosition,
|
|
31
|
-
|
|
48
|
+
minPosition,
|
|
49
|
+
bid,
|
|
50
|
+
ask,
|
|
32
51
|
postOnly,
|
|
52
|
+
priceType,
|
|
33
53
|
};
|
|
34
54
|
return this.program.methods
|
|
35
55
|
.jit(jitParams)
|
package/lib/jitter.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/// <reference types="bn.js" />
|
|
2
|
+
import { JitProxyClient, PriceType } from './jitProxyClient';
|
|
3
|
+
import { PublicKey } from '@solana/web3.js';
|
|
4
|
+
import { AuctionSubscriber, BN, DriftClient, Order, UserAccount } from '@drift-labs/sdk';
|
|
5
|
+
export declare type UserFilter = (userAccount: UserAccount, userKey: string, order: Order) => boolean;
|
|
6
|
+
export declare type JitParams = {
|
|
7
|
+
bid: BN;
|
|
8
|
+
ask: BN;
|
|
9
|
+
minPosition: BN;
|
|
10
|
+
maxPosition: any;
|
|
11
|
+
priceType: PriceType;
|
|
12
|
+
};
|
|
13
|
+
export declare class Jitter {
|
|
14
|
+
auctionSubscriber: AuctionSubscriber;
|
|
15
|
+
driftClient: DriftClient;
|
|
16
|
+
jitProxyClient: JitProxyClient;
|
|
17
|
+
perpParams: Map<number, JitParams>;
|
|
18
|
+
spotParams: Map<number, JitParams>;
|
|
19
|
+
onGoingAuctions: Map<string, Promise<void>>;
|
|
20
|
+
userFilter: UserFilter;
|
|
21
|
+
constructor({ auctionSubscriber, jitProxyClient, driftClient, }: {
|
|
22
|
+
driftClient: DriftClient;
|
|
23
|
+
auctionSubscriber: AuctionSubscriber;
|
|
24
|
+
jitProxyClient: JitProxyClient;
|
|
25
|
+
});
|
|
26
|
+
subscribe(): Promise<void>;
|
|
27
|
+
createTryFill(taker: UserAccount, takerKey: PublicKey, takerStatsKey: PublicKey, order: Order, orderSignature: string): () => Promise<void>;
|
|
28
|
+
getOrderSignatures(takerKey: string, orderId: number): string;
|
|
29
|
+
updatePerpParams(marketIndex: number, params: JitParams): void;
|
|
30
|
+
updateSpotParams(marketIndex: number, params: JitParams): void;
|
|
31
|
+
setUserFilter(userFilter: UserFilter | undefined): void;
|
|
32
|
+
}
|
package/lib/jitter.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Jitter = void 0;
|
|
4
|
+
const sdk_1 = require("@drift-labs/sdk");
|
|
5
|
+
class Jitter {
|
|
6
|
+
constructor({ auctionSubscriber, jitProxyClient, driftClient, }) {
|
|
7
|
+
this.perpParams = new Map();
|
|
8
|
+
this.spotParams = new Map();
|
|
9
|
+
this.onGoingAuctions = new Map();
|
|
10
|
+
this.auctionSubscriber = auctionSubscriber;
|
|
11
|
+
this.driftClient = driftClient;
|
|
12
|
+
this.jitProxyClient = jitProxyClient;
|
|
13
|
+
}
|
|
14
|
+
async subscribe() {
|
|
15
|
+
await this.auctionSubscriber.subscribe();
|
|
16
|
+
this.auctionSubscriber.eventEmitter.on('onAccountUpdate', async (taker, takerKey, slot) => {
|
|
17
|
+
const takerKeyString = takerKey.toBase58();
|
|
18
|
+
const takerStatsKey = sdk_1.getUserStatsAccountPublicKey(this.driftClient.program.programId, taker.authority);
|
|
19
|
+
for (const order of taker.orders) {
|
|
20
|
+
if (!sdk_1.isVariant(order.status, 'open')) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (!sdk_1.hasAuctionPrice(order, slot)) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (this.userFilter) {
|
|
27
|
+
if (this.userFilter(taker, takerKeyString, order)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const orderSignature = this.getOrderSignatures(takerKeyString, order.orderId);
|
|
32
|
+
if (this.onGoingAuctions.has(orderSignature)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (sdk_1.isVariant(order.marketType, 'perp')) {
|
|
36
|
+
if (!this.perpParams.has(order.marketIndex)) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const promise = this.createTryFill(taker, takerKey, takerStatsKey, order, orderSignature).bind(this)();
|
|
40
|
+
this.onGoingAuctions.set(orderSignature, promise);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
if (!this.spotParams.has(order.marketIndex)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const promise = this.createTryFill(taker, takerKey, takerStatsKey, order, orderSignature).bind(this)();
|
|
47
|
+
this.onGoingAuctions.set(orderSignature, promise);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
createTryFill(taker, takerKey, takerStatsKey, order, orderSignature) {
|
|
53
|
+
return async () => {
|
|
54
|
+
let i = 0;
|
|
55
|
+
while (i < 10) {
|
|
56
|
+
const params = this.perpParams.get(order.marketIndex);
|
|
57
|
+
if (!params) {
|
|
58
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log(`Trying to fill ${orderSignature}`);
|
|
62
|
+
try {
|
|
63
|
+
const { txSig } = await this.jitProxyClient.jit({
|
|
64
|
+
takerKey,
|
|
65
|
+
takerStatsKey,
|
|
66
|
+
taker,
|
|
67
|
+
takerOrderId: order.orderId,
|
|
68
|
+
maxPosition: params.maxPosition,
|
|
69
|
+
minPosition: params.minPosition,
|
|
70
|
+
bid: params.bid,
|
|
71
|
+
ask: params.ask,
|
|
72
|
+
postOnly: null,
|
|
73
|
+
priceType: params.priceType,
|
|
74
|
+
});
|
|
75
|
+
console.log(`Filled ${orderSignature} txSig ${txSig}`);
|
|
76
|
+
await sleep(10000);
|
|
77
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
console.error(`Failed to fill ${orderSignature}`);
|
|
82
|
+
if (e.message.includes('0x1770') || e.message.includes('0x1771')) {
|
|
83
|
+
console.log('Order does not cross params yet, retrying');
|
|
84
|
+
}
|
|
85
|
+
else if (e.message.includes('0x1793')) {
|
|
86
|
+
console.log('Oracle invalid, retrying');
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
await sleep(10000);
|
|
90
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
i++;
|
|
95
|
+
}
|
|
96
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
getOrderSignatures(takerKey, orderId) {
|
|
100
|
+
return `${takerKey}-${orderId}`;
|
|
101
|
+
}
|
|
102
|
+
updatePerpParams(marketIndex, params) {
|
|
103
|
+
this.perpParams.set(marketIndex, params);
|
|
104
|
+
}
|
|
105
|
+
updateSpotParams(marketIndex, params) {
|
|
106
|
+
this.spotParams.set(marketIndex, params);
|
|
107
|
+
}
|
|
108
|
+
setUserFilter(userFilter) {
|
|
109
|
+
this.userFilter = userFilter;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.Jitter = Jitter;
|
|
113
|
+
function sleep(ms) {
|
|
114
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
115
|
+
}
|
package/lib/types/jit_proxy.d.ts
CHANGED
|
@@ -66,8 +66,22 @@ export declare type JitProxy = {
|
|
|
66
66
|
type: 'i64';
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
-
name: '
|
|
70
|
-
type: '
|
|
69
|
+
name: 'minPosition';
|
|
70
|
+
type: 'i64';
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'bid';
|
|
74
|
+
type: 'i64';
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'ask';
|
|
78
|
+
type: 'i64';
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'priceType';
|
|
82
|
+
type: {
|
|
83
|
+
defined: 'PriceType';
|
|
84
|
+
};
|
|
71
85
|
},
|
|
72
86
|
{
|
|
73
87
|
name: 'postOnly';
|
|
@@ -96,16 +110,35 @@ export declare type JitProxy = {
|
|
|
96
110
|
}
|
|
97
111
|
];
|
|
98
112
|
};
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'PriceType';
|
|
116
|
+
type: {
|
|
117
|
+
kind: 'enum';
|
|
118
|
+
variants: [
|
|
119
|
+
{
|
|
120
|
+
name: 'Limit';
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'Oracle';
|
|
124
|
+
}
|
|
125
|
+
];
|
|
126
|
+
};
|
|
99
127
|
}
|
|
100
128
|
];
|
|
101
129
|
errors: [
|
|
102
130
|
{
|
|
103
131
|
code: 6000;
|
|
104
|
-
name: '
|
|
105
|
-
msg: '
|
|
132
|
+
name: 'BidNotCrossed';
|
|
133
|
+
msg: 'BidNotCrossed';
|
|
106
134
|
},
|
|
107
135
|
{
|
|
108
136
|
code: 6001;
|
|
137
|
+
name: 'AskNotCrossed';
|
|
138
|
+
msg: 'AskNotCrossed';
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
code: 6002;
|
|
109
142
|
name: 'TakerOrderNotFound';
|
|
110
143
|
msg: 'TakerOrderNotFound';
|
|
111
144
|
}
|
package/lib/types/jit_proxy.js
CHANGED
|
@@ -69,8 +69,22 @@ exports.IDL = {
|
|
|
69
69
|
type: 'i64',
|
|
70
70
|
},
|
|
71
71
|
{
|
|
72
|
-
name: '
|
|
73
|
-
type: '
|
|
72
|
+
name: 'minPosition',
|
|
73
|
+
type: 'i64',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'bid',
|
|
77
|
+
type: 'i64',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'ask',
|
|
81
|
+
type: 'i64',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'priceType',
|
|
85
|
+
type: {
|
|
86
|
+
defined: 'PriceType',
|
|
87
|
+
},
|
|
74
88
|
},
|
|
75
89
|
{
|
|
76
90
|
name: 'postOnly',
|
|
@@ -100,15 +114,34 @@ exports.IDL = {
|
|
|
100
114
|
],
|
|
101
115
|
},
|
|
102
116
|
},
|
|
117
|
+
{
|
|
118
|
+
name: 'PriceType',
|
|
119
|
+
type: {
|
|
120
|
+
kind: 'enum',
|
|
121
|
+
variants: [
|
|
122
|
+
{
|
|
123
|
+
name: 'Limit',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'Oracle',
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
},
|
|
103
131
|
],
|
|
104
132
|
errors: [
|
|
105
133
|
{
|
|
106
134
|
code: 6000,
|
|
107
|
-
name: '
|
|
108
|
-
msg: '
|
|
135
|
+
name: 'BidNotCrossed',
|
|
136
|
+
msg: 'BidNotCrossed',
|
|
109
137
|
},
|
|
110
138
|
{
|
|
111
139
|
code: 6001,
|
|
140
|
+
name: 'AskNotCrossed',
|
|
141
|
+
msg: 'AskNotCrossed',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
code: 6002,
|
|
112
145
|
name: 'TakerOrderNotFound',
|
|
113
146
|
msg: 'TakerOrderNotFound',
|
|
114
147
|
},
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
package/src/jitProxyClient.ts
CHANGED
|
@@ -18,10 +18,18 @@ export type JitIxParams = {
|
|
|
18
18
|
taker: UserAccount;
|
|
19
19
|
takerOrderId: number;
|
|
20
20
|
maxPosition: BN;
|
|
21
|
-
|
|
21
|
+
minPosition: BN;
|
|
22
|
+
bid: BN;
|
|
23
|
+
ask: BN;
|
|
22
24
|
postOnly: PostOnlyParams | null;
|
|
25
|
+
priceType?: PriceType;
|
|
23
26
|
};
|
|
24
27
|
|
|
28
|
+
export class PriceType {
|
|
29
|
+
static readonly LIMIT = { limit: {} };
|
|
30
|
+
static readonly ORACLE = { oracle: {} };
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
export class JitProxyClient {
|
|
26
34
|
private driftClient: DriftClient;
|
|
27
35
|
private program: Program<JitProxy>;
|
|
@@ -52,8 +60,11 @@ export class JitProxyClient {
|
|
|
52
60
|
taker,
|
|
53
61
|
takerOrderId,
|
|
54
62
|
maxPosition,
|
|
55
|
-
|
|
63
|
+
minPosition,
|
|
64
|
+
bid,
|
|
65
|
+
ask,
|
|
56
66
|
postOnly = null,
|
|
67
|
+
priceType = PriceType.LIMIT,
|
|
57
68
|
}: JitIxParams): Promise<TransactionInstruction> {
|
|
58
69
|
const order = taker.orders.find((order) => order.orderId === takerOrderId);
|
|
59
70
|
const remainingAccounts = this.driftClient.getRemainingAccounts({
|
|
@@ -66,11 +77,27 @@ export class JitProxyClient {
|
|
|
66
77
|
: [],
|
|
67
78
|
});
|
|
68
79
|
|
|
80
|
+
if (isVariant(order.marketType, 'spot')) {
|
|
81
|
+
remainingAccounts.push({
|
|
82
|
+
pubkey: this.driftClient.getSpotMarketAccount(order.marketIndex).vault,
|
|
83
|
+
isWritable: false,
|
|
84
|
+
isSigner: false,
|
|
85
|
+
});
|
|
86
|
+
remainingAccounts.push({
|
|
87
|
+
pubkey: this.driftClient.getQuoteSpotMarketAccount().vault,
|
|
88
|
+
isWritable: false,
|
|
89
|
+
isSigner: false,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
69
93
|
const jitParams = {
|
|
70
94
|
takerOrderId,
|
|
71
95
|
maxPosition,
|
|
72
|
-
|
|
96
|
+
minPosition,
|
|
97
|
+
bid,
|
|
98
|
+
ask,
|
|
73
99
|
postOnly,
|
|
100
|
+
priceType,
|
|
74
101
|
};
|
|
75
102
|
|
|
76
103
|
return this.program.methods
|
package/src/jitter.ts
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { JitProxyClient, PriceType } from './jitProxyClient';
|
|
2
|
+
import { PublicKey } from '@solana/web3.js';
|
|
3
|
+
import {
|
|
4
|
+
AuctionSubscriber,
|
|
5
|
+
BN,
|
|
6
|
+
DriftClient,
|
|
7
|
+
getUserStatsAccountPublicKey,
|
|
8
|
+
hasAuctionPrice,
|
|
9
|
+
isVariant,
|
|
10
|
+
Order,
|
|
11
|
+
UserAccount,
|
|
12
|
+
} from '@drift-labs/sdk';
|
|
13
|
+
|
|
14
|
+
export type UserFilter = (
|
|
15
|
+
userAccount: UserAccount,
|
|
16
|
+
userKey: string,
|
|
17
|
+
order: Order
|
|
18
|
+
) => boolean;
|
|
19
|
+
export type JitParams = {
|
|
20
|
+
bid: BN;
|
|
21
|
+
ask: BN;
|
|
22
|
+
minPosition: BN;
|
|
23
|
+
maxPosition;
|
|
24
|
+
priceType: PriceType;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export class Jitter {
|
|
28
|
+
auctionSubscriber: AuctionSubscriber;
|
|
29
|
+
driftClient: DriftClient;
|
|
30
|
+
jitProxyClient: JitProxyClient;
|
|
31
|
+
|
|
32
|
+
perpParams = new Map<number, JitParams>();
|
|
33
|
+
spotParams = new Map<number, JitParams>();
|
|
34
|
+
|
|
35
|
+
onGoingAuctions = new Map<string, Promise<void>>();
|
|
36
|
+
|
|
37
|
+
userFilter: UserFilter;
|
|
38
|
+
|
|
39
|
+
constructor({
|
|
40
|
+
auctionSubscriber,
|
|
41
|
+
jitProxyClient,
|
|
42
|
+
driftClient,
|
|
43
|
+
}: {
|
|
44
|
+
driftClient: DriftClient;
|
|
45
|
+
auctionSubscriber: AuctionSubscriber;
|
|
46
|
+
jitProxyClient: JitProxyClient;
|
|
47
|
+
}) {
|
|
48
|
+
this.auctionSubscriber = auctionSubscriber;
|
|
49
|
+
this.driftClient = driftClient;
|
|
50
|
+
this.jitProxyClient = jitProxyClient;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async subscribe(): Promise<void> {
|
|
54
|
+
await this.auctionSubscriber.subscribe();
|
|
55
|
+
this.auctionSubscriber.eventEmitter.on(
|
|
56
|
+
'onAccountUpdate',
|
|
57
|
+
async (taker, takerKey, slot) => {
|
|
58
|
+
const takerKeyString = takerKey.toBase58();
|
|
59
|
+
|
|
60
|
+
const takerStatsKey = getUserStatsAccountPublicKey(
|
|
61
|
+
this.driftClient.program.programId,
|
|
62
|
+
taker.authority
|
|
63
|
+
);
|
|
64
|
+
for (const order of taker.orders) {
|
|
65
|
+
if (!isVariant(order.status, 'open')) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!hasAuctionPrice(order, slot)) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (this.userFilter) {
|
|
74
|
+
if (this.userFilter(taker, takerKeyString, order)) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const orderSignature = this.getOrderSignatures(
|
|
80
|
+
takerKeyString,
|
|
81
|
+
order.orderId
|
|
82
|
+
);
|
|
83
|
+
if (this.onGoingAuctions.has(orderSignature)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (isVariant(order.marketType, 'perp')) {
|
|
88
|
+
if (!this.perpParams.has(order.marketIndex)) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const promise = this.createTryFill(
|
|
93
|
+
taker,
|
|
94
|
+
takerKey,
|
|
95
|
+
takerStatsKey,
|
|
96
|
+
order,
|
|
97
|
+
orderSignature
|
|
98
|
+
).bind(this)();
|
|
99
|
+
this.onGoingAuctions.set(orderSignature, promise);
|
|
100
|
+
} else {
|
|
101
|
+
if (!this.spotParams.has(order.marketIndex)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const promise = this.createTryFill(
|
|
106
|
+
taker,
|
|
107
|
+
takerKey,
|
|
108
|
+
takerStatsKey,
|
|
109
|
+
order,
|
|
110
|
+
orderSignature
|
|
111
|
+
).bind(this)();
|
|
112
|
+
this.onGoingAuctions.set(orderSignature, promise);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
createTryFill(
|
|
120
|
+
taker: UserAccount,
|
|
121
|
+
takerKey: PublicKey,
|
|
122
|
+
takerStatsKey: PublicKey,
|
|
123
|
+
order: Order,
|
|
124
|
+
orderSignature: string
|
|
125
|
+
): () => Promise<void> {
|
|
126
|
+
return async () => {
|
|
127
|
+
let i = 0;
|
|
128
|
+
while (i < 10) {
|
|
129
|
+
const params = this.perpParams.get(order.marketIndex);
|
|
130
|
+
if (!params) {
|
|
131
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log(`Trying to fill ${orderSignature}`);
|
|
136
|
+
try {
|
|
137
|
+
const { txSig } = await this.jitProxyClient.jit({
|
|
138
|
+
takerKey,
|
|
139
|
+
takerStatsKey,
|
|
140
|
+
taker,
|
|
141
|
+
takerOrderId: order.orderId,
|
|
142
|
+
maxPosition: params.maxPosition,
|
|
143
|
+
minPosition: params.minPosition,
|
|
144
|
+
bid: params.bid,
|
|
145
|
+
ask: params.ask,
|
|
146
|
+
postOnly: null,
|
|
147
|
+
priceType: params.priceType,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
console.log(`Filled ${orderSignature} txSig ${txSig}`);
|
|
151
|
+
await sleep(10000);
|
|
152
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
153
|
+
return;
|
|
154
|
+
} catch (e) {
|
|
155
|
+
console.error(`Failed to fill ${orderSignature}`);
|
|
156
|
+
if (e.message.includes('0x1770') || e.message.includes('0x1771')) {
|
|
157
|
+
console.log('Order does not cross params yet, retrying');
|
|
158
|
+
} else if (e.message.includes('0x1793')) {
|
|
159
|
+
console.log('Oracle invalid, retrying');
|
|
160
|
+
} else {
|
|
161
|
+
await sleep(10000);
|
|
162
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
i++;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.onGoingAuctions.delete(orderSignature);
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getOrderSignatures(takerKey: string, orderId: number): string {
|
|
174
|
+
return `${takerKey}-${orderId}`;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public updatePerpParams(marketIndex: number, params: JitParams): void {
|
|
178
|
+
this.perpParams.set(marketIndex, params);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public updateSpotParams(marketIndex: number, params: JitParams): void {
|
|
182
|
+
this.spotParams.set(marketIndex, params);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public setUserFilter(userFilter: UserFilter | undefined): void {
|
|
186
|
+
this.userFilter = userFilter;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function sleep(ms: number): Promise<void> {
|
|
191
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
192
|
+
}
|
package/src/types/jit_proxy.ts
CHANGED
|
@@ -66,8 +66,22 @@ export type JitProxy = {
|
|
|
66
66
|
type: 'i64';
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
|
-
name: '
|
|
70
|
-
type: '
|
|
69
|
+
name: 'minPosition';
|
|
70
|
+
type: 'i64';
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: 'bid';
|
|
74
|
+
type: 'i64';
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'ask';
|
|
78
|
+
type: 'i64';
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'priceType';
|
|
82
|
+
type: {
|
|
83
|
+
defined: 'PriceType';
|
|
84
|
+
};
|
|
71
85
|
},
|
|
72
86
|
{
|
|
73
87
|
name: 'postOnly';
|
|
@@ -96,16 +110,35 @@ export type JitProxy = {
|
|
|
96
110
|
}
|
|
97
111
|
];
|
|
98
112
|
};
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'PriceType';
|
|
116
|
+
type: {
|
|
117
|
+
kind: 'enum';
|
|
118
|
+
variants: [
|
|
119
|
+
{
|
|
120
|
+
name: 'Limit';
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: 'Oracle';
|
|
124
|
+
}
|
|
125
|
+
];
|
|
126
|
+
};
|
|
99
127
|
}
|
|
100
128
|
];
|
|
101
129
|
errors: [
|
|
102
130
|
{
|
|
103
131
|
code: 6000;
|
|
104
|
-
name: '
|
|
105
|
-
msg: '
|
|
132
|
+
name: 'BidNotCrossed';
|
|
133
|
+
msg: 'BidNotCrossed';
|
|
106
134
|
},
|
|
107
135
|
{
|
|
108
136
|
code: 6001;
|
|
137
|
+
name: 'AskNotCrossed';
|
|
138
|
+
msg: 'AskNotCrossed';
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
code: 6002;
|
|
109
142
|
name: 'TakerOrderNotFound';
|
|
110
143
|
msg: 'TakerOrderNotFound';
|
|
111
144
|
}
|
|
@@ -180,8 +213,22 @@ export const IDL: JitProxy = {
|
|
|
180
213
|
type: 'i64',
|
|
181
214
|
},
|
|
182
215
|
{
|
|
183
|
-
name: '
|
|
184
|
-
type: '
|
|
216
|
+
name: 'minPosition',
|
|
217
|
+
type: 'i64',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: 'bid',
|
|
221
|
+
type: 'i64',
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
name: 'ask',
|
|
225
|
+
type: 'i64',
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
name: 'priceType',
|
|
229
|
+
type: {
|
|
230
|
+
defined: 'PriceType',
|
|
231
|
+
},
|
|
185
232
|
},
|
|
186
233
|
{
|
|
187
234
|
name: 'postOnly',
|
|
@@ -211,15 +258,34 @@ export const IDL: JitProxy = {
|
|
|
211
258
|
],
|
|
212
259
|
},
|
|
213
260
|
},
|
|
261
|
+
{
|
|
262
|
+
name: 'PriceType',
|
|
263
|
+
type: {
|
|
264
|
+
kind: 'enum',
|
|
265
|
+
variants: [
|
|
266
|
+
{
|
|
267
|
+
name: 'Limit',
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
name: 'Oracle',
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
},
|
|
274
|
+
},
|
|
214
275
|
],
|
|
215
276
|
errors: [
|
|
216
277
|
{
|
|
217
278
|
code: 6000,
|
|
218
|
-
name: '
|
|
219
|
-
msg: '
|
|
279
|
+
name: 'BidNotCrossed',
|
|
280
|
+
msg: 'BidNotCrossed',
|
|
220
281
|
},
|
|
221
282
|
{
|
|
222
283
|
code: 6001,
|
|
284
|
+
name: 'AskNotCrossed',
|
|
285
|
+
msg: 'AskNotCrossed',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
code: 6002,
|
|
223
289
|
name: 'TakerOrderNotFound',
|
|
224
290
|
msg: 'TakerOrderNotFound',
|
|
225
291
|
},
|
package/src/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
-
}) : (function(o, m, k, k2) {
|
|
6
|
-
if (k2 === undefined) k2 = k;
|
|
7
|
-
o[k2] = m[k];
|
|
8
|
-
}));
|
|
9
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
-
};
|
|
12
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
__exportStar(require("./types/jit_proxy"), exports);
|
|
14
|
-
__exportStar(require("./jitProxyClient"), exports);
|
package/src/types/jit_proxy.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IDL = void 0;
|
|
4
|
-
exports.IDL = {
|
|
5
|
-
"version": "0.1.0",
|
|
6
|
-
"name": "jit_proxy",
|
|
7
|
-
"instructions": [
|
|
8
|
-
{
|
|
9
|
-
"name": "jit",
|
|
10
|
-
"accounts": [
|
|
11
|
-
{
|
|
12
|
-
"name": "state",
|
|
13
|
-
"isMut": false,
|
|
14
|
-
"isSigner": false
|
|
15
|
-
},
|
|
16
|
-
{
|
|
17
|
-
"name": "user",
|
|
18
|
-
"isMut": true,
|
|
19
|
-
"isSigner": false
|
|
20
|
-
},
|
|
21
|
-
{
|
|
22
|
-
"name": "userStats",
|
|
23
|
-
"isMut": true,
|
|
24
|
-
"isSigner": false
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
"name": "taker",
|
|
28
|
-
"isMut": true,
|
|
29
|
-
"isSigner": false
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
"name": "takerStats",
|
|
33
|
-
"isMut": true,
|
|
34
|
-
"isSigner": false
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
"name": "authority",
|
|
38
|
-
"isMut": false,
|
|
39
|
-
"isSigner": true
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
"name": "driftProgram",
|
|
43
|
-
"isMut": false,
|
|
44
|
-
"isSigner": false
|
|
45
|
-
}
|
|
46
|
-
],
|
|
47
|
-
"args": [
|
|
48
|
-
{
|
|
49
|
-
"name": "params",
|
|
50
|
-
"type": {
|
|
51
|
-
"defined": "JitParams"
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
]
|
|
55
|
-
}
|
|
56
|
-
],
|
|
57
|
-
"types": [
|
|
58
|
-
{
|
|
59
|
-
"name": "JitParams",
|
|
60
|
-
"type": {
|
|
61
|
-
"kind": "struct",
|
|
62
|
-
"fields": [
|
|
63
|
-
{
|
|
64
|
-
"name": "takerOrderId",
|
|
65
|
-
"type": "u32"
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
"name": "maxPosition",
|
|
69
|
-
"type": "i64"
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
"name": "worstPrice",
|
|
73
|
-
"type": "u64"
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"name": "postOnly",
|
|
77
|
-
"type": {
|
|
78
|
-
"option": {
|
|
79
|
-
"defined": "PostOnlyParam"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
"name": "PostOnlyParam",
|
|
88
|
-
"type": {
|
|
89
|
-
"kind": "enum",
|
|
90
|
-
"variants": [
|
|
91
|
-
{
|
|
92
|
-
"name": "None"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
"name": "MustPostOnly"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"name": "TryPostOnly"
|
|
99
|
-
}
|
|
100
|
-
]
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
],
|
|
104
|
-
"errors": [
|
|
105
|
-
{
|
|
106
|
-
"code": 6000,
|
|
107
|
-
"name": "WorstPriceExceeded",
|
|
108
|
-
"msg": "WorstPriceExceeded"
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
"code": 6001,
|
|
112
|
-
"name": "TakerOrderNotFound",
|
|
113
|
-
"msg": "TakerOrderNotFound"
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
};
|