UNPKG

@layerzerolabs/hyperliquid-composer

Version:

LayerZero Labs reference EVM OmniChain Fungible Token (OFT) implementation for Hyperliquid

192 lines (160 loc) 6.77 kB
import { createModuleLogger, setDefaultLogLevel } from '@layerzerolabs/io-devtools' import { getERC20abi, writeCoreSpotDeployment } from '@/io' import { getSpotMeta, getHipTokenInfo, getSpotDeployState } from '@/operations' import { toAssetBridgeAddress } from '@/types' import type { CoreSpotDeployment, CoreSpotMetaData, SpotDeployStates, SpotInfo, TxData, UserGenesis, CoreSpotDeploymentArgs, TokenIndexArgs, SpotDeployStateArgs, } from '@/types' import { ethers } from 'ethers' import { RPC_URLS } from '@/types' import { LOGGER_MODULES } from '@/types/cli-constants' import inquirer from 'inquirer' export async function coreSpotDeployment(args: CoreSpotDeploymentArgs): Promise<void> { setDefaultLogLevel(args.logLevel) const logger = createModuleLogger(LOGGER_MODULES.CORE_SPOT_DEPLOYMENT, args.logLevel) const network = args.network const tokenIndex = args.tokenIndex const action = args.action const isTestnet = args.network === 'testnet' const coreSpot: CoreSpotMetaData = await getSpotMeta(null, isTestnet, args.logLevel, tokenIndex) if (action === 'create') { const { tokenAddress, tokenTxHash } = await inquirer.prompt([ { type: 'input', name: 'tokenAddress', message: 'Enter the token address', }, { type: 'input', name: 'tokenTxHash', message: 'Enter the token tx hash', }, ]) let shouldQuit = false const token_txHash = ethers.utils.isHexString(tokenTxHash) ? tokenTxHash : '' if (!token_txHash) { logger.error('Invalid token tx hash') shouldQuit = true } const token_address = ethers.utils.isAddress(tokenAddress) ? tokenAddress : '' if (!token_address) { logger.error('Invalid token address') shouldQuit = true } if (shouldQuit) { logger.info('Quitting...') process.exit(1) } const token_abi = await getERC20abi() if (!token_abi) { logger.error(`ERC20 abi not found for ${network}`) return } const provider = new ethers.providers.JsonRpcProvider({ url: RPC_URLS[network.toUpperCase()], skipFetchSetup: true, }) const tx = await provider.getTransaction(token_txHash) const nonce = tx?.nonce const from = tx?.from logger.verbose(`Nonce: ${nonce}, From: ${from}`) const contract = new ethers.Contract(token_address, token_abi, provider) const tokenName = await contract.name() const decimals = await contract.decimals() logger.verbose(`Token name: ${tokenName}, Decimals: ${decimals}`) const weiDiff = decimals - coreSpot.weiDecimals logger.verbose(`Wei diff: ${weiDiff}`) const assetBridgeAddress = toAssetBridgeAddress(parseInt(tokenIndex)) logger.verbose(`Asset bridge address: ${assetBridgeAddress}`) const txData: TxData = { txHash: token_txHash, nonce: nonce, from: from, weiDiff: weiDiff, assetBridgeAddress: assetBridgeAddress, connected: coreSpot.evmContract ? true : false, } logger.info('Populating userAndWei with the asset bridge address') const existingTokenAndWei: { token: number; wei: string }[] = [] const msg = 'Do you want to distribute some part of the genesis to the holders of an existing token (this is uncommon and optional)?' const { usingExistingTokenAndWei } = await inquirer.prompt([ { type: 'confirm', name: 'usingExistingTokenAndWei', message: `${msg} (y/N)`, }, ]) if (usingExistingTokenAndWei === 'y') { existingTokenAndWei.push({ token: 0, wei: '', }) } const userGenesis: UserGenesis = { userAndWei: [ { address: assetBridgeAddress, wei: '', }, ], existingTokenAndWei: existingTokenAndWei, blacklistUsers: [], } const coreSpotDeployment: CoreSpotDeployment = { coreSpot, txData, userGenesis, } writeCoreSpotDeployment(tokenIndex, isTestnet, coreSpotDeployment, logger) } else if (action === 'get') { logger.info(JSON.stringify(coreSpot, null, 2)) } } export async function hipTokenInfo(args: TokenIndexArgs): Promise<void> { setDefaultLogLevel(args.logLevel) const logger = createModuleLogger(LOGGER_MODULES.HIP_TOKEN_INFO, args.logLevel) const tokenIndex = args.tokenIndex const network = args.network const isTestnet = network === 'testnet' const coreSpot: CoreSpotMetaData = await getSpotMeta(null, isTestnet, args.logLevel, tokenIndex) const coreSpotInfo: SpotInfo = await getHipTokenInfo(null, isTestnet, args.logLevel, coreSpot.tokenId) logger.info(JSON.stringify(coreSpotInfo, null, 2)) } export async function spotDeployState(args: SpotDeployStateArgs): Promise<void> { setDefaultLogLevel(args.logLevel) const logger = createModuleLogger(LOGGER_MODULES.GET_DEPLOY_STATE, args.logLevel) const tokenIndex = args.tokenIndex const network = args.network const isTestnet = network === 'testnet' let deployerAddress: string if (args.deployerAddress) { deployerAddress = args.deployerAddress } else { const coreSpot: CoreSpotMetaData = await getSpotMeta(null, isTestnet, args.logLevel, tokenIndex) const coreSpotInfo: SpotInfo = await getHipTokenInfo(null, isTestnet, args.logLevel, coreSpot.tokenId) deployerAddress = coreSpotInfo.deployer logger.info( `Using deployer address: ${deployerAddress} for token ${coreSpotInfo.name} with index ${tokenIndex}` ) } const deployState = (await getSpotDeployState(deployerAddress, isTestnet, args.logLevel)) as SpotDeployStates logger.verbose(`All deployment states for ${deployerAddress}: ${JSON.stringify(deployState, null, 2)}`) // iterate through deployState and print out the one with the same "token" as tokenIndex const state = deployState.states.find((state) => state.token === parseInt(tokenIndex)) if (!state) { logger.error( `No in progress deployment state found for token ${tokenIndex}. This means that your token is deployed.` ) process.exit(1) } logger.info(JSON.stringify(state, null, 2)) }