@paraswap/dex-lib 3.8.15 → 3.8.16-oswap.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.
Files changed (118) hide show
  1. package/build/abi/lite-psm/dai.json +333 -0
  2. package/build/abi/lite-psm/psm.json +468 -0
  3. package/build/abi/lite-psm/usdc.json +814 -0
  4. package/build/config.js +1 -0
  5. package/build/config.js.map +1 -1
  6. package/build/dex/angle-transmuter/angle-transmuter.js +1 -1
  7. package/build/dex/angle-transmuter/angle-transmuter.js.map +1 -1
  8. package/build/dex/dexalot/config.js +3 -0
  9. package/build/dex/dexalot/config.js.map +1 -1
  10. package/build/dex/idex.d.ts +11 -7
  11. package/build/dex/index.js +6 -0
  12. package/build/dex/index.js.map +1 -1
  13. package/build/dex/integral/integral.js +8 -9
  14. package/build/dex/integral/integral.js.map +1 -1
  15. package/build/dex/integral/types.d.ts +1 -0
  16. package/build/dex/integral/types.js.map +1 -1
  17. package/build/dex/lite-psm/config.d.ts +3 -0
  18. package/build/dex/lite-psm/config.js +29 -0
  19. package/build/dex/lite-psm/config.js.map +1 -0
  20. package/build/dex/lite-psm/lite-psm-event-pool.d.ts +29 -0
  21. package/build/dex/lite-psm/lite-psm-event-pool.js +164 -0
  22. package/build/dex/lite-psm/lite-psm-event-pool.js.map +1 -0
  23. package/build/dex/lite-psm/lite-psm.d.ts +52 -0
  24. package/build/dex/lite-psm/lite-psm.js +341 -0
  25. package/build/dex/lite-psm/lite-psm.js.map +1 -0
  26. package/build/dex/lite-psm/types.d.ts +40 -0
  27. package/build/dex/lite-psm/types.js +3 -0
  28. package/build/dex/lite-psm/types.js.map +1 -0
  29. package/build/dex/maker-psm/maker-psm.js +4 -1
  30. package/build/dex/maker-psm/maker-psm.js.map +1 -1
  31. package/build/dex/maverick-v2/config.js +4 -0
  32. package/build/dex/maverick-v2/config.js.map +1 -1
  33. package/build/dex/maverick-v2/maverick-math/maverick-pool-math.js +4 -0
  34. package/build/dex/maverick-v2/maverick-math/maverick-pool-math.js.map +1 -1
  35. package/build/dex/maverick-v2/maverick-v2-pool.d.ts +1 -1
  36. package/build/dex/maverick-v2/maverick-v2-pool.js +8 -8
  37. package/build/dex/maverick-v2/maverick-v2-pool.js.map +1 -1
  38. package/build/dex/maverick-v2/maverick-v2.d.ts +5 -4
  39. package/build/dex/maverick-v2/maverick-v2.js +73 -63
  40. package/build/dex/maverick-v2/maverick-v2.js.map +1 -1
  41. package/build/dex/maverick-v2/types.d.ts +4 -0
  42. package/build/dex/oswap/oswap-pool.js +8 -8
  43. package/build/dex/oswap/oswap-pool.js.map +1 -1
  44. package/build/dex/oswap/oswap.d.ts +2 -2
  45. package/build/dex/oswap/oswap.js +51 -44
  46. package/build/dex/oswap/oswap.js.map +1 -1
  47. package/build/dex/oswap/types.d.ts +4 -4
  48. package/build/dex/solidly-v3/solidly-v3.js +7 -0
  49. package/build/dex/solidly-v3/solidly-v3.js.map +1 -1
  50. package/build/dex/trader-joe-v2.1/base.d.ts +18 -0
  51. package/build/dex/trader-joe-v2.1/base.js +88 -0
  52. package/build/dex/trader-joe-v2.1/base.js.map +1 -0
  53. package/build/dex/trader-joe-v2.1/config.d.ts +3 -0
  54. package/build/dex/trader-joe-v2.1/config.js +7 -3
  55. package/build/dex/trader-joe-v2.1/config.js.map +1 -1
  56. package/build/dex/trader-joe-v2.1/optimizer.d.ts +2 -0
  57. package/build/dex/trader-joe-v2.1/optimizer.js +44 -0
  58. package/build/dex/trader-joe-v2.1/optimizer.js.map +1 -0
  59. package/build/dex/trader-joe-v2.1/trader-joe-v2.1.d.ts +2 -14
  60. package/build/dex/trader-joe-v2.1/trader-joe-v2.1.js +3 -85
  61. package/build/dex/trader-joe-v2.1/trader-joe-v2.1.js.map +1 -1
  62. package/build/dex/trader-joe-v2.1/trader-joe-v2.2.d.ts +7 -0
  63. package/build/dex/trader-joe-v2.1/trader-joe-v2.2.js +20 -0
  64. package/build/dex/trader-joe-v2.1/trader-joe-v2.2.js.map +1 -0
  65. package/build/dex/trader-joe-v2.1/types.d.ts +3 -3
  66. package/build/dex/weth/config.js +3 -0
  67. package/build/dex/weth/config.js.map +1 -1
  68. package/build/dex-helper/dummy-dex-helper.js +1 -1
  69. package/build/dex-helper/dummy-dex-helper.js.map +1 -1
  70. package/build/executor/types.d.ts +2 -1
  71. package/build/executor/types.js +1 -0
  72. package/build/executor/types.js.map +1 -1
  73. package/package.json +1 -1
  74. package/src/abi/lite-psm/dai.json +333 -0
  75. package/src/abi/lite-psm/psm.json +468 -0
  76. package/src/abi/lite-psm/usdc.json +814 -0
  77. package/src/abi/maverick-v2/MaverickV2Router.json +778 -0
  78. package/src/abi/oswap/oswap.abi.json +452 -0
  79. package/src/config.ts +1 -0
  80. package/src/dex/angle-transmuter/angle-transmuter.ts +1 -1
  81. package/src/dex/dexalot/config.ts +3 -0
  82. package/src/dex/dexalot/dexalot-e2e.test.ts +23 -1
  83. package/src/dex/dexalot/dexalot-integration.test.ts +122 -0
  84. package/src/dex/idex.ts +48 -41
  85. package/src/dex/index.ts +6 -0
  86. package/src/dex/lite-psm/config.ts +29 -0
  87. package/src/dex/lite-psm/lite-psm-e2e.test.ts +79 -0
  88. package/src/dex/lite-psm/lite-psm-event-pool.ts +216 -0
  89. package/src/dex/lite-psm/lite-psm-events.test.ts +61 -0
  90. package/src/dex/lite-psm/lite-psm-integration.test.ts +99 -0
  91. package/src/dex/lite-psm/lite-psm.ts +523 -0
  92. package/src/dex/lite-psm/types.ts +46 -0
  93. package/src/dex/maker-psm/maker-psm.ts +4 -1
  94. package/src/dex/maverick-v2/config.ts +4 -0
  95. package/src/dex/maverick-v2/maverick-math/maverick-pool-math.ts +5 -0
  96. package/src/dex/maverick-v2/maverick-v2-e2e.test.ts +21 -43
  97. package/src/dex/maverick-v2/maverick-v2-integration.test.ts +100 -96
  98. package/src/dex/maverick-v2/maverick-v2-pool.ts +8 -8
  99. package/src/dex/maverick-v2/maverick-v2.ts +111 -81
  100. package/src/dex/maverick-v2/types.ts +4 -0
  101. package/src/dex/oswap/config.ts +32 -0
  102. package/src/dex/oswap/oswap-e2e.test.ts +91 -0
  103. package/src/dex/oswap/oswap-events.test.ts +88 -0
  104. package/src/dex/oswap/oswap-integration.test.ts +269 -0
  105. package/src/dex/oswap/oswap-pool.ts +190 -0
  106. package/src/dex/oswap/oswap.ts +392 -0
  107. package/src/dex/oswap/types.ts +29 -0
  108. package/src/dex/solidly-v3/solidly-v3.ts +7 -0
  109. package/src/dex/trader-joe-v2.1/base.ts +167 -0
  110. package/src/dex/trader-joe-v2.1/config.ts +7 -2
  111. package/src/dex/trader-joe-v2.1/trader-joe-v2.1.ts +8 -165
  112. package/src/dex/trader-joe-v2.1/trader-joe-v2.2.ts +23 -0
  113. package/src/dex/trader-joe-v2.1/types.ts +3 -3
  114. package/src/dex/weth/config.ts +3 -0
  115. package/src/dex/weth/weth-e2e.test.ts +156 -0
  116. package/src/dex-helper/dummy-dex-helper.ts +1 -1
  117. package/src/executor/types.ts +1 -0
  118. package/tests/constants-e2e.ts +9 -0
package/src/dex/idex.ts CHANGED
@@ -24,34 +24,7 @@ export type Context = {
24
24
  isGlobalDestToken: boolean;
25
25
  };
26
26
 
27
- export interface IDexTxBuilder<ExchangeData, DirectParam = null> {
28
- needWrapNative: boolean;
29
- needsSequentialPreprocessing?: boolean;
30
-
31
- // Returns the ETH fee required to swap
32
- // It is optional for a DEX to implement this
33
- // This is a legacy function and will be removed soon
34
- getNetworkFee?(
35
- srcToken: Address,
36
- destToken: Address,
37
- srcAmount: NumberAsString,
38
- destAmount: NumberAsString,
39
- data: ExchangeData,
40
- side: SwapSide,
41
- ): NumberAsString;
42
-
43
- // If exists, called before getAdapterParam to use async calls and receive data if needed
44
- preProcessTransaction?(
45
- optimalSwapExchange: OptimalSwapExchange<ExchangeData>,
46
- srcToken: Token,
47
- destToken: Token,
48
- side: SwapSide,
49
- options: PreprocessTransactionOptions,
50
- ): AsyncOrSync<[OptimalSwapExchange<ExchangeData>, ExchangeTxInfo]>;
51
-
52
- // This is helper a function to support testing if preProcessTransaction is implemented
53
- getTokenFromAddress?(address: Address): Token;
54
-
27
+ export interface IDexTxBuilderV5<ExchangeData, DirectParam = null> {
55
28
  // Encode params required by the exchange adapter
56
29
  // V5: Used for multiSwap, buy & megaSwap
57
30
  // V6: NOT used, pass a placeholder
@@ -76,18 +49,6 @@ export interface IDexTxBuilder<ExchangeData, DirectParam = null> {
76
49
  side: SwapSide,
77
50
  ): AsyncOrSync<SimpleExchangeParam>;
78
51
 
79
- getDexParam?(
80
- srcToken: Address,
81
- destToken: Address,
82
- srcAmount: NumberAsString,
83
- destAmount: NumberAsString,
84
- recipient: Address,
85
- data: ExchangeData,
86
- side: SwapSide,
87
- context: Context,
88
- executorAddress: Address,
89
- ): AsyncOrSync<DexExchangeParam>;
90
-
91
52
  // Returns params required by direct swap method.
92
53
  // Only Dexes which have a direct method should implement this
93
54
  // Used if there is a possibility for direct swap (Eg. UniswapV2,
@@ -108,8 +69,23 @@ export interface IDexTxBuilder<ExchangeData, DirectParam = null> {
108
69
  beneficiary: string,
109
70
  contractMethod: string,
110
71
  ): TxInfo<DirectParam>;
72
+ }
111
73
 
112
- // Same as above but for V6
74
+ export interface IDexTxBuilderV6<ExchangeData, DirectParam = null> {
75
+ // Returns params required by generic method
76
+ getDexParam?(
77
+ srcToken: Address,
78
+ destToken: Address,
79
+ srcAmount: NumberAsString,
80
+ destAmount: NumberAsString,
81
+ recipient: Address,
82
+ data: ExchangeData,
83
+ side: SwapSide,
84
+ context: Context,
85
+ executorAddress: Address,
86
+ ): AsyncOrSync<DexExchangeParam>;
87
+
88
+ // Returns params for direct method
113
89
  getDirectParamV6?(
114
90
  srcToken: Address,
115
91
  destToken: Address,
@@ -127,6 +103,37 @@ export interface IDexTxBuilder<ExchangeData, DirectParam = null> {
127
103
  ): TxInfo<DirectParam>;
128
104
  }
129
105
 
106
+ export interface IDexTxBuilder<ExchangeData, DirectParam = null>
107
+ extends IDexTxBuilderV5<ExchangeData, DirectParam>,
108
+ IDexTxBuilderV6<ExchangeData, DirectParam> {
109
+ needWrapNative: boolean;
110
+ needsSequentialPreprocessing?: boolean;
111
+
112
+ // Returns the ETH fee required to swap
113
+ // It is optional for a DEX to implement this
114
+ // This is a legacy function and will be removed soon
115
+ getNetworkFee?(
116
+ srcToken: Address,
117
+ destToken: Address,
118
+ srcAmount: NumberAsString,
119
+ destAmount: NumberAsString,
120
+ data: ExchangeData,
121
+ side: SwapSide,
122
+ ): NumberAsString;
123
+
124
+ // If exists, called before getAdapterParam to use async calls and receive data if needed
125
+ preProcessTransaction?(
126
+ optimalSwapExchange: OptimalSwapExchange<ExchangeData>,
127
+ srcToken: Token,
128
+ destToken: Token,
129
+ side: SwapSide,
130
+ options: PreprocessTransactionOptions,
131
+ ): AsyncOrSync<[OptimalSwapExchange<ExchangeData>, ExchangeTxInfo]>;
132
+
133
+ // This is helper a function to support testing if preProcessTransaction is implemented
134
+ getTokenFromAddress?(address: Address): Token;
135
+ }
136
+
130
137
  export interface IDexPricing<ExchangeData> {
131
138
  readonly dexKey: string;
132
139
  // This is true if the the DEX is simply
package/src/dex/index.ts CHANGED
@@ -67,6 +67,7 @@ import { QuickSwapV3 } from './quickswap/quickswap-v3';
67
67
  import { ThenaFusion } from './quickswap/thena-fusion';
68
68
  import { SwaapV2 } from './swaap-v2/swaap-v2';
69
69
  import { TraderJoeV21 } from './trader-joe-v2.1/trader-joe-v2.1';
70
+ import { TraderJoeV22 } from './trader-joe-v2.1/trader-joe-v2.2';
70
71
  import { PancakeswapV3 } from './pancakeswap-v3/pancakeswap-v3';
71
72
  import { Algebra } from './algebra/algebra';
72
73
  import { AngleTransmuter } from './angle-transmuter/angle-transmuter';
@@ -81,8 +82,10 @@ import { EtherFi } from './etherfi';
81
82
  import { Spark } from './spark/spark';
82
83
  import { VelodromeSlipstream } from './uniswap-v3/forks/velodrome-slipstream/velodrome-slipstream';
83
84
  import { AaveV3Stata } from './aave-v3-stata/aave-v3-stata';
85
+ import { OSwap } from './oswap/oswap';
84
86
  import { ConcentratorArusd } from './concentrator-arusd/concentrator-arusd';
85
87
  import { FxProtocolRusd } from './fx-protocol-rusd/fx-protocol-rusd';
88
+ import { LitePsm } from './lite-psm/lite-psm';
86
89
 
87
90
  const LegacyDexes = [
88
91
  CurveV2,
@@ -95,6 +98,7 @@ const LegacyDexes = [
95
98
  QuickSwapV3,
96
99
  ThenaFusion,
97
100
  TraderJoeV21,
101
+ TraderJoeV22,
98
102
  Lido,
99
103
  AugustusRFQOrder,
100
104
  EtherFi,
@@ -159,8 +163,10 @@ const Dexes = [
159
163
  PharaohV1,
160
164
  Spark,
161
165
  AaveV3Stata,
166
+ OSwap,
162
167
  ConcentratorArusd,
163
168
  FxProtocolRusd,
169
+ LitePsm,
164
170
  ];
165
171
 
166
172
  export type LegacyDexConstructor = new (dexHelper: IDexHelper) => IDexTxBuilder<
@@ -0,0 +1,29 @@
1
+ import { DexParams } from './types';
2
+ import { DexConfigMap } from '../../types';
3
+ import { Network } from '../../constants';
4
+
5
+ // Warning: Addresses should be lowercased
6
+ export const LitePsmConfig: DexConfigMap<DexParams> = {
7
+ LitePsm: {
8
+ [Network.MAINNET]: {
9
+ dai: {
10
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
11
+ decimals: 18,
12
+ },
13
+ vatAddress: '0x35d1b3f3d7966a1dfe207aa4514c12a259a0492b',
14
+ pools: [
15
+ {
16
+ gem: {
17
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
18
+ decimals: 6,
19
+ },
20
+ gemJoinAddress: '0xf6e72db5454dd049d0788e411b06cfaf16853042', // Same as psmAddress. LitePsm does not have an external gem join.
21
+ pocketAddress: '0x37305b1cd40574e4c5ce33f8e8306be057fd7341',
22
+ psmAddress: '0xf6e72db5454dd049d0788e411b06cfaf16853042',
23
+ identifier:
24
+ '0x4c4954452d50534d2d555344432d410000000000000000000000000000000000', // bytes32("LITE-PSM-USDC-A")
25
+ },
26
+ ],
27
+ },
28
+ },
29
+ };
@@ -0,0 +1,79 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ import { testE2E } from '../../../tests/utils-e2e';
5
+ import { Tokens, Holders } from '../../../tests/constants-e2e';
6
+ import { Network, ContractMethod, SwapSide } from '../../constants';
7
+ import { StaticJsonRpcProvider } from '@ethersproject/providers';
8
+ import { generateConfig } from '../../config';
9
+
10
+ describe('LitePsm E2E', () => {
11
+ const dexKey = 'LitePsm';
12
+
13
+ describe('LitePsm MAINNET_V6', () => {
14
+ const network = Network.MAINNET;
15
+ const tokens = Tokens[network];
16
+ const holders = Holders[network];
17
+ const provider = new StaticJsonRpcProvider(
18
+ generateConfig(network).privateHttpProvider,
19
+ network,
20
+ );
21
+
22
+ const tokenASymbol: string = 'USDC';
23
+ const tokenBSymbol: string = 'DAI';
24
+
25
+ const tokenAAmount: string = '10000000';
26
+ const tokenBAmount: string = '10000000000000000';
27
+
28
+ const sideToContractMethods = new Map([
29
+ [
30
+ SwapSide.SELL,
31
+ [
32
+ ContractMethod.swapExactAmountIn,
33
+ ContractMethod.swapExactAmountInOutOnMakerPSM,
34
+ ],
35
+ ],
36
+ [
37
+ SwapSide.BUY,
38
+ [
39
+ ContractMethod.swapExactAmountOut,
40
+ ContractMethod.swapExactAmountInOutOnMakerPSM,
41
+ ],
42
+ ],
43
+ ]);
44
+
45
+ sideToContractMethods.forEach((contractMethods, side) =>
46
+ contractMethods.forEach((contractMethod: ContractMethod) => {
47
+ describe(`${contractMethod}`, () => {
48
+ it(`${side}:${tokenASymbol} -> ${tokenBSymbol}`, async () => {
49
+ await testE2E(
50
+ tokens[tokenASymbol],
51
+ tokens[tokenBSymbol],
52
+ holders[tokenASymbol],
53
+ side === SwapSide.SELL ? tokenAAmount : tokenBAmount,
54
+ side,
55
+ dexKey,
56
+ contractMethod,
57
+ network,
58
+ provider,
59
+ );
60
+ });
61
+
62
+ it(`${side}:${tokenBSymbol} -> ${tokenASymbol}`, async () => {
63
+ await testE2E(
64
+ tokens[tokenBSymbol],
65
+ tokens[tokenASymbol],
66
+ holders[tokenBSymbol],
67
+ side === SwapSide.SELL ? tokenBAmount : tokenAAmount,
68
+ side,
69
+ dexKey,
70
+ contractMethod,
71
+ network,
72
+ provider,
73
+ );
74
+ });
75
+ });
76
+ }),
77
+ );
78
+ });
79
+ });
@@ -0,0 +1,216 @@
1
+ import { Interface } from '@ethersproject/abi';
2
+ import { DeepReadonly } from 'ts-essentials';
3
+ import { Contract } from 'web3-eth-contract';
4
+ import { Address, Log, Logger } from '../../types';
5
+ import { StatefulEventSubscriber } from '../../stateful-event-subscriber';
6
+ import { getBigIntPow } from '../../utils';
7
+ import { IDexHelper } from '../../dex-helper/idex-helper';
8
+ import { PoolState, PoolConfig } from './types';
9
+ import { LitePsmConfig } from './config';
10
+ import PsmABI from '../../abi/maker-psm/psm.json';
11
+ import VatABI from '../../abi/maker-psm/vat.json';
12
+ import { erc20Iface } from '../../lib/tokens/utils';
13
+ import DaiABI from '../../abi/lite-psm/dai.json';
14
+ import UsdcABI from '../../abi/lite-psm/usdc.json';
15
+
16
+ const vatInterface = new Interface(VatABI);
17
+ const psmInterface = new Interface(PsmABI);
18
+ const daiInterface = new Interface(DaiABI);
19
+ const usdcInterface = new Interface(UsdcABI);
20
+
21
+ const bigIntify = (b: any) => BigInt(b.toString());
22
+
23
+ export async function getOnChainState(
24
+ multiContract: Contract,
25
+ poolConfigs: PoolConfig[],
26
+ vatAddress: Address,
27
+ blockNumber: number | 'latest',
28
+ daiAddress: Address,
29
+ ): Promise<PoolState[]> {
30
+ const callData = poolConfigs
31
+ .map(c => [
32
+ {
33
+ target: c.psmAddress,
34
+ callData: psmInterface.encodeFunctionData('tin', []),
35
+ },
36
+ {
37
+ target: c.psmAddress,
38
+ callData: psmInterface.encodeFunctionData('tout', []),
39
+ },
40
+ {
41
+ target: vatAddress,
42
+ callData: vatInterface.encodeFunctionData('ilks', [c.identifier]),
43
+ },
44
+ // dai liquidity
45
+ // ceiling for `sellGem`
46
+ {
47
+ target: daiAddress,
48
+ callData: erc20Iface.encodeFunctionData('balanceOf', [c.psmAddress]),
49
+ },
50
+ // gem liquidity
51
+ // ceiling for `buyGem`
52
+ {
53
+ target: c.gem.address,
54
+ callData: erc20Iface.encodeFunctionData('balanceOf', [c.pocketAddress]),
55
+ },
56
+ ])
57
+ .flat();
58
+
59
+ const res = await multiContract.methods
60
+ .aggregate(callData)
61
+ .call({}, blockNumber);
62
+
63
+ let i = 0;
64
+ const result = poolConfigs.map(c => {
65
+ const tin = bigIntify(
66
+ psmInterface.decodeFunctionResult('tin', res.returnData[i++])[0],
67
+ );
68
+ const tout = bigIntify(
69
+ psmInterface.decodeFunctionResult('tout', res.returnData[i++])[0],
70
+ );
71
+ const ilks = vatInterface.decodeFunctionResult('ilks', res.returnData[i++]);
72
+ const rate = bigIntify(ilks.rate);
73
+ const daiBalance = bigIntify(
74
+ erc20Iface.decodeFunctionResult('balanceOf', res.returnData[i++])[0],
75
+ );
76
+ const gemBalance = bigIntify(
77
+ erc20Iface.decodeFunctionResult('balanceOf', res.returnData[i++])[0],
78
+ );
79
+ const response = {
80
+ tin,
81
+ tout,
82
+ daiBalance,
83
+ gemBalance,
84
+ rate,
85
+ };
86
+
87
+ return response;
88
+ });
89
+
90
+ return result;
91
+ }
92
+
93
+ export class LitePsmEventPool extends StatefulEventSubscriber<PoolState> {
94
+ handlers: {
95
+ [event: string]: (event: any, pool: PoolState, log: Log) => PoolState;
96
+ } = {};
97
+
98
+ logDecoder: (log: Log) => any;
99
+
100
+ to18ConversionFactor: bigint;
101
+ bytes32Tout =
102
+ '0x746f757400000000000000000000000000000000000000000000000000000000'; // bytes32('tout')
103
+ bytes32Tin =
104
+ '0x74696e0000000000000000000000000000000000000000000000000000000000'; // bytes32('tin')
105
+
106
+ daiAddress: Address;
107
+
108
+ constructor(
109
+ parentName: string,
110
+ protected network: number,
111
+ protected dexHelper: IDexHelper,
112
+ logger: Logger,
113
+ public poolConfig: PoolConfig,
114
+ protected vatAddress: Address,
115
+ ) {
116
+ super(parentName, poolConfig.identifier, dexHelper, logger);
117
+
118
+ this.daiAddress =
119
+ LitePsmConfig[this.parentName][this.network].dai.address.toLowerCase();
120
+ this.logDecoder = (log: Log) => {
121
+ const logAddress = log.address.toLowerCase();
122
+ if (logAddress === this.daiAddress) {
123
+ return daiInterface.parseLog(log);
124
+ } else if (logAddress === this.poolConfig.gem.address) {
125
+ return usdcInterface.parseLog(log);
126
+ } else {
127
+ return psmInterface.parseLog(log);
128
+ }
129
+ };
130
+ this.addressesSubscribed = [
131
+ poolConfig.psmAddress,
132
+ this.daiAddress,
133
+ this.poolConfig.gem.address,
134
+ ];
135
+ this.to18ConversionFactor = getBigIntPow(18 - poolConfig.gem.decimals);
136
+
137
+ // Add handlers
138
+ this.handlers['File'] = this.handleFile.bind(this);
139
+ this.handlers['Transfer'] = this.handleTransfer.bind(this);
140
+ }
141
+
142
+ handleFile(event: any, pool: PoolState, log: Log): PoolState {
143
+ if (event.args.what === this.bytes32Tin) {
144
+ pool.tin = bigIntify(event.args.data);
145
+ } else if (event.args.what === this.bytes32Tout) {
146
+ pool.tout = bigIntify(event.args.data);
147
+ }
148
+ return pool;
149
+ }
150
+
151
+ handleTransfer(event: any, pool: PoolState, log: Log): PoolState {
152
+ if (log.address.toLowerCase() === this.daiAddress) {
153
+ return this.handleTransferDAI(event, pool, log);
154
+ } else if (log.address.toLowerCase() === this.poolConfig.gem.address) {
155
+ return this.handleTransferGEM(event, pool, log);
156
+ }
157
+ return pool;
158
+ }
159
+
160
+ handleTransferDAI(event: any, pool: PoolState, log: Log): PoolState {
161
+ if (event.args?.src?.toLowerCase() === this.poolConfig.psmAddress) {
162
+ pool.daiBalance -= bigIntify(event.args.wad);
163
+ } else if (event.args?.dst?.toLowerCase() === this.poolConfig.psmAddress) {
164
+ pool.daiBalance += bigIntify(event.args.wad);
165
+ }
166
+ return pool;
167
+ }
168
+
169
+ handleTransferGEM(event: any, pool: PoolState, log: Log): PoolState {
170
+ if (event.args?.from?.toLowerCase() === this.poolConfig.pocketAddress) {
171
+ pool.gemBalance -= bigIntify(event.args.value);
172
+ } else if (
173
+ event.args?.to?.toLowerCase() === this.poolConfig.pocketAddress
174
+ ) {
175
+ pool.gemBalance += bigIntify(event.args.value);
176
+ }
177
+ return pool;
178
+ }
179
+
180
+ getIdentifier(): string {
181
+ return `${this.parentName}_${this.poolConfig.psmAddress}`.toLowerCase();
182
+ }
183
+
184
+ protected processLog(
185
+ state: DeepReadonly<PoolState>,
186
+ log: Readonly<Log>,
187
+ ): DeepReadonly<PoolState> | null {
188
+ try {
189
+ const event = this.logDecoder(log);
190
+ if (event.name in this.handlers) {
191
+ return this.handlers[event.name](event, state, log);
192
+ }
193
+ return state;
194
+ } catch (e) {
195
+ this.logger.error(
196
+ `Error_${this.parentName}_processLog could not parse the log with topic ${log.topics}:`,
197
+ e,
198
+ );
199
+ return null;
200
+ }
201
+ }
202
+
203
+ async generateState(
204
+ blockNumber: number | 'latest',
205
+ ): Promise<Readonly<PoolState>> {
206
+ return (
207
+ await getOnChainState(
208
+ this.dexHelper.multiContract,
209
+ [this.poolConfig],
210
+ this.vatAddress,
211
+ blockNumber,
212
+ this.daiAddress,
213
+ )
214
+ )[0];
215
+ }
216
+ }
@@ -0,0 +1,61 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ import { LitePsmEventPool } from './lite-psm-event-pool';
5
+ import { LitePsmConfig } from './config';
6
+ import { Network } from '../../constants';
7
+ import { DummyDexHelper } from '../../dex-helper/index';
8
+ import { testEventSubscriber } from '../../../tests/utils-events';
9
+ import { PoolState } from './types';
10
+
11
+ jest.setTimeout(50 * 1000);
12
+ const dexKey = 'LitePsm';
13
+ const network = Network.MAINNET;
14
+ const config = LitePsmConfig[dexKey][network];
15
+
16
+ function fetchPoolState(
17
+ makerPsmPool: LitePsmEventPool,
18
+ blockNumber: number,
19
+ ): Promise<PoolState> {
20
+ return makerPsmPool.generateState(blockNumber);
21
+ }
22
+
23
+ describe('LitePsm Event', function () {
24
+ const blockNumbers: { [eventName: string]: number[] } = {
25
+ // File: [], // never happened
26
+ SellGem: [20559136, 20559876, 20561086, 20563099, 20563672, 20563887],
27
+ BuyGem: [
28
+ 20554181, 20555354, 20555452, 20555880, 20556086, 20556431, 20558791,
29
+ ],
30
+ };
31
+
32
+ describe('LitePsmEventPool', function () {
33
+ Object.keys(blockNumbers).forEach((event: string) => {
34
+ blockNumbers[event].forEach((blockNumber: number) => {
35
+ it(`Should return the correct state after the ${blockNumber}:${event}`, async function () {
36
+ const dexHelper = new DummyDexHelper(network);
37
+ const logger = dexHelper.getLogger(dexKey);
38
+
39
+ const makerPsmPool = new LitePsmEventPool(
40
+ dexKey,
41
+ network,
42
+ dexHelper,
43
+ logger,
44
+ config.pools[0],
45
+ config.vatAddress,
46
+ );
47
+
48
+ await testEventSubscriber(
49
+ makerPsmPool,
50
+ makerPsmPool.addressesSubscribed,
51
+ (_blockNumber: number) =>
52
+ fetchPoolState(makerPsmPool, _blockNumber),
53
+ blockNumber,
54
+ `${dexKey}_${config.pools[0].psmAddress}`,
55
+ dexHelper.provider,
56
+ );
57
+ });
58
+ });
59
+ });
60
+ });
61
+ });
@@ -0,0 +1,99 @@
1
+ import dotenv from 'dotenv';
2
+ dotenv.config();
3
+
4
+ import { DummyDexHelper } from '../../dex-helper/index';
5
+ import { Network, SwapSide } from '../../constants';
6
+ import { LitePsm } from './lite-psm';
7
+ import { checkPoolPrices, checkPoolsLiquidity } from '../../../tests/utils';
8
+ import { Tokens } from '../../../tests/constants-e2e';
9
+ import { BI_POWS } from '../../bigint-constants';
10
+
11
+ const network = Network.MAINNET;
12
+ const TokenASymbol = 'USDC';
13
+ const TokenA = Tokens[network][TokenASymbol];
14
+
15
+ const TokenBSymbol = 'DAI';
16
+ const TokenB = Tokens[network][TokenBSymbol];
17
+
18
+ const tokenAAmounts = [0n, BI_POWS[8], 200000000n];
19
+
20
+ const tokenBAmounts = [0n, BI_POWS[18], 2000000000000000000n];
21
+
22
+ const dexKey = 'LitePsm';
23
+
24
+ describe('LitePsm', function () {
25
+ it('getPoolIdentifiers and getPricesVolume SELL', async function () {
26
+ const dexHelper = new DummyDexHelper(network);
27
+ const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
28
+ const litePsm = new LitePsm(network, dexKey, dexHelper);
29
+
30
+ await litePsm.initializePricing(blocknumber);
31
+
32
+ const pools = await litePsm.getPoolIdentifiers(
33
+ TokenA,
34
+ TokenB,
35
+ SwapSide.SELL,
36
+ blocknumber,
37
+ );
38
+ console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Identifiers: `, pools);
39
+
40
+ expect(pools.length).toBeGreaterThan(0);
41
+
42
+ const poolPrices = await litePsm.getPricesVolume(
43
+ TokenA,
44
+ TokenB,
45
+ tokenAAmounts,
46
+ SwapSide.SELL,
47
+ blocknumber,
48
+ pools,
49
+ );
50
+ console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Prices: `, poolPrices);
51
+
52
+ expect(poolPrices).not.toBeNull();
53
+ checkPoolPrices(poolPrices!, tokenAAmounts, SwapSide.SELL, dexKey);
54
+ });
55
+
56
+ it('getPoolIdentifiers and getPricesVolume BUY', async function () {
57
+ const dexHelper = new DummyDexHelper(network);
58
+ const blocknumber = await dexHelper.web3Provider.eth.getBlockNumber();
59
+ const litePsm = new LitePsm(network, dexKey, dexHelper);
60
+
61
+ await litePsm.initializePricing(blocknumber);
62
+
63
+ const pools = await litePsm.getPoolIdentifiers(
64
+ TokenA,
65
+ TokenB,
66
+ SwapSide.BUY,
67
+ blocknumber,
68
+ );
69
+ console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Identifiers: `, pools);
70
+
71
+ expect(pools.length).toBeGreaterThan(0);
72
+
73
+ const poolPrices = await litePsm.getPricesVolume(
74
+ TokenA,
75
+ TokenB,
76
+ tokenBAmounts,
77
+ SwapSide.BUY,
78
+ blocknumber,
79
+ pools,
80
+ );
81
+ console.log(`${TokenASymbol} <> ${TokenBSymbol} Pool Prices: `, poolPrices);
82
+
83
+ expect(poolPrices).not.toBeNull();
84
+ checkPoolPrices(poolPrices!, tokenBAmounts, SwapSide.BUY, dexKey);
85
+ });
86
+
87
+ it('getTopPoolsForToken', async function () {
88
+ const dexHelper = new DummyDexHelper(network);
89
+ const litePsm = new LitePsm(network, dexKey, dexHelper);
90
+
91
+ const poolLiquidity = await litePsm.getTopPoolsForToken(TokenA.address, 10);
92
+ console.log(
93
+ `${TokenASymbol} Top Pools:`,
94
+ JSON.stringify(poolLiquidity, null, 2),
95
+ );
96
+
97
+ checkPoolsLiquidity(poolLiquidity, TokenA.address, dexKey);
98
+ });
99
+ });