From d76046366ae4aba045e02120741a66b7c0d4c5f6 Mon Sep 17 00:00:00 2001 From: 0xkenj1 <165053496+0xkenj1@users.noreply.github.com> Date: Mon, 12 Aug 2024 10:47:04 -0300 Subject: [PATCH] feat: baseTokens & chainIds (#43) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 🤖 Linear Closes ZKS-151 ZKS-152 ## Description - `getBaseTokens` - `getChainIds` - Removed `bridgehubAddress` & `sharedBridgeAddress` from `shared/constants.ts` - Add `bridgehubAddress` , `sharedBridgeAddress` & `stateTransitionManagerAddress` as parameters for `L1MetricsService` --- libs/metrics/src/l1/abis/index.ts | 1 + .../src/l1/abis/stateTransitionManager.abi.ts | 1329 +++++++++++++++++ libs/metrics/src/l1/l1MetricsService.ts | 110 +- libs/metrics/src/types/tvl.type.ts | 4 +- .../test/unit/l1/l1MetricsService.spec.ts | 320 ++-- libs/shared/src/constants/index.ts | 2 +- libs/shared/src/constants/l1.ts | 5 - .../{tokens/tokens.ts => constants/token.ts} | 117 +- libs/shared/src/types/index.ts | 1 + libs/shared/src/types/token.type.ts | 12 + libs/shared/src/utils/index.ts | 1 + libs/shared/src/utils/token.ts | 4 + 12 files changed, 1712 insertions(+), 194 deletions(-) create mode 100644 libs/metrics/src/l1/abis/stateTransitionManager.abi.ts delete mode 100644 libs/shared/src/constants/l1.ts rename libs/shared/src/{tokens/tokens.ts => constants/token.ts} (86%) create mode 100644 libs/shared/src/types/token.type.ts create mode 100644 libs/shared/src/utils/token.ts diff --git a/libs/metrics/src/l1/abis/index.ts b/libs/metrics/src/l1/abis/index.ts index a8c48ff..9700b77 100644 --- a/libs/metrics/src/l1/abis/index.ts +++ b/libs/metrics/src/l1/abis/index.ts @@ -1,3 +1,4 @@ export * from "./bridgeHub.abi"; export * from "./diamondProxy.abi"; export * from "./sharedBridge.abi"; +export * from "./stateTransitionManager.abi"; diff --git a/libs/metrics/src/l1/abis/stateTransitionManager.abi.ts b/libs/metrics/src/l1/abis/stateTransitionManager.abi.ts new file mode 100644 index 0000000..b01bfcb --- /dev/null +++ b/libs/metrics/src/l1/abis/stateTransitionManager.abi.ts @@ -0,0 +1,1329 @@ +export const stateTransitionManagerAbi = [ + { + inputs: [ + { + internalType: "address", + name: "_bridgehub", + type: "address", + }, + { + internalType: "uint256", + name: "_maxNumberOfHyperchains", + type: "uint256", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "uint8", + name: "version", + type: "uint8", + }, + ], + name: "Initialized", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldAdmin", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newAdmin", + type: "address", + }, + ], + name: "NewAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "genesisUpgrade", + type: "address", + }, + { + indexed: false, + internalType: "bytes32", + name: "genesisBatchHash", + type: "bytes32", + }, + { + indexed: false, + internalType: "uint64", + name: "genesisIndexRepeatedStorageChanges", + type: "uint64", + }, + { + indexed: false, + internalType: "bytes32", + name: "genesisBatchCommitment", + type: "bytes32", + }, + { + indexed: false, + internalType: "bytes32", + name: "newInitialCutHash", + type: "bytes32", + }, + ], + name: "NewChainCreationParams", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + indexed: true, + internalType: "address", + name: "_hyperchainContract", + type: "address", + }, + ], + name: "NewHyperchain", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldPendingAdmin", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newPendingAdmin", + type: "address", + }, + ], + name: "NewPendingAdmin", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "oldProtocolVersion", + type: "uint256", + }, + { + indexed: true, + internalType: "uint256", + name: "newProtocolVersion", + type: "uint256", + }, + ], + name: "NewProtocolVersion", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "uint256", + name: "protocolVersion", + type: "uint256", + }, + { + indexed: true, + internalType: "bytes32", + name: "upgradeCutHash", + type: "bytes32", + }, + ], + name: "NewUpgradeCutHash", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "oldValidatorTimelock", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newValidatorTimelock", + type: "address", + }, + ], + name: "NewValidatorTimelock", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferStarted", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "_hyperchain", + type: "address", + }, + { + components: [ + { + internalType: "uint256", + name: "txType", + type: "uint256", + }, + { + internalType: "uint256", + name: "from", + type: "uint256", + }, + { + internalType: "uint256", + name: "to", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "gasPerPubdataByteLimit", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "maxPriorityFeePerGas", + type: "uint256", + }, + { + internalType: "uint256", + name: "paymaster", + type: "uint256", + }, + { + internalType: "uint256", + name: "nonce", + type: "uint256", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256[4]", + name: "reserved", + type: "uint256[4]", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + { + internalType: "bytes", + name: "signature", + type: "bytes", + }, + { + internalType: "uint256[]", + name: "factoryDeps", + type: "uint256[]", + }, + { + internalType: "bytes", + name: "paymasterInput", + type: "bytes", + }, + { + internalType: "bytes", + name: "reservedDynamic", + type: "bytes", + }, + ], + indexed: false, + internalType: "struct L2CanonicalTransaction", + name: "_l2Transaction", + type: "tuple", + }, + { + indexed: true, + internalType: "uint256", + name: "_protocolVersion", + type: "uint256", + }, + ], + name: "SetChainIdUpgrade", + type: "event", + }, + { + inputs: [], + name: "BRIDGE_HUB", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "MAX_NUMBER_OF_HYPERCHAINS", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "acceptAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "acceptOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "admin", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + components: [ + { + internalType: "enum PubdataPricingMode", + name: "pubdataPricingMode", + type: "uint8", + }, + { + internalType: "uint32", + name: "batchOverheadL1Gas", + type: "uint32", + }, + { + internalType: "uint32", + name: "maxPubdataPerBatch", + type: "uint32", + }, + { + internalType: "uint32", + name: "maxL2GasPerBatch", + type: "uint32", + }, + { + internalType: "uint32", + name: "priorityTxMaxPubdata", + type: "uint32", + }, + { + internalType: "uint64", + name: "minimalL2GasPrice", + type: "uint64", + }, + ], + internalType: "struct FeeParams", + name: "_newFeeParams", + type: "tuple", + }, + ], + name: "changeFeeParams", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "address", + name: "_baseToken", + type: "address", + }, + { + internalType: "address", + name: "_sharedBridge", + type: "address", + }, + { + internalType: "address", + name: "_admin", + type: "address", + }, + { + internalType: "bytes", + name: "_diamondCut", + type: "bytes", + }, + ], + name: "createNewChain", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "_diamondCut", + type: "tuple", + }, + ], + name: "executeUpgrade", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + ], + name: "freezeChain", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "genesisUpgrade", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAllHyperchainChainIDs", + outputs: [ + { + internalType: "uint256[]", + name: "", + type: "uint256[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getAllHyperchains", + outputs: [ + { + internalType: "address[]", + name: "chainAddresses", + type: "address[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + ], + name: "getChainAdmin", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + ], + name: "getHyperchain", + outputs: [ + { + internalType: "address", + name: "chainAddress", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "getSemverProtocolVersion", + outputs: [ + { + internalType: "uint32", + name: "", + type: "uint32", + }, + { + internalType: "uint32", + name: "", + type: "uint32", + }, + { + internalType: "uint32", + name: "", + type: "uint32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "initialCutHash", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "validatorTimelock", + type: "address", + }, + { + components: [ + { + internalType: "address", + name: "genesisUpgrade", + type: "address", + }, + { + internalType: "bytes32", + name: "genesisBatchHash", + type: "bytes32", + }, + { + internalType: "uint64", + name: "genesisIndexRepeatedStorageChanges", + type: "uint64", + }, + { + internalType: "bytes32", + name: "genesisBatchCommitment", + type: "bytes32", + }, + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "diamondCut", + type: "tuple", + }, + ], + internalType: "struct ChainCreationParams", + name: "chainCreationParams", + type: "tuple", + }, + { + internalType: "uint256", + name: "protocolVersion", + type: "uint256", + }, + ], + internalType: "struct StateTransitionManagerInitializeData", + name: "_initializeData", + type: "tuple", + }, + ], + name: "initialize", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pendingOwner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "protocolVersion", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_protocolVersion", + type: "uint256", + }, + ], + name: "protocolVersionDeadline", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_protocolVersion", + type: "uint256", + }, + ], + name: "protocolVersionIsActive", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "address", + name: "_hyperchain", + type: "address", + }, + ], + name: "registerAlreadyDeployedHyperchain", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_newLastBatch", + type: "uint256", + }, + ], + name: "revertBatches", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + internalType: "address", + name: "genesisUpgrade", + type: "address", + }, + { + internalType: "bytes32", + name: "genesisBatchHash", + type: "bytes32", + }, + { + internalType: "uint64", + name: "genesisIndexRepeatedStorageChanges", + type: "uint64", + }, + { + internalType: "bytes32", + name: "genesisBatchCommitment", + type: "bytes32", + }, + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "diamondCut", + type: "tuple", + }, + ], + internalType: "struct ChainCreationParams", + name: "_chainCreationParams", + type: "tuple", + }, + ], + name: "setChainCreationParams", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "_cutData", + type: "tuple", + }, + { + internalType: "uint256", + name: "_oldProtocolVersion", + type: "uint256", + }, + { + internalType: "uint256", + name: "_oldProtocolVersionDeadline", + type: "uint256", + }, + { + internalType: "uint256", + name: "_newProtocolVersion", + type: "uint256", + }, + ], + name: "setNewVersionUpgrade", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_newPendingAdmin", + type: "address", + }, + ], + name: "setPendingAdmin", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "bool", + name: "_zkPorterIsAvailable", + type: "bool", + }, + ], + name: "setPorterAvailability", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_maxGasLimit", + type: "uint256", + }, + ], + name: "setPriorityTxMaxGasLimit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_protocolVersion", + type: "uint256", + }, + { + internalType: "uint256", + name: "_timestamp", + type: "uint256", + }, + ], + name: "setProtocolVersionDeadline", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "uint128", + name: "_nominator", + type: "uint128", + }, + { + internalType: "uint128", + name: "_denominator", + type: "uint128", + }, + ], + name: "setTokenMultiplier", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "_cutData", + type: "tuple", + }, + { + internalType: "uint256", + name: "_oldProtocolVersion", + type: "uint256", + }, + ], + name: "setUpgradeDiamondCut", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "address", + name: "_validator", + type: "address", + }, + { + internalType: "bool", + name: "_active", + type: "bool", + }, + ], + name: "setValidator", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "_validatorTimelock", + type: "address", + }, + ], + name: "setValidatorTimelock", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "storedBatchZero", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + ], + name: "unfreezeChain", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "_chainId", + type: "uint256", + }, + { + internalType: "uint256", + name: "_oldProtocolVersion", + type: "uint256", + }, + { + components: [ + { + components: [ + { + internalType: "address", + name: "facet", + type: "address", + }, + { + internalType: "enum Diamond.Action", + name: "action", + type: "uint8", + }, + { + internalType: "bool", + name: "isFreezable", + type: "bool", + }, + { + internalType: "bytes4[]", + name: "selectors", + type: "bytes4[]", + }, + ], + internalType: "struct Diamond.FacetCut[]", + name: "facetCuts", + type: "tuple[]", + }, + { + internalType: "address", + name: "initAddress", + type: "address", + }, + { + internalType: "bytes", + name: "initCalldata", + type: "bytes", + }, + ], + internalType: "struct Diamond.DiamondCutData", + name: "_diamondCut", + type: "tuple", + }, + ], + name: "upgradeChainFromVersion", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "protocolVersion", + type: "uint256", + }, + ], + name: "upgradeCutHash", + outputs: [ + { + internalType: "bytes32", + name: "cutHash", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "validatorTimelock", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, +] as const; diff --git a/libs/metrics/src/l1/l1MetricsService.ts b/libs/metrics/src/l1/l1MetricsService.ts index 67d34ca..8bc6548 100644 --- a/libs/metrics/src/l1/l1MetricsService.ts +++ b/libs/metrics/src/l1/l1MetricsService.ts @@ -17,26 +17,25 @@ import { InvalidChainType, L1MetricsServiceException, } from "@zkchainhub/metrics/exceptions"; -import { bridgeHubAbi, diamondProxyAbi, sharedBridgeAbi } from "@zkchainhub/metrics/l1/abis"; +import { + bridgeHubAbi, + diamondProxyAbi, + sharedBridgeAbi, + stateTransitionManagerAbi, +} from "@zkchainhub/metrics/l1/abis"; import { AssetTvl, GasInfo } from "@zkchainhub/metrics/types"; import { IPricingService, PRICING_PROVIDER } from "@zkchainhub/pricing"; import { EvmProviderService } from "@zkchainhub/providers"; -import { - BatchesInfo, - ChainId, - Chains, - ChainType, - L1_CONTRACTS, - vitalikAddress, -} from "@zkchainhub/shared"; -import { ETH_TOKEN_ADDRESS } from "@zkchainhub/shared/constants"; +import { BatchesInfo, ChainId, Chains, ChainType, vitalikAddress } from "@zkchainhub/shared"; import { erc20Tokens, - isNativeToken, + ETH_TOKEN_ADDRESS, nativeToken, tokens, WETH, -} from "@zkchainhub/shared/tokens/tokens"; +} from "@zkchainhub/shared/constants"; +import { Token } from "@zkchainhub/shared/types"; +import { isNativeToken } from "@zkchainhub/shared/utils"; const ONE_ETHER = parseEther("1"); @@ -45,17 +44,12 @@ const ONE_ETHER = parseEther("1"); */ @Injectable() export class L1MetricsService { - private readonly bridgeHub = { - abi: bridgeHubAbi, - address: L1_CONTRACTS.BRIDGE_HUB, - }; - private readonly sharedBridge = { - abi: sharedBridgeAbi, - address: L1_CONTRACTS.SHARED_BRIDGE, - }; private readonly diamondContracts: Map = new Map(); - + private chainIds?: ChainId[]; constructor( + private readonly bridgeHubAddress: Address, + private readonly sharedBridgeAddress: Address, + private readonly stateTransitionManagerAddresses: Address[], private readonly evmProviderService: EvmProviderService, @Inject(PRICING_PROVIDER) private readonly pricingService: IPricingService, @Inject(WINSTON_MODULE_NEST_PROVIDER) private readonly logger: LoggerService, @@ -66,7 +60,7 @@ export class L1MetricsService { * @returns A Promise that resolves to an array of AssetTvl objects representing the TVL for each asset. */ async l1Tvl(): Promise { - const erc20Addresses = erc20Tokens.map((token) => token.contractAddress); + const erc20Addresses = Object.values(erc20Tokens).map((token) => token.contractAddress); const balances = await this.fetchTokenBalances(erc20Addresses); const pricesRecord = await this.pricingService.getTokenPrices( @@ -141,13 +135,13 @@ export class L1MetricsService { address: tokenAddress, abi: erc20Abi, functionName: "balanceOf", - args: [this.sharedBridge.address], + args: [this.sharedBridgeAddress], } as const; }), ], allowFailure: false, }); - const ethBalance = await this.evmProviderService.getBalance(this.sharedBridge.address); + const ethBalance = await this.evmProviderService.getBalance(this.sharedBridgeAddress); assert(balances.length === addresses.length, "Invalid balances length"); @@ -192,7 +186,7 @@ export class L1MetricsService { * @returns A Promise that resolves to an array of AssetTvl objects representing the TVL for each asset. */ async tvl(chainId: ChainId): Promise { - const erc20Addresses = erc20Tokens.map((token) => token.contractAddress); + const erc20Addresses = Object.values(erc20Tokens).map((token) => token.contractAddress); const balances = await this.fetchTokenBalancesByChain(chainId, erc20Addresses); const pricesRecord = await this.pricingService.getTokenPrices( @@ -215,15 +209,15 @@ export class L1MetricsService { contracts: [ ...addresses.map((tokenAddress) => { return { - address: this.sharedBridge.address, - abi: this.sharedBridge.abi, + address: this.sharedBridgeAddress, + abi: sharedBridgeAbi, functionName: "chainBalance", args: [chainId, tokenAddress], } as const; }), { - address: this.sharedBridge.address, - abi: this.sharedBridge.abi, + address: this.sharedBridgeAddress, + abi: sharedBridgeAbi, functionName: "chainBalance", args: [chainId, ETH_TOKEN_ADDRESS], } as const, @@ -259,8 +253,8 @@ export class L1MetricsService { if (!diamondProxyAddress) { diamondProxyAddress = await this.evmProviderService.readContract( - this.bridgeHub.address, - this.bridgeHub.abi, + this.bridgeHubAddress, + bridgeHubAbi, "getHyperchain", [chainId], ); @@ -292,7 +286,7 @@ export class L1MetricsService { data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", - args: [L1_CONTRACTS.SHARED_BRIDGE, ONE_ETHER], + args: [this.sharedBridgeAddress, ONE_ETHER], }), }), // Get the current gas price. @@ -324,6 +318,58 @@ export class L1MetricsService { } } + /** + * Get the chainIds for the ecosystem + * @returns A list of chainIds + */ + async getChainIds(): Promise { + if (!this.chainIds) { + const chainIds = await this.evmProviderService.multicall({ + contracts: this.stateTransitionManagerAddresses.map((address) => { + return { + address, + abi: stateTransitionManagerAbi, + functionName: "getAllHyperchainChainIDs", + args: [], + } as const; + }), + allowFailure: false, + }); + this.chainIds = chainIds.flat(); + } + return this.chainIds; + } + /** + * Get the base token for each chain + * @returns A map of chainId to base token address + */ + async getBaseTokens(chainIds: ChainId[]): Promise[]> { + if (chainIds.length === 0) return []; + const baseTokens = await this.evmProviderService.multicall({ + contracts: chainIds.map((chainId) => { + return { + address: this.bridgeHubAddress, + abi: bridgeHubAbi, + functionName: "baseToken", + args: [chainId], + } as const; + }), + allowFailure: false, + }); + return baseTokens.map((baseToken) => { + return baseToken === ETH_TOKEN_ADDRESS + ? nativeToken + : erc20Tokens[baseToken] || { + contractAddress: baseToken, + decimals: 18, + name: "unknown", + type: "erc20", + symbol: "unknown", + coingeckoId: "unknown", + }; + }); + } + //TODO: Implement feeParams. async feeParams(_chainId: ChainId): Promise<{ batchOverheadL1Gas: number; diff --git a/libs/metrics/src/types/tvl.type.ts b/libs/metrics/src/types/tvl.type.ts index 1b59dda..c0fc73b 100644 --- a/libs/metrics/src/types/tvl.type.ts +++ b/libs/metrics/src/types/tvl.type.ts @@ -1,6 +1,6 @@ -import { TokenUnion } from "@zkchainhub/shared/tokens/tokens"; +import { Token, TokenType } from "@zkchainhub/shared"; -export type AssetTvl = Omit & { +export type AssetTvl = Omit, "coingeckoId"> & { amount: string; amountUsd: string; price: string; diff --git a/libs/metrics/test/unit/l1/l1MetricsService.spec.ts b/libs/metrics/test/unit/l1/l1MetricsService.spec.ts index 17089a1..573931c 100644 --- a/libs/metrics/test/unit/l1/l1MetricsService.spec.ts +++ b/libs/metrics/test/unit/l1/l1MetricsService.spec.ts @@ -2,7 +2,7 @@ import { createMock } from "@golevelup/ts-jest"; import { Logger } from "@nestjs/common"; import { Test, TestingModule } from "@nestjs/testing"; import { WINSTON_MODULE_PROVIDER } from "nest-winston"; -import { encodeFunctionData, erc20Abi, parseEther, zeroAddress } from "viem"; +import { Address, encodeFunctionData, erc20Abi, parseEther, zeroAddress } from "viem"; import { InvalidChainId, @@ -15,12 +15,16 @@ import { IPricingService, PRICING_PROVIDER } from "@zkchainhub/pricing"; import { EvmProviderService } from "@zkchainhub/providers"; import { BatchesInfo, + ChainId, ChainType, + erc20Tokens, ETH_TOKEN_ADDRESS, - L1_CONTRACTS, + nativeToken, + Token, + TokenType, vitalikAddress, + WETH, } from "@zkchainhub/shared"; -import { nativeToken, WETH } from "@zkchainhub/shared/tokens/tokens"; // Mock implementations of the dependencies const mockEvmProviderService = createMock(); @@ -28,31 +32,29 @@ const mockEvmProviderService = createMock(); const mockPricingService = createMock(); const ONE_ETHER = parseEther("1"); -jest.mock("@zkchainhub/shared/tokens/tokens", () => ({ - ...jest.requireActual("@zkchainhub/shared/tokens/tokens"), - get erc20Tokens() { - return [ - { - name: "USDC", - symbol: "USDC", - contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - coingeckoId: "usd-coin", - imageUrl: - "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694", - type: "erc20", - decimals: 6, - }, - { - name: "Wrapped BTC", - symbol: "WBTC", - contractAddress: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", - coingeckoId: "wrapped-bitcoin", - imageUrl: - "https://coin-images.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857", - type: "erc20", - decimals: 8, - }, - ]; +jest.mock("@zkchainhub/shared/constants/token", () => ({ + ...jest.requireActual("@zkchainhub/shared/constants/token"), + erc20Tokens: { + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": { + name: "USDC", + symbol: "USDC", + contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + coingeckoId: "usd-coin", + imageUrl: + "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694", + type: "erc20", + decimals: 6, + }, + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": { + name: "Wrapped BTC", + symbol: "WBTC", + contractAddress: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + coingeckoId: "wrapped-bitcoin", + imageUrl: + "https://coin-images.coingecko.com/coins/images/7598/large/wrapped_bitcoin_wbtc.png?1696507857", + type: "erc20", + decimals: 8, + }, }, get tokens() { return [ @@ -97,44 +99,64 @@ export const mockLogger: Partial = { debug: jest.fn(), }; +const mockMetricsModule = async ( + mockedBridgeHubAddress: Address, + mockedSharedBridgeAddress: Address, + mockedSTMAddresses: Address[], +) => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + L1MetricsService, + { + provide: L1MetricsService, + useFactory: ( + mockEvmProviderService: EvmProviderService, + mockPricingService: IPricingService, + logger: Logger, + ) => { + return new L1MetricsService( + mockedBridgeHubAddress, + mockedSharedBridgeAddress, + mockedSTMAddresses, + mockEvmProviderService, + mockPricingService, + logger, + ); + }, + inject: [EvmProviderService, PRICING_PROVIDER, WINSTON_MODULE_PROVIDER], + }, + { + provide: EvmProviderService, + useValue: mockEvmProviderService, + }, + { + provide: PRICING_PROVIDER, + useValue: mockPricingService, + }, + { + provide: WINSTON_MODULE_PROVIDER, + useValue: mockLogger, + }, + ], + }).compile(); + + return module.get(L1MetricsService); +}; + describe("L1MetricsService", () => { let l1MetricsService: L1MetricsService; - + const mockedBridgeHubAddress = "0x1234567890123456789012345678901234567890"; + const mockedSharedBridgeAddress = "0x1234567890123456789012345678901234567891"; + const mockedSTMAddresses: Address[] = [ + "0x1234567890123456789012345678901234567892", + "0x1234567890123456789012345678901234567893", + ]; beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [ - L1MetricsService, - { - provide: L1MetricsService, - useFactory: ( - mockEvmProviderService: EvmProviderService, - mockPricingService: IPricingService, - logger: Logger, - ) => { - return new L1MetricsService( - mockEvmProviderService, - mockPricingService, - logger, - ); - }, - inject: [EvmProviderService, PRICING_PROVIDER, WINSTON_MODULE_PROVIDER], - }, - { - provide: EvmProviderService, - useValue: mockEvmProviderService, - }, - { - provide: PRICING_PROVIDER, - useValue: mockPricingService, - }, - { - provide: WINSTON_MODULE_PROVIDER, - useValue: mockLogger, - }, - ], - }).compile(); - - l1MetricsService = module.get(L1MetricsService); + l1MetricsService = await mockMetricsModule( + mockedBridgeHubAddress, + mockedSharedBridgeAddress, + mockedSTMAddresses, + ); }); afterEach(() => { @@ -143,14 +165,9 @@ describe("L1MetricsService", () => { describe("constructor", () => { it("initialize bridgeHub and sharedBridge", () => { - expect(l1MetricsService["bridgeHub"]).toEqual({ - abi: bridgeHubAbi, - address: L1_CONTRACTS.BRIDGE_HUB, - }); - expect(l1MetricsService["sharedBridge"]).toEqual({ - abi: sharedBridgeAbi, - address: L1_CONTRACTS.SHARED_BRIDGE, - }); + expect(l1MetricsService["bridgeHubAddress"]).toEqual(mockedBridgeHubAddress); + expect(l1MetricsService["sharedBridgeAddress"]).toEqual(mockedSharedBridgeAddress); + expect(l1MetricsService["stateTransitionManagerAddresses"]).toEqual(mockedSTMAddresses); }); it("initialize diamondContracts map as empty", () => { @@ -217,19 +234,19 @@ describe("L1MetricsService", () => { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", abi: erc20Abi, functionName: "balanceOf", - args: [L1_CONTRACTS.SHARED_BRIDGE], + args: [l1MetricsService["sharedBridgeAddress"]], }, { address: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", abi: erc20Abi, functionName: "balanceOf", - args: [L1_CONTRACTS.SHARED_BRIDGE], + args: [l1MetricsService["sharedBridgeAddress"]], }, ], allowFailure: false, }); expect(mockEvmProviderService.getBalance).toHaveBeenCalledWith( - L1_CONTRACTS.SHARED_BRIDGE, + l1MetricsService["sharedBridgeAddress"], ); expect(mockPricingService.getTokenPrices).toHaveBeenCalledWith([ "ethereum", @@ -340,10 +357,10 @@ describe("L1MetricsService", () => { mockedDiamondProxyAddress, ); expect(mockEvmProviderService.readContract).toHaveBeenCalledWith( - l1MetricsService["bridgeHub"].address, - l1MetricsService["bridgeHub"].abi, + l1MetricsService["bridgeHubAddress"], + bridgeHubAbi, "getHyperchain", - [BigInt(chainId)], + [chainId], ); expect(mockEvmProviderService.multicall).toHaveBeenCalledWith({ contracts: [ @@ -404,10 +421,10 @@ describe("L1MetricsService", () => { mockedDiamondProxyAddress, ); expect(mockEvmProviderService.readContract).toHaveBeenCalledWith( - l1MetricsService["bridgeHub"].address, - l1MetricsService["bridgeHub"].abi, + l1MetricsService["bridgeHubAddress"], + bridgeHubAbi, "getHyperchain", - [BigInt(chainId)], + [chainId], ); }); }); @@ -465,22 +482,22 @@ describe("L1MetricsService", () => { expect(mockEvmProviderService.multicall).toHaveBeenCalledWith({ contracts: [ { - address: L1_CONTRACTS.SHARED_BRIDGE, + address: l1MetricsService["sharedBridgeAddress"], abi: sharedBridgeAbi, functionName: "chainBalance", - args: [BigInt(chainId), "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], + args: [chainId, "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], }, { - address: L1_CONTRACTS.SHARED_BRIDGE, + address: l1MetricsService["sharedBridgeAddress"], abi: sharedBridgeAbi, functionName: "chainBalance", - args: [BigInt(chainId), "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"], + args: [chainId, "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599"], }, { - address: L1_CONTRACTS.SHARED_BRIDGE, + address: l1MetricsService["sharedBridgeAddress"], abi: sharedBridgeAbi, functionName: "chainBalance", - args: [BigInt(chainId), ETH_TOKEN_ADDRESS], + args: [chainId, ETH_TOKEN_ADDRESS], }, ], allowFailure: false, @@ -595,7 +612,7 @@ describe("L1MetricsService", () => { data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", - args: [L1_CONTRACTS.SHARED_BRIDGE, ONE_ETHER], + args: [l1MetricsService["sharedBridgeAddress"], ONE_ETHER], }), }); @@ -644,7 +661,7 @@ describe("L1MetricsService", () => { data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", - args: [L1_CONTRACTS.SHARED_BRIDGE, ONE_ETHER], + args: [l1MetricsService["sharedBridgeAddress"], ONE_ETHER], }), }); @@ -706,7 +723,7 @@ describe("L1MetricsService", () => { data: encodeFunctionData({ abi: erc20Abi, functionName: "transfer", - args: [L1_CONTRACTS.SHARED_BRIDGE, ONE_ETHER], + args: [l1MetricsService["sharedBridgeAddress"], ONE_ETHER], }), }); @@ -716,6 +733,131 @@ describe("L1MetricsService", () => { }); }); + describe("getChainIds", () => { + it("returns chainIds", async () => { + true && true; + l1MetricsService = await mockMetricsModule( + mockedBridgeHubAddress, + mockedSharedBridgeAddress, + mockedSTMAddresses, + ); + const mockedMulticallReturnValue = [ + [1n, 2n, 3n], + [4n, 5n, 6n], + ]; + jest.spyOn(mockEvmProviderService, "multicall").mockResolvedValue( + mockedMulticallReturnValue, + ); + + const result = await l1MetricsService.getChainIds(); + + expect(result).toEqual(mockedMulticallReturnValue.flat()); + expect(l1MetricsService["chainIds"]).toEqual(mockedMulticallReturnValue.flat()); + }); + it("returns chainIds previously setted up", async () => { + const mockedChainIds = [1n, 2n, 3n, 4n, 5n]; + l1MetricsService = await mockMetricsModule( + mockedBridgeHubAddress, + mockedSharedBridgeAddress, + mockedSTMAddresses, + ); + l1MetricsService["chainIds"] = mockedChainIds; + + const result = await l1MetricsService.getChainIds(); + + expect(result).toEqual(mockedChainIds); + }); + it("returns empty array if chainIds are empty", async () => { + const mockedChainIds: bigint[] = []; + l1MetricsService = await mockMetricsModule( + mockedBridgeHubAddress, + mockedSharedBridgeAddress, + mockedSTMAddresses, + ); + l1MetricsService["chainIds"] = mockedChainIds; + + const result = await l1MetricsService.getChainIds(); + + expect(result).toEqual(mockedChainIds); + }); + it("throws if multicall throws", async () => { + jest.spyOn(mockEvmProviderService, "multicall").mockRejectedValue(new Error()); + await expect(l1MetricsService.getChainIds()).rejects.toThrow(Error); + }); + }); + + describe("getBaseTokens", () => { + it("returns known tokens", async () => { + const mockedChainIds = [1n, 2n]; + const knownTokenAddress1 = Object.keys(erc20Tokens)[0]; + const knownTokenAddress2 = Object.keys(erc20Tokens)[0]; + + if (!knownTokenAddress1 || !knownTokenAddress2) { + throw new Error("ERC20 tokens are not defined"); + } + const mockedMulticallReturnValue = [knownTokenAddress1, knownTokenAddress2]; + jest.spyOn(mockEvmProviderService, "multicall").mockResolvedValue( + mockedMulticallReturnValue, + ); + const mockedReturnData: Token[] = [ + erc20Tokens[knownTokenAddress1 as Address] as Token<"erc20">, + erc20Tokens[knownTokenAddress2 as Address] as Token<"erc20">, + ]; + + const result = await l1MetricsService.getBaseTokens(mockedChainIds); + + expect(result).toEqual(mockedReturnData); + }); + + it("returns unknown tokens", async () => { + const mockedChainIds = [1n, 2n]; + const mockedMulticallReturnValue = [ + "0x1234567890123456789012345678901234567123", + "0x1234567890123456789012345678901234567345", + ]; + jest.spyOn(mockEvmProviderService, "multicall").mockResolvedValue( + mockedMulticallReturnValue, + ); + const mockedReturnData: Token[] = [ + { + contractAddress: "0x1234567890123456789012345678901234567123", + symbol: "unknown", + name: "unknown", + decimals: 18, + type: "erc20", + coingeckoId: "unknown", + }, + { + contractAddress: "0x1234567890123456789012345678901234567345", + symbol: "unknown", + name: "unknown", + decimals: 18, + type: "erc20", + coingeckoId: "unknown", + }, + ]; + + const result = await l1MetricsService.getBaseTokens(mockedChainIds); + + expect(result).toEqual(mockedReturnData); + }); + it("returns empty array if chainIds is empty", async () => { + const mockedChainIds: ChainId[] = []; + const result = await l1MetricsService.getBaseTokens(mockedChainIds); + expect(result).toEqual([]); + }); + it("throws if multicall fails", async () => { + const mockedChainIds: ChainId[] = [1n, 2n]; + jest.spyOn(mockEvmProviderService, "multicall").mockRejectedValue(new Error()); + await expect(l1MetricsService.getBaseTokens(mockedChainIds)).rejects.toThrow(Error); + }); + it("returns eth token", async () => { + const mockedChainIds: ChainId[] = [1n, 2n]; + jest.spyOn(mockEvmProviderService, "multicall").mockRejectedValue(new Error()); + await expect(l1MetricsService.getBaseTokens(mockedChainIds)).rejects.toThrow(Error); + }); + }); + describe("feeParams", () => { it("return feeParams", async () => { const result = await l1MetricsService.feeParams(1n); diff --git a/libs/shared/src/constants/index.ts b/libs/shared/src/constants/index.ts index 4016c2e..fc76fca 100644 --- a/libs/shared/src/constants/index.ts +++ b/libs/shared/src/constants/index.ts @@ -1,4 +1,4 @@ -export * from "./l1"; export * from "./addresses"; +export * from "./token"; export const TOKEN_CACHE_TTL_IN_SEC = 60; export const BASE_CURRENCY = "usd"; diff --git a/libs/shared/src/constants/l1.ts b/libs/shared/src/constants/l1.ts deleted file mode 100644 index b1edade..0000000 --- a/libs/shared/src/constants/l1.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const L1_CONTRACTS = { - BRIDGE_HUB: "0x303a465B659cBB0ab36eE643eA362c509EEb5213", - DIAMOND_PROXY: "0x32400084C286CF3E17e7B677ea9583e60a000324", - SHARED_BRIDGE: "0xD7f9f54194C633F36CCD5F3da84ad4a1c38cB2cB", -} as const; diff --git a/libs/shared/src/tokens/tokens.ts b/libs/shared/src/constants/token.ts similarity index 86% rename from libs/shared/src/tokens/tokens.ts rename to libs/shared/src/constants/token.ts index 0a206ee..87c7070 100644 --- a/libs/shared/src/tokens/tokens.ts +++ b/libs/shared/src/constants/token.ts @@ -10,17 +10,7 @@ import { Address } from "abitype"; -export type Token = { - name: string; - symbol: string; - coingeckoId: string; - type: TokenType; - contractAddress: TokenType extends "erc20" ? Address : null; - decimals: number; - imageUrl?: string; -}; - -export type TokenUnion = Token<"erc20"> | Token<"native">; +import { Token, TokenType } from "@zkchainhub/shared/types"; export const nativeToken: Readonly> = { name: "Ethereum", @@ -42,8 +32,8 @@ export const WETH: Readonly> = { decimals: 18, }; -export const erc20Tokens: Readonly[]> = [ - { +export const erc20Tokens: Readonly>> = { + "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48": { name: "USDC", symbol: "USDC", contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", @@ -52,7 +42,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 6, }, - { + "0x9D14BcE1dADdf408d77295BB1be9b343814f44DE": { name: "Koi", symbol: "KOI", contractAddress: "0x9D14BcE1dADdf408d77295BB1be9b343814f44DE", @@ -62,7 +52,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xdAC17F958D2ee523a2206206994597C13D831ec7": { name: "Tether USD", symbol: "USDT", contractAddress: "0xdAC17F958D2ee523a2206206994597C13D831ec7", @@ -71,7 +61,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 6, }, - { + "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599": { name: "Wrapped BTC", symbol: "WBTC", contractAddress: "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", @@ -81,7 +71,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 8, }, - { + "0x77F76483399Dc6328456105B1db23e2Aca455bf9": { name: "HYCO", symbol: "HYCO", contractAddress: "0x77F76483399Dc6328456105B1db23e2Aca455bf9", @@ -91,7 +81,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xae78736Cd615f374D3085123A210448E74Fc6393": { name: "Rocket Pool ETH", symbol: "rETH", contractAddress: "0xae78736Cd615f374D3085123A210448E74Fc6393", @@ -100,7 +90,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xF9c53268e9de692AE1b2ea5216E24e1c3ad7CB1E": { name: "Idexo Token", symbol: "IDO", contractAddress: "0xF9c53268e9de692AE1b2ea5216E24e1c3ad7CB1E", @@ -110,7 +100,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x6B175474E89094C44Da98b954EedeAC495271d0F": { name: "Dai Stablecoin", symbol: "DAI", contractAddress: "0x6B175474E89094C44Da98b954EedeAC495271d0F", @@ -120,7 +110,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x5F64Ab1544D28732F0A24F4713c2C8ec0dA089f0": { name: "DEXTF Token", symbol: "DEXTF", contractAddress: "0x5F64Ab1544D28732F0A24F4713c2C8ec0dA089f0", @@ -130,7 +120,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xeEAA40B28A2d1b0B08f6f97bB1DD4B75316c6107": { name: "GOVI", symbol: "GOVI", contractAddress: "0xeEAA40B28A2d1b0B08f6f97bB1DD4B75316c6107", @@ -139,7 +129,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0": { name: "LUSD Stablecoin", symbol: "LUSD", contractAddress: "0x5f98805A4E8be255a32880FDeC7F6728C6568bA0", @@ -149,7 +139,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x6982508145454Ce325dDbE47a25d4ec3d2311933": { name: "Pepe", symbol: "PEPE", contractAddress: "0x6982508145454Ce325dDbE47a25d4ec3d2311933", @@ -159,7 +149,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xd38BB40815d2B0c2d2c866e0c72c5728ffC76dd9": { name: "Symbiosis", symbol: "SIS", contractAddress: "0xd38BB40815d2B0c2d2c866e0c72c5728ffC76dd9", @@ -169,7 +159,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xDDdddd4301A082e62E84e43F474f044423921918": { name: "DeversiFi Token", symbol: "DVF", contractAddress: "0xDDdddd4301A082e62E84e43F474f044423921918", @@ -179,7 +169,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704": { name: "Coinbase Wrapped Staked ETH", symbol: "cbETH", contractAddress: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", @@ -188,7 +178,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xBBBbbBBB46A1dA0F0C3F64522c275BAA4C332636": { name: "ZKBase", symbol: "ZKB", contractAddress: "0xBBBbbBBB46A1dA0F0C3F64522c275BAA4C332636", @@ -198,7 +188,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xD31a59c85aE9D8edEFeC411D448f90841571b89c": { name: "Wrapped SOL (Wormhole)", symbol: "SOL", contractAddress: "0xD31a59c85aE9D8edEFeC411D448f90841571b89c", @@ -208,7 +198,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 9, }, - { + "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC": { name: "Storj", symbol: "STORJ", contractAddress: "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC", @@ -217,7 +207,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2": { name: "Wrapped Ether", symbol: "WETH", contractAddress: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", @@ -226,7 +216,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x582d872A1B094FC48F5DE31D3B73F2D9bE47def1": { name: "Wrapped TON Coin", symbol: "TONCOIN", contractAddress: "0x582d872A1B094FC48F5DE31D3B73F2D9bE47def1", @@ -236,7 +226,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 9, }, - { + "0xfAC77A24E52B463bA9857d6b758ba41aE20e31FF": { name: "LSD Coin", symbol: "LSD", contractAddress: "0xfAC77A24E52B463bA9857d6b758ba41aE20e31FF", @@ -245,7 +235,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E": { name: "Curve.Fi USD Stablecoin", symbol: "crvUSD", contractAddress: "0xf939E0A03FB07F59A73314E73794Be0E57ac1b4E", @@ -255,7 +245,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0": { name: "Wrapped liquid staked Ether 2.0", symbol: "wstETH", contractAddress: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", @@ -265,7 +255,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE": { name: "SHIBA INU", symbol: "SHIB", contractAddress: "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", @@ -274,7 +264,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xA91ac63D040dEB1b7A5E4d4134aD23eb0ba07e14": { name: "Bella", symbol: "BEL", contractAddress: "0xA91ac63D040dEB1b7A5E4d4134aD23eb0ba07e14", @@ -283,7 +273,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x111111111117dC0aa78b770fA6A738034120C302": { name: "1INCH Token", symbol: "1INCH", contractAddress: "0x111111111117dC0aa78b770fA6A738034120C302", @@ -293,7 +283,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xA487bF43cF3b10dffc97A9A744cbB7036965d3b9": { name: "Deri", symbol: "DERI", contractAddress: "0xA487bF43cF3b10dffc97A9A744cbB7036965d3b9", @@ -303,7 +293,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x163f8C2467924be0ae7B5347228CABF260318753": { name: "Worldcoin", symbol: "WLD", contractAddress: "0x163f8C2467924be0ae7B5347228CABF260318753", @@ -313,7 +303,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x7448c7456a97769F6cD04F1E83A4a23cCdC46aBD": { name: "Maverick Token", symbol: "MAV", contractAddress: "0x7448c7456a97769F6cD04F1E83A4a23cCdC46aBD", @@ -323,7 +313,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xa41d2f8Ee4F47D3B860A149765A7dF8c3287b7F0": { name: "Syncus", symbol: "SYNC", contractAddress: "0xa41d2f8Ee4F47D3B860A149765A7dF8c3287b7F0", @@ -333,7 +323,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xC91a71A1fFA3d8B22ba615BA1B9c01b2BBBf55ad": { name: "ZigZag", symbol: "ZZ", contractAddress: "0xC91a71A1fFA3d8B22ba615BA1B9c01b2BBBf55ad", @@ -342,7 +332,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x18084fbA666a33d37592fA2633fD49a74DD93a88": { name: "tBTC v2", symbol: "tBTC", contractAddress: "0x18084fbA666a33d37592fA2633fD49a74DD93a88", @@ -352,7 +342,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7": { name: "rsETH", symbol: "rsETH", contractAddress: "0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7", @@ -362,7 +352,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x0a77eF9bf662D62Fbf9BA4cf861EaA83F9CC4FEC": { name: "XWG", symbol: "XWG", contractAddress: "0x0a77eF9bf662D62Fbf9BA4cf861EaA83F9CC4FEC", @@ -372,7 +362,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x72e364F2ABdC788b7E918bc238B21f109Cd634D7": { name: "Metaverse Index", symbol: "MVI", contractAddress: "0x72e364F2ABdC788b7E918bc238B21f109Cd634D7", @@ -382,7 +372,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x514910771AF9Ca656af840dff83E8264EcF986CA": { name: "ChainLink Token", symbol: "LINK", contractAddress: "0x514910771AF9Ca656af840dff83E8264EcF986CA", @@ -392,7 +382,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9": { name: "Aave Token", symbol: "AAVE", contractAddress: "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", @@ -402,7 +392,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x5C1d9aA868a30795F92fAe903eDc9eFF269044bf": { name: "Changer", symbol: "CNG", contractAddress: "0x5C1d9aA868a30795F92fAe903eDc9eFF269044bf", @@ -411,7 +401,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x88dF592F8eb5D7Bd38bFeF7dEb0fBc02cf3778a0": { name: "Tellor Tributes", symbol: "TRB", contractAddress: "0x88dF592F8eb5D7Bd38bFeF7dEb0fBc02cf3778a0", @@ -421,7 +411,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110": { name: "Renzo Restaked ETH", symbol: "Renzo Restaked ETH", contractAddress: "0xbf5495Efe5DB9ce00f80364C8B423567e58d2110", @@ -431,7 +421,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0": { name: "Matic Token", symbol: "MATIC", contractAddress: "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", @@ -441,7 +431,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x4691937a7508860F876c9c0a2a617E7d9E945D4B": { name: "WOO", symbol: "WOO", contractAddress: "0x4691937a7508860F876c9c0a2a617E7d9E945D4B", @@ -451,7 +441,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0x62D0A8458eD7719FDAF978fe5929C6D342B0bFcE": { name: "Beam", symbol: "BEAM", contractAddress: "0x62D0A8458eD7719FDAF978fe5929C6D342B0bFcE", @@ -461,7 +451,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xC9fE6E1C76210bE83DC1B5b20ec7FD010B0b1D15": { name: "Fringe", symbol: "FRIN", contractAddress: "0xC9fE6E1C76210bE83DC1B5b20ec7FD010B0b1D15", @@ -470,7 +460,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xfFffFffF2ba8F66D4e51811C5190992176930278": { name: "Furucombo", symbol: "COMBO", contractAddress: "0xfFffFffF2ba8F66D4e51811C5190992176930278", @@ -480,7 +470,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa": { name: "mETH", symbol: "mETH", contractAddress: "0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa", @@ -490,7 +480,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xe2353069f71a27bBbe66eEabfF05dE109c7d5E19": { name: "Bonsai3", symbol: "SEED", contractAddress: "0xe2353069f71a27bBbe66eEabfF05dE109c7d5E19", @@ -500,7 +490,7 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, - { + "0xD33526068D116cE69F19A9ee46F0bd304F21A51f": { name: "Rocket Pool", symbol: "RPL", contractAddress: "0xD33526068D116cE69F19A9ee46F0bd304F21A51f", @@ -510,9 +500,6 @@ export const erc20Tokens: Readonly[]> = [ type: "erc20", decimals: 18, }, -]; - -export const tokens: Readonly = [nativeToken, ...erc20Tokens]; +}; -export const isNativeToken = (token: TokenUnion): token is Token<"native"> => - token.type === "native"; +export const tokens: Readonly[]> = [nativeToken, Object(erc20Tokens).values]; diff --git a/libs/shared/src/types/index.ts b/libs/shared/src/types/index.ts index 4a63843..6ab96bb 100644 --- a/libs/shared/src/types/index.ts +++ b/libs/shared/src/types/index.ts @@ -1,3 +1,4 @@ export * from "./rollup.type"; export * from "./utils.type"; export * from "./l1.type"; +export * from "./token.type"; diff --git a/libs/shared/src/types/token.type.ts b/libs/shared/src/types/token.type.ts new file mode 100644 index 0000000..2849ea1 --- /dev/null +++ b/libs/shared/src/types/token.type.ts @@ -0,0 +1,12 @@ +import { Address } from "abitype"; + +export type TokenType = "erc20" | "native"; +export type Token = { + name: string; + symbol: string; + coingeckoId: string; + type: T; + contractAddress: T extends "erc20" ? Address : null; + decimals: number; + imageUrl?: string; +}; diff --git a/libs/shared/src/utils/index.ts b/libs/shared/src/utils/index.ts index e69de29..2503d5b 100644 --- a/libs/shared/src/utils/index.ts +++ b/libs/shared/src/utils/index.ts @@ -0,0 +1 @@ +export * from "./token"; diff --git a/libs/shared/src/utils/token.ts b/libs/shared/src/utils/token.ts new file mode 100644 index 0000000..f4a86ff --- /dev/null +++ b/libs/shared/src/utils/token.ts @@ -0,0 +1,4 @@ +import { Token, TokenType } from "@zkchainhub/shared/types"; + +export const isNativeToken = (token: Token): token is Token<"native"> => + token.type === "native";