@paraswap/dex-lib 3.6.3 → 3.6.4-transmuter

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 (188) hide show
  1. package/build/abi/Redstone.json +739 -0
  2. package/build/abi/aavev3stata/Factory.json +128 -0
  3. package/build/abi/aavev3stata/Token.json +735 -0
  4. package/build/abi/angle-transmuter/MorphoOracle.json +193 -0
  5. package/build/abi/angle-transmuter/MorphoVault.json +2506 -0
  6. package/build/abi/angle-transmuter/Pyth.json +1534 -0
  7. package/build/abi/angle-transmuter/Transmuter.json +1711 -0
  8. package/build/abi/angle-transmuter/TransmuterSidechain.json +1798 -0
  9. package/build/abi/idle-dao/idle-cdo-factory.json +38 -0
  10. package/build/abi/idle-dao/idle-cdo.json +1245 -0
  11. package/build/dex/aave-v1/aave-v1.d.ts +2 -1
  12. package/build/dex/aave-v1/aave-v1.js +22 -0
  13. package/build/dex/aave-v1/aave-v1.js.map +1 -1
  14. package/build/dex/aave-v3-stata/aave-v3-stata.d.ts +40 -0
  15. package/build/dex/aave-v3-stata/aave-v3-stata.js +309 -0
  16. package/build/dex/aave-v3-stata/aave-v3-stata.js.map +1 -0
  17. package/build/dex/aave-v3-stata/config.d.ts +4 -0
  18. package/build/dex/aave-v3-stata/config.js +46 -0
  19. package/build/dex/aave-v3-stata/config.js.map +1 -0
  20. package/build/dex/aave-v3-stata/tokens.d.ts +9 -0
  21. package/build/dex/aave-v3-stata/tokens.js +37 -0
  22. package/build/dex/aave-v3-stata/tokens.js.map +1 -0
  23. package/build/dex/aave-v3-stata/types.d.ts +42 -0
  24. package/build/dex/aave-v3-stata/types.js +18 -0
  25. package/build/dex/aave-v3-stata/types.js.map +1 -0
  26. package/build/dex/aave-v3-stata/utils.d.ts +4 -0
  27. package/build/dex/aave-v3-stata/utils.js +67 -0
  28. package/build/dex/aave-v3-stata/utils.js.map +1 -0
  29. package/build/dex/angle-transmuter/angle-transmuter-pool.d.ts +61 -0
  30. package/build/dex/angle-transmuter/angle-transmuter-pool.js +424 -0
  31. package/build/dex/angle-transmuter/angle-transmuter-pool.js.map +1 -0
  32. package/build/dex/angle-transmuter/angle-transmuter.d.ts +60 -0
  33. package/build/dex/angle-transmuter/angle-transmuter.js +282 -0
  34. package/build/dex/angle-transmuter/angle-transmuter.js.map +1 -0
  35. package/build/dex/angle-transmuter/backedOracle.d.ts +19 -0
  36. package/build/dex/angle-transmuter/backedOracle.js +56 -0
  37. package/build/dex/angle-transmuter/backedOracle.js.map +1 -0
  38. package/build/dex/angle-transmuter/config.d.ts +4 -0
  39. package/build/dex/angle-transmuter/config.js +50 -0
  40. package/build/dex/angle-transmuter/config.js.map +1 -0
  41. package/build/dex/angle-transmuter/constants.d.ts +10 -0
  42. package/build/dex/angle-transmuter/constants.js +137 -0
  43. package/build/dex/angle-transmuter/constants.js.map +1 -0
  44. package/build/dex/angle-transmuter/morphoOracle.d.ts +42 -0
  45. package/build/dex/angle-transmuter/morphoOracle.js +179 -0
  46. package/build/dex/angle-transmuter/morphoOracle.js.map +1 -0
  47. package/build/dex/angle-transmuter/morphoVault.d.ts +20 -0
  48. package/build/dex/angle-transmuter/morphoVault.js +84 -0
  49. package/build/dex/angle-transmuter/morphoVault.js.map +1 -0
  50. package/build/dex/angle-transmuter/pyth.d.ts +19 -0
  51. package/build/dex/angle-transmuter/pyth.js +70 -0
  52. package/build/dex/angle-transmuter/pyth.js.map +1 -0
  53. package/build/dex/angle-transmuter/redstone.d.ts +20 -0
  54. package/build/dex/angle-transmuter/redstone.js +73 -0
  55. package/build/dex/angle-transmuter/redstone.js.map +1 -0
  56. package/build/dex/angle-transmuter/transmuter.d.ts +55 -0
  57. package/build/dex/angle-transmuter/transmuter.js +410 -0
  58. package/build/dex/angle-transmuter/transmuter.js.map +1 -0
  59. package/build/dex/angle-transmuter/types.d.ts +189 -0
  60. package/build/dex/angle-transmuter/types.js +33 -0
  61. package/build/dex/angle-transmuter/types.js.map +1 -0
  62. package/build/dex/angle-transmuter/utils.d.ts +9 -0
  63. package/build/dex/angle-transmuter/utils.js +257 -0
  64. package/build/dex/angle-transmuter/utils.js.map +1 -0
  65. package/build/dex/idle-dao/config.d.ts +6 -0
  66. package/build/dex/idle-dao/config.js +297 -0
  67. package/build/dex/idle-dao/config.js.map +1 -0
  68. package/build/dex/idle-dao/idle-dao-pool.d.ts +56 -0
  69. package/build/dex/idle-dao/idle-dao-pool.js +176 -0
  70. package/build/dex/idle-dao/idle-dao-pool.js.map +1 -0
  71. package/build/dex/idle-dao/idle-dao-pooling-pool.d.ts +16 -0
  72. package/build/dex/idle-dao/idle-dao-pooling-pool.js +57 -0
  73. package/build/dex/idle-dao/idle-dao-pooling-pool.js.map +1 -0
  74. package/build/dex/idle-dao/idle-dao.d.ts +41 -0
  75. package/build/dex/idle-dao/idle-dao.js +238 -0
  76. package/build/dex/idle-dao/idle-dao.js.map +1 -0
  77. package/build/dex/idle-dao/scripts.d.ts +9 -0
  78. package/build/dex/idle-dao/scripts.js +552 -0
  79. package/build/dex/idle-dao/scripts.js.map +1 -0
  80. package/build/dex/idle-dao/tokens.d.ts +9 -0
  81. package/build/dex/idle-dao/tokens.js +65 -0
  82. package/build/dex/idle-dao/tokens.js.map +1 -0
  83. package/build/dex/idle-dao/types.d.ts +34 -0
  84. package/build/dex/idle-dao/types.js +11 -0
  85. package/build/dex/idle-dao/types.js.map +1 -0
  86. package/build/dex/idle-dao/utils.d.ts +8 -0
  87. package/build/dex/idle-dao/utils.js +146 -0
  88. package/build/dex/idle-dao/utils.js.map +1 -0
  89. package/build/dex/index.js +2 -0
  90. package/build/dex/index.js.map +1 -1
  91. package/build/dex/maverick-v2/maverick-v2.js +1 -1
  92. package/build/dex/maverick-v2/maverick-v2.js.map +1 -1
  93. package/build/dex/maverick-v2/types.d.ts +1 -1
  94. package/build/dex/platypus/platypus.d.ts +2 -1
  95. package/build/dex/platypus/platypus.js +31 -0
  96. package/build/dex/platypus/platypus.js.map +1 -1
  97. package/build/dex/swaap-v1/swaap-v1.d.ts +2 -1
  98. package/build/dex/swaap-v1/swaap-v1.js +10 -0
  99. package/build/dex/swaap-v1/swaap-v1.js.map +1 -1
  100. package/build/lib/chainlink.d.ts +2 -0
  101. package/build/lib/chainlink.js +9 -0
  102. package/build/lib/chainlink.js.map +1 -1
  103. package/build/utils.d.ts +1 -1
  104. package/package.json +1 -1
  105. package/src/abi/Redstone.json +739 -0
  106. package/src/abi/angle-transmuter/ChainlinkAccessControlledOffchainAggregator.json +1246 -0
  107. package/src/abi/angle-transmuter/ChainlinkEACAggregatorProxy.json +509 -0
  108. package/src/abi/angle-transmuter/Getters.json +568 -0
  109. package/src/abi/angle-transmuter/MorphoOracle.json +193 -0
  110. package/src/abi/angle-transmuter/MorphoVault.json +2506 -0
  111. package/src/abi/angle-transmuter/Pyth.json +1534 -0
  112. package/src/abi/angle-transmuter/Swapper.json +329 -0
  113. package/src/abi/angle-transmuter/Transmuter.json +1711 -0
  114. package/src/abi/angle-transmuter/TransmuterSidechain.json +1798 -0
  115. package/src/dex/angle-transmuter/angle-transmuter-e2e.test.ts +156 -0
  116. package/src/dex/angle-transmuter/angle-transmuter-events.test.ts +365 -0
  117. package/src/dex/angle-transmuter/angle-transmuter-integration.test.ts +384 -0
  118. package/src/dex/angle-transmuter/angle-transmuter-pool.ts +861 -0
  119. package/src/dex/angle-transmuter/angle-transmuter.ts +443 -0
  120. package/src/dex/angle-transmuter/backedOracle.ts +91 -0
  121. package/src/dex/angle-transmuter/config.ts +50 -0
  122. package/src/dex/angle-transmuter/constants.ts +139 -0
  123. package/src/dex/angle-transmuter/morphoOracle.ts +335 -0
  124. package/src/dex/angle-transmuter/morphoVault.ts +134 -0
  125. package/src/dex/angle-transmuter/pyth.ts +105 -0
  126. package/src/dex/angle-transmuter/redstone.ts +114 -0
  127. package/src/dex/angle-transmuter/transmuter.ts +645 -0
  128. package/src/dex/angle-transmuter/types.ts +203 -0
  129. package/src/dex/angle-transmuter/utils.ts +358 -0
  130. package/src/dex/index.ts +2 -0
  131. package/src/dex/maverick-v2/maverick-v2.ts +1 -1
  132. package/src/dex/maverick-v2/types.ts +1 -1
  133. package/src/lib/chainlink.ts +15 -0
  134. package/tests/constants-e2e.ts +50 -5
  135. package/build/dex/bProtocol.d.ts +0 -18
  136. package/build/dex/bProtocol.js +0 -39
  137. package/build/dex/bProtocol.js.map +0 -1
  138. package/build/dex/bancor.d.ts +0 -26
  139. package/build/dex/bancor.js +0 -58
  140. package/build/dex/bancor.js.map +0 -1
  141. package/build/dex/compound.d.ts +0 -18
  142. package/build/dex/compound.js +0 -46
  143. package/build/dex/compound.js.map +0 -1
  144. package/build/dex/curve-v2.d.ts +0 -58
  145. package/build/dex/curve-v2.js +0 -180
  146. package/build/dex/curve-v2.js.map +0 -1
  147. package/build/dex/dodo-v1.d.ts +0 -33
  148. package/build/dex/dodo-v1.js +0 -63
  149. package/build/dex/dodo-v1.js.map +0 -1
  150. package/build/dex/etherfi/etherfi.d.ts +0 -26
  151. package/build/dex/etherfi/etherfi.js +0 -96
  152. package/build/dex/etherfi/etherfi.js.map +0 -1
  153. package/build/dex/lido.d.ts +0 -19
  154. package/build/dex/lido.js +0 -42
  155. package/build/dex/lido.js.map +0 -1
  156. package/build/dex/onebit.d.ts +0 -25
  157. package/build/dex/onebit.js +0 -42
  158. package/build/dex/onebit.js.map +0 -1
  159. package/build/dex/sdai/config.d.ts +0 -11
  160. package/build/dex/sdai/config.js +0 -21
  161. package/build/dex/sdai/config.js.map +0 -1
  162. package/build/dex/sdai/constants.d.ts +0 -2
  163. package/build/dex/sdai/constants.js +0 -6
  164. package/build/dex/sdai/constants.js.map +0 -1
  165. package/build/dex/sdai/scripts/validate-state.d.ts +0 -1
  166. package/build/dex/sdai/scripts/validate-state.js +0 -102
  167. package/build/dex/sdai/scripts/validate-state.js.map +0 -1
  168. package/build/dex/sdai/sdai-pool.d.ts +0 -16
  169. package/build/dex/sdai/sdai-pool.js +0 -85
  170. package/build/dex/sdai/sdai-pool.js.map +0 -1
  171. package/build/dex/sdai/sdai.d.ts +0 -51
  172. package/build/dex/sdai/sdai.js +0 -172
  173. package/build/dex/sdai/sdai.js.map +0 -1
  174. package/build/dex/sdai/types.d.ts +0 -21
  175. package/build/dex/sdai/types.js +0 -11
  176. package/build/dex/sdai/types.js.map +0 -1
  177. package/build/dex/sdai/utils.d.ts +0 -4
  178. package/build/dex/sdai/utils.js +0 -39
  179. package/build/dex/sdai/utils.js.map +0 -1
  180. package/build/dex/smoothy.d.ts +0 -26
  181. package/build/dex/smoothy.js +0 -48
  182. package/build/dex/smoothy.js.map +0 -1
  183. package/build/dex/stable-pool.d.ts +0 -28
  184. package/build/dex/stable-pool.js +0 -62
  185. package/build/dex/stable-pool.js.map +0 -1
  186. package/build/dex/trader-joe-v2.1.d.ts +0 -43
  187. package/build/dex/trader-joe-v2.1.js +0 -79
  188. package/build/dex/trader-joe-v2.1.js.map +0 -1
@@ -0,0 +1,645 @@
1
+ import { DeepReadonly } from 'ts-essentials';
2
+ import { PartialEventSubscriber } from '../../composed-event-subscriber';
3
+ import {
4
+ Address,
5
+ BlockHeader,
6
+ Log,
7
+ Logger,
8
+ MultiCallInput,
9
+ MultiCallOutput,
10
+ } from '../../types';
11
+ import { BLOCK_UPGRADE_ORACLE, CBETH, RETH, SFRXETH, STETH } from './constants';
12
+ import { Lens } from '../../lens';
13
+ import { Interface } from '@ethersproject/abi';
14
+ import TransmuterABI from '../../abi/angle-transmuter/Transmuter.json';
15
+ import TransmuterSidechainABI from '../../abi/angle-transmuter/TransmuterSidechain.json';
16
+ import {
17
+ DecodedOracleConfig,
18
+ Chainlink,
19
+ OracleFeed,
20
+ OracleReadType,
21
+ Pyth,
22
+ TransmuterState,
23
+ Fees,
24
+ Oracle,
25
+ CollateralState,
26
+ MaxOracle,
27
+ MorphoOracle,
28
+ } from './types';
29
+ import _ from 'lodash';
30
+ import { BigNumber, ethers } from 'ethers';
31
+ import { formatEther, formatUnits } from 'ethers/lib/utils';
32
+ import { filterDictionaryOnly } from './utils';
33
+ import { Network } from '../../constants';
34
+
35
+ export class TransmuterSubscriber<State> extends PartialEventSubscriber<
36
+ State,
37
+ TransmuterState
38
+ > {
39
+ static readonly transmuterCrosschainInterface = new Interface(TransmuterABI);
40
+ public readonly interface;
41
+
42
+ constructor(
43
+ private EURA: Address,
44
+ private transmuter: Address,
45
+ private collaterals: Address[],
46
+ protected network: number,
47
+ lens: Lens<DeepReadonly<State>, DeepReadonly<TransmuterState>>,
48
+ logger: Logger,
49
+ ) {
50
+ super([transmuter], lens, logger);
51
+ if (network === Network.MAINNET)
52
+ this.interface = new Interface(TransmuterABI);
53
+ else this.interface = new Interface(TransmuterSidechainABI);
54
+ }
55
+
56
+ public processLog(
57
+ state: DeepReadonly<TransmuterState>,
58
+ log: Readonly<Log>,
59
+ blockHeader: Readonly<BlockHeader>,
60
+ ): DeepReadonly<TransmuterState> | null {
61
+ try {
62
+ const parsed = this.interface.parseLog(log);
63
+ const _state: TransmuterState = _.cloneDeep(state) as TransmuterState;
64
+ switch (parsed.name) {
65
+ case 'FeesSet':
66
+ return this._handleFeesSet(parsed, _state);
67
+ case 'RedemptionCurveParamsSet':
68
+ return this._handleRedemptionCurveSet(parsed, _state);
69
+ case 'OracleSet':
70
+ return this._handleOracleSet(parsed, _state, blockHeader.number);
71
+ case 'Swap':
72
+ return this._handleSwap(parsed, _state);
73
+ case 'Redeemed':
74
+ return this._handleRedeem(parsed, _state);
75
+ case 'ReservesAdjusted':
76
+ return this._handleAdjustStablecoins(parsed, _state);
77
+ case 'CollateralAdded':
78
+ return this._handleAddCollateral(parsed, _state);
79
+ case 'CollateralRevoked':
80
+ return this._handleRevokeCollateral(parsed, _state);
81
+ case 'CollateralWhitelistStatusUpdated':
82
+ return this._handleSetWhitelistedStatus(parsed, _state);
83
+ case 'WhitelistStatusToggled':
84
+ return this._handleIsWhitelistedForType(parsed, _state);
85
+ case 'StablecoinCapSet':
86
+ return this._handleStablecoinCapSet(parsed, _state);
87
+ default:
88
+ return null;
89
+ }
90
+ } catch (e) {
91
+ this.logger.error('Failed to parse log', e);
92
+ return null;
93
+ }
94
+ }
95
+
96
+ public getGenerateStateMultiCallInputs(): MultiCallInput[] {
97
+ const multicallInput = [
98
+ ...this.collaterals.map(collat => ({
99
+ target: this.transmuter,
100
+ callData: this.interface.encodeFunctionData('getIssuedByCollateral', [
101
+ collat,
102
+ ]),
103
+ })),
104
+ ...this.collaterals.map(collat => ({
105
+ target: this.transmuter,
106
+ callData: this.interface.encodeFunctionData('getOracle', [collat]),
107
+ })),
108
+ ...this.collaterals.map(collat => ({
109
+ target: this.transmuter,
110
+ callData: this.interface.encodeFunctionData('getCollateralMintFees', [
111
+ collat,
112
+ ]),
113
+ })),
114
+ ...this.collaterals.map(collat => ({
115
+ target: this.transmuter,
116
+ callData: this.interface.encodeFunctionData('getCollateralBurnFees', [
117
+ collat,
118
+ ]),
119
+ })),
120
+ ...this.collaterals.map(collat => ({
121
+ target: this.transmuter,
122
+ callData: this.interface.encodeFunctionData('isWhitelistedCollateral', [
123
+ collat,
124
+ ]),
125
+ })),
126
+ ...this.collaterals.map(collat => ({
127
+ target: this.transmuter,
128
+ callData: this.interface.encodeFunctionData(
129
+ 'getCollateralWhitelistData',
130
+ [collat],
131
+ ),
132
+ })),
133
+ ];
134
+ if (this.network !== Network.MAINNET) {
135
+ multicallInput.push(
136
+ ...this.collaterals.map(collat => ({
137
+ target: this.transmuter,
138
+ callData: this.interface.encodeFunctionData('getStablecoinCap', [
139
+ collat,
140
+ ]),
141
+ })),
142
+ );
143
+ }
144
+ multicallInput.push(
145
+ ...[
146
+ {
147
+ target: this.transmuter,
148
+ callData: this.interface.encodeFunctionData('getRedemptionFees'),
149
+ },
150
+ {
151
+ target: this.transmuter,
152
+ callData: this.interface.encodeFunctionData('getTotalIssued'),
153
+ },
154
+ ],
155
+ );
156
+ return multicallInput;
157
+ }
158
+
159
+ public generateState(
160
+ multicallOutputs: MultiCallOutput[],
161
+ blockNumber?: number | 'latest',
162
+ ): DeepReadonly<TransmuterState> {
163
+ const transmuterState = {
164
+ collaterals: {} as {
165
+ [token: string]: CollateralState;
166
+ },
167
+ isWhitelisted: {} as {
168
+ [token: string]: Set<string>;
169
+ },
170
+ totalStablecoinIssued: 0,
171
+ xRedemptionCurve: [],
172
+ yRedemptionCurve: [],
173
+ } as TransmuterState;
174
+
175
+ const nbrCollaterals = this.collaterals.length;
176
+ const indexStableIssued = 0;
177
+ const indexOracleFees = 1;
178
+ const indexMintFees = 2;
179
+ const indexBurnFees = 3;
180
+ const indexWhitelistStatus = 4;
181
+ const indexWhitelistData = 5;
182
+ const indexStablecoinCap = 6;
183
+
184
+ this.collaterals.forEach(
185
+ (collat: Address, i: number) =>
186
+ (transmuterState.collaterals[collat] = {
187
+ fees: {
188
+ xFeeMint: (
189
+ this.interface.decodeFunctionResult(
190
+ 'getCollateralMintFees',
191
+ multicallOutputs[indexMintFees * nbrCollaterals + i],
192
+ )[0] as BigNumber[]
193
+ ).map(f => Number.parseFloat(formatUnits(f, 9))),
194
+ yFeeMint: (
195
+ this.interface.decodeFunctionResult(
196
+ 'getCollateralMintFees',
197
+ multicallOutputs[indexMintFees * nbrCollaterals + i],
198
+ )[1] as BigNumber[]
199
+ ).map(f => Number.parseFloat(formatUnits(f, 9))),
200
+ xFeeBurn: (
201
+ this.interface.decodeFunctionResult(
202
+ 'getCollateralBurnFees',
203
+ multicallOutputs[indexBurnFees * nbrCollaterals + i],
204
+ )[0] as BigNumber[]
205
+ ).map(f => Number.parseFloat(formatUnits(f, 9))),
206
+ yFeeBurn: (
207
+ this.interface.decodeFunctionResult(
208
+ 'getCollateralBurnFees',
209
+ multicallOutputs[indexBurnFees * nbrCollaterals + i],
210
+ )[1] as BigNumber[]
211
+ ).map(f => Number.parseFloat(formatUnits(f, 9))),
212
+ } as Fees,
213
+ stablecoinsIssued: Number.parseFloat(
214
+ formatUnits(
215
+ this.interface.decodeFunctionResult(
216
+ 'getIssuedByCollateral',
217
+ multicallOutputs[indexStableIssued * nbrCollaterals + i],
218
+ )[0],
219
+ 18,
220
+ ),
221
+ ),
222
+ stablecoinCap:
223
+ this.network === Network.MAINNET
224
+ ? -1
225
+ : Number.parseFloat(
226
+ formatUnits(
227
+ this.interface.decodeFunctionResult(
228
+ 'getStablecoinCap',
229
+ multicallOutputs[indexStablecoinCap * nbrCollaterals + i],
230
+ )[0],
231
+ 18,
232
+ ),
233
+ ),
234
+ config: this._setOracleConfig(
235
+ multicallOutputs[indexOracleFees * nbrCollaterals + i],
236
+ blockNumber === undefined || blockNumber === 'latest'
237
+ ? BLOCK_UPGRADE_ORACLE + 1
238
+ : blockNumber,
239
+ ),
240
+ whitelist: {
241
+ status: this.interface.decodeFunctionResult(
242
+ 'isWhitelistedCollateral',
243
+ multicallOutputs[indexWhitelistStatus * nbrCollaterals + i],
244
+ )[0] as boolean,
245
+ data: this.interface.decodeFunctionResult(
246
+ 'getCollateralWhitelistData',
247
+ multicallOutputs[indexWhitelistData * nbrCollaterals + i],
248
+ )[0] as string,
249
+ },
250
+ }),
251
+ );
252
+ transmuterState.xRedemptionCurve = (
253
+ this.interface.decodeFunctionResult(
254
+ 'getRedemptionFees',
255
+ multicallOutputs[multicallOutputs.length - 2],
256
+ )[0] as BigNumber[]
257
+ ).map(f => Number.parseFloat(formatUnits(f, 9)));
258
+ transmuterState.yRedemptionCurve = (
259
+ this.interface.decodeFunctionResult(
260
+ 'getRedemptionFees',
261
+ multicallOutputs[multicallOutputs.length - 2],
262
+ )[1] as BigNumber[]
263
+ ).map(f => Number.parseFloat(formatUnits(f, 9)));
264
+ transmuterState.totalStablecoinIssued = Number.parseFloat(
265
+ formatUnits(
266
+ this.interface.decodeFunctionResult(
267
+ 'getTotalIssued',
268
+ multicallOutputs[multicallOutputs.length - 1],
269
+ )[0],
270
+ 18,
271
+ ),
272
+ );
273
+
274
+ return transmuterState;
275
+ }
276
+
277
+ /**
278
+ * Update Mint and Burn fees parameters
279
+ */
280
+ _handleFeesSet(
281
+ event: ethers.utils.LogDescription,
282
+ state: TransmuterState,
283
+ ): Readonly<TransmuterState> | null {
284
+ const isMint: boolean = event.args.mint;
285
+ const collateral: string = event.args.collateral;
286
+ const xFee: BigNumber[] = event.args.xFee;
287
+ const yFee: BigNumber[] = event.args.yFee;
288
+ if (isMint) {
289
+ state.collaterals[collateral].fees.xFeeMint = xFee.map(f =>
290
+ Number.parseFloat(formatUnits(f, 9)),
291
+ );
292
+ state.collaterals[collateral].fees.yFeeMint = yFee.map(f =>
293
+ Number.parseFloat(formatUnits(f, 9)),
294
+ );
295
+ } else {
296
+ state.collaterals[collateral].fees.xFeeBurn = xFee.map(f =>
297
+ Number.parseFloat(formatUnits(f, 9)),
298
+ );
299
+ state.collaterals[collateral].fees.yFeeBurn = yFee.map(f =>
300
+ Number.parseFloat(formatUnits(f, 9)),
301
+ );
302
+ }
303
+ return state;
304
+ }
305
+
306
+ /**
307
+ * Update redemption curve parameters
308
+ */
309
+ _handleRedemptionCurveSet(
310
+ event: ethers.utils.LogDescription,
311
+ state: TransmuterState,
312
+ ): Readonly<TransmuterState> | null {
313
+ const xFee: BigNumber[] = event.args.xFee;
314
+ const yFee: BigNumber[] = event.args.yFee;
315
+ state.xRedemptionCurve = xFee.map(f =>
316
+ Number.parseFloat(formatUnits(f, 9)),
317
+ );
318
+ state.yRedemptionCurve = yFee.map(f =>
319
+ Number.parseFloat(formatUnits(f, 9)),
320
+ );
321
+ return state;
322
+ }
323
+
324
+ /**
325
+ * Adapt collateral exposure after a swap event
326
+ */
327
+ _handleSwap(
328
+ event: ethers.utils.LogDescription,
329
+ state: TransmuterState,
330
+ ): Readonly<TransmuterState> | null {
331
+ const tokenIn: string = event.args.tokenIn;
332
+ const tokenOut: string = event.args.tokenOut;
333
+ // in case of a burn
334
+ if (tokenIn.toLowerCase() === this.EURA.toLowerCase()) {
335
+ const amount: number = Number.parseFloat(
336
+ formatUnits(event.args.amountIn, 18),
337
+ );
338
+ state.collaterals[tokenOut].stablecoinsIssued -= amount;
339
+ state.totalStablecoinIssued -= amount;
340
+ } else {
341
+ const amount: number = Number.parseFloat(
342
+ formatUnits(event.args.amountOut, 18),
343
+ );
344
+ state.collaterals[tokenIn].stablecoinsIssued += amount;
345
+ state.totalStablecoinIssued += amount;
346
+ }
347
+ return state;
348
+ }
349
+
350
+ /**
351
+ * Adapt collateral balances after a redeem event
352
+ */
353
+ _handleRedeem(
354
+ event: ethers.utils.LogDescription,
355
+ state: TransmuterState,
356
+ ): Readonly<TransmuterState> | null {
357
+ const amount: number = Number.parseFloat(
358
+ formatUnits(event.args.amount, 18),
359
+ );
360
+ const currentStablecoinEmission = state.totalStablecoinIssued;
361
+ for (const collat of Object.keys(state.collaterals)) {
362
+ state.collaterals[collat].stablecoinsIssued -=
363
+ (amount / currentStablecoinEmission) *
364
+ state.collaterals[collat].stablecoinsIssued;
365
+ }
366
+ state.totalStablecoinIssued -= amount;
367
+
368
+ return state;
369
+ }
370
+
371
+ _handleAddCollateral(
372
+ event: ethers.utils.LogDescription,
373
+ state: TransmuterState,
374
+ ): Readonly<TransmuterState> | null {
375
+ this.collaterals.push(event.args.collateral);
376
+ state.collaterals[event.args.collateral] = {} as CollateralState;
377
+ return state;
378
+ }
379
+
380
+ _handleRevokeCollateral(
381
+ event: ethers.utils.LogDescription,
382
+ state: TransmuterState,
383
+ ): Readonly<TransmuterState> | null {
384
+ const index = this.collaterals.indexOf(event.args.collateral);
385
+ if (index > -1) this.collaterals.splice(index, 1);
386
+ delete state.collaterals[event.args.collateral];
387
+
388
+ return state;
389
+ }
390
+
391
+ _handleAdjustStablecoins(
392
+ event: ethers.utils.LogDescription,
393
+ state: TransmuterState,
394
+ ): Readonly<TransmuterState> | null {
395
+ const collateral = event.args.collateral;
396
+ const isIncrease: boolean = event.args.increase;
397
+ const amount: number =
398
+ Number.parseFloat(formatUnits(event.args.amount, 18)) *
399
+ Number(isIncrease);
400
+ state.totalStablecoinIssued += amount;
401
+ state.collaterals[collateral].stablecoinsIssued += amount;
402
+ return state;
403
+ }
404
+
405
+ _handleSetWhitelistedStatus(
406
+ event: ethers.utils.LogDescription,
407
+ state: TransmuterState,
408
+ ): Readonly<TransmuterState> | null {
409
+ const status: number = event.args.whitelistStatus;
410
+ const collateral: string = event.args.collateral;
411
+ const data: string = event.args.whitelistData;
412
+ if (!state.collaterals[collateral])
413
+ state.collaterals[collateral] = {} as CollateralState;
414
+ if (status === 1) state.collaterals[collateral].whitelist.data = data;
415
+ state.collaterals[collateral].whitelist.status = status > 0;
416
+ return state;
417
+ }
418
+
419
+ _handleIsWhitelistedForType(
420
+ event: ethers.utils.LogDescription,
421
+ state: TransmuterState,
422
+ ): Readonly<TransmuterState> | null {
423
+ const status: number = event.args.whitelistStatus;
424
+ const who: string = event.args.who;
425
+ const whitelistType: number = event.args.whitelistType;
426
+ if (!state.isWhitelisted[whitelistType])
427
+ state.isWhitelisted[whitelistType] = new Set();
428
+ if (status === 0 && state.isWhitelisted[whitelistType].has(who))
429
+ state.isWhitelisted[whitelistType].delete(who);
430
+ else if (status !== 0 && !state.isWhitelisted[whitelistType].has(who))
431
+ state.isWhitelisted[whitelistType].add(who);
432
+ return state;
433
+ }
434
+
435
+ _handleStablecoinCapSet(
436
+ event: ethers.utils.LogDescription,
437
+ state: TransmuterState,
438
+ ): Readonly<TransmuterState> | null {
439
+ const capAmount: number = event.args.stablecoinCap;
440
+ const collateral: string = event.args.collateral;
441
+ state.collaterals[collateral].stablecoinCap = capAmount;
442
+ return state;
443
+ }
444
+
445
+ /**
446
+ * Keep track of used oracles for each collaterals
447
+ */
448
+ _handleOracleSet(
449
+ event: ethers.utils.LogDescription,
450
+ state: TransmuterState,
451
+ blockNumber: number,
452
+ ): Readonly<TransmuterState> | null {
453
+ const collateral: string = event.args.collateral;
454
+ const oracleConfig: string = event.args.oracleConfig;
455
+
456
+ state.collaterals[collateral].config = this._setOracleConfig(
457
+ oracleConfig,
458
+ blockNumber,
459
+ );
460
+ return state;
461
+ }
462
+
463
+ /**
464
+ * Keep track of used oracles for each collaterals
465
+ */
466
+ _setOracleConfig(oracleConfig: string, blockNumber: number): Oracle {
467
+ const configOracle = {} as Oracle;
468
+ const oracleConfigDecoded = TransmuterSubscriber._decodeOracleConfig(
469
+ oracleConfig,
470
+ blockNumber,
471
+ );
472
+
473
+ configOracle.oracleType = oracleConfigDecoded.oracleType;
474
+ configOracle.targetType = oracleConfigDecoded.targetType;
475
+ configOracle.hyperparameters = oracleConfigDecoded.hyperparameters;
476
+ if (oracleConfigDecoded.oracleType === OracleReadType.EXTERNAL) {
477
+ const externalOracle: Address = ethers.utils.defaultAbiCoder.decode(
478
+ [`address externalOracle`],
479
+ oracleConfigDecoded.oracleData,
480
+ )[0];
481
+ configOracle.externalOracle = externalOracle;
482
+ } else {
483
+ configOracle.oracleFeed = TransmuterSubscriber._decodeOracleFeed(
484
+ oracleConfigDecoded.oracleType,
485
+ oracleConfigDecoded.oracleData,
486
+ );
487
+ configOracle.targetFeed = TransmuterSubscriber._decodeOracleFeed(
488
+ oracleConfigDecoded.targetType,
489
+ oracleConfigDecoded.targetData,
490
+ );
491
+ }
492
+ return configOracle;
493
+ }
494
+
495
+ static _decodeOracleConfig(
496
+ oracleConfig: string,
497
+ blockNumber: number,
498
+ ): DecodedOracleConfig {
499
+ if (BLOCK_UPGRADE_ORACLE > blockNumber) {
500
+ const oracleConfigDecoded = filterDictionaryOnly(
501
+ ethers.utils.defaultAbiCoder.decode(
502
+ [
503
+ 'uint8 oracleType',
504
+ 'uint8 targetType',
505
+ 'bytes oracleData',
506
+ 'bytes targetData',
507
+ ],
508
+ oracleConfig,
509
+ ),
510
+ ) as unknown as DecodedOracleConfig;
511
+ oracleConfigDecoded.hyperparameters = '';
512
+ return oracleConfigDecoded;
513
+ }
514
+ const oracleConfigDecoded = filterDictionaryOnly(
515
+ ethers.utils.defaultAbiCoder.decode(
516
+ [
517
+ 'uint8 oracleType',
518
+ 'uint8 targetType',
519
+ 'bytes oracleData',
520
+ 'bytes targetData',
521
+ 'bytes hyperparameters',
522
+ ],
523
+ oracleConfig,
524
+ ),
525
+ ) as unknown as DecodedOracleConfig;
526
+
527
+ return oracleConfigDecoded;
528
+ }
529
+
530
+ static _decodeOracleFeed(
531
+ readType: OracleReadType,
532
+ oracleData: string,
533
+ ): OracleFeed {
534
+ if (readType === OracleReadType.CHAINLINK_FEEDS)
535
+ return {
536
+ isChainlink: true,
537
+ isPyth: false,
538
+ isMorpho: false,
539
+ chainlink: TransmuterSubscriber._decodeChainlinkOracle(oracleData),
540
+ };
541
+ if (readType === OracleReadType.PYTH)
542
+ return {
543
+ isChainlink: false,
544
+ isPyth: true,
545
+ isMorpho: false,
546
+ pyth: TransmuterSubscriber._decodePythOracle(oracleData),
547
+ };
548
+ if (readType === OracleReadType.MAX)
549
+ return {
550
+ isChainlink: false,
551
+ isPyth: false,
552
+ isMorpho: false,
553
+ maxValue: TransmuterSubscriber._decodeMaxOracle(oracleData),
554
+ };
555
+ if (readType === OracleReadType.MORPHO_ORACLE)
556
+ return {
557
+ isChainlink: false,
558
+ isPyth: false,
559
+ isMorpho: true,
560
+ morpho: TransmuterSubscriber._decodeMorphoOracle(oracleData),
561
+ };
562
+ if (readType === OracleReadType.WSTETH)
563
+ return {
564
+ isChainlink: false,
565
+ isPyth: false,
566
+ isMorpho: false,
567
+ otherContract: STETH,
568
+ };
569
+ if (readType === OracleReadType.CBETH)
570
+ return {
571
+ isChainlink: false,
572
+ isPyth: false,
573
+ isMorpho: false,
574
+ otherContract: CBETH,
575
+ };
576
+ if (readType === OracleReadType.RETH)
577
+ return {
578
+ isChainlink: false,
579
+ isPyth: false,
580
+ isMorpho: false,
581
+ otherContract: RETH,
582
+ };
583
+ if (readType === OracleReadType.SFRXETH)
584
+ return {
585
+ isChainlink: false,
586
+ isPyth: false,
587
+ isMorpho: false,
588
+ otherContract: SFRXETH,
589
+ };
590
+ return { isChainlink: false, isPyth: false, isMorpho: false };
591
+ }
592
+
593
+ static _decodeChainlinkOracle(oracleData: string): Chainlink {
594
+ const chainlinkOracleDecoded = filterDictionaryOnly(
595
+ ethers.utils.defaultAbiCoder.decode(
596
+ [
597
+ 'address[] circuitChainlink',
598
+ 'uint32[] stalePeriods',
599
+ 'uint8[] circuitChainIsMultiplied',
600
+ 'uint8[] chainlinkDecimals',
601
+ 'uint8 quoteType',
602
+ ],
603
+ oracleData,
604
+ ),
605
+ ) as unknown as Chainlink;
606
+
607
+ return chainlinkOracleDecoded;
608
+ }
609
+
610
+ static _decodePythOracle(oracleData: string): Pyth {
611
+ const pythOracleDecoded = filterDictionaryOnly(
612
+ ethers.utils.defaultAbiCoder.decode(
613
+ [
614
+ 'address pyth',
615
+ 'bytes32[] feedIds',
616
+ 'uint32[] stalePeriods',
617
+ 'uint8[] isMultiplied',
618
+ 'uint8 quoteType',
619
+ ],
620
+ oracleData,
621
+ ),
622
+ ) as unknown as Pyth;
623
+
624
+ return pythOracleDecoded;
625
+ }
626
+
627
+ static _decodeMaxOracle(oracleData: string): number {
628
+ const maxOracleDecoded = filterDictionaryOnly(
629
+ ethers.utils.defaultAbiCoder.decode(['uint256 maxValue'], oracleData),
630
+ ) as unknown as MaxOracle;
631
+
632
+ return Number.parseFloat(formatEther(maxOracleDecoded.maxValue));
633
+ }
634
+
635
+ static _decodeMorphoOracle(oracleData: string): MorphoOracle {
636
+ const morphoOracleDecoded = filterDictionaryOnly(
637
+ ethers.utils.defaultAbiCoder.decode(
638
+ ['address oracle', 'uint256 normalizationFactor'],
639
+ oracleData,
640
+ ),
641
+ ) as unknown as MorphoOracle;
642
+
643
+ return morphoOracleDecoded;
644
+ }
645
+ }