@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.
- package/build/abi/lite-psm/dai.json +333 -0
- package/build/abi/lite-psm/psm.json +468 -0
- package/build/abi/lite-psm/usdc.json +814 -0
- package/build/config.js +1 -0
- package/build/config.js.map +1 -1
- package/build/dex/angle-transmuter/angle-transmuter.js +1 -1
- package/build/dex/angle-transmuter/angle-transmuter.js.map +1 -1
- package/build/dex/dexalot/config.js +3 -0
- package/build/dex/dexalot/config.js.map +1 -1
- package/build/dex/idex.d.ts +11 -7
- package/build/dex/index.js +6 -0
- package/build/dex/index.js.map +1 -1
- package/build/dex/integral/integral.js +8 -9
- package/build/dex/integral/integral.js.map +1 -1
- package/build/dex/integral/types.d.ts +1 -0
- package/build/dex/integral/types.js.map +1 -1
- package/build/dex/lite-psm/config.d.ts +3 -0
- package/build/dex/lite-psm/config.js +29 -0
- package/build/dex/lite-psm/config.js.map +1 -0
- package/build/dex/lite-psm/lite-psm-event-pool.d.ts +29 -0
- package/build/dex/lite-psm/lite-psm-event-pool.js +164 -0
- package/build/dex/lite-psm/lite-psm-event-pool.js.map +1 -0
- package/build/dex/lite-psm/lite-psm.d.ts +52 -0
- package/build/dex/lite-psm/lite-psm.js +341 -0
- package/build/dex/lite-psm/lite-psm.js.map +1 -0
- package/build/dex/lite-psm/types.d.ts +40 -0
- package/build/dex/lite-psm/types.js +3 -0
- package/build/dex/lite-psm/types.js.map +1 -0
- package/build/dex/maker-psm/maker-psm.js +4 -1
- package/build/dex/maker-psm/maker-psm.js.map +1 -1
- package/build/dex/maverick-v2/config.js +4 -0
- package/build/dex/maverick-v2/config.js.map +1 -1
- package/build/dex/maverick-v2/maverick-math/maverick-pool-math.js +4 -0
- package/build/dex/maverick-v2/maverick-math/maverick-pool-math.js.map +1 -1
- package/build/dex/maverick-v2/maverick-v2-pool.d.ts +1 -1
- package/build/dex/maverick-v2/maverick-v2-pool.js +8 -8
- package/build/dex/maverick-v2/maverick-v2-pool.js.map +1 -1
- package/build/dex/maverick-v2/maverick-v2.d.ts +5 -4
- package/build/dex/maverick-v2/maverick-v2.js +73 -63
- package/build/dex/maverick-v2/maverick-v2.js.map +1 -1
- package/build/dex/maverick-v2/types.d.ts +4 -0
- package/build/dex/oswap/oswap-pool.js +8 -8
- package/build/dex/oswap/oswap-pool.js.map +1 -1
- package/build/dex/oswap/oswap.d.ts +2 -2
- package/build/dex/oswap/oswap.js +51 -44
- package/build/dex/oswap/oswap.js.map +1 -1
- package/build/dex/oswap/types.d.ts +4 -4
- package/build/dex/solidly-v3/solidly-v3.js +7 -0
- package/build/dex/solidly-v3/solidly-v3.js.map +1 -1
- package/build/dex/trader-joe-v2.1/base.d.ts +18 -0
- package/build/dex/trader-joe-v2.1/base.js +88 -0
- package/build/dex/trader-joe-v2.1/base.js.map +1 -0
- package/build/dex/trader-joe-v2.1/config.d.ts +3 -0
- package/build/dex/trader-joe-v2.1/config.js +7 -3
- package/build/dex/trader-joe-v2.1/config.js.map +1 -1
- package/build/dex/trader-joe-v2.1/optimizer.d.ts +2 -0
- package/build/dex/trader-joe-v2.1/optimizer.js +44 -0
- package/build/dex/trader-joe-v2.1/optimizer.js.map +1 -0
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1.d.ts +2 -14
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1.js +3 -85
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1.js.map +1 -1
- package/build/dex/trader-joe-v2.1/trader-joe-v2.2.d.ts +7 -0
- package/build/dex/trader-joe-v2.1/trader-joe-v2.2.js +20 -0
- package/build/dex/trader-joe-v2.1/trader-joe-v2.2.js.map +1 -0
- package/build/dex/trader-joe-v2.1/types.d.ts +3 -3
- package/build/dex/weth/config.js +3 -0
- package/build/dex/weth/config.js.map +1 -1
- package/build/dex-helper/dummy-dex-helper.js +1 -1
- package/build/dex-helper/dummy-dex-helper.js.map +1 -1
- package/build/executor/types.d.ts +2 -1
- package/build/executor/types.js +1 -0
- package/build/executor/types.js.map +1 -1
- package/package.json +1 -1
- package/src/abi/lite-psm/dai.json +333 -0
- package/src/abi/lite-psm/psm.json +468 -0
- package/src/abi/lite-psm/usdc.json +814 -0
- package/src/abi/maverick-v2/MaverickV2Router.json +778 -0
- package/src/abi/oswap/oswap.abi.json +452 -0
- package/src/config.ts +1 -0
- package/src/dex/angle-transmuter/angle-transmuter.ts +1 -1
- package/src/dex/dexalot/config.ts +3 -0
- package/src/dex/dexalot/dexalot-e2e.test.ts +23 -1
- package/src/dex/dexalot/dexalot-integration.test.ts +122 -0
- package/src/dex/idex.ts +48 -41
- package/src/dex/index.ts +6 -0
- package/src/dex/lite-psm/config.ts +29 -0
- package/src/dex/lite-psm/lite-psm-e2e.test.ts +79 -0
- package/src/dex/lite-psm/lite-psm-event-pool.ts +216 -0
- package/src/dex/lite-psm/lite-psm-events.test.ts +61 -0
- package/src/dex/lite-psm/lite-psm-integration.test.ts +99 -0
- package/src/dex/lite-psm/lite-psm.ts +523 -0
- package/src/dex/lite-psm/types.ts +46 -0
- package/src/dex/maker-psm/maker-psm.ts +4 -1
- package/src/dex/maverick-v2/config.ts +4 -0
- package/src/dex/maverick-v2/maverick-math/maverick-pool-math.ts +5 -0
- package/src/dex/maverick-v2/maverick-v2-e2e.test.ts +21 -43
- package/src/dex/maverick-v2/maverick-v2-integration.test.ts +100 -96
- package/src/dex/maverick-v2/maverick-v2-pool.ts +8 -8
- package/src/dex/maverick-v2/maverick-v2.ts +111 -81
- package/src/dex/maverick-v2/types.ts +4 -0
- package/src/dex/oswap/config.ts +32 -0
- package/src/dex/oswap/oswap-e2e.test.ts +91 -0
- package/src/dex/oswap/oswap-events.test.ts +88 -0
- package/src/dex/oswap/oswap-integration.test.ts +269 -0
- package/src/dex/oswap/oswap-pool.ts +190 -0
- package/src/dex/oswap/oswap.ts +392 -0
- package/src/dex/oswap/types.ts +29 -0
- package/src/dex/solidly-v3/solidly-v3.ts +7 -0
- package/src/dex/trader-joe-v2.1/base.ts +167 -0
- package/src/dex/trader-joe-v2.1/config.ts +7 -2
- package/src/dex/trader-joe-v2.1/trader-joe-v2.1.ts +8 -165
- package/src/dex/trader-joe-v2.1/trader-joe-v2.2.ts +23 -0
- package/src/dex/trader-joe-v2.1/types.ts +3 -3
- package/src/dex/weth/config.ts +3 -0
- package/src/dex/weth/weth-e2e.test.ts +156 -0
- package/src/dex-helper/dummy-dex-helper.ts +1 -1
- package/src/executor/types.ts +1 -0
- 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
|
|
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
|
-
|
|
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
|
+
});
|