@gearbox-protocol/sdk 3.0.0-vfourabi.1 → 3.0.0-vfourabi.3
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/.eslintignore +3 -0
- package/.github/workflows/lint_pr.yml +18 -0
- package/.github/workflows/pr.yml +39 -0
- package/.github/workflows/release.yml +47 -0
- package/.gitignore +19 -0
- package/.husky/commit-msg +1 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.releaserc.json +34 -0
- package/.vscode/extensions.json +7 -0
- package/.vscode/settings.json +16 -0
- package/.yarn/install-state.gz +0 -0
- package/.yarnrc.yml +1 -0
- package/ContributionAgreement +72 -0
- package/dist/cjs/abi/iZapper.cjs +85 -0
- package/dist/cjs/abi/iZapper.d.ts +123 -0
- package/dist/cjs/sdk/index.cjs +19830 -19764
- package/dist/cjs/sdk/index.d.ts +3746 -3061
- package/dist/esm/abi/iZapper.d.mts +123 -0
- package/dist/esm/abi/iZapper.mjs +83 -0
- package/dist/esm/sdk/index.d.mts +3746 -3061
- package/dist/esm/sdk/index.mjs +19807 -19765
- package/jest.config.js +7 -0
- package/package.json +32 -2
- package/scripts/example.ts +30 -0
- package/src/abi/compressors.ts +3962 -0
- package/src/abi/errors.ts +196 -0
- package/src/abi/iERC20.ts +122 -0
- package/src/abi/iPausable.ts +35 -0
- package/src/abi/iPriceFeedStore.ts +227 -0
- package/src/abi/iUpdatablePriceFeed.ts +16 -0
- package/src/abi/iVersion.ts +28 -0
- package/src/abi/iZapper.ts +84 -0
- package/src/abi/routerV300.ts +378 -0
- package/src/abi/v300.ts +4151 -0
- package/src/abi/v310.ts +5179 -0
- package/src/adapters/AbstractAdapter.ts +28 -0
- package/src/adapters/BalancerV2VaultAdapterContract.ts +19 -0
- package/src/adapters/BalancerV3RouterAdapterContract.ts +19 -0
- package/src/adapters/CamelotV3AdapterContract.ts +20 -0
- package/src/adapters/ConvexV1BaseRewardPoolAdapterContract.ts +20 -0
- package/src/adapters/ConvexV1BoosterAdapterContract.ts +20 -0
- package/src/adapters/Curve2AssetsAdapterContract.ts +20 -0
- package/src/adapters/Curve3AssetsAdapterContract.ts +20 -0
- package/src/adapters/Curve4AssetsAdapterContract.ts +20 -0
- package/src/adapters/CurveV1AdapterStETHContract.ts +20 -0
- package/src/adapters/CurveV1StableNGAdapterContract.ts +20 -0
- package/src/adapters/DaiUsdsAdapterContract.ts +21 -0
- package/src/adapters/ERC4626AdapterContract.ts +20 -0
- package/src/adapters/MellowERC4626VaultAdapterContract.ts +20 -0
- package/src/adapters/MellowVaultAdapterContract.ts +20 -0
- package/src/adapters/PendleRouterAdapterContract.ts +21 -0
- package/src/adapters/StakingRewardsAdapterContract.ts +21 -0
- package/src/adapters/UniswapV2AdapterContract.ts +20 -0
- package/src/adapters/UniswapV3AdapterContract.ts +170 -0
- package/src/adapters/VelodromeV2AdapterContract.ts +20 -0
- package/src/adapters/WstETHV1AdapterContract.ts +20 -0
- package/src/adapters/YearnV2AdapterContract.ts +20 -0
- package/src/adapters/abi/adapters.ts +4325 -0
- package/src/adapters/abi/iBalancerV3RouterAdapter.ts +126 -0
- package/src/adapters/abi/index.ts +2 -0
- package/src/adapters/index.ts +2 -0
- package/src/adapters/plugin.ts +90 -0
- package/src/adapters/types.ts +62 -0
- package/src/dev/AccountOpener.ts +611 -0
- package/src/dev/PriceFeedStore.ts +95 -0
- package/src/dev/SDKExample.ts +167 -0
- package/src/dev/abi.ts +14 -0
- package/src/dev/calcLiquidatableLTs.ts +77 -0
- package/src/dev/createAnvilClient.ts +155 -0
- package/src/dev/index.ts +7 -0
- package/src/dev/setLTZero.ts +127 -0
- package/src/dev/setLTs.ts +68 -0
- package/src/sdk/GearboxSDK.ts +488 -0
- package/src/sdk/abi/index.ts +1 -0
- package/src/sdk/abi/oracles.ts +4614 -0
- package/src/sdk/accounts/CreditAccountsService.ts +1123 -0
- package/src/sdk/accounts/index.ts +1 -0
- package/src/sdk/base/AddressLabeller.ts +35 -0
- package/src/sdk/base/BaseContract.ts +237 -0
- package/src/sdk/base/IAddressLabeller.ts +13 -0
- package/src/sdk/base/PlaceholderContract.ts +12 -0
- package/src/sdk/base/SDKConstruct.ts +35 -0
- package/src/sdk/base/TokensMeta.ts +45 -0
- package/src/sdk/base/index.ts +6 -0
- package/src/sdk/base/types.ts +102 -0
- package/src/sdk/bots/BotsService.ts +92 -0
- package/src/sdk/bots/index.ts +2 -0
- package/src/sdk/bots/utils.ts +19 -0
- package/src/sdk/chain/Provider.ts +99 -0
- package/src/sdk/chain/chains.ts +41 -0
- package/src/sdk/chain/detectChain.ts +21 -0
- package/src/sdk/chain/index.ts +3 -0
- package/src/sdk/constants/address-provider.ts +47 -0
- package/src/sdk/constants/addresses.ts +82 -0
- package/src/sdk/constants/bot-permissions.ts +36 -0
- package/src/sdk/constants/index.ts +6 -0
- package/src/sdk/constants/math.ts +23 -0
- package/src/sdk/constants/networks.ts +38 -0
- package/src/sdk/constants/periphery.ts +7 -0
- package/src/sdk/core/BotListV3Contract.ts +103 -0
- package/src/sdk/core/GearStakingV3Contract.ts +84 -0
- package/src/sdk/core/address-provider/AbstractAddressProviderContract.ts +101 -0
- package/src/sdk/core/address-provider/AddressProviderV3Contract.ts +105 -0
- package/src/sdk/core/address-provider/AddressProviderV3_1Contract.ts +92 -0
- package/src/sdk/core/address-provider/getAddressProvider.ts +45 -0
- package/src/sdk/core/address-provider/index.ts +4 -0
- package/src/sdk/core/address-provider/types.ts +17 -0
- package/src/sdk/core/index.ts +3 -0
- package/src/sdk/gauges/GaugeStakingService.ts +100 -0
- package/src/sdk/gauges/index.ts +2 -0
- package/src/sdk/gauges/utils.ts +25 -0
- package/src/sdk/index.ts +17 -0
- package/src/sdk/market/MarketConfiguratorContract.ts +78 -0
- package/src/sdk/market/MarketRegister.ts +330 -0
- package/src/sdk/market/MarketSuite.ts +83 -0
- package/src/sdk/market/adapters/PlaceholderAdapterContracts.ts +18 -0
- package/src/sdk/market/adapters/factory.ts +34 -0
- package/src/sdk/market/adapters/index.ts +3 -0
- package/src/sdk/market/adapters/types.ts +7 -0
- package/src/sdk/market/credit/CreditConfiguratorV300Contract.ts +164 -0
- package/src/sdk/market/credit/CreditConfiguratorV310Contract.ts +139 -0
- package/src/sdk/market/credit/CreditFacadeV300Contract.ts +206 -0
- package/src/sdk/market/credit/CreditFacadeV310Contract.ts +190 -0
- package/src/sdk/market/credit/CreditManagerV300Contract.ts +122 -0
- package/src/sdk/market/credit/CreditManagerV310Contract.ts +122 -0
- package/src/sdk/market/credit/CreditSuite.ts +65 -0
- package/src/sdk/market/credit/createCreditConfigurator.ts +18 -0
- package/src/sdk/market/credit/createCreditFacade.ts +18 -0
- package/src/sdk/market/credit/createCreditManager.ts +18 -0
- package/src/sdk/market/credit/index.ts +8 -0
- package/src/sdk/market/credit/types.ts +42 -0
- package/src/sdk/market/index.ts +7 -0
- package/src/sdk/market/oracle/PriceOracleBaseContract.ts +376 -0
- package/src/sdk/market/oracle/PriceOracleV300Contract.ts +71 -0
- package/src/sdk/market/oracle/PriceOracleV310Contract.ts +43 -0
- package/src/sdk/market/oracle/createPriceOracle.ts +22 -0
- package/src/sdk/market/oracle/index.ts +4 -0
- package/src/sdk/market/oracle/types.ts +48 -0
- package/src/sdk/market/pool/GaugeContract.ts +120 -0
- package/src/sdk/market/pool/LinearInterestRateModelContract.ts +75 -0
- package/src/sdk/market/pool/PoolQuotaKeeperV300Contract.ts +89 -0
- package/src/sdk/market/pool/PoolQuotaKeeperV310Contract.ts +89 -0
- package/src/sdk/market/pool/PoolSuite.ts +76 -0
- package/src/sdk/market/pool/PoolV300Contract.ts +144 -0
- package/src/sdk/market/pool/PoolV310Contract.ts +144 -0
- package/src/sdk/market/pool/TumblerContract.ts +73 -0
- package/src/sdk/market/pool/createInterestRateModel.ts +33 -0
- package/src/sdk/market/pool/createPool.ts +19 -0
- package/src/sdk/market/pool/createPoolQuotaKeeper.ts +20 -0
- package/src/sdk/market/pool/createRateKeeper.ts +25 -0
- package/src/sdk/market/pool/index.ts +6 -0
- package/src/sdk/market/pool/types.ts +28 -0
- package/src/sdk/market/pricefeeds/AbstractLPPriceFeed.ts +71 -0
- package/src/sdk/market/pricefeeds/AbstractPriceFeed.ts +137 -0
- package/src/sdk/market/pricefeeds/BalancerStablePriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/BalancerWeightedPriceFeed.ts +70 -0
- package/src/sdk/market/pricefeeds/BoundedPriceFeed.ts +34 -0
- package/src/sdk/market/pricefeeds/ChainlinkPriceFeed.ts +16 -0
- package/src/sdk/market/pricefeeds/CompositePriceFeed.ts +25 -0
- package/src/sdk/market/pricefeeds/CurveCryptoPriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/CurveStablePriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/CurveUSDPriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/Erc4626PriceFeed.ts +36 -0
- package/src/sdk/market/pricefeeds/MellowLRTPriceFeed.ts +26 -0
- package/src/sdk/market/pricefeeds/PendleTWAPPTPriceFeed.ts +44 -0
- package/src/sdk/market/pricefeeds/PriceFeedRef.ts +34 -0
- package/src/sdk/market/pricefeeds/PriceFeedsRegister.ts +293 -0
- package/src/sdk/market/pricefeeds/RedstonePriceFeed.ts +65 -0
- package/src/sdk/market/pricefeeds/RedstoneUpdater.ts +304 -0
- package/src/sdk/market/pricefeeds/WstETHPriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/YearnPriceFeed.ts +24 -0
- package/src/sdk/market/pricefeeds/ZeroPriceFeed.ts +17 -0
- package/src/sdk/market/pricefeeds/index.ts +20 -0
- package/src/sdk/market/pricefeeds/types.ts +82 -0
- package/src/sdk/market/pricefeeds/utils.ts +24 -0
- package/src/sdk/plugins/index.ts +10 -0
- package/src/sdk/router/PathOptionFactory.ts +147 -0
- package/src/sdk/router/RouterV3Contract.ts +558 -0
- package/src/sdk/router/index.ts +2 -0
- package/src/sdk/router/types.ts +48 -0
- package/src/sdk/sdk-gov-legacy/contracts/adapters.ts +39 -0
- package/src/sdk/sdk-gov-legacy/contracts/contracts.ts +647 -0
- package/src/sdk/sdk-gov-legacy/contracts/index.ts +2 -0
- package/src/sdk/sdk-gov-legacy/core/constants.ts +11 -0
- package/src/sdk/sdk-gov-legacy/index.ts +4 -0
- package/src/sdk/sdk-gov-legacy/oracles/PriceFeedType.ts +24 -0
- package/src/sdk/sdk-gov-legacy/oracles/index.ts +1 -0
- package/src/sdk/sdk-gov-legacy/tokens/aave.ts +101 -0
- package/src/sdk/sdk-gov-legacy/tokens/aura.ts +284 -0
- package/src/sdk/sdk-gov-legacy/tokens/balancer.ts +421 -0
- package/src/sdk/sdk-gov-legacy/tokens/compound.ts +79 -0
- package/src/sdk/sdk-gov-legacy/tokens/convex.ts +561 -0
- package/src/sdk/sdk-gov-legacy/tokens/curveLP.ts +480 -0
- package/src/sdk/sdk-gov-legacy/tokens/decimals.ts +301 -0
- package/src/sdk/sdk-gov-legacy/tokens/erc4626.ts +75 -0
- package/src/sdk/sdk-gov-legacy/tokens/gear.ts +273 -0
- package/src/sdk/sdk-gov-legacy/tokens/index.ts +18 -0
- package/src/sdk/sdk-gov-legacy/tokens/normal.ts +613 -0
- package/src/sdk/sdk-gov-legacy/tokens/quoted.ts +10 -0
- package/src/sdk/sdk-gov-legacy/tokens/stakingRewards.ts +41 -0
- package/src/sdk/sdk-gov-legacy/tokens/token.ts +2354 -0
- package/src/sdk/sdk-gov-legacy/tokens/tokenData.ts +44 -0
- package/src/sdk/sdk-gov-legacy/tokens/tokenType.ts +33 -0
- package/src/sdk/sdk-gov-legacy/tokens/wrapped.ts +28 -0
- package/src/sdk/sdk-gov-legacy/tokens/yearn.ts +122 -0
- package/src/sdk/sdk-gov-legacy/tokens/zircuit.ts +44 -0
- package/src/sdk/sdk-legacy/apy/index.ts +149 -0
- package/src/sdk/sdk-legacy/core/assets.ts +200 -0
- package/src/sdk/sdk-legacy/core/creditAccount.spec.ts +1966 -0
- package/src/sdk/sdk-legacy/core/creditAccount.ts +816 -0
- package/src/sdk/sdk-legacy/core/creditManager.ts +316 -0
- package/src/sdk/sdk-legacy/core/creditSession.ts +352 -0
- package/src/sdk/sdk-legacy/core/endpoint.ts +131 -0
- package/src/sdk/sdk-legacy/core/eventOrTx.ts +101 -0
- package/src/sdk/sdk-legacy/core/pool.ts +439 -0
- package/src/sdk/sdk-legacy/core/strategy.ts +82 -0
- package/src/sdk/sdk-legacy/core/transactions.ts +865 -0
- package/src/sdk/sdk-legacy/gearboxRewards/api.ts +704 -0
- package/src/sdk/sdk-legacy/gearboxRewards/apy.ts +267 -0
- package/src/sdk/sdk-legacy/gearboxRewards/extraAPY.ts +165 -0
- package/src/sdk/sdk-legacy/gearboxRewards/index.ts +3 -0
- package/src/sdk/sdk-legacy/gearboxRewards/merklAPI.ts +151 -0
- package/src/sdk/sdk-legacy/index.ts +21 -0
- package/src/sdk/sdk-legacy/pathfinder/core.ts +18 -0
- package/src/sdk/sdk-legacy/pathfinder/index.ts +1 -0
- package/src/sdk/sdk-legacy/payload/creditAccount.ts +48 -0
- package/src/sdk/sdk-legacy/payload/creditManager.ts +133 -0
- package/src/sdk/sdk-legacy/payload/creditSession.ts +143 -0
- package/src/sdk/sdk-legacy/payload/graphPayload.ts +10 -0
- package/src/sdk/sdk-legacy/payload/pool.ts +198 -0
- package/src/sdk/sdk-legacy/payload/token.ts +13 -0
- package/src/sdk/sdk-legacy/tokens/tokenData.ts +57 -0
- package/src/sdk/sdk-legacy/types/IAirdropDistributor.ts +103 -0
- package/src/sdk/sdk-legacy/types/IBaseRewardPool.ts +249 -0
- package/src/sdk/sdk-legacy/types/IDataCompressorV3.ts +957 -0
- package/src/sdk/sdk-legacy/types/IDegenDistributor.ts +70 -0
- package/src/sdk/sdk-legacy/types/IERC20Permit.ts +35 -0
- package/src/sdk/sdk-legacy/types/IERC20ZapperDeposits.ts +99 -0
- package/src/sdk/sdk-legacy/types/IETHZapperDeposits.ts +27 -0
- package/src/sdk/sdk-legacy/types/IFarmingPool.ts +229 -0
- package/src/sdk/sdk-legacy/types/IInterestRateModel.ts +23 -0
- package/src/sdk/sdk-legacy/types/IMulticall3.ts +242 -0
- package/src/sdk/sdk-legacy/types/IOffchainOracle.ts +31 -0
- package/src/sdk/sdk-legacy/types/index.ts +11 -0
- package/src/sdk/sdk-legacy/utils/formatter.ts +46 -0
- package/src/sdk/sdk-legacy/utils/index.ts +3 -0
- package/src/sdk/sdk-legacy/utils/math.ts +6 -0
- package/src/sdk/sdk-legacy/utils/price.ts +27 -0
- package/src/sdk/types/index.ts +5 -0
- package/src/sdk/types/logger.ts +13 -0
- package/src/sdk/types/state-human.ts +224 -0
- package/src/sdk/types/state.ts +8 -0
- package/src/sdk/types/transactions.ts +22 -0
- package/src/sdk/types/tvl.ts +4 -0
- package/src/sdk/utils/AddressMap.ts +111 -0
- package/src/sdk/utils/bytes32ToString.ts +6 -0
- package/src/sdk/utils/childLogger.ts +8 -0
- package/src/sdk/utils/createRawTx.ts +86 -0
- package/src/sdk/utils/etherscan.ts +42 -0
- package/src/sdk/utils/filterDust.ts +20 -0
- package/src/sdk/utils/formatter.ts +124 -0
- package/src/sdk/utils/index.ts +10 -0
- package/src/sdk/utils/internal/Hooks.ts +51 -0
- package/src/sdk/utils/internal/index.ts +1 -0
- package/src/sdk/utils/json.ts +27 -0
- package/src/sdk/utils/mappers.ts +38 -0
- package/src/sdk/utils/retry.ts +24 -0
- package/src/sdk/utils/viem/detectNetwork.ts +27 -0
- package/src/sdk/utils/viem/index.ts +3 -0
- package/src/sdk/utils/viem/sendRawTx.ts +36 -0
- package/src/sdk/utils/viem/simulateMulticall.ts +262 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +16 -0
- package/tsup.config.ts +77 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Address,
|
|
3
|
+
getChainContractAddress,
|
|
4
|
+
type Hex,
|
|
5
|
+
multicall3Abi,
|
|
6
|
+
} from "viem";
|
|
7
|
+
|
|
8
|
+
import { iMarketCompressorAbi } from "../../../abi/compressors";
|
|
9
|
+
import type { BaseParams, PriceFeedTreeNode } from "../../base";
|
|
10
|
+
import { SDKConstruct } from "../../base";
|
|
11
|
+
import { ADDRESS_0X0, AP_MARKET_COMPRESSOR } from "../../constants";
|
|
12
|
+
import type { GearboxSDK } from "../../GearboxSDK";
|
|
13
|
+
import type { ILogger, RawTx } from "../../types";
|
|
14
|
+
import {
|
|
15
|
+
AddressMap,
|
|
16
|
+
bytes32ToString,
|
|
17
|
+
childLogger,
|
|
18
|
+
createRawTx,
|
|
19
|
+
} from "../../utils";
|
|
20
|
+
import type { IHooks } from "../../utils/internal";
|
|
21
|
+
import { Hooks } from "../../utils/internal";
|
|
22
|
+
import type { PartialPriceFeedTreeNode } from "./AbstractPriceFeed";
|
|
23
|
+
import { BalancerStablePriceFeedContract } from "./BalancerStablePriceFeed";
|
|
24
|
+
import { BalancerWeightedPriceFeedContract } from "./BalancerWeightedPriceFeed";
|
|
25
|
+
import { BoundedPriceFeedContract } from "./BoundedPriceFeed";
|
|
26
|
+
import { ChainlinkPriceFeedContract } from "./ChainlinkPriceFeed";
|
|
27
|
+
import { CompositePriceFeedContract } from "./CompositePriceFeed";
|
|
28
|
+
import { CurveCryptoPriceFeedContract } from "./CurveCryptoPriceFeed";
|
|
29
|
+
import { CurveStablePriceFeedContract } from "./CurveStablePriceFeed";
|
|
30
|
+
import { CurveUSDPriceFeedContract } from "./CurveUSDPriceFeed";
|
|
31
|
+
import { Erc4626PriceFeedContract } from "./Erc4626PriceFeed";
|
|
32
|
+
import { MellowLRTPriceFeedContract } from "./MellowLRTPriceFeed";
|
|
33
|
+
import { PendleTWAPPTPriceFeed } from "./PendleTWAPPTPriceFeed";
|
|
34
|
+
import { RedstonePriceFeedContract } from "./RedstonePriceFeed";
|
|
35
|
+
import { RedstoneUpdater } from "./RedstoneUpdater";
|
|
36
|
+
import type {
|
|
37
|
+
IPriceFeedContract,
|
|
38
|
+
PriceFeedContractType,
|
|
39
|
+
UpdatePriceFeedsResult,
|
|
40
|
+
} from "./types";
|
|
41
|
+
import { WstETHPriceFeedContract } from "./WstETHPriceFeed";
|
|
42
|
+
import { YearnPriceFeedContract } from "./YearnPriceFeed";
|
|
43
|
+
import { ZeroPriceFeedContract } from "./ZeroPriceFeed";
|
|
44
|
+
|
|
45
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
|
46
|
+
export type PriceFeedRegisterHooks = {
|
|
47
|
+
/**
|
|
48
|
+
* Emitted when transactions to update price feeds have been generated, but before they're used anywhere
|
|
49
|
+
*/
|
|
50
|
+
updatesGenerated: [UpdatePriceFeedsResult];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* PriceFeedRegister acts as a chain-level cache to avoid creating multiple contract instances.
|
|
55
|
+
* It's reused by PriceOracles belonging to different markets
|
|
56
|
+
*
|
|
57
|
+
**/
|
|
58
|
+
export class PriceFeedRegister
|
|
59
|
+
extends SDKConstruct
|
|
60
|
+
implements IHooks<PriceFeedRegisterHooks>
|
|
61
|
+
{
|
|
62
|
+
public readonly logger?: ILogger;
|
|
63
|
+
readonly #hooks = new Hooks<PriceFeedRegisterHooks>();
|
|
64
|
+
#feeds = new AddressMap<IPriceFeedContract>(undefined, "priceFeeds");
|
|
65
|
+
public readonly redstoneUpdater: RedstoneUpdater;
|
|
66
|
+
|
|
67
|
+
constructor(sdk: GearboxSDK) {
|
|
68
|
+
super(sdk);
|
|
69
|
+
this.logger = childLogger("PriceFeedRegister", sdk.logger);
|
|
70
|
+
this.redstoneUpdater = new RedstoneUpdater(sdk);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
public addHook = this.#hooks.addHook.bind(this.#hooks);
|
|
74
|
+
public removeHook = this.#hooks.removeHook.bind(this.#hooks);
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Returns RawTxs to update price feeds
|
|
78
|
+
* @param priceFeeds top-level price feeds, actual updatable price feeds will be derived. If not provided will use all price feeds that are attached
|
|
79
|
+
* @param logContext extra information for logging
|
|
80
|
+
* @returns
|
|
81
|
+
*/
|
|
82
|
+
public async generatePriceFeedsUpdateTxs(
|
|
83
|
+
priceFeeds?: IPriceFeedContract[],
|
|
84
|
+
logContext: Record<string, any> = {},
|
|
85
|
+
): Promise<UpdatePriceFeedsResult> {
|
|
86
|
+
const updateables = priceFeeds
|
|
87
|
+
? priceFeeds.flatMap(pf => pf.updatableDependencies())
|
|
88
|
+
: this.#feeds.values();
|
|
89
|
+
return this.#generatePriceFeedsUpdateTxs(updateables, logContext);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public has(address: Address): boolean {
|
|
93
|
+
return this.#feeds.has(address);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public mustGet(address: Address): IPriceFeedContract {
|
|
97
|
+
return this.#feeds.mustGet(address);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public getOrCreate(data: PriceFeedTreeNode): IPriceFeedContract {
|
|
101
|
+
const existing = this.#feeds.get(data.baseParams.addr);
|
|
102
|
+
// it's possible to have non-loaded price feed here first from MarketCompressor.getUpdatablePriceFeeds
|
|
103
|
+
// we ovewrite them using full tree nodes
|
|
104
|
+
if (existing?.loaded) {
|
|
105
|
+
return existing;
|
|
106
|
+
}
|
|
107
|
+
const feed = this.create(data);
|
|
108
|
+
this.#feeds.upsert(data.baseParams.addr, feed);
|
|
109
|
+
return feed;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Loads PARTIAL information about all updatable price feeds from MarketCompressor
|
|
114
|
+
* This can later be used to load price feed updates
|
|
115
|
+
*/
|
|
116
|
+
public async preloadUpdatablePriceFeeds(
|
|
117
|
+
marketConfigurators?: Address[],
|
|
118
|
+
pools?: Address[],
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
const feedsData = await this.#loadUpdatablePriceFeeds(
|
|
121
|
+
marketConfigurators,
|
|
122
|
+
pools,
|
|
123
|
+
);
|
|
124
|
+
for (const data of feedsData) {
|
|
125
|
+
const feed = this.create({ baseParams: data });
|
|
126
|
+
this.#feeds.upsert(feed.address, feed);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Generates price update transaction via multicall3 without any market data knowledge
|
|
132
|
+
* @param marketConfigurators
|
|
133
|
+
* @param pools
|
|
134
|
+
* @returns
|
|
135
|
+
*/
|
|
136
|
+
public async getUpdatePriceFeedsTx(
|
|
137
|
+
marketConfigurators?: Address[],
|
|
138
|
+
pools?: Address[],
|
|
139
|
+
): Promise<RawTx> {
|
|
140
|
+
const feedsData = await this.#loadUpdatablePriceFeeds(
|
|
141
|
+
marketConfigurators,
|
|
142
|
+
pools,
|
|
143
|
+
);
|
|
144
|
+
const feeds = feedsData.map(data => this.create({ baseParams: data }));
|
|
145
|
+
const updates = await this.#generatePriceFeedsUpdateTxs(feeds);
|
|
146
|
+
|
|
147
|
+
return createRawTx(
|
|
148
|
+
getChainContractAddress({
|
|
149
|
+
chain: this.sdk.provider.chain,
|
|
150
|
+
contract: "multicall3",
|
|
151
|
+
}),
|
|
152
|
+
{
|
|
153
|
+
abi: multicall3Abi,
|
|
154
|
+
functionName: "aggregate3",
|
|
155
|
+
args: [
|
|
156
|
+
updates.txs.map(tx => ({
|
|
157
|
+
target: tx.to,
|
|
158
|
+
allowFailure: false,
|
|
159
|
+
callData: tx.callData,
|
|
160
|
+
})),
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async #generatePriceFeedsUpdateTxs(
|
|
167
|
+
updateables: IPriceFeedContract[],
|
|
168
|
+
logContext: Record<string, any> = {},
|
|
169
|
+
): Promise<UpdatePriceFeedsResult> {
|
|
170
|
+
const txs: RawTx[] = [];
|
|
171
|
+
const redstonePFs: RedstonePriceFeedContract[] = [];
|
|
172
|
+
|
|
173
|
+
for (const pf of updateables) {
|
|
174
|
+
if (pf instanceof RedstonePriceFeedContract) {
|
|
175
|
+
redstonePFs.push(pf);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
let maxTimestamp = 0;
|
|
180
|
+
if (redstonePFs.length > 0) {
|
|
181
|
+
const redstoneUpdates = await this.redstoneUpdater.getUpdateTxs(
|
|
182
|
+
redstonePFs,
|
|
183
|
+
logContext,
|
|
184
|
+
);
|
|
185
|
+
for (const { tx, timestamp } of redstoneUpdates) {
|
|
186
|
+
if (timestamp > maxTimestamp) {
|
|
187
|
+
maxTimestamp = timestamp;
|
|
188
|
+
}
|
|
189
|
+
txs.push(tx);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const result: UpdatePriceFeedsResult = { txs, timestamp: maxTimestamp };
|
|
194
|
+
this.logger?.debug(
|
|
195
|
+
logContext,
|
|
196
|
+
`generated ${txs.length} price feed update transactions, timestamp: ${maxTimestamp}`,
|
|
197
|
+
);
|
|
198
|
+
if (txs.length) {
|
|
199
|
+
await this.#hooks.triggerHooks("updatesGenerated", result);
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async #loadUpdatablePriceFeeds(
|
|
205
|
+
marketConfigurators?: Address[],
|
|
206
|
+
pools?: Address[],
|
|
207
|
+
): Promise<readonly BaseParams[]> {
|
|
208
|
+
const marketCompressorAddress = this.sdk.addressProvider.getAddress(
|
|
209
|
+
AP_MARKET_COMPRESSOR,
|
|
210
|
+
3_10,
|
|
211
|
+
);
|
|
212
|
+
const configurators =
|
|
213
|
+
marketConfigurators ??
|
|
214
|
+
this.sdk.marketRegister.marketConfigurators.map(mc => mc.address);
|
|
215
|
+
this.logger?.debug(
|
|
216
|
+
{ configurators, pools },
|
|
217
|
+
"calling getUpdatablePriceFeeds",
|
|
218
|
+
);
|
|
219
|
+
const result = await this.provider.publicClient.readContract({
|
|
220
|
+
address: marketCompressorAddress,
|
|
221
|
+
abi: iMarketCompressorAbi,
|
|
222
|
+
functionName: "getUpdatablePriceFeeds",
|
|
223
|
+
args: [
|
|
224
|
+
{
|
|
225
|
+
configurators,
|
|
226
|
+
pools: pools ?? [],
|
|
227
|
+
underlying: ADDRESS_0X0,
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
// It's passed as ...rest in viem readContract action, but this might change
|
|
231
|
+
// @ts-ignore
|
|
232
|
+
// gas: 500_000_000n,
|
|
233
|
+
});
|
|
234
|
+
this.logger?.debug(`loaded ${result.length} updatable price feeds`);
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public create(data: PartialPriceFeedTreeNode): IPriceFeedContract {
|
|
239
|
+
const contractType = bytes32ToString(
|
|
240
|
+
data.baseParams.contractType as Hex,
|
|
241
|
+
) as PriceFeedContractType;
|
|
242
|
+
|
|
243
|
+
switch (contractType) {
|
|
244
|
+
case "PRICE_FEED::EXTERNAL":
|
|
245
|
+
return new ChainlinkPriceFeedContract(this.sdk, data);
|
|
246
|
+
|
|
247
|
+
case "PRICE_FEED::YEARN":
|
|
248
|
+
return new YearnPriceFeedContract(this.sdk, data);
|
|
249
|
+
|
|
250
|
+
case "PRICE_FEED::CURVE_STABLE":
|
|
251
|
+
return new CurveStablePriceFeedContract(this.sdk, data);
|
|
252
|
+
|
|
253
|
+
case "PRICE_FEED::WSTETH":
|
|
254
|
+
return new WstETHPriceFeedContract(this.sdk, data);
|
|
255
|
+
|
|
256
|
+
case "PRICE_FEED::BOUNDED":
|
|
257
|
+
return new BoundedPriceFeedContract(this.sdk, data);
|
|
258
|
+
|
|
259
|
+
case "PRICE_FEED::COMPOSITE":
|
|
260
|
+
return new CompositePriceFeedContract(this.sdk, data);
|
|
261
|
+
|
|
262
|
+
case "PRICE_FEED::BALANCER_STABLE":
|
|
263
|
+
return new BalancerStablePriceFeedContract(this.sdk, data);
|
|
264
|
+
|
|
265
|
+
case "PRICE_FEED::BALANCER_WEIGHTED":
|
|
266
|
+
return new BalancerWeightedPriceFeedContract(this.sdk, data);
|
|
267
|
+
|
|
268
|
+
case "PRICE_FEED::CURVE_CRYPTO":
|
|
269
|
+
return new CurveCryptoPriceFeedContract(this.sdk, data);
|
|
270
|
+
|
|
271
|
+
case "PRICE_FEED::REDSTONE":
|
|
272
|
+
return new RedstonePriceFeedContract(this.sdk, data);
|
|
273
|
+
|
|
274
|
+
case "PRICE_FEED::ERC4626":
|
|
275
|
+
return new Erc4626PriceFeedContract(this.sdk, data);
|
|
276
|
+
|
|
277
|
+
case "PRICE_FEED::CURVE_USD":
|
|
278
|
+
return new CurveUSDPriceFeedContract(this.sdk, data);
|
|
279
|
+
|
|
280
|
+
case "PRICE_FEED::ZERO":
|
|
281
|
+
return new ZeroPriceFeedContract(this.sdk, data);
|
|
282
|
+
|
|
283
|
+
case "PRICE_FEED::MELLOW_LRT":
|
|
284
|
+
return new MellowLRTPriceFeedContract(this.sdk, data);
|
|
285
|
+
|
|
286
|
+
case "PRICE_FEED::PENDLE_PT_TWAP":
|
|
287
|
+
return new PendleTWAPPTPriceFeed(this.sdk, data);
|
|
288
|
+
|
|
289
|
+
default:
|
|
290
|
+
throw new Error(`Price feed type ${contractType} not supported, `);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { Hex } from "viem";
|
|
2
|
+
import { bytesToString, decodeAbiParameters, toBytes } from "viem";
|
|
3
|
+
|
|
4
|
+
import { redstonePriceFeedAbi } from "../../abi";
|
|
5
|
+
import type { GearboxSDK } from "../../GearboxSDK";
|
|
6
|
+
import type { RedstonePriceFeedStateHuman } from "../../types";
|
|
7
|
+
import type { PartialPriceFeedTreeNode } from "./AbstractPriceFeed";
|
|
8
|
+
import { AbstractPriceFeedContract } from "./AbstractPriceFeed";
|
|
9
|
+
|
|
10
|
+
type abi = typeof redstonePriceFeedAbi;
|
|
11
|
+
|
|
12
|
+
export class RedstonePriceFeedContract extends AbstractPriceFeedContract<abi> {
|
|
13
|
+
public readonly dataServiceId: string;
|
|
14
|
+
public readonly dataId: string;
|
|
15
|
+
public readonly signers: Hex[];
|
|
16
|
+
public readonly signersThreshold: number;
|
|
17
|
+
|
|
18
|
+
constructor(sdk: GearboxSDK, args: PartialPriceFeedTreeNode) {
|
|
19
|
+
super(sdk, {
|
|
20
|
+
...args,
|
|
21
|
+
name: `RedstonePriceFeed`,
|
|
22
|
+
abi: redstonePriceFeedAbi,
|
|
23
|
+
});
|
|
24
|
+
const decoder = decodeAbiParameters(
|
|
25
|
+
[
|
|
26
|
+
{ type: "address" }, // [0]: pf.token(),
|
|
27
|
+
{ type: "bytes32" }, // [1]: pf.dataFeedId(),
|
|
28
|
+
{ type: "address" }, // [2]: pf.signerAddress0(),
|
|
29
|
+
{ type: "address" }, // [3]: pf.signerAddress1(),
|
|
30
|
+
{ type: "address" }, // [4]: pf.signerAddress2(),
|
|
31
|
+
{ type: "address" }, // [5]: pf.signerAddress3(),
|
|
32
|
+
{ type: "address" }, // [6]: pf.signerAddress4(),
|
|
33
|
+
{ type: "address" }, // [7]: pf.signerAddress5()
|
|
34
|
+
{ type: "address" }, // [8]: pf.signerAddress6(),
|
|
35
|
+
{ type: "address" }, // [9]: pf.signerAddress7(),
|
|
36
|
+
{ type: "address" }, // [10]: pf.signerAddress8(),
|
|
37
|
+
{ type: "address" }, // [11]: pf.signerAddress9(),
|
|
38
|
+
{ type: "uint8" }, // [12]: pf.getUniqueSignersThreshold()
|
|
39
|
+
{ type: "uint128" }, // [13]: pf.lastPrice(),
|
|
40
|
+
{ type: "uint40" }, // [14]: pf.lastPayloadTimestamp()
|
|
41
|
+
],
|
|
42
|
+
args.baseParams.serializedParams,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
this.dataId = bytesToString(toBytes(decoder[1])).replaceAll("\x00", "");
|
|
46
|
+
this.signers = decoder.slice(2, 11) as Hex[];
|
|
47
|
+
this.signersThreshold = Number(decoder[12]);
|
|
48
|
+
this.dataServiceId = ["GMX", "BAL"].includes(this.dataId)
|
|
49
|
+
? "redstone-arbitrum-prod"
|
|
50
|
+
: "redstone-primary-prod";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public override stateHuman(
|
|
54
|
+
raw = true,
|
|
55
|
+
): Omit<RedstonePriceFeedStateHuman, "stalenessPeriod"> {
|
|
56
|
+
return {
|
|
57
|
+
...super.stateHuman(raw),
|
|
58
|
+
contractType: "PRICE_FEED::REDSTONE",
|
|
59
|
+
dataId: this.dataId,
|
|
60
|
+
signers: this.signers,
|
|
61
|
+
signersThreshold: this.signersThreshold,
|
|
62
|
+
skipCheck: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
/* eslint-disable accessor-pairs */
|
|
2
|
+
import { DataServiceWrapper } from "@redstone-finance/evm-connector";
|
|
3
|
+
import type { SignedDataPackage } from "@redstone-finance/protocol";
|
|
4
|
+
import { RedstonePayload } from "@redstone-finance/protocol";
|
|
5
|
+
import type { Address, Hex } from "viem";
|
|
6
|
+
import { encodeAbiParameters, toBytes } from "viem";
|
|
7
|
+
|
|
8
|
+
import { SDKConstruct } from "../../base";
|
|
9
|
+
import type { GearboxSDK } from "../../GearboxSDK";
|
|
10
|
+
import type { ILogger, RawTx } from "../../types";
|
|
11
|
+
import { childLogger, retry } from "../../utils";
|
|
12
|
+
import type { RedstonePriceFeedContract } from "./RedstonePriceFeed";
|
|
13
|
+
|
|
14
|
+
interface TimestampedCalldata {
|
|
15
|
+
dataFeedId: string;
|
|
16
|
+
data: `0x${string}`;
|
|
17
|
+
timestamp: number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface UpdatePFTask {
|
|
21
|
+
priceFeed: Address;
|
|
22
|
+
tx: RawTx;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Class to update multiple redstone price feeds at once
|
|
28
|
+
*/
|
|
29
|
+
export class RedstoneUpdater extends SDKConstruct {
|
|
30
|
+
#logger?: ILogger;
|
|
31
|
+
#cache = new Map<string, TimestampedCalldata>();
|
|
32
|
+
#historicalTimestampMs?: number;
|
|
33
|
+
#gateways?: string[];
|
|
34
|
+
|
|
35
|
+
constructor(sdk: GearboxSDK) {
|
|
36
|
+
super(sdk);
|
|
37
|
+
this.#logger = childLogger("RedstoneUpdater", sdk.logger);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Set redstone historical timestamp in milliseconds
|
|
42
|
+
*/
|
|
43
|
+
public set historicalTimestamp(timestampMs: number) {
|
|
44
|
+
// redstone timestamps are rounded to one minute
|
|
45
|
+
this.#historicalTimestampMs = 60_000 * Math.floor(timestampMs / 60_000);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Set redstone gateways
|
|
50
|
+
*/
|
|
51
|
+
public set gateways(gateways: string[]) {
|
|
52
|
+
this.#gateways = gateways;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async getUpdateTxs(
|
|
56
|
+
feeds: RedstonePriceFeedContract[],
|
|
57
|
+
logContext: Record<string, any> = {},
|
|
58
|
+
): Promise<UpdatePFTask[]> {
|
|
59
|
+
this.#logger?.debug(
|
|
60
|
+
logContext,
|
|
61
|
+
`generating update transactions for ${feeds.length} redstone price feeds`,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Group feeds by dataServiceId and uniqueSignersCount
|
|
65
|
+
const groupedFeeds: Record<string, Set<string>> = {};
|
|
66
|
+
const priceFeeds = new Map<string, RedstonePriceFeedContract>();
|
|
67
|
+
for (const feed of feeds) {
|
|
68
|
+
const key = `${feed.dataServiceId}:${feed.signersThreshold}`;
|
|
69
|
+
if (!groupedFeeds[key]) {
|
|
70
|
+
groupedFeeds[key] = new Set();
|
|
71
|
+
}
|
|
72
|
+
groupedFeeds[key].add(feed.dataId);
|
|
73
|
+
priceFeeds.set(feed.dataId, feed);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const results: UpdatePFTask[] = [];
|
|
77
|
+
for (const [key, group] of Object.entries(groupedFeeds)) {
|
|
78
|
+
const [dataServiceId, signersStr] = key.split(":");
|
|
79
|
+
const uniqueSignersCount = parseInt(signersStr, 10);
|
|
80
|
+
const payloads = await this.#getPayloads(
|
|
81
|
+
dataServiceId,
|
|
82
|
+
group,
|
|
83
|
+
uniqueSignersCount,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
for (const { dataFeedId, data, timestamp } of payloads) {
|
|
87
|
+
const priceFeed = priceFeeds.get(dataFeedId);
|
|
88
|
+
if (!priceFeed) {
|
|
89
|
+
throw new Error(`cannot get price feed address for ${dataFeedId}`);
|
|
90
|
+
}
|
|
91
|
+
results.push({
|
|
92
|
+
priceFeed: priceFeed.address.toLowerCase() as Address,
|
|
93
|
+
tx: priceFeed.createRawTx({
|
|
94
|
+
functionName: "updatePrice",
|
|
95
|
+
args: [data as Hex],
|
|
96
|
+
description: `updating price for ${dataFeedId} [${this.sdk.provider.addressLabels.get(priceFeed.address)}]`,
|
|
97
|
+
}),
|
|
98
|
+
timestamp,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
this.#logger?.debug(
|
|
103
|
+
logContext,
|
|
104
|
+
`generated ${results.length} update transactions for redstone price feeds`,
|
|
105
|
+
);
|
|
106
|
+
return results;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Gets redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
111
|
+
* If historicalTimestamp is set, responses will be cached
|
|
112
|
+
* @param dataServiceId
|
|
113
|
+
* @param dataFeedsIds
|
|
114
|
+
* @param uniqueSignersCount
|
|
115
|
+
* @returns
|
|
116
|
+
*/
|
|
117
|
+
async #getPayloads(
|
|
118
|
+
dataServiceId: string,
|
|
119
|
+
dataFeedsIds: Set<string>,
|
|
120
|
+
uniqueSignersCount: number,
|
|
121
|
+
): Promise<TimestampedCalldata[]> {
|
|
122
|
+
this.#logger?.debug(
|
|
123
|
+
`getting redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${Array.from(dataFeedsIds).join(", ")}`,
|
|
124
|
+
);
|
|
125
|
+
const fromCache: TimestampedCalldata[] = [];
|
|
126
|
+
const uncached: string[] = [];
|
|
127
|
+
for (const dataFeedId of dataFeedsIds) {
|
|
128
|
+
const key = cacheKey(
|
|
129
|
+
dataServiceId,
|
|
130
|
+
dataFeedId,
|
|
131
|
+
uniqueSignersCount,
|
|
132
|
+
this.#historicalTimestampMs,
|
|
133
|
+
);
|
|
134
|
+
const cached = this.#cache.get(key);
|
|
135
|
+
if (this.#historicalTimestampMs && !!cached) {
|
|
136
|
+
fromCache.push(cached);
|
|
137
|
+
} else {
|
|
138
|
+
uncached.push(dataFeedId);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const fromRedstone = await this.#fetchPayloads(
|
|
143
|
+
dataServiceId,
|
|
144
|
+
new Set(uncached),
|
|
145
|
+
uniqueSignersCount,
|
|
146
|
+
);
|
|
147
|
+
// cache newly fetched responses
|
|
148
|
+
if (this.#historicalTimestampMs) {
|
|
149
|
+
for (const resp of fromRedstone) {
|
|
150
|
+
const key = cacheKey(
|
|
151
|
+
dataServiceId,
|
|
152
|
+
resp.dataFeedId,
|
|
153
|
+
uniqueSignersCount,
|
|
154
|
+
this.#historicalTimestampMs,
|
|
155
|
+
);
|
|
156
|
+
this.#cache.set(key, resp);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
this.#logger?.debug(
|
|
160
|
+
`got ${fromRedstone.length} new redstone updates and ${fromCache.length} from cache`,
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
return [...fromCache, ...fromRedstone];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Fetches redstone payloads in one request for multiple feeds with the same dataServiceId and uniqueSignersCount
|
|
168
|
+
* Payloads are loaded in one request to avoid redstone rate limit
|
|
169
|
+
* @param dataServiceId
|
|
170
|
+
* @param dataFeedsIds
|
|
171
|
+
* @param uniqueSignersCount
|
|
172
|
+
* @returns
|
|
173
|
+
*/
|
|
174
|
+
async #fetchPayloads(
|
|
175
|
+
dataServiceId: string,
|
|
176
|
+
dataFeedsIds: Set<string>,
|
|
177
|
+
uniqueSignersCount: number,
|
|
178
|
+
): Promise<TimestampedCalldata[]> {
|
|
179
|
+
if (dataFeedsIds.size === 0) {
|
|
180
|
+
return [];
|
|
181
|
+
}
|
|
182
|
+
const dataPackagesIds = Array.from(dataFeedsIds);
|
|
183
|
+
const tsStr = this.#historicalTimestampMs
|
|
184
|
+
? ` with historical timestamp ${this.#historicalTimestampMs}`
|
|
185
|
+
: "";
|
|
186
|
+
this.#logger?.debug(
|
|
187
|
+
`fetching redstone payloads for ${dataFeedsIds.size} data feeds in ${dataServiceId} with ${uniqueSignersCount} signers: ${dataPackagesIds.join(", ")}${tsStr}`,
|
|
188
|
+
);
|
|
189
|
+
const wrapper = new DataServiceWrapper({
|
|
190
|
+
dataServiceId,
|
|
191
|
+
dataPackagesIds,
|
|
192
|
+
uniqueSignersCount,
|
|
193
|
+
historicalTimestamp: this.#historicalTimestampMs,
|
|
194
|
+
urls: this.#gateways,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const dataPayload = await retry(
|
|
198
|
+
() => wrapper.prepareRedstonePayload(true),
|
|
199
|
+
{ attempts: 5, interval: this.#historicalTimestampMs ? 30_500 : 250 },
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
const parsed = RedstonePayload.parse(toBytes(`0x${dataPayload}`));
|
|
203
|
+
const packagesByDataFeedId = groupDataPackages(parsed.signedDataPackages);
|
|
204
|
+
|
|
205
|
+
return dataPackagesIds.map(dataFeedId => {
|
|
206
|
+
const signedDataPackages = packagesByDataFeedId[dataFeedId];
|
|
207
|
+
if (!signedDataPackages) {
|
|
208
|
+
throw new Error(`cannot find data packages for ${dataFeedId}`);
|
|
209
|
+
}
|
|
210
|
+
if (signedDataPackages.length !== uniqueSignersCount) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`got ${signedDataPackages.length} data packages for ${dataFeedId}, but expected ${uniqueSignersCount}`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
return getCalldataWithTimestamp(
|
|
216
|
+
dataFeedId,
|
|
217
|
+
signedDataPackages,
|
|
218
|
+
wrapper.getUnsignedMetadata(),
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function cacheKey(
|
|
225
|
+
dataServiceId: string,
|
|
226
|
+
dataFeedId: string,
|
|
227
|
+
uniqueSignersCount: number,
|
|
228
|
+
historicalTimestamp = 0,
|
|
229
|
+
): string {
|
|
230
|
+
return `${dataServiceId}:${dataFeedId}:${uniqueSignersCount}:${historicalTimestamp}`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Groups SignedDataPackages by dataFeedId
|
|
235
|
+
* @param signedDataPackages
|
|
236
|
+
* @returns
|
|
237
|
+
*/
|
|
238
|
+
function groupDataPackages(
|
|
239
|
+
signedDataPackages: SignedDataPackage[],
|
|
240
|
+
): Record<string, SignedDataPackage[]> {
|
|
241
|
+
const packagesByDataFeedId: Record<string, SignedDataPackage[]> = {};
|
|
242
|
+
for (const p of signedDataPackages) {
|
|
243
|
+
const { dataPoints } = p.dataPackage;
|
|
244
|
+
|
|
245
|
+
// Check if all data points have the same dataFeedId
|
|
246
|
+
const dataFeedId0 = dataPoints[0].dataFeedId;
|
|
247
|
+
for (const dp of dataPoints) {
|
|
248
|
+
if (dp.dataFeedId !== dataFeedId0) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`data package contains data points with different dataFeedIds: ${dp.dataFeedId} and ${dataFeedId0}`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Group data packages by dataFeedId
|
|
256
|
+
if (!packagesByDataFeedId[dataFeedId0]) {
|
|
257
|
+
packagesByDataFeedId[dataFeedId0] = [];
|
|
258
|
+
}
|
|
259
|
+
packagesByDataFeedId[dataFeedId0].push(p);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return packagesByDataFeedId;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function getCalldataWithTimestamp(
|
|
266
|
+
dataFeedId: string,
|
|
267
|
+
packages: SignedDataPackage[],
|
|
268
|
+
unsignedMetadata: string,
|
|
269
|
+
): TimestampedCalldata {
|
|
270
|
+
const originalPayload = RedstonePayload.prepare(packages, unsignedMetadata);
|
|
271
|
+
|
|
272
|
+
// Calculating the number of bytes in the hex representation of payload
|
|
273
|
+
// We divide by 2, beacuse 2 symbols in a hex string represent one byte
|
|
274
|
+
const originalPayloadLength = originalPayload.length / 2;
|
|
275
|
+
|
|
276
|
+
// Number of bytes that we want to add to unsigned metadata so that
|
|
277
|
+
// payload byte size becomes a multiplicity of 32
|
|
278
|
+
const bytesToAdd = 32 - (originalPayloadLength % 32);
|
|
279
|
+
|
|
280
|
+
// Adding underscores to the end of the metadata string, each underscore
|
|
281
|
+
// uses one byte in UTF-8
|
|
282
|
+
const newUnsignedMetadata = unsignedMetadata + "_".repeat(bytesToAdd);
|
|
283
|
+
|
|
284
|
+
const payload = RedstonePayload.prepare(packages, newUnsignedMetadata);
|
|
285
|
+
|
|
286
|
+
let timestamp = 0;
|
|
287
|
+
for (const p of packages) {
|
|
288
|
+
const newTimestamp = p.dataPackage.timestampMilliseconds / 1000;
|
|
289
|
+
if (timestamp === 0) {
|
|
290
|
+
timestamp = newTimestamp;
|
|
291
|
+
} else if (timestamp !== newTimestamp) {
|
|
292
|
+
throw new Error("Timestamps are not equal");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
dataFeedId,
|
|
298
|
+
data: encodeAbiParameters(
|
|
299
|
+
[{ type: "uint256" }, { type: "bytes" }],
|
|
300
|
+
[BigInt(timestamp), `0x${payload}`],
|
|
301
|
+
),
|
|
302
|
+
timestamp,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { iwstEthAbi, wstEthPriceFeedAbi } from "../../abi";
|
|
2
|
+
import type { GearboxSDK } from "../../GearboxSDK";
|
|
3
|
+
import { AbstractLPPriceFeedContract } from "./AbstractLPPriceFeed";
|
|
4
|
+
import type { PartialPriceFeedTreeNode } from "./AbstractPriceFeed";
|
|
5
|
+
|
|
6
|
+
type abi = typeof wstEthPriceFeedAbi;
|
|
7
|
+
|
|
8
|
+
export class WstETHPriceFeedContract extends AbstractLPPriceFeedContract<abi> {
|
|
9
|
+
constructor(sdk: GearboxSDK, args: PartialPriceFeedTreeNode) {
|
|
10
|
+
super(sdk, {
|
|
11
|
+
...args,
|
|
12
|
+
name: "WstETHPriceFeed",
|
|
13
|
+
abi: wstEthPriceFeedAbi,
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public override async getValue(): Promise<bigint> {
|
|
18
|
+
return await this.sdk.provider.publicClient.readContract({
|
|
19
|
+
abi: iwstEthAbi,
|
|
20
|
+
address: this.lpContract,
|
|
21
|
+
functionName: "stEthPerToken",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|