@paraswap/dex-lib 2.36.1 → 2.36.2-cache-invalidation

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.
Files changed (135) hide show
  1. package/build/abi/pancakeswap-v3/PancakeswapV3Factory.abi.json +300 -0
  2. package/build/abi/uniswap-v3/UniswapV3Factory.abi.json +148 -0
  3. package/build/dex/algebra/algebra-factory.d.ts +25 -0
  4. package/build/dex/algebra/algebra-factory.js +43 -0
  5. package/build/dex/algebra/algebra-factory.js.map +1 -0
  6. package/build/dex/algebra/algebra.d.ts +3 -0
  7. package/build/dex/algebra/algebra.js +27 -5
  8. package/build/dex/algebra/algebra.js.map +1 -1
  9. package/build/dex/algebra/config.js +0 -1
  10. package/build/dex/algebra/config.js.map +1 -1
  11. package/build/dex/algebra/types.d.ts +1 -1
  12. package/build/dex/curve-v1/config.js +40 -38
  13. package/build/dex/curve-v1/config.js.map +1 -1
  14. package/build/dex/{woo-fi → hello}/config.d.ts +1 -1
  15. package/build/dex/{test-dex → hello}/config.js +3 -3
  16. package/build/dex/hello/config.js.map +1 -0
  17. package/build/dex/{test-dex/test-dex-pool.d.ts → hello/hello-pool.d.ts} +4 -4
  18. package/build/dex/{test-dex/test-dex-pool.js → hello/hello-pool.js} +9 -8
  19. package/build/dex/hello/hello-pool.js.map +1 -0
  20. package/build/dex/{test-dex/test-dex.d.ts → hello/hello.d.ts} +8 -8
  21. package/build/dex/{test-dex/test-dex.js → hello/hello.js} +7 -7
  22. package/build/dex/hello/hello.js.map +1 -0
  23. package/build/dex/{test-dex → hello}/types.d.ts +1 -1
  24. package/build/dex/{woo-fi → hello}/types.js.map +1 -1
  25. package/build/dex/{test-dex → my-test-dex}/config.d.ts +1 -1
  26. package/build/dex/my-test-dex/config.js +15 -0
  27. package/build/dex/my-test-dex/config.js.map +1 -0
  28. package/build/dex/my-test-dex/my-test-dex-pool.d.ts +39 -0
  29. package/build/dex/my-test-dex/my-test-dex-pool.js +64 -0
  30. package/build/dex/my-test-dex/my-test-dex-pool.js.map +1 -0
  31. package/build/dex/my-test-dex/my-test-dex.d.ts +37 -0
  32. package/build/dex/my-test-dex/my-test-dex.js +126 -0
  33. package/build/dex/my-test-dex/my-test-dex.js.map +1 -0
  34. package/build/dex/my-test-dex/types.d.ts +6 -0
  35. package/build/dex/{test-dex → my-test-dex}/types.js.map +1 -1
  36. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.d.ts +26 -0
  37. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.js +44 -0
  38. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.js.map +1 -0
  39. package/build/dex/pancakeswap-v3/pancakeswap-v3.d.ts +3 -0
  40. package/build/dex/pancakeswap-v3/pancakeswap-v3.js +26 -2
  41. package/build/dex/pancakeswap-v3/pancakeswap-v3.js.map +1 -1
  42. package/build/dex/uniswap-v3/types.d.ts +1 -0
  43. package/build/dex/uniswap-v3/types.js.map +1 -1
  44. package/build/dex/uniswap-v3/uniswap-v3-factory.d.ts +26 -0
  45. package/build/dex/uniswap-v3/uniswap-v3-factory.js +44 -0
  46. package/build/dex/uniswap-v3/uniswap-v3-factory.js.map +1 -0
  47. package/build/dex/uniswap-v3/uniswap-v3.d.ts +3 -0
  48. package/build/dex/uniswap-v3/uniswap-v3.js +26 -2
  49. package/build/dex/uniswap-v3/uniswap-v3.js.map +1 -1
  50. package/build/dex-helper/dummy-dex-helper.js +3 -0
  51. package/build/dex-helper/dummy-dex-helper.js.map +1 -1
  52. package/build/dex-helper/icache.d.ts +1 -0
  53. package/package.json +1 -1
  54. package/src/abi/pancakeswap-v3/PancakeswapV3Factory.abi.json +300 -0
  55. package/src/dex/algebra/algebra-factory.ts +70 -0
  56. package/src/dex/algebra/algebra.ts +47 -6
  57. package/src/dex/algebra/config.ts +0 -1
  58. package/src/dex/algebra/types.ts +2 -1
  59. package/src/dex/curve-v1/config.ts +40 -38
  60. package/src/dex/pancakeswap-v3/pancakeswap-v3-factory.ts +73 -0
  61. package/src/dex/pancakeswap-v3/pancakeswap-v3.ts +50 -2
  62. package/src/dex/uniswap-v3/types.ts +2 -0
  63. package/src/dex/uniswap-v3/uniswap-v3-factory.ts +73 -0
  64. package/src/dex/uniswap-v3/uniswap-v3.ts +47 -2
  65. package/src/dex-helper/dummy-dex-helper.ts +4 -0
  66. package/src/dex-helper/icache.ts +2 -0
  67. package/build/abi/quickPerps/fast-price-events.json +0 -70
  68. package/build/abi/quickPerps/fast-price-feed.json +0 -748
  69. package/build/abi/quickPerps/reader.json +0 -313
  70. package/build/abi/quickPerps/vault-price-feed.json +0 -477
  71. package/build/abi/quickPerps/vault.json +0 -1953
  72. package/build/abi/uniswap-v3/UniswapV3Quoter.abi.json +0 -193
  73. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3QuoterV2.abi.json +0 -285
  74. package/build/abi/uniswap-v3/pancakeswap-v3/PancakeswapV3Router.abi.json +0 -583
  75. package/build/abi/woo-fi/WooFeeManager.abi.json +0 -318
  76. package/build/abi/woo-fi/WooPP.abi.json +0 -548
  77. package/build/abi/woo-fi/Wooracle.abi.json +0 -260
  78. package/build/dex/aave-v3/tokens/arbitrum.json +0 -50
  79. package/build/dex/aave-v3/tokens/avalanche.json +0 -74
  80. package/build/dex/aave-v3/tokens/fantom.json +0 -62
  81. package/build/dex/aave-v3/tokens/optimism.json +0 -50
  82. package/build/dex/aave-v3/tokens/polygon.json +0 -116
  83. package/build/dex/balancer-v2/LinearMath.d.ts +0 -19
  84. package/build/dex/balancer-v2/LinearMath.js +0 -179
  85. package/build/dex/balancer-v2/LinearMath.js.map +0 -1
  86. package/build/dex/balancer-v2/LinearPool.d.ts +0 -47
  87. package/build/dex/balancer-v2/LinearPool.js +0 -324
  88. package/build/dex/balancer-v2/LinearPool.js.map +0 -1
  89. package/build/dex/balancer-v2/PhantomStablePool.d.ts +0 -47
  90. package/build/dex/balancer-v2/PhantomStablePool.js +0 -294
  91. package/build/dex/balancer-v2/PhantomStablePool.js.map +0 -1
  92. package/build/dex/balancer-v2/StableMath.d.ts +0 -9
  93. package/build/dex/balancer-v2/StableMath.js +0 -272
  94. package/build/dex/balancer-v2/StableMath.js.map +0 -1
  95. package/build/dex/balancer-v2/balancer-v2-pool.d.ts +0 -75
  96. package/build/dex/balancer-v2/balancer-v2-pool.js +0 -417
  97. package/build/dex/balancer-v2/balancer-v2-pool.js.map +0 -1
  98. package/build/dex/quickswap/camelot-v3.d.ts +0 -6
  99. package/build/dex/quickswap/camelot-v3.js +0 -19
  100. package/build/dex/quickswap/camelot-v3.js.map +0 -1
  101. package/build/dex/quickswap/zyberswap-v3.d.ts +0 -6
  102. package/build/dex/quickswap/zyberswap-v3.js +0 -19
  103. package/build/dex/quickswap/zyberswap-v3.js.map +0 -1
  104. package/build/dex/quickswap-v3.d.ts +0 -21
  105. package/build/dex/quickswap-v3.js +0 -40
  106. package/build/dex/quickswap-v3.js.map +0 -1
  107. package/build/dex/test-dex/config.js.map +0 -1
  108. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  109. package/build/dex/test-dex/test-dex.js.map +0 -1
  110. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.d.ts +0 -12
  111. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js +0 -23
  112. package/build/dex/uniswap-v3/forks/pancakeswap-v3/pancakeswap-v3.js.map +0 -1
  113. package/build/dex/woo-fi/config.js +0 -141
  114. package/build/dex/woo-fi/config.js.map +0 -1
  115. package/build/dex/woo-fi/constants.d.ts +0 -5
  116. package/build/dex/woo-fi/constants.js +0 -20
  117. package/build/dex/woo-fi/constants.js.map +0 -1
  118. package/build/dex/woo-fi/types.d.ts +0 -48
  119. package/build/dex/woo-fi/woo-fi-decimal-math.d.ts +0 -14
  120. package/build/dex/woo-fi/woo-fi-decimal-math.js +0 -42
  121. package/build/dex/woo-fi/woo-fi-decimal-math.js.map +0 -1
  122. package/build/dex/woo-fi/woo-fi-math.d.ts +0 -31
  123. package/build/dex/woo-fi/woo-fi-math.js +0 -300
  124. package/build/dex/woo-fi/woo-fi-math.js.map +0 -1
  125. package/build/dex/woo-fi/woo-fi.d.ts +0 -65
  126. package/build/dex/woo-fi/woo-fi.js +0 -480
  127. package/build/dex/woo-fi/woo-fi.js.map +0 -1
  128. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  129. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  130. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  131. package/build/workers.d.ts +0 -0
  132. package/build/workers.js +0 -2
  133. package/build/workers.js.map +0 -1
  134. /package/build/dex/{test-dex → hello}/types.js +0 -0
  135. /package/build/dex/{woo-fi → my-test-dex}/types.js +0 -0
@@ -38,14 +38,15 @@ import {
38
38
  import { AlgebraMath } from './lib/AlgebraMath';
39
39
  import { AlgebraEventPoolV1_1 } from './algebra-pool-v1_1';
40
40
  import { AlgebraEventPoolV1_9 } from './algebra-pool-v1_9';
41
+ import { AlgebraFactory, OnPoolCreatedCallback } from './algebra-factory';
41
42
 
42
43
  type PoolPairsInfo = {
43
44
  token0: Address;
44
45
  token1: Address;
45
46
  };
46
47
 
47
- const ALGEBRA_CLEAN_NOT_EXISTING_POOL_TTL_MS = 3 * 60 * 60 * 1000; // 3 hours
48
- const ALGEBRA_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 30 * 60 * 1000; // Once in 30 minutes
48
+ const ALGEBRA_CLEAN_NOT_EXISTING_POOL_TTL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
49
+ const ALGEBRA_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 24 * 60 * 60 * 1000; // Once in a day
49
50
  const ALGEBRA_EFFICIENCY_FACTOR = 3;
50
51
  const ALGEBRA_TICK_GAS_COST = 24_000; // Ceiled
51
52
  const ALGEBRA_TICK_BASE_OVERHEAD = 75_000;
@@ -59,6 +60,7 @@ const MAX_STALE_STATE_BLOCK_AGE = {
59
60
  type IAlgebraEventPool = AlgebraEventPoolV1_1 | AlgebraEventPoolV1_9;
60
61
 
61
62
  export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
63
+ private readonly factory: AlgebraFactory;
62
64
  readonly isFeeOnTransferSupported: boolean = false;
63
65
  protected eventPools: Record<string, IAlgebraEventPool | null> = {};
64
66
 
@@ -114,6 +116,14 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
114
116
 
115
117
  this.AlgebraPoolImplem =
116
118
  config.version === 'v1.1' ? AlgebraEventPoolV1_1 : AlgebraEventPoolV1_9;
119
+
120
+ this.factory = new AlgebraFactory(
121
+ dexHelper,
122
+ dexKey,
123
+ this.config.factory,
124
+ this.logger,
125
+ this.onPoolCreatedDeleteFromNonExistingSet.bind(this),
126
+ );
117
127
  }
118
128
 
119
129
  getAdapters(side: SwapSide): { name: string; index: number }[] | null {
@@ -126,13 +136,13 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
126
136
  }
127
137
 
128
138
  async initializePricing(blockNumber: number) {
129
- const cleanNonExistingPoolTTLMs =
130
- this.config.cleanExistingPoolTTLMs ||
131
- ALGEBRA_CLEAN_NOT_EXISTING_POOL_TTL_MS;
139
+ // Init listening to new pools creation
140
+ await this.factory.initialize(blockNumber);
132
141
 
133
142
  if (!this.dexHelper.config.isSlave) {
134
143
  const cleanExpiredNotExistingPoolsKeys = async () => {
135
- const maxTimestamp = Date.now() - cleanNonExistingPoolTTLMs;
144
+ const maxTimestamp =
145
+ Date.now() - ALGEBRA_CLEAN_NOT_EXISTING_POOL_TTL_MS;
136
146
  await this.dexHelper.cache.zremrangebyscore(
137
147
  this.notExistingPoolSetKey,
138
148
  0,
@@ -147,6 +157,37 @@ export class Algebra extends SimpleExchange implements IDex<AlgebraData> {
147
157
  }
148
158
  }
149
159
 
160
+ /*
161
+ * When a non existing pool is queried, it's blacklisted for an arbitrary long period in order to prevent issuing too many rpc calls
162
+ * Once the pool is created, it gets immediately flagged
163
+ */
164
+ onPoolCreatedDeleteFromNonExistingSet: OnPoolCreatedCallback = async ({
165
+ token0,
166
+ token1,
167
+ }) => {
168
+ const logPrefix = '[Algebra.onPoolCreatedDeleteFromNonExistingSet]';
169
+ const [_token0, _token1] = this._sortTokens(token0, token1);
170
+ const poolKey = `${token0}_${token1}`.toLowerCase();
171
+
172
+ // consider doing it only from master pool for less calls to distant cache
173
+
174
+ // delete entry locally to let local instance discover the pool
175
+ delete this.eventPools[this.getPoolIdentifier(_token0, _token1)];
176
+
177
+ try {
178
+ this.logger.info(
179
+ `${logPrefix} delete pool from not existing set: ${poolKey}`,
180
+ );
181
+ // delete pool record from set
182
+ await this.dexHelper.cache.zrem(this.notExistingPoolSetKey, [poolKey]);
183
+ } catch (error) {
184
+ this.logger.error(
185
+ `${logPrefix} failed to delete pool from set: ${poolKey}`,
186
+ error,
187
+ );
188
+ }
189
+ };
190
+
150
191
  async getPool(
151
192
  srcAddress: Address,
152
193
  destAddress: Address,
@@ -83,7 +83,6 @@ export const AlgebraConfig: DexConfigMap<DexParams> = {
83
83
  uniswapMulticall: '0x1F98415757620B543A52E61c46B32eB19261F984',
84
84
  deployer: '0x6dd3fb9653b10e806650f107c3b5a0a6ff974f65',
85
85
  version: 'v1.9',
86
- cleanExistingPoolTTLMs: 20 * 60 * 1000,
87
86
  },
88
87
  },
89
88
  };
@@ -51,6 +51,8 @@ export type PoolState_v1_9 = {
51
51
  areTicksCompressed: boolean;
52
52
  };
53
53
 
54
+ export type FactoryState = Record<string, never>;
55
+
54
56
  export type AlgebraData = {
55
57
  path: {
56
58
  tokenIn: Address;
@@ -73,7 +75,6 @@ export type DexParams = {
73
75
  version: 'v1.1' | 'v1.9';
74
76
  forceRPC?: boolean;
75
77
  forceManualStateGenerate?: boolean;
76
- cleanExistingPoolTTLMs?: number;
77
78
  };
78
79
 
79
80
  export type IAlgebraPoolState = PoolStateV1_1 | PoolState_v1_9;
@@ -939,44 +939,46 @@ export const CurveV1Config: DexConfigMap<DexParams> = {
939
939
  isMetapool: false,
940
940
  baseToken: '0x321162Cd933E2Be498Cd2267a90534A804051b11',
941
941
  },
942
- main_gDAI_gUSDC_gUSDT: {
943
- underlying: [
944
- '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E', // DAI
945
- '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', // USDC
946
- '0x049d68029688eAbF473097a2fC38ef61633A3C7A', // fUSDT
947
- ],
948
- coins: [
949
- '0x07E6332dD090D287d3489245038daF987955DCFB', // gDAI
950
- '0xe578C856933D8e1082740bf7661e379Aa2A30b26', // gUSDC
951
- '0x940F41F0ec9ba1A34CF001cc03347ac092F5F6B5', // gUSDT
952
- ],
953
- address: '0x0fa949783947Bf6c1b171DB13AEACBB488845B3f',
954
- name: 'main_gDAI_gUSDC_gUSDT',
955
- type: 2,
956
- version: 3,
957
- isLending: true,
958
- isMetapool: false,
959
- baseToken: '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E',
960
- },
961
- main_iDAI_iUSDC_iFUSDT: {
962
- underlying: [
963
- '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E', // DAI
964
- '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', // USDC
965
- '0x049d68029688eAbF473097a2fC38ef61633A3C7A', // fUSDT
966
- ],
967
- coins: [
968
- '0x04c762a5dF2Fa02FE868F25359E0C259fB811CfE', // iDAI
969
- '0x328A7b4d538A2b3942653a9983fdA3C12c571141', // iUSDC
970
- '0x70faC71debfD67394D1278D98A29dea79DC6E57A', // iFUSDT
971
- ],
972
- address: '0x4FC8D635c3cB1d0aa123859e2B2587d0FF2707b1',
973
- name: 'main_iDAI_iUSDC_iFUSDT',
974
- type: 2,
975
- version: 3,
976
- isLending: true,
977
- isMetapool: false,
978
- baseToken: '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E',
979
- },
942
+ // Disabled pool
943
+ // main_gDAI_gUSDC_gUSDT: {
944
+ // underlying: [
945
+ // '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E', // DAI
946
+ // '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', // USDC
947
+ // '0x049d68029688eAbF473097a2fC38ef61633A3C7A', // fUSDT
948
+ // ],
949
+ // coins: [
950
+ // '0x07E6332dD090D287d3489245038daF987955DCFB', // gDAI
951
+ // '0xe578C856933D8e1082740bf7661e379Aa2A30b26', // gUSDC
952
+ // '0x940F41F0ec9ba1A34CF001cc03347ac092F5F6B5', // gUSDT
953
+ // ],
954
+ // address: '0x0fa949783947Bf6c1b171DB13AEACBB488845B3f',
955
+ // name: 'main_gDAI_gUSDC_gUSDT',
956
+ // type: 2,
957
+ // version: 3,
958
+ // isLending: true,
959
+ // isMetapool: false,
960
+ // baseToken: '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E',
961
+ // },
962
+ // Disabled pool
963
+ // main_iDAI_iUSDC_iFUSDT: {
964
+ // underlying: [
965
+ // '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E', // DAI
966
+ // '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', // USDC
967
+ // '0x049d68029688eAbF473097a2fC38ef61633A3C7A', // fUSDT
968
+ // ],
969
+ // coins: [
970
+ // '0x04c762a5dF2Fa02FE868F25359E0C259fB811CfE', // iDAI
971
+ // '0x328A7b4d538A2b3942653a9983fdA3C12c571141', // iUSDC
972
+ // '0x70faC71debfD67394D1278D98A29dea79DC6E57A', // iFUSDT
973
+ // ],
974
+ // address: '0x4FC8D635c3cB1d0aa123859e2B2587d0FF2707b1',
975
+ // name: 'main_iDAI_iUSDC_iFUSDT',
976
+ // type: 2,
977
+ // version: 3,
978
+ // isLending: true,
979
+ // isMetapool: false,
980
+ // baseToken: '0x8D11eC38a3EB5E956B052f67Da8Bdc9bef8Abf3E',
981
+ // },
980
982
  },
981
983
  },
982
984
  [Network.AVALANCHE]: {
@@ -0,0 +1,73 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { DeepReadonly } from 'ts-essentials';
3
+ import FactoryABI from '../../abi/pancakeswap-v3/PancakeswapV3Factory.abi.json';
4
+ import { IDexHelper } from '../../dex-helper/idex-helper';
5
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
6
+ import { Address, Log, Logger } from '../../types';
7
+ import { LogDescription } from 'ethers/lib/utils';
8
+ import { FactoryState } from '../uniswap-v3/types';
9
+
10
+ export type OnPoolCreatedCallback = ({
11
+ token0,
12
+ token1,
13
+ fee,
14
+ }: {
15
+ token0: string;
16
+ token1: string;
17
+ fee: bigint;
18
+ }) => Promise<void>;
19
+
20
+ /*
21
+ * "Stateless" event subscriber in order to capture "PoolCreated" event on new pools created.
22
+ * State is present, but it's a placeholder to actually make the events reach handlers (if there's no previous state - `processBlockLogs` is not called)
23
+ */
24
+ export class PancakeswapV3Factory extends StatefulEventSubscriber<FactoryState> {
25
+ handlers: {
26
+ [event: string]: (event: any) => Promise<void>;
27
+ } = {};
28
+
29
+ logDecoder: (log: Log) => any;
30
+
31
+ public readonly factoryIface = new Interface(FactoryABI);
32
+
33
+ constructor(
34
+ readonly dexHelper: IDexHelper,
35
+ parentName: string,
36
+ protected readonly factoryAddress: Address,
37
+ logger: Logger,
38
+ protected readonly onPoolCreated: OnPoolCreatedCallback,
39
+ mapKey: string = '',
40
+ ) {
41
+ super(parentName, `${parentName} Factory`, dexHelper, logger, true, mapKey);
42
+
43
+ this.addressesSubscribed = [factoryAddress];
44
+
45
+ this.logDecoder = (log: Log) => this.factoryIface.parseLog(log);
46
+
47
+ this.handlers['PoolCreated'] = this.handleNewPool.bind(this);
48
+ }
49
+
50
+ generateState(): FactoryState {
51
+ return {};
52
+ }
53
+
54
+ protected async processLog(
55
+ _: DeepReadonly<FactoryState>,
56
+ log: Readonly<Log>,
57
+ ): Promise<FactoryState> {
58
+ const event = this.logDecoder(log);
59
+ if (event.name in this.handlers) {
60
+ await this.handlers[event.name](event);
61
+ }
62
+
63
+ return {};
64
+ }
65
+
66
+ async handleNewPool(event: LogDescription) {
67
+ const token0 = event.args.token0;
68
+ const token1 = event.args.token1;
69
+ const fee = event.args.fee;
70
+
71
+ await this.onPoolCreated({ token0, token1, fee });
72
+ }
73
+ }
@@ -56,6 +56,10 @@ import {
56
56
  DEFAULT_ID_ERC20,
57
57
  DEFAULT_ID_ERC20_AS_STRING,
58
58
  } from '../../lib/tokens/types';
59
+ import {
60
+ OnPoolCreatedCallback,
61
+ PancakeswapV3Factory,
62
+ } from './pancakeswap-v3-factory';
59
63
 
60
64
  type PoolPairsInfo = {
61
65
  token0: Address;
@@ -63,14 +67,15 @@ type PoolPairsInfo = {
63
67
  fee: string;
64
68
  };
65
69
 
66
- const PANCAKESWAPV3_CLEAN_NOT_EXISTING_POOL_TTL_MS = 60 * 60 * 24 * 1000; // 24 hours
67
- const PANCAKESWAPV3_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 30 * 60 * 1000; // Once in 30 minutes
70
+ const PANCAKESWAPV3_CLEAN_NOT_EXISTING_POOL_TTL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
71
+ const PANCAKESWAPV3_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 24 * 60 * 60 * 1000; // Once in a day
68
72
  const PANCAKESWAPV3_QUOTE_GASLIMIT = 200_000;
69
73
 
70
74
  export class PancakeswapV3
71
75
  extends SimpleExchange
72
76
  implements IDex<UniswapV3Data>
73
77
  {
78
+ private readonly factory: PancakeswapV3Factory;
74
79
  readonly isFeeOnTransferSupported: boolean = false;
75
80
  readonly eventPools: Record<string, PancakeSwapV3EventPool | null> = {};
76
81
 
@@ -117,6 +122,14 @@ export class PancakeswapV3
117
122
 
118
123
  this.notExistingPoolSetKey =
119
124
  `${CACHE_PREFIX}_${network}_${dexKey}_not_existings_pool_set`.toLowerCase();
125
+
126
+ this.factory = new PancakeswapV3Factory(
127
+ dexHelper,
128
+ dexKey,
129
+ this.config.factory,
130
+ this.logger,
131
+ this.onPoolCreatedDeleteFromNonExistingSet.bind(this),
132
+ );
120
133
  }
121
134
 
122
135
  get supportedFees() {
@@ -133,6 +146,9 @@ export class PancakeswapV3
133
146
  }
134
147
 
135
148
  async initializePricing(blockNumber: number) {
149
+ // Init listening to new pools creation
150
+ await this.factory.initialize(blockNumber);
151
+
136
152
  if (!this.dexHelper.config.isSlave) {
137
153
  const cleanExpiredNotExistingPoolsKeys = async () => {
138
154
  const maxTimestamp =
@@ -151,6 +167,38 @@ export class PancakeswapV3
151
167
  }
152
168
  }
153
169
 
170
+ /*
171
+ * When a non existing pool is queried, it's blacklisted for an arbitrary long period in order to prevent issuing too many rpc calls
172
+ * Once the pool is created, it gets immediately flagged
173
+ */
174
+ onPoolCreatedDeleteFromNonExistingSet: OnPoolCreatedCallback = async ({
175
+ token0,
176
+ token1,
177
+ fee,
178
+ }) => {
179
+ const logPrefix = '[PancakeV3.onPoolCreatedDeleteFromNonExistingSet]';
180
+ const [_token0, _token1] = this._sortTokens(token0, token1);
181
+ const poolKey = `${token0}_${token1}_${fee}`.toLowerCase();
182
+
183
+ // consider doing it only from master pool for less calls to distant cache
184
+
185
+ // delete entry locally to let local instance discover the pool
186
+ delete this.eventPools[this.getPoolIdentifier(_token0, _token1, fee)];
187
+
188
+ try {
189
+ this.logger.info(
190
+ `${logPrefix} delete pool from not existing set: ${poolKey}`,
191
+ );
192
+ // delete pool record from set
193
+ await this.dexHelper.cache.zrem(this.notExistingPoolSetKey, [poolKey]);
194
+ } catch (error) {
195
+ this.logger.error(
196
+ `${logPrefix} failed to delete pool from set :${poolKey}`,
197
+ error,
198
+ );
199
+ }
200
+ };
201
+
154
202
  async getPool(
155
203
  srcAddress: Address,
156
204
  destAddress: Address,
@@ -53,6 +53,8 @@ export type PoolState = {
53
53
  balance1: bigint;
54
54
  };
55
55
 
56
+ export type FactoryState = Record<string, never>;
57
+
56
58
  export type UniswapV3Data = {
57
59
  path: {
58
60
  tokenIn: Address;
@@ -0,0 +1,73 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { DeepReadonly } from 'ts-essentials';
3
+ import FactoryABI from '../../abi/uniswap-v3/UniswapV3Factory.abi.json';
4
+ import { IDexHelper } from '../../dex-helper/idex-helper';
5
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
6
+ import { Address, Log, Logger } from '../../types';
7
+ import { LogDescription } from 'ethers/lib/utils';
8
+ import { FactoryState } from './types';
9
+
10
+ export type OnPoolCreatedCallback = ({
11
+ token0,
12
+ token1,
13
+ fee,
14
+ }: {
15
+ token0: string;
16
+ token1: string;
17
+ fee: bigint;
18
+ }) => Promise<void>;
19
+
20
+ /*
21
+ * "Stateless" event subscriber in order to capture "PoolCreated" event on new pools created.
22
+ * State is present, but it's a placeholder to actually make the events reach handlers (if there's no previous state - `processBlockLogs` is not called)
23
+ */
24
+ export class UniswapV3Factory extends StatefulEventSubscriber<FactoryState> {
25
+ handlers: {
26
+ [event: string]: (event: any) => Promise<void>;
27
+ } = {};
28
+
29
+ logDecoder: (log: Log) => any;
30
+
31
+ public readonly factoryIface = new Interface(FactoryABI);
32
+
33
+ constructor(
34
+ readonly dexHelper: IDexHelper,
35
+ parentName: string,
36
+ protected readonly factoryAddress: Address,
37
+ logger: Logger,
38
+ protected readonly onPoolCreated: OnPoolCreatedCallback,
39
+ mapKey: string = '',
40
+ ) {
41
+ super(parentName, `${parentName} Factory`, dexHelper, logger, true, mapKey);
42
+
43
+ this.addressesSubscribed = [factoryAddress];
44
+
45
+ this.logDecoder = (log: Log) => this.factoryIface.parseLog(log);
46
+
47
+ this.handlers['PoolCreated'] = this.handleNewPool.bind(this);
48
+ }
49
+
50
+ generateState(): FactoryState {
51
+ return {};
52
+ }
53
+
54
+ protected async processLog(
55
+ _: DeepReadonly<FactoryState>,
56
+ log: Readonly<Log>,
57
+ ): Promise<FactoryState> {
58
+ const event = this.logDecoder(log);
59
+ if (event.name in this.handlers) {
60
+ await this.handlers[event.name](event);
61
+ }
62
+
63
+ return {};
64
+ }
65
+
66
+ async handleNewPool(event: LogDescription) {
67
+ const token0 = event.args.token0;
68
+ const token1 = event.args.token1;
69
+ const fee = event.args.fee;
70
+
71
+ await this.onPoolCreated({ token0, token1, fee });
72
+ }
73
+ }
@@ -64,6 +64,7 @@ import {
64
64
  DEFAULT_ID_ERC20_AS_STRING,
65
65
  } from '../../lib/tokens/types';
66
66
  import { OptimalSwapExchange } from '@paraswap/core';
67
+ import { OnPoolCreatedCallback, UniswapV3Factory } from './uniswap-v3-factory';
67
68
 
68
69
  type PoolPairsInfo = {
69
70
  token0: Address;
@@ -71,14 +72,15 @@ type PoolPairsInfo = {
71
72
  fee: string;
72
73
  };
73
74
 
74
- const UNISWAPV3_CLEAN_NOT_EXISTING_POOL_TTL_MS = 60 * 60 * 24 * 1000; // 24 hours
75
- const UNISWAPV3_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 30 * 60 * 1000; // Once in 30 minutes
75
+ const UNISWAPV3_CLEAN_NOT_EXISTING_POOL_TTL_MS = 3 * 24 * 60 * 60 * 1000; // 3 days
76
+ const UNISWAPV3_CLEAN_NOT_EXISTING_POOL_INTERVAL_MS = 24 * 60 * 60 * 1000; // Once in a day
76
77
  const UNISWAPV3_QUOTE_GASLIMIT = 200_000;
77
78
 
78
79
  export class UniswapV3
79
80
  extends SimpleExchange
80
81
  implements IDex<UniswapV3Data, UniswapV3Param>
81
82
  {
83
+ private readonly factory: UniswapV3Factory;
82
84
  readonly isFeeOnTransferSupported: boolean = false;
83
85
  readonly eventPools: Record<string, UniswapV3EventPool | null> = {};
84
86
 
@@ -138,6 +140,14 @@ export class UniswapV3
138
140
 
139
141
  this.notExistingPoolSetKey =
140
142
  `${CACHE_PREFIX}_${network}_${dexKey}_not_existings_pool_set`.toLowerCase();
143
+
144
+ this.factory = new UniswapV3Factory(
145
+ dexHelper,
146
+ dexKey,
147
+ this.config.factory,
148
+ this.logger,
149
+ this.onPoolCreatedDeleteFromNonExistingSet.bind(this),
150
+ );
141
151
  }
142
152
 
143
153
  get supportedFees() {
@@ -154,6 +164,9 @@ export class UniswapV3
154
164
  }
155
165
 
156
166
  async initializePricing(blockNumber: number) {
167
+ // Init listening to new pools creation
168
+ await this.factory.initialize(blockNumber);
169
+
157
170
  // This is only for testing, because cold pool fetching is goes out of
158
171
  // FETCH_POOL_INDENTIFIER_TIMEOUT range
159
172
  await Promise.all(
@@ -184,6 +197,38 @@ export class UniswapV3
184
197
  }
185
198
  }
186
199
 
200
+ /*
201
+ * When a non existing pool is queried, it's blacklisted for an arbitrary long period in order to prevent issuing too many rpc calls
202
+ * Once the pool is created, it gets immediately flagged
203
+ */
204
+ onPoolCreatedDeleteFromNonExistingSet: OnPoolCreatedCallback = async ({
205
+ token0,
206
+ token1,
207
+ fee,
208
+ }) => {
209
+ const logPrefix = '[UniswapV3.onPoolCreatedDeleteFromNonExistingSet]';
210
+ const [_token0, _token1] = this._sortTokens(token0, token1);
211
+ const poolKey = `${token0}_${token1}_${fee}`.toLowerCase();
212
+
213
+ // consider doing it only from master pool for less calls to distant cache
214
+
215
+ // delete entry locally to let local instance discover the pool
216
+ delete this.eventPools[this.getPoolIdentifier(_token0, _token1, fee)];
217
+
218
+ try {
219
+ this.logger.info(
220
+ `${logPrefix} delete pool from not existing set: ${poolKey}`,
221
+ );
222
+ // delete pool record from set
223
+ await this.dexHelper.cache.zrem(this.notExistingPoolSetKey, [poolKey]);
224
+ } catch (error) {
225
+ this.logger.error(
226
+ `${logPrefix} failed to delete pool from set: ${poolKey}`,
227
+ error,
228
+ );
229
+ }
230
+ };
231
+
187
232
  async getPool(
188
233
  srcAddress: Address,
189
234
  destAddress: Address,
@@ -115,6 +115,10 @@ class DummyCache implements ICache {
115
115
  return 0;
116
116
  }
117
117
 
118
+ async zrem(key: string, membersKeys: string[]): Promise<number> {
119
+ return 0;
120
+ }
121
+
118
122
  async zadd(key: string, bulkItemsToAdd: (number | string)[], option?: 'NX') {
119
123
  return 0;
120
124
  }
@@ -46,6 +46,8 @@ export interface ICache {
46
46
 
47
47
  zremrangebyscore(key: string, min: number, max: number): Promise<number>;
48
48
 
49
+ zrem(key: string, membersKeys: string[]): Promise<number>;
50
+
49
51
  zscore(setKey: string, key: string): Promise<string | null>;
50
52
 
51
53
  sismember(setKey: string, key: string): Promise<boolean>;
@@ -1,70 +0,0 @@
1
- [
2
- {
3
- "anonymous": false,
4
- "inputs": [
5
- {
6
- "indexed": false,
7
- "internalType": "address",
8
- "name": "token",
9
- "type": "address"
10
- },
11
- {
12
- "indexed": false,
13
- "internalType": "uint256",
14
- "name": "price",
15
- "type": "uint256"
16
- },
17
- {
18
- "indexed": false,
19
- "internalType": "address",
20
- "name": "priceFeed",
21
- "type": "address"
22
- }
23
- ],
24
- "name": "PriceUpdate",
25
- "type": "event"
26
- },
27
- {
28
- "inputs": [
29
- { "internalType": "address", "name": "_token", "type": "address" },
30
- { "internalType": "uint256", "name": "_price", "type": "uint256" }
31
- ],
32
- "name": "emitPriceEvent",
33
- "outputs": [],
34
- "stateMutability": "nonpayable",
35
- "type": "function"
36
- },
37
- {
38
- "inputs": [],
39
- "name": "gov",
40
- "outputs": [{ "internalType": "address", "name": "", "type": "address" }],
41
- "stateMutability": "view",
42
- "type": "function"
43
- },
44
- {
45
- "inputs": [{ "internalType": "address", "name": "", "type": "address" }],
46
- "name": "isPriceFeed",
47
- "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
48
- "stateMutability": "view",
49
- "type": "function"
50
- },
51
- {
52
- "inputs": [
53
- { "internalType": "address", "name": "_gov", "type": "address" }
54
- ],
55
- "name": "setGov",
56
- "outputs": [],
57
- "stateMutability": "nonpayable",
58
- "type": "function"
59
- },
60
- {
61
- "inputs": [
62
- { "internalType": "address", "name": "_priceFeed", "type": "address" },
63
- { "internalType": "bool", "name": "_isPriceFeed", "type": "bool" }
64
- ],
65
- "name": "setIsPriceFeed",
66
- "outputs": [],
67
- "stateMutability": "nonpayable",
68
- "type": "function"
69
- }
70
- ]