uniswap-v2-loader 5.0.17 → 5.0.19

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.
@@ -35,7 +35,7 @@ jobs:
35
35
 
36
36
  run: npm i -g .
37
37
 
38
- - name: CLI Load first 4 pairs from Uniswap V2 using 2 workers
38
+ - name: Test CLI load first 4 pairs from Uniswap V2 using 2 workers
39
39
  run: uniswap-v2-loader --to=4 --multicall_size=2 --workers=2
40
40
 
41
41
  - name: Run ESM tests
package/README.md CHANGED
@@ -41,6 +41,7 @@ High-performance parallel fetcher for liquidity pairs. Efficiently synchronizes
41
41
  | `multicall_size` | `number` | RPC batch size per multicall request. | `50` |
42
42
  | `workers` | `number` | Number of parallel worker threads. | `CPU - 1` |
43
43
  | `progress` | `function` | Progress callback: `(current, total) => {}`. | `undefined` |
44
+ | `abort_signal` | `AbortSignal` | Signal to cancel loading and release workers. | `undefined` |
44
45
 
45
46
  **Returns**: `Promise<Pair[]>`
46
47
 
package/index.d.ts CHANGED
@@ -36,6 +36,8 @@ export interface load_params {
36
36
  pairs?: pair[]
37
37
  /** Timeout between updates in milliseconds. */
38
38
  update_timeout?: number
39
+ /** Signal to abort the loading process. */
40
+ abort_signal?: AbortSignal
39
41
  }
40
42
 
41
43
  /**
package/index.js CHANGED
@@ -16,9 +16,11 @@ const load = (params = {}) => {
16
16
  from = 0,
17
17
  to,
18
18
  progress,
19
+ abort_signal,
19
20
  workers = max_workers,
20
21
  pairs,
21
22
  } = params
23
+
22
24
  filename ??= default_cache_filename(factory)
23
25
  workers = Math.min(workers, max_workers)
24
26
 
@@ -44,10 +46,11 @@ const load = (params = {}) => {
44
46
 
45
47
  return Promise.resolve(pairs.slice(0, to))
46
48
  }
47
-
49
+
48
50
  return (to
49
51
  ? Promise.resolve(to)
50
52
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
53
+ signal: abort_signal,
51
54
  method: 'POST',
52
55
  headers: { 'Content-Type': 'application/json' },
53
56
  body: JSON.stringify({
@@ -92,7 +95,7 @@ const load = (params = {}) => {
92
95
  const ids = []
93
96
  for (var i = start_loading_from; i < all_pairs_length; i++)
94
97
  ids.push(i)
95
- return require('./loader')({ ids, factory, key, multicall_size }, onpair)
98
+ return require('./loader')({ ids, factory, key, multicall_size, abort_signal }, onpair)
96
99
  .then(() => pairs)
97
100
  }
98
101
 
@@ -112,13 +115,14 @@ const load = (params = {}) => {
112
115
  .filter(_ => _.length)
113
116
  .map((ids, i) => new Promise(y => {
114
117
  const w = cluster.fork()
118
+ abort_signal?.addEventListener('abort', () => w.send('abort'))
115
119
  w.send({ ids, factory, key, multicall_size })
116
120
  w.on('message', onpair)
117
121
  w.on('exit', y)
118
122
  }))
119
123
  ).then(() => pairs)
120
124
  })
121
- .catch(() => new Promise(resolve => setTimeout(() => resolve(load(params)), 1000)))
125
+ .catch(() => abort_signal?.aborted ? pairs : new Promise(resolve => setTimeout(() => resolve(load(params)), 1000)))
122
126
  }
123
127
 
124
128
  module.exports.load = (params = {}) =>
package/loader.js CHANGED
@@ -1,6 +1,7 @@
1
- const get_pairs_addresses = (key, factory, ids) => ids.length == 0
1
+ const get_pairs_addresses = (key, factory, ids, abort_signal) => ids.length == 0
2
2
  ? Promise.resolve([])
3
3
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
4
+ signal: abort_signal,
4
5
  method: 'POST',
5
6
  headers: { 'Content-Type': 'application/json' },
6
7
  body: JSON.stringify(ids.map((id, i) => ({
@@ -30,14 +31,15 @@ const get_pairs_addresses = (key, factory, ids) => ids.length == 0
30
31
  return failed_ids.length == 0
31
32
  ? addresses
32
33
  : new Promise(resolve => setTimeout(() => resolve(
33
- get_pairs_addresses(key, factory, failed_ids).then(retried => [...addresses, ...retried])
34
+ get_pairs_addresses(key, factory, failed_ids, abort_signal).then(retried => [...addresses, ...retried])
34
35
  ), 10000))
35
36
  })
36
- .catch(() => new Promise(resolve => setTimeout(() => resolve(get_pairs_addresses(key, factory, ids)), 10000)))
37
+ .catch(() => abort_signal?.aborted ? [] : new Promise(resolve => setTimeout(() => resolve(get_pairs_addresses(key, factory, ids, abort_signal)), 10000)))
37
38
 
38
- const get_tokens = (key, addresses) => addresses.length == 0
39
+ const get_tokens = (key, addresses, abort_signal) => addresses.length == 0
39
40
  ? Promise.resolve({})
40
41
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
42
+ signal: abort_signal,
41
43
  method: 'POST',
42
44
  headers: { 'Content-Type': 'application/json' },
43
45
  body: JSON.stringify(addresses.flatMap((address, i) => [
@@ -83,20 +85,20 @@ const get_tokens = (key, addresses) => addresses.length == 0
83
85
  return failed_addresses.length == 0
84
86
  ? tokens
85
87
  : new Promise(resolve => setTimeout(() => resolve(
86
- get_tokens(key, failed_addresses).then(retried => ({ ...tokens, ...retried }))
88
+ get_tokens(key, failed_addresses, abort_signal).then(retried => ({ ...tokens, ...retried }))
87
89
  ), 10000))
88
90
  })
89
- .catch(() => new Promise(resolve => setTimeout(() => resolve(get_tokens(key, addresses)), 10000)))
91
+ .catch(() => abort_signal?.aborted ? {} : new Promise(resolve => setTimeout(() => resolve(get_tokens(key, addresses, abort_signal)), 10000)))
90
92
 
91
- const main = ({ids, factory, key, multicall_size}, onpair) => {
93
+ const main = ({ids, factory, key, multicall_size, abort_signal}, onpair) => {
92
94
  const chunks = []
93
95
  for (let i = 0; i < ids.length; i += multicall_size)
94
96
  chunks.push(ids.slice(i, i + multicall_size))
95
97
 
96
98
  return chunks.reduce((p, ids, ic) =>
97
99
  p.then(() =>
98
- get_pairs_addresses(key, factory, ids).then(pairs_addresses =>
99
- get_tokens(key, pairs_addresses).then(tokens =>
100
+ get_pairs_addresses(key, factory, ids, abort_signal).then(pairs_addresses =>
101
+ get_tokens(key, pairs_addresses, abort_signal).then(tokens =>
100
102
  ids.forEach((id, i) =>
101
103
  onpair({
102
104
  id,
@@ -113,12 +115,20 @@ const main = ({ids, factory, key, multicall_size}, onpair) => {
113
115
  }
114
116
 
115
117
 
116
- if (require.main != module)
118
+ if (require.main != module) {
117
119
  module.exports = main
118
- else
120
+ } else {
121
+ const abort_controller = new AbortController()
122
+ const abort_signal = abort_controller.signal
123
+
119
124
  process.on(
120
125
  'message',
121
- message =>
122
- main(message, pair => process.send(pair))
123
- .then(() => process.exit())
126
+ message => {
127
+ if (message == 'abort')
128
+ abort_controller.abort()
129
+ else
130
+ main({...message, abort_signal}, pair => process.send(pair))
131
+ .finally(() => process.exit())
132
+ }
124
133
  )
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniswap-v2-loader",
3
- "version": "5.0.17",
3
+ "version": "5.0.19",
4
4
  "description": "Uniswap v2 protocol loader",
5
5
  "keywords": [
6
6
  "uniswap-v2",
package/test-cache.js DELETED
@@ -1,111 +0,0 @@
1
- const fs = require('fs')
2
- const { describe, before, after, it } = require('node:test')
3
- const assert = require('node:assert/strict')
4
- const {load, subscribe} = require('./index')
5
- const default_cache_filename = require('./default_cache_filename')
6
- const uniswap_v2_factory = '0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f'
7
-
8
- describe('Cache OS filename at win32', () => {
9
- const platform = process.platform
10
- const os = require('os')
11
- const path = require('path')
12
-
13
- before(() => {
14
- process.env.GITHUB_ACTIONS = ''
15
- Object.defineProperty(process, 'platform', {value: 'win32', configurable: true})
16
- })
17
-
18
- it('win32', () => {
19
- const expected = path.join(os.homedir(), 'AppData', 'Local', `uniswap-v2-loader_${uniswap_v2_factory}.csv`)
20
- assert.equal(default_cache_filename(uniswap_v2_factory), expected)
21
- })
22
- it('win32 & APPDATA', () => {
23
- process.env.APPDATA = 'cache'
24
- assert.equal(
25
- default_cache_filename(uniswap_v2_factory),
26
- 'cache/uniswap-v2-loader_0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f.csv'
27
- )
28
- })
29
- it('win32 & LOCALAPPDATA', () => {
30
- process.env.LOCALAPPDATA = 'cache'
31
- assert.equal(
32
- default_cache_filename(uniswap_v2_factory),
33
- 'cache/uniswap-v2-loader_0x5c69bee701ef814a2b6a3edd4b1652cb9cc5aa6f.csv'
34
- )
35
- })
36
-
37
- it('linux .cache', () => {
38
- const exists_sync = fs.existsSync
39
- fs.existsSync = p => p.endsWith('.cache')
40
- Object.defineProperty(process, 'platform', {value: 'linux', configurable: true})
41
- process.env.XDG_CACHE_HOME = ''
42
- const expected = path.join(os.homedir(), '.cache', `uniswap-v2-loader_${uniswap_v2_factory}.csv`)
43
- assert.equal(default_cache_filename(uniswap_v2_factory), expected)
44
- fs.existsSync = exists_sync
45
- })
46
-
47
- it('os.tmpdir()', () => {
48
- const exists_sync = fs.existsSync
49
- fs.existsSync = path => false
50
- Object.defineProperty(process, 'platform', {value: 'linux', configurable: true})
51
- process.env.XDG_CACHE_HOME = ''
52
-
53
- const expected = path.join(os.tmpdir(), `uniswap-v2-loader_${uniswap_v2_factory}.csv`)
54
- assert.equal(default_cache_filename(uniswap_v2_factory), expected)
55
- fs.existsSync = exists_sync
56
- })
57
-
58
- after(() => {
59
- process.env.GITHUB_ACTIONS = 1
60
- Object.defineProperty(process, 'platform', {value: platform})
61
- })
62
- })
63
-
64
- describe('Cache OS filename at darwin', () => {
65
- const platform = process.platform
66
- const os = require('os')
67
- const path = require('path')
68
-
69
- before(() => {
70
- process.env.GITHUB_ACTIONS = ''
71
- Object.defineProperty(process, 'platform', {value: 'darwin', configurable: true})
72
- })
73
-
74
- it('darwin', () => {
75
- const expected = path.join(os.homedir(), 'Library', 'Caches', `uniswap-v2-loader_${uniswap_v2_factory}.csv`)
76
- assert.equal(default_cache_filename(uniswap_v2_factory), expected)
77
- })
78
-
79
- after(() => {
80
- process.env.GITHUB_ACTIONS = 1
81
- Object.defineProperty(process, 'platform', {value: platform})
82
- })
83
- })
84
-
85
- describe('Cache OS filename at linux', () => {
86
- const platform = process.platform
87
- const XDG_CACHE_HOME = process.env.XDG_CACHE_HOME
88
- const os = require('os')
89
- const path = require('path')
90
-
91
- before(() => {
92
- process.env.GITHUB_ACTIONS = ''
93
- Object.defineProperty(process, 'platform', {value: 'linux', configurable: true})
94
- })
95
-
96
- it('linux XDG_CACHE_HOME', () => {
97
- const exists_sync = fs.existsSync
98
- const cache_dir = path.join(os.homedir(), '.cache')
99
- fs.existsSync = p => p === cache_dir
100
- process.env.XDG_CACHE_HOME = cache_dir
101
- const expected = path.join(cache_dir, `uniswap-v2-loader_${uniswap_v2_factory}.csv`)
102
- assert.equal(default_cache_filename(uniswap_v2_factory), expected)
103
- fs.existsSync = exists_sync
104
- })
105
-
106
- after(() => {
107
- process.env.GITHUB_ACTIONS = 1
108
- process.env.XDG_CACHE_HOME = XDG_CACHE_HOME
109
- Object.defineProperty(process, 'platform', {value: platform})
110
- })
111
- })