Order ERC20

Demo for making an immediate swap

Mini-order

To support small quantity trading, we introduce an additional concept tradeCost, which is the minimum gas fee when a trade transaction is uplink to Ethereum.
Let's take LRC-ETH trading as an example.
Below are the steps:
Step 1
Step 2
Step 3
Step 4
Step 5

Query api/v3/exchange/tokens to get the dust value of orderAmounts for both LRC and ETH

The dust value is the minimum value to pass Relayer check. Any amount less than "dust" can't be traded.
In this case, we will get both minTokenLRC and minTokenETH after getting dust value.
If a user wants to convert LRC to ETH, the set LRC amount can't be less than minTokenLRC and the converted ETH amount can't be less than minTokenETH.
Query api/v3/user/orderUserRateAmount to get the tradeCost value
The parameters to call this interface are accountId and market=LRC-ETH.
In this example, we will get two tradeCost values for LRC and ETH as tradeCostLRC and tradeCostETH.

Set maxAllowBips = 50%

the maxFeeBips can't exceed 50%

Set slippage as the slippage value user configured in UI

Example: 0.1%

Caculate minCostLRC and minCostETH as below

minCostLRC = max(minTokenLRC, tradeCostLRC/maxAllowBips)
minCostETH = max(minTokenETH, tradeCostETH/maxAllowBips)
Step 6
Step 7
Step 8
Step 9

Caculate the cost by considering slippage

minCostLRCSlip = minCostLRC/(1-slippage)
minCostETHSlip = minCostETH/(1-slippage)

Cacluate the minimum quantity user has to set

tradeCostSellLRC = max(tradeCostSellLRC, minTokenLRC) * 1.1
tradeCostSellETH = max(tradeCostSellETH, minTokenETH) * 1.1
Here we add additonally 10% tolerance.

Caculate the previous minimum token amount per calling api/v3/user/orderUserRateAmount (existing logic)

This is the threshold to distinguish small quantity trading and normal trading. We will get two values (configSellLRC and configSellETH) which are used for previous trading quantity limit (Per USD 100) caculation.

Caculate the new maxFeeBips and start trading

Let's take LRC->ETH as the example. User inputs the amount of LRC to convert, amount = sellLRC
if sellLRC >= configSellLRC then
// Normal trading case, stay with previous logic
maxFeeBips=63 (the default value for maxFeeBips)
Trade
else if sellLRC < tradeCostSellLRC then
// Really too small to support
Prompt user the amount is too small to support
Exit
else
// This is what we call as small quantity
costRate = Ceil(tradeCostETH/minbuyETH)
maxFeeBips = max(costRate, takerRate)
Trade
End If

Price impact update

  1. 1.
    sellTokenMinAmount = baseOrderInfo.minAmount from LoopringAPI.userAPI.getMinimumTokenAmt({accountId,marke}, apiKey)
  2. 2.
    {output} from sdk.getOutputAmount(input: sellTokenMinAmount, isAtoB: isAtoB,…}).output
  3. 3.
    PriceBase = output / sellTokenMinAmount
  4. 4.
    tradePrice = calcTradeParams.minReceive / userInputSell
  5. 5.
    priceImpact = 1 - tradePrice/PriceBase - 0.005
  6. 6.
    If priceImpact < 0 priceImpact = 0 Else priceImpact

LRC-ETH : for Base to Quote

An example swap of ETH into LRC.
Calculate swap function

1
const calculateSwap = (
2
sellSymbol = "LRC",
3
buySymbol = "ETH",
4
isInputSellToBuy: boolean,
5
inputValue: number, // user Input value no decimal,
6
_slippage = 0.1,
7
// MOCK value
8
amountMap: { [key: string]: any } = userAmount,
9
market: string = deepMock.symbol,
10
// close = ticker.tickers[7],
11
depth: any = deepMock,
12
ammPoolSnapshot: sdk.AmmPoolSnapshot = ammPoolSnapshotMock,
13
tokenMap: sdk.LoopringMap<sdk.TokenInfo> = TokenMapMockSwap,
14
ammMap: { [key: string]: any } = AMM_MAP
15
) => {
16
let calcFor100USDAmount, calcForMinCost, calcForPriceImpact;
17
if (depth && market && tokenMap) {
18
const sellToken = tokenMap[sellSymbol];
19
const buyToken = tokenMap[buySymbol];
20
const isInputSellOutputBuy = isInputSellToBuy;
21
let input: any = inputValue;
22
23
console.log(
24
"sellToken: Symbol ",
25
sellSymbol,
26
"buyToken: Symbol",
27
buySymbol,
28
"is Input Sell Output Buy:",
29
isInputSellOutputBuy,
30
"input value",
31
input
32
);
33
input = input === undefined || isNaN(Number(input)) ? 0 : Number(input);
34
let slippage = sdk.toBig(_slippage).times(100).toString();
35
let totalFee = undefined;
36
let feeTakerRate = undefined;
37
let feeBips = undefined;
38
let takerRate = undefined;
39
let buyMinAmtInfo = undefined;
40
let sellMinAmtInfo = undefined;
41
let tradeCost = undefined;
42
let basePrice = undefined;
43
let maxFeeBips = MAPFEEBIPS;
44
let minAmt = undefined;
45
46
if (amountMap && amountMap[market] && ammMap) {
47
console.log(`amountMap[${market}]:`, amountMap[market]);
48
49
const ammMarket = `AMM-${market}`;
50
51
const amountMarket = amountMap[market]; // userAmount from LRC-ETH(Market)
52
53
buyMinAmtInfo = amountMarket[buySymbol];
54
sellMinAmtInfo = amountMarket[sellSymbol];
55
console.log(
56
`buyMinAmtInfo: ${market}, ${buySymbol}`,
57
buyMinAmtInfo,
58
`sellMinAmtInfo: ${market}, ${sellSymbol}`,
59
sellMinAmtInfo
60
);
61
62
feeBips = ammMap[ammMarket] ? ammMap[ammMarket].feeBips : 1;
63
64
feeTakerRate =
65
amountMarket[buySymbol] &&
66
amountMarket[buySymbol].userOrderInfo.takerRate;
67
tradeCost = amountMarket[buySymbol].tradeCost;
68
69
/** @description for charge fee calc, calcFor100USDAmount
70
* Loopring market consider buyToken value small then max(buyMinAmtInfo.userOrderInfo.minAmount,buyToken.orderAmounts.dust) is a small order,
71
* the fee will take the Max(tradeCost,userTakeRate)
72
* use the buyMinAmount Input calc the selltoken value,
73
* please read Line:321
74
* **/
75
const minAmountInput = BigNumber.max(
76
buyMinAmtInfo.userOrderInfo.minAmount,
77
buyToken.orderAmounts.dust
78
)
79
.div(sdk.toBig(1).minus(sdk.toBig(slippage).div(10000)))
80
.div("1e" + buyToken.decimals)
81
.toString();
82
calcFor100USDAmount = sdk.getOutputAmount({
83
input: minAmountInput,
84
sell: sellSymbol,
85
buy: buySymbol,
86
isAtoB: false,
87
marketArr: marketArray as string[],
88
tokenMap: tokenMap as any,
89
marketMap: marketMap as any,
90
depth,
91
ammPoolSnapshot: ammPoolSnapshot,
92
feeBips: feeBips ? feeBips.toString() : 1,
93
takerRate: "0",
94
slipBips: slippage,
95
});
96
97
console.log(
98
"buyMinAmtInfo.userOrderInfo.minAmount:",
99
buyMinAmtInfo.userOrderInfo.minAmount,
100
`buyMinAmtInfo.userOrderInfo.minAmount, with slippage:${slippage}`,
101
sdk
102
.toBig(buyMinAmtInfo.userOrderInfo.minAmount)
103
.div(sdk.toBig(1).minus(sdk.toBig(slippage).div(10000)))
104
.toString()
105
);
106
107
/*** calc for Price Impact ****/
108
const sellMinAmtInput = sdk
109
.toBig(sellMinAmtInfo.baseOrderInfo.minAmount)
110
.div("1e" + sellToken.decimals)
111
.toString();
112
113
calcForPriceImpact = sdk.getOutputAmount({
114
input: sellMinAmtInput,
115
sell: sellSymbol,
116
buy: buySymbol,
117
isAtoB: true,
118
marketArr: marketArray as string[],
119
tokenMap: tokenMap as any,
120
marketMap: marketMap as any,
121
depth,
122
ammPoolSnapshot: ammPoolSnapshot,
123
feeBips: feeBips ? feeBips.toString() : 1,
124
takerRate: "0",
125
slipBips: "10",
126
});
127
128
basePrice = sdk.toBig(calcForPriceImpact?.output).div(sellMinAmtInput);
129
130
console.log(
131
"calcForPriceImpact input: ",
132
sellMinAmtInput,
133
", output: ",
134
sdk.toBig(calcForPriceImpact?.output).div(sellMinAmtInput).toNumber(),
135
", calcForPriceImpact:",
136
calcForPriceImpact?.amountBOutSlip?.minReceivedVal,
137
", calcForPriceImpact basePrice: ",
138
basePrice.toNumber()
139
);
140
141
/**** calc for mini Cost ****/
142
143
//minCostBuyToken = max(dustBuyToken, tradeCostETH/maxAllowBips)
144
const dustToken = buyToken;
145
let minCostBuyTokenInput = BigNumber.max(
146
sdk.toBig(tradeCost).times(2), //maxAllowBips = 50% tradeCostETH/50%
147
dustToken.orderAmounts.dust
148
);
149
150
const tradeCostInput = sdk
151
.toBig(minCostBuyTokenInput)
152
.div(sdk.toBig(1).minus(sdk.toBig(slippage).div(10000)))
153
.div("1e" + dustToken.decimals)
154
.toString();
155
156
console.log(
157
`tradeCost: ${tradeCost}*2:`,
158
sdk.toBig(tradeCost).times(2).toString(),
159
"buyToken.orderAmounts.dust",
160
buyToken.orderAmounts.dust,
161
"minCostBuyToken:",
162
minCostBuyTokenInput.toString(),
163
`calcForMinCostInput, with slippage:${slippage}`,
164
sdk
165
.toBig(minCostBuyTokenInput ?? 0)
166
.div(sdk.toBig(1).minus(sdk.toBig(slippage).div(10000)))
167
.toString(),
168
"calcForMinCost, Input",
169
tradeCostInput
170
);
171
172
calcForMinCost = sdk.getOutputAmount({
173
input: tradeCostInput,
174
sell: sellSymbol,
175
buy: buySymbol,
176
isAtoB: false,
177
marketArr: marketArray as string[],
178
tokenMap: tokenMap as any,
179
marketMap: marketMap as any,
180
depth,
181
ammPoolSnapshot: ammPoolSnapshot,
182
feeBips: feeBips ? feeBips.toString() : 1,
183
takerRate: "0",
184
slipBips: slippage,
185
});
186
187
//add additionally 10% tolerance for minimum quantity user has to set on sell Token
188
/**
189
* @output: minAmt for UI
190
* this value mini-order Sell token amount (show on the UI for available order check)
191
* setSellMinAmt(minAmt.toString());
192
*/
193
minAmt = BigNumber.max(
194
sellToken.orderAmounts.dust,
195
calcForMinCost?.amountS ?? 0
196
).times(1.1);
197
198
console.log(
199
"UI show mini-order Sell token amount:",
200
minAmt.toString(),
201
sdk
202
.toBig(minAmt)
203
.div("1e" + sellToken.decimals)
204
.toString()
205
);
206
207
console.log(
208
`calcFor100USDAmount.amountS`,
209
sdk
210
.toBig(calcFor100USDAmount?.amountS ?? 0)
211
.div("1e" + sellToken.decimals)
212
.toString(),
213
"calcForMinCost.amountS",
214
sdk
215
.toBig(calcForMinCost?.amountS ?? 0)
216
.div("1e" + sellToken.decimals)
217
.toString()
218
);
219
}
220
const calcTradeParams = sdk.getOutputAmount({
221
input: input.toString(),
222
sell: sellSymbol,
223
buy: buySymbol,
224
isAtoB: isInputSellOutputBuy,
225
marketArr: marketArray as string[],
226
tokenMap: tokenMap as any,
227
marketMap: marketMap as any,
228
depth,
229
ammPoolSnapshot: ammPoolSnapshot,
230
feeBips: feeBips ? feeBips.toString() : 1,
231
takerRate: "0", // for new calc miniReceive will minus fee, so takeRate can fix as 0
232
slipBips: slippage,
233
});
234
235
const minSymbol = buySymbol;
236
const tradePrice = sdk
237
.toBig(calcTradeParams?.amountBOutSlip?.minReceivedVal ?? 0)
238
.div(isInputSellOutputBuy ? input.toString() : calcTradeParams?.output);
239
const priceImpact = sdk
240
.toBig(1)
241
.minus(sdk.toBig(tradePrice).div(basePrice ?? 1))
242
.minus(0.001);
243
if (calcTradeParams && priceImpact.gte(0)) {
244
calcTradeParams.priceImpact = priceImpact.toFixed(4, 1);
245
} else {
246
calcTradeParams && (calcTradeParams.priceImpact = "0");
247
}
248
249
console.log(
250
"calcTradeParams input:",
251
input.toString(),
252
", calcTradeParams Price: ",
253
sdk
254
.toBig(calcTradeParams?.amountBOutSlip?.minReceivedVal ?? 0)
255
.div(input.toString())
256
.toNumber(),
257
`isAtoB mean isInputSellOutputBuy:${isInputSellOutputBuy}, ${
258
isInputSellOutputBuy ? input.toString() : calcTradeParams?.output
259
} tradePrice: `,
260
tradePrice.toString(),
261
"basePrice: ",
262
basePrice?.toString(),
263
"toBig(tradePrice).div(basePrice)",
264
sdk
265
.toBig(tradePrice)
266
.div(basePrice ?? 1)
267
.toNumber(),
268
"priceImpact (1-tradePrice/basePrice) - 0.001",
269
priceImpact.toNumber(),
270
"priceImpact view",
271
calcTradeParams?.priceImpact
272
);
273
274
if (
275
tradeCost &&
276
calcTradeParams &&
277
calcTradeParams.amountBOutSlip?.minReceived &&
278
feeTakerRate
279
) {
280
let value = sdk
281
.toBig(calcTradeParams.amountBOutSlip?.minReceived)
282
.times(feeTakerRate)
283
.div(10000);
284
285
console.log(
286
"input Accounts",
287
calcTradeParams?.amountS,
288
"100 U Amount Sell:",
289
calcFor100USDAmount?.amountS
290
);
291
292
let validAmt = !!(
293
calcTradeParams?.amountS &&
294
calcFor100USDAmount?.amountS &&
295
sdk.toBig(calcTradeParams?.amountS).gte(calcFor100USDAmount.amountS)
296
);
297
let totalFeeRaw;
298
299
console.log(
300
`${minSymbol} tradeCost:`,
301
tradeCost,
302
"useTakeRate Fee:",
303
value.toString(),
304
"calcFor100USDAmount?.amountS:",
305
calcFor100USDAmount?.amountS,
306
`is setup minTrade amount, ${calcFor100USDAmount?.amountS}:`,
307
validAmt
308
);
309
310
if (!validAmt) {
311
if (sdk.toBig(tradeCost).gte(value)) {
312
totalFeeRaw = sdk.toBig(tradeCost);
313
} else {
314
totalFeeRaw = value;
315
}
316
console.log(
317
"maxFeeBips update for tradeCost before value:",
318
maxFeeBips,
319
"totalFeeRaw",
320
totalFeeRaw.toString()
321
);
322
maxFeeBips = Math.ceil(
323
totalFeeRaw
324
.times(10000)
325
.div(calcTradeParams.amountBOutSlip?.minReceived)
326
.toNumber()
327
);
328
console.log("maxFeeBips update for tradeCost after value:", maxFeeBips);
329
} else {
330
totalFeeRaw = sdk.toBig(value);
331
}
332
333
/**
334
* totalFee
335
*/
336
totalFee = totalFeeRaw
337
.div("1e" + tokenMap[minSymbol].decimals)
338
.toString();
339
/** @output: UI
340
* getValuePrecisionThousand(
341
* totalFeeRaw.div("1e" + tokenMap[minSymbol].decimals).toString(),
342
* tokenMap[minSymbol].precision,
343
* tokenMap[minSymbol].precision,
344
* tokenMap[minSymbol].precision,
345
* false,
346
* { floor: true }
347
* );
348
*/
349
350
tradeCost = sdk
351
.toBig(tradeCost)
352
// @ts-ignore
353
.div("1e" + tokenMap[minSymbol].decimals)
354
.toString();
355
356
/** @output: UI code with precision
357
* getValuePrecisionThousand(
358
* sdk
359
* .toBig(tradeCost)
360
* .div("1e" + tokenMap[minSymbol].decimals)
361
* .toString(),
362
* tokenMap[minSymbol].precision,
363
* tokenMap[minSymbol].precision,
364
* tokenMap[minSymbol].precision,
365
* false,
366
* { floor: true }
367
* );
368
*/
369
370
console.log("totalFee view value:", totalFee + " " + minSymbol);
371
console.log("tradeCost view value:", tradeCost + " " + minSymbol);
372
}
373
374
const minimumReceived = sdk
375
.toBig(calcTradeParams?.amountBOutSlip?.minReceivedVal ?? 0)
376
.minus(totalFee ?? 0)
377
.toString();
378
console.log("minimumReceived:", minimumReceived);
379
380
/** @output: UI code with precision
381
* getValuePrecisionThousand(
382
* toBig(calcTradeParams?.amountBOutSlip?.minReceivedVal ?? 0)
383
* .minus(totalFee)
384
* .toString(),
385
* tokenMap[minSymbol].precision,
386
* tokenMap[minSymbol].precision,
387
* tokenMap[minSymbol].precision,
388
* false,
389
* { floor: true }
390
* );
391
*/
392
393
let priceImpactView: any = calcTradeParams?.priceImpact
394
? parseFloat(calcTradeParams?.priceImpact) * 100
395
: undefined;
396
console.log("priceImpact view:", priceImpactView + "%");
397
// @output: UI code with color alert
398
// const priceImpactObj = getPriceImpactInfo(calcTradeParams);
399
// const _tradeCalcData: Partial<TradeCalcData<C>> = {
400
// priceImpact: priceImpactObj.value.toString(),
401
// priceImpactColor: priceImpactObj.priceImpactColor,
402
// minimumReceived: !minimumReceived?.toString().startsWith("-")
403
// ? minimumReceived
404
// : undefined,
405
// fee: totalFee,
406
// feeTakerRate,
407
// tradeCost,
408
// };
409
410
console.log(
411
`isInputSellOutputBuy:${isInputSellOutputBuy}`,
412
`output ${isInputSellOutputBuy ? "Buy" : "Sell"}`,
413
calcTradeParams?.output
414
);
415
416
return {
417
market,
418
feeBips,
419
takerRate,
420
sellMinAmtInfo: sellMinAmtInfo as any,
421
buyMinAmtInfo: buyMinAmtInfo as any,
422
totalFee,
423
maxFeeBips,
424
feeTakerRate,
425
tradeCost,
426
minimumReceived,
427
calcTradeParams,
428
minAmt,
429
};
430
}
431
};
Step 1
Step 2
Step 3
Step 4
Step 5
Step 6

Get apikey & eddsaKey

1
const {accInfo} = await LoopringAPI.exchangeAPI.getAccount({
2
owner: LOOPRING_EXPORTED_ACCOUNT.address,
3
});
4
const eddsaKey = await signatureKeyPairMock(accInfo);
5
apiKey = (
6
await LoopringAPI.userAPI.getUserApiKey(
7
{
8
accountId: accInfo.accountId,
9
},
10
eddsaKey.sk
11
)
12
).apiKey;

Get storageId

1
const storageId = await LoopringAPI.userAPI.getNextStorageId(
2
{
3
accountId: LOOPRING_EXPORTED_ACCOUNT.accountId,
4
sellTokenId: TOKEN_INFO.tokenMap[sell].tokenId,
5
},
6
apiKey
7
);

Get user AmountMap, which decides users minimum order

yconst amountMap = {
[AMM_MARKET]: (
await LoopringAPI.userAPI.getMinimumTokenAmt(
{
accountId: LOOPRING_EXPORTED_ACCOUNT.accountId,
market: AMM_MAP[AMM_MARKET].market,
},
apiKey
)
).amountMap,
[MARKET]: (
await LoopringAPI.userAPI.getMinimumTokenAmt(
{
accountId: LOOPRING_EXPORTED_ACCOUNT.accountId,
market: MARKET,
},
apiKey
)
).amountMap,
};

Depth, ammPoolSnapshot ,tickMap

1
const [{depth}, {ammPoolSnapshot}] = await Promise.all([
2
LoopringAPI.exchangeAPI.getMixDepth({
3
market: AMM_MAP["AMM-LRC-ETH"].market,
4
}),
5
LoopringAPI.ammpoolAPI.getAmmPoolSnapshot({
6
poolAddress: AMM_MAP["AMM-LRC-ETH"].address,
7
}),
8
]);

Check MinAmt see log and calc mini receive and ouput value & maxfeeBips & priceImpact & swap output

1
const { calcTradeParams, maxFeeBips, minimumReceived } = calculateSwap(
2
sell,
3
buy,
4
isAtoB,
5
10, // user Input value no decimal 10 lrc,
6
0.1,
7
//TODO MOCK value
8
amountMap,
9
"LRC-ETH",
10
// close = ticker.tickers[7],
11
depth,
12
ammPoolSnapshot,
13
TOKEN_INFO.tokenMap,
14
AMM_MAP
15
);

Submit

1
const response: { hash: string } | any =
2
await LoopringAPI.userAPI.submitOrder(
3
{
4
exchange: LOOPRING_EXPORTED_ACCOUNT.exchangeAddress,
5
accountId: LOOPRING_EXPORTED_ACCOUNT.accountId,
6
storageId: storageId.orderId,
7
sellToken: {
8
tokenId: TOKEN_INFO.tokenMap[sell].tokenId,
9
volume: calcTradeParams?.amountS as string,
10
},
11
buyToken: {
12
tokenId: TOKEN_INFO.tokenMap[buy].tokenId,
13
volume: calcTradeParams?.amountBOutSlip.minReceived as string,
14
},
15
allOrNone: false,
16
validUntil: LOOPRING_EXPORTED_ACCOUNT.validUntil,
17
maxFeeBips: 63,
18
fillAmountBOrS: false, // amm only false
19
tradeChannel: calcTradeParams?.exceedDepth
20
? sdk.TradeChannel.BLANK
21
: sdk.TradeChannel.MIXED,
22
orderType: calcTradeParams?.exceedDepth
23
? sdk.OrderType.ClassAmm
24
: sdk.OrderType.TakerOnly,
25
eddsaSignature: "",
26
},
27
eddsaKey.sk,
28
apiKey
29
);
30
console.log("submitOrder", response);
Mock Swap Data
import * as sdk from "../index";
export const marketArray = ["LRC-ETH"];
export const marketMap = {
"LRC-ETH": {
baseTokenId: 1,
enabled: true,
market: "LRC-ETH",
orderbookAggLevels: 5,
precisionForPrice: 6,
quoteTokenId: 0,
status: 3,
isSwapEnabled: true,
createdAt: 1617967800000,
},
};
//v3/mix/depth?level=0&limit=50&market=LRC-ETH
export const deepMock = {
symbol: "LRC-ETH",
version: 23249677,
timestamp: 1655719492365,
mid_price: 0.00033248,
bids: [
{
price: 0.00030689,
amt: "12041160324514792497908",
vol: "3695372332571085210",
amtTotal: "618450503644320209925641",
volTotal: "198539605794234049017",
},
{
price: 0.00030752,
amt: "12016302126785109160251",
vol: "3695372332571085210",
amtTotal: "606409343319805417427733",
volTotal: "194844233461662963807",
},
{
price: 0.00030816,
amt: "11991520826895479525387",
vol: "3695372332571085210",
amtTotal: "594393041193020308267482",
volTotal: "191148861129091878597",
},
{
price: 0.00030881,
amt: "12329062048917727073625",
vol: "3807353312345966580",
amtTotal: "582401520366124828742095",
volTotal: "187453488796520793387",
},
{
price: 0.00030945,
amt: "11941442525358097768419",
vol: "3695372332571085210",
amtTotal: "570072458317207101668470",
volTotal: "183646135484174826807",
},
{
price: 0.0003102,
amt: "3223726000000000000000",
vol: "999999805200000000",
amtTotal: "558131015791849003900051",
volTotal: "179950763151603741597",
},
{
price: 0.0003104,
amt: "11904963012947201084062",
vol: "3695372332571085210",
amtTotal: "554907289791849003900051",
volTotal: "178950763346403741597",
},
{
price: 0.00031072,
amt: "11892800074855146120151",
vol: "3695372332571085210",
amtTotal: "543002326778901802815989",
volTotal: "175255391013832656387",
},
{
price: 0.00031137,
amt: "12227667622887455762012",
vol: "3807353312345966580",
amtTotal: "531109526704046656695838",
volTotal: "171560018681261571177",
},
{
price: 0.00031202,
amt: "11843337524732768607817",
vol: "3695372332571085210",
amtTotal: "518881859081159200933826",
volTotal: "167752665368915604597",
},
{
price: 0.00031266,
amt: "11819088718260537718160",
vol: "3695372332571085210",
amtTotal: "507038521556426432326009",
volTotal: "164057293036344519387",
},
{
price: 0.0003133,
amt: "11794914308461194855590",
vol: "3695372332571085210",
amtTotal: "495219432838165894607849",
volTotal: "160361920703773434177",
},
{
price: 0.00031395,
amt: "12127129883064173669497",
vol: "3807353312345966580",
amtTotal: "483424518529704699752259",
volTotal: "156666548371202348967",
},
{
price: 0.0003146,
amt: "11746060536480763829870",
vol: "3695372332571085210",
amtTotal: "471297388646640526082762",
volTotal: "152859195058856382387",
},
{
price: 0.00031524,
amt: "11722109721002274877424",
vol: "3695372332571085210",
amtTotal: "459551328110159762252892",
volTotal: "149163822726285297177",
},
{
price: 0.0003159,
amt: "12052351993023897680738",
vol: "3807353312345966580",
amtTotal: "447829218389157487375468",
volTotal: "145468450393714211967",
},
{
price: 0.00031655,
amt: "11673707113082743010268",
vol: "3695372332571085210",
amtTotal: "435776866396133589694730",
volTotal: "141661097081368245387",
},
{
price: 0.00031699,
amt: "615000000000000000000",
vol: "194954999999999949",
amtTotal: "424103159283050846684462",
volTotal: "137965724748797160177",
},
{
price: 0.00031719,
amt: "11649977142974837964110",
vol: "3695372332571085210",
amtTotal: "423488159283050846684462",
volTotal: "137770769748797160228",
},
{
price: 0.00031784,
amt: "11626319455782556517212",
vol: "3695372332571085210",
amtTotal: "411838182140076008720352",
volTotal: "134075397416226075018",
},
{
price: 0.0003185,
amt: "11953964321007990024755",
vol: "3807353312345966580",
amtTotal: "400211862684293452203140",
volTotal: "130380025083654989808",
},
{
price: 0.00031934,
amt: "11571837200722111826863",
vol: "3695372332571085210",
amtTotal: "388257898363285462178385",
volTotal: "126572671771309023228",
},
{
price: 0.00031979,
amt: "11555429099390519988949",