@paraswap/dex-lib 4.1.7 → 4.1.8
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/.idea/codeStyles/Project.xml +44 -4
- package/.idea/codeStyles/codeStyleConfig.xml +1 -1
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/paraswap-dex-lib.iml +7 -4
- package/build/dex/angle-staked-stable/angle-staked-stable.js +2 -1
- package/build/dex/angle-staked-stable/angle-staked-stable.js.map +1 -1
- package/build/dex/angle-transmuter/angle-transmuter.js.map +1 -1
- package/build/dex/balancer-v1/config.js +2 -1
- package/build/dex/balancer-v1/config.js.map +1 -1
- package/build/dex/jarvis.d.ts +2 -1
- package/build/dex/jarvis.js +58 -0
- package/build/dex/jarvis.js.map +1 -1
- package/build/dex/weth/weth.js +2 -1
- package/build/dex/weth/weth.js.map +1 -1
- package/build/dex/zerox/index.d.ts +3 -25
- package/build/dex/zerox/index.js +50 -42
- package/build/dex/zerox/index.js.map +1 -1
- package/build/dex/zerox/types.d.ts +29 -0
- package/build/dex/zerox/types.js +8 -1
- package/build/dex/zerox/types.js.map +1 -1
- package/package.json +1 -1
- package/scripts/get-uniswap-v3-dexes.ts +64 -0
- package/src/dex/aave-gsm/aave-gsm-gas-estimation.test.ts +32 -0
- package/src/dex/aave-v2/aave-v2-gas-estimation.test.ts +28 -0
- package/src/dex/aave-v3/aave-v3-gas-estimation.test.ts +66 -0
- package/src/dex/aave-v3-stata/aave-v3-stata-gas-estimation.test.ts +41 -0
- package/src/dex/aave-v3-stata-v2/aave-v3-stata-v2-gas-estimation.test.ts +41 -0
- package/src/dex/angle-staked-stable/angle-staked-stable-gas-estimation.test.ts +29 -0
- package/src/dex/angle-staked-stable/angle-staked-stable.ts +2 -1
- package/src/dex/angle-transmuter/angle-transmuter-gas-estimation.test.ts +41 -0
- package/src/dex/angle-transmuter/angle-transmuter.ts +0 -1
- package/src/dex/balancer-v1/balancer-v1-gas-estimation.test.ts +29 -0
- package/src/dex/balancer-v1/config.ts +2 -1
- package/src/dex/balancer-v2/balancer-v2-gas-estimation.test.ts +98 -0
- package/src/dex/balancer-v3/balancer-v3-gas-estimation.test.ts +30 -0
- package/src/dex/bancor/bancor-gas-estimation.test.ts +30 -0
- package/src/dex/bebop/bebop-gas-estimation.test.ts +30 -0
- package/src/dex/concentrator-arusd/concentrator-arusd-gas-estimation.test.ts +29 -0
- package/src/dex/curve-v1/curve-v1-gas-estimation.test.ts +29 -0
- package/src/dex/curve-v2/curve-v2-gas-estimation.test.ts +29 -0
- package/src/dex/fluid-dex/fluid-dex-gas-estimation.test.ts +29 -0
- package/src/dex/fx-protocol-rusd/fx-protocol-rusd-gas-estimation.test.ts +29 -0
- package/src/dex/hashflow/hashflow-gas-estimation.test.ts +30 -0
- package/src/dex/idle-dao/idle-dao--gas-estimation.test.ts +30 -0
- package/src/dex/lido/lido-gas-estimation.test.ts +29 -0
- package/src/dex/lite-psm/lite-psm-gas-estimation.test.ts +34 -0
- package/src/dex/maker-psm/maker-psm-gas-estimation.test.ts +34 -0
- package/src/dex/maverick-v1/maverick-v1-gas-estimation.test.ts +29 -0
- package/src/dex/maverick-v2/maverick-v2-gas-estimation.test.ts +29 -0
- package/src/dex/pancakeswap-v3/pancakeswap-v3-gas-estimation.test.ts +29 -0
- package/src/dex/polygon-migrator/polygon-migrator-gas-estimation.test.ts +41 -0
- package/src/dex/sky-converter/sky-converter-gas-estimation.test.ts +78 -0
- package/src/dex/solidly/solidly-gas-estimation.test.ts +29 -0
- package/src/dex/solidly-v3/solidly-v3-gas-estimation.test.ts +29 -0
- package/src/dex/spark/spark-gas-estimation.test.ts +29 -0
- package/src/dex/stader/stader-gas-estimation.test.ts +29 -0
- package/src/dex/stkgho/stkgho-gas-estimation.test.ts +29 -0
- package/src/dex/swaap-v2/swaap-v2-estimation.test.ts +29 -0
- package/src/dex/swell/swell-estimation.test.ts +29 -0
- package/src/dex/trader-joe-v2.1/trader-joe-v2.1-gas-estimation.test.ts +29 -0
- package/src/dex/uniswap-v2/uniswap-v2-gas-estimation.test.ts +98 -0
- package/src/dex/uniswap-v3/uniswap-v3-gas-estimation.test.ts +98 -0
- package/src/dex/usual/usual-gas-estimation.test.ts +54 -0
- package/src/dex/usual-pp/usual-pp-gas-estimation.test.ts +29 -0
- package/src/dex/weth/weth-gas-estimation.test.ts +42 -0
- package/src/dex/weth/weth.ts +3 -1
- package/src/dex/wombat/wombat-gas-estimation.test.ts +29 -0
- package/src/dex/wsteth/wsteth-gas-estimation.test.ts +41 -0
- package/src/dex/wusdm/wusdm-gas-estimation.test.ts +41 -0
- package/tests/constants-e2e.ts +8 -0
- package/tests/tenderly-simulation-new.test.ts +151 -0
- package/tests/tenderly-simulation-new.ts +698 -0
- package/tests/token-storage-slots.json +532 -0
- package/tests/utils-e2e.ts +137 -1
- package/.idea/aws.xml +0 -17
- package/.idea/misc.xml +0 -6
- package/.idea/prettier.xml +0 -7
- package/build/abi/AaveV1_lending_pool.json +0 -27
- package/build/abi/integral/factory.json +0 -333
- package/build/abi/integral/oracle.json +0 -501
- package/build/abi/integral/pool.json +0 -1041
- package/build/abi/integral/relayer.json +0 -1536
- package/build/abi/platypus/asset.json +0 -490
- package/build/abi/platypus/avax-pool.json +0 -820
- package/build/abi/platypus/oracle.json +0 -119
- package/build/abi/platypus/pool.json +0 -677
- package/build/abi/smardex/all/smardex-router.json +0 -648
- package/build/abi/smardex/layer-1/smardex-factory.json +0 -242
- package/build/abi/smardex/layer-1/smardex-pool.json +0 -506
- package/build/abi/smardex/layer-2/smardex-factory.json +0 -185
- package/build/abi/smardex/layer-2/smardex-pool.json +0 -578
- package/build/abi/swaap-v1/pool.json +0 -1346
- package/build/dex/aave-v1/aave-v1.d.ts +0 -33
- package/build/dex/aave-v1/aave-v1.js +0 -158
- package/build/dex/aave-v1/aave-v1.js.map +0 -1
- package/build/dex/aave-v1/config.d.ts +0 -11
- package/build/dex/aave-v1/config.js +0 -20
- package/build/dex/aave-v1/config.js.map +0 -1
- package/build/dex/aave-v1/tokens-mainnet.json +0 -134
- package/build/dex/aave-v1/tokens.d.ts +0 -3
- package/build/dex/aave-v1/tokens.js +0 -50
- package/build/dex/aave-v1/tokens.js.map +0 -1
- package/build/dex/aave-v1/types.d.ts +0 -12
- package/build/dex/aave-v1/types.js +0 -3
- package/build/dex/aave-v1/types.js.map +0 -1
- package/build/dex/bProtocol.d.ts +0 -18
- package/build/dex/bProtocol.js +0 -39
- package/build/dex/bProtocol.js.map +0 -1
- package/build/dex/bancor.d.ts +0 -26
- package/build/dex/bancor.js +0 -58
- package/build/dex/bancor.js.map +0 -1
- package/build/dex/compound.d.ts +0 -18
- package/build/dex/compound.js +0 -46
- package/build/dex/compound.js.map +0 -1
- package/build/dex/curve-v2.d.ts +0 -58
- package/build/dex/curve-v2.js +0 -180
- package/build/dex/curve-v2.js.map +0 -1
- package/build/dex/dodo-v1.d.ts +0 -33
- package/build/dex/dodo-v1.js +0 -63
- package/build/dex/dodo-v1.js.map +0 -1
- package/build/dex/fluid-dex/fluid-dex-generate-pool.d.ts +0 -49
- package/build/dex/fluid-dex/fluid-dex-generate-pool.js +0 -104
- package/build/dex/fluid-dex/fluid-dex-generate-pool.js.map +0 -1
- package/build/dex/integral/config.d.ts +0 -4
- package/build/dex/integral/config.js +0 -20
- package/build/dex/integral/config.js.map +0 -1
- package/build/dex/integral/context.d.ts +0 -40
- package/build/dex/integral/context.js +0 -158
- package/build/dex/integral/context.js.map +0 -1
- package/build/dex/integral/integral-factory.d.ts +0 -24
- package/build/dex/integral/integral-factory.js +0 -95
- package/build/dex/integral/integral-factory.js.map +0 -1
- package/build/dex/integral/integral-pool.d.ts +0 -50
- package/build/dex/integral/integral-pool.js +0 -149
- package/build/dex/integral/integral-pool.js.map +0 -1
- package/build/dex/integral/integral-pricing.d.ts +0 -18
- package/build/dex/integral/integral-pricing.js +0 -114
- package/build/dex/integral/integral-pricing.js.map +0 -1
- package/build/dex/integral/integral-relayer.d.ts +0 -42
- package/build/dex/integral/integral-relayer.js +0 -192
- package/build/dex/integral/integral-relayer.js.map +0 -1
- package/build/dex/integral/integral-token.d.ts +0 -27
- package/build/dex/integral/integral-token.js +0 -59
- package/build/dex/integral/integral-token.js.map +0 -1
- package/build/dex/integral/integral.d.ts +0 -41
- package/build/dex/integral/integral.js +0 -376
- package/build/dex/integral/integral.js.map +0 -1
- package/build/dex/integral/types.d.ts +0 -85
- package/build/dex/integral/types.js +0 -9
- package/build/dex/integral/types.js.map +0 -1
- package/build/dex/integral/utils-e2e.d.ts +0 -9
- package/build/dex/integral/utils-e2e.js +0 -131
- package/build/dex/integral/utils-e2e.js.map +0 -1
- package/build/dex/integral/utils.d.ts +0 -17
- package/build/dex/integral/utils.js +0 -94
- package/build/dex/integral/utils.js.map +0 -1
- package/build/dex/lido.d.ts +0 -19
- package/build/dex/lido.js +0 -42
- package/build/dex/lido.js.map +0 -1
- package/build/dex/m-token/config.d.ts +0 -3
- package/build/dex/m-token/config.js +0 -19
- package/build/dex/m-token/config.js.map +0 -1
- package/build/dex/m-token/m-token.d.ts +0 -29
- package/build/dex/m-token/m-token.js +0 -145
- package/build/dex/m-token/m-token.js.map +0 -1
- package/build/dex/m-token/m-wrapped-m.d.ts +0 -17
- package/build/dex/m-token/m-wrapped-m.js +0 -50
- package/build/dex/m-token/m-wrapped-m.js.map +0 -1
- package/build/dex/m-token/types.d.ts +0 -12
- package/build/dex/m-token/types.js +0 -3
- package/build/dex/m-token/types.js.map +0 -1
- package/build/dex/onebit.d.ts +0 -25
- package/build/dex/onebit.js +0 -42
- package/build/dex/onebit.js.map +0 -1
- package/build/dex/platypus/asset.d.ts +0 -14
- package/build/dex/platypus/asset.js +0 -97
- package/build/dex/platypus/asset.js.map +0 -1
- package/build/dex/platypus/config.d.ts +0 -11
- package/build/dex/platypus/config.js +0 -69
- package/build/dex/platypus/config.js.map +0 -1
- package/build/dex/platypus/platypus.d.ts +0 -62
- package/build/dex/platypus/platypus.js +0 -442
- package/build/dex/platypus/platypus.js.map +0 -1
- package/build/dex/platypus/pool-avax.d.ts +0 -8
- package/build/dex/platypus/pool-avax.js +0 -54
- package/build/dex/platypus/pool-avax.js.map +0 -1
- package/build/dex/platypus/pool-base.d.ts +0 -19
- package/build/dex/platypus/pool-base.js +0 -86
- package/build/dex/platypus/pool-base.js.map +0 -1
- package/build/dex/platypus/pool-pure.d.ts +0 -8
- package/build/dex/platypus/pool-pure.js +0 -37
- package/build/dex/platypus/pool-pure.js.map +0 -1
- package/build/dex/platypus/pool-subscriber.d.ts +0 -14
- package/build/dex/platypus/pool-subscriber.js +0 -167
- package/build/dex/platypus/pool-subscriber.js.map +0 -1
- package/build/dex/platypus/pool.d.ts +0 -8
- package/build/dex/platypus/pool.js +0 -58
- package/build/dex/platypus/pool.js.map +0 -1
- package/build/dex/platypus/types.d.ts +0 -92
- package/build/dex/platypus/types.js +0 -10
- package/build/dex/platypus/types.js.map +0 -1
- package/build/dex/quickswap/spiritswap-v3.d.ts +0 -6
- package/build/dex/quickswap/spiritswap-v3.js +0 -19
- package/build/dex/quickswap/spiritswap-v3.js.map +0 -1
- package/build/dex/smardex/config.d.ts +0 -4
- package/build/dex/smardex/config.js +0 -64
- package/build/dex/smardex/config.js.map +0 -1
- package/build/dex/smardex/constants.d.ts +0 -18
- package/build/dex/smardex/constants.js +0 -33
- package/build/dex/smardex/constants.js.map +0 -1
- package/build/dex/smardex/sdk/constants.d.ts +0 -6
- package/build/dex/smardex/sdk/constants.js +0 -13
- package/build/dex/smardex/sdk/constants.js.map +0 -1
- package/build/dex/smardex/sdk/core.d.ts +0 -113
- package/build/dex/smardex/sdk/core.js +0 -499
- package/build/dex/smardex/sdk/core.js.map +0 -1
- package/build/dex/smardex/sdk/errors.d.ts +0 -15
- package/build/dex/smardex/sdk/errors.js +0 -22
- package/build/dex/smardex/sdk/errors.js.map +0 -1
- package/build/dex/smardex/sdk/types.d.ts +0 -62
- package/build/dex/smardex/sdk/types.js +0 -3
- package/build/dex/smardex/sdk/types.js.map +0 -1
- package/build/dex/smardex/sdk/utils.d.ts +0 -44
- package/build/dex/smardex/sdk/utils.js +0 -133
- package/build/dex/smardex/sdk/utils.js.map +0 -1
- package/build/dex/smardex/smardex-event-pool.d.ts +0 -28
- package/build/dex/smardex/smardex-event-pool.js +0 -119
- package/build/dex/smardex/smardex-event-pool.js.map +0 -1
- package/build/dex/smardex/smardex.d.ts +0 -65
- package/build/dex/smardex/smardex.js +0 -519
- package/build/dex/smardex/smardex.js.map +0 -1
- package/build/dex/smardex/types.d.ts +0 -55
- package/build/dex/smardex/types.js +0 -3
- package/build/dex/smardex/types.js.map +0 -1
- package/build/dex/smoothy.d.ts +0 -26
- package/build/dex/smoothy.js +0 -48
- package/build/dex/smoothy.js.map +0 -1
- package/build/dex/solidly/forks-override/cone.d.ts +0 -22
- package/build/dex/solidly/forks-override/cone.js +0 -53
- package/build/dex/solidly/forks-override/cone.js.map +0 -1
- package/build/dex/solidly/forks-override/solisnek.d.ts +0 -8
- package/build/dex/solidly/forks-override/solisnek.js +0 -15
- package/build/dex/solidly/forks-override/solisnek.js.map +0 -1
- package/build/dex/stable-pool.d.ts +0 -28
- package/build/dex/stable-pool.js +0 -62
- package/build/dex/stable-pool.js.map +0 -1
- package/build/dex/swaap-v1/config.d.ts +0 -17
- package/build/dex/swaap-v1/config.js +0 -56
- package/build/dex/swaap-v1/config.js.map +0 -1
- package/build/dex/swaap-v1/constants.d.ts +0 -6
- package/build/dex/swaap-v1/constants.js +0 -17
- package/build/dex/swaap-v1/constants.js.map +0 -1
- package/build/dex/swaap-v1/libraries/ChainlinkUtils.d.ts +0 -25
- package/build/dex/swaap-v1/libraries/ChainlinkUtils.js +0 -62
- package/build/dex/swaap-v1/libraries/ChainlinkUtils.js.map +0 -1
- package/build/dex/swaap-v1/libraries/Const.d.ts +0 -18
- package/build/dex/swaap-v1/libraries/Const.js +0 -26
- package/build/dex/swaap-v1/libraries/Const.js.map +0 -1
- package/build/dex/swaap-v1/libraries/GeometricBrownianMotion.d.ts +0 -77
- package/build/dex/swaap-v1/libraries/GeometricBrownianMotion.js +0 -316
- package/build/dex/swaap-v1/libraries/GeometricBrownianMotion.js.map +0 -1
- package/build/dex/swaap-v1/libraries/LogExpMath.d.ts +0 -75
- package/build/dex/swaap-v1/libraries/LogExpMath.js +0 -418
- package/build/dex/swaap-v1/libraries/LogExpMath.js.map +0 -1
- package/build/dex/swaap-v1/libraries/MathMMM.d.ts +0 -185
- package/build/dex/swaap-v1/libraries/MathMMM.js +0 -453
- package/build/dex/swaap-v1/libraries/MathMMM.js.map +0 -1
- package/build/dex/swaap-v1/libraries/Num.d.ts +0 -31
- package/build/dex/swaap-v1/libraries/Num.js +0 -167
- package/build/dex/swaap-v1/libraries/Num.js.map +0 -1
- package/build/dex/swaap-v1/libraries/PoolQuotations.d.ts +0 -23
- package/build/dex/swaap-v1/libraries/PoolQuotations.js +0 -131
- package/build/dex/swaap-v1/libraries/PoolQuotations.js.map +0 -1
- package/build/dex/swaap-v1/libraries/Struct.d.ts +0 -56
- package/build/dex/swaap-v1/libraries/Struct.js +0 -3
- package/build/dex/swaap-v1/libraries/Struct.js.map +0 -1
- package/build/dex/swaap-v1/swaap-v1-pool.d.ts +0 -45
- package/build/dex/swaap-v1/swaap-v1-pool.js +0 -656
- package/build/dex/swaap-v1/swaap-v1-pool.js.map +0 -1
- package/build/dex/swaap-v1/swaap-v1.d.ts +0 -61
- package/build/dex/swaap-v1/swaap-v1.js +0 -369
- package/build/dex/swaap-v1/swaap-v1.js.map +0 -1
- package/build/dex/swaap-v1/types.d.ts +0 -106
- package/build/dex/swaap-v1/types.js +0 -9
- package/build/dex/swaap-v1/types.js.map +0 -1
- package/build/dex/trader-joe-v2.1/optimizer.d.ts +0 -2
- package/build/dex/trader-joe-v2.1/optimizer.js +0 -47
- package/build/dex/trader-joe-v2.1/optimizer.js.map +0 -1
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1-new.d.ts +0 -7
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1-new.js +0 -20
- package/build/dex/trader-joe-v2.1/trader-joe-v2.1-new.js.map +0 -1
- package/build/dex/trader-joe-v2.1.d.ts +0 -43
- package/build/dex/trader-joe-v2.1.js +0 -79
- package/build/dex/trader-joe-v2.1.js.map +0 -1
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import 'dotenv/config';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import { ethers } from 'ethers';
|
|
5
|
+
import * as fs from 'fs/promises';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { ETHER_ADDRESS } from '../src/constants';
|
|
8
|
+
|
|
9
|
+
const TENDERLY_TOKEN = process.env.TENDERLY_TOKEN!;
|
|
10
|
+
const TENDERLY_ACCOUNT_ID = process.env.TENDERLY_ACCOUNT_ID!;
|
|
11
|
+
const TENDERLY_PROJECT = process.env.TENDERLY_PROJECT!;
|
|
12
|
+
|
|
13
|
+
interface StateObject {
|
|
14
|
+
// Overrides of storage slots.
|
|
15
|
+
// In this mapping, the key is variable storage slot,
|
|
16
|
+
// and the value contains the override.
|
|
17
|
+
storage?: Record<string, string>; // storage slot -> value
|
|
18
|
+
balance?: string;
|
|
19
|
+
nonce?: number;
|
|
20
|
+
// Bytecode that will override the code associated to the given account.
|
|
21
|
+
code?: string;
|
|
22
|
+
}
|
|
23
|
+
export type StateOverride = Record<string, StateObject>; // contract -> storage override
|
|
24
|
+
|
|
25
|
+
interface TokenStorageSlots {
|
|
26
|
+
balanceSlot: string;
|
|
27
|
+
allowanceSlot: string;
|
|
28
|
+
isVyper?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface SimulateTransactionRequest {
|
|
32
|
+
from: string | null;
|
|
33
|
+
to: string | null;
|
|
34
|
+
value?: string;
|
|
35
|
+
data: string;
|
|
36
|
+
chainId: number;
|
|
37
|
+
timestamp?: number;
|
|
38
|
+
blockNumber?: number;
|
|
39
|
+
stateOverride?: StateOverride;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// not fully complete
|
|
43
|
+
interface SimulatedTransactionCall {
|
|
44
|
+
hash: string;
|
|
45
|
+
contract_name: string;
|
|
46
|
+
function_name: string;
|
|
47
|
+
function_pc: number;
|
|
48
|
+
function_op: string;
|
|
49
|
+
function_file_index: number;
|
|
50
|
+
function_code_start: number;
|
|
51
|
+
function_line_number: number;
|
|
52
|
+
function_code_length: number;
|
|
53
|
+
absolute_position: number;
|
|
54
|
+
caller_pc: number;
|
|
55
|
+
caller_op: string;
|
|
56
|
+
call_type: string;
|
|
57
|
+
address: string;
|
|
58
|
+
from: string;
|
|
59
|
+
from_balance: string;
|
|
60
|
+
to: string;
|
|
61
|
+
to_balance: string;
|
|
62
|
+
value: string | null;
|
|
63
|
+
caller: {
|
|
64
|
+
address: string;
|
|
65
|
+
balance: string;
|
|
66
|
+
};
|
|
67
|
+
block_timestamp: string;
|
|
68
|
+
gas: number;
|
|
69
|
+
gas_used: number;
|
|
70
|
+
intrinsic_gas: number;
|
|
71
|
+
storage_address: string;
|
|
72
|
+
input: string;
|
|
73
|
+
storage_slot: string[] | undefined;
|
|
74
|
+
calls: SimulatedTransactionCall[] | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// not fully complete
|
|
78
|
+
interface Simulation {
|
|
79
|
+
id: string;
|
|
80
|
+
project_id: string;
|
|
81
|
+
owner_id: string;
|
|
82
|
+
network_id: string;
|
|
83
|
+
block_number: number;
|
|
84
|
+
transaction_index: number;
|
|
85
|
+
from: string;
|
|
86
|
+
to: string;
|
|
87
|
+
input: string;
|
|
88
|
+
gas: number;
|
|
89
|
+
gas_price: string;
|
|
90
|
+
gas_used: number;
|
|
91
|
+
value: string;
|
|
92
|
+
method: string;
|
|
93
|
+
status: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// not complete, all details include a lot more info
|
|
97
|
+
interface SimulatedTransactionDetails {
|
|
98
|
+
transaction: {
|
|
99
|
+
hash: string;
|
|
100
|
+
block_hash: string;
|
|
101
|
+
block_number: number;
|
|
102
|
+
from: string;
|
|
103
|
+
gas: number;
|
|
104
|
+
gas_price: number;
|
|
105
|
+
gas_fee_cap: number;
|
|
106
|
+
gas_tip_cap: number;
|
|
107
|
+
cumulative_gas_used: number;
|
|
108
|
+
gas_used: number;
|
|
109
|
+
effective_gas_price: number;
|
|
110
|
+
input: string;
|
|
111
|
+
nonce: number;
|
|
112
|
+
to: string;
|
|
113
|
+
index: number;
|
|
114
|
+
value: string;
|
|
115
|
+
access_list: null;
|
|
116
|
+
status: boolean;
|
|
117
|
+
transaction_info: {
|
|
118
|
+
call_trace: SimulatedTransactionCall;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
class TokenStorageSlotsCache {
|
|
124
|
+
private static TOKEN_STORAGE_SLOTS: Record<
|
|
125
|
+
number,
|
|
126
|
+
Record<string, TokenStorageSlots>
|
|
127
|
+
> | null = null;
|
|
128
|
+
private static readonly TOKEN_STORAGE_SLOTS_FILEPATH = path.join(
|
|
129
|
+
__dirname,
|
|
130
|
+
'token-storage-slots.json',
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
private static async loadTokenStorageSlots(): Promise<
|
|
134
|
+
Record<number, Record<string, TokenStorageSlots>>
|
|
135
|
+
> {
|
|
136
|
+
return JSON.parse(
|
|
137
|
+
await fs.readFile(TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS_FILEPATH, {
|
|
138
|
+
encoding: 'utf-8',
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private static async saveTokenStorageSlots(): Promise<void> {
|
|
144
|
+
await fs.writeFile(
|
|
145
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS_FILEPATH,
|
|
146
|
+
JSON.stringify(TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS, null, 2),
|
|
147
|
+
{ encoding: 'utf-8' },
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
static async getTokenStorageSlots(
|
|
152
|
+
chainId: number,
|
|
153
|
+
token: string,
|
|
154
|
+
): Promise<TokenStorageSlots | null> {
|
|
155
|
+
if (!TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS) {
|
|
156
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS =
|
|
157
|
+
await TokenStorageSlotsCache.loadTokenStorageSlots();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS[chainId]?.[
|
|
162
|
+
token.toLowerCase()
|
|
163
|
+
] ?? null
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
static async setTokenStorageSlots(
|
|
168
|
+
chainId: number,
|
|
169
|
+
token: string,
|
|
170
|
+
slots: TokenStorageSlots,
|
|
171
|
+
): Promise<void> {
|
|
172
|
+
if (!TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS) {
|
|
173
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS =
|
|
174
|
+
await TokenStorageSlotsCache.loadTokenStorageSlots();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS ||= {};
|
|
178
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS[chainId] ||= {};
|
|
179
|
+
TokenStorageSlotsCache.TOKEN_STORAGE_SLOTS[chainId][token.toLowerCase()] =
|
|
180
|
+
slots;
|
|
181
|
+
|
|
182
|
+
void TokenStorageSlotsCache.saveTokenStorageSlots();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export class TenderlySimulatorNew {
|
|
187
|
+
// public constants
|
|
188
|
+
static readonly DEFAULT_OWNER = '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
|
|
189
|
+
static readonly DEFAULT_SPENDER =
|
|
190
|
+
'0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb';
|
|
191
|
+
|
|
192
|
+
// singleton
|
|
193
|
+
private static instance: TenderlySimulatorNew;
|
|
194
|
+
|
|
195
|
+
private constructor() {}
|
|
196
|
+
|
|
197
|
+
public static getInstance(): TenderlySimulatorNew {
|
|
198
|
+
if (!TenderlySimulatorNew.instance) {
|
|
199
|
+
TenderlySimulatorNew.instance = new TenderlySimulatorNew();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return TenderlySimulatorNew.instance;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public async simulateTransaction(
|
|
206
|
+
request: SimulateTransactionRequest,
|
|
207
|
+
): Promise<Simulation> {
|
|
208
|
+
const data = {
|
|
209
|
+
network_id: request.chainId,
|
|
210
|
+
from: request.from,
|
|
211
|
+
to: request.to,
|
|
212
|
+
input: request.data,
|
|
213
|
+
value: request.value,
|
|
214
|
+
save: true,
|
|
215
|
+
save_if_fails: true,
|
|
216
|
+
state_objects: request.stateOverride,
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
console.log('Sending transaction simulation with params:');
|
|
220
|
+
console.log(JSON.stringify(data, null, 2));
|
|
221
|
+
|
|
222
|
+
const response = await axios.request({
|
|
223
|
+
method: 'POST',
|
|
224
|
+
url: `https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_ID}/project/${TENDERLY_PROJECT}/simulate`,
|
|
225
|
+
headers: {
|
|
226
|
+
'X-Access-Key': TENDERLY_TOKEN,
|
|
227
|
+
},
|
|
228
|
+
data,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const simulation = response.data.simulation as Simulation;
|
|
232
|
+
const url = `https://dashboard.tenderly.co/${TENDERLY_ACCOUNT_ID}/${TENDERLY_PROJECT}/simulator/${simulation.id}`;
|
|
233
|
+
|
|
234
|
+
console.log('Successfully simulated a transaction:');
|
|
235
|
+
console.log(`Simulation URL - ${url}`);
|
|
236
|
+
|
|
237
|
+
return simulation;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public async getSimulatedTransactionDetails(
|
|
241
|
+
id: string,
|
|
242
|
+
): Promise<SimulatedTransactionDetails | null> {
|
|
243
|
+
try {
|
|
244
|
+
const { data } = await axios.post(
|
|
245
|
+
`https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_ID}/project/${TENDERLY_PROJECT}/simulations/${id}`,
|
|
246
|
+
{},
|
|
247
|
+
{ headers: { 'X-Access-Key': TENDERLY_TOKEN } },
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
return data;
|
|
251
|
+
} catch (e) {
|
|
252
|
+
console.error(e);
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
getSLOADCalls = (
|
|
258
|
+
callTrace: SimulatedTransactionCall,
|
|
259
|
+
): SimulatedTransactionCall[] => {
|
|
260
|
+
const results: SimulatedTransactionCall[] = [];
|
|
261
|
+
|
|
262
|
+
if (callTrace.call_type === 'SLOAD') {
|
|
263
|
+
results.push(callTrace);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (callTrace.calls) {
|
|
267
|
+
for (const call of callTrace.calls) {
|
|
268
|
+
results.push(...this.getSLOADCalls(call));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return results;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
*
|
|
277
|
+
* @param balanceOfSlot storage slot of `balanceOf` mapping
|
|
278
|
+
* @param owner account's address
|
|
279
|
+
* @param isVyper `true` if contract is written in Vyper
|
|
280
|
+
*/
|
|
281
|
+
calculateAddressBalanceSlot(
|
|
282
|
+
balanceOfSlot: string,
|
|
283
|
+
owner: string,
|
|
284
|
+
isVyper = false,
|
|
285
|
+
) {
|
|
286
|
+
return isVyper
|
|
287
|
+
? this.calculateVyperAddressBalanceSlot(balanceOfSlot, owner)
|
|
288
|
+
: this.calculateSolidityAddressBalanceSlot(balanceOfSlot, owner);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
*
|
|
293
|
+
* @param balanceOfSlot storage slot of `balanceOf` mapping
|
|
294
|
+
* @param owner account's address
|
|
295
|
+
*/
|
|
296
|
+
calculateSolidityAddressBalanceSlot(balanceOfSlot: string, owner: string) {
|
|
297
|
+
return ethers.utils.keccak256(
|
|
298
|
+
ethers.utils.concat([ethers.utils.hexZeroPad(owner, 32), balanceOfSlot]),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
*
|
|
304
|
+
* @param balanceOfSlot storage slot of `balanceOf` mapping
|
|
305
|
+
* @param owner account's address
|
|
306
|
+
*/
|
|
307
|
+
calculateVyperAddressBalanceSlot(balanceOfSlot: string, owner: string) {
|
|
308
|
+
return ethers.utils.keccak256(
|
|
309
|
+
ethers.utils.concat([balanceOfSlot, ethers.utils.hexZeroPad(owner, 32)]),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
*
|
|
315
|
+
* @param allowanceSlot storage slot of `allowance` mapping
|
|
316
|
+
* @param owner account's address
|
|
317
|
+
* @param spender spender's address
|
|
318
|
+
* @param isVyper `true` if contract is written in Vyper
|
|
319
|
+
*/
|
|
320
|
+
calculateAddressAllowanceSlot(
|
|
321
|
+
allowanceSlot: string,
|
|
322
|
+
owner: string,
|
|
323
|
+
spender: string,
|
|
324
|
+
isVyper = false,
|
|
325
|
+
) {
|
|
326
|
+
return isVyper
|
|
327
|
+
? this.calculateVyperAddressAllowanceSlot(allowanceSlot, owner, spender)
|
|
328
|
+
: this.calculateSolidityAddressAllowanceSlot(
|
|
329
|
+
allowanceSlot,
|
|
330
|
+
owner,
|
|
331
|
+
spender,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
*
|
|
337
|
+
* @param allowanceSlot storage slot of `allowance` mapping
|
|
338
|
+
* @param owner account's address
|
|
339
|
+
* @param spender spender's address
|
|
340
|
+
*/
|
|
341
|
+
calculateSolidityAddressAllowanceSlot(
|
|
342
|
+
allowanceSlot: string,
|
|
343
|
+
owner: string,
|
|
344
|
+
spender: string,
|
|
345
|
+
) {
|
|
346
|
+
const slotHash = ethers.utils.keccak256(
|
|
347
|
+
ethers.utils.concat([
|
|
348
|
+
ethers.utils.hexZeroPad(owner, 32),
|
|
349
|
+
ethers.utils.hexZeroPad(allowanceSlot, 32),
|
|
350
|
+
]),
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
return ethers.utils.keccak256(
|
|
354
|
+
ethers.utils.concat([ethers.utils.hexZeroPad(spender, 32), slotHash]),
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
*
|
|
360
|
+
* @param allowanceSlot storage slot of `allowance` mapping
|
|
361
|
+
* @param owner account's address
|
|
362
|
+
* @param spender spender's address
|
|
363
|
+
*/
|
|
364
|
+
calculateVyperAddressAllowanceSlot(
|
|
365
|
+
allowanceSlot: string,
|
|
366
|
+
owner: string,
|
|
367
|
+
spender: string,
|
|
368
|
+
) {
|
|
369
|
+
const slotHash = ethers.utils.keccak256(
|
|
370
|
+
ethers.utils.concat([
|
|
371
|
+
ethers.utils.hexZeroPad(allowanceSlot, 32),
|
|
372
|
+
ethers.utils.hexZeroPad(owner, 32),
|
|
373
|
+
]),
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
return ethers.utils.keccak256(
|
|
377
|
+
ethers.utils.concat([slotHash, ethers.utils.hexZeroPad(spender, 32)]),
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
buildBalanceOfSimulationRequest(
|
|
382
|
+
chainId: number,
|
|
383
|
+
token: string,
|
|
384
|
+
owner: string,
|
|
385
|
+
): SimulateTransactionRequest {
|
|
386
|
+
const iface = new ethers.utils.Interface([
|
|
387
|
+
'function balanceOf(address owner) view returns (uint)',
|
|
388
|
+
]);
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
from: ethers.constants.AddressZero,
|
|
392
|
+
to: token,
|
|
393
|
+
data: iface.encodeFunctionData('balanceOf', [owner]),
|
|
394
|
+
chainId,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
buildAllowanceSimulationRequest(
|
|
399
|
+
chainId: number,
|
|
400
|
+
token: string,
|
|
401
|
+
owner: string,
|
|
402
|
+
spender: string,
|
|
403
|
+
): SimulateTransactionRequest {
|
|
404
|
+
const iface = new ethers.utils.Interface([
|
|
405
|
+
'function allowance(address owner, address spender) view returns (uint)',
|
|
406
|
+
]);
|
|
407
|
+
|
|
408
|
+
return {
|
|
409
|
+
from: ethers.constants.AddressZero,
|
|
410
|
+
to: token,
|
|
411
|
+
data: iface.encodeFunctionData('allowance', [owner, spender]),
|
|
412
|
+
chainId,
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Finds the slot of the `balanceOf` mapping in given token contract's storage.
|
|
418
|
+
* Supports `Solidity` and `Vyper` contracts
|
|
419
|
+
* @param chainId token chain id
|
|
420
|
+
* @param token token address
|
|
421
|
+
*/
|
|
422
|
+
async findTokenBalanceOfSlot(
|
|
423
|
+
chainId: number,
|
|
424
|
+
token: string,
|
|
425
|
+
): Promise<{ slot: string; isVyper?: boolean }> {
|
|
426
|
+
const account = TenderlySimulatorNew.DEFAULT_OWNER;
|
|
427
|
+
|
|
428
|
+
const balanceOfSimulationRequest = this.buildBalanceOfSimulationRequest(
|
|
429
|
+
chainId,
|
|
430
|
+
token,
|
|
431
|
+
account,
|
|
432
|
+
);
|
|
433
|
+
|
|
434
|
+
const { id: simulationId } = await this.simulateTransaction(
|
|
435
|
+
balanceOfSimulationRequest,
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const simulationDetails = await this.getSimulatedTransactionDetails(
|
|
439
|
+
simulationId,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
if (!simulationDetails) {
|
|
443
|
+
throw `No simulation with id ${simulationId} details found`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const callTrace = simulationDetails.transaction.transaction_info.call_trace;
|
|
447
|
+
|
|
448
|
+
const sloadCalls = this.getSLOADCalls(callTrace);
|
|
449
|
+
// token's storage slots that were read during the `balanceOf` call
|
|
450
|
+
const readSlots = sloadCalls
|
|
451
|
+
.map(call => call.storage_slot?.[0])
|
|
452
|
+
.filter<string>((slot): slot is string => !!slot);
|
|
453
|
+
|
|
454
|
+
const startingPoints = [
|
|
455
|
+
// regular contract
|
|
456
|
+
0n,
|
|
457
|
+
// ERC20Upgradeable
|
|
458
|
+
BigInt(
|
|
459
|
+
'0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00',
|
|
460
|
+
),
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
for (const startingPoint of startingPoints) {
|
|
464
|
+
for (let i = startingPoint; i < startingPoint + 1_000n; i += 1n) {
|
|
465
|
+
const candidateSlot = ethers.utils.defaultAbiCoder.encode(
|
|
466
|
+
['uint'],
|
|
467
|
+
[i],
|
|
468
|
+
);
|
|
469
|
+
// try solidity slot
|
|
470
|
+
const solitidyBalanceOfSlot = this.calculateSolidityAddressBalanceSlot(
|
|
471
|
+
candidateSlot,
|
|
472
|
+
account,
|
|
473
|
+
);
|
|
474
|
+
if (readSlots.includes(solitidyBalanceOfSlot)) {
|
|
475
|
+
return { slot: candidateSlot };
|
|
476
|
+
}
|
|
477
|
+
// try vyper slot
|
|
478
|
+
const vyperBalanceOfSlot = this.calculateVyperAddressBalanceSlot(
|
|
479
|
+
candidateSlot,
|
|
480
|
+
account,
|
|
481
|
+
);
|
|
482
|
+
if (readSlots.includes(vyperBalanceOfSlot)) {
|
|
483
|
+
return { slot: candidateSlot, isVyper: true };
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
throw new Error(
|
|
489
|
+
`Could not find a 'balanceOf' mapping slot for token ${token} on chain ${chainId}`,
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Finds the slot of the `allowance` mapping in given token contract's storage
|
|
495
|
+
* Supports `Solidity` and `Vyper` contracts
|
|
496
|
+
* @param chainId token chain id
|
|
497
|
+
* @param token token address
|
|
498
|
+
*/
|
|
499
|
+
async findTokenAllowanceSlot(
|
|
500
|
+
chainId: number,
|
|
501
|
+
token: string,
|
|
502
|
+
): Promise<{ slot: string; isVyper?: boolean }> {
|
|
503
|
+
const account = TenderlySimulatorNew.DEFAULT_OWNER;
|
|
504
|
+
const spender = TenderlySimulatorNew.DEFAULT_SPENDER;
|
|
505
|
+
|
|
506
|
+
const allowanceSimulationRequest = this.buildAllowanceSimulationRequest(
|
|
507
|
+
chainId,
|
|
508
|
+
token,
|
|
509
|
+
account,
|
|
510
|
+
spender,
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
const { id: simulationId } = await this.simulateTransaction(
|
|
514
|
+
allowanceSimulationRequest,
|
|
515
|
+
);
|
|
516
|
+
|
|
517
|
+
const simulationDetails = await this.getSimulatedTransactionDetails(
|
|
518
|
+
simulationId,
|
|
519
|
+
);
|
|
520
|
+
|
|
521
|
+
if (!simulationDetails) {
|
|
522
|
+
throw `No simulation with id ${simulationId} details found`;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const callTrace = simulationDetails.transaction.transaction_info.call_trace;
|
|
526
|
+
|
|
527
|
+
const sloadCalls = this.getSLOADCalls(callTrace);
|
|
528
|
+
// token's storage slots that were read during the `allowance` call
|
|
529
|
+
const readSlots = sloadCalls
|
|
530
|
+
.map(call => call.storage_slot?.[0])
|
|
531
|
+
.filter<string>((slot): slot is string => !!slot);
|
|
532
|
+
|
|
533
|
+
const startingPoints = [
|
|
534
|
+
// regular contract
|
|
535
|
+
0n,
|
|
536
|
+
// ERC20Upgradeable
|
|
537
|
+
BigInt(
|
|
538
|
+
'0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00',
|
|
539
|
+
),
|
|
540
|
+
];
|
|
541
|
+
|
|
542
|
+
for (const init of startingPoints) {
|
|
543
|
+
for (let i = init; i < init + 1000n; i += 1n) {
|
|
544
|
+
const candidateSlot = ethers.utils.defaultAbiCoder.encode(
|
|
545
|
+
['uint'],
|
|
546
|
+
[i],
|
|
547
|
+
);
|
|
548
|
+
// try solidity
|
|
549
|
+
const solidityAllowanceSlot =
|
|
550
|
+
this.calculateSolidityAddressAllowanceSlot(
|
|
551
|
+
candidateSlot,
|
|
552
|
+
account,
|
|
553
|
+
spender,
|
|
554
|
+
);
|
|
555
|
+
if (readSlots.includes(solidityAllowanceSlot)) {
|
|
556
|
+
return { slot: candidateSlot };
|
|
557
|
+
}
|
|
558
|
+
// try vyper
|
|
559
|
+
const vyperAllowanceSlot = this.calculateVyperAddressAllowanceSlot(
|
|
560
|
+
candidateSlot,
|
|
561
|
+
account,
|
|
562
|
+
spender,
|
|
563
|
+
);
|
|
564
|
+
if (readSlots.includes(vyperAllowanceSlot)) {
|
|
565
|
+
return { slot: candidateSlot, isVyper: true };
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
throw new Error(
|
|
571
|
+
`Could not find a 'allowance' mapping slot for token ${token} on chain ${chainId}`,
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Returns storage slots for the given token contract.
|
|
577
|
+
* @param chainId Token chain ID
|
|
578
|
+
* @param token Token address. Doesn't have to be normalized
|
|
579
|
+
*/
|
|
580
|
+
async getTokenStorageSlots(
|
|
581
|
+
chainId: number,
|
|
582
|
+
token: string,
|
|
583
|
+
): Promise<TokenStorageSlots> {
|
|
584
|
+
const normalizedToken = token.toLowerCase();
|
|
585
|
+
|
|
586
|
+
if (normalizedToken === ETHER_ADDRESS) {
|
|
587
|
+
throw new Error('Cannot provide storage slots for native token');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// check cache
|
|
591
|
+
const cachedSlots = await TokenStorageSlotsCache.getTokenStorageSlots(
|
|
592
|
+
chainId,
|
|
593
|
+
normalizedToken,
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
// return if cached
|
|
597
|
+
if (cachedSlots) {
|
|
598
|
+
return cachedSlots;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
// find the slots
|
|
602
|
+
const [balanceSlot, allowanceSlot] = await Promise.all([
|
|
603
|
+
this.findTokenBalanceOfSlot(chainId, token),
|
|
604
|
+
this.findTokenAllowanceSlot(chainId, token),
|
|
605
|
+
]);
|
|
606
|
+
|
|
607
|
+
// save the slots and return
|
|
608
|
+
const slots: TokenStorageSlots = {
|
|
609
|
+
balanceSlot: balanceSlot.slot,
|
|
610
|
+
allowanceSlot: allowanceSlot.slot,
|
|
611
|
+
isVyper: balanceSlot.isVyper,
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// no need to await
|
|
615
|
+
void TokenStorageSlotsCache.setTokenStorageSlots(chainId, token, slots);
|
|
616
|
+
|
|
617
|
+
return slots;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Adds native balance override to an existing `StateOverride` object
|
|
622
|
+
* @param stateOverride object to add the override to
|
|
623
|
+
* @param account address to be given the balance
|
|
624
|
+
* @param amount token amount in wei
|
|
625
|
+
*/
|
|
626
|
+
addBalanceOverride(
|
|
627
|
+
stateOverride: StateOverride,
|
|
628
|
+
account: string,
|
|
629
|
+
amount: bigint,
|
|
630
|
+
): void {
|
|
631
|
+
// add the balance override
|
|
632
|
+
stateOverride[account] ||= {};
|
|
633
|
+
stateOverride[account].balance = amount.toString();
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Adds token balance override to an existing `StateOverride` object
|
|
638
|
+
* @param stateOverride object to add the override to
|
|
639
|
+
* @param chainId token chain ID
|
|
640
|
+
* @param token token address
|
|
641
|
+
* @param account address to be given the balance
|
|
642
|
+
* @param amount token amount in wei
|
|
643
|
+
*/
|
|
644
|
+
async addTokenBalanceOverride(
|
|
645
|
+
stateOverride: StateOverride,
|
|
646
|
+
chainId: number,
|
|
647
|
+
token: string,
|
|
648
|
+
account: string,
|
|
649
|
+
amount: bigint,
|
|
650
|
+
): Promise<void> {
|
|
651
|
+
// get mapping slots
|
|
652
|
+
const tokenSlots = await this.getTokenStorageSlots(chainId, token);
|
|
653
|
+
// calculate balance slot
|
|
654
|
+
const slotToOverride = this.calculateAddressBalanceSlot(
|
|
655
|
+
tokenSlots.balanceSlot,
|
|
656
|
+
account,
|
|
657
|
+
tokenSlots.isVyper,
|
|
658
|
+
);
|
|
659
|
+
// add the balance override
|
|
660
|
+
stateOverride[token] ||= {};
|
|
661
|
+
stateOverride[token].storage ||= {};
|
|
662
|
+
stateOverride[token].storage[slotToOverride] =
|
|
663
|
+
ethers.utils.defaultAbiCoder.encode(['uint'], [amount]);
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Adds token allowance override to an existing `StateOverride` object
|
|
668
|
+
* @param stateOverride object to add the override to
|
|
669
|
+
* @param chainId token chain ID
|
|
670
|
+
* @param token token address
|
|
671
|
+
* @param account owner address
|
|
672
|
+
* @param spender spender address
|
|
673
|
+
* @param amount token amount in wei
|
|
674
|
+
*/
|
|
675
|
+
async addAllowanceOverride(
|
|
676
|
+
stateOverride: StateOverride,
|
|
677
|
+
chainId: number,
|
|
678
|
+
token: string,
|
|
679
|
+
account: string,
|
|
680
|
+
spender: string,
|
|
681
|
+
amount: bigint,
|
|
682
|
+
): Promise<void> {
|
|
683
|
+
// get mapping slots
|
|
684
|
+
const tokenSlots = await this.getTokenStorageSlots(chainId, token);
|
|
685
|
+
// calculate allowance slot
|
|
686
|
+
const slotToOverride = this.calculateAddressAllowanceSlot(
|
|
687
|
+
tokenSlots.allowanceSlot,
|
|
688
|
+
account,
|
|
689
|
+
spender,
|
|
690
|
+
tokenSlots.isVyper,
|
|
691
|
+
);
|
|
692
|
+
// add the allowance override
|
|
693
|
+
stateOverride[token] ||= {};
|
|
694
|
+
stateOverride[token].storage ||= {};
|
|
695
|
+
stateOverride[token].storage[slotToOverride] =
|
|
696
|
+
ethers.utils.defaultAbiCoder.encode(['uint'], [amount]);
|
|
697
|
+
}
|
|
698
|
+
}
|