@paraswap/dex-lib 2.37.2 → 2.37.4-current-fee-ramses-v2

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 (201) hide show
  1. package/.idea/aws.xml +17 -0
  2. package/.idea/codeStyles/Project.xml +19 -0
  3. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  4. package/.idea/misc.xml +6 -0
  5. package/.idea/modules.xml +8 -0
  6. package/.idea/paraswap-dex-lib.iml +9 -0
  7. package/.idea/vcs.xml +6 -0
  8. package/build/abi/algebra/AlgebraPool.abi.json +727 -0
  9. package/build/abi/curve-v1/StableSwapFRXETH.json +889 -0
  10. package/build/abi/curve-v1/StableSwapWBETH.json +1223 -0
  11. package/build/abi/dexalot/DexalotMainnetRFQ.json +887 -0
  12. package/build/abi/pancakeswap-v3/PancakeswapV3Factory.abi.json +300 -0
  13. package/build/abi/ramses-v2/RamsesV2Pool.abi.json +1580 -0
  14. package/build/abi/sushiswap-v3/QuoterV2.json +267 -0
  15. package/build/abi/sushiswap-v3/RouterProcessor3.json +289 -0
  16. package/build/abi/uniswap-v3/UniswapV3Factory.abi.json +148 -0
  17. package/build/abi/wBETH.json +1527 -0
  18. package/build/dex/algebra/algebra-factory.d.ts +25 -0
  19. package/build/dex/algebra/algebra-factory.js +43 -0
  20. package/build/dex/algebra/algebra-factory.js.map +1 -0
  21. package/build/dex/algebra/algebra-pool.d.ts +46 -0
  22. package/build/dex/algebra/algebra-pool.js +336 -0
  23. package/build/dex/algebra/algebra-pool.js.map +1 -0
  24. package/build/dex/algebra/algebra.d.ts +3 -0
  25. package/build/dex/algebra/algebra.js +27 -5
  26. package/build/dex/algebra/algebra.js.map +1 -1
  27. package/build/dex/algebra/config.js +0 -1
  28. package/build/dex/algebra/config.js.map +1 -1
  29. package/build/dex/algebra/types.d.ts +1 -1
  30. package/build/dex/curve-v1/pools/frxETHpool.d.ts +7 -0
  31. package/build/dex/curve-v1/pools/frxETHpool.js +27 -0
  32. package/build/dex/curve-v1/pools/frxETHpool.js.map +1 -0
  33. package/build/dex/curve-v1/pools/wbETHpool.d.ts +29 -0
  34. package/build/dex/curve-v1/pools/wbETHpool.js +408 -0
  35. package/build/dex/curve-v1/pools/wbETHpool.js.map +1 -0
  36. package/build/dex/{test-dex → dexalot}/config.d.ts +1 -1
  37. package/build/dex/dexalot/config.js +18 -0
  38. package/build/dex/dexalot/config.js.map +1 -0
  39. package/build/dex/dexalot/constants.d.ts +15 -0
  40. package/build/dex/dexalot/constants.js +22 -0
  41. package/build/dex/dexalot/constants.js.map +1 -0
  42. package/build/dex/dexalot/dexalot.d.ts +69 -0
  43. package/build/dex/dexalot/dexalot.js +646 -0
  44. package/build/dex/dexalot/dexalot.js.map +1 -0
  45. package/build/dex/dexalot/rate-fetcher.d.ts +28 -0
  46. package/build/dex/dexalot/rate-fetcher.js +100 -0
  47. package/build/dex/dexalot/rate-fetcher.js.map +1 -0
  48. package/build/dex/dexalot/types.d.ts +114 -0
  49. package/build/dex/dexalot/types.js +12 -0
  50. package/build/dex/dexalot/types.js.map +1 -0
  51. package/build/dex/dexalot/validators.d.ts +5 -0
  52. package/build/dex/dexalot/validators.js +45 -0
  53. package/build/dex/dexalot/validators.js.map +1 -0
  54. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.d.ts +26 -0
  55. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.js +44 -0
  56. package/build/dex/pancakeswap-v3/pancakeswap-v3-factory.js.map +1 -0
  57. package/build/dex/pancakeswap-v3/pancakeswap-v3.d.ts +3 -0
  58. package/build/dex/pancakeswap-v3/pancakeswap-v3.js +26 -2
  59. package/build/dex/pancakeswap-v3/pancakeswap-v3.js.map +1 -1
  60. package/build/dex/pancakeswap-v3/types.d.ts +14 -0
  61. package/build/dex/{test-dex → pancakeswap-v3}/types.js.map +1 -1
  62. package/build/dex/ramses-v2/config.d.ts +4 -0
  63. package/build/dex/ramses-v2/config.js +28 -0
  64. package/build/dex/ramses-v2/config.js.map +1 -0
  65. package/build/dex/ramses-v2/constants.d.ts +28 -0
  66. package/build/dex/ramses-v2/constants.js +35 -0
  67. package/build/dex/ramses-v2/constants.js.map +1 -0
  68. package/build/dex/ramses-v2/contract-math/BitMath.d.ts +4 -0
  69. package/build/dex/ramses-v2/contract-math/BitMath.js +93 -0
  70. package/build/dex/ramses-v2/contract-math/BitMath.js.map +1 -0
  71. package/build/dex/ramses-v2/contract-math/FixedPoint128.d.ts +3 -0
  72. package/build/dex/ramses-v2/contract-math/FixedPoint128.js +8 -0
  73. package/build/dex/ramses-v2/contract-math/FixedPoint128.js.map +1 -0
  74. package/build/dex/ramses-v2/contract-math/FixedPoint96.d.ts +4 -0
  75. package/build/dex/ramses-v2/contract-math/FixedPoint96.js +9 -0
  76. package/build/dex/ramses-v2/contract-math/FixedPoint96.js.map +1 -0
  77. package/build/dex/ramses-v2/contract-math/FullMath.d.ts +4 -0
  78. package/build/dex/ramses-v2/contract-math/FullMath.js +19 -0
  79. package/build/dex/ramses-v2/contract-math/FullMath.js.map +1 -0
  80. package/build/dex/ramses-v2/contract-math/LiquidityMath.d.ts +3 -0
  81. package/build/dex/ramses-v2/contract-math/LiquidityMath.js +22 -0
  82. package/build/dex/ramses-v2/contract-math/LiquidityMath.js.map +1 -0
  83. package/build/dex/ramses-v2/contract-math/Oracle.d.ts +10 -0
  84. package/build/dex/ramses-v2/contract-math/Oracle.js +133 -0
  85. package/build/dex/ramses-v2/contract-math/Oracle.js.map +1 -0
  86. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.d.ts +10 -0
  87. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.js +91 -0
  88. package/build/dex/ramses-v2/contract-math/SqrtPriceMath.js.map +1 -0
  89. package/build/dex/ramses-v2/contract-math/SwapMath.d.ts +8 -0
  90. package/build/dex/ramses-v2/contract-math/SwapMath.js +70 -0
  91. package/build/dex/ramses-v2/contract-math/SwapMath.js.map +1 -0
  92. package/build/dex/ramses-v2/contract-math/Tick.d.ts +7 -0
  93. package/build/dex/ramses-v2/contract-math/Tick.js +45 -0
  94. package/build/dex/ramses-v2/contract-math/Tick.js.map +1 -0
  95. package/build/dex/ramses-v2/contract-math/TickBitMap.d.ts +8 -0
  96. package/build/dex/ramses-v2/contract-math/TickBitMap.js +87 -0
  97. package/build/dex/ramses-v2/contract-math/TickBitMap.js.map +1 -0
  98. package/build/dex/ramses-v2/contract-math/TickMath.d.ts +8 -0
  99. package/build/dex/ramses-v2/contract-math/TickMath.js +162 -0
  100. package/build/dex/ramses-v2/contract-math/TickMath.js.map +1 -0
  101. package/build/dex/ramses-v2/contract-math/UnsafeMath.d.ts +3 -0
  102. package/build/dex/ramses-v2/contract-math/UnsafeMath.js +10 -0
  103. package/build/dex/ramses-v2/contract-math/UnsafeMath.js.map +1 -0
  104. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.d.ts +18 -0
  105. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.js +392 -0
  106. package/build/dex/ramses-v2/contract-math/uniswap-v3-math.js.map +1 -0
  107. package/build/dex/ramses-v2/contract-math/utils.d.ts +3 -0
  108. package/build/dex/ramses-v2/contract-math/utils.js +16 -0
  109. package/build/dex/ramses-v2/contract-math/utils.js.map +1 -0
  110. package/build/dex/ramses-v2/ramses-v2-pool.d.ts +42 -0
  111. package/build/dex/ramses-v2/ramses-v2-pool.js +307 -0
  112. package/build/dex/ramses-v2/ramses-v2-pool.js.map +1 -0
  113. package/build/dex/ramses-v2/ramses-v2.d.ts +61 -0
  114. package/build/dex/ramses-v2/ramses-v2.js +690 -0
  115. package/build/dex/ramses-v2/ramses-v2.js.map +1 -0
  116. package/build/dex/ramses-v2/types.d.ts +154 -0
  117. package/build/dex/ramses-v2/types.js +9 -0
  118. package/build/dex/ramses-v2/types.js.map +1 -0
  119. package/build/dex/ramses-v2/utils.d.ts +6 -0
  120. package/build/dex/ramses-v2/utils.js +71 -0
  121. package/build/dex/ramses-v2/utils.js.map +1 -0
  122. package/build/dex/sushiswap-v3/config.d.ts +4 -0
  123. package/build/dex/sushiswap-v3/config.js +132 -0
  124. package/build/dex/sushiswap-v3/config.js.map +1 -0
  125. package/build/dex/sushiswap-v3/constants.d.ts +4 -0
  126. package/build/dex/sushiswap-v3/constants.js +32 -0
  127. package/build/dex/sushiswap-v3/constants.js.map +1 -0
  128. package/build/dex/sushiswap-v3/sushiswap-v3-original.d.ts +56 -0
  129. package/build/dex/sushiswap-v3/sushiswap-v3-original.js +598 -0
  130. package/build/dex/sushiswap-v3/sushiswap-v3-original.js.map +1 -0
  131. package/build/dex/sushiswap-v3/sushiswap-v3-pool.d.ts +1 -0
  132. package/build/dex/sushiswap-v3/sushiswap-v3-pool.js +6 -0
  133. package/build/dex/sushiswap-v3/sushiswap-v3-pool.js.map +1 -0
  134. package/build/dex/sushiswap-v3/sushiswap-v3.d.ts +21 -0
  135. package/build/dex/sushiswap-v3/sushiswap-v3.js +58 -0
  136. package/build/dex/sushiswap-v3/sushiswap-v3.js.map +1 -0
  137. package/build/dex/sushiswap-v3/token.d.ts +6 -0
  138. package/build/dex/sushiswap-v3/token.js +23 -0
  139. package/build/dex/sushiswap-v3/token.js.map +1 -0
  140. package/build/dex/sushiswap-v3/types.d.ts +15 -0
  141. package/build/dex/sushiswap-v3/types.js +18 -0
  142. package/build/dex/sushiswap-v3/types.js.map +1 -0
  143. package/build/dex/uniswap-v3/config.js +2 -0
  144. package/build/dex/uniswap-v3/config.js.map +1 -1
  145. package/build/dex/uniswap-v3/forks/ramses-v2/ramses-v2-pool.d.ts +7 -0
  146. package/build/dex/uniswap-v3/forks/ramses-v2/ramses-v2-pool.js +87 -0
  147. package/build/dex/uniswap-v3/forks/ramses-v2/ramses-v2-pool.js.map +1 -0
  148. package/build/dex/uniswap-v3/types.d.ts +3 -0
  149. package/build/dex/uniswap-v3/types.js.map +1 -1
  150. package/build/dex/uniswap-v3/uniswap-v3-factory.d.ts +26 -0
  151. package/build/dex/uniswap-v3/uniswap-v3-factory.js +44 -0
  152. package/build/dex/uniswap-v3/uniswap-v3-factory.js.map +1 -0
  153. package/build/dex/uniswap-v3/uniswap-v3-pool.d.ts +7 -5
  154. package/build/dex/uniswap-v3/uniswap-v3-pool.js.map +1 -1
  155. package/build/dex/uniswap-v3/uniswap-v3.d.ts +3 -0
  156. package/build/dex/uniswap-v3/uniswap-v3.js +33 -5
  157. package/build/dex/uniswap-v3/uniswap-v3.js.map +1 -1
  158. package/build/dex-helper/dummy-dex-helper.js +3 -0
  159. package/build/dex-helper/dummy-dex-helper.js.map +1 -1
  160. package/build/dex-helper/icache.d.ts +1 -0
  161. package/package.json +1 -1
  162. package/src/abi/pancakeswap-v3/PancakeswapV3Factory.abi.json +300 -0
  163. package/src/abi/ramses-v2/RamsesV2Pool.abi.json +1580 -0
  164. package/src/dex/algebra/algebra-factory.ts +70 -0
  165. package/src/dex/algebra/algebra.ts +47 -6
  166. package/src/dex/algebra/config.ts +0 -1
  167. package/src/dex/algebra/types.ts +2 -1
  168. package/src/dex/pancakeswap-v3/pancakeswap-v3-factory.ts +73 -0
  169. package/src/dex/pancakeswap-v3/pancakeswap-v3.ts +50 -2
  170. package/src/dex/uniswap-v3/config.ts +2 -0
  171. package/src/dex/uniswap-v3/forks/ramses-v2/ramses-v2-pool.ts +104 -0
  172. package/src/dex/uniswap-v3/types.ts +4 -0
  173. package/src/dex/uniswap-v3/uniswap-v3-factory.ts +73 -0
  174. package/src/dex/uniswap-v3/uniswap-v3-pool.ts +6 -4
  175. package/src/dex/uniswap-v3/uniswap-v3.ts +72 -22
  176. package/src/dex-helper/dummy-dex-helper.ts +4 -0
  177. package/src/dex-helper/icache.ts +2 -0
  178. package/build/abi/quickPerps/fast-price-events.json +0 -70
  179. package/build/abi/quickPerps/fast-price-feed.json +0 -748
  180. package/build/abi/quickPerps/reader.json +0 -313
  181. package/build/abi/quickPerps/vault-price-feed.json +0 -477
  182. package/build/abi/quickPerps/vault.json +0 -1953
  183. package/build/dex/maverick-v1/scripts/event-sequence.d.ts +0 -1
  184. package/build/dex/maverick-v1/scripts/event-sequence.js +0 -110
  185. package/build/dex/maverick-v1/scripts/event-sequence.js.map +0 -1
  186. package/build/dex/test-dex/config.js +0 -15
  187. package/build/dex/test-dex/config.js.map +0 -1
  188. package/build/dex/test-dex/test-dex-pool.d.ts +0 -39
  189. package/build/dex/test-dex/test-dex-pool.js +0 -63
  190. package/build/dex/test-dex/test-dex-pool.js.map +0 -1
  191. package/build/dex/test-dex/test-dex.d.ts +0 -37
  192. package/build/dex/test-dex/test-dex.js +0 -126
  193. package/build/dex/test-dex/test-dex.js.map +0 -1
  194. package/build/dex/test-dex/types.d.ts +0 -6
  195. package/build/dex/woo-fi-v2/woo-fi-math.d.ts +0 -16
  196. package/build/dex/woo-fi-v2/woo-fi-math.js +0 -137
  197. package/build/dex/woo-fi-v2/woo-fi-math.js.map +0 -1
  198. package/build/workers.d.ts +0 -0
  199. package/build/workers.js +0 -2
  200. package/build/workers.js.map +0 -1
  201. /package/build/dex/{test-dex → pancakeswap-v3}/types.js +0 -0
@@ -0,0 +1,70 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { DeepReadonly } from 'ts-essentials';
3
+ import FactoryABI from '../../abi/algebra/AlgebraFactory-v1_1.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
+ }: {
14
+ token0: string;
15
+ token1: string;
16
+ }) => Promise<void>;
17
+
18
+ /*
19
+ * "Stateless" event subscriber in order to capture "PoolCreated" event on new pools created.
20
+ * 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)
21
+ */
22
+ export class AlgebraFactory extends StatefulEventSubscriber<FactoryState> {
23
+ handlers: {
24
+ [event: string]: (event: any) => Promise<void>;
25
+ } = {};
26
+
27
+ logDecoder: (log: Log) => any;
28
+
29
+ public readonly factoryIface = new Interface(FactoryABI);
30
+
31
+ constructor(
32
+ readonly dexHelper: IDexHelper,
33
+ parentName: string,
34
+ protected readonly factoryAddress: Address,
35
+ logger: Logger,
36
+ protected readonly onPoolCreated: OnPoolCreatedCallback,
37
+ mapKey: string = '',
38
+ ) {
39
+ super(parentName, `${parentName} Factory`, dexHelper, logger, true, mapKey);
40
+
41
+ this.addressesSubscribed = [factoryAddress];
42
+
43
+ this.logDecoder = (log: Log) => this.factoryIface.parseLog(log);
44
+
45
+ this.handlers['Pool'] = this.handleNewPool.bind(this);
46
+ }
47
+
48
+ generateState(): FactoryState {
49
+ return {};
50
+ }
51
+
52
+ protected async processLog(
53
+ _: DeepReadonly<FactoryState>,
54
+ log: Readonly<Log>,
55
+ ): Promise<FactoryState> {
56
+ const event = this.logDecoder(log);
57
+ if (event.name in this.handlers) {
58
+ await this.handlers[event.name](event);
59
+ }
60
+
61
+ return {};
62
+ }
63
+
64
+ async handleNewPool(event: LogDescription) {
65
+ const token0 = event.args.token0;
66
+ const token1 = event.args.token1;
67
+
68
+ await this.onPoolCreated({ token0, token1 });
69
+ }
70
+ }
@@ -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,
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;
@@ -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,
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,
@@ -5,6 +5,7 @@ import { Address } from '../../types';
5
5
  import RamsesV2StateMulticallABI from '../../abi/RamsesV2StateMulticall.abi.json';
6
6
  import { AbiItem } from 'web3-utils';
7
7
  import { decodeStateMultiCallResultWithRelativeBitmaps } from './forks/ramses-v2/utils';
8
+ import { RamsesV2EventPool } from './forks/ramses-v2/ramses-v2-pool';
8
9
 
9
10
  const SUPPORTED_FEES = [10000n, 3000n, 500n, 100n];
10
11
 
@@ -251,6 +252,7 @@ export const UniswapV3Config: DexConfigMap<DexParams> = {
251
252
  uniswapMulticall: '0x1F98415757620B543A52E61c46B32eB19261F984',
252
253
  chunksCount: 10,
253
254
  initRetryFrequency: 10,
255
+ eventPoolImplementation: RamsesV2EventPool,
254
256
  decodeStateMultiCallResultWithRelativeBitmaps,
255
257
  initHash:
256
258
  '0x1565b129f2d1790f12d45301b9b084335626f0c92410bc43130763b69971135d',
@@ -0,0 +1,104 @@
1
+ import { UniswapV3EventPool } from '../../uniswap-v3-pool';
2
+ import { DecodedStateMultiCallResultWithRelativeBitmaps, PoolState } from '../../types';
3
+ import { assert } from 'ts-essentials';
4
+ import { _reduceTickBitmap, _reduceTicks } from '../../contract-math/utils';
5
+ import { bigIntify } from '../../../../utils';
6
+ import { TickBitMap } from '../../contract-math/TickBitMap';
7
+ import { uint24ToBigInt } from '../../../../lib/decoders';
8
+ import { Interface } from 'ethers/lib/utils';
9
+ import RamsesV2PoolABI from '../../../../abi/ramses-v2/RamsesV2Pool.abi.json';
10
+
11
+ export class RamsesV2EventPool extends UniswapV3EventPool {
12
+
13
+ public readonly poolIface = new Interface(RamsesV2PoolABI);
14
+
15
+ async generateState(blockNumber: number): Promise<Readonly<PoolState>> {
16
+ const callData = this._getStateRequestCallData();
17
+
18
+ const calldataWithFee = [
19
+ ...callData,
20
+ {
21
+ target: this.poolAddress,
22
+ callData: this.poolIface.encodeFunctionData('currentFee'),
23
+ decodeFunction: uint24ToBigInt,
24
+ },
25
+ ];
26
+
27
+ this._stateRequestCallData = calldataWithFee;
28
+
29
+ const [resBalance0, resBalance1, resState, resCurrentFee] =
30
+ await this.dexHelper.multiWrapper.tryAggregate<
31
+ bigint | DecodedStateMultiCallResultWithRelativeBitmaps
32
+ >(
33
+ false,
34
+ calldataWithFee,
35
+ blockNumber,
36
+ this.dexHelper.multiWrapper.defaultBatchSize,
37
+ false,
38
+ );
39
+
40
+ assert(resState.success, 'Pool does not exist');
41
+
42
+ const [balance0, balance1, _state, fee] = [
43
+ resBalance0.returnData,
44
+ resBalance1.returnData,
45
+ resState.returnData,
46
+ resCurrentFee.returnData,
47
+ ] as [bigint, bigint, DecodedStateMultiCallResultWithRelativeBitmaps, bigint];
48
+
49
+ const tickBitmap = {};
50
+ const ticks = {};
51
+
52
+ this.currentFeeCodeAsString = fee.toString();
53
+ _reduceTickBitmap(tickBitmap, _state.tickBitmap);
54
+ _reduceTicks(ticks, _state.ticks);
55
+
56
+ const observations = {
57
+ [_state.slot0.observationIndex]: {
58
+ blockTimestamp: bigIntify(_state.observation.blockTimestamp),
59
+ tickCumulative: bigIntify(_state.observation.tickCumulative),
60
+ secondsPerLiquidityCumulativeX128: bigIntify(
61
+ _state.observation.secondsPerLiquidityCumulativeX128,
62
+ ),
63
+ initialized: _state.observation.initialized,
64
+ },
65
+ };
66
+
67
+ const currentTick = bigIntify(_state.slot0.tick);
68
+ const tickSpacing = bigIntify(_state.tickSpacing);
69
+
70
+ const startTickBitmap = TickBitMap.position(currentTick / tickSpacing)[0];
71
+ const requestedRange = this.getBitmapRangeToRequest();
72
+
73
+ return {
74
+ pool: _state.pool,
75
+ blockTimestamp: bigIntify(_state.blockTimestamp),
76
+ slot0: {
77
+ sqrtPriceX96: bigIntify(_state.slot0.sqrtPriceX96),
78
+ tick: currentTick,
79
+ observationIndex: +_state.slot0.observationIndex,
80
+ observationCardinality: +_state.slot0.observationCardinality,
81
+ observationCardinalityNext: +_state.slot0.observationCardinalityNext,
82
+ feeProtocol: bigIntify(_state.slot0.feeProtocol),
83
+ },
84
+ liquidity: bigIntify(_state.liquidity),
85
+ fee,
86
+ tickSpacing,
87
+ maxLiquidityPerTick: bigIntify(_state.maxLiquidityPerTick),
88
+ tickBitmap,
89
+ ticks,
90
+ observations,
91
+ isValid: true,
92
+ startTickBitmap,
93
+ lowestKnownTick:
94
+ (BigInt.asIntN(24, startTickBitmap - requestedRange) << 8n) *
95
+ tickSpacing,
96
+ highestKnownTick:
97
+ ((BigInt.asIntN(24, startTickBitmap + requestedRange) << 8n) +
98
+ BigInt.asIntN(24, 255n)) *
99
+ tickSpacing,
100
+ balance0,
101
+ balance1,
102
+ };
103
+ }
104
+ }
@@ -3,6 +3,7 @@ import { NumberAsString } from '../../types';
3
3
  import { Address } from '../../types';
4
4
  import { AbiItem } from 'web3-utils';
5
5
  import { MultiResult } from '../../lib/multi-wrapper';
6
+ import { UniswapV3EventPool } from './uniswap-v3-pool';
6
7
 
7
8
  export type OracleObservation = {
8
9
  blockTimestamp: bigint;
@@ -53,6 +54,8 @@ export type PoolState = {
53
54
  balance1: bigint;
54
55
  };
55
56
 
57
+ export type FactoryState = Record<string, never>;
58
+
56
59
  export type UniswapV3Data = {
57
60
  path: {
58
61
  tokenIn: Address;
@@ -79,6 +82,7 @@ export type DexParams = {
79
82
  subgraphURL: string;
80
83
  initHash: string;
81
84
  stateMultiCallAbi?: AbiItem[];
85
+ eventPoolImplementation?: typeof UniswapV3EventPool;
82
86
  decodeStateMultiCallResultWithRelativeBitmaps?: DecodeStateMultiCallFunc;
83
87
  };
84
88
 
@@ -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
+ }
@@ -46,7 +46,9 @@ export class UniswapV3EventPool extends StatefulEventSubscriber<PoolState> {
46
46
 
47
47
  private _poolAddress?: Address;
48
48
 
49
- private _stateRequestCallData?: MultiCallParams<
49
+ public currentFeeCodeAsString: string | undefined;
50
+
51
+ protected _stateRequestCallData?: MultiCallParams<
50
52
  bigint | DecodedStateMultiCallResultWithRelativeBitmaps
51
53
  >[];
52
54
 
@@ -55,7 +57,7 @@ export class UniswapV3EventPool extends StatefulEventSubscriber<PoolState> {
55
57
  public initFailed = false;
56
58
  public initRetryAttemptCount = 0;
57
59
 
58
- public readonly feeCodeAsString;
60
+ public feeCodeAsString;
59
61
 
60
62
  constructor(
61
63
  readonly dexHelper: IDexHelper,
@@ -66,7 +68,7 @@ export class UniswapV3EventPool extends StatefulEventSubscriber<PoolState> {
66
68
  | undefined,
67
69
  readonly erc20Interface: Interface,
68
70
  protected readonly factoryAddress: Address,
69
- public readonly feeCode: bigint,
71
+ public feeCode: bigint,
70
72
  token0: Address,
71
73
  token1: Address,
72
74
  logger: Logger,
@@ -199,7 +201,7 @@ export class UniswapV3EventPool extends StatefulEventSubscriber<PoolState> {
199
201
  return null; // ignore unrecognized event
200
202
  }
201
203
 
202
- private _getStateRequestCallData() {
204
+ protected _getStateRequestCallData() {
203
205
  if (!this._stateRequestCallData) {
204
206
  const callData: MultiCallParams<
205
207
  bigint | DecodedStateMultiCallResultWithRelativeBitmaps