-
Notifications
You must be signed in to change notification settings - Fork 1
/
dexrpc.js
161 lines (145 loc) · 4.58 KB
/
dexrpc.js
1
2
3
4
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Interactions with the DEX contract, via RPC
import { JsonRpc, Api, JsSignatureProvider } from '@proton/js';
import { BigNumber } from 'bignumber.js';
import * as dexapi from './dexapi.js';
import { getConfig, getLogger } from './utils.js';
const logger = getLogger();
const config = getConfig();
const { username } = config;
const { endpoints, privateKey, privateKeyPermission } = config.get('rpc');
// Initialize
const rpc = new JsonRpc(endpoints);
const api = new Api({
rpc,
signatureProvider: new JsSignatureProvider([privateKey]),
});
const apiTransact = (actions) => api.transact({ actions }, {
blocksBehind: 300,
expireSeconds: 3000,
});
/**
* Given a list of on-chain actions, apply authorization and send
* @param {array} actions - array of actions to send to the chain
*/
const transact = async (actions) => {
// apply authorization to each action
const authorization = [{
actor: username,
permission: privateKeyPermission,
}];
const authorizedActions = actions.map((action) => ({ ...action, authorization }));
await apiTransact(authorizedActions);
};
export const ORDERSIDES = {
BUY: 1,
SELL: 2,
};
export const ORDERTYPES = {
LIMIT: 1,
STOP_LOSS: 2,
TAKE_PROFIT: 3,
};
export const FILLTYPES = {
GOOD_TILL_CANCEL: 0,
IMMEDIATE_OR_CANCEL: 1,
POST_ONLY: 2,
};
/**
* Place a buy or sell limit order. Quantity and price are string values to
* avoid loss of precision when placing order
* @param {string} symbol - market symbol, ex. 'XPR_XMD'
* @param {number} orderSide - 1 = BUY, 2 = SELL; use ORDERSIDES.BUY, ORDERSIDES.SELL
* @param {string} quantity - for buys, the qty of ask tokens, for sells the qty of bid tokens
* @param {string} price - price to pay
* @returns nothing - use fetchOpenOrders to retrieve details of successful but unfilled orders
* @returns {Promise<object>} - response object from the api.transact()
*/
export const submitLimitOrder = async (symbol, orderSide, quantity, price = undefined) => {
const market = dexapi.getMarketBySymbol(symbol);
const askToken = market.ask_token;
const bidToken = market.bid_token;
const bnQuantity = new BigNumber(quantity);
const quantityText = orderSide === ORDERSIDES.SELL
? `${bnQuantity.toFixed(bidToken.precision)} ${bidToken.code}`
: `${bnQuantity.toFixed(askToken.precision)} ${askToken.code}`;
const orderSideText = orderSide === ORDERSIDES.SELL ? 'sell' : 'buy';
logger.info(`Attempting to place ${orderSideText} order for ${quantityText} at ${price}`);
const quantityNormalized = orderSide === ORDERSIDES.SELL
? (bnQuantity.times(bidToken.multiplier)).toString()
: (bnQuantity.times(askToken.multiplier)).toString();
const priceNormalized = Math.trunc(price * askToken.multiplier);
const actions = [
{
account: orderSide === ORDERSIDES.SELL ? bidToken.contract : askToken.contract,
name: 'transfer',
data: {
from: username,
to: 'dex',
quantity: quantityText,
memo: '',
},
},
{
account: 'dex',
name: 'placeorder',
data: {
market_id: market.market_id,
account: username,
order_type: ORDERTYPES.LIMIT,
order_side: orderSide,
quantity: quantityNormalized,
price: priceNormalized,
bid_symbol: {
sym: `${bidToken.precision},${bidToken.code}`,
contract: bidToken.contract,
},
ask_symbol: {
sym: `${askToken.precision},${askToken.code}`,
contract: askToken.contract,
},
trigger_price: 0,
fill_type: FILLTYPES.POST_ONLY,
referrer: '',
},
},
{
account: 'dex',
name: 'process',
data: {
q_size: 5,
show_error_msg: 0,
},
},
];
const response = await transact(actions);
return response;
};
const createCancelAction = (orderId) => ({
account: 'dex',
name: 'cancelorder',
data: {
account: username,
order_id: orderId,
},
});
/**
* Cancel a single order
* @param {number} orderId - if of order to cancel
* @returns {Promise<void>}
*/
export const cancelOrder = async (orderId) => {
logger.info(`Canceling order with id: ${orderId}`);
const response = await transact([createCancelAction(orderId)]);
return response;
};
/**
* Cancel all orders for the current account
* @returns {Promise<void>}
*/
export const cancelAllOrders = async () => {
const orders = await dexapi.fetchOpenOrders(username);
logger.info(`Canceling all (${orders.length}) orders`);
const actions = orders.map((order) => createCancelAction(order.order_id));
const response = await transact(actions);
return response;
};