@dydxprotocol/v4-client-js 1.18.0 → 1.20.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/CHANGELOG.md +2 -2
- package/__tests__/clients/composite-client.test.ts +140 -0
- package/build/__tests__/clients/composite-client.test.d.ts +1 -0
- package/build/__tests__/clients/composite-client.test.js +130 -0
- package/build/examples/permissioned_keys_example.js +22 -8
- package/build/examples/websocket_orderbook_example.js +10 -12
- package/build/src/clients/composite-client.d.ts +2 -1
- package/build/src/clients/composite-client.js +38 -2
- package/build/src/clients/constants.d.ts +4 -0
- package/build/src/clients/constants.js +1 -1
- package/build/src/clients/modules/local-wallet.d.ts +4 -4
- package/build/src/clients/modules/local-wallet.js +1 -1
- package/build/src/clients/modules/signer.d.ts +3 -3
- package/build/src/clients/modules/signer.js +18 -8
- package/build/tsconfig.tsbuildinfo +1 -1
- package/examples/permissioned_keys_example.ts +38 -12
- package/examples/websocket_orderbook_example.ts +202 -215
- package/package.json +1 -1
- package/src/clients/composite-client.ts +60 -7
- package/src/clients/constants.ts +5 -0
- package/src/clients/modules/local-wallet.ts +4 -4
- package/src/clients/modules/signer.ts +33 -12
|
@@ -47,31 +47,57 @@ async function test(): Promise<void> {
|
|
|
47
47
|
await placeOrder(client, subaccount2, subaccount1, authenticatorID);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
async function removeAuthenticator(
|
|
50
|
+
async function removeAuthenticator(
|
|
51
|
+
client: CompositeClient,
|
|
52
|
+
subaccount: SubaccountInfo,
|
|
53
|
+
id: Long,
|
|
54
|
+
): Promise<void> {
|
|
51
55
|
await client.removeAuthenticator(subaccount, id);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
async function addAuthenticator(
|
|
55
|
-
|
|
58
|
+
async function addAuthenticator(
|
|
59
|
+
client: CompositeClient,
|
|
60
|
+
subaccount: SubaccountInfo,
|
|
61
|
+
authedPubKey: string,
|
|
62
|
+
): Promise<void> {
|
|
63
|
+
const subAuth = [ {
|
|
56
64
|
type: AuthenticatorType.SIGNATURE_VERIFICATION,
|
|
57
65
|
config: authedPubKey,
|
|
58
66
|
},
|
|
59
67
|
{
|
|
60
|
-
type: AuthenticatorType.
|
|
61
|
-
config:
|
|
62
|
-
|
|
68
|
+
type: AuthenticatorType.ANY_OF,
|
|
69
|
+
config: [
|
|
70
|
+
{
|
|
71
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
72
|
+
config: toBase64(new TextEncoder().encode('/dydxprotocol.clob.MsgPlaceOrder')),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: AuthenticatorType.MESSAGE_FILTER,
|
|
76
|
+
config: toBase64(new TextEncoder().encode('/dydxprotocol.clob.MsgPlaceOrder')),
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
}
|
|
63
80
|
];
|
|
64
81
|
|
|
65
|
-
const jsonString = JSON.stringify(
|
|
82
|
+
const jsonString = JSON.stringify(subAuth);
|
|
66
83
|
const encodedData = new TextEncoder().encode(jsonString);
|
|
67
84
|
|
|
68
|
-
|
|
85
|
+
try {
|
|
86
|
+
await client.addAuthenticator(subaccount, AuthenticatorType.ALL_OF, encodedData);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.log(error.message);
|
|
89
|
+
}
|
|
69
90
|
}
|
|
70
91
|
|
|
71
|
-
async function placeOrder(
|
|
92
|
+
async function placeOrder(
|
|
93
|
+
client: CompositeClient,
|
|
94
|
+
fromAccount: SubaccountInfo,
|
|
95
|
+
forAccount: SubaccountInfo,
|
|
96
|
+
authenticatorId: Long,
|
|
97
|
+
): Promise<void> {
|
|
72
98
|
try {
|
|
73
|
-
const side = OrderSide.BUY
|
|
74
|
-
const price = Number(
|
|
99
|
+
const side = OrderSide.BUY;
|
|
100
|
+
const price = Number('1000');
|
|
75
101
|
const currentBlock = await client.validatorClient.get.latestBlockHeight();
|
|
76
102
|
const nextValidBlockHeight = currentBlock + 5;
|
|
77
103
|
const goodTilBlock = nextValidBlockHeight + 10;
|
|
@@ -94,7 +120,7 @@ async function placeOrder(client: CompositeClient, fromAccount: SubaccountInfo,
|
|
|
94
120
|
{
|
|
95
121
|
authenticators: [authenticatorId],
|
|
96
122
|
accountForOrder: forAccount,
|
|
97
|
-
}
|
|
123
|
+
},
|
|
98
124
|
);
|
|
99
125
|
console.log('**Order Tx**');
|
|
100
126
|
console.log(Buffer.from(tx.hash).toString('hex'));
|
|
@@ -1,252 +1,239 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
/* eslint-disable no-param-reassign */
|
|
1
3
|
import { Network } from '../src/clients/constants';
|
|
2
4
|
import { SocketClient } from '../src/clients/socket-client';
|
|
3
5
|
|
|
4
6
|
function test(): void {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
orderBookBidList.length > 0 &&
|
|
50
|
-
orderBookAskList.length > 0 &&
|
|
51
|
-
orderBookBidList[0][0] >= orderBookAskList[0][0]
|
|
52
|
-
) {
|
|
53
|
-
[orderBookBidList, orderBookAskList] =
|
|
54
|
-
resolveCrossedOrderBook(
|
|
55
|
-
orderBookBidList,
|
|
56
|
-
orderBookAskList,
|
|
57
|
-
);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
printOrderBook(orderBookBidList, orderBookAskList);
|
|
61
|
-
|
|
62
|
-
if (orderBookBidList.length > 300) {
|
|
63
|
-
orderBookBidList.splice(50);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (orderBookAskList.length > 300) {
|
|
67
|
-
orderBookAskList.splice(50);
|
|
68
|
-
}
|
|
69
|
-
} else if (
|
|
70
|
-
orderBookDataList !== null &&
|
|
71
|
-
orderBookDataList !== undefined
|
|
72
|
-
) {
|
|
73
|
-
// initial OrderBook data
|
|
74
|
-
setInitialOrderBook(
|
|
75
|
-
orderBookDataList,
|
|
76
|
-
orderBookBidList,
|
|
77
|
-
orderBookAskList,
|
|
78
|
-
messageId,
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error('Error parsing JSON message:', e);
|
|
7
|
+
let orderBookBidList: [number, number, number][] = [];
|
|
8
|
+
let orderBookAskList: [number, number, number][] = [];
|
|
9
|
+
|
|
10
|
+
const mySocket = new SocketClient(
|
|
11
|
+
Network.mainnet().indexerConfig,
|
|
12
|
+
() => {
|
|
13
|
+
console.log('socket opened');
|
|
14
|
+
|
|
15
|
+
mySocket.subscribeToOrderbook('ETH-USD');
|
|
16
|
+
},
|
|
17
|
+
() => {
|
|
18
|
+
console.log('socket closed');
|
|
19
|
+
},
|
|
20
|
+
(message) => {
|
|
21
|
+
try {
|
|
22
|
+
if (typeof message.data === 'string') {
|
|
23
|
+
const jsonString = message.data;
|
|
24
|
+
const parsingData = JSON.parse(jsonString);
|
|
25
|
+
const messageId = parsingData.message_id;
|
|
26
|
+
const orderBookDataList = parsingData.contents;
|
|
27
|
+
|
|
28
|
+
if (orderBookDataList instanceof Array) {
|
|
29
|
+
// common orderBook data;
|
|
30
|
+
[orderBookBidList, orderBookAskList] = updateOrderBook(
|
|
31
|
+
orderBookDataList,
|
|
32
|
+
orderBookBidList,
|
|
33
|
+
orderBookAskList,
|
|
34
|
+
messageId,
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// sort
|
|
38
|
+
orderBookBidList = sortByNthElementDesc(orderBookBidList, 0);
|
|
39
|
+
orderBookAskList = sortByNthElementAsc(orderBookAskList, 0);
|
|
40
|
+
|
|
41
|
+
// resolving crossed orderBook
|
|
42
|
+
if (
|
|
43
|
+
orderBookBidList.length > 0 &&
|
|
44
|
+
orderBookAskList.length > 0 &&
|
|
45
|
+
orderBookBidList[0][0] >= orderBookAskList[0][0]
|
|
46
|
+
) {
|
|
47
|
+
[orderBookBidList, orderBookAskList] = resolveCrossedOrderBook(
|
|
48
|
+
orderBookBidList,
|
|
49
|
+
orderBookAskList,
|
|
50
|
+
);
|
|
84
51
|
}
|
|
85
|
-
},
|
|
86
|
-
(event) => {
|
|
87
|
-
console.error('Encountered error:', event.message);
|
|
88
|
-
},
|
|
89
|
-
);
|
|
90
52
|
|
|
91
|
-
|
|
53
|
+
printOrderBook(orderBookBidList, orderBookAskList);
|
|
54
|
+
|
|
55
|
+
if (orderBookBidList.length > 300) {
|
|
56
|
+
orderBookBidList.splice(50);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (orderBookAskList.length > 300) {
|
|
60
|
+
orderBookAskList.splice(50);
|
|
61
|
+
}
|
|
62
|
+
} else if (orderBookDataList !== null && orderBookDataList !== undefined) {
|
|
63
|
+
// initial OrderBook data
|
|
64
|
+
setInitialOrderBook(orderBookDataList, orderBookBidList, orderBookAskList, messageId);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error('Error parsing JSON message:', e);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
(event) => {
|
|
72
|
+
console.error('Encountered error:', event.message);
|
|
73
|
+
},
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
mySocket.connect();
|
|
92
77
|
}
|
|
93
78
|
|
|
94
|
-
const sortByNthElementAsc = (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
79
|
+
const sortByNthElementAsc = (
|
|
80
|
+
arr: [number, number, number][],
|
|
81
|
+
n: number,
|
|
82
|
+
): [number, number, number][] => {
|
|
83
|
+
return arr.sort((a, b) => {
|
|
84
|
+
if (a[n] < b[n]) return -1;
|
|
85
|
+
if (a[n] > b[n]) return 1;
|
|
86
|
+
return 0;
|
|
87
|
+
});
|
|
100
88
|
};
|
|
101
|
-
const sortByNthElementDesc = (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
89
|
+
const sortByNthElementDesc = (
|
|
90
|
+
arr: [number, number, number][],
|
|
91
|
+
n: number,
|
|
92
|
+
): [number, number, number][] => {
|
|
93
|
+
return arr.sort((a, b) => {
|
|
94
|
+
if (a[n] > b[n]) return -1;
|
|
95
|
+
if (a[n] < b[n]) return 1;
|
|
96
|
+
return 0;
|
|
97
|
+
});
|
|
107
98
|
};
|
|
108
99
|
|
|
109
100
|
const printOrderBook = (
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
orderBookBidList: [number, number, number][],
|
|
102
|
+
orderBookAskList: [number, number, number][],
|
|
112
103
|
): void => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
104
|
+
// print
|
|
105
|
+
console.log(`OrderBook for ETH-USD:`);
|
|
106
|
+
console.log(`Price Qty`);
|
|
107
|
+
for (let i = 4; i > -1; i--) {
|
|
108
|
+
const priceStr = String(orderBookAskList[i][0]);
|
|
109
|
+
const spaces = createSpaces(10 - priceStr.length);
|
|
110
|
+
console.log(`${priceStr}${spaces}${orderBookAskList[i][1]}`);
|
|
111
|
+
}
|
|
112
|
+
console.log('---------------------');
|
|
113
|
+
for (let i = 0; i < 5; i++) {
|
|
114
|
+
const priceStr = String(orderBookBidList[i][0]);
|
|
115
|
+
const spaces = createSpaces(10 - priceStr.length);
|
|
116
|
+
console.log(`${priceStr}${spaces}${orderBookBidList[i][1]}`);
|
|
117
|
+
}
|
|
118
|
+
console.log('');
|
|
128
119
|
};
|
|
129
120
|
|
|
130
121
|
function createSpaces(count: number): string {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
122
|
+
if (count <= 0) {
|
|
123
|
+
return '';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let spaces = '';
|
|
127
|
+
for (let i = 0; i < count; i++) {
|
|
128
|
+
spaces += ' ';
|
|
129
|
+
}
|
|
130
|
+
return spaces;
|
|
140
131
|
}
|
|
141
132
|
|
|
142
133
|
const resolveCrossedOrderBook = (
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
orderBookBidList: [number, number, number][],
|
|
135
|
+
orderBookAskList: [number, number, number][],
|
|
145
136
|
): [[number, number, number][], [number, number, number][]] => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
137
|
+
while (orderBookBidList[0][0] >= orderBookAskList[0][0]) {
|
|
138
|
+
if (orderBookBidList[0][2] < orderBookAskList[0][2]) {
|
|
139
|
+
orderBookBidList.shift();
|
|
140
|
+
} else if (orderBookBidList[0][2] > orderBookAskList[0][2]) {
|
|
141
|
+
orderBookAskList.shift();
|
|
142
|
+
} else {
|
|
143
|
+
if (orderBookBidList[0][1] > orderBookAskList[0][1]) {
|
|
144
|
+
orderBookBidList[0][1] -= orderBookAskList[0][1];
|
|
145
|
+
orderBookAskList.shift();
|
|
146
|
+
} else if (orderBookBidList[0][1] < orderBookAskList[0][1]) {
|
|
147
|
+
orderBookAskList[0][1] -= orderBookBidList[0][1];
|
|
148
|
+
orderBookBidList.shift();
|
|
149
|
+
} else {
|
|
150
|
+
orderBookAskList.shift();
|
|
151
|
+
orderBookBidList.shift();
|
|
152
|
+
}
|
|
163
153
|
}
|
|
154
|
+
}
|
|
164
155
|
|
|
165
|
-
|
|
156
|
+
return [orderBookBidList, orderBookAskList];
|
|
166
157
|
};
|
|
167
158
|
const setInitialOrderBook = (
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
159
|
+
orderBookDataList: { bids: []; asks: [] },
|
|
160
|
+
orderBookBidList: [number, number, number][],
|
|
161
|
+
orderBookAskList: [number, number, number][],
|
|
162
|
+
messageId: number,
|
|
172
163
|
): void => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
164
|
+
orderBookDataList.bids.forEach((item: { price: string; size: string }) => {
|
|
165
|
+
orderBookBidList.push([Number(item.price), Number(item.size), messageId]);
|
|
166
|
+
});
|
|
176
167
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
168
|
+
orderBookDataList.asks.forEach((item: { price: string; size: string }) => {
|
|
169
|
+
orderBookAskList.push([Number(item.price), Number(item.size), messageId]);
|
|
170
|
+
});
|
|
180
171
|
};
|
|
181
172
|
|
|
182
173
|
const updateOrderBook = (
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
174
|
+
orderBookDataList: { bids: [[]]; asks: [[]] }[],
|
|
175
|
+
orderBookBidList: [number, number, number][],
|
|
176
|
+
orderBookAskList: [number, number, number][],
|
|
177
|
+
messageId: number,
|
|
187
178
|
): [[number, number, number][], [number, number, number][]] => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
orderBookBidList[index][1] = entryBidSize;
|
|
209
|
-
orderBookBidList[index][2] = messageId;
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
} else {
|
|
213
|
-
// Add new data to order book
|
|
214
|
-
orderBookBidList.push([entryBidPrice, entryBidSize, messageId]);
|
|
215
|
-
}
|
|
179
|
+
orderBookDataList.forEach((entry: { bids: [[]]; asks: [[]] }) => {
|
|
180
|
+
if (entry.bids !== null && entry.bids !== undefined) {
|
|
181
|
+
const flattened = entry.bids.reduce((acc: any[], val: any[]) => acc.concat(val), []);
|
|
182
|
+
const entryBidPrice = Number(flattened[0]);
|
|
183
|
+
const entryBidSize = Number(flattened[1]);
|
|
184
|
+
|
|
185
|
+
// remove prices with zero Qty
|
|
186
|
+
if (entryBidSize === 0) {
|
|
187
|
+
for (let i = orderBookBidList.length - 1; i >= 0; i--) {
|
|
188
|
+
if (orderBookBidList[i][0] === entryBidPrice) {
|
|
189
|
+
orderBookBidList.splice(i, 1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
// The price that already exists in the order book is modified only Qty
|
|
194
|
+
if (orderBookBidList.some((innerArray) => innerArray[0] === entryBidPrice)) {
|
|
195
|
+
orderBookBidList.forEach((item, index) => {
|
|
196
|
+
if (item[0] === entryBidPrice) {
|
|
197
|
+
orderBookBidList[index][1] = entryBidSize;
|
|
198
|
+
orderBookBidList[index][2] = messageId;
|
|
216
199
|
}
|
|
200
|
+
});
|
|
201
|
+
} else {
|
|
202
|
+
// Add new data to order book
|
|
203
|
+
orderBookBidList.push([entryBidPrice, entryBidSize, messageId]);
|
|
217
204
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
} else {
|
|
242
|
-
// Add new data to order book
|
|
243
|
-
orderBookAskList.push([entryAskPrice, entryAskSize, messageId]);
|
|
244
|
-
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
if (entry.asks !== null && entry.asks !== undefined) {
|
|
208
|
+
const flattened = entry.asks.reduce((acc: any[], val: any[]) => acc.concat(val), []);
|
|
209
|
+
const entryAskPrice = Number(flattened[0]);
|
|
210
|
+
const entryAskSize = Number(flattened[1]);
|
|
211
|
+
|
|
212
|
+
if (entryAskSize === 0) {
|
|
213
|
+
// remove prices with zero Qty
|
|
214
|
+
for (let i = orderBookAskList.length - 1; i >= 0; i--) {
|
|
215
|
+
if (orderBookAskList[i][0] === entryAskPrice) {
|
|
216
|
+
orderBookAskList.splice(i, 1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
// The price that already exists in the order book is modified only Qty
|
|
221
|
+
if (orderBookAskList.some((innerArray) => innerArray[0] === entryAskPrice)) {
|
|
222
|
+
orderBookAskList.forEach((item, index) => {
|
|
223
|
+
if (item[0] === entryAskPrice) {
|
|
224
|
+
orderBookAskList[index][1] = entryAskSize;
|
|
225
|
+
orderBookAskList[index][2] = messageId;
|
|
245
226
|
}
|
|
227
|
+
});
|
|
228
|
+
} else {
|
|
229
|
+
// Add new data to order book
|
|
230
|
+
orderBookAskList.push([entryAskPrice, entryAskSize, messageId]);
|
|
246
231
|
}
|
|
247
|
-
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
248
235
|
|
|
249
|
-
|
|
236
|
+
return [orderBookBidList, orderBookAskList];
|
|
250
237
|
};
|
|
251
238
|
|
|
252
|
-
test();
|
|
239
|
+
test();
|
package/package.json
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { TextDecoder } from 'util';
|
|
2
|
+
|
|
1
3
|
import { EncodeObject } from '@cosmjs/proto-signing';
|
|
2
4
|
import { Account, GasPrice, IndexedTx, StdFee } from '@cosmjs/stargate';
|
|
3
5
|
import { Method } from '@cosmjs/tendermint-rpc';
|
|
@@ -18,6 +20,7 @@ import { bigIntToBytes } from '../lib/helpers';
|
|
|
18
20
|
import { isStatefulOrder, verifyOrderFlags } from '../lib/validation';
|
|
19
21
|
import { GovAddNewMarketParams, OrderFlags } from '../types';
|
|
20
22
|
import {
|
|
23
|
+
Authenticator,
|
|
21
24
|
AuthenticatorType,
|
|
22
25
|
Network,
|
|
23
26
|
OrderExecution,
|
|
@@ -169,7 +172,7 @@ export class CompositeClient {
|
|
|
169
172
|
broadcastMode,
|
|
170
173
|
account,
|
|
171
174
|
undefined,
|
|
172
|
-
|
|
175
|
+
authenticators,
|
|
173
176
|
);
|
|
174
177
|
}
|
|
175
178
|
|
|
@@ -311,9 +314,10 @@ export class CompositeClient {
|
|
|
311
314
|
): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
|
|
312
315
|
// For permissioned orders, use the permissioning account details instead of the subaccount
|
|
313
316
|
// This allows placing orders on behalf of another account when using permissioned keys
|
|
314
|
-
const accountForOrder = permissionedKeysAccountAuth
|
|
317
|
+
const accountForOrder = permissionedKeysAccountAuth
|
|
318
|
+
? permissionedKeysAccountAuth.accountForOrder
|
|
319
|
+
: subaccount;
|
|
315
320
|
const msgs: Promise<EncodeObject[]> = new Promise((resolve, reject) => {
|
|
316
|
-
|
|
317
321
|
const msg = this.placeShortTermOrderMessage(
|
|
318
322
|
accountForOrder,
|
|
319
323
|
marketId,
|
|
@@ -1233,7 +1237,13 @@ export class CompositeClient {
|
|
|
1233
1237
|
gasAdjustment?: number,
|
|
1234
1238
|
memo?: string,
|
|
1235
1239
|
): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
|
|
1236
|
-
return this.validatorClient.post.createMarketPermissionless(
|
|
1240
|
+
return this.validatorClient.post.createMarketPermissionless(
|
|
1241
|
+
ticker,
|
|
1242
|
+
subaccount,
|
|
1243
|
+
broadcastMode,
|
|
1244
|
+
gasAdjustment,
|
|
1245
|
+
memo,
|
|
1246
|
+
);
|
|
1237
1247
|
}
|
|
1238
1248
|
|
|
1239
1249
|
async addAuthenticator(
|
|
@@ -1241,17 +1251,60 @@ export class CompositeClient {
|
|
|
1241
1251
|
authenticatorType: AuthenticatorType,
|
|
1242
1252
|
data: Uint8Array,
|
|
1243
1253
|
): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
|
|
1244
|
-
|
|
1254
|
+
// Validate the provided authenticators before sending to the validator
|
|
1255
|
+
const authenticator: Authenticator = {
|
|
1256
|
+
type: authenticatorType,
|
|
1257
|
+
config: JSON.parse(new TextDecoder().decode(data)),
|
|
1258
|
+
};
|
|
1259
|
+
if (!this.validateAuthenticator(authenticator)) {
|
|
1260
|
+
throw new Error(
|
|
1261
|
+
'Invalid authenticator, please ensure the authenticator permissions are correct',
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
return this.validatorClient.post.addAuthenticator(subaccount, authenticatorType, data);
|
|
1245
1266
|
}
|
|
1246
1267
|
|
|
1247
1268
|
async removeAuthenticator(
|
|
1248
1269
|
subaccount: SubaccountInfo,
|
|
1249
1270
|
id: Long,
|
|
1250
1271
|
): Promise<BroadcastTxAsyncResponse | BroadcastTxSyncResponse | IndexedTx> {
|
|
1251
|
-
return this.validatorClient.post.removeAuthenticator(subaccount, id)
|
|
1272
|
+
return this.validatorClient.post.removeAuthenticator(subaccount, id);
|
|
1252
1273
|
}
|
|
1253
1274
|
|
|
1254
|
-
async getAuthenticators(address: string): Promise<GetAuthenticatorsResponse>{
|
|
1275
|
+
async getAuthenticators(address: string): Promise<GetAuthenticatorsResponse> {
|
|
1255
1276
|
return this.validatorClient.get.getAuthenticators(address);
|
|
1256
1277
|
}
|
|
1278
|
+
|
|
1279
|
+
validateAuthenticator(authenticator: Authenticator): boolean {
|
|
1280
|
+
function checkAuthenticator(auth: Authenticator): boolean {
|
|
1281
|
+
if (auth.type === AuthenticatorType.SIGNATURE_VERIFICATION) {
|
|
1282
|
+
return true; // A SignatureVerification authenticator is safe.
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
if (!Array.isArray(auth.config)) {
|
|
1286
|
+
return false; // Unsafe case: a non-array config for a composite authenticator
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
if (auth.type === AuthenticatorType.ANY_OF) {
|
|
1290
|
+
// ANY_OF is safe only if ALL sub-authenticators return true
|
|
1291
|
+
return auth.config.every((nestedAuth) => checkAuthenticator(nestedAuth));
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
if (auth.type === AuthenticatorType.ALL_OF) {
|
|
1295
|
+
// ALL_OF is safe if at least one sub-authenticator returns true
|
|
1296
|
+
return auth.config.some((nestedAuth) => checkAuthenticator(nestedAuth));
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
// If it's a base-case authenticator but not SignatureVerification, it's unsafe
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// The top-level authenticator must pass validation
|
|
1304
|
+
if (!checkAuthenticator(authenticator)) {
|
|
1305
|
+
return false
|
|
1306
|
+
}
|
|
1307
|
+
|
|
1308
|
+
return true;
|
|
1309
|
+
}
|
|
1257
1310
|
}
|
package/src/clients/constants.ts
CHANGED
|
@@ -211,6 +211,11 @@ export enum AuthenticatorType {
|
|
|
211
211
|
SUBACCOUNT_FILTER = 'SubaccountFilter',
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
export interface Authenticator {
|
|
215
|
+
type: AuthenticatorType;
|
|
216
|
+
config: string | Authenticator[];
|
|
217
|
+
}
|
|
218
|
+
|
|
214
219
|
export enum TradingRewardAggregationPeriod {
|
|
215
220
|
DAILY = 'DAILY',
|
|
216
221
|
WEEKLY = 'WEEKLY',
|