jsir 1.2.9 → 1.3.1
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/cmd/ooa.js +238 -286
- package/evalCode.js +14 -0
- package/index.js +0 -1
- package/package.json +2 -5
- package/util.js +172 -52
- package/cmd/ethPrivateHit.js +0 -64
- package/ethWeb.js +0 -1241
- package/source/uniFact.json +0 -193
- package/source/uniPair.json +0 -713
package/ethWeb.js
DELETED
|
@@ -1,1241 +0,0 @@
|
|
|
1
|
-
let {BigNumber, getLibDataDir, trim, toBigNum, getConfig, objDataFile, infoStr, errorStr, batchAsync,
|
|
2
|
-
eFn, removeFirst, randomInt, splitArray, sleep, vl, cacheFn, isError, bMin, getOr, errorStack} = require('./util')
|
|
3
|
-
const abiDecoder = require('abi-decoder');
|
|
4
|
-
let fs = require('fs')
|
|
5
|
-
let contractMapPath = getLibDataDir() + "/contractMap.json"
|
|
6
|
-
let erc20Abi = require('./source/erc20Abi')
|
|
7
|
-
let createKeccakHash = require('keccak')
|
|
8
|
-
let tokenMapCache = {}
|
|
9
|
-
const util = require('ethereumjs-util')
|
|
10
|
-
const Tx = require('ethereumjs-tx');
|
|
11
|
-
const ethers = require("ethers")
|
|
12
|
-
let { Interface } = require('@ethersproject/abi')
|
|
13
|
-
const batchCallAbi = [{"inputs":[{"internalType":"bool","name":"atom","type":"bool"},{"components":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct main.Call[]","name":"calls","type":"tuple[]"}],"name":"aggregate","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes[]","name":"returnData","type":"bytes[]"},{"internalType":"bool[]","name":"results","type":"bool[]"}],"stateMutability":"nonpayable","type":"function"}]
|
|
14
|
-
let Web3Contract = require('web3-eth-contract');
|
|
15
|
-
|
|
16
|
-
let batchCallAddressMap = {
|
|
17
|
-
1: '0xf375451681f567bEB7AeAD101F7944C2574718Eb',
|
|
18
|
-
128: '0x0817dC05EAb0A0C8aDBafDbE35883B5e5DD8a299',
|
|
19
|
-
137: '0xa36e94d707ff68629F01f0886c4d790459b90fB4',
|
|
20
|
-
66: '0x5a8138bF21BdCf8424A999069F24f6F7A065F6A0',
|
|
21
|
-
56: '0x3C23d715f13797CDF93E54a054ACa2d3A98DD18C',
|
|
22
|
-
250: '0x8D334d8fd2da9D610Ec69eef7a44fA6a2AcE1fD9',
|
|
23
|
-
1313161554: '0x4633F95925951F856544DD7ADaE262Bb487c3422'
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function _ethBatchQuery(calls = [], web3) {
|
|
27
|
-
web3 = web3 || global.web3;
|
|
28
|
-
let chainId = global.chainId || await web3.eth.getChainId()
|
|
29
|
-
let batchCallAddress = batchCallAddressMap[chainId]
|
|
30
|
-
if (!batchCallAddress) {
|
|
31
|
-
throw 'batchCallAddress not found on chainId ' + chainId
|
|
32
|
-
}
|
|
33
|
-
if (calls.length === 0) {
|
|
34
|
-
return []
|
|
35
|
-
}
|
|
36
|
-
const itfs = calls.map(call => newAbiInterface(call.abi))
|
|
37
|
-
const calldata = calls.map((call, i) => [call.address.toLowerCase(), itfs[i].encodeFunctionData(call.name || call.method, call.params || call.args || [])])
|
|
38
|
-
const { returnData } = await newContract(web3, batchCallAbi, batchCallAddress).methods.aggregate(false, calldata).call()
|
|
39
|
-
let pros = []
|
|
40
|
-
for(let i = 0; i<returnData.length; i++) {
|
|
41
|
-
let data = returnData[i]
|
|
42
|
-
let result
|
|
43
|
-
let error
|
|
44
|
-
try {
|
|
45
|
-
result = itfs[i].decodeFunctionResult(calls[i].name || calls[i].method, data)
|
|
46
|
-
} catch (e) {
|
|
47
|
-
$log(new Error(errorStack(e)).stack)
|
|
48
|
-
error = e
|
|
49
|
-
}
|
|
50
|
-
pros.push(new Promise(async resolve => {
|
|
51
|
-
if (calls[i].callback) {
|
|
52
|
-
try {
|
|
53
|
-
await calls[i].callback(error, result)
|
|
54
|
-
} catch (e) {
|
|
55
|
-
$log(new Error(errorStack(e)).stack)
|
|
56
|
-
resolve(result || error);
|
|
57
|
-
throw e
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
resolve(result || error);
|
|
61
|
-
}))
|
|
62
|
-
}
|
|
63
|
-
return await Promise.all(pros);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function ethBatchQuery(calls = [], web3, batchNum = 49, asyncNum = 33, useWebReq = false) {
|
|
67
|
-
web3 = web3 || global.web3;
|
|
68
|
-
let chainId = global.chainId || await web3.eth.getChainId()
|
|
69
|
-
if (batchCallAddressMap[chainId] && !useWebReq) {
|
|
70
|
-
return await ethBatchQuery_(calls, web3, batchNum, asyncNum)
|
|
71
|
-
} else {
|
|
72
|
-
let transResult = result => {
|
|
73
|
-
if (!result) {
|
|
74
|
-
return [null]
|
|
75
|
-
}
|
|
76
|
-
if (result.constructor.name !== 'Result') {
|
|
77
|
-
return [result]
|
|
78
|
-
} else {
|
|
79
|
-
let temp = []
|
|
80
|
-
for (let key of Object.keys(result)) {
|
|
81
|
-
if (/^\d+$/.test(key)) {
|
|
82
|
-
temp.push(result[key])
|
|
83
|
-
} else {
|
|
84
|
-
temp[key] = result[key]
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return temp;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
let newCalls = []
|
|
91
|
-
for (let call of calls) {
|
|
92
|
-
let item = {
|
|
93
|
-
method: newContract(web3, call.abi, call.address)
|
|
94
|
-
.methods[call.name || call.method](...(call.args || call.params || []))
|
|
95
|
-
.call
|
|
96
|
-
}
|
|
97
|
-
if (call.callback) {
|
|
98
|
-
item.callback = async (error, result) => {
|
|
99
|
-
await call.callback(error, transResult(result))
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
newCalls.push(item)
|
|
103
|
-
}
|
|
104
|
-
let results = await web3BatchReq(newCalls, batchNum, asyncNum, web3)
|
|
105
|
-
let newResults = []
|
|
106
|
-
for (let result of results) {
|
|
107
|
-
if (isError(result)) {
|
|
108
|
-
newResults.push(result)
|
|
109
|
-
continue
|
|
110
|
-
}
|
|
111
|
-
newResults.push(transResult(result))
|
|
112
|
-
}
|
|
113
|
-
return newResults
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async function ethBatchQuery_(calls = [], web3, batchNum, asyncNum) {
|
|
118
|
-
if (calls.length <= 0) {
|
|
119
|
-
return []
|
|
120
|
-
}
|
|
121
|
-
if (batchNum) {
|
|
122
|
-
let callBatchs = splitArray(calls, batchNum)
|
|
123
|
-
return (await batchAsync(callBatchs.map(item => () => _ethBatchQuery(item, web3)), asyncNum))
|
|
124
|
-
.reduce((a,b) => a.concat(b))
|
|
125
|
-
}
|
|
126
|
-
return _ethBatchQuery(calls, web3)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// avoid memory leak
|
|
130
|
-
function newAbiInterface(abi) {
|
|
131
|
-
if (!global.$abiInterfaces) {
|
|
132
|
-
global.$abiInterfaces = {}
|
|
133
|
-
}
|
|
134
|
-
let key = JSON.stringify(abi)
|
|
135
|
-
if (!global.$abiInterfaces[key]) {
|
|
136
|
-
global.$abiInterfaces[key] = new Interface(abi)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return global.$abiInterfaces[key]
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function initRootWallet(mnemonic) {
|
|
143
|
-
let wallets = {}
|
|
144
|
-
return {
|
|
145
|
-
getWallet(i) {
|
|
146
|
-
i = String(i)
|
|
147
|
-
if (!wallets[i]) {
|
|
148
|
-
if (/^\d+$/.test(i)) {
|
|
149
|
-
wallets[i] = ethers.Wallet.fromMnemonic(mnemonic, `m/44\'/60\'/0\'/0/${i}`)
|
|
150
|
-
} else {
|
|
151
|
-
wallets[i] = new ethers.Wallet(i);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return wallets[i]
|
|
155
|
-
},
|
|
156
|
-
getAddress(i){
|
|
157
|
-
return this.getWallet(i).address
|
|
158
|
-
},
|
|
159
|
-
getPrivateKey(i){
|
|
160
|
-
return this.getWallet(i).privateKey
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
async function erc20Query(address, method, ...args) {
|
|
166
|
-
try {
|
|
167
|
-
const contract = newContract(web3, erc20Abi, address);
|
|
168
|
-
return await contract.methods[method](...args).call()
|
|
169
|
-
} catch (e) {
|
|
170
|
-
$log(new Error(errorStack(e)).stack)
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async function initSender(web3, wallet, froms, resetNum) {
|
|
176
|
-
let senderQueue = {}
|
|
177
|
-
let senderBlock = {}
|
|
178
|
-
let senderNonce = {}
|
|
179
|
-
let senderResetNum = Number(resetNum)
|
|
180
|
-
|
|
181
|
-
for(let aIndex of froms) {
|
|
182
|
-
senderNonce[aIndex] = Number(await web3.eth.getTransactionCount(walletGet(wallet, aIndex).address)) -1
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
let sender = async (txObject) => {
|
|
186
|
-
let aIndex = froms[randomInt(froms.length) - 1]
|
|
187
|
-
let adInfo = walletGet(wallet, aIndex)
|
|
188
|
-
|
|
189
|
-
if (!(txObject.gasLimit || txObject.gas)) {
|
|
190
|
-
try {
|
|
191
|
-
let gas = await web3.eth.estimateGas({
|
|
192
|
-
from: adInfo.address,
|
|
193
|
-
to: txObject.to,
|
|
194
|
-
value: txObject.value,
|
|
195
|
-
data: txObject.data
|
|
196
|
-
})
|
|
197
|
-
txObject.gasLimit = gas + 10000;
|
|
198
|
-
} catch (e) {
|
|
199
|
-
return [Promise.reject(e), {}, aIndex]
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (senderBlock[aIndex]) {
|
|
204
|
-
return []
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (!senderQueue[aIndex]) {
|
|
208
|
-
senderQueue[aIndex] = []
|
|
209
|
-
}
|
|
210
|
-
senderNonce[aIndex] ++
|
|
211
|
-
txObject.nonce = senderNonce[aIndex]
|
|
212
|
-
let signedTx = txnSign(txObject, adInfo.privateKey)
|
|
213
|
-
|
|
214
|
-
let result = web3.eth.sendSignedTransaction(signedTx.rawTransaction).then(resp => {
|
|
215
|
-
removeFirst(senderQueue[aIndex], result)
|
|
216
|
-
return Promise.resolve(resp)
|
|
217
|
-
}).catch(e => {
|
|
218
|
-
removeFirst(senderQueue[aIndex], result)
|
|
219
|
-
return Promise.reject(e)
|
|
220
|
-
})
|
|
221
|
-
senderQueue[aIndex].push(result)
|
|
222
|
-
|
|
223
|
-
let nonce = senderNonce[aIndex]
|
|
224
|
-
if (nonce > 0 && senderResetNum > 0 && nonce%senderResetNum === 0) {
|
|
225
|
-
senderBlock[aIndex] = true
|
|
226
|
-
let queueFin = async () => {
|
|
227
|
-
try {
|
|
228
|
-
senderNonce[aIndex] = Number(await web3.eth.getTransactionCount(adInfo.address)) -1
|
|
229
|
-
} catch (e) {}
|
|
230
|
-
senderBlock[aIndex] = false
|
|
231
|
-
}
|
|
232
|
-
Promise.all(senderQueue[aIndex]).then(queueFin).catch(queueFin)
|
|
233
|
-
}
|
|
234
|
-
return [result, signedTx, aIndex]
|
|
235
|
-
}
|
|
236
|
-
sender.web3 = web3
|
|
237
|
-
return sender
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async function initSenderWithKeys(web3, privateKeys, resetNum) {
|
|
241
|
-
let senderQueue = {}
|
|
242
|
-
let senderBlock = {}
|
|
243
|
-
let senderNonce = {}
|
|
244
|
-
let senderResetNum = Number(resetNum)
|
|
245
|
-
|
|
246
|
-
let keyMap = {}
|
|
247
|
-
for(let key of privateKeys) {
|
|
248
|
-
let adds = privateToAddress(key)
|
|
249
|
-
senderNonce[adds] = Number(await web3.eth.getTransactionCount(adds)) -1
|
|
250
|
-
keyMap[key] = adds
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
let sender = async (txObject) => {
|
|
254
|
-
let key = privateKeys[randomInt(privateKeys.length) - 1]
|
|
255
|
-
let adds = keyMap[key]
|
|
256
|
-
|
|
257
|
-
if (!(txObject.gasLimit || txObject.gas)) {
|
|
258
|
-
try {
|
|
259
|
-
let gas = await web3.eth.estimateGas({
|
|
260
|
-
from: adds,
|
|
261
|
-
to: txObject.to,
|
|
262
|
-
value: txObject.value,
|
|
263
|
-
data: txObject.data
|
|
264
|
-
})
|
|
265
|
-
txObject.gasLimit = gas + 10000;
|
|
266
|
-
} catch (e) {
|
|
267
|
-
return [Promise.reject(e), {}, adds]
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
if (senderBlock[adds]) {
|
|
272
|
-
return []
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
if (!senderQueue[adds]) {
|
|
276
|
-
senderQueue[adds] = []
|
|
277
|
-
}
|
|
278
|
-
senderNonce[adds] ++
|
|
279
|
-
txObject.nonce = senderNonce[adds]
|
|
280
|
-
let signedTx = txnSign(txObject, key)
|
|
281
|
-
|
|
282
|
-
let result = web3.eth.sendSignedTransaction(signedTx.rawTransaction).then(resp => {
|
|
283
|
-
removeFirst(senderQueue[adds], result)
|
|
284
|
-
return Promise.resolve(resp)
|
|
285
|
-
}).catch(e => {
|
|
286
|
-
removeFirst(senderQueue[adds], result)
|
|
287
|
-
return Promise.reject(e)
|
|
288
|
-
})
|
|
289
|
-
senderQueue[adds].push(result)
|
|
290
|
-
|
|
291
|
-
let nonce = senderNonce[adds]
|
|
292
|
-
if (nonce > 0 && senderResetNum > 0 && nonce%senderResetNum === 0) {
|
|
293
|
-
senderBlock[adds] = true
|
|
294
|
-
let queueFin = async () => {
|
|
295
|
-
try {
|
|
296
|
-
senderNonce[adds] = Number(await web3.eth.getTransactionCount(adds)) - 1
|
|
297
|
-
} catch (e) {}
|
|
298
|
-
senderBlock[adds] = false
|
|
299
|
-
}
|
|
300
|
-
Promise.all(senderQueue[adds]).then(queueFin).catch(queueFin)
|
|
301
|
-
}
|
|
302
|
-
return [result, signedTx, adds]
|
|
303
|
-
}
|
|
304
|
-
sender.web3 = web3
|
|
305
|
-
return sender
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function privateToAddress(privateKey) {
|
|
309
|
-
return util.bufferToHex(util.privateToAddress(util.toBuffer('0x' + privateKey.replace(/^0x/, ''))))
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
function txnSign(txObject, privateKey) {
|
|
313
|
-
let params = {
|
|
314
|
-
nonce: web3.utils.toHex(txObject.nonce),
|
|
315
|
-
gasPrice: web3.utils.toHex(txObject.gasPrice),
|
|
316
|
-
gasLimit: web3.utils.toHex(txObject.gasLimit || txObject.gas),
|
|
317
|
-
to: txObject.to,
|
|
318
|
-
value: web3.utils.toHex(txObject.value),
|
|
319
|
-
data: txObject.data
|
|
320
|
-
}
|
|
321
|
-
if (global.chainId) {
|
|
322
|
-
params.chainId = web3.utils.toHex(global.chainId)
|
|
323
|
-
}
|
|
324
|
-
let tx = new Tx(params);
|
|
325
|
-
tx.sign(util.toBuffer(privateKey));
|
|
326
|
-
let serializedTx = tx.serialize();
|
|
327
|
-
|
|
328
|
-
let transactionHash = "0x" + tx.hash().toString("hex")
|
|
329
|
-
let rawTransaction = '0x' + serializedTx.toString('hex')
|
|
330
|
-
return {
|
|
331
|
-
transactionHash,
|
|
332
|
-
rawTransaction,
|
|
333
|
-
hash: transactionHash,
|
|
334
|
-
raw: rawTransaction
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
function walletGet(wallet, i) {
|
|
339
|
-
i = Number(i)
|
|
340
|
-
return {
|
|
341
|
-
address: wallet.getAddress(i),
|
|
342
|
-
privateKey: wallet.getPrivateKey(i),
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
async function sendTxn(privateKey, toAddress, value, contract, method, ...args) {
|
|
347
|
-
let ADDRESS = util.bufferToHex(util.privateToAddress(util.toBuffer('0x' + privateKey.replace(/^0x/, ''))))
|
|
348
|
-
let signTxn = await web3.eth.accounts.signTransaction({
|
|
349
|
-
from: ADDRESS,
|
|
350
|
-
to: toAddress,
|
|
351
|
-
value,
|
|
352
|
-
gas: 1000000,
|
|
353
|
-
gasPrice: Number(await web3.eth.getGasPrice()) + (Number(getConfig("gasAddGwei") || 0) * 1000 * 1000 * 1000),
|
|
354
|
-
data: contract.methods[method](...args).encodeABI()
|
|
355
|
-
}, privateKey)
|
|
356
|
-
|
|
357
|
-
console.log(`begin send txn ${signTxn.transactionHash}`)
|
|
358
|
-
try {
|
|
359
|
-
await web3.eth.sendSignedTransaction(signTxn.rawTransaction)
|
|
360
|
-
console.info(`发送成功:${signTxn.transactionHash}`)
|
|
361
|
-
} catch (e) {
|
|
362
|
-
console.error(`发送失败:${signTxn.transactionHash}`)
|
|
363
|
-
console.log(String(e))
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function gasPrice() {
|
|
368
|
-
return web3.utils.fromWei(await web3.eth.getGasPrice(), 'gwei')
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// avoid memory leak
|
|
372
|
-
function newContract(web3, abi, address) {
|
|
373
|
-
if (!global.$contracts) {
|
|
374
|
-
global.$contracts = {}
|
|
375
|
-
}
|
|
376
|
-
if (address) {
|
|
377
|
-
address = address.toLowerCase()
|
|
378
|
-
}
|
|
379
|
-
let key = [String(chainId), JSON.stringify(abi), address].filter(i => i).join("-")
|
|
380
|
-
|
|
381
|
-
if (!global.$contracts[key]) {
|
|
382
|
-
global.$contracts[key] = new web3.eth.Contract(abi, address);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
return global.$contracts[key]
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// avoid memory leak
|
|
389
|
-
function newWeb3Contract(abi, address) {
|
|
390
|
-
if (!global.$web3Contracts) {
|
|
391
|
-
global.$web3Contracts = {}
|
|
392
|
-
}
|
|
393
|
-
if (address) {
|
|
394
|
-
address = address.toLowerCase()
|
|
395
|
-
}
|
|
396
|
-
let key = [JSON.stringify(abi), address].filter(i => i).join("-")
|
|
397
|
-
|
|
398
|
-
if (!global.$web3Contracts[key]) {
|
|
399
|
-
global.$web3Contracts[key] = new Web3Contract(abi, address);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
return global.$web3Contracts[key]
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
async function tokenMap(address, web3) {
|
|
406
|
-
if (!address) {
|
|
407
|
-
return {name: '本币', decimals: 18, symbol: '本币'}
|
|
408
|
-
}
|
|
409
|
-
address = '0x' + address.toLowerCase().replace(/^0x/, '')
|
|
410
|
-
let chainMap = await getTokenMap([address], web3)
|
|
411
|
-
|
|
412
|
-
if (chainMap[address]) {
|
|
413
|
-
let decimals = chainMap[address].decimals
|
|
414
|
-
if (Number.isNaN(Number(String(decimals)))) {
|
|
415
|
-
throw new Error(`invalid token decimals ${address} ${decimals}`)
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
return chainMap[address]
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
async function getLastBlockSecTime() {
|
|
423
|
-
let blockNum = await web3.eth.getBlockNumber();
|
|
424
|
-
let blockInfo = await web3.eth.getBlock(blockNum)
|
|
425
|
-
return blockInfo.timestamp
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
async function getPrice(token0Addr, token1Addr, factory, web3) {
|
|
429
|
-
web3 = web3 || global.web3;
|
|
430
|
-
return await getPriceByAmt(token0Addr, token1Addr, 1, factory, web3)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
async function getPriceNoFee(token0Addr, token1Addr, factory, web3) {
|
|
434
|
-
web3 = web3 || global.web3;
|
|
435
|
-
return await getPriceByAmtNoFee(token0Addr, token1Addr, 1, factory, web3)
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
//返回买入baseAmt个a所需要的b数
|
|
439
|
-
//包含千三手续费
|
|
440
|
-
async function getPriceByAmt(token0Addr, token1Addr, token0Amt, factory, web3) {
|
|
441
|
-
web3 = web3 || global.web3;
|
|
442
|
-
token0Amt = toBigNum(token0Amt)
|
|
443
|
-
let result = await getPoolAmt(token0Addr, token1Addr, factory, web3)
|
|
444
|
-
return getPairAmt(result[0], result[1], token0Amt)
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
//返回买入baseAmt个a所需要的b数
|
|
448
|
-
//不包含千三手续费
|
|
449
|
-
async function getPriceByAmtNoFee(token0Addr, token1Addr, token0Amt, factory, web3) {
|
|
450
|
-
web3 = web3 || global.web3;
|
|
451
|
-
token0Amt = toBigNum(token0Amt)
|
|
452
|
-
let result = await getPoolAmt(token0Addr, token1Addr, factory, web3)
|
|
453
|
-
return getPairAmtNoFee(result[0], result[1], token0Amt)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// 获得池子中两种币的数量
|
|
457
|
-
async function getPoolAmt(token0Addr, token1Addr, factory, web3) {
|
|
458
|
-
web3 = web3 || global.web3;
|
|
459
|
-
let tokenOInfo = await tokenMap(token0Addr, web3)
|
|
460
|
-
let token1Info = await tokenMap(token1Addr, web3)
|
|
461
|
-
|
|
462
|
-
let pair = await ethQuery1(web3, factory, require('./source/uniFact'), 'getPair', token0Addr, token1Addr)
|
|
463
|
-
if (!pair) {
|
|
464
|
-
return null;
|
|
465
|
-
}
|
|
466
|
-
let pairToken0 = await ethQuery1(web3, pair, require('./source/uniPair'), "token0")
|
|
467
|
-
|
|
468
|
-
let result = await ethQuery1(web3, pair, require('./source/uniPair'), "getReserves")
|
|
469
|
-
|
|
470
|
-
let num0;
|
|
471
|
-
let num1;
|
|
472
|
-
if (pairToken0.toLowerCase() === token0Addr.toLowerCase()) {
|
|
473
|
-
num0 = exDcmNum(result[0], -parseInt(tokenOInfo['decimals']))
|
|
474
|
-
num1 = exDcmNum(result[1], -parseInt(token1Info['decimals']))
|
|
475
|
-
} else {
|
|
476
|
-
num1 = exDcmNum(result[0], -parseInt(token1Info['decimals']))
|
|
477
|
-
num0= exDcmNum(result[1], -parseInt(tokenOInfo['decimals']))
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return [num0, num1]
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
//返回买入baseAmt个a所需要的b数
|
|
484
|
-
//包含千三手续费
|
|
485
|
-
function getPairAmt(a, b, baseAmt) {
|
|
486
|
-
return toBigNum(getPairAmtNoFee(a,b,baseAmt)).abs().multipliedBy(Number(baseAmt) > 0 ? 1.003:0.997).toFixed(9).toString()
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
//返回买入baseAmt个a所需要的b数
|
|
490
|
-
//不包含千三手续费
|
|
491
|
-
function getPairAmtNoFee(a, b, baseAmt) {
|
|
492
|
-
a = toBigNum(String(a))
|
|
493
|
-
b = toBigNum(String(b))
|
|
494
|
-
baseAmt = toBigNum(String(baseAmt))
|
|
495
|
-
let out = a.multipliedBy(b).dividedBy(a.minus(baseAmt)).minus(b)
|
|
496
|
-
|
|
497
|
-
if (a.minus(baseAmt).comparedTo(0) < 0 || b.plus(out).comparedTo(0) < 0) {
|
|
498
|
-
throw "exceed pool"
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
return out.abs().toFixed(9).toString()
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
let tokenMapLoaded = {}
|
|
505
|
-
let tokenMapLoadSize = {}
|
|
506
|
-
async function saveTokenMap(web3) {
|
|
507
|
-
web3 = web3 || global.web3;
|
|
508
|
-
let chainId = global.chainId || await web3.getChainId()
|
|
509
|
-
let chainMap = getOr(tokenMapCache, chainId, {})
|
|
510
|
-
let tokenMapFile = `tokenMap_${chainId}`
|
|
511
|
-
if (!tokenMapLoaded[chainId]) {
|
|
512
|
-
let temp = objDataFile(tokenMapFile)
|
|
513
|
-
tokenMapLoadSize[chainId] = Object.keys(temp).length
|
|
514
|
-
Object.assign(chainMap, temp)
|
|
515
|
-
tokenMapLoaded[chainId] = true
|
|
516
|
-
}
|
|
517
|
-
if (Object.keys(chainMap).length > tokenMapLoadSize[chainId]) {
|
|
518
|
-
await objDataFile(tokenMapFile, () => chainMap);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
async function getTokenMap(tokens, web3, batchNum, asyncNum) {
|
|
522
|
-
web3 = web3 || global.web3;
|
|
523
|
-
let chainId = global.chainId || await web3.getChainId()
|
|
524
|
-
let chainMap = getOr(tokenMapCache, chainId, {})
|
|
525
|
-
if (!tokenMapLoaded[chainId]) {
|
|
526
|
-
let tokenMapFile = `tokenMap_${chainId}`
|
|
527
|
-
let temp = objDataFile(tokenMapFile)
|
|
528
|
-
tokenMapLoadSize[chainId] = Object.keys(temp).length
|
|
529
|
-
Object.assign(chainMap, temp)
|
|
530
|
-
tokenMapLoaded[chainId] = true
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
tokens = tokens || []
|
|
534
|
-
tokens = tokens.map(token => '0x' + token.toLowerCase().replace(/^0x/, ''))
|
|
535
|
-
tokens = [...new Set(tokens)]
|
|
536
|
-
tokens = tokens.filter(token => !chainMap[token])
|
|
537
|
-
if (tokens.length <= 0) {
|
|
538
|
-
return chainMap
|
|
539
|
-
}
|
|
540
|
-
let calls = []
|
|
541
|
-
for (let token of tokens) {
|
|
542
|
-
calls.push({
|
|
543
|
-
abi: erc20Abi,
|
|
544
|
-
address: token,
|
|
545
|
-
name: 'name'
|
|
546
|
-
})
|
|
547
|
-
calls.push({
|
|
548
|
-
abi: erc20Abi,
|
|
549
|
-
address: token,
|
|
550
|
-
name: 'symbol'
|
|
551
|
-
})
|
|
552
|
-
calls.push({
|
|
553
|
-
abi: erc20Abi,
|
|
554
|
-
address: token,
|
|
555
|
-
name: 'decimals'
|
|
556
|
-
})
|
|
557
|
-
}
|
|
558
|
-
let results = await ethBatchQuery(calls, web3, batchNum, asyncNum)
|
|
559
|
-
for(let i = 0; i<results.length; i+=3) {
|
|
560
|
-
let token = calls[i].address
|
|
561
|
-
try {
|
|
562
|
-
if (isError(results[i]) || isError(results[i + 1]) || isError(results[i + 2])) {
|
|
563
|
-
$log(`${token} erc20 info error`)
|
|
564
|
-
continue
|
|
565
|
-
}
|
|
566
|
-
chainMap[token] = {
|
|
567
|
-
name: results[i] ? results[i][0] : null,
|
|
568
|
-
symbol: results[i + 1] ? results[i + 1][0] : null,
|
|
569
|
-
decimals: results[i + 2] ? results[i + 2][0] : null,
|
|
570
|
-
}
|
|
571
|
-
} catch (e) {
|
|
572
|
-
$log(`${token} erc20 info error`)
|
|
573
|
-
$log(new Error(errorStack(e)).stack)
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
return chainMap
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
async function getReserves(pairs, factory, fmt, web3) {
|
|
580
|
-
web3 = web3 || global.web3;
|
|
581
|
-
|
|
582
|
-
if (!Array.isArray(pairs[0])) {
|
|
583
|
-
pairs = [pairs]
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
let calls = []
|
|
587
|
-
let uniFact = require('./source/uniFact')
|
|
588
|
-
for(let i = 0; i < pairs.length; i++) {
|
|
589
|
-
let pair = pairs[i]
|
|
590
|
-
calls.push({
|
|
591
|
-
abi: uniFact,
|
|
592
|
-
address: factory,
|
|
593
|
-
name: 'getPair',
|
|
594
|
-
params: pair
|
|
595
|
-
})
|
|
596
|
-
}
|
|
597
|
-
let results = await ethBatchQuery(calls, web3)
|
|
598
|
-
let pairMap = {}
|
|
599
|
-
for(let i = 0; i<results.length; i++) {
|
|
600
|
-
let call = calls[i]
|
|
601
|
-
if (results[i]) {
|
|
602
|
-
pairMap[results[i][0]] = pairMap[call.params.join('-')] = {
|
|
603
|
-
pairAddress: results[i][0]
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
let uniPair = require('./source/uniPair')
|
|
610
|
-
calls = []
|
|
611
|
-
for(let i = 0; i<pairs.length; i++) {
|
|
612
|
-
let pair = pairs[i]
|
|
613
|
-
let pairInfo = pairMap[pair.join('-')]
|
|
614
|
-
if (!pairInfo) {
|
|
615
|
-
continue
|
|
616
|
-
}
|
|
617
|
-
calls.push({
|
|
618
|
-
abi: uniPair,
|
|
619
|
-
address: pairInfo.pairAddress,
|
|
620
|
-
name: 'token0'
|
|
621
|
-
})
|
|
622
|
-
calls.push({
|
|
623
|
-
abi: uniPair,
|
|
624
|
-
address: pairInfo.pairAddress,
|
|
625
|
-
name: 'getReserves'
|
|
626
|
-
})
|
|
627
|
-
}
|
|
628
|
-
results = await ethBatchQuery(calls, web3)
|
|
629
|
-
for(let i = 0; i < results.length; i+=2) {
|
|
630
|
-
let call = calls[i]
|
|
631
|
-
pairMap[call.address].token0 = results[i][0]
|
|
632
|
-
pairMap[call.address].reserves = results[i + 1].map(i => i.toString()).slice(0, 2)
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
let tokenMap
|
|
636
|
-
if (fmt) {
|
|
637
|
-
let tempMap = {}
|
|
638
|
-
for (let pair of pairs) {
|
|
639
|
-
tempMap[pair[0]] = true;
|
|
640
|
-
tempMap[pair[1]] = true;
|
|
641
|
-
}
|
|
642
|
-
tokenMap = await getTokenMap(Object.keys(tempMap), web3)
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
let rs = []
|
|
646
|
-
for(let i =0; i<pairs.length; i++) {
|
|
647
|
-
let pair = pairs[i]
|
|
648
|
-
let pairInfo = pairMap[pair.join('-')]
|
|
649
|
-
if (!pairInfo) {
|
|
650
|
-
rs.push([])
|
|
651
|
-
continue
|
|
652
|
-
}
|
|
653
|
-
let item
|
|
654
|
-
if (pairInfo.token0.toLowerCase() === pair[0].toLowerCase()) {
|
|
655
|
-
item = pairInfo.reserves
|
|
656
|
-
} else {
|
|
657
|
-
item = pairInfo.reserves.reverse()
|
|
658
|
-
}
|
|
659
|
-
rs.push(item)
|
|
660
|
-
if (fmt) {
|
|
661
|
-
let tokenOInfo = tokenMap[pair[0].toLowerCase()]
|
|
662
|
-
let token1Info = tokenMap[pair[1].toLowerCase()]
|
|
663
|
-
item[0] = exDcmNum(item[0], -tokenOInfo['decimals']).toString()
|
|
664
|
-
item[1] = exDcmNum(item[1], -token1Info['decimals']).toString()
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
return rs.length === 1 ? rs[0]:rs
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
async function fmtErc20Amt(token, amount, direction = 1, web3) {
|
|
671
|
-
web3 = web3 || global.web3;
|
|
672
|
-
let decimals = (await tokenMap(token, web3)).decimals;
|
|
673
|
-
if (direction >= 0) {
|
|
674
|
-
return exDcmNum(amount, direction * decimals).toFixed(0)
|
|
675
|
-
} else {
|
|
676
|
-
return exDcmNum(amount, direction * decimals).toString()
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
async function getTokenBal(address, token, fmt, web3) {
|
|
681
|
-
web3 = web3 || global.web3;
|
|
682
|
-
let bal
|
|
683
|
-
if (token) {
|
|
684
|
-
bal = await ethRead(token, erc20Abi, 'balanceOf', [address])
|
|
685
|
-
} else {
|
|
686
|
-
bal = await web3.eth.getBalance(address)
|
|
687
|
-
}
|
|
688
|
-
if (fmt) {
|
|
689
|
-
return fmtErc20Amt(token, bal, -1, web3)
|
|
690
|
-
}
|
|
691
|
-
return bal
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
function swapExactFor(amount, reserves, fee) {
|
|
695
|
-
fee = fee || 0
|
|
696
|
-
if (!Array.isArray(reserves[0])) {
|
|
697
|
-
reserves = [reserves]
|
|
698
|
-
}
|
|
699
|
-
for(let i = 0; i<reserves.length; i++) {
|
|
700
|
-
let r = reserves[i]
|
|
701
|
-
let a = toBigNum(r[0])
|
|
702
|
-
let b = toBigNum(r[1])
|
|
703
|
-
amount = b.minus(a.multipliedBy(b).dividedBy(a.plus(toBigNum(amount))))
|
|
704
|
-
amount = amount.multipliedBy(1 - Number(fee))
|
|
705
|
-
}
|
|
706
|
-
return amount.toString()
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
function fastSwapExactFor(amount, reserves, fee) {
|
|
710
|
-
fee = fee || 0
|
|
711
|
-
if (!Array.isArray(reserves[0])) {
|
|
712
|
-
reserves = [reserves]
|
|
713
|
-
}
|
|
714
|
-
for(let i = 0; i<reserves.length; i++) {
|
|
715
|
-
let r = reserves[i]
|
|
716
|
-
let a = Number(r[0])
|
|
717
|
-
let b = Number(r[1])
|
|
718
|
-
amount = b - (a*b/(a + Number(amount)))
|
|
719
|
-
amount = amount * (1 - Number(fee))
|
|
720
|
-
}
|
|
721
|
-
return amount
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
function swapForExact(amount, reserves, fee) {
|
|
725
|
-
fee = fee || 0
|
|
726
|
-
if (!Array.isArray(reserves[0])) {
|
|
727
|
-
reserves = [reserves]
|
|
728
|
-
}
|
|
729
|
-
for(let i = reserves.length - 1; i>=0; i--) {
|
|
730
|
-
let r = reserves[i]
|
|
731
|
-
let a = toBigNum(r[0])
|
|
732
|
-
let b = toBigNum(r[1])
|
|
733
|
-
amount = a.multipliedBy(b).div(b.minus(toBigNum(amount))).minus(a)
|
|
734
|
-
amount = amount.multipliedBy(1 + Number(fee))
|
|
735
|
-
}
|
|
736
|
-
return amount.toString()
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
function fastSwapForExact(amount, reserves, fee) {
|
|
740
|
-
fee = fee || 0
|
|
741
|
-
if (!Array.isArray(reserves[0])) {
|
|
742
|
-
reserves = [reserves]
|
|
743
|
-
}
|
|
744
|
-
for(let i = reserves.length - 1; i>=0; i--) {
|
|
745
|
-
let r = reserves[i]
|
|
746
|
-
let a = Number(r[0])
|
|
747
|
-
let b = Number(r[1])
|
|
748
|
-
amount = (a * b / (b - Number(amount))) - a
|
|
749
|
-
amount = amount * (1 + Number(fee))
|
|
750
|
-
}
|
|
751
|
-
return amount
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
function encodeEthAddress(address) {
|
|
755
|
-
if (address.length !== 42) throw new TypeError('Bad address')
|
|
756
|
-
address = address.slice(2).toLowerCase()
|
|
757
|
-
let checksum = createKeccakHash('keccak256')
|
|
758
|
-
.update(address)
|
|
759
|
-
.digest()
|
|
760
|
-
|
|
761
|
-
let ret = '0x'
|
|
762
|
-
for (let i = 0; i < 20; ++i) {
|
|
763
|
-
let byte = checksum[i]
|
|
764
|
-
let ha = address.charAt(i * 2)
|
|
765
|
-
let hb = address.charAt(i * 2 + 1)
|
|
766
|
-
ret += (byte & 0xf0) >= 0x80 ? ha.toUpperCase() : ha
|
|
767
|
-
ret += (byte & 0x0f) >= 0x08 ? hb.toUpperCase() : hb
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
return ret
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
async function ethQuery(web3, address, method, ...args) {
|
|
774
|
-
try {
|
|
775
|
-
const contract = newContract(web3, (await getContractJson(address)).abi, address);
|
|
776
|
-
return await contract.methods[method](...args).call()
|
|
777
|
-
} catch (e) {
|
|
778
|
-
$log(new Error(errorStack(e)).stack)
|
|
779
|
-
return null;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
async function ethQuery1(web3, address, abi, method, ...args) {
|
|
784
|
-
try {
|
|
785
|
-
const contract = newContract(web3, abi, address);
|
|
786
|
-
return await contract.methods[method](...args).call()
|
|
787
|
-
} catch (e) {
|
|
788
|
-
$log(new Error(errorStack(e)).stack)
|
|
789
|
-
return null
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
async function ethRead(address, abi, method, args, web3) {
|
|
794
|
-
web3 = web3 || global.web3
|
|
795
|
-
try {
|
|
796
|
-
const contract = newContract(web3, abi, address);
|
|
797
|
-
return await contract.methods[method](...args).call()
|
|
798
|
-
} catch (e) {
|
|
799
|
-
$log(new Error(errorStack(e)).stack)
|
|
800
|
-
return null
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
function createEthWrite(config = {}) {
|
|
805
|
-
return async (sender, address, opt) => {
|
|
806
|
-
return await ethWrite(sender, address, Object.assign({}, config, opt))
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
async function ethWrite(sender, address,
|
|
811
|
-
{data, abi, method, args, gasPrice, gasPriceAdd, gasLimit,
|
|
812
|
-
value, waitConfirm, sleepSec, msg, onError} = {}) {
|
|
813
|
-
if (!address) {
|
|
814
|
-
throw 'address require for ethWrite'
|
|
815
|
-
}
|
|
816
|
-
let web3 = sender.web3 || global.web3
|
|
817
|
-
|
|
818
|
-
let txObject = {
|
|
819
|
-
gasPrice: gasPrice ? gasPrice * 1000000000 : await cacheFn('getGasPrice', async () => await web3.eth.getGasPrice(), 1000 * 5),
|
|
820
|
-
gasLimit: gasLimit,
|
|
821
|
-
to: address,
|
|
822
|
-
value
|
|
823
|
-
}
|
|
824
|
-
if (gasPriceAdd && !gasPrice) {
|
|
825
|
-
txObject.gasPrice = Number(txObject.gasPrice) + (gasPriceAdd * 1000000000)
|
|
826
|
-
}
|
|
827
|
-
if (method) {
|
|
828
|
-
txObject.data = newContract(web3, abi, address).methods[method](...args).encodeABI()
|
|
829
|
-
}
|
|
830
|
-
if (data) {
|
|
831
|
-
txObject.data = data
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
let [result, signedTx] = await sender(txObject)
|
|
835
|
-
if (!signedTx) {
|
|
836
|
-
console.log("No address to used")
|
|
837
|
-
return {}
|
|
838
|
-
}
|
|
839
|
-
msg = trim(msg)
|
|
840
|
-
msg = msg ? msg + ' ':''
|
|
841
|
-
console.log(`${msg}send ${signedTx.hash} ${txObject.gasPrice/1000000000}g`)
|
|
842
|
-
result = result.then(resp => {
|
|
843
|
-
console.log(infoStr(`${msg}${signedTx.hash} 交易成功`))
|
|
844
|
-
return true
|
|
845
|
-
}).catch(async e => {
|
|
846
|
-
console.log(errorStr(`${msg}${signedTx.hash} 交易失败`))
|
|
847
|
-
if (onError) {
|
|
848
|
-
return await onError(e)
|
|
849
|
-
} else {
|
|
850
|
-
console.error(String(e))
|
|
851
|
-
$log(new Error(errorStack(e)).stack)
|
|
852
|
-
return false
|
|
853
|
-
}
|
|
854
|
-
})
|
|
855
|
-
if (waitConfirm) {
|
|
856
|
-
await result
|
|
857
|
-
}
|
|
858
|
-
if (sleepSec) {
|
|
859
|
-
await sleep(sleepSec * 1000)
|
|
860
|
-
}
|
|
861
|
-
return {
|
|
862
|
-
promise: result
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
function parseInputData(abi, input) {
|
|
867
|
-
abiDecoder.addABI(abi);
|
|
868
|
-
return abiDecoder.decodeMethod(input);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
async function forEachBlock(web3, num, fn) {
|
|
872
|
-
let blockNum = await web3.eth.getBlockNumber();
|
|
873
|
-
while (num > 0 && blockNum > 0) {
|
|
874
|
-
let blockInfo = await web3.eth.getBlock(blockNum)
|
|
875
|
-
|
|
876
|
-
await fn(blockInfo)
|
|
877
|
-
|
|
878
|
-
blockNum --
|
|
879
|
-
num --
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
async function web3BatchReq(items, batchNum = 49, asyncNum = 33, web3) {
|
|
884
|
-
web3 = web3 || global.web3
|
|
885
|
-
if (items.length <= 0) {
|
|
886
|
-
return []
|
|
887
|
-
}
|
|
888
|
-
if (batchNum) {
|
|
889
|
-
let callBatchs = splitArray(items, batchNum)
|
|
890
|
-
return (await batchAsync(callBatchs.map(item => () => _web3BatchReq(item, web3)), asyncNum))
|
|
891
|
-
.reduce((a,b) => a.concat(b))
|
|
892
|
-
}
|
|
893
|
-
return _web3BatchReq(items, web3)
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
async function _web3BatchReq(items, web3) {
|
|
897
|
-
let batcher = new web3.BatchRequest();
|
|
898
|
-
let proms = []
|
|
899
|
-
items.forEach(item => {
|
|
900
|
-
proms.push(
|
|
901
|
-
new Promise(resolve => {
|
|
902
|
-
batcher.add((item.method || item.name).request(...(item.args || item.params || []), async (error, result) => {
|
|
903
|
-
if (item.callback) {
|
|
904
|
-
try {
|
|
905
|
-
await item.callback(error, result)
|
|
906
|
-
} catch (e) {
|
|
907
|
-
$log(new Error(errorStack(e)).stack)
|
|
908
|
-
resolve(result || error);
|
|
909
|
-
throw e
|
|
910
|
-
}
|
|
911
|
-
}
|
|
912
|
-
if (error) {
|
|
913
|
-
$log(new Error(errorStack(error)).stack)
|
|
914
|
-
}
|
|
915
|
-
resolve(result || error);
|
|
916
|
-
}));
|
|
917
|
-
}))
|
|
918
|
-
})
|
|
919
|
-
batcher.execute();
|
|
920
|
-
return await Promise.all(proms)
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
async function forEachBlockBatch(getFromAndTo, fn, web3) {
|
|
924
|
-
web3 = web3 || global.web3;
|
|
925
|
-
let arr = getFromAndTo
|
|
926
|
-
if (!Array.isArray(getFromAndTo)) {
|
|
927
|
-
let blockNum = await web3.eth.getBlockNumber();
|
|
928
|
-
arr = await getFromAndTo(blockNum);
|
|
929
|
-
}
|
|
930
|
-
let [from, to] = arr;
|
|
931
|
-
|
|
932
|
-
let items = []
|
|
933
|
-
for(let i = from; i<= to; i++) {
|
|
934
|
-
items.push({
|
|
935
|
-
method: web3.eth.getBlock,
|
|
936
|
-
args: [i],
|
|
937
|
-
callback: async (...args) => await fn(...args)
|
|
938
|
-
})
|
|
939
|
-
}
|
|
940
|
-
await web3BatchReq(items)
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
async function forEachBlockAsync(web3, num, fn) {
|
|
944
|
-
let blockNum = await web3.eth.getBlockNumber();
|
|
945
|
-
let items = []
|
|
946
|
-
while (num > 0 && blockNum > 0) {
|
|
947
|
-
items.push(eFn(async (blockNum) => {
|
|
948
|
-
let blockInfo = await web3.eth.getBlock(blockNum)
|
|
949
|
-
await fn(blockInfo)
|
|
950
|
-
}, blockNum))
|
|
951
|
-
blockNum --
|
|
952
|
-
num --
|
|
953
|
-
}
|
|
954
|
-
await Promise.all(items);
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
async function forEachEvent(con, eventName, getFromAndTo, callback, filter = {}, web3) {
|
|
958
|
-
web3 = web3 || global.web3;
|
|
959
|
-
let arr = getFromAndTo
|
|
960
|
-
if (!Array.isArray(getFromAndTo)) {
|
|
961
|
-
let blockNum = await web3.eth.getBlockNumber();
|
|
962
|
-
arr = await getFromAndTo(blockNum);
|
|
963
|
-
}
|
|
964
|
-
let [from, to] = arr;
|
|
965
|
-
|
|
966
|
-
let proms = [];
|
|
967
|
-
for(let i = from; i<= to; i+=5000) {
|
|
968
|
-
let prom = new Promise(async resolve => {
|
|
969
|
-
await con.getPastEvents(eventName, {
|
|
970
|
-
filter,
|
|
971
|
-
fromBlock: i,
|
|
972
|
-
toBlock: (i+5000) > to ? to : i+5000
|
|
973
|
-
}, async function(error, events){
|
|
974
|
-
try {
|
|
975
|
-
await callback(error, events)
|
|
976
|
-
} catch (e) {
|
|
977
|
-
resolve()
|
|
978
|
-
throw e
|
|
979
|
-
}
|
|
980
|
-
resolve()
|
|
981
|
-
})
|
|
982
|
-
})
|
|
983
|
-
|
|
984
|
-
if (i % 33 === 0) {
|
|
985
|
-
await prom;
|
|
986
|
-
}
|
|
987
|
-
proms.push(prom)
|
|
988
|
-
}
|
|
989
|
-
await Promise.all(proms)
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
let newSender = async (item) => {
|
|
994
|
-
if (String(item).startsWith('0x')) {
|
|
995
|
-
return await initSenderWithKeys(web3, [item])
|
|
996
|
-
} else {
|
|
997
|
-
return await initSender(web3, global.$wallet, [item])
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
async function batchTranfer(ethTranserWrite, token, froms, tos, min, max) {
|
|
1002
|
-
let decimals = 18
|
|
1003
|
-
let symbol
|
|
1004
|
-
if (token) {
|
|
1005
|
-
let info = await tokenMap(token)
|
|
1006
|
-
decimals = info.decimals
|
|
1007
|
-
symbol = info.symbol
|
|
1008
|
-
}
|
|
1009
|
-
if (!vl(max)) {
|
|
1010
|
-
max = min
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
min = Number(exDcmNum(min, decimals).toFixed(0))
|
|
1014
|
-
max = Number(exDcmNum(max, decimals).toFixed(0))
|
|
1015
|
-
|
|
1016
|
-
let pros = []
|
|
1017
|
-
for(let from of froms) {
|
|
1018
|
-
let sender = await newSender(from)
|
|
1019
|
-
for(let to of tos) {
|
|
1020
|
-
let fromAddress = String(from).startsWith('0x') ? privateToAddress(from):global.$wallet.getAddress(from);
|
|
1021
|
-
let toAddress = String(to).startsWith('0x') ? to:global.$wallet.getAddress(to);
|
|
1022
|
-
|
|
1023
|
-
if (token) {
|
|
1024
|
-
let fb = await ethRead(token, erc20Abi, 'balanceOf', [fromAddress])
|
|
1025
|
-
let tb = await ethRead(token, erc20Abi, 'balanceOf', [toAddress])
|
|
1026
|
-
|
|
1027
|
-
if (Number(tb) >= min) {
|
|
1028
|
-
continue
|
|
1029
|
-
}
|
|
1030
|
-
let transferAmt = BigNumber(bMin(max, tb)).toFixed(0)
|
|
1031
|
-
if (Number(fb) < Number(transferAmt)) {
|
|
1032
|
-
continue
|
|
1033
|
-
}
|
|
1034
|
-
let fmtTransferAmt = exDcmNum(transferAmt, -decimals).toString()
|
|
1035
|
-
pros.push(await ethTranserWrite(sender, token, {
|
|
1036
|
-
abi: erc20Abi,
|
|
1037
|
-
method: 'transfer',
|
|
1038
|
-
args: [toAddress, transferAmt],
|
|
1039
|
-
msg: from + '转' + fmtTransferAmt + symbol +'给' + to
|
|
1040
|
-
}))
|
|
1041
|
-
} else {
|
|
1042
|
-
let fb = await web3.eth.getBalance(fromAddress);
|
|
1043
|
-
let tb = await web3.eth.getBalance(toAddress);
|
|
1044
|
-
|
|
1045
|
-
if (Number(tb) >= min) {
|
|
1046
|
-
continue
|
|
1047
|
-
}
|
|
1048
|
-
let transferAmt = BigNumber(bMin(max, tb)).toFixed(0)
|
|
1049
|
-
if (Number(fb) < Number(transferAmt)) {
|
|
1050
|
-
continue
|
|
1051
|
-
}
|
|
1052
|
-
let fmtTransferAmt = exDcmNum(transferAmt, -decimals).toString()
|
|
1053
|
-
pros.push(await ethTranserWrite(sender, toAddress, {
|
|
1054
|
-
value: transferAmt,
|
|
1055
|
-
msg: from + '转' + fmtTransferAmt + '本币给' + to
|
|
1056
|
-
}))
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
await Promise.all(pros.map(i => i.promise))
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
async function batchCollect(ethTranserWrite, token, froms, to, remain) {
|
|
1064
|
-
let decimals = 18
|
|
1065
|
-
let symbol
|
|
1066
|
-
if (token) {
|
|
1067
|
-
let info = await tokenMap(token)
|
|
1068
|
-
decimals = info.decimals
|
|
1069
|
-
symbol = info.symbol
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
remain = Number(exDcmNum(remain, decimals).toFixed(0))
|
|
1073
|
-
let pros = []
|
|
1074
|
-
for(let from of froms) {
|
|
1075
|
-
let sender = await newSender(from)
|
|
1076
|
-
|
|
1077
|
-
let fromAddress = String(from).startsWith('0x') ? privateToAddress(from):global.$wallet.getAddress(from);
|
|
1078
|
-
let toAddress = String(to).startsWith('0x') ? to:global.$wallet.getAddress(to);
|
|
1079
|
-
|
|
1080
|
-
if (token) {
|
|
1081
|
-
let fb = await ethRead(token, erc20Abi, 'balanceOf', [fromAddress])
|
|
1082
|
-
|
|
1083
|
-
if (Number(fb) <= remain) {
|
|
1084
|
-
continue
|
|
1085
|
-
}
|
|
1086
|
-
let transferAmt = BigNumber(bMin(fb, remain)).toFixed(0)
|
|
1087
|
-
let fmtTransferAmt = exDcmNum(transferAmt, -decimals).toString()
|
|
1088
|
-
pros.push(await ethTranserWrite(sender, token, {
|
|
1089
|
-
abi: erc20Abi,
|
|
1090
|
-
method: 'transfer',
|
|
1091
|
-
args: [toAddress, transferAmt],
|
|
1092
|
-
msg: from + '转' + fmtTransferAmt + symbol +'给' + to
|
|
1093
|
-
}))
|
|
1094
|
-
} else {
|
|
1095
|
-
let fb = await web3.eth.getBalance(fromAddress);
|
|
1096
|
-
|
|
1097
|
-
if (Number(fb) <= remain) {
|
|
1098
|
-
continue
|
|
1099
|
-
}
|
|
1100
|
-
let transferAmt = BigNumber(bMin(fb, remain)).toFixed(0)
|
|
1101
|
-
let fmtTransferAmt = exDcmNum(transferAmt, -decimals).toString()
|
|
1102
|
-
pros.push(await ethTranserWrite(sender, toAddress, {
|
|
1103
|
-
value: transferAmt,
|
|
1104
|
-
msg: from + '转' + fmtTransferAmt + '本币给' + to
|
|
1105
|
-
}))
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
await Promise.all(pros.map(i => i.promise))
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
function coinNum(num, decimals) {
|
|
1112
|
-
return parseFloat(String(new BigNumber(num).dividedBy(new BigNumber(`10e+${(decimals || 18) - 1}`))))
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
function exDcm(num, decimals, fixed) {
|
|
1116
|
-
return new BigNumber(num).multipliedBy(new BigNumber(`1e${(decimals || 18)}`)).toFixed(fixed || 9).toString()
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
function exDcmNum(num, decimals) {
|
|
1120
|
-
return new BigNumber(num).multipliedBy(new BigNumber(`1e${(decimals || 18)}`))
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
async function getContractJson(address) {
|
|
1124
|
-
if (fs.existsSync(address)) {
|
|
1125
|
-
return JSON.parse(String(fs.readFileSync(address)))
|
|
1126
|
-
}
|
|
1127
|
-
if (fs.existsSync(contractMapPath)) {
|
|
1128
|
-
let obj = JSON.parse(String(fs.readFileSync(contractMapPath)))
|
|
1129
|
-
if (obj[address]) {
|
|
1130
|
-
return JSON.parse(String(fs.readFileSync(obj[address]['abiPath'])))
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
async function transferToken(ethTranserWrite, sender, address, token, amt, msg) {
|
|
1136
|
-
if (token) {
|
|
1137
|
-
await ethTranserWrite(sender, token, {
|
|
1138
|
-
abi: erc20Abi,
|
|
1139
|
-
method: 'transfer',
|
|
1140
|
-
args: [address, amt],
|
|
1141
|
-
msg
|
|
1142
|
-
})
|
|
1143
|
-
} else {
|
|
1144
|
-
await ethTranserWrite(sender, address, {
|
|
1145
|
-
value: amt,
|
|
1146
|
-
msg
|
|
1147
|
-
})
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
async function tokenApprove(ethWrite, sender, senderAddress, erc20, spender, opt) {
|
|
1152
|
-
if (!erc20) {
|
|
1153
|
-
return
|
|
1154
|
-
}
|
|
1155
|
-
let {amt = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', msg} = opt
|
|
1156
|
-
let bal = await ethRead(erc20, erc20Abi, 'allowance', [senderAddress, spender])
|
|
1157
|
-
if (bal <Number(amt) ) {
|
|
1158
|
-
return await ethWrite(sender, erc20, {
|
|
1159
|
-
abi: erc20Abi,
|
|
1160
|
-
method: 'approve',
|
|
1161
|
-
args: [spender, amt],
|
|
1162
|
-
msg
|
|
1163
|
-
})
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
return {
|
|
1167
|
-
promise: true
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
function txnInputReplacer(input, callback) {
|
|
1172
|
-
let item = [input.substring(0, 10)]
|
|
1173
|
-
input = input.substring(10, input.length)
|
|
1174
|
-
|
|
1175
|
-
let str = ''
|
|
1176
|
-
while (input.length > 0) {
|
|
1177
|
-
str = input.substring(0, 64);
|
|
1178
|
-
input = input.substring(64, input.length);
|
|
1179
|
-
if (callback) {
|
|
1180
|
-
str = callback(str)
|
|
1181
|
-
}
|
|
1182
|
-
item.push(str)
|
|
1183
|
-
}
|
|
1184
|
-
return item.join('')
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
module.exports = {
|
|
1188
|
-
getContractJson,
|
|
1189
|
-
coinNum,
|
|
1190
|
-
forEachBlock,
|
|
1191
|
-
parseInputData,
|
|
1192
|
-
exDcm,
|
|
1193
|
-
ethQuery,
|
|
1194
|
-
ethQuery1,
|
|
1195
|
-
exDcmNum,
|
|
1196
|
-
encodeEthAddress,
|
|
1197
|
-
gasPrice,
|
|
1198
|
-
tokenMap,
|
|
1199
|
-
getPrice,
|
|
1200
|
-
getPriceNoFee,
|
|
1201
|
-
getPriceByAmt,
|
|
1202
|
-
getPriceByAmtNoFee,
|
|
1203
|
-
getPairAmt,
|
|
1204
|
-
getPairAmtNoFee,
|
|
1205
|
-
getPoolAmt,
|
|
1206
|
-
getLastBlockSecTime,
|
|
1207
|
-
forEachBlockAsync,
|
|
1208
|
-
newContract,
|
|
1209
|
-
sendTxn,
|
|
1210
|
-
walletGet,
|
|
1211
|
-
txnSign,
|
|
1212
|
-
initSender,
|
|
1213
|
-
privateToAddress,
|
|
1214
|
-
initSenderWithKeys,
|
|
1215
|
-
erc20Query,
|
|
1216
|
-
initRootWallet,
|
|
1217
|
-
ethBatchQuery,
|
|
1218
|
-
newAbiInterface,
|
|
1219
|
-
newWeb3Contract,
|
|
1220
|
-
getTokenMap,
|
|
1221
|
-
getReserves,
|
|
1222
|
-
swapExactFor,
|
|
1223
|
-
swapForExact,
|
|
1224
|
-
ethRead,
|
|
1225
|
-
ethWrite,
|
|
1226
|
-
fmtErc20Amt,
|
|
1227
|
-
createEthWrite,
|
|
1228
|
-
forEachBlockBatch,
|
|
1229
|
-
forEachEvent,
|
|
1230
|
-
batchTranfer,
|
|
1231
|
-
batchCollect,
|
|
1232
|
-
web3BatchReq,
|
|
1233
|
-
fastSwapExactFor,
|
|
1234
|
-
fastSwapForExact,
|
|
1235
|
-
getTokenBal,
|
|
1236
|
-
transferToken,
|
|
1237
|
-
tokenApprove,
|
|
1238
|
-
txnInputReplacer,
|
|
1239
|
-
abiDecoder,
|
|
1240
|
-
saveTokenMap
|
|
1241
|
-
}
|