diff --git a/package.json b/package.json index 6d4d5227d7..fd22701367 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dependencies": { "@across-protocol/constants": "^3.1.72", "@across-protocol/contracts": "^4.1.5", - "@across-protocol/sdk": "4.3.58", + "@across-protocol/sdk": "4.3.59", "@arbitrum/sdk": "^4.0.2", "@consensys/linea-sdk": "^0.3.0", "@coral-xyz/anchor": "^0.31.1", @@ -79,7 +79,8 @@ "deposit": "yarn ts-node ./scripts/spokepool.ts deposit", "dispute": "yarn ts-node ./scripts/hubpool.ts dispute", "update": "git pull && yarn reinstall && yarn version --non-interactive && git show --quiet", - "update-addresses": "yarn ts-node ./scripts/fetch-addresses.ts" + "update-addresses": "yarn ts-node ./scripts/fetch-addresses.ts", + "validate-root-bundle": "yarn ts-node src/scripts/validateRootBundle.ts" }, "devDependencies": { "@nomiclabs/hardhat-ethers": "^2.2.3", diff --git a/src/dataworker/PoolRebalanceUtils.ts b/src/dataworker/PoolRebalanceUtils.ts index d2f1a6ea10..4663a6367b 100644 --- a/src/dataworker/PoolRebalanceUtils.ts +++ b/src/dataworker/PoolRebalanceUtils.ts @@ -12,7 +12,6 @@ import { winston, assert, getNetworkName, - isChainDisabled, EvmAddress, Address, isDefined, @@ -68,9 +67,9 @@ export function generateMarkdownForRootBundle( let bundleBlockRangePretty = ""; bundleBlockRange.forEach((_blockRange, index) => { const chainId = chainIdListForBundleEvaluationBlockNumbers[index]; - bundleBlockRangePretty += `\n\t\t${chainId}: ${JSON.stringify(bundleBlockRange[index])}${ - isChainDisabled(bundleBlockRange[index]) ? " 🥶" : "" - }`; + const [startBlock, endBlock] = bundleBlockRange[index]; + const paused = startBlock === endBlock ? " 🥶" : ""; + bundleBlockRangePretty += `\n\t\t${chainId}: ${JSON.stringify(bundleBlockRange[index])}${paused}`; }); const convertTokenListFromWei = (chainId: number, tokenAddresses: Address[], weiVals: string[]) => { diff --git a/src/utils/SDKUtils.ts b/src/utils/SDKUtils.ts index b738b88a40..fdc4781d48 100644 --- a/src/utils/SDKUtils.ts +++ b/src/utils/SDKUtils.ts @@ -104,7 +104,7 @@ export const { export const { getRefundsFromBundle, - isChainDisabled, + isChainDisabledAtBlock, getWidestPossibleExpectedBlockRange, getEndBlockBuffers, buildPoolRebalanceLeafTree, diff --git a/test/Dataworker.executeRelayerRefunds.ts b/test/Dataworker.executeRelayerRefunds.ts index 19de248656..9255d1e1c3 100644 --- a/test/Dataworker.executeRelayerRefunds.ts +++ b/test/Dataworker.executeRelayerRefunds.ts @@ -1,19 +1,10 @@ -import { BundleDataClient, HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; -import { - EvmAddress, - buildRelayerRefundTree, - MAX_UINT_VAL, - RelayerRefundLeaf, - toBN, - toBNWei, - toAddressType, -} from "../src/utils"; +import { HubPoolClient, MultiCallerClient, SpokePoolClient } from "../src/clients"; +import { EvmAddress, buildRelayerRefundTree, MAX_UINT_VAL, RelayerRefundLeaf, toBNWei } from "../src/utils"; import { MAX_L1_TOKENS_PER_POOL_REBALANCE_LEAF, MAX_REFUNDS_PER_RELAYER_REFUND_LEAF, amountToDeposit, destinationChainId, - repaymentChainId, } from "./constants"; import { setupDataworker } from "./fixtures/Dataworker.Fixture"; import { Contract, SignerWithAddress, depositV3, ethers, expect, fillV3Relay } from "./utils"; @@ -148,11 +139,9 @@ describe("Dataworker: Execute relayer refunds", async function () { }); describe("Computing refunds for bundles", function () { let relayer: SignerWithAddress; - let bundleDataClient: BundleDataClient; beforeEach(async function () { relayer = depositor; - bundleDataClient = dataworkerInstance.clients.bundleDataClient; await updateAllClients(); const deposit1 = await depositV3( @@ -172,169 +161,5 @@ describe("Dataworker: Execute relayer refunds", async function () { await updateAllClients(); }); - it("No validated bundle refunds", async function () { - // Propose a bundle: - await dataworkerInstance.proposeRootBundle(spokePoolClients); - await multiCallerClient.executeTxnQueues(); - await updateAllClients(); - - // No bundle is validated so no refunds. - const refunds = await bundleDataClient.getPendingRefundsFromValidBundles(); - expect( - bundleDataClient.getTotalRefund( - refunds, - EvmAddress.from(relayer.address), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ) - ).to.equal(toBN(0)); - }); - it("Get refunds from validated bundles", async function () { - await updateAllClients(); - // Propose a bundle: - await dataworkerInstance.proposeRootBundle(spokePoolClients); - await multiCallerClient.executeTxnQueues(); - - // Advance time and execute leaves: - await hubPool.setCurrentTime(Number(await hubPool.getCurrentTime()) + Number(await hubPool.liveness()) + 1); - await updateAllClients(); - await dataworkerInstance.executePoolRebalanceLeaves(spokePoolClients, await getNewBalanceAllocator()); - await multiCallerClient.executeTxnQueues(); - - // Before relayer refund leaves are not executed, should have pending refunds: - await updateAllClients(); - const validatedRootBundles = hubPoolClient.getValidatedRootBundles(); - expect(validatedRootBundles.length).to.equal(1); - const refunds = await bundleDataClient.getPendingRefundsFromValidBundles(); - const totalRefund1 = bundleDataClient.getTotalRefund( - refunds, - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ); - expect(totalRefund1).to.gt(0); - - // Test edge cases of `getTotalRefund` that should return BN(0) - expect( - bundleDataClient.getTotalRefund( - refunds, - toAddressType(relayer.address, repaymentChainId), - repaymentChainId, - toAddressType(erc20_2.address, repaymentChainId) - ) - ).to.equal(toBN(0)); - expect( - bundleDataClient.getTotalRefund( - refunds, - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_1.address, destinationChainId) - ) - ).to.equal(toBN(0)); - - // Manually relay the roots to spoke pools since adapter is a dummy and won't actually relay messages. - const rootBundle = validatedRootBundles[0]; - await spokePool_1.relayRootBundle(rootBundle.relayerRefundRoot, rootBundle.slowRelayRoot); - await spokePool_2.relayRootBundle(rootBundle.relayerRefundRoot, rootBundle.slowRelayRoot); - await updateAllClients(); - - // Execute relayer refund leaves. Send funds to spoke pools to execute the leaves. - await erc20_2.mint(spokePool_2.address, amountToDeposit); - await dataworkerInstance.executeRelayerRefundLeaves(spokePoolClients, await getNewBalanceAllocator()); - await multiCallerClient.executeTxnQueues(); - - // Should now have zero pending refunds - await updateAllClients(); - // If we call `getPendingRefundsFromLatestBundle` multiple times, there should be no error. If there is an error, - // then it means that `getPendingRefundsFromLatestBundle` is mutating the return value of `.loadData` which is - // stored in the bundle data client's cache. `getPendingRefundsFromLatestBundle` should instead be using a - // deep cloned copy of `.loadData`'s output. - await bundleDataClient.getPendingRefundsFromValidBundles(); - const postExecutionRefunds = await bundleDataClient.getPendingRefundsFromValidBundles(); - expect( - bundleDataClient.getTotalRefund( - postExecutionRefunds, - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ) - ).to.equal(toBN(0)); - - // Submit fill2 and propose another bundle: - const newDepositAmount = amountToDeposit.mul(2); - const deposit2 = await depositV3( - spokePool_1, - destinationChainId, - depositor, - erc20_1.address, - newDepositAmount, - erc20_2.address, - amountToDeposit - ); - await updateAllClients(); - - // Submit a valid fill. - await fillV3Relay(spokePool_2, deposit2, relayer, destinationChainId); - await updateAllClients(); - - // Validate another bundle: - await dataworkerInstance.proposeRootBundle(spokePoolClients); - await multiCallerClient.executeTxnQueues(); - await hubPool.setCurrentTime(Number(await hubPool.getCurrentTime()) + Number(await hubPool.liveness()) + 1); - await updateAllClients(); - await dataworkerInstance.executePoolRebalanceLeaves(spokePoolClients, await getNewBalanceAllocator()); - await multiCallerClient.executeTxnQueues(); - await updateAllClients(); - - expect(hubPoolClient.getValidatedRootBundles().length).to.equal(2); - - // Should include refunds for most recently validated bundle but not count first one - // since they were already refunded. - const refunds2 = await bundleDataClient.getPendingRefundsFromValidBundles(); - expect( - bundleDataClient.getTotalRefund( - refunds2, - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ) - ).to.gt(0); - }); - it("Refunds in next bundle", async function () { - // Before proposal should show refunds: - expect( - bundleDataClient.getRefundsFor( - (await bundleDataClient.getNextBundleRefunds())[0], - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ) - ).to.gt(0); - - // Propose a bundle: - await dataworkerInstance.proposeRootBundle(spokePoolClients); - await multiCallerClient.executeTxnQueues(); - await updateAllClients(); - - // After proposal but before execution should show upcoming refund: - expect( - bundleDataClient.getRefundsFor( - (await bundleDataClient.getNextBundleRefunds())[0], - toAddressType(relayer.address, destinationChainId), - destinationChainId, - toAddressType(erc20_2.address, destinationChainId) - ) - ).to.gt(0); - - // Advance time and execute root bundle: - await hubPool.setCurrentTime(Number(await hubPool.getCurrentTime()) + Number(await hubPool.liveness()) + 1); - await updateAllClients(); - await dataworkerInstance.executePoolRebalanceLeaves(spokePoolClients, await getNewBalanceAllocator()); - await multiCallerClient.executeTxnQueues(); - - // Should reset to no refunds in "next bundle", though these will show up in pending bundle. - await updateAllClients(); - expect(await bundleDataClient.getNextBundleRefunds()).to.deep.equal([{}]); - }); }); }); diff --git a/test/Dataworker.loadData.deposit.ts b/test/Dataworker.loadData.deposit.ts index e791f6e918..53df977dde 100644 --- a/test/Dataworker.loadData.deposit.ts +++ b/test/Dataworker.loadData.deposit.ts @@ -1,12 +1,11 @@ import { BundleDataClient, ConfigStoreClient, HubPoolClient, SpokePoolClient } from "../src/clients"; -import { amountToDeposit, destinationChainId, originChainId, repaymentChainId } from "./constants"; +import { destinationChainId, originChainId, repaymentChainId } from "./constants"; import { DataworkerConfig, setupDataworker } from "./fixtures/Dataworker.Fixture"; import { Contract, FakeContract, SignerWithAddress, V3FillFromDeposit, - depositV3, ethers, expect, getDefaultBlockRange, @@ -21,11 +20,11 @@ import { getCurrentTime, toBNWei, ZERO_ADDRESS, BigNumber, bnZero, toAddressType import { MockHubPoolClient, MockSpokePoolClient } from "./mocks"; import { interfaces, utils as sdkUtils } from "@across-protocol/sdk"; -let spokePool_1: Contract, erc20_1: Contract, spokePool_2: Contract, erc20_2: Contract; +let erc20_1: Contract, erc20_2: Contract; let l1Token_1: Contract; -let depositor: SignerWithAddress, relayer: SignerWithAddress; +let relayer: SignerWithAddress; -let spokePoolClient_1: SpokePoolClient, spokePoolClient_2: SpokePoolClient, bundleDataClient: BundleDataClient; +let spokePoolClient_1: SpokePoolClient, spokePoolClient_2: SpokePoolClient; let hubPoolClient: HubPoolClient, configStoreClient: ConfigStoreClient; let dataworkerInstance: Dataworker; let spokePoolClients: { [chainId: number]: SpokePoolClient }; @@ -38,14 +37,11 @@ let updateAllClients: () => Promise; describe("Dataworker: Load bundle data", async function () { beforeEach(async function () { ({ - spokePool_1, erc20_1, - spokePool_2, erc20_2, configStoreClient, hubPoolClient, l1Token_1, - depositor, relayer, dataworkerInstance, spokePoolClient_1, @@ -54,7 +50,6 @@ describe("Dataworker: Load bundle data", async function () { updateAllClients, spy, } = await setupDataworker(ethers, 25, 25, 0)); - bundleDataClient = dataworkerInstance.clients.bundleDataClient; }); describe("Computing bundle deposits and expired deposits to refund", function () { @@ -558,71 +553,4 @@ describe("Dataworker: Load bundle data", async function () { expect(data1.bundleFillsV3[repaymentChainId][toBytes32(l1Token_1.address)].fills.length).to.equal(1); }); }); - - describe("Miscellaneous functions", function () { - it("getUpcomingDepositAmount", async function () { - // Send two deposits on different chains - await depositV3( - spokePool_1, - destinationChainId, - depositor, - erc20_1.address, - amountToDeposit, - ZERO_ADDRESS, - amountToDeposit - ); - await depositV3( - spokePool_2, - originChainId, - depositor, - erc20_2.address, - amountToDeposit, - ZERO_ADDRESS, - amountToDeposit - ); - await updateAllClients(); - expect( - await bundleDataClient.getUpcomingDepositAmount(originChainId, toAddressType(erc20_1.address, originChainId), 0) - ).to.equal(amountToDeposit); - expect( - await bundleDataClient.getUpcomingDepositAmount( - destinationChainId, - toAddressType(erc20_2.address, destinationChainId), - 0 - ) - ).to.equal(amountToDeposit); - - // Removes deposits using block, token, and chain filters. - expect( - await bundleDataClient.getUpcomingDepositAmount( - originChainId, - toAddressType(erc20_1.address, originChainId), - spokePoolClient_1.latestHeightSearched // block higher than the deposit - ) - ).to.equal(0); - expect( - await bundleDataClient.getUpcomingDepositAmount( - originChainId, - toAddressType(erc20_2.address, originChainId), // diff token - 0 - ) - ).to.equal(0); - expect( - await bundleDataClient.getUpcomingDepositAmount( - destinationChainId, // diff chain - toAddressType(erc20_1.address, destinationChainId), - 0 - ) - ).to.equal(0); - - // spoke pool client for chain not defined - expect( - await bundleDataClient.getUpcomingDepositAmount( - originChainId + destinationChainId + repaymentChainId + 1, // spoke pool client for chain is not defined in BundleDataClient - toAddressType(erc20_1.address, originChainId), - 0 - ) - ).to.equal(0); - }); - }); }); diff --git a/test/Dataworker.loadData.fill.ts b/test/Dataworker.loadData.fill.ts index 7f5d24c3df..758c4f5811 100644 --- a/test/Dataworker.loadData.fill.ts +++ b/test/Dataworker.loadData.fill.ts @@ -47,7 +47,6 @@ import { } from "./mocks"; import { interfaces, constants as sdkConstants, utils as sdkUtils, providers } from "@across-protocol/sdk"; import { cloneDeep } from "lodash"; -import { CombinedRefunds } from "../src/dataworker/DataworkerUtils"; import { INFINITE_FILL_DEADLINE } from "../src/common"; describe("Dataworker: Load bundle data", async function () { @@ -1181,90 +1180,4 @@ describe("Dataworker: Load bundle data", async function () { }); }); }); - - describe("Miscellaneous functions", function () { - it("getApproximateRefundsForBlockRange", async function () { - // Send two deposits on different chains - // Fill both deposits and request repayment on same chain - await depositV3( - spokePool_1, - destinationChainId, - depositor, - erc20_1.address, - amountToDeposit, - ZERO_ADDRESS, - amountToDeposit - ); - await depositV3( - spokePool_2, - originChainId, - depositor, - erc20_2.address, - amountToDeposit, - ZERO_ADDRESS, - amountToDeposit - ); - await updateAllClients(); - const deposit1 = spokePoolClient_1.getDeposits()[0]; - const deposit2 = spokePoolClient_2.getDeposits()[0]; - - await fillV3Relay(spokePool_2, deposit1, relayer, repaymentChainId); - await fillV3Relay(spokePool_1, deposit2, relayer, repaymentChainId); - - // Approximate refunds should count both fills - await updateAllClients(); - const refunds = await bundleDataClient.getApproximateRefundsForBlockRange( - [originChainId, destinationChainId], - getDefaultBlockRange(5) - ); - const expectedRefunds = { - [repaymentChainId]: { - [toBytes32(l1Token_1.address)]: { - [toBytes32(relayer.address)]: BigNumber.from(amountToDeposit.mul(2)).toString(), - }, - }, - }; - - // Convert refunds to have a nested string instead of BigNumber. It's three levels deep - // which is a bit ugly but it's the easiest way to compare the two objects that are having - // these BN issues. - const convertToNumericStrings = (data: CombinedRefunds) => - Object.entries(data).reduce( - (acc, [chainId, refunds]) => ({ - ...acc, - [chainId]: Object.entries(refunds).reduce( - (acc, [token, refunds]) => ({ - ...acc, - [toBytes32(token)]: Object.entries(refunds).reduce( - (acc, [address, amount]) => ({ ...acc, [address]: amount.toString() }), - {} - ), - }), - {} - ), - }), - {} - ); - - expect(convertToNumericStrings(refunds)).to.deep.equal(expectedRefunds); - - // Send an invalid fill and check it is not included. - await fillV3Relay(spokePool_2, { ...deposit1, depositId: deposit1.depositId.add(1) }, relayer, repaymentChainId); - await updateAllClients(); - expect( - convertToNumericStrings( - await bundleDataClient.getApproximateRefundsForBlockRange( - [originChainId, destinationChainId], - getDefaultBlockRange(5) - ) - ) - ).to.deep.equal({ - [repaymentChainId]: { - [toBytes32(l1Token_1.address)]: { - [toBytes32(relayer.address)]: amountToDeposit.mul(2).toString(), - }, - }, - }); - }); - }); }); diff --git a/test/InventoryClient.RefundChain.ts b/test/InventoryClient.RefundChain.ts index c0d4380b14..e4e6369fac 100644 --- a/test/InventoryClient.RefundChain.ts +++ b/test/InventoryClient.RefundChain.ts @@ -862,10 +862,11 @@ describe("InventoryClient: Refund chain selection", async function () { }); it("includes hub chain and origin chain on repayment chain list", async function () { const possibleRepaymentChains = inventoryClient.getPossibleRepaymentChainIds(sampleDepositData); - [sampleDepositData.originChainId, hubPoolClient.chainId].forEach((chainId) => { + const slowWithdrawalChain = OPTIMISM; + [sampleDepositData.originChainId, hubPoolClient.chainId, slowWithdrawalChain].forEach((chainId) => { expect(possibleRepaymentChains).to.include(chainId); }); - expect(possibleRepaymentChains.length).to.equal(2); + expect(possibleRepaymentChains.length).to.equal(3); }); }); diff --git a/test/mocks/MockBundleDataClient.ts b/test/mocks/MockBundleDataClient.ts index b854c2f654..51e512a166 100644 --- a/test/mocks/MockBundleDataClient.ts +++ b/test/mocks/MockBundleDataClient.ts @@ -8,14 +8,6 @@ export class MockBundleDataClient extends BundleDataClient { private nextBundleRefunds: CombinedRefunds = {}; private matchingFillEvents: Record = {}; - async getPendingRefundsFromValidBundles(): Promise { - return [this.pendingBundleRefunds]; - } - - async getNextBundleRefunds(): Promise { - return [this.nextBundleRefunds]; - } - setReturnedPendingBundleRefunds(refunds: CombinedRefunds): void { this.pendingBundleRefunds = refunds; } diff --git a/yarn.lock b/yarn.lock index 01283a0c5e..1ce59d7108 100644 --- a/yarn.lock +++ b/yarn.lock @@ -62,10 +62,10 @@ yargs "^17.7.2" zksync-web3 "^0.14.3" -"@across-protocol/sdk@4.3.58": - version "4.3.58" - resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-4.3.58.tgz#de49dbcae25a5d167e4cc73bdba3accd9ba25004" - integrity sha512-8CeB7hSw0EK+6zagNTmyeIpE1a+U4YMRzZr+nCQINxN994fhgQT/xoUNAagl2Wq+AqKXl2XlL4/10EbxQgbTxQ== +"@across-protocol/sdk@4.3.59": + version "4.3.59" + resolved "https://registry.yarnpkg.com/@across-protocol/sdk/-/sdk-4.3.59.tgz#a871f4d22d00488d83915fcc5d5c9724be4c20fd" + integrity sha512-9OBmQEvfRistZ32rx2i3ePFYEOk0to+yyYisPrdx3PRRBVjd9Ly9WmL5pvbypx9M+SMy55AHA4CqTlGeBGsQQQ== dependencies: "@across-protocol/across-token" "^1.0.0" "@across-protocol/constants" "^3.1.72"