diff --git a/.eslintrc.js b/.eslintrc.js index 4b61def37..8156c11f4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -34,6 +34,7 @@ module.exports = { // Disable warnings for { a, b, ...rest } variables, since this is typically used to remove variables. "@typescript-eslint/no-unused-vars": ["error", { ignoreRestSiblings: true }], "chai-expect/missing-assertion": 2, + "no-duplicate-imports": "error", }, settings: { node: { diff --git a/index.ts b/index.ts index 63064dc92..9dec9d333 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,16 @@ import minimist from "minimist"; import { CommonConfig } from "./src/common"; -import { AnyObject, config, delay, getSigner, help, Logger, processCrash, usage, winston } from "./src/utils"; +import { + AnyObject, + config, + delay, + retrieveSignerFromCLIArgs, + help, + Logger, + processCrash, + usage, + winston, +} from "./src/utils"; import { runRelayer } from "./src/relayer"; import { runDataworker } from "./src/dataworker"; import { runMonitor } from "./src/monitor"; @@ -37,7 +47,7 @@ export async function run(args: { [k: string]: boolean | string }): Promise/dev/null && rm -r \"${dir}_\" &", "reinstall": "yarn clean && yarn install && yarn build", "update": "git pull && yarn reinstall && yarn version --non-interactive && git show --quiet", - "relay": "HARDHAT_CONFIG=./dist/hardhat.config.js node ./dist/index.js --relayer" + "relay": "HARDHAT_CONFIG=./dist/hardhat.config.js node ./dist/index.js --relayer", + "deposit": "yarn ts-node ./scripts/spokepool.ts deposit" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", diff --git a/scripts/constructEmergencyRoot.ts b/scripts/constructEmergencyRoot.ts index b0f940e6d..ecdab0e0f 100644 --- a/scripts/constructEmergencyRoot.ts +++ b/scripts/constructEmergencyRoot.ts @@ -1,7 +1,7 @@ import { PoolRebalanceLeaf } from "../src/interfaces"; import { ethers, - getSigner, + retrieveSignerFromCLIArgs, RelayerRefundLeaf, MerkleTree, buildRelayerRefundTree, @@ -33,7 +33,7 @@ function prettyPoolRebalanceLeaf(leaves: PoolRebalanceLeaf[]) { } // This script can be used to generate a manual merkle root and is filled with example data. export async function run(): Promise { - const baseSigner = await getSigner(); + const baseSigner = await retrieveSignerFromCLIArgs(); // 1. Construct relayer refund leaves const relayerRefundLeaves: RelayerRefundLeaf[] = [ diff --git a/scripts/disableDepositRoutes.ts b/scripts/disableDepositRoutes.ts index c993f568a..63d46a233 100644 --- a/scripts/disableDepositRoutes.ts +++ b/scripts/disableDepositRoutes.ts @@ -1,5 +1,5 @@ /* eslint-disable no-process-exit */ -import { getSigner, winston, Logger, assert } from "../src/utils"; +import { retrieveSignerFromCLIArgs, winston, Logger, assert } from "../src/utils"; import { CommonConfig, constructClients, constructSpokePoolClientsWithStartBlocks, updateClients } from "../src/common"; import minimist from "minimist"; @@ -19,7 +19,7 @@ export async function run(logger: winston.Logger): Promise { message: "Constructing data to disable all deposits to or from the following chains", chainsToDisable, }); - const baseSigner = await getSigner(); + const baseSigner = await retrieveSignerFromCLIArgs(); const config = new CommonConfig(process.env); // Get all deposit routes involving chainId and token diff --git a/scripts/sendTokens.ts b/scripts/sendTokens.ts index febb08946..8661ddaba 100644 --- a/scripts/sendTokens.ts +++ b/scripts/sendTokens.ts @@ -1,4 +1,4 @@ -import { ethers, getSigner, getProvider, ERC20, ZERO_ADDRESS, toBN, getGasPrice } from "../src/utils"; +import { ethers, retrieveSignerFromCLIArgs, getProvider, ERC20, ZERO_ADDRESS, toBN, getGasPrice } from "../src/utils"; import { askYesNoQuestion } from "./utils"; import minimist from "minimist"; const args = minimist(process.argv.slice(2), { @@ -27,7 +27,7 @@ export async function run(): Promise { if (!Object.keys(args).includes("chainId")) { throw new Error("Define `chainId` as the chain you want to connect on"); } - const baseSigner = await getSigner(); + const baseSigner = await retrieveSignerFromCLIArgs(); const connectedSigner = baseSigner.connect(await getProvider(Number(args.chainId))); console.log("Connected to account", connectedSigner.address); const recipient = args.to; diff --git a/scripts/spokepool.ts b/scripts/spokepool.ts new file mode 100644 index 000000000..c6e284328 --- /dev/null +++ b/scripts/spokepool.ts @@ -0,0 +1,343 @@ +import assert from "assert"; +import * as contracts from "@across-protocol/contracts-v2"; +import { LogDescription } from "@ethersproject/abi"; +import { Contract, ethers, Wallet } from "ethers"; +import minimist from "minimist"; +import { groupBy } from "lodash"; +import { config } from "dotenv"; +import { getDeployedContract, getNetworkName, getNodeUrlList, getSigner, resolveTokenSymbols } from "../src/utils"; + +type ERC20 = { + address: string; + decimals: number; + symbol: string; +}; + +const { MaxUint256, Zero } = ethers.constants; +const { isAddress } = ethers.utils; + +const testChains = [5, 280]; +const chains = [1, 10, 137, 324, 8453, 42161]; + +function validateChainIds(chainIds: number[]): boolean { + const knownChainIds = [...chains, ...testChains]; + return chainIds.every((chainId) => { + const ok = knownChainIds.includes(chainId); + if (!ok) { + console.log(`Invalid chain ID: ${chainId}`); + } + return ok; + }); +} + +function printDeposit(log: LogDescription): void { + const { originChainId, originToken } = log.args; + const eventArgs = Object.keys(log.args).filter((key) => isNaN(Number(key))); + const padLeft = eventArgs.reduce((acc, cur) => (cur.length > acc ? cur.length : acc), 0); + + const fields = { + tokenSymbol: resolveTokenSymbols([originToken], originChainId)[0], + ...Object.fromEntries(eventArgs.map((key) => [key, log.args[key]])), + }; + console.log( + `Deposit # ${log.args.depositId} on ${getNetworkName(originChainId)}:\n` + + Object.entries(fields) + .map(([k, v]) => `\t${k.padEnd(padLeft)} : ${v}`) + .join("\n") + + "\n" + ); +} + +function printFill(log: LogDescription): void { + const { originChainId, destinationChainId, destinationToken, amount, totalFilledAmount } = log.args; + const eventArgs = Object.keys(log.args).filter((key) => isNaN(Number(key))); + const padLeft = eventArgs.reduce((acc, cur) => (cur.length > acc ? cur.length : acc), 0); + + const fields = { + tokenSymbol: resolveTokenSymbols([destinationToken], destinationChainId)[0], + totalFilledPct: `${totalFilledAmount.mul(100).div(amount)} %`, + ...Object.fromEntries(eventArgs.map((key) => [key, log.args[key]])), + }; + console.log( + `Fill for ${getNetworkName(originChainId)} deposit # ${log.args.depositId}:\n` + + Object.entries(fields) + .map(([k, v]) => `\t${k.padEnd(padLeft)} : ${v}`) + .join("\n") + + "\n" + ); +} + +/** + * Resolves an ERC20 type from a chain ID, and symbol or address. + * @param token The address or symbol of the token to resolve. + * @param chainId The chain ID to resolve the token on. + * @returns The ERC20 attributes of the token. + */ +function resolveToken(token: string, chainId: number): ERC20 { + // `token` may be an address or a symbol. Normalise it to a symbol for easy lookup. + const symbol = !isAddress(token) + ? token.toUpperCase() + : Object.values(contracts.TOKEN_SYMBOLS_MAP).find(({ addresses }) => addresses[chainId] === token)?.symbol; + + const _token = contracts.TOKEN_SYMBOLS_MAP[symbol]; + if (_token === undefined) { + throw new Error(`Token ${token} on chain ID ${chainId} unrecognised`); + } + + return { + address: _token.addresses[chainId], + decimals: _token.decimals, + symbol: _token.symbol, + }; +} + +function resolveHubChainId(spokeChainId: number): number { + if (chains.includes(spokeChainId)) { + return 1; + } + + assert(testChains.includes(spokeChainId), `Unsupported SpokePool chain ID: ${spokeChainId}`); + return 5; +} + +async function getHubPoolContract(chainId: number): Promise { + const contractName = "HubPool"; + const hubPoolChainId = resolveHubChainId(chainId); + + const hubPool = getDeployedContract(contractName, hubPoolChainId); + const provider = new ethers.providers.StaticJsonRpcProvider(getNodeUrlList(hubPoolChainId, 1)[0]); + return hubPool.connect(provider); +} + +async function getSpokePoolContract(chainId: number): Promise { + const hubPool = await getHubPoolContract(chainId); + const spokePoolAddr = (await hubPool.crossChainContracts(chainId))[1]; + + const contract = new Contract(spokePoolAddr, contracts.SpokePool__factory.abi); + return contract; +} + +async function deposit(args: Record, signer: Wallet): Promise { + const depositor = await signer.getAddress(); + const [fromChainId, toChainId, baseAmount] = [Number(args.from), Number(args.to), Number(args.amount)]; + const recipient = (args.recipient as string) ?? depositor; + + if (!validateChainIds([fromChainId, toChainId])) { + usage(); // no return + } + const network = getNetworkName(fromChainId); + + if (!isAddress(recipient)) { + console.log(`Invalid recipient address (${recipient})`); + usage(); // no return + } + + const token = resolveToken(args.token as string, fromChainId); + const tokenSymbol = token.symbol.toUpperCase(); + const amount = ethers.utils.parseUnits(baseAmount.toString(), args.decimals ? 0 : token.decimals); + + const provider = new ethers.providers.StaticJsonRpcProvider(getNodeUrlList(fromChainId, 1)[0]); + signer = signer.connect(provider); + const spokePool = (await getSpokePoolContract(fromChainId)).connect(signer); + + const erc20 = new Contract(token.address, contracts.ExpandedERC20__factory.abi, signer); + const allowance = await erc20.allowance(depositor, spokePool.address); + if (amount.gt(allowance)) { + const approvalAmount = amount.mul(5); + const approval = await erc20.approve(spokePool.address, approvalAmount); + console.log(`Approving SpokePool for ${approvalAmount} ${tokenSymbol}: ${approval.hash}.`); + await approval.wait(); + console.log("Approval complete..."); + } + + const relayerFeePct = Zero; // @todo: Make configurable. + const maxCount = MaxUint256; + const quoteTimestamp = Math.round(Date.now() / 1000); + + const deposit = await spokePool.deposit( + recipient, + token.address, + amount, + toChainId, + relayerFeePct, + quoteTimestamp, + "0x", + maxCount + ); + const { hash: transactionHash } = deposit; + console.log(`Submitting ${tokenSymbol} deposit on ${network}: ${transactionHash}.`); + const receipt = await deposit.wait(); + + receipt.logs + .filter((log) => log.address === spokePool.address) + .forEach((log) => printDeposit(spokePool.interface.parseLog(log))); + + return true; +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +async function dumpConfig(args: Record, _signer: Wallet): Promise { + const chainId = Number(args.chainId); + const _spokePool = await getSpokePoolContract(chainId); + + const hubChainId = resolveHubChainId(chainId); + const spokeProvider = new ethers.providers.StaticJsonRpcProvider(getNodeUrlList(chainId, 1)[0]); + const spokePool = _spokePool.connect(spokeProvider); + + const [spokePoolChainId, hubPool, crossDomainAdmin, weth, _currentTime] = await Promise.all([ + spokePool.chainId(), + spokePool.hubPool(), + spokePool.crossDomainAdmin(), + spokePool.wrappedNativeToken(), + spokePool.getCurrentTime(), + ]); + + if (chainId !== Number(spokePoolChainId)) { + throw new Error(`Chain ${chainId} SpokePool mismatch: ${spokePoolChainId} != ${chainId} (${spokePool.address})`); + } + + const currentTime = `${_currentTime} (${new Date(Number(_currentTime) * 1000).toUTCString()})`; + + const fields = { + hubChainId, + hubPool, + crossDomainAdmin, + weth, + currentTime, + }; + + // @todo: Support handlers for chain-specific configuration (i.e. address of bridge to L1). + + const padLeft = Object.keys(fields).reduce((acc, cur) => (cur.length > acc ? cur.length : acc), 0); + console.log( + `${getNetworkName(chainId)} SpokePool configuration:\n` + + Object.entries(fields) + .map(([k, v]) => `\t${k.padEnd(padLeft)} : ${v}`) + .join("\n") + + "\n" + ); + + return true; +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +async function fetchTxn(args: Record, _signer: Wallet): Promise { + const { txnHash } = args; + const chainId = Number(args.chainId); + + if (!validateChainIds([chainId])) { + usage(); // no return + } + + if (txnHash === undefined || typeof txnHash !== "string" || txnHash.length != 66 || !txnHash.startsWith("0x")) { + throw new Error(`Missing or malformed transaction hash: ${txnHash}`); + } + + const provider = new ethers.providers.StaticJsonRpcProvider(getNodeUrlList(chainId, 1)[0]); + const spokePool = await getSpokePoolContract(chainId); + + const txn = await provider.getTransactionReceipt(txnHash); + const fundsDeposited = spokePool.interface.getEventTopic("FundsDeposited"); + const filledRelay = spokePool.interface.getEventTopic("FilledRelay"); + const logs = txn.logs.filter(({ address }) => address === spokePool.address); + const { deposits = [], fills = [] } = groupBy(logs, ({ topics }) => { + switch (topics[0]) { + case fundsDeposited: + return "deposits"; + case filledRelay: + return "fills"; + } + }); + + deposits.forEach((deposit) => { + printDeposit(spokePool.interface.parseLog(deposit)); + }); + + fills.forEach((fill) => { + printFill(spokePool.interface.parseLog(fill)); + }); + + return true; +} + +function usage(badInput?: string): boolean { + let usageStr = badInput ? `\nUnrecognized input: "${badInput}".\n\n` : ""; + const walletOpts = "mnemonic|privateKey"; + const depositArgs = + "--from --to " + + " --token --amount [--recipient ] [--decimals]"; + const dumpConfigArgs = "--chainId"; + const fetchArgs = "--chainId --txnHash "; + const fillArgs = "--from --hash "; + + const pad = "deposit".length; + usageStr += ` + Usage: + \tyarn ts-node ./scripts/spokepool --wallet <${walletOpts}> ${"deposit".padEnd(pad)} ${depositArgs} + \tyarn ts-node ./scripts/spokepool --wallet <${walletOpts}> ${"dump".padEnd(pad)} ${dumpConfigArgs} + \tyarn ts-node ./scripts/spokepool --wallet <${walletOpts}> ${"fetch".padEnd(pad)} ${fetchArgs} + \tyarn ts-node ./scripts/spokepool --wallet <${walletOpts}> ${"fill".padEnd(pad)} ${fillArgs} + `.slice(1); // Skip leading newline + console.log(usageStr); + + // eslint-disable-next-line no-process-exit + process.exit(badInput === undefined ? 0 : 9); + // not reached +} + +async function run(argv: string[]): Promise { + const configOpts = ["chainId"]; + const depositOpts = ["from", "to", "token", "amount", "recipient"]; + const fetchOpts = ["chainId", "transactionHash"]; + const fillOpts = []; + const opts = { + string: ["wallet", ...configOpts, ...depositOpts, ...fetchOpts, ...fillOpts], + boolean: ["decimals"], // @dev tbd whether this is good UX or not...may need to change. + default: { + wallet: "mnemonic", + decimals: false, + }, + alias: { + transactionHash: "txnHash", + }, + unknown: usage, + }; + const args = minimist(argv.slice(1), opts); + + config(); + + let signer: Wallet; + try { + signer = await getSigner({ keyType: args.wallet, cleanEnv: true }); + } catch (err) { + usage(args.wallet); // no return + } + + switch (argv[0]) { + case "deposit": + return await deposit(args, signer); + case "dump": + return await dumpConfig(args, signer); + case "fetch": + return await fetchTxn(args, signer); + case "fill": + // @todo Not supported yet... + usage(); // no return + break; // ...keep the linter less dissatisfied! + default: + usage(); // no return + } +} + +if (require.main === module) { + run(process.argv.slice(2)) + .then(async () => { + // eslint-disable-next-line no-process-exit + process.exit(0); + }) + .catch(async (error) => { + console.error("Process exited with", error); + // eslint-disable-next-line no-process-exit + process.exit(1); + }); +} diff --git a/scripts/unwrapWeth.ts b/scripts/unwrapWeth.ts index dcc092db8..cb6cd4de4 100644 --- a/scripts/unwrapWeth.ts +++ b/scripts/unwrapWeth.ts @@ -1,4 +1,4 @@ -import { ethers, getSigner, getProvider, WETH9, toBN, isKeyOf, getNetworkName } from "../src/utils"; +import { ethers, retrieveSignerFromCLIArgs, getProvider, WETH9, toBN, isKeyOf, getNetworkName } from "../src/utils"; import { askYesNoQuestion } from "./utils"; import minimist from "minimist"; @@ -32,7 +32,7 @@ export async function run(): Promise { if (!Object.keys(args).includes("amount")) { throw new Error("Define `amount` as how much you want to unwrap"); } - const baseSigner = await getSigner(); + const baseSigner = await retrieveSignerFromCLIArgs(); const chainId = Number(args.chainId); const connectedSigner = baseSigner.connect(await getProvider(chainId)); if (!isKeyOf(chainId, WETH_ADDRESSES)) { diff --git a/scripts/zkSyncDemo.ts b/scripts/zkSyncDemo.ts index d941b9fd9..e28403166 100644 --- a/scripts/zkSyncDemo.ts +++ b/scripts/zkSyncDemo.ts @@ -1,7 +1,7 @@ import { AugmentedTransaction, TransactionClient } from "../src/clients"; import { ethers, - getSigner, + retrieveSignerFromCLIArgs, getProvider, ERC20, ZERO_ADDRESS, @@ -34,7 +34,7 @@ export async function run(): Promise { } }); - const baseSigner = await getSigner(); + const baseSigner = await retrieveSignerFromCLIArgs(); const l1ChainId = Number(args.chainId); const l1Provider = await getProvider(l1ChainId); const connectedSigner = baseSigner.connect(l1Provider); diff --git a/src/clients/BundleDataClient.ts b/src/clients/BundleDataClient.ts index cc35a2699..ff792ef40 100644 --- a/src/clients/BundleDataClient.ts +++ b/src/clients/BundleDataClient.ts @@ -1,4 +1,3 @@ -import { winston, BigNumber, toBN } from "../utils"; import * as _ from "lodash"; import { DepositWithBlock, @@ -11,12 +10,13 @@ import { } from "../interfaces"; import { SpokePoolClient } from "../clients"; import { + winston, + BigNumber, + toBN, assignValidFillToFillsToRefund, getRefundInformationFromFill, updateTotalRefundAmount, updateTotalRealizedLpFeePct, -} from "../utils"; -import { flattenAndFilterUnfilledDepositsByOriginChain, updateUnfilledDepositsWithMatchedDeposit, getUniqueDepositsInRange, @@ -371,16 +371,14 @@ export class BundleDataClient { const fillsForOriginChain = destinationClient .getFillsForOriginChain(Number(originChainId)) .filter((fillWithBlock) => fillWithBlock.blockNumber <= blockRangeForChain[1]); + // In the UBA model, fills that request repayment on another chain must send a separate refund request + // in order to mark their place in the outflow queue for that chain. This is because the UBA determines + // fees based on sequencing of events. Pre-UBA, the fee model treats each fill independently so there + // is no need to mark a fill's place in line on the repayment chain. await Promise.all( - fillsForOriginChain.map(async (fill) => { - // In the UBA model, fills that request repayment on another chain must send a separate refund request - // in order to mark their place in the outflow queue for that chain. This is because the UBA determines - // fees based on sequencing of events. Pre-UBA, the fee model treats each fill independently so there - // is no need to mark a fill's place in line on the repayment chain. - if (!isUBA || fill.destinationChainId === fill.repaymentChainId) { - validateFillAndSaveData(fill, blockRangeForChain); - } - }) + fillsForOriginChain + .filter((fill) => !isUBA || fill.destinationChainId === fill.repaymentChainId) + .map((fill) => validateFillAndSaveData(fill, blockRangeForChain)) ); } diff --git a/src/clients/InventoryClient.ts b/src/clients/InventoryClient.ts index 97c72d9c4..89d49e719 100644 --- a/src/clients/InventoryClient.ts +++ b/src/clients/InventoryClient.ts @@ -4,7 +4,7 @@ import { toBN, getNetworkName, createFormatFunction, - etherscanLink, + blockExplorerLink, Contract, runTransaction, isDefined, @@ -362,7 +362,7 @@ export class InventoryClient { cumulativeBalance.toString() )} ${symbol} over all chains (ignoring hubpool repayments). This chain has a shortfall of ` + `${formatter(this.getTokenShortFall(l1Token, chainId).toString())} ${symbol} ` + - `tx: ${etherscanLink(hash, this.hubPoolClient.chainId)}\n`; + `tx: ${blockExplorerLink(hash, this.hubPoolClient.chainId)}\n`; } } @@ -502,7 +502,7 @@ export class InventoryClient { `${this.formatWei(unwrapWethTarget.toString())} (trigger of ` + `${this.formatWei(unwrapWethThreshold.toString())} ETH), ` + `current balance of ${this.formatWei(balance.toString())} ` + - `tx: ${etherscanLink(hash, chainId)}\n`; + `tx: ${blockExplorerLink(hash, chainId)}\n`; } for (const { chainInfo, amount } of unexecutedUnwraps) { diff --git a/src/clients/TokenClient.ts b/src/clients/TokenClient.ts index 9bfb87ffc..7fc5b208c 100644 --- a/src/clients/TokenClient.ts +++ b/src/clients/TokenClient.ts @@ -1,7 +1,18 @@ -import { BigNumber, winston, assign, ERC20, Contract, toBN, MAX_SAFE_ALLOWANCE } from "../utils"; -import { runTransaction, getNetworkName, etherscanLink, MAX_UINT_VAL } from "../utils"; import { HubPoolClient, SpokePoolClient } from "."; import { Deposit } from "../interfaces"; +import { + BigNumber, + Contract, + ERC20, + MAX_SAFE_ALLOWANCE, + MAX_UINT_VAL, + assign, + blockExplorerLink, + getNetworkName, + runTransaction, + toBN, + winston, +} from "../utils"; type TokenDataType = { [chainId: number]: { [token: string]: { balance: BigNumber; allowance: BigNumber } } }; type TokenShortfallType = { @@ -133,9 +144,9 @@ export class TokenClient { const contract = new Contract(token, ERC20.abi, targetSpokePool.signer); const tx = await runTransaction(this.logger, contract, "approve", [targetSpokePool.address, MAX_UINT_VAL]); mrkdwn += - ` - Approved SpokePool ${etherscanLink(targetSpokePool.address, chainId)} ` + - `to spend ${await contract.symbol()} ${etherscanLink(token, chainId)} on ${getNetworkName(chainId)}. ` + - `tx: ${etherscanLink(tx.hash, chainId)}\n`; + ` - Approved SpokePool ${blockExplorerLink(targetSpokePool.address, chainId)} ` + + `to spend ${await contract.symbol()} ${blockExplorerLink(token, chainId)} on ${getNetworkName(chainId)}. ` + + `tx: ${blockExplorerLink(tx.hash, chainId)}\n`; } this.logger.info({ at: "TokenBalanceClient", message: "Approved whitelisted tokens! 💰", mrkdwn }); } @@ -155,9 +166,9 @@ export class TokenClient { MAX_UINT_VAL, ]); const mrkdwn = - ` - Approved HubPool ${etherscanLink(this.hubPoolClient.hubPool.address, 1)} ` + - `to spend ${await this.bondToken.symbol()} ${etherscanLink(this.bondToken.address, 1)}. ` + - `tx ${etherscanLink(tx.hash, 1)}\n`; + ` - Approved HubPool ${blockExplorerLink(this.hubPoolClient.hubPool.address, 1)} ` + + `to spend ${await this.bondToken.symbol()} ${blockExplorerLink(this.bondToken.address, 1)}. ` + + `tx ${blockExplorerLink(tx.hash, 1)}\n`; this.logger.info({ at: "hubPoolClient", message: "Approved bond tokens! 💰", mrkdwn }); } else { this.logger.debug({ at: "hubPoolClient", message: "Bond token approval set" }); diff --git a/src/clients/TransactionClient.ts b/src/clients/TransactionClient.ts index 3ccedfab6..ebba1e3d0 100644 --- a/src/clients/TransactionClient.ts +++ b/src/clients/TransactionClient.ts @@ -1,12 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { utils as sdkUtils } from "@across-protocol/sdk-v2"; +import { utils as sdkUtils, typeguards } from "@across-protocol/sdk-v2"; import { winston, getNetworkName, Contract, runTransaction, BigNumber, - etherscanLink, + blockExplorerLink, toBNWei, TransactionResponse, TransactionSimulationResult, @@ -29,6 +29,7 @@ export interface AugmentedTransaction { } const { fixedPointAdjustment: fixedPoint } = sdkUtils; +const { isError } = typeguards; const DEFAULT_GASLIMIT_MULTIPLIER = 1.0; @@ -95,6 +96,8 @@ export class TransactionClient { at: "TransactionClient#submit", message: `Transaction ${idx + 1} submission on ${networkName} failed or timed out.`, mrkdwn, + // @dev `error` _sometimes_ doesn't decode correctly (especially on Polygon), so fish for the reason. + errorMessage: isError(error) ? (error as Error).message : undefined, error, notificationPath: "across-error", }); @@ -102,7 +105,7 @@ export class TransactionClient { } nonce = response.nonce + 1; - const blockExplorer = etherscanLink(response.hash, txn.chainId); + const blockExplorer = blockExplorerLink(response.hash, txn.chainId); mrkdwn += ` ${idx + 1}. ${txn.message || "No message"} (${blockExplorer}): ${txn.mrkdwn || "No markdown"}\n`; txnResponses.push(response); } diff --git a/src/clients/bridges/AdapterManager.ts b/src/clients/bridges/AdapterManager.ts index e4187d858..4c7ad5ca6 100644 --- a/src/clients/bridges/AdapterManager.ts +++ b/src/clients/bridges/AdapterManager.ts @@ -18,16 +18,13 @@ export class AdapterManager { readonly logger: winston.Logger, readonly spokePoolClients: { [chainId: number]: SpokePoolClient }, readonly hubPoolClient: HubPoolClient, - readonly monitoredAddresses: string[], - // Optional sender address where the cross chain transfers originate from. This is useful for the use case of - // monitoring transfers from HubPool to SpokePools where the sender is HubPool. - readonly senderAddress?: string + readonly monitoredAddresses: string[] ) { if (!spokePoolClients) { return; } if (this.spokePoolClients[10] !== undefined) { - this.adapters[10] = new OptimismAdapter(logger, spokePoolClients, monitoredAddresses, senderAddress); + this.adapters[10] = new OptimismAdapter(logger, spokePoolClients, monitoredAddresses); } if (this.spokePoolClients[137] !== undefined) { this.adapters[137] = new PolygonAdapter(logger, spokePoolClients, monitoredAddresses); diff --git a/src/clients/bridges/ArbitrumAdapter.ts b/src/clients/bridges/ArbitrumAdapter.ts index 89a62a348..823a701a0 100644 --- a/src/clients/bridges/ArbitrumAdapter.ts +++ b/src/clients/bridges/ArbitrumAdapter.ts @@ -9,13 +9,15 @@ import { isDefined, TransactionResponse, resolveTokenSymbols, + toBN, + toWei, + paginatedEventQuery, + Event, } from "../../utils"; -import { toBN, toWei, paginatedEventQuery, Event } from "../../utils"; import { SpokePoolClient } from "../../clients"; import { BaseAdapter } from "./BaseAdapter"; -import { SortableEvent } from "../../interfaces"; +import { SortableEvent, OutstandingTransfers } from "../../interfaces"; import { constants } from "@across-protocol/sdk-v2"; -import { OutstandingTransfers } from "../../interfaces"; import { CONTRACT_ADDRESSES } from "../../common"; const { TOKEN_SYMBOLS_MAP, CHAIN_IDs } = constants; diff --git a/src/clients/bridges/BaseAdapter.ts b/src/clients/bridges/BaseAdapter.ts index edf12f652..b9c12a94e 100644 --- a/src/clients/bridges/BaseAdapter.ts +++ b/src/clients/bridges/BaseAdapter.ts @@ -1,31 +1,35 @@ /* eslint-disable @typescript-eslint/ban-types */ +import { constants as sdkConstants } from "@across-protocol/sdk-v2"; import { Provider } from "@ethersproject/abstract-provider"; import { Signer } from "@ethersproject/abstract-signer"; -import { constants as sdkConstants } from "@across-protocol/sdk-v2"; import { AugmentedTransaction, SpokePoolClient, TransactionClient } from "../../clients"; import { - toBN, - MAX_SAFE_ALLOWANCE, + AnyObject, + BigNumber, Contract, + DefaultLogLevels, ERC20, - winston, EventSearchConfig, - DefaultLogLevels, + MAX_SAFE_ALLOWANCE, + MAX_UINT_VAL, MakeOptional, - AnyObject, - BigNumber, - matchTokenSymbol, + TransactionResponse, ZERO_ADDRESS, assert, + blockExplorerLink, compareAddressesSimple, formatUnitsForToken, + getNetworkName, + matchTokenSymbol, + runTransaction, + toBN, + winston, + createFormatFunction, + BigNumberish, } from "../../utils"; -import { etherscanLink, getNetworkName, MAX_UINT_VAL, runTransaction } from "../../utils"; -import { OutstandingTransfers, SortableEvent } from "../../interfaces"; -import { TransactionResponse } from "../../utils"; import { CONTRACT_ADDRESSES } from "../../common"; -import { BigNumberish, createFormatFunction } from "../../utils/FormattingUtils"; +import { OutstandingTransfers, SortableEvent } from "../../interfaces"; interface DepositEvent extends SortableEvent { amount: BigNumber; to: string; @@ -56,7 +60,6 @@ export abstract class BaseAdapter { l1DepositInitiatedEvents: Events = {}; l2DepositFinalizedEvents: Events = {}; - l2DepositFinalizedEvents_DepositAdapter: Events = {}; txnClient: TransactionClient; @@ -150,9 +153,9 @@ export abstract class BaseAdapter { const hubNetwork = getNetworkName(hubChainId); const spokeNetwork = getNetworkName(this.chainId); mrkdwn += - ` - Approved canonical ${spokeNetwork} token bridge ${etherscanLink(targetContract, hubChainId)} ` + - `to spend ${await l1Token.symbol()} ${etherscanLink(l1Token.address, hubChainId)} on ${hubNetwork}.` + - `tx: ${etherscanLink(receipt.transactionHash, hubChainId)}\n`; + ` - Approved canonical ${spokeNetwork} token bridge ${blockExplorerLink(targetContract, hubChainId)} ` + + `to spend ${await l1Token.symbol()} ${blockExplorerLink(l1Token.address, hubChainId)} on ${hubNetwork}.` + + `tx: ${blockExplorerLink(receipt.transactionHash, hubChainId)}\n`; } this.log("Approved whitelisted tokens! 💰", { mrkdwn }, "info"); } @@ -183,20 +186,7 @@ export abstract class BaseAdapter { if (this.l2DepositFinalizedEvents[monitoredAddress][l1Token] === undefined) { this.l2DepositFinalizedEvents[monitoredAddress][l1Token] = []; } - let l2FinalizationSet = this.l2DepositFinalizedEvents[monitoredAddress][l1Token]; - if (this.isWeth(l1Token)) { - let depositFinalizedEventsForL1 = - this.l2DepositFinalizedEvents_DepositAdapter[monitoredAddress]?.[l1Token] || []; - depositFinalizedEventsForL1 = depositFinalizedEventsForL1.filter((event) => event.to === monitoredAddress); - if (depositFinalizedEventsForL1.length > 0) { - // If this is WETH and there are atomic depositor events then consider the union as the full set of - // finalization events. We do this as the output event on L2 will show the Atomic depositor as the sender, - // not the original sender (monitored address). - l2FinalizationSet = [...l2FinalizationSet, ...depositFinalizedEventsForL1].sort( - (a, b) => a.blockNumber - b.blockNumber - ); - } - } + const l2FinalizationSet = this.l2DepositFinalizedEvents[monitoredAddress][l1Token]; // Match deposits and finalizations by amount. We're only doing a limited lookback of events so collisions // should be unlikely. diff --git a/src/clients/bridges/PolygonAdapter.ts b/src/clients/bridges/PolygonAdapter.ts index c412fd537..9f05ef725 100644 --- a/src/clients/bridges/PolygonAdapter.ts +++ b/src/clients/bridges/PolygonAdapter.ts @@ -9,13 +9,14 @@ import { BigNumberish, TransactionResponse, resolveTokenSymbols, + ZERO_ADDRESS, + spreadEventWithBlockNumber, + paginatedEventQuery, } from "../../utils"; -import { ZERO_ADDRESS, spreadEventWithBlockNumber, paginatedEventQuery } from "../../utils"; import { SpokePoolClient } from "../../clients"; import { BaseAdapter } from "./"; -import { SortableEvent } from "../../interfaces"; +import { SortableEvent, OutstandingTransfers } from "../../interfaces"; import { constants } from "@across-protocol/sdk-v2"; -import { OutstandingTransfers } from "../../interfaces"; import { CONTRACT_ADDRESSES } from "../../common"; const { TOKEN_SYMBOLS_MAP, CHAIN_IDs } = constants; diff --git a/src/clients/bridges/ZKSyncAdapter.ts b/src/clients/bridges/ZKSyncAdapter.ts index fd1f0629d..e4c3a8723 100644 --- a/src/clients/bridges/ZKSyncAdapter.ts +++ b/src/clients/bridges/ZKSyncAdapter.ts @@ -1,4 +1,4 @@ -import { BigNumber, Contract } from "ethers"; +import { BigNumber, BigNumberish, Contract } from "ethers"; import { BaseAdapter } from "./BaseAdapter"; import { OutstandingTransfers, SortableEvent } from "../../interfaces"; import { @@ -19,7 +19,6 @@ import { TOKEN_SYMBOLS_MAP } from "@across-protocol/contracts-v2"; import { isDefined } from "../../utils/TypeGuards"; import { gasPriceOracle, utils } from "@across-protocol/sdk-v2"; import { zkSync as zkSyncUtils } from "../../utils/chains"; -import { BigNumberish } from "../../utils/FormattingUtils"; /** * Responsible for providing a common interface for interacting with the ZKSync Era diff --git a/src/clients/bridges/op-stack/OpStackAdapter.ts b/src/clients/bridges/op-stack/OpStackAdapter.ts index 7fce08092..cfff52c8b 100644 --- a/src/clients/bridges/op-stack/OpStackAdapter.ts +++ b/src/clients/bridges/op-stack/OpStackAdapter.ts @@ -7,12 +7,13 @@ import { Event, checkAddressChecksum, ethers, + spreadEventWithBlockNumber, + assign, + winston, } from "../../../utils"; -import { spreadEventWithBlockNumber, assign, winston } from "../../../utils"; import { SpokePoolClient } from "../.."; import { BaseAdapter } from ".."; -import { SortableEvent } from "../../../interfaces"; -import { OutstandingTransfers } from "../../../interfaces"; +import { SortableEvent, OutstandingTransfers } from "../../../interfaces"; import { CONTRACT_ADDRESSES } from "../../../common"; import { constants } from "@across-protocol/sdk-v2"; import { OpStackBridge } from "./OpStackBridgeInterface"; @@ -31,10 +32,7 @@ export class OpStackAdapter extends BaseAdapter { logger: winston.Logger, supportedTokens: string[], readonly spokePoolClients: { [chainId: number]: SpokePoolClient }, - monitoredAddresses: string[], - // Optional sender address where the cross chain transfers originate from. This is useful for the use case of - // monitoring transfers from HubPool to SpokePools where the sender is HubPool. - readonly senderAddress?: string + monitoredAddresses: string[] ) { super(spokePoolClients, chainId, monitoredAddresses, logger, supportedTokens); this.l2Gas = 200000; @@ -86,17 +84,10 @@ export class OpStackAdapter extends BaseAdapter { l1Tokens.map(async (l1Token) => { const bridge = this.getBridge(l1Token); - const [depositInitiatedResults, depositFinalizedResults, depositFinalizedResults_DepositAdapter] = - await Promise.all([ - bridge.queryL1BridgeInitiationEvents(l1Token, monitoredAddress, l1SearchConfig), - bridge.queryL2BridgeFinalizationEvents(l1Token, monitoredAddress, l2SearchConfig), - // Transfers might have come from the monitored address itself or another sender address (if specified). - bridge.queryL2BridgeFinalizationEvents( - l1Token, - this.senderAddress || this.atomicDepositorAddress, - l2SearchConfig - ), - ]); + const [depositInitiatedResults, depositFinalizedResults] = await Promise.all([ + bridge.queryL1BridgeInitiationEvents(l1Token, monitoredAddress, l1SearchConfig), + bridge.queryL2BridgeFinalizationEvents(l1Token, monitoredAddress, l2SearchConfig), + ]); assign( this.l1DepositInitiatedEvents, @@ -108,11 +99,6 @@ export class OpStackAdapter extends BaseAdapter { [monitoredAddress, l1Token], depositFinalizedResults.map(processEvent) ); - assign( - this.l2DepositFinalizedEvents_DepositAdapter, - [monitoredAddress, l1Token], - depositFinalizedResults_DepositAdapter.map(processEvent) - ); }) ) ) diff --git a/src/clients/bridges/op-stack/WethBridge.ts b/src/clients/bridges/op-stack/WethBridge.ts index 0dbc99da2..b551731a1 100644 --- a/src/clients/bridges/op-stack/WethBridge.ts +++ b/src/clients/bridges/op-stack/WethBridge.ts @@ -50,11 +50,7 @@ export class WethBridge implements OpStackBridge { fromAddress: string, eventConfig: EventSearchConfig ): Promise { - return paginatedEventQuery( - this.l1Bridge, - this.l1Bridge.filters.ETHDepositInitiated(undefined, fromAddress), - eventConfig - ); + return paginatedEventQuery(this.l1Bridge, this.l1Bridge.filters.ETHDepositInitiated(fromAddress), eventConfig); } queryL2BridgeFinalizationEvents( diff --git a/src/clients/bridges/op-stack/base/BaseChainAdapter.ts b/src/clients/bridges/op-stack/base/BaseChainAdapter.ts index 0df8ecc36..88a0c3ac7 100644 --- a/src/clients/bridges/op-stack/base/BaseChainAdapter.ts +++ b/src/clients/bridges/op-stack/base/BaseChainAdapter.ts @@ -7,10 +7,7 @@ export class BaseChainAdapter extends OpStackAdapter { constructor( logger: winston.Logger, readonly spokePoolClients: { [chainId: number]: SpokePoolClient }, - monitoredAddresses: string[], - // Optional sender address where the cross chain transfers originate from. This is useful for the use case of - // monitoring transfers from HubPool to SpokePools where the sender is HubPool. - readonly senderAddress?: string + monitoredAddresses: string[] ) { super( 8453, @@ -19,8 +16,7 @@ export class BaseChainAdapter extends OpStackAdapter { logger, ["BAL", "DAI", "ETH", "WETH", "USDC"], spokePoolClients, - monitoredAddresses, - senderAddress + monitoredAddresses ); } } diff --git a/src/clients/bridges/op-stack/optimism/OptimismAdapter.ts b/src/clients/bridges/op-stack/optimism/OptimismAdapter.ts index 72ecd4bab..663a0ac9a 100644 --- a/src/clients/bridges/op-stack/optimism/OptimismAdapter.ts +++ b/src/clients/bridges/op-stack/optimism/OptimismAdapter.ts @@ -11,10 +11,7 @@ export class OptimismAdapter extends OpStackAdapter { constructor( logger: winston.Logger, readonly spokePoolClients: { [chainId: number]: SpokePoolClient }, - monitoredAddresses: string[], - // Optional sender address where the cross chain transfers originate from. This is useful for the use case of - // monitoring transfers from HubPool to SpokePools where the sender is HubPool. - readonly senderAddress?: string + monitoredAddresses: string[] ) { const hubChainId = BaseAdapter.HUB_CHAIN_ID; const l2ChainId = 10; @@ -31,8 +28,7 @@ export class OptimismAdapter extends OpStackAdapter { logger, ["DAI", "SNX", "USDC", "USDT", "WETH", "WBTC", "UMA", "BAL", "ACX", "POOL"], spokePoolClients, - monitoredAddresses, - senderAddress + monitoredAddresses ); } } diff --git a/src/clients/bridges/op-stack/optimism/SnxOptimismBridge.ts b/src/clients/bridges/op-stack/optimism/SnxOptimismBridge.ts index 11f7b28f8..2452953b6 100644 --- a/src/clients/bridges/op-stack/optimism/SnxOptimismBridge.ts +++ b/src/clients/bridges/op-stack/optimism/SnxOptimismBridge.ts @@ -41,19 +41,21 @@ export class SnxOptimismBridge implements OpStackBridge { }; } - queryL1BridgeInitiationEvents( - l1Token: string, - fromAddress: string, - eventConfig: EventSearchConfig - ): Promise { - return paginatedEventQuery(this.l1Bridge, this.l1Bridge.filters.DepositInitiated(fromAddress), eventConfig); + queryL1BridgeInitiationEvents(l1Token: string, toAddress: string, eventConfig: EventSearchConfig): Promise { + // @dev For the SnxBridge, only the `toAddress` is indexed on the L2 event so we treat the `fromAddress` as the + // toAddress when fetching the L1 event. + return paginatedEventQuery( + this.l1Bridge, + this.l1Bridge.filters.DepositInitiated(undefined, toAddress), + eventConfig + ); } queryL2BridgeFinalizationEvents( l1Token: string, - fromAddress: string, + toAddress: string, eventConfig: EventSearchConfig ): Promise { - return paginatedEventQuery(this.l2Bridge, this.l2Bridge.filters.DepositFinalized(fromAddress), eventConfig); + return paginatedEventQuery(this.l2Bridge, this.l2Bridge.filters.DepositFinalized(toAddress), eventConfig); } } diff --git a/src/dataworker/Dataworker.ts b/src/dataworker/Dataworker.ts index ec6828fd6..e0c91dea3 100644 --- a/src/dataworker/Dataworker.ts +++ b/src/dataworker/Dataworker.ts @@ -9,8 +9,10 @@ import { isDefined, buildPoolRebalanceLeafTree, updateTotalRefundAmountRaw, + toBNWei, + getFillsInRange, + ZERO_ADDRESS, } from "../utils"; -import { toBNWei, getFillsInRange, ZERO_ADDRESS } from "../utils"; import { DepositWithBlock, FillsToRefund, @@ -22,8 +24,6 @@ import { SlowFillLeaf, SpokePoolClientsByChain, UnfilledDeposit, -} from "../interfaces"; -import { PendingRootBundle, RunningBalances, PoolRebalanceLeaf, @@ -31,7 +31,7 @@ import { BigNumberForToken, } from "../interfaces"; import { DataworkerClients } from "./DataworkerClientHelper"; -import { SpokePoolClient, UBAClient } from "../clients"; +import { SpokePoolClient, UBAClient, BalanceAllocator } from "../clients"; import * as PoolRebalanceUtils from "./PoolRebalanceUtils"; import { blockRangesAreInvalidForSpokeClients, @@ -45,7 +45,6 @@ import { _buildRelayerRefundRoot, _buildSlowRelayRoot, } from "./DataworkerUtils"; -import { BalanceAllocator } from "../clients"; import _ from "lodash"; import { spokePoolClientsToProviders } from "../common"; import * as sdk from "@across-protocol/sdk-v2"; @@ -2230,7 +2229,10 @@ export class Dataworker { logSlowFillExcessData = false ): Promise { const key = JSON.stringify(blockRangesForChains); - if (!this.rootCache[key]) { + // FIXME: Temporary fix to disable root cache rebalancing and to keep the + // executor running for tonight (2023-08-28) until we can fix the + // root cache rebalancing bug. + if (!this.rootCache[key] || process.env.DATAWORKER_DISABLE_REBALANCE_ROOT_CACHE === "true") { this.rootCache[key] = await _buildPoolRebalanceRoot( latestMainnetBlock, mainnetBundleEndBlock, diff --git a/src/dataworker/DataworkerUtils.ts b/src/dataworker/DataworkerUtils.ts index 1bc4a32cf..1d823d175 100644 --- a/src/dataworker/DataworkerUtils.ts +++ b/src/dataworker/DataworkerUtils.ts @@ -1,36 +1,49 @@ +import { utils } from "@across-protocol/sdk-v2"; import { SpokePoolClient } from "../clients"; +import { spokesThatHoldEthAndWeth } from "../common/Constants"; +import { CONTRACT_ADDRESSES } from "../common/ContractAddresses"; import { BigNumberForToken, DepositWithBlock, FillsToRefund, FillWithBlock, PoolRebalanceLeaf, + RelayerRefundLeaf, + RelayerRefundLeafWithGroup, + RunningBalances, SlowFillLeaf, SpokePoolClientsByChain, + UnfilledDeposit, } from "../interfaces"; -import { RelayerRefundLeaf } from "../interfaces"; -import { RelayerRefundLeafWithGroup, RunningBalances, UnfilledDeposit } from "../interfaces"; import { AnyObject, buildPoolRebalanceLeafTree, buildRelayerRefundTree, buildSlowRelayTree, + getDepositPath, + getFillsInRange, + groupObjectCountsByProp, + groupObjectCountsByTwoProps, isDefined, MerkleTree, + toBN, winston, } from "../utils"; -import { getDepositPath, getFillsInRange, groupObjectCountsByProp, groupObjectCountsByTwoProps, toBN } from "../utils"; import { PoolRebalanceRoot } from "./Dataworker"; import { DataworkerClients } from "./DataworkerClientHelper"; -import { addSlowFillsToRunningBalances, initializeRunningBalancesFromRelayerRepayments } from "./PoolRebalanceUtils"; -import { addLastRunningBalance, constructPoolRebalanceLeaves } from "./PoolRebalanceUtils"; -import { updateRunningBalanceForDeposit } from "./PoolRebalanceUtils"; -import { subtractExcessFromPreviousSlowFillsFromRunningBalances } from "./PoolRebalanceUtils"; -import { getAmountToReturnForRelayerRefundLeaf } from "./RelayerRefundUtils"; -import { sortRefundAddresses, sortRelayerRefundLeaves } from "./RelayerRefundUtils"; -import { utils } from "@across-protocol/sdk-v2"; -import { CONTRACT_ADDRESSES } from "../common/ContractAddresses"; -import { spokesThatHoldEthAndWeth } from "../common/Constants"; +import { + addLastRunningBalance, + addSlowFillsToRunningBalances, + constructPoolRebalanceLeaves, + initializeRunningBalancesFromRelayerRepayments, + subtractExcessFromPreviousSlowFillsFromRunningBalances, + updateRunningBalanceForDeposit, +} from "./PoolRebalanceUtils"; +import { + getAmountToReturnForRelayerRefundLeaf, + sortRefundAddresses, + sortRelayerRefundLeaves, +} from "./RelayerRefundUtils"; export const { getImpliedBundleBlockRanges, getBlockRangeForChain, getBlockForChain } = utils; export function getEndBlockBuffers( diff --git a/src/dataworker/PoolRebalanceUtils.ts b/src/dataworker/PoolRebalanceUtils.ts index b04100a6c..e2ef9b8e6 100644 --- a/src/dataworker/PoolRebalanceUtils.ts +++ b/src/dataworker/PoolRebalanceUtils.ts @@ -1,34 +1,34 @@ import { ConfigStoreClient, HubPoolClient, SpokePoolClient } from "../clients"; +import { Clients } from "../common"; import * as interfaces from "../interfaces"; import { BigNumberForToken, + PendingRootBundle, PoolRebalanceLeaf, RelayerRefundLeaf, - PendingRootBundle, RunningBalances, - UnfilledDeposit, - SpokePoolTargetBalance, - SpokePoolClientsByChain, SlowFillLeaf, + SpokePoolClientsByChain, + SpokePoolTargetBalance, + UnfilledDeposit, } from "../interfaces"; import { - assign, + AnyObject, BigNumber, + MerkleTree, + assign, compareAddresses, convertFromWei, + formatFeePct, + getFillDataForSlowFillFromPreviousRootBundle, + getRefund, shortenHexString, shortenHexStrings, toBN, - MerkleTree, - winston, toBNWei, - formatFeePct, - getRefund, - AnyObject, + winston, } from "../utils"; import { DataworkerClients } from "./DataworkerClientHelper"; -import { getFillDataForSlowFillFromPreviousRootBundle } from "../utils"; -import { Clients } from "../common"; export function updateRunningBalance( runningBalances: interfaces.RunningBalances, diff --git a/src/finalizer/index.ts b/src/finalizer/index.ts index 7e845f91b..c78be8a56 100644 --- a/src/finalizer/index.ts +++ b/src/finalizer/index.ts @@ -6,7 +6,7 @@ import { startupLogLevel, processEndPollingLoop, getNetworkName, - etherscanLink, + blockExplorerLink, getBlockForTimestamp, getCurrentTime, disconnectRedisClient, @@ -126,7 +126,7 @@ export async function finalize( logger.info({ at: "Finalizer", message: `Submitted proof on chain ${hubChain} to initiate ${spokeChain} withdrawal of ${amount} ${symbol} 🔜`, - transactionHash: etherscanLink(txn.transactionHash, hubChainId), + transactionHash: blockExplorerLink(txn.transactionHash, hubChainId), }); }); withdrawals.forEach(({ l2ChainId, amount, l1TokenSymbol: symbol }) => { @@ -134,7 +134,7 @@ export async function finalize( logger.info({ at: "Finalizer", message: `Finalized ${spokeChain} withdrawal for ${amount} ${symbol} 🪃`, - transactionHash: etherscanLink(txn.transactionHash, hubChainId), + transactionHash: blockExplorerLink(txn.transactionHash, hubChainId), }); }); } catch (_error) { diff --git a/src/finalizer/utils/zkSync.ts b/src/finalizer/utils/zkSync.ts index e48370775..da054dbad 100644 --- a/src/finalizer/utils/zkSync.ts +++ b/src/finalizer/utils/zkSync.ts @@ -1,11 +1,10 @@ +import { interfaces, utils as sdkUtils } from "@across-protocol/sdk-v2"; import { Contract, ethers, Wallet } from "ethers"; -import { Provider as zksProvider, types as zkTypes, utils as zkUtils, Wallet as zkWallet } from "zksync-web3"; import { groupBy } from "lodash"; -import { interfaces, utils as sdkUtils } from "@across-protocol/sdk-v2"; +import { Provider as zksProvider, types as zkTypes, utils as zkUtils, Wallet as zkWallet } from "zksync-web3"; import { HubPoolClient, SpokePoolClient } from "../../clients"; import { CONTRACT_ADDRESSES, Multicall2Call } from "../../common"; -import { convertFromWei, getEthAddressForChain, winston } from "../../utils"; -import { zkSync as zkSyncUtils } from "../../utils"; +import { convertFromWei, getEthAddressForChain, winston, zkSync as zkSyncUtils } from "../../utils"; import { FinalizerPromise, Withdrawal } from "../types"; type Provider = ethers.providers.Provider; diff --git a/src/monitor/Monitor.ts b/src/monitor/Monitor.ts index 1fbcfddb9..cfcbea01f 100644 --- a/src/monitor/Monitor.ts +++ b/src/monitor/Monitor.ts @@ -19,8 +19,8 @@ import { createFormatFunction, ERC20, ethers, - etherscanLink, - etherscanLinks, + blockExplorerLink, + blockExplorerLinks, getEthAddressForChain, getGasPrice, getNativeTokenSymbol, @@ -134,7 +134,7 @@ export class Monitor { if (l1TokenUtilization.utilization.gt(toBN(this.monitorConfig.utilizationThreshold).mul(toBN(toWei("0.01"))))) { const utilizationString = l1TokenUtilization.utilization.mul(100).toString(); const mrkdwn = `${l1TokenUtilization.poolCollateralSymbol} pool token at \ - ${etherscanLink(l1TokenUtilization.l1Token, l1TokenUtilization.chainId)} on \ + ${blockExplorerLink(l1TokenUtilization.l1Token, l1TokenUtilization.chainId)} on \ ${getNetworkName(l1TokenUtilization.chainId)} is at \ ${createFormatFunction(0, 2)(utilizationString)}% utilization!"`; this.logger.debug({ at: "Monitor#checkUtilization", message: "High pool utilization warning 🏊", mrkdwn }); @@ -184,8 +184,8 @@ export class Monitor { } const mrkdwn = - `An unknown relayer ${etherscanLink(fill.relayer, chainId)}` + - ` filled a deposit on ${getNetworkName(chainId)}\ntx: ${etherscanLink(fill.transactionHash, chainId)}`; + `An unknown relayer ${blockExplorerLink(fill.relayer, chainId)}` + + ` filled a deposit on ${getNetworkName(chainId)}\ntx: ${blockExplorerLink(fill.transactionHash, chainId)}`; this.logger.warn({ at: "Monitor#checkUnknownRelayers", message: "Unknown relayer 🛺", mrkdwn }); } } @@ -360,7 +360,7 @@ export class Monitor { ).symbol(); return { level: trippedThreshold.level, - text: ` ${getNetworkName(chainId)} ${symbol} balance for ${etherscanLink( + text: ` ${getNetworkName(chainId)} ${symbol} balance for ${blockExplorerLink( account, chainId )} is ${ethers.utils.formatUnits(balance, decimals)}. Threshold: ${trippedThreshold.threshold}`, @@ -465,7 +465,7 @@ export class Monitor { deficit, decimals )} ${nativeSymbolForChain} for ${account} from ${signerAddress} 🫡!`, - transactionHash: etherscanLink(receipt.transactionHash, chainId), + transactionHash: blockExplorerLink(receipt.transactionHash, chainId), }); } } else { @@ -541,7 +541,7 @@ export class Monitor { chainId, l1Token.address ); - const outstandingDepositTxs = etherscanLinks( + const outstandingDepositTxs = blockExplorerLinks( this.clients.crossChainTransferClient.getOutstandingCrossChainTransferTxs( spokePoolAddress, chainId, @@ -746,7 +746,7 @@ export class Monitor { const totalAmount = this.getTotalTransferAmount(transfers); let mrkdwn = `other: ${convertFromWei(totalAmount.toString(), decimals)}\n`; const transactionHashes = [...new Set(transfers.map((transfer) => transfer.transactionHash))]; - mrkdwn += etherscanLinks(transactionHashes, chainId); + mrkdwn += blockExplorerLinks(transactionHashes, chainId); return mrkdwn; } @@ -852,13 +852,13 @@ export class Monitor { } const mrkdwn = - `An unknown EOA ${etherscanLink(caller, 1)} has ${action} a bundle on ${getNetworkName(1)}` + - `\ntx: ${etherscanLink(transactionHash, 1)}`; + `An unknown EOA ${blockExplorerLink(caller, 1)} has ${action} a bundle on ${getNetworkName(1)}` + + `\ntx: ${blockExplorerLink(transactionHash, 1)}`; this.logger.error({ at: "Monitor#notifyIfUnknownCaller", message: `Unknown bundle caller (${action}) ${emoji}${ action === BundleAction.PROPOSED - ? `. If proposer identity cannot be determined quickly, then the safe response is to call "disputeRootBundle" on the HubPool here ${etherscanLink( + ? `. If proposer identity cannot be determined quickly, then the safe response is to call "disputeRootBundle" on the HubPool here ${blockExplorerLink( this.clients.hubPoolClient.hubPool.address, 1 )}. Note that you will need to approve the HubPool to transfer 0.4 WETH from your wallet as a dispute bond.` diff --git a/src/monitor/MonitorClientHelper.ts b/src/monitor/MonitorClientHelper.ts index 15355efae..a9aff3a17 100644 --- a/src/monitor/MonitorClientHelper.ts +++ b/src/monitor/MonitorClientHelper.ts @@ -47,13 +47,14 @@ export async function constructMonitorClients( // Need to update HubPoolClient to get latest tokens. const spokePoolAddresses = Object.values(spokePoolClients).map((client) => client.spokePool.address); - const adapterManager = new AdapterManager( - logger, - spokePoolClients, - commonClients.hubPoolClient, - [baseSigner.address, ...spokePoolAddresses], - commonClients.hubPoolClient.hubPool.address - ); + + // Cross-chain transfers will originate from the HubPool's address and target SpokePool addresses, so + // track both. + const adapterManager = new AdapterManager(logger, spokePoolClients, commonClients.hubPoolClient, [ + baseSigner.address, + commonClients.hubPoolClient.hubPool.address, + ...spokePoolAddresses, + ]); const spokePoolChains = Object.keys(spokePoolClients).map((chainId) => Number(chainId)); const providerPerChain = Object.fromEntries( spokePoolChains.map((chainId) => [chainId, spokePoolClients[chainId].spokePool.provider]) diff --git a/src/relayer/Relayer.ts b/src/relayer/Relayer.ts index affae6c51..27967667a 100644 --- a/src/relayer/Relayer.ts +++ b/src/relayer/Relayer.ts @@ -1,22 +1,26 @@ +import { utils as sdkUtils } from "@across-protocol/sdk-v2"; import { constants as ethersConstants } from "ethers"; import { groupBy } from "lodash"; -import { utils as sdkUtils } from "@across-protocol/sdk-v2"; +import { Deposit, DepositWithBlock, FillWithBlock, L1Token, RefundRequestWithBlock } from "../interfaces"; import { BigNumber, - isDefined, - winston, + RelayerUnfilledDeposit, + blockExplorerLink, buildFillRelayProps, - getNetworkName, + buildFillRelayWithUpdatedFeeProps, + createFormatFunction, + formatFeePct, getBlockForTimestamp, - getUnfilledDeposits, getCurrentTime, - buildFillRelayWithUpdatedFeeProps, + getNetworkName, + getUnfilledDeposits, + isDefined, isDepositSpedUp, - RelayerUnfilledDeposit, + toBN, + toBNWei, + winston, } from "../utils"; -import { createFormatFunction, etherscanLink, formatFeePct, toBN, toBNWei } from "../utils"; import { RelayerClients } from "./RelayerClientHelper"; -import { Deposit, DepositWithBlock, FillWithBlock, L1Token, RefundRequestWithBlock } from "../interfaces"; import { RelayerConfig } from "./RelayerConfig"; const UNPROFITABLE_DEPOSIT_NOTICE_PERIOD = 60 * 60; // 1 hour @@ -619,9 +623,9 @@ export class Relayer { const { symbol, decimals } = this.clients.hubPoolClient.getTokenInfoForDeposit(deposit); const formatFunction = createFormatFunction(2, 4, false, decimals); const gasFormatFunction = createFormatFunction(2, 10, false, 18); - const depositEtherscanLink = etherscanLink(deposit.transactionHash, deposit.originChainId); + const depositblockExplorerLink = blockExplorerLink(deposit.transactionHash, deposit.originChainId); depositMrkdwn += - `- DepositId ${deposit.depositId} (tx: ${depositEtherscanLink}) of amount ${formatFunction( + `- DepositId ${deposit.depositId} (tx: ${depositblockExplorerLink}) of amount ${formatFunction( deposit.amount.toString() )} ${symbol}` + ` with a relayerFeePct ${formatFeePct(deposit.relayerFeePct)}% and gas cost ${gasFormatFunction(gasCost)}` + @@ -658,7 +662,7 @@ export class Relayer { `Relayed depositId ${deposit.depositId} from ${getNetworkName(deposit.originChainId)} ` + `to ${getNetworkName(deposit.destinationChainId)} of ` + `${createFormatFunction(2, 4, false, decimals)(deposit.amount.toString())} ${symbol}. ` + - `with depositor ${etherscanLink(deposit.depositor, deposit.originChainId)}. ` + + `with depositor ${blockExplorerLink(deposit.depositor, deposit.originChainId)}. ` + `Fill amount of ${createFormatFunction(2, 4, false, decimals)(fillAmount.toString())} ${symbol} with ` + `relayerFee ${formatFeePct(deposit.relayerFeePct)}% & ` + `realizedLpFee ${formatFeePct(deposit.realizedLpFeePct)}%. ` diff --git a/src/relayer/RelayerClientHelper.ts b/src/relayer/RelayerClientHelper.ts index 58f62a665..a407a1260 100644 --- a/src/relayer/RelayerClientHelper.ts +++ b/src/relayer/RelayerClientHelper.ts @@ -1,12 +1,18 @@ +import { clients as sdkClients, utils as sdkUtils } from "@across-protocol/sdk-v2"; import winston from "winston"; -import { utils as sdkUtils, clients as sdkClients } from "@across-protocol/sdk-v2"; -import { Wallet } from "../utils"; -import { TokenClient, ProfitClient, BundleDataClient, InventoryClient, AcrossApiClient, UBAClient } from "../clients"; +import { AcrossApiClient, BundleDataClient, InventoryClient, ProfitClient, TokenClient, UBAClient } from "../clients"; import { AdapterManager, CrossChainTransferClient } from "../clients/bridges"; -import { RelayerConfig } from "./RelayerConfig"; -import { Clients, constructClients, updateClients, updateSpokePoolClients } from "../common"; +import { + CONTRACT_ADDRESSES, + Clients, + constructClients, + constructSpokePoolClientsWithLookback, + updateClients, + updateSpokePoolClients, +} from "../common"; import { SpokePoolClientsByChain } from "../interfaces"; -import { constructSpokePoolClientsWithLookback } from "../common"; +import { Wallet } from "../utils"; +import { RelayerConfig } from "./RelayerConfig"; export interface RelayerClients extends Clients { spokePoolClients: SpokePoolClientsByChain; @@ -76,8 +82,11 @@ export async function constructRelayerClients( ); await profitClient.update(); + // The relayer will originate cross chain rebalances from both its own EOA address and the atomic depositor address + // so we should track both for accurate cross-chain inventory management. const adapterManager = new AdapterManager(logger, spokePoolClients, commonClients.hubPoolClient, [ baseSigner.address, + CONTRACT_ADDRESSES[commonClients.hubPoolClient.chainId].atomicDepositor.address, ]); const bundleDataClient = new BundleDataClient( diff --git a/src/scripts/testUBAClient.ts b/src/scripts/testUBAClient.ts index ded027335..ae1040966 100644 --- a/src/scripts/testUBAClient.ts +++ b/src/scripts/testUBAClient.ts @@ -12,7 +12,7 @@ import { Wallet, winston, config, - getSigner, + retrieveSignerFromCLIArgs, Logger, getBlockForTimestamp, disconnectRedisClient, @@ -140,7 +140,7 @@ export async function testUBAClient(_logger: winston.Logger, baseSigner: Wallet) } export async function run(_logger: winston.Logger): Promise { - const baseSigner: Wallet = await getSigner(); + const baseSigner: Wallet = await retrieveSignerFromCLIArgs(); await testUBAClient(_logger, baseSigner); await disconnectRedisClient(logger); } diff --git a/src/scripts/validateRootBundle.ts b/src/scripts/validateRootBundle.ts index 27caff3b0..2d9642bd2 100644 --- a/src/scripts/validateRootBundle.ts +++ b/src/scripts/validateRootBundle.ts @@ -13,7 +13,7 @@ import { Wallet, winston, config, - getSigner, + retrieveSignerFromCLIArgs, startupLogLevel, Logger, getDvmContract, @@ -201,7 +201,7 @@ export async function validate(_logger: winston.Logger, baseSigner: Wallet): Pro } export async function run(_logger: winston.Logger): Promise { - const baseSigner: Wallet = await getSigner(); + const baseSigner: Wallet = await retrieveSignerFromCLIArgs(); await validate(_logger, baseSigner); await disconnectRedisClient(logger); } diff --git a/src/scripts/validateRunningBalances.ts b/src/scripts/validateRunningBalances.ts index 71cd31ecb..6c0f18982 100644 --- a/src/scripts/validateRunningBalances.ts +++ b/src/scripts/validateRunningBalances.ts @@ -23,7 +23,6 @@ import { Wallet, winston, config, - getSigner, Logger, toBN, fromWei, @@ -43,6 +42,7 @@ import { getBlockForChain, getEndBlockBuffers } from "../dataworker/DataworkerUt import { ProposedRootBundle, SlowFillLeaf, SpokePoolClientsByChain } from "../interfaces"; import { constructSpokePoolClientsWithStartBlocks, updateSpokePoolClients } from "../common"; import { createConsoleTransport } from "@uma/financial-templates-lib"; +import { retrieveSignerFromCLIArgs } from "../utils/CLIUtils"; config(); let logger: winston.Logger; @@ -450,7 +450,7 @@ export async function runScript(_logger: winston.Logger, baseSigner: Wallet): Pr } export async function run(_logger: winston.Logger): Promise { - const baseSigner: Wallet = await getSigner(); + const baseSigner: Wallet = await retrieveSignerFromCLIArgs(); await runScript(_logger, baseSigner); await disconnectRedisClient(logger); } diff --git a/src/utils/AddressUtils.ts b/src/utils/AddressUtils.ts index 126885879..c15c6e4b6 100644 --- a/src/utils/AddressUtils.ts +++ b/src/utils/AddressUtils.ts @@ -29,10 +29,23 @@ export function compareAddressesSimple(addressA: string, addressB: string): bool export function matchTokenSymbol(tokenAddress: string, chainId: number): string[] { // We can match one l1 token address on multiple symbols in some special cases, like ETH/WETH. return Object.values(TOKEN_SYMBOLS_MAP) - .filter(({ addresses }) => addresses[chainId].toLowerCase() === tokenAddress.toLowerCase()) + .filter(({ addresses }) => addresses[chainId]?.toLowerCase() === tokenAddress.toLowerCase()) .map(({ symbol }) => symbol); } +/** + * Match the token decimals for a given token symbol. + * @param tokenSymbol Symbol of the token to query. + * @returns The number of ERC20 decimals configured for the requested token. + */ +export function resolveTokenDecimals(tokenSymbol: string): number { + const decimals = TOKEN_SYMBOLS_MAP[tokenSymbol]?.decimals; + if (decimals === undefined) { + throw new Error(`Unrecognized token symbol: ${tokenSymbol}`); + } + return decimals; +} + /** * Resolves a list of token symbols for a list of token addresses and a chain ID. * @param tokenAddresses The token addresses to resolve the symbols for. @@ -43,7 +56,7 @@ export function resolveTokenSymbols(tokenAddresses: string[], chainId: number): const tokenSymbols = Object.values(TOKEN_SYMBOLS_MAP); return tokenAddresses .map((tokenAddress) => { - return tokenSymbols.find(({ addresses }) => addresses[chainId].toLowerCase() === tokenAddress.toLowerCase()) + return tokenSymbols.find(({ addresses }) => addresses[chainId]?.toLowerCase() === tokenAddress.toLowerCase()) ?.symbol; }) .filter(Boolean); diff --git a/src/utils/BigNumberUtils.ts b/src/utils/BigNumberUtils.ts deleted file mode 100644 index d1e9fb8de..000000000 --- a/src/utils/BigNumberUtils.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { BigNumber } from "."; - -export function max(a: BigNumber, b: BigNumber): BigNumber { - return a.gt(b) ? a : b; -} - -export function min(a: BigNumber, b: BigNumber): BigNumber { - return a.gt(b) ? b : a; -} diff --git a/src/utils/CLIUtils.ts b/src/utils/CLIUtils.ts new file mode 100644 index 000000000..9c84ea3a6 --- /dev/null +++ b/src/utils/CLIUtils.ts @@ -0,0 +1,35 @@ +import minimist from "minimist"; +import { SignerOptions, getSigner } from "./SignerUtils"; +import { Wallet } from "ethers"; + +/** + * Retrieves a signer based on both the CLI args and the env. + * @returns A signer based on the CLI args. + */ +export function retrieveSignerFromCLIArgs(): Promise { + // Call into the process' argv to retrieve the CLI args. + const args = minimist(process.argv.slice(2)); + // Resolve the wallet type & verify that it is valid. + const keyType = ((args.wallet as string) ?? "MNEMONIC").toLowerCase(); + if (!isValidKeyType(keyType)) { + throw new Error("Must define mnemonic, privatekey or gckms for wallet"); + } + + // Build out the signer options to pass to the signer utils. + const signerOptions: SignerOptions = { + keyType, + gckmsKeys: [args.keys], + cleanEnv: false, // TODO: We don't want to clean the env for now. This will be changed in the future. + }; + // Return the signer. + return getSigner(signerOptions); +} + +/** + * Checks if the key type is valid for being passed as input to the CLI + * @param keyType The key type to check. + * @returns True if the key type is valid, false otherwise. + */ +function isValidKeyType(keyType: unknown): keyType is "mnemonic" | "privateKey" | "gckms" { + return ["mnemonic", "privateKey", "gckms"].includes((keyType as string).toLowerCase()); +} diff --git a/src/utils/FillMathUtils.ts b/src/utils/FillMathUtils.ts index 0a379aa8f..8701c08d3 100644 --- a/src/utils/FillMathUtils.ts +++ b/src/utils/FillMathUtils.ts @@ -1,5 +1,5 @@ import { Fill } from "../interfaces"; -import { toBNWei, BigNumber, toBN } from "."; +import { BigNumber, toBN, toBNWei } from "."; export function _getRefundForFill(fill: Fill): BigNumber { return fill.fillAmount.mul(toBNWei(1).sub(fill.realizedLpFeePct)).div(toBNWei(1)); diff --git a/src/utils/FillUtils.ts b/src/utils/FillUtils.ts index 0dbf0901a..40e61cc30 100644 --- a/src/utils/FillUtils.ts +++ b/src/utils/FillUtils.ts @@ -9,8 +9,8 @@ import { getRefundForFills, isDefined, sortEventsDescending, - toBN, sortEventsAscending, + toBN, } from "./"; import { getBlockRangeForChain } from "../dataworker/DataworkerUtils"; import { clients } from "@across-protocol/sdk-v2"; diff --git a/src/utils/FormattingUtils.ts b/src/utils/FormattingUtils.ts deleted file mode 100644 index f395d875a..000000000 --- a/src/utils/FormattingUtils.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { ethers, BigNumber } from "ethers"; -import { utils, constants } from "@across-protocol/sdk-v2"; -import { createFormatFunction } from "@uma/common"; - -export { createFormatFunction }; -export type BigNumberish = ethers.BigNumberish; -export type BN = ethers.BigNumber; - -export const toWei = (num: BigNumberish): BN => ethers.utils.parseEther(num.toString()); - -export const toBNWei = utils.toBNWei; - -export const toGWei = (num: BigNumberish): BN => ethers.utils.parseUnits(num.toString(), 9); - -export const fromWei = utils.fromWei; - -// @todo: Backport support for decimal points to @across-protocol/sdk-v2 -export const toBN = (num: BigNumberish): BN => { - // If the string version of the num contains a `.` then it is a number which needs to be parsed to a string int. - if (num.toString().includes(".")) { - return BigNumber.from(parseInt(num.toString())); - } - return BigNumber.from(num.toString()); -}; - -export const formatFeePct = (relayerFeePct: BigNumber): string => { - // 1e18 = 100% so 1e16 = 1%. - return createFormatFunction(2, 4, false, 16)(toBN(relayerFeePct).toString()); -}; - -export function etherscanLink(txHashOrAddress: string, chainId: number | string): string { - return _createEtherscanLinkMarkdown(txHashOrAddress, Number(chainId)); -} - -// Generate an etherscan link prefix. If a networkId is provided then the URL will point to this network. Else, assume mainnet. -export function createEtherscanLinkFromTx(networkId: number): string { - let url; - if (constants.PUBLIC_NETWORKS[networkId]) { - url = `${constants.PUBLIC_NETWORKS[networkId].etherscan}`; - } else { - url = "https://etherscan.io/"; - } - - return url; -} - -// Convert either an address or transaction to a shorter version. -// 0x772871a444c6e4e9903d8533a5a13101b74037158123e6709470f0afbf6e7d94 -> 0x7787...7d94 -export function createShortHexString(hex: string): string { - return hex.substring(0, 5) + "..." + hex.substring(hex.length - 6, hex.length); -} - -// Take in either a transaction or an account and generate an etherscan link for the corresponding -// network formatted in markdown. -function _createEtherscanLinkMarkdown(hex: string, chainId = 1): string | null { - if (hex.substring(0, 2) != "0x") { - return null; - } - const shortURLString = createShortHexString(hex); - // Transaction hash - if (hex.length == 66) { - return `<${createEtherscanLinkFromTx(chainId)}tx/${hex}|${shortURLString}>`; - } - // Account - else if (hex.length == 42) { - return `<${createEtherscanLinkFromTx(chainId)}address/${hex}|${shortURLString}>`; - } - return null; -} - -export function etherscanLinks(txHashesOrAddresses: string[], chainId: number | string): string { - return txHashesOrAddresses.map((hash) => `${etherscanLink(hash, chainId)}\n`).join(""); -} - -export const utf8ToHex = (input: string): string => ethers.utils.formatBytes32String(input); - -export const hexToUtf8 = (input: string): string => ethers.utils.toUtf8String(input); - -export const bnToHex = (input: BigNumber): string => ethers.utils.hexZeroPad(ethers.utils.hexlify(toBN(input)), 32); - -export const convertFromWei = (weiVal: string, decimals: number): string => { - const formatFunction = createFormatFunction(2, 4, false, decimals); - return formatFunction(weiVal); -}; - -export const shortenHexStrings = (addresses: string[]): string[] => { - return addresses.map((address) => shortenHexString(address)); -}; - -export const shortenHexString = (hexString: string): string => { - return hexString.substring(0, 10); -}; diff --git a/src/utils/ProviderUtils.ts b/src/utils/ProviderUtils.ts index 66bcad297..9f60c3dcd 100644 --- a/src/utils/ProviderUtils.ts +++ b/src/utils/ProviderUtils.ts @@ -90,7 +90,8 @@ function compareRpcResults(method: string, rpcResultA: any, rpcResultB: any): bo // We've seen some RPC's like QuickNode add in transactionLogIndex which isn't in the // JSON RPC spec: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_getfilterchanges // Additional reference: https://github.com/ethers-io/ethers.js/issues/1721 - return compareResultsAndFilterIgnoredKeys(["transactionLogIndex"], rpcResultA, rpcResultB); + // 2023-08-31 Added blockHash because of upstream zkSync provider disagreements. Consider removing later. + return compareResultsAndFilterIgnoredKeys(["blockHash", "transactionLogIndex"], rpcResultA, rpcResultB); } else { return lodash.isEqual(rpcResultA, rpcResultB); } diff --git a/src/utils/SDKUtils.ts b/src/utils/SDKUtils.ts new file mode 100644 index 000000000..47122d435 --- /dev/null +++ b/src/utils/SDKUtils.ts @@ -0,0 +1,19 @@ +import { utils as sdkUtils } from "@across-protocol/sdk-v2"; + +export const { + toBN, + bnToHex, + toWei, + toBNWei, + formatFeePct, + shortenHexStrings, + convertFromWei, + max, + min, + utf8ToHex, + createFormatFunction, + fromWei, + blockExplorerLink, + blockExplorerLinks, + createShortHexString: shortenHexString, +} = sdkUtils; diff --git a/src/utils/SignerUtils.ts b/src/utils/SignerUtils.ts index f24b7adee..8ff77d1ed 100644 --- a/src/utils/SignerUtils.ts +++ b/src/utils/SignerUtils.ts @@ -1,42 +1,103 @@ -import { Wallet, retrieveGckmsKeys, getGckmsConfig } from "./"; -// const args = require("minimist")(process.argv.slice(2)); +import { Wallet, retrieveGckmsKeys, getGckmsConfig, isDefined } from "./"; -import minimist from "minimist"; -const args = minimist(process.argv.slice(2)); +/** + * Signer options for the getSigner function. + */ +export type SignerOptions = { + /* + * The type of wallet to use. + * @note If using a GCKMS wallet, the gckmsKeys parameter must be set. + */ + keyType: "mnemonic" | "privateKey" | "gckms"; + /** + * Whether or not to clear the mnemonic/private key from the env after retrieving the signer. + * @note Not including this parameter or setting it to false will not clear the mnemonic/private key from the env. + */ + cleanEnv?: boolean; + /** + * The GCKMS keys to use. + * @note This parameter is only required if the keyType is set to gckms. + */ + gckmsKeys?: string[]; +}; -export async function getSigner(): Promise { - if (!Object.keys(args).includes("wallet")) { - throw new Error("Must define mnemonic, privatekey or gckms for wallet"); - } - if (args.wallet === "mnemonic") { - return getMnemonicSigner(); +/** + * Retrieves a signer based on the wallet type defined in the args. + * @param cleanEnv If true, clears the mnemonic and private key from the env after retrieving the signer. + * @returns A signer. + * @throws If the wallet type is not defined or the mnemonic/private key is not set. + * @note If cleanEnv is true, the mnemonic and private key will be cleared from the env after retrieving the signer. + * @note This function will throw if called a second time after the first call with cleanEnv = true. + */ +export async function getSigner({ keyType, gckmsKeys, cleanEnv }: SignerOptions): Promise { + let wallet: Wallet | undefined = undefined; + switch (keyType) { + case "mnemonic": + wallet = getMnemonicSigner(); + break; + case "privateKey": + wallet = getPrivateKeySigner(); + break; + case "gckms": + wallet = await getGckmsSigner(gckmsKeys); + break; + default: + throw new Error("Must define mnemonic, privatekey or gckms for wallet"); } - if (args.wallet === "privateKey") { - return getPrivateKeySigner(); + if (!wallet) { + throw new Error("Must define mnemonic, privatekey or gckms for wallet"); } - if (args.wallet === "gckms") { - return await getGckmsSigner(); + if (cleanEnv) { + cleanKeysFromEnvironment(); } + return wallet; } -function getPrivateKeySigner() { +/** + * Retrieves a signer based on the mnemonic set in the env. + * @returns A signer based on the mnemonic set in the env. + * @throws If a valid private key is not defined in the environment. + */ +function getPrivateKeySigner(): Wallet { if (!process.env.PRIVATE_KEY) { throw new Error("Wallet private key selected but no PRIVATE_KEY env set!"); } return new Wallet(process.env.PRIVATE_KEY); } -async function getGckmsSigner() { - if (!args.keys) { +/** + * Retrieves a signer based on the GCKMS key set in the args. + * @returns A signer based on the GCKMS key set in the args. + * @throws If the GCKMS key is not set. + */ +async function getGckmsSigner(keys?: string[]): Promise { + if (!isDefined(keys) || keys.length === 0) { throw new Error("Wallet GCKSM selected but no keys parameter set! Set GCKMS key to use"); } - const privateKeys = await retrieveGckmsKeys(getGckmsConfig([args.keys])); + const privateKeys = await retrieveGckmsKeys(getGckmsConfig(keys)); return new Wallet(privateKeys[0]); // GCKMS retrieveGckmsKeys returns multiple keys. For now we only support 1. } -function getMnemonicSigner() { +/** + * Retrieves a signer based on the mnemonic set in the env. + * @returns A signer based on the mnemonic set in the env. + * @throws If a valid mnemonic is not defined in the environment. + */ +function getMnemonicSigner(): Wallet { if (!process.env.MNEMONIC) { throw new Error("Wallet mnemonic selected but no MNEMONIC env set!"); } return Wallet.fromMnemonic(process.env.MNEMONIC); } + +/** + * Clears the mnemonic and private key from the env. + */ +function cleanKeysFromEnvironment(): void { + if (process.env.MNEMONIC) { + delete process.env.MNEMONIC; + } + if (process.env.PRIVATE_KEY) { + delete process.env.PRIVATE_KEY; + } +} diff --git a/src/utils/TransactionUtils.ts b/src/utils/TransactionUtils.ts index ea0da36f2..616ef0d5c 100644 --- a/src/utils/TransactionUtils.ts +++ b/src/utils/TransactionUtils.ts @@ -1,12 +1,21 @@ import { gasPriceOracle, typeguards } from "@across-protocol/sdk-v2"; -import { AugmentedTransaction } from "../clients"; -import { winston, Contract, getContractInfoFromAddress, ethers, Wallet } from "../utils"; -import { DEFAULT_GAS_FEE_SCALERS, multicall3Addresses } from "../common"; -import { toBNWei, BigNumber, toBN, TransactionResponse } from "../utils"; +import { FeeData } from "@ethersproject/abstract-provider"; import { getAbi } from "@uma/contracts-node"; import dotenv from "dotenv"; -import { FeeData } from "@ethersproject/abstract-provider"; +import { AugmentedTransaction } from "../clients"; +import { DEFAULT_GAS_FEE_SCALERS, multicall3Addresses } from "../common"; import { EthersError } from "../interfaces"; +import { + BigNumber, + Contract, + TransactionResponse, + Wallet, + ethers, + getContractInfoFromAddress, + toBN, + toBNWei, + winston, +} from "../utils"; dotenv.config(); export type TransactionSimulationResult = { diff --git a/src/utils/index.ts b/src/utils/index.ts index ad6941498..8e1074a45 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,6 +1,7 @@ // Utils from other packages. import winston from "winston"; import assert from "assert"; + export { winston, assert }; export { Logger } from "@uma/financial-templates-lib"; @@ -11,6 +12,7 @@ export type { Block, TransactionResponse, TransactionReceipt, Provider } from "@ export { config } from "dotenv"; // Utils specifically for this bot. +export * from "./SDKUtils"; export * from "./chains"; export * from "./ProviderUtils"; export * from "./SignerUtils"; @@ -19,7 +21,6 @@ export * from "./BlockUtils"; export * from "./EventUtils"; export * from "./FillUtils"; export * from "./ObjectUtils"; -export * from "./FormattingUtils"; export * from "./TransactionPropBuilder"; export * from "./ContractUtils"; export * from "./ExecutionUtils"; @@ -34,10 +35,10 @@ export * from "./TypeGuards"; export * from "./Help"; export * from "./LogUtils"; export * from "./TypeUtils"; -export * from "./BigNumberUtils"; export * from "./RedisUtils"; export * from "./UmaUtils"; export * from "./TokenUtils"; +export * from "./CLIUtils"; export { ZERO_ADDRESS, MAX_SAFE_ALLOWANCE, MAX_UINT_VAL, replaceAddressCase } from "@uma/common"; diff --git a/test/AdapterManager.SendTokensCrossChain.ts b/test/AdapterManager.SendTokensCrossChain.ts index 6dfa7f249..e25ea3cb8 100644 --- a/test/AdapterManager.SendTokensCrossChain.ts +++ b/test/AdapterManager.SendTokensCrossChain.ts @@ -1,12 +1,23 @@ -import { expect, ethers, SignerWithAddress, createSpyLogger, winston } from "./utils"; -import { BigNumber, deployConfigStore, FakeContract, hubPoolFixture, smock, toBN } from "./utils"; -import { MockConfigStoreClient, MockHubPoolClient } from "./mocks"; -import { bnToHex, getL2TokenAddresses, toBNWei } from "../src/utils"; +import { constants } from "@across-protocol/sdk-v2"; +import * as zksync from "zksync-web3"; import { SpokePoolClient } from "../src/clients"; import { AdapterManager } from "../src/clients/bridges"; // Tested -import { constants } from "@across-protocol/sdk-v2"; import { CONTRACT_ADDRESSES } from "../src/common"; -import * as zksync from "zksync-web3"; +import { bnToHex, getL2TokenAddresses, toBNWei } from "../src/utils"; +import { MockConfigStoreClient, MockHubPoolClient } from "./mocks"; +import { + BigNumber, + FakeContract, + SignerWithAddress, + createSpyLogger, + deployConfigStore, + ethers, + expect, + hubPoolFixture, + smock, + toBN, + winston, +} from "./utils"; const { TOKEN_SYMBOLS_MAP, CHAIN_IDs } = constants; let hubPoolClient: MockHubPoolClient; diff --git a/test/AdapterManager.getOutstandingCrossChainTokenTransferAmount.ts b/test/AdapterManager.getOutstandingCrossChainTokenTransferAmount.ts index d5c13673a..1e7c68409 100644 --- a/test/AdapterManager.getOutstandingCrossChainTokenTransferAmount.ts +++ b/test/AdapterManager.getOutstandingCrossChainTokenTransferAmount.ts @@ -1,8 +1,7 @@ -import { expect, createSpyLogger } from "./utils"; -import { toBN } from "./utils"; -import { BaseAdapter } from "../src/clients/bridges"; import { SpokePoolClient } from "../src/clients"; +import { BaseAdapter } from "../src/clients/bridges"; import { OutstandingTransfers } from "../src/interfaces"; +import { createSpyLogger, expect, toBN } from "./utils"; class TestAdapter extends BaseAdapter { constructor() { diff --git a/test/ConfigStoreClient.ts b/test/ConfigStoreClient.ts index 00bd97207..3e9275d04 100644 --- a/test/ConfigStoreClient.ts +++ b/test/ConfigStoreClient.ts @@ -1,15 +1,28 @@ -import { mineRandomBlocks, originChainId } from "./utils"; -import { expect, ethers, Contract, SignerWithAddress } from "./utils"; -import { toWei, createSpyLogger } from "./utils"; -import { getContractFactory, hubPoolFixture, toBN, utf8ToHex } from "./utils"; -import { destinationChainId } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD } from "./constants"; +import { AcrossConfigStore } from "@across-protocol/contracts-v2"; +import { constants } from "@across-protocol/sdk-v2"; import { GLOBAL_CONFIG_STORE_KEYS } from "../src/clients"; import { SpokePoolTargetBalance } from "../src/interfaces"; +import { + DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + destinationChainId, +} from "./constants"; import { DEFAULT_CONFIG_STORE_VERSION, MockConfigStoreClient } from "./mocks"; -import { constants } from "@across-protocol/sdk-v2"; -import { AcrossConfigStore } from "@across-protocol/contracts-v2"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + ethers, + expect, + getContractFactory, + hubPoolFixture, + mineRandomBlocks, + originChainId, + toBN, + toWei, + utf8ToHex, +} from "./utils"; let l1Token: Contract, l2Token: Contract, configStore: AcrossConfigStore; let owner: SignerWithAddress; diff --git a/test/Dataworker.buildRoots.ts b/test/Dataworker.buildRoots.ts index 4b947aef4..aa1761042 100644 --- a/test/Dataworker.buildRoots.ts +++ b/test/Dataworker.buildRoots.ts @@ -1,33 +1,53 @@ +import { ConfigStoreClient, HubPoolClient, SpokePoolClient } from "../src/clients"; +import { Deposit, Fill, RunningBalances } from "../src/interfaces"; import { - buildSlowRelayTree, - buildSlowRelayLeaves, - buildFillForRepaymentChain, - enableRoutesOnHubPool, - createSpyLogger, - lastSpyLogIncludes, - deepEqualsWithBigNumber, - buildRefundRequest, -} from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, toBN, toBNWei, setupTokensForWallet } from "./utils"; -import { buildDeposit, buildFill, buildSlowFill, BigNumber, deployNewTokenMapping } from "./utils"; -import { buildRelayerRefundTreeWithUnassignedLeafIds, constructPoolRebalanceTree } from "./utils"; -import { buildPoolRebalanceLeafTree, sampleRateModel, getDefaultBlockRange } from "./utils"; -import { HubPoolClient, ConfigStoreClient, SpokePoolClient } from "../src/clients"; + EMPTY_MERKLE_ROOT, + compareAddresses, + getRealizedLpFeeForFills, + getRefund, + getRefundForFills, +} from "../src/utils"; import { + CHAIN_ID_TEST_LIST, + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, amountToDeposit, + buildPoolRebalanceLeaves, destinationChainId, - originChainId, mockTreeRoot, - buildPoolRebalanceLeaves, modifyRelayHelper, + originChainId, + refundProposalLiveness, repaymentChainId, } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { refundProposalLiveness, CHAIN_ID_TEST_LIST } from "./constants"; import { setupFastDataworker } from "./fixtures/Dataworker.Fixture"; -import { Deposit, Fill, RunningBalances } from "../src/interfaces"; -import { getRealizedLpFeeForFills, getRefundForFills, getRefund, EMPTY_MERKLE_ROOT } from "../src/utils"; -import { compareAddresses } from "../src/utils"; +import { + BigNumber, + Contract, + SignerWithAddress, + buildDeposit, + buildFill, + buildFillForRepaymentChain, + buildPoolRebalanceLeafTree, + buildRefundRequest, + buildRelayerRefundTreeWithUnassignedLeafIds, + buildSlowFill, + buildSlowRelayLeaves, + buildSlowRelayTree, + constructPoolRebalanceTree, + createSpyLogger, + deepEqualsWithBigNumber, + deployNewTokenMapping, + enableRoutesOnHubPool, + ethers, + expect, + getDefaultBlockRange, + lastSpyLogIncludes, + sampleRateModel, + setupTokensForWallet, + toBN, + toBNWei, +} from "./utils"; // Tested import { Dataworker } from "../src/dataworker/Dataworker"; diff --git a/test/Dataworker.customSpokePoolClients.ts b/test/Dataworker.customSpokePoolClients.ts index 1f8d84ce9..ebe0b5d96 100644 --- a/test/Dataworker.customSpokePoolClients.ts +++ b/test/Dataworker.customSpokePoolClients.ts @@ -1,10 +1,8 @@ -import { lastSpyLogIncludes, lastSpyLogLevel, spyLogIncludes, spyLogLevel } from "./utils"; -import { expect, ethers, Contract } from "./utils"; -import { SpokePoolClient, MultiCallerClient } from "../src/clients"; -import { utf8ToHex } from "./constants"; -import { CHAIN_ID_TEST_LIST } from "./constants"; -import { setupFastDataworker } from "./fixtures/Dataworker.Fixture"; +import { MultiCallerClient, SpokePoolClient } from "../src/clients"; import { MAX_UINT_VAL } from "../src/utils"; +import { CHAIN_ID_TEST_LIST, utf8ToHex } from "./constants"; +import { setupFastDataworker } from "./fixtures/Dataworker.Fixture"; +import { Contract, ethers, expect, lastSpyLogIncludes, lastSpyLogLevel, spyLogIncludes, spyLogLevel } from "./utils"; // Tested import { Dataworker } from "../src/dataworker/Dataworker"; diff --git a/test/Dataworker.executePoolRebalances.ts b/test/Dataworker.executePoolRebalances.ts index 598d7caae..a44d26707 100644 --- a/test/Dataworker.executePoolRebalances.ts +++ b/test/Dataworker.executePoolRebalances.ts @@ -1,16 +1,18 @@ -import { buildFillForRepaymentChain } from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, buildDeposit } from "./utils"; import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; -import { amountToDeposit } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD } from "./constants"; -import { setupDataworker } from "./fixtures/Dataworker.Fixture"; import { MAX_UINT_VAL } from "../src/utils"; +import { + DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + amountToDeposit, +} from "./constants"; +import { setupDataworker } from "./fixtures/Dataworker.Fixture"; +import { Contract, SignerWithAddress, buildDeposit, buildFillForRepaymentChain, ethers, expect } from "./utils"; // Tested -import { Dataworker } from "../src/dataworker/Dataworker"; -import { spokePoolClientsToProviders } from "../src/common"; import { BalanceAllocator } from "../src/clients/BalanceAllocator"; +import { spokePoolClientsToProviders } from "../src/common"; +import { Dataworker } from "../src/dataworker/Dataworker"; // Set to arbitrum to test that the dataworker sends ETH to the HubPool to test L1 --> Arbitrum message transfers. const destinationChainId = 42161; diff --git a/test/Dataworker.executeRelayerRefunds.ts b/test/Dataworker.executeRelayerRefunds.ts index f57a91acc..0152195d7 100644 --- a/test/Dataworker.executeRelayerRefunds.ts +++ b/test/Dataworker.executeRelayerRefunds.ts @@ -1,15 +1,18 @@ -import { buildFillForRepaymentChain } from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, buildDeposit } from "./utils"; import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; -import { amountToDeposit, destinationChainId } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { setupDataworker } from "./fixtures/Dataworker.Fixture"; import { MAX_UINT_VAL } from "../src/utils"; +import { + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + amountToDeposit, + destinationChainId, +} from "./constants"; +import { setupDataworker } from "./fixtures/Dataworker.Fixture"; +import { Contract, SignerWithAddress, buildDeposit, buildFillForRepaymentChain, ethers, expect } from "./utils"; // Tested -import { Dataworker } from "../src/dataworker/Dataworker"; -import { spokePoolClientsToProviders } from "../src/common"; import { BalanceAllocator } from "../src/clients/BalanceAllocator"; +import { spokePoolClientsToProviders } from "../src/common"; +import { Dataworker } from "../src/dataworker/Dataworker"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; let l1Token_1: Contract, hubPool: Contract; diff --git a/test/Dataworker.executeSlowRelay.ts b/test/Dataworker.executeSlowRelay.ts index 11c1dfbeb..c7bcd52af 100644 --- a/test/Dataworker.executeSlowRelay.ts +++ b/test/Dataworker.executeSlowRelay.ts @@ -1,12 +1,15 @@ -import { buildFillForRepaymentChain } from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, buildDeposit } from "./utils"; import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; -import { amountToDeposit, destinationChainId } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { setupDataworker } from "./fixtures/Dataworker.Fixture"; -import { MAX_UINT_VAL } from "../src/utils"; import { BalanceAllocator } from "../src/clients/BalanceAllocator"; import { spokePoolClientsToProviders } from "../src/common"; +import { MAX_UINT_VAL } from "../src/utils"; +import { + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + amountToDeposit, + destinationChainId, +} from "./constants"; +import { setupDataworker } from "./fixtures/Dataworker.Fixture"; +import { Contract, SignerWithAddress, buildDeposit, buildFillForRepaymentChain, ethers, expect } from "./utils"; // Tested import { Dataworker } from "../src/dataworker/Dataworker"; diff --git a/test/Dataworker.loadData.ts b/test/Dataworker.loadData.ts index 91871b622..5fe5bf105 100644 --- a/test/Dataworker.loadData.ts +++ b/test/Dataworker.loadData.ts @@ -1,33 +1,44 @@ import { - expect, - ethers, + BalanceAllocator, + BundleDataClient, + ConfigStoreClient, + HubPoolClient, + MultiCallerClient, + SpokePoolClient, +} from "../src/clients"; +import { + CHAIN_ID_TEST_LIST, + IMPOSSIBLE_BLOCK_RANGE, + amountToDeposit, + destinationChainId, + originChainId, + repaymentChainId, +} from "./constants"; +import { setupDataworker } from "./fixtures/Dataworker.Fixture"; +import { Contract, - getDefaultBlockRange, - buildFillForRepaymentChain, - getLastBlockNumber, + SignerWithAddress, assertPromiseError, - spyLogIncludes, + buildDeposit, + buildFill, + buildFillForRepaymentChain, + buildModifiedFill, buildRefundRequest, + buildSlowFill, + buildSlowRelayLeaves, + buildSlowRelayTree, + ethers, + expect, + getDefaultBlockRange, + getLastBlockNumber, sinon, + spyLogIncludes, } from "./utils"; -import { SignerWithAddress, buildSlowRelayTree } from "./utils"; -import { buildDeposit, buildFill, buildModifiedFill, buildSlowRelayLeaves, buildSlowFill } from "./utils"; -import { - SpokePoolClient, - HubPoolClient, - ConfigStoreClient, - BundleDataClient, - MultiCallerClient, - BalanceAllocator, -} from "../src/clients"; -import { amountToDeposit, repaymentChainId, destinationChainId, originChainId, CHAIN_ID_TEST_LIST } from "./constants"; -import { IMPOSSIBLE_BLOCK_RANGE } from "./constants"; -import { setupDataworker } from "./fixtures/Dataworker.Fixture"; -import { Dataworker } from "../src/dataworker/Dataworker"; // Tested -import { toBN, getRefundForFills, getRealizedLpFeeForFills, MAX_UINT_VAL } from "../src/utils"; import { spokePoolClientsToProviders } from "../src/common"; +import { Dataworker } from "../src/dataworker/Dataworker"; // Tested import { DepositWithBlock, Fill } from "../src/interfaces"; +import { MAX_UINT_VAL, getRealizedLpFeeForFills, getRefundForFills, toBN } from "../src/utils"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; let l1Token_1: Contract, l1Token_2: Contract, hubPool: Contract; @@ -732,7 +743,8 @@ describe("Dataworker: Load data used in all functions", async function () { (await dataworkerInstance.clients.bundleDataClient.loadData(IMPOSSIBLE_BLOCK_RANGE, spokePoolClients)).deposits ).to.deep.equal([]); }); - it.skip("Can fetch historical deposits not found in spoke pool client's memory", async function () { + + it("Can fetch historical deposits not found in spoke pool client's memory", async function () { // Send a deposit. await updateAllClients(); const deposit1 = await buildDeposit( @@ -761,16 +773,18 @@ describe("Dataworker: Load data used in all functions", async function () { // For queryHistoricalDepositForFill to work we need to have a deployment block set for the spoke pool client. const bundleData = await bundleDataClient.loadData(getDefaultBlockRange(0), spokePoolClients); expect(spyLogIncludes(spy, -2, "Located deposit outside of SpokePoolClient's search range")).is.true; - expect(bundleData.fillsToRefund).to.deep.equal({ - [destinationChainId]: { - [erc20_2.address]: { - fills: [fill1], - refunds: { [relayer.address]: getRefundForFills([fill1]) }, - totalRefundAmount: getRefundForFills([fill1]), - realizedLpFees: getRealizedLpFeeForFills([fill1]), + expect(bundleData.fillsToRefund) + .excludingEvery(["blockTimestamp"]) + .to.deep.equal({ + [destinationChainId]: { + [erc20_2.address]: { + fills: [fill1], + refunds: { [relayer.address]: getRefundForFills([fill1]) }, + totalRefundAmount: getRefundForFills([fill1]), + realizedLpFees: getRealizedLpFeeForFills([fill1]), + }, }, - }, - }); + }); expect(bundleData.deposits).to.deep.equal([]); expect(bundleData.allValidFills.length).to.equal(1); expect(bundleData.unfilledDeposits) diff --git a/test/Dataworker.proposeRootBundle.ts b/test/Dataworker.proposeRootBundle.ts index 0f7dd6e01..eb9e067a2 100644 --- a/test/Dataworker.proposeRootBundle.ts +++ b/test/Dataworker.proposeRootBundle.ts @@ -1,14 +1,21 @@ -import { buildFillForRepaymentChain, lastSpyLogIncludes, lastSpyLogLevel } from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, buildDeposit, toBNWei } from "./utils"; -import { HubPoolClient, SpokePoolClient, MultiCallerClient } from "../src/clients"; -import { amountToDeposit, destinationChainId, originChainId, utf8ToHex } from "./constants"; -import { CHAIN_ID_TEST_LIST } from "./constants"; +import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; +import { EMPTY_MERKLE_ROOT, MAX_UINT_VAL, getDepositPath } from "../src/utils"; +import { CHAIN_ID_TEST_LIST, amountToDeposit, destinationChainId, originChainId, utf8ToHex } from "./constants"; import { setupFastDataworker } from "./fixtures/Dataworker.Fixture"; -import { MAX_UINT_VAL, EMPTY_MERKLE_ROOT } from "../src/utils"; +import { + Contract, + SignerWithAddress, + buildDeposit, + buildFillForRepaymentChain, + ethers, + expect, + lastSpyLogIncludes, + lastSpyLogLevel, + toBNWei, +} from "./utils"; // Tested import { Dataworker } from "../src/dataworker/Dataworker"; -import { getDepositPath } from "../src/utils"; import { FillWithBlock } from "../src/interfaces"; import { MockConfigStoreClient } from "./mocks"; diff --git a/test/Dataworker.validateRootBundle.ts b/test/Dataworker.validateRootBundle.ts index a8dffaaf5..a33c566a3 100644 --- a/test/Dataworker.validateRootBundle.ts +++ b/test/Dataworker.validateRootBundle.ts @@ -1,12 +1,27 @@ import hre from "hardhat"; -import { buildFillForRepaymentChain, lastSpyLogIncludes, spyLogIncludes, lastSpyLogLevel } from "./utils"; -import { SignerWithAddress, expect, ethers, Contract, buildDeposit } from "./utils"; -import { HubPoolClient, SpokePoolClient, MultiCallerClient } from "../src/clients"; -import { amountToDeposit, destinationChainId, BUNDLE_END_BLOCK_BUFFER, createRandomBytes32 } from "./constants"; -import { MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF } from "./constants"; -import { DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD } from "./constants"; +import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; +import { EMPTY_MERKLE_ROOT, MAX_UINT_VAL, utf8ToHex } from "../src/utils"; +import { + BUNDLE_END_BLOCK_BUFFER, + DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + amountToDeposit, + createRandomBytes32, + destinationChainId, +} from "./constants"; import { setupDataworker } from "./fixtures/Dataworker.Fixture"; -import { MAX_UINT_VAL, EMPTY_MERKLE_ROOT, utf8ToHex } from "../src/utils"; +import { + Contract, + SignerWithAddress, + buildDeposit, + buildFillForRepaymentChain, + ethers, + expect, + lastSpyLogIncludes, + lastSpyLogLevel, + spyLogIncludes, +} from "./utils"; // Tested import { Dataworker } from "../src/dataworker/Dataworker"; diff --git a/test/HubPoolClient.DepositToDestinationToken.ts b/test/HubPoolClient.DepositToDestinationToken.ts index 2e3146f24..cde36b6d1 100644 --- a/test/HubPoolClient.DepositToDestinationToken.ts +++ b/test/HubPoolClient.DepositToDestinationToken.ts @@ -1,7 +1,18 @@ -import { getContractFactory, expect, ethers, Contract, SignerWithAddress, originChainId } from "./utils"; -import { deployConfigStore, zeroAddress, destinationChainId, toBN, createSpyLogger } from "./utils"; -import { randomL1Token, randomOriginToken, randomDestinationToken, randomDestinationToken2 } from "./constants"; import { ConfigStoreClient, HubPoolClient } from "../src/clients"; +import { randomDestinationToken, randomDestinationToken2, randomL1Token, randomOriginToken } from "./constants"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + deployConfigStore, + destinationChainId, + ethers, + expect, + getContractFactory, + originChainId, + toBN, + zeroAddress, +} from "./utils"; let hubPool: Contract, lpTokenFactory: Contract, mockAdapter: Contract; let owner: SignerWithAddress; diff --git a/test/HubPoolClient.RootBundleEvents.ts b/test/HubPoolClient.RootBundleEvents.ts index 697e41f0e..6c9fb7075 100644 --- a/test/HubPoolClient.RootBundleEvents.ts +++ b/test/HubPoolClient.RootBundleEvents.ts @@ -1,13 +1,26 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import hre from "hardhat"; import { random } from "lodash"; -import { buildPoolRebalanceLeafTree, buildPoolRebalanceLeaves, createSpyLogger, randomAddress, winston } from "./utils"; -import { deployConfigStore, SignerWithAddress, expect, ethers, Contract, toBNWei, toBN, BigNumber } from "./utils"; import { ConfigStoreClient, HubPoolClient, UBA_MIN_CONFIG_STORE_VERSION } from "../src/clients"; +import { ProposedRootBundle } from "../src/interfaces"; import * as constants from "./constants"; import { setupDataworker } from "./fixtures/Dataworker.Fixture"; -import { ProposedRootBundle } from "../src/interfaces"; import { DEFAULT_CONFIG_STORE_VERSION, MockConfigStoreClient, MockHubPoolClient } from "./mocks"; +import { + BigNumber, + Contract, + SignerWithAddress, + buildPoolRebalanceLeafTree, + buildPoolRebalanceLeaves, + createSpyLogger, + deployConfigStore, + ethers, + expect, + randomAddress, + toBN, + toBNWei, + winston, +} from "./utils"; let hubPool: Contract, timer: Contract; let l1Token_1: Contract, l1Token_2: Contract; diff --git a/test/HubPoolClient.Utilization.ts b/test/HubPoolClient.Utilization.ts index 4f8dc84ab..f3aae8c61 100644 --- a/test/HubPoolClient.Utilization.ts +++ b/test/HubPoolClient.Utilization.ts @@ -1,8 +1,6 @@ -import { deploySpokePoolWithToken, repaymentChainId, originChainId, buildPoolRebalanceLeaves } from "./utils"; -import { expect, ethers, Contract, SignerWithAddress, setupTokensForWallet } from "./utils"; -import { toBNWei, toWei, buildPoolRebalanceLeafTree, createSpyLogger } from "./utils"; -import { deployConfigStore, hubPoolFixture, toBN } from "./utils"; +import { HubPoolClient } from "../src/clients"; import { + DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, amountToLp, destinationChainId, mockTreeRoot, @@ -10,9 +8,25 @@ import { refundProposalLiveness, totalBond, } from "./constants"; -import { DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD } from "./constants"; -import { HubPoolClient } from "../src/clients"; import { DEFAULT_CONFIG_STORE_VERSION, MockConfigStoreClient } from "./mocks"; +import { + Contract, + SignerWithAddress, + buildPoolRebalanceLeafTree, + buildPoolRebalanceLeaves, + createSpyLogger, + deployConfigStore, + deploySpokePoolWithToken, + ethers, + expect, + hubPoolFixture, + originChainId, + repaymentChainId, + setupTokensForWallet, + toBN, + toBNWei, + toWei, +} from "./utils"; let configStore: Contract, hubPool: Contract; let l1Token: Contract, l2Token: Contract, timer: Contract, weth: Contract; diff --git a/test/InventoryClient.InventoryRebalance.ts b/test/InventoryClient.InventoryRebalance.ts index 773142a12..d3f8a246b 100644 --- a/test/InventoryClient.InventoryRebalance.ts +++ b/test/InventoryClient.InventoryRebalance.ts @@ -1,10 +1,23 @@ -import { expect, ethers, SignerWithAddress, createSpyLogger, winston, BigNumber, lastSpyLogIncludes } from "./utils"; -import { deployConfigStore, hubPoolFixture, toBN, toWei, randomAddress, spyLogIncludes } from "./utils"; +import { + BigNumber, + SignerWithAddress, + createSpyLogger, + deployConfigStore, + ethers, + expect, + hubPoolFixture, + lastSpyLogIncludes, + randomAddress, + spyLogIncludes, + toBN, + toWei, + winston, +} from "./utils"; -import { InventoryConfig } from "../src/interfaces"; -import { MockBundleDataClient, MockHubPoolClient, MockAdapterManager, MockTokenClient } from "./mocks/"; import { ConfigStoreClient, InventoryClient } from "../src/clients"; // Tested import { CrossChainTransferClient } from "../src/clients/bridges"; +import { InventoryConfig } from "../src/interfaces"; +import { MockAdapterManager, MockBundleDataClient, MockHubPoolClient, MockTokenClient } from "./mocks/"; const toMegaWei = (num: string | number | BigNumber) => ethers.utils.parseUnits(num.toString(), 6); diff --git a/test/InventoryClient.RefundChain.ts b/test/InventoryClient.RefundChain.ts index c217243d2..af785419f 100644 --- a/test/InventoryClient.RefundChain.ts +++ b/test/InventoryClient.RefundChain.ts @@ -1,10 +1,23 @@ -import { expect, ethers, SignerWithAddress, createSpyLogger, winston, BigNumber, lastSpyLogIncludes } from "./utils"; -import { deployConfigStore, hubPoolFixture, toBN, toWei, randomAddress, createRefunds } from "./utils"; +import { + BigNumber, + SignerWithAddress, + createRefunds, + createSpyLogger, + deployConfigStore, + ethers, + expect, + hubPoolFixture, + lastSpyLogIncludes, + randomAddress, + toBN, + toWei, + winston, +} from "./utils"; -import { InventoryConfig, Deposit } from "../src/interfaces"; -import { MockBundleDataClient, MockHubPoolClient, MockAdapterManager, MockTokenClient } from "./mocks"; import { ConfigStoreClient, InventoryClient } from "../src/clients"; // Tested import { CrossChainTransferClient } from "../src/clients/bridges"; +import { Deposit, InventoryConfig } from "../src/interfaces"; +import { MockAdapterManager, MockBundleDataClient, MockHubPoolClient, MockTokenClient } from "./mocks"; const toMegaWei = (num: string | number | BigNumber) => ethers.utils.parseUnits(num.toString(), 6); diff --git a/test/Monitor.ts b/test/Monitor.ts index df52f2c35..e1e20f38b 100644 --- a/test/Monitor.ts +++ b/test/Monitor.ts @@ -1,30 +1,39 @@ -import { buildDeposit, buildFillForRepaymentChain, createSpyLogger, lastSpyLogIncludes, toBNWei } from "./utils"; -import { Contract, SignerWithAddress, ethers, expect } from "./utils"; import { - ConfigStoreClient, + BalanceAllocator, BundleDataClient, + ConfigStoreClient, HubPoolClient, - SpokePoolClient, MultiCallerClient, + SpokePoolClient, TokenTransferClient, - BalanceAllocator, } from "../src/clients"; import { CrossChainTransferClient } from "../src/clients/bridges"; +import { spokePoolClientsToProviders } from "../src/common"; +import { Dataworker } from "../src/dataworker/Dataworker"; +import { BalanceType } from "../src/interfaces"; import { - Monitor, ALL_CHAINS_NAME, - UNKNOWN_TRANSFERS_NAME, + Monitor, REBALANCE_FINALIZE_GRACE_PERIOD, + UNKNOWN_TRANSFERS_NAME, } from "../src/monitor/Monitor"; import { MonitorConfig } from "../src/monitor/MonitorConfig"; -import { amountToDeposit, destinationChainId, mockTreeRoot, originChainId, repaymentChainId } from "./constants"; +import { MAX_UINT_VAL, getNetworkName, getRefundForFills, toBN } from "../src/utils"; import * as constants from "./constants"; +import { amountToDeposit, destinationChainId, mockTreeRoot, originChainId, repaymentChainId } from "./constants"; import { setupDataworker } from "./fixtures/Dataworker.Fixture"; -import { Dataworker } from "../src/dataworker/Dataworker"; -import { getNetworkName, getRefundForFills, MAX_UINT_VAL, toBN } from "../src/utils"; -import { spokePoolClientsToProviders } from "../src/common"; import { MockAdapterManager } from "./mocks"; -import { BalanceType } from "../src/interfaces"; +import { + Contract, + SignerWithAddress, + buildDeposit, + buildFillForRepaymentChain, + createSpyLogger, + ethers, + expect, + lastSpyLogIncludes, + toBNWei, +} from "./utils"; let l1Token: Contract, l2Token: Contract, erc20_2: Contract; let hubPool: Contract, spokePool_1: Contract, spokePool_2: Contract; diff --git a/test/ProfitClient.ConsiderProfitability.ts b/test/ProfitClient.ConsiderProfitability.ts index a39dca79c..97431c878 100644 --- a/test/ProfitClient.ConsiderProfitability.ts +++ b/test/ProfitClient.ConsiderProfitability.ts @@ -1,20 +1,28 @@ import { utils as sdkUtils } from "@across-protocol/sdk-v2"; +import { + ConfigStoreClient, + FillProfit, + GAS_TOKEN_BY_CHAIN_ID, + MATIC, + SpokePoolClient, + USDC, + WBTC, + WETH, +} from "../src/clients"; +import { Deposit, DepositWithBlock, L1Token } from "../src/interfaces"; import { BigNumber, formatFeePct, toBN, toBNWei } from "../src/utils"; +import { MockHubPoolClient, MockProfitClient } from "./mocks"; import { - expect, createSpyLogger, deployConfigStore, - hubPoolFixture, - winston, - ethers, deploySpokePoolWithToken, - originChainId, destinationChainId, + ethers, + expect, + hubPoolFixture, + originChainId, + winston, } from "./utils"; -import { MockHubPoolClient, MockProfitClient } from "./mocks"; -import { Deposit, DepositWithBlock, L1Token } from "../src/interfaces"; -import { FillProfit, GAS_TOKEN_BY_CHAIN_ID, SpokePoolClient, MATIC, USDC, WBTC, WETH } from "../src/clients"; -import { ConfigStoreClient } from "../src/clients"; const { fixedPointAdjustment: fixedPoint } = sdkUtils; const { formatEther } = ethers.utils; diff --git a/test/Relayer.BasicFill.ts b/test/Relayer.BasicFill.ts index 4c7eaa7d9..8f13ec2f0 100644 --- a/test/Relayer.BasicFill.ts +++ b/test/Relayer.BasicFill.ts @@ -1,17 +1,16 @@ import { random } from "lodash"; import { - expect, - deposit, - ethers, - Contract, - SignerWithAddress, - setupTokensForWallet, - getLastBlockTime, - buildDeposit, -} from "./utils"; -import { lastSpyLogIncludes, createSpyLogger, deployConfigStore, deployAndConfigureHubPool, winston } from "./utils"; -import { deploySpokePoolWithToken, enableRoutesOnHubPool, destinationChainId } from "./utils"; -import { originChainId, sinon, toBNWei } from "./utils"; + AcrossApiClient, + ConfigStoreClient, + HubPoolClient, + MultiCallerClient, + SpokePoolClient, + TokenClient, +} from "../src/clients"; +import { CONFIG_STORE_VERSION, UBA_MIN_CONFIG_STORE_VERSION } from "../src/common"; +import { Deposit } from "../src/interfaces"; +import { Relayer } from "../src/relayer/Relayer"; +import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested import { amountToLp, defaultMinDepositConfirmations, @@ -21,20 +20,29 @@ import { repaymentChainId, utf8ToHex, } from "./constants"; -import { - SpokePoolClient, - HubPoolClient, - ConfigStoreClient, - MultiCallerClient, - AcrossApiClient, - TokenClient, -} from "../src/clients"; -import { CONFIG_STORE_VERSION, UBA_MIN_CONFIG_STORE_VERSION } from "../src/common"; import { MockConfigStoreClient, MockInventoryClient, MockProfitClient, MockUBAClient } from "./mocks"; -import { Relayer } from "../src/relayer/Relayer"; -import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested import { MockedMultiCallerClient } from "./mocks/MockMultiCallerClient"; -import { Deposit } from "../src/interfaces"; +import { + Contract, + SignerWithAddress, + buildDeposit, + createSpyLogger, + deployAndConfigureHubPool, + deployConfigStore, + deploySpokePoolWithToken, + deposit, + destinationChainId, + enableRoutesOnHubPool, + ethers, + expect, + getLastBlockTime, + lastSpyLogIncludes, + originChainId, + setupTokensForWallet, + sinon, + toBNWei, + winston, +} from "./utils"; import { generateNoOpSpokePoolClientsForDefaultChainIndices } from "./utils/UBAUtils"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; diff --git a/test/Relayer.RefundRequests.ts b/test/Relayer.RefundRequests.ts index a6a67eba8..27b222739 100644 --- a/test/Relayer.RefundRequests.ts +++ b/test/Relayer.RefundRequests.ts @@ -1,44 +1,50 @@ +import * as sdk from "@across-protocol/sdk-v2"; import hre from "hardhat"; import { random } from "lodash"; import { - ethers, - expect, - Contract, - SignerWithAddress, - setupTokensForWallet, - getLastBlockTime, - buildDeposit, - buildFillForRepaymentChain, - buildRefundRequest, -} from "./utils"; -import { createSpyLogger, deployConfigStore, deployAndConfigureHubPool, winston } from "./utils"; -import { deploySpokePoolWithToken, enableRoutesOnHubPool, destinationChainId } from "./utils"; -import { originChainId, toBNWei } from "./utils"; -import { - CHAIN_ID_TEST_LIST, - amountToLp, - defaultMinDepositConfirmations, - defaultTokenConfig, - repaymentChainId, -} from "./constants"; -import { - SpokePoolClient, - HubPoolClient, + AcrossApiClient, ConfigStoreClient, + HubPoolClient, MultiCallerClient, - AcrossApiClient, + SpokePoolClient, TokenClient, UBAClient, } from "../src/clients"; -import { FillWithBlock, RefundRequestWithBlock } from "../src/interfaces"; import { CONFIG_STORE_VERSION } from "../src/common"; -import { delay } from "../src/utils"; -import { MockConfigStoreClient, MockInventoryClient, MockProfitClient } from "./mocks"; +import { FillWithBlock, RefundRequestWithBlock } from "../src/interfaces"; import { Relayer } from "../src/relayer/Relayer"; import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested +import { delay } from "../src/utils"; +import { + CHAIN_ID_TEST_LIST, + amountToLp, + defaultMinDepositConfirmations, + defaultTokenConfig, + repaymentChainId, +} from "./constants"; +import { MockConfigStoreClient, MockInventoryClient, MockProfitClient } from "./mocks"; import { MockedMultiCallerClient } from "./mocks/MockMultiCallerClient"; +import { + Contract, + SignerWithAddress, + buildDeposit, + buildFillForRepaymentChain, + buildRefundRequest, + createSpyLogger, + deployAndConfigureHubPool, + deployConfigStore, + deploySpokePoolWithToken, + destinationChainId, + enableRoutesOnHubPool, + ethers, + expect, + getLastBlockTime, + originChainId, + setupTokensForWallet, + toBNWei, + winston, +} from "./utils"; import { generateNoOpSpokePoolClientsForDefaultChainIndices } from "./utils/UBAUtils"; -import * as sdk from "@across-protocol/sdk-v2"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; let hubPool: Contract, configStore: Contract, l1Token: Contract; diff --git a/test/Relayer.SlowFill.ts b/test/Relayer.SlowFill.ts index e61e12c76..550c9072c 100644 --- a/test/Relayer.SlowFill.ts +++ b/test/Relayer.SlowFill.ts @@ -1,26 +1,42 @@ -import { expect, deposit, ethers, Contract, SignerWithAddress, setupTokensForWallet, getLastBlockTime } from "./utils"; -import { lastSpyLogIncludes, createSpyLogger, deployConfigStore, deployAndConfigureHubPool, winston } from "./utils"; -import { deploySpokePoolWithToken, enableRoutesOnHubPool, destinationChainId, spyLogIncludes } from "./utils"; -import { originChainId, sinon } from "./utils"; import { - amountToLp, - defaultTokenConfig, - amountToDeposit, - defaultMinDepositConfirmations, - CHAIN_ID_TEST_LIST, - repaymentChainId, -} from "./constants"; -import { - SpokePoolClient, - HubPoolClient, + AcrossApiClient, ConfigStoreClient, + HubPoolClient, MultiCallerClient, - AcrossApiClient, - TokenClient, ProfitClient, + SpokePoolClient, + TokenClient, } from "../src/clients"; import { CONFIG_STORE_VERSION } from "../src/common"; +import { + CHAIN_ID_TEST_LIST, + amountToDeposit, + amountToLp, + defaultMinDepositConfirmations, + defaultTokenConfig, + repaymentChainId, +} from "./constants"; import { MockInventoryClient } from "./mocks"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + deployAndConfigureHubPool, + deployConfigStore, + deploySpokePoolWithToken, + deposit, + destinationChainId, + enableRoutesOnHubPool, + ethers, + expect, + getLastBlockTime, + lastSpyLogIncludes, + originChainId, + setupTokensForWallet, + sinon, + spyLogIncludes, + winston, +} from "./utils"; import { Relayer } from "../src/relayer/Relayer"; import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested diff --git a/test/Relayer.TokenShortfall.ts b/test/Relayer.TokenShortfall.ts index 057cdb3d6..7e178f06c 100644 --- a/test/Relayer.TokenShortfall.ts +++ b/test/Relayer.TokenShortfall.ts @@ -1,27 +1,43 @@ -import { deploySpokePoolWithToken, enableRoutesOnHubPool, destinationChainId, originChainId, sinon } from "./utils"; -import { expect, deposit, ethers, Contract, SignerWithAddress, setupTokensForWallet, getLastBlockTime } from "./utils"; -import { lastSpyLogIncludes, toBNWei, createSpyLogger, deployConfigStore } from "./utils"; -import { deployAndConfigureHubPool, winston } from "./utils"; import { - CHAIN_ID_TEST_LIST, - amountToLp, - defaultMinDepositConfirmations, - defaultTokenConfig, - repaymentChainId, -} from "./constants"; -import { - SpokePoolClient, - HubPoolClient, + AcrossApiClient, ConfigStoreClient, + HubPoolClient, MultiCallerClient, - AcrossApiClient, + SpokePoolClient, TokenClient, } from "../src/clients"; import { CONFIG_STORE_VERSION } from "../src/common"; -import { MockInventoryClient, MockProfitClient } from "./mocks"; import { Relayer } from "../src/relayer/Relayer"; import { RelayerConfig } from "../src/relayer/RelayerConfig"; // Tested +import { + CHAIN_ID_TEST_LIST, + amountToLp, + defaultMinDepositConfirmations, + defaultTokenConfig, + repaymentChainId, +} from "./constants"; +import { MockInventoryClient, MockProfitClient } from "./mocks"; import { MockedMultiCallerClient } from "./mocks/MockMultiCallerClient"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + deployAndConfigureHubPool, + deployConfigStore, + deploySpokePoolWithToken, + deposit, + destinationChainId, + enableRoutesOnHubPool, + ethers, + expect, + getLastBlockTime, + lastSpyLogIncludes, + originChainId, + setupTokensForWallet, + sinon, + toBNWei, + winston, +} from "./utils"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; let hubPool: Contract, configStore: Contract, l1Token: Contract; diff --git a/test/Relayer.UnfilledDeposits.ts b/test/Relayer.UnfilledDeposits.ts index 650cec257..fa478481d 100644 --- a/test/Relayer.UnfilledDeposits.ts +++ b/test/Relayer.UnfilledDeposits.ts @@ -1,36 +1,37 @@ +import { AcrossApiClient, HubPoolClient, MultiCallerClient, SpokePoolClient, TokenClient } from "../src/clients"; import { - createSpyLogger, - deployAndConfigureHubPool, - enableRoutesOnHubPool, + CHAIN_ID_TEST_LIST, + amountToLp, + defaultMinDepositConfirmations, + modifyRelayHelper, + originChainId, + repaymentChainId, +} from "./constants"; +import { MockInventoryClient, MockProfitClient, MockConfigStoreClient, MockedMultiCallerClient } from "./mocks"; +import { + Contract, + SignerWithAddress, buildDepositStruct, - lastSpyLogIncludes, buildFill, -} from "./utils"; -import { + createSpyLogger, + deployAndConfigureHubPool, + deployConfigStore, deploySpokePoolWithToken, destinationChainId, - deployConfigStore, - getLastBlockTime, + enableRoutesOnHubPool, + ethers, expect, + getLastBlockTime, + lastSpyLogIncludes, + setupTokensForWallet, + simpleDeposit, toBNWei, } from "./utils"; -import { simpleDeposit, ethers, Contract, SignerWithAddress, setupTokensForWallet } from "./utils"; -import { - amountToLp, - originChainId, - defaultMinDepositConfirmations, - modifyRelayHelper, - CHAIN_ID_TEST_LIST, - repaymentChainId, -} from "./constants"; -import { SpokePoolClient, HubPoolClient, MultiCallerClient, TokenClient, AcrossApiClient } from "../src/clients"; -import { MockInventoryClient, MockProfitClient } from "./mocks"; // Tested import { Relayer } from "../src/relayer/Relayer"; -import { getUnfilledDeposits, toBN, RelayerUnfilledDeposit, utf8ToHex } from "../src/utils"; import { RelayerConfig } from "../src/relayer/RelayerConfig"; -import { MockConfigStoreClient, MockedMultiCallerClient } from "./mocks"; +import { RelayerUnfilledDeposit, getUnfilledDeposits, toBN, utf8ToHex } from "../src/utils"; let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; let hubPool: Contract, l1Token: Contract, configStore: Contract; diff --git a/test/SpokePoolClient.DepositRoutes.ts b/test/SpokePoolClient.DepositRoutes.ts index d5f2ea485..835a8dad7 100644 --- a/test/SpokePoolClient.DepositRoutes.ts +++ b/test/SpokePoolClient.DepositRoutes.ts @@ -1,6 +1,17 @@ import hre from "hardhat"; -import { expect, ethers, Contract, SignerWithAddress, getContractFactory, createSpyLogger } from "./utils"; -import { randomAddress, enableRoutes, zeroAddress, originChainId, destinationChainId } from "./utils"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + destinationChainId, + enableRoutes, + ethers, + expect, + getContractFactory, + originChainId, + randomAddress, + zeroAddress, +} from "./utils"; import { SpokePoolClient } from "../src/clients"; // tested diff --git a/test/SpokePoolClient.SpeedUp.ts b/test/SpokePoolClient.SpeedUp.ts index ad270c12f..ee1b1e728 100644 --- a/test/SpokePoolClient.SpeedUp.ts +++ b/test/SpokePoolClient.SpeedUp.ts @@ -1,14 +1,18 @@ +import { depositRelayerFeePct, destinationChainId, modifyRelayHelper } from "./constants"; import { - expect, - ethers, Contract, SignerWithAddress, + createSpyLogger, + deepEqualsWithBigNumber, + deploySpokePoolWithToken, + enableRoutes, + ethers, + expect, + originChainId, setupTokensForWallet, + simpleDeposit, toBNWei, - deepEqualsWithBigNumber, } from "./utils"; -import { deploySpokePoolWithToken, enableRoutes, simpleDeposit, originChainId, createSpyLogger } from "./utils"; -import { depositRelayerFeePct, destinationChainId, modifyRelayHelper } from "./constants"; import { SpokePoolClient } from "../src/clients"; import { DepositWithBlock } from "../src/interfaces"; diff --git a/test/SpokePoolClient.deposits.ts b/test/SpokePoolClient.deposits.ts index aa1fb30a1..ae493e27b 100644 --- a/test/SpokePoolClient.deposits.ts +++ b/test/SpokePoolClient.deposits.ts @@ -1,6 +1,17 @@ -import { expect, ethers, Contract, SignerWithAddress, setupTokensForWallet, createSpyLogger } from "./utils"; -import { deploySpokePoolWithToken, enableRoutes, simpleDeposit, originChainId, destinationChainId } from "./utils"; import { SpokePoolClient } from "../src/clients"; +import { + Contract, + SignerWithAddress, + createSpyLogger, + deploySpokePoolWithToken, + destinationChainId, + enableRoutes, + ethers, + expect, + originChainId, + setupTokensForWallet, + simpleDeposit, +} from "./utils"; let spokePool: Contract, erc20: Contract, destErc20: Contract, weth: Contract; let depositor1: SignerWithAddress, depositor2: SignerWithAddress; diff --git a/test/SpokePoolClient.fills.ts b/test/SpokePoolClient.fills.ts index 64969f618..a97b48629 100644 --- a/test/SpokePoolClient.fills.ts +++ b/test/SpokePoolClient.fills.ts @@ -1,7 +1,18 @@ -import { setupTokensForWallet, expect, ethers, Contract, SignerWithAddress, buildFill, toBNWei } from "./utils"; -import { originChainId, deploySpokePoolWithToken, destinationChainId, createSpyLogger } from "./utils"; import { SpokePoolClient } from "../src/clients"; import { Deposit } from "../src/interfaces"; +import { + Contract, + SignerWithAddress, + buildFill, + createSpyLogger, + deploySpokePoolWithToken, + destinationChainId, + ethers, + expect, + originChainId, + setupTokensForWallet, + toBNWei, +} from "./utils"; let spokePool: Contract, erc20: Contract, destErc20: Contract, weth: Contract; let depositor: SignerWithAddress, relayer1: SignerWithAddress, relayer2: SignerWithAddress; diff --git a/test/TokenClient.Approval.ts b/test/TokenClient.Approval.ts index 37abc0da7..a4a70140f 100644 --- a/test/TokenClient.Approval.ts +++ b/test/TokenClient.Approval.ts @@ -1,8 +1,23 @@ -import { deploySpokePoolWithToken, expect, ethers, Contract, SignerWithAddress, MAX_UINT_VAL } from "./utils"; -import { createSpyLogger, winston, originChainId, destinationChainId, lastSpyLogIncludes } from "./utils"; -import { deployAndConfigureHubPool, zeroAddress, getContractFactory, utf8ToHex, toBNWei } from "./utils"; -import { TokenClient, SpokePoolClient, HubPoolClient } from "../src/clients"; import { interfaceName } from "@uma/common"; +import { HubPoolClient, SpokePoolClient, TokenClient } from "../src/clients"; +import { + Contract, + MAX_UINT_VAL, + SignerWithAddress, + createSpyLogger, + deployAndConfigureHubPool, + deploySpokePoolWithToken, + destinationChainId, + ethers, + expect, + getContractFactory, + lastSpyLogIncludes, + originChainId, + toBNWei, + utf8ToHex, + winston, + zeroAddress, +} from "./utils"; let spokePool_1: Contract, spokePool_2: Contract, hubPool: Contract; let erc20_1: Contract, weth_1: Contract, erc20_2: Contract, weth_2: Contract, l1Token_1: Contract; diff --git a/test/TokenClient.BalanceAlowance.ts b/test/TokenClient.BalanceAlowance.ts index 237b44556..3f419e73e 100644 --- a/test/TokenClient.BalanceAlowance.ts +++ b/test/TokenClient.BalanceAlowance.ts @@ -1,15 +1,20 @@ import { - deploySpokePoolWithToken, - expect, - ethers, Contract, SignerWithAddress, + createSpyLogger, deepEqualsWithBigNumber, + deployAndConfigureHubPool, + deploySpokePoolWithToken, + destinationChainId, + ethers, + expect, + originChainId, + toBNWei, + winston, + zeroAddress, } from "./utils"; -import { createSpyLogger, winston, originChainId, destinationChainId, toBNWei } from "./utils"; -import { deployAndConfigureHubPool, zeroAddress } from "./utils"; -import { TokenClient, SpokePoolClient, HubPoolClient } from "../src/clients"; // Tested +import { HubPoolClient, SpokePoolClient, TokenClient } from "../src/clients"; // Tested let spokePool_1: Contract, spokePool_2: Contract; let erc20_1: Contract, weth_1: Contract, erc20_2: Contract, weth_2: Contract; diff --git a/test/TokenClient.TokenShortfall.ts b/test/TokenClient.TokenShortfall.ts index e411d0cde..aa2a1c5fc 100644 --- a/test/TokenClient.TokenShortfall.ts +++ b/test/TokenClient.TokenShortfall.ts @@ -1,14 +1,19 @@ +import { HubPoolClient, SpokePoolClient, TokenClient } from "../src/clients"; import { - deploySpokePoolWithToken, - expect, - ethers, Contract, SignerWithAddress, + createSpyLogger, deepEqualsWithBigNumber, + deployAndConfigureHubPool, + deploySpokePoolWithToken, + destinationChainId, + ethers, + expect, + originChainId, + toBNWei, + winston, + zeroAddress, } from "./utils"; -import { createSpyLogger, winston, originChainId, destinationChainId, toBNWei } from "./utils"; -import { TokenClient, SpokePoolClient, HubPoolClient } from "../src/clients"; -import { deployAndConfigureHubPool, zeroAddress } from "./utils"; let spokePool_1: Contract, spokePool_2: Contract; let erc20_2: Contract; diff --git a/test/fixtures/Dataworker.Fixture.ts b/test/fixtures/Dataworker.Fixture.ts index 85b09bb58..44191f227 100644 --- a/test/fixtures/Dataworker.Fixture.ts +++ b/test/fixtures/Dataworker.Fixture.ts @@ -6,10 +6,14 @@ import { BigNumber, enableRoutes, sampleRateModel, - sinon, + createSpyLogger, + winston, + deployAndConfigureHubPool, + deployConfigStore, + SignerWithAddress, + setupTokensForWallet, + getLastBlockTime, } from "../utils"; -import { SignerWithAddress, setupTokensForWallet, getLastBlockTime } from "../utils"; -import { createSpyLogger, winston, deployAndConfigureHubPool, deployConfigStore } from "../utils"; import * as clients from "../../src/clients"; import { amountToLp, diff --git a/test/utils/utils.ts b/test/utils/utils.ts index 2dc6c7bbe..2304c13dc 100644 --- a/test/utils/utils.ts +++ b/test/utils/utils.ts @@ -1,36 +1,39 @@ -import { constants as ethersConstants } from "ethers"; import * as utils from "@across-protocol/contracts-v2/dist/test-utils"; import { TokenRolesEnum } from "@uma/common"; -export { MAX_SAFE_ALLOWANCE, MAX_UINT_VAL } from "@uma/common"; import { SpyTransport, bigNumberFormatter } from "@uma/financial-templates-lib"; +import { constants as ethersConstants, providers } from "ethers"; +import { ConfigStoreClient, GLOBAL_CONFIG_STORE_KEYS, HubPoolClient, SpokePoolClient } from "../../src/clients"; +import { Deposit, Fill, FillWithBlock, RunningBalances } from "../../src/interfaces"; +import { TransactionResponse, buildRelayerRefundTree, toBN, toBNWei, utf8ToHex } from "../../src/utils"; import { - sampleRateModel, - DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, DEFAULT_BLOCK_RANGE_FOR_CHAIN, + DEFAULT_POOL_BALANCE_TOKEN_TRANSFER_THRESHOLD, + MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, + MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, + amountToDeposit, + depositRelayerFeePct, + l1TokenTransferThreshold, + sampleRateModel, + zeroAddress, } from "../constants"; -import { amountToDeposit, depositRelayerFeePct, l1TokenTransferThreshold, zeroAddress } from "../constants"; -import { MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, MAX_REFUNDS_PER_RELAYER_REFUND_LEAF } from "../constants"; -import { HubPoolClient, ConfigStoreClient, GLOBAL_CONFIG_STORE_KEYS } from "../../src/clients"; -import { SpokePoolClient } from "../../src/clients"; -import { deposit, Contract, SignerWithAddress, BigNumber } from "./index"; -import { Deposit, Fill, FillWithBlock, RunningBalances } from "../../src/interfaces"; -import { buildRelayerRefundTree, toBN, toBNWei, TransactionResponse, utf8ToHex } from "../../src/utils"; -import { providers } from "ethers"; +import { BigNumber, Contract, SignerWithAddress, deposit } from "./index"; +export { MAX_SAFE_ALLOWANCE, MAX_UINT_VAL } from "@uma/common"; +export { sinon, winston }; -import winston from "winston"; -import sinon from "sinon"; +import { AcrossConfigStore } from "@across-protocol/contracts-v2"; +import { constants } from "@across-protocol/sdk-v2"; import chai from "chai"; import chaiExclude from "chai-exclude"; import _ from "lodash"; -import { AcrossConfigStore } from "@across-protocol/contracts-v2"; -import { constants } from "@across-protocol/sdk-v2"; +import sinon from "sinon"; +import winston from "winston"; import { SpokePoolDeploymentResult, SpyLoggerResult } from "../types"; + chai.use(chaiExclude); -export { winston, sinon }; const assert = chai.assert; -export { chai, assert }; +export { assert, chai }; export function deepEqualsWithBigNumber( x: Iterable | Record, diff --git a/yarn.lock b/yarn.lock index 818765edf..6e9554c27 100644 --- a/yarn.lock +++ b/yarn.lock @@ -37,10 +37,10 @@ "@openzeppelin/contracts" "4.1.0" "@uma/core" "^2.18.0" -"@across-protocol/sdk-v2@0.15.18": - version "0.15.18" - resolved "https://registry.yarnpkg.com/@across-protocol/sdk-v2/-/sdk-v2-0.15.18.tgz#5334e36fda7cf1cab753549fd309ff2595155950" - integrity sha512-Wcf6A/zy8SG+UXcGDsDI2k5jVMbvlHLqG/iJ3H9YgQ5A5KeRdw5H8mLTdXavTN86aIZCD1Ls5RskCVT6SujoIA== +"@across-protocol/sdk-v2@0.15.20": + version "0.15.20" + resolved "https://registry.yarnpkg.com/@across-protocol/sdk-v2/-/sdk-v2-0.15.20.tgz#35e3faf01069bb6e82522efecef8c97ad8863462" + integrity sha512-LjnL9lwEoCA80XpOh6JwBPYys1aI7HP7XhDe3vkzBU7u86P7MY2oMDc4p2AErr7w+iR0mkUD727eYCSl10zfRg== dependencies: "@across-protocol/across-token" "^1.0.0" "@across-protocol/contracts-v2" "^2.4.3" @@ -443,7 +443,7 @@ "@ethersproject/abstract-provider" "^5.7.0" "@ethersproject/abstract-signer" "^5.7.0" -"@eth-optimism/core-utils@0.12.0", "@eth-optimism/core-utils@^0.12.0": +"@eth-optimism/core-utils@0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz#6337e4599a34de23f8eceb20378de2a2de82b0ea" integrity sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw== @@ -465,7 +465,7 @@ bufio "^1.0.7" chai "^4.3.4" -"@eth-optimism/core-utils@0.12.2": +"@eth-optimism/core-utils@0.12.2", "@eth-optimism/core-utils@^0.12.0": version "0.12.2" resolved "https://registry.yarnpkg.com/@eth-optimism/core-utils/-/core-utils-0.12.2.tgz#cacf8c488e8c9bf75b193a08763043294a4882fa" integrity sha512-rJjsRF//hegpfeWzcWRVO+SJ7XK+uwpidUGECQ5/aGfO+o0/J0kaiRhvGtUvJHsY5D2+gThqQkkx+ZwlGuBeuQ== @@ -3191,21 +3191,16 @@ web3 "^1.6.0" winston "^3.2.1" -"@uma/contracts-frontend@^0.4.16": - version "0.4.16" - resolved "https://registry.yarnpkg.com/@uma/contracts-frontend/-/contracts-frontend-0.4.16.tgz#47f90874800a64e046143eefee9614fcafa8ca5b" - integrity sha512-2/0A7wTh2zEw8GjYZmydRmTtQDfUtRHrttU2E5w8dACDIMA5EYrAm+G/r67SYcrt7+cWUmsBmR9AZ0QR01zN2A== +"@uma/contracts-frontend@^0.4.17": + version "0.4.17" + resolved "https://registry.yarnpkg.com/@uma/contracts-frontend/-/contracts-frontend-0.4.17.tgz#27f5292e8ec5e02f5ac467f384601a56c27ff4c6" + integrity sha512-g6+1PnHGvos4zcAPaBHAHQcK6tSNvEaiy/36Q8vzp4pX0IV8lrwfBKJtXjqLgjyK2okSSQgZKuT+quVPO9h4Cg== -"@uma/contracts-node@^0.4.0", "@uma/contracts-node@^0.4.17": +"@uma/contracts-node@^0.4.0", "@uma/contracts-node@^0.4.16", "@uma/contracts-node@^0.4.17": version "0.4.17" resolved "https://registry.yarnpkg.com/@uma/contracts-node/-/contracts-node-0.4.17.tgz#6abd815723c8344017eb5c302f6a5b0b690eeb4e" integrity sha512-e7cVJr3yhKrPZn1TAo/CCOt+QacJON6Mj71lcwHq/rnx+tgjujK2MsOhihytmb79ejPTKg1b5+2GIDL02ttrrQ== -"@uma/contracts-node@^0.4.16": - version "0.4.16" - resolved "https://registry.yarnpkg.com/@uma/contracts-node/-/contracts-node-0.4.16.tgz#1b4d50fae0a6a0233fb9ff7bcaacc003a80feeb2" - integrity sha512-7x0X68m/th0ieoGkEKniKEu08ee1r/SVF0vF97QRgiD0VvdKrQ9Z8ED0HDXreh/g8Rd7LBPgJzgHrrHOpkLDyQ== - "@uma/core@^2.18.0": version "2.43.2" resolved "https://registry.yarnpkg.com/@uma/core/-/core-2.43.2.tgz#b4dc17594f6ff8b57720f6451043e8ee91841942" @@ -3281,18 +3276,18 @@ mocha "^8.3.0" node-fetch "^2.6.1" -"@uma/sdk@^0.34.0", "@uma/sdk@^0.34.1": - version "0.34.1" - resolved "https://registry.yarnpkg.com/@uma/sdk/-/sdk-0.34.1.tgz#cbd38640c3c3a976eb369c26abd86d7263271fba" - integrity sha512-ZyUqdAYD/+mkw18b7VVmlsNbfOgPxOnf0vVVbHEDQjV1GCRDKeMxojJAVPOPLQT9X3+ycATZLHu5tYxeXRxrzg== +"@uma/sdk@^0.34.1", "@uma/sdk@^0.34.2": + version "0.34.2" + resolved "https://registry.yarnpkg.com/@uma/sdk/-/sdk-0.34.2.tgz#b433b437f750c4afaf2f110209c80c513437eb94" + integrity sha512-49akhv4eOLjoWvxawciNI9OztfDp2IyuJEuU8ME3BWAaQM+RYurPylKyxCPSzrmlCbx1KSQU97FXDOeH7hP4gg== dependencies: "@eth-optimism/core-utils" "^0.7.7" "@ethersproject/abstract-signer" "^5.4.0" "@ethersproject/providers" "^5.4.2" "@google-cloud/datastore" "^7.0.0" "@types/lodash-es" "^4.17.5" - "@uma/contracts-frontend" "^0.4.16" - "@uma/contracts-node" "^0.4.16" + "@uma/contracts-frontend" "^0.4.17" + "@uma/contracts-node" "^0.4.17" axios "^0.24.0" bluebird "^3.7.2" bn.js "^4.11.9"