diff --git a/package.json b/package.json index f212ad64..8024eb7f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@across-protocol/sdk", "author": "UMA Team", - "version": "3.4.8", + "version": "3.4.9", "license": "AGPL-3.0", "homepage": "https://docs.across.to/reference/sdk", "files": [ @@ -99,8 +99,8 @@ }, "dependencies": { "@across-protocol/across-token": "^1.0.0", - "@across-protocol/constants": "^3.1.25", - "@across-protocol/contracts": "^3.0.19", + "@across-protocol/constants": "^3.1.27", + "@across-protocol/contracts": "^3.0.20", "@eth-optimism/sdk": "^3.3.1", "@ethersproject/bignumber": "^5.7.0", "@pinata/sdk": "^2.1.0", diff --git a/src/constants.ts b/src/constants.ts index 09b76161..82579196 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,5 +1,5 @@ import { constants as ethersConstants } from "ethers"; -import { TOKEN_SYMBOLS_MAP } from "@across-protocol/constants"; +import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "@across-protocol/constants"; export { ChainFamily, @@ -60,3 +60,12 @@ export const BRIDGED_USDC_SYMBOLS = [ TOKEN_SYMBOLS_MAP.USDbC.symbol, TOKEN_SYMBOLS_MAP.USDzC.symbol, ]; + +export const CUSTOM_GAS_TOKENS = { + [CHAIN_IDs.POLYGON]: "MATIC", + [CHAIN_IDs.POLYGON_AMOY]: "MATIC", + [CHAIN_IDs.ALEPH_ZERO]: "AZERO", + // FIXME: Replace with GRASS price once listed on Coingecko. + // For testing purposes, we use ETH price instead. + [CHAIN_IDs.LENS_SEPOLIA]: "ETH", +}; diff --git a/src/relayFeeCalculator/chain-queries/alephZero.ts b/src/relayFeeCalculator/chain-queries/alephZero.ts deleted file mode 100644 index 0c7ff48a..00000000 --- a/src/relayFeeCalculator/chain-queries/alephZero.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CHAIN_IDs } from "../../constants"; -import { Coingecko } from "../../coingecko/Coingecko"; -import { QueryBase } from "./baseQuery"; - -export class AlephZeroQueries extends QueryBase { - override async getTokenPrice(tokenSymbol: string): Promise { - if (!this.symbolMapping[tokenSymbol]) throw new Error(`${tokenSymbol} does not exist in mapping`); - const coingeckoInstance = Coingecko.get(this.logger, this.coingeckoProApiKey); - const [, tokenPrice] = await coingeckoInstance.getCurrentPriceByContract( - this.symbolMapping[tokenSymbol].addresses[CHAIN_IDs.MAINNET], - "usd" - ); - - const [, alephZeroPrice] = await coingeckoInstance.getCurrentPriceByContract( - this.symbolMapping["AZERO"].addresses[CHAIN_IDs.MAINNET], - "usd" - ); - return Number((tokenPrice / alephZeroPrice).toFixed(this.symbolMapping["AZERO"].decimals)); - } -} diff --git a/src/relayFeeCalculator/chain-queries/customGasToken.ts b/src/relayFeeCalculator/chain-queries/customGasToken.ts new file mode 100644 index 00000000..34210250 --- /dev/null +++ b/src/relayFeeCalculator/chain-queries/customGasToken.ts @@ -0,0 +1,29 @@ +import { CHAIN_IDs } from "../../constants"; +import { Coingecko } from "../../coingecko/Coingecko"; +import { QueryBase } from "./baseQuery"; + +type QueryBaseArgs = ConstructorParameters; + +export class CustomGasTokenQueries extends QueryBase { + readonly customGasTokenSymbol: string; + + constructor(args: { queryBaseArgs: QueryBaseArgs; customGasTokenSymbol: string }) { + super(...args.queryBaseArgs); + this.customGasTokenSymbol = args.customGasTokenSymbol; + } + + override async getTokenPrice(tokenSymbol: string): Promise { + if (!this.symbolMapping[tokenSymbol]) throw new Error(`${tokenSymbol} does not exist in mapping`); + const coingeckoInstance = Coingecko.get(this.logger, this.coingeckoProApiKey); + const [, tokenPrice] = await coingeckoInstance.getCurrentPriceByContract( + this.symbolMapping[tokenSymbol].addresses[CHAIN_IDs.MAINNET], + "usd" + ); + + const [, customGasTokenPrice] = await coingeckoInstance.getCurrentPriceByContract( + this.symbolMapping[this.customGasTokenSymbol].addresses[CHAIN_IDs.MAINNET], + "usd" + ); + return Number((tokenPrice / customGasTokenPrice).toFixed(this.symbolMapping[this.customGasTokenSymbol].decimals)); + } +} diff --git a/src/relayFeeCalculator/chain-queries/factory.ts b/src/relayFeeCalculator/chain-queries/factory.ts index 9bfee85f..941f947a 100644 --- a/src/relayFeeCalculator/chain-queries/factory.ts +++ b/src/relayFeeCalculator/chain-queries/factory.ts @@ -3,12 +3,11 @@ import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "@across-protocol/constants"; import { getDeployedAddress } from "@across-protocol/contracts"; import { asL2Provider } from "@eth-optimism/sdk"; import { providers } from "ethers"; -import { DEFAULT_SIMULATED_RELAYER_ADDRESS } from "../../constants"; -import { chainIsAlephZero, chainIsMatic, chainIsOPStack, isDefined } from "../../utils"; +import { DEFAULT_SIMULATED_RELAYER_ADDRESS, CUSTOM_GAS_TOKENS } from "../../constants"; +import { chainIsOPStack, isDefined } from "../../utils"; import { QueryBase } from "./baseQuery"; -import { PolygonQueries } from "./polygon"; import { DEFAULT_LOGGER, Logger } from "../relayFeeCalculator"; -import { AlephZeroQueries } from "./alephZero"; +import { CustomGasTokenQueries } from "./customGasToken"; /** * Some chains have a fixed gas price that is applied to the gas estimates. We should override @@ -31,30 +30,21 @@ export class QueryBase__factory { ): QueryBase { assert(isDefined(spokePoolAddress)); - if (chainIsMatic(chainId)) { - return new PolygonQueries( - provider, - symbolMapping, - spokePoolAddress, - simulatedRelayerAddress, - logger, - coingeckoProApiKey, - fixedGasPrice[chainId], - "usd" - ); - } - - if (chainIsAlephZero(chainId)) { - return new AlephZeroQueries( - provider, - symbolMapping, - spokePoolAddress, - simulatedRelayerAddress, - logger, - coingeckoProApiKey, - fixedGasPrice[chainId], - "usd" - ); + const customGasTokenSymbol = CUSTOM_GAS_TOKENS[chainId]; + if (customGasTokenSymbol) { + return new CustomGasTokenQueries({ + queryBaseArgs: [ + provider, + symbolMapping, + spokePoolAddress, + simulatedRelayerAddress, + logger, + coingeckoProApiKey, + fixedGasPrice[chainId], + "usd", + ], + customGasTokenSymbol, + }); } // For OPStack chains, we need to wrap the provider in an L2Provider diff --git a/src/relayFeeCalculator/chain-queries/index.ts b/src/relayFeeCalculator/chain-queries/index.ts index 26478090..49061c0f 100644 --- a/src/relayFeeCalculator/chain-queries/index.ts +++ b/src/relayFeeCalculator/chain-queries/index.ts @@ -1,3 +1,3 @@ export * from "./baseQuery"; -export * from "./polygon"; export * from "./factory"; +export * from "./customGasToken"; diff --git a/src/relayFeeCalculator/chain-queries/polygon.ts b/src/relayFeeCalculator/chain-queries/polygon.ts deleted file mode 100644 index 29e1fa07..00000000 --- a/src/relayFeeCalculator/chain-queries/polygon.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CHAIN_IDs } from "../../constants"; -import { Coingecko } from "../../coingecko/Coingecko"; -import { QueryBase } from "./baseQuery"; - -export class PolygonQueries extends QueryBase { - override async getTokenPrice(tokenSymbol: string): Promise { - if (!this.symbolMapping[tokenSymbol]) throw new Error(`${tokenSymbol} does not exist in mapping`); - const coingeckoInstance = Coingecko.get(this.logger, this.coingeckoProApiKey); - const [, tokenPrice] = await coingeckoInstance.getCurrentPriceByContract( - this.symbolMapping[tokenSymbol].addresses[CHAIN_IDs.MAINNET], - "usd" - ); - - const [, maticPrice] = await coingeckoInstance.getCurrentPriceByContract( - this.symbolMapping["MATIC"].addresses[CHAIN_IDs.MAINNET], - "usd" - ); - return Number((tokenPrice / maticPrice).toFixed(this.symbolMapping["MATIC"].decimals)); - } -} diff --git a/src/utils/Multicall.ts b/src/utils/Multicall.ts index bc82e2de..6efa4678 100644 --- a/src/utils/Multicall.ts +++ b/src/utils/Multicall.ts @@ -19,6 +19,7 @@ const DETERMINISTIC_MULTICALL_ADDRESS = "0xcA11bde05977b3631167028862bE2a173976C const NON_DETERMINISTIC_MULTICALL_ADDRESSES = { [CHAIN_IDs.ZK_SYNC]: "0xF9cda624FBC7e059355ce98a31693d299FACd963", + [CHAIN_IDs.LENS_SEPOLIA]: "0x8A44EDE8a6843a997bC0Cc4659e4dB1Da8f91116", }; // @notice Multicall3 is an OP stack preinstall, so don't specify it here. diff --git a/src/utils/NetworkUtils.ts b/src/utils/NetworkUtils.ts index 9adb4db9..56b21ae8 100644 --- a/src/utils/NetworkUtils.ts +++ b/src/utils/NetworkUtils.ts @@ -60,6 +60,15 @@ export function chainIsOPStack(chainId: number): boolean { return PUBLIC_NETWORKS[chainId]?.family === ChainFamily.OP_STACK; } +/** + * Determines whether a chain ID is a ZkStack implementation. + * @param chainId Chain ID to evaluate. + * @returns True if chainId is a ZkStack chain, otherwise false. + */ +export function chainIsZkStack(chainId: number): boolean { + return PUBLIC_NETWORKS[chainId]?.family === ChainFamily.ZK_STACK; +} + /** * Determines whether a chain ID is an Arbitrum Orbit implementation. * @param chainId Chain ID to evaluate. @@ -87,6 +96,15 @@ export function chainIsAlephZero(chainId: number): boolean { return [CHAIN_IDs.ALEPH_ZERO].includes(chainId); } +/** + * Determines whether a chain ID is a Lens implementation + * @param chainId Chain ID to evaluate + * @returns True if chainId is a Lens chain, otherwise false. + */ +export function chainIsLens(chainId: number): boolean { + return [CHAIN_IDs.LENS_SEPOLIA].includes(chainId); +} + /** * Determines whether a chain ID is a Linea implementation. * @param chainId Chain ID to evaluate. diff --git a/yarn.lock b/yarn.lock index fdb69ac3..55cf08ab 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16,15 +16,10 @@ "@uma/common" "^2.17.0" hardhat "^2.9.3" -"@across-protocol/constants@^3.1.24": - version "3.1.24" - resolved "https://registry.yarnpkg.com/@across-protocol/constants/-/constants-3.1.24.tgz#01fe49330bb467dd01813387ddbac741bc74a035" - integrity sha512-guKtvIbif//vsmSZbwGubTWVtfkWiyWenr2sVyo63U/68GOW89ceJRLu4efLjeLVGiSrNAJtFUCv9dTwrrosWA== - -"@across-protocol/constants@^3.1.25": - version "3.1.25" - resolved "https://registry.yarnpkg.com/@across-protocol/constants/-/constants-3.1.25.tgz#60d6d9814582ff91faf2b6d9f51d6dccb447b4ce" - integrity sha512-GpZoYn7hETYL2BPMM2GqXAer6+l/xuhder+pvpb00HJcb/sqCjF7vaaeKxjKJ3jKtyeulYmdu0NDkeNm5KbNWA== +"@across-protocol/constants@^3.1.27": + version "3.1.27" + resolved "https://registry.yarnpkg.com/@across-protocol/constants/-/constants-3.1.27.tgz#6c7b2b277d83ae1024c1de6faf474192391af0bd" + integrity sha512-3YEK2ERB2FVdDdrkFk5YeuRu/oIAHTIeu6YfT39SfZjIPyltP0ReFlDfZQ8c+rFiHurwyK39kjZF70VxRRREYw== "@across-protocol/contracts@^0.1.4": version "0.1.4" @@ -35,12 +30,12 @@ "@openzeppelin/contracts" "4.1.0" "@uma/core" "^2.18.0" -"@across-protocol/contracts@^3.0.19": - version "3.0.19" - resolved "https://registry.yarnpkg.com/@across-protocol/contracts/-/contracts-3.0.19.tgz#3756504bb3f5f625f9ca403045a79050e675602f" - integrity sha512-9GjKKF8SHGKP9FGhawHzLZ8sfBVFUICd+Bn1pn3SFuh0p+ndQIayG+QEYRKGFUXVPV6+XXLve750PQ1Hu7dIEg== +"@across-protocol/contracts@^3.0.20": + version "3.0.20" + resolved "https://registry.yarnpkg.com/@across-protocol/contracts/-/contracts-3.0.20.tgz#5a70782093d21a96b2e955b7ed725bea7af6e804" + integrity sha512-ufyO+MrbY7+0TDm/1cDl9iAeR4P8jt0AM1F9wiCBHVIYtj1wMD4eNm7G5Am3u8p1ruMjRhi6dJEVQcRF2O+LUg== dependencies: - "@across-protocol/constants" "^3.1.24" + "@across-protocol/constants" "^3.1.27" "@coral-xyz/anchor" "^0.30.1" "@defi-wonderland/smock" "^2.3.4" "@eth-optimism/contracts" "^0.5.40"