From e07a9e335fdeeeb68818ec7d8884d3d1d36c8fcb Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 18 Apr 2024 15:33:58 +0200 Subject: [PATCH 01/12] Adding MezoAllocator tests to run against mainnet fork This configuration is aimed to run MezoAllocator tests against mainnet fork and check the flow with the real Mezo Portal contract deployed on mainnet. This also sets up a ground for other tests that can also be moved and check against the real contracts on mainnet. The network is called "integration". A local hardhat node should be run to execute these tests. --- solidity/.gitignore | 1 + solidity/deploy/00_resolve_mezo_portal.ts | 10 +- solidity/deploy/00_resolve_tbtc_token.ts | 5 +- solidity/deploy/00_resolve_tbtc_vault.ts | 20 +- solidity/deploy/01_deploy_stbtc.ts | 5 +- solidity/deploy/02_deploy_mezo_allocator.ts | 8 +- .../deploy/03_deploy_bitcoin_depositor.ts | 5 +- solidity/deploy/04_deploy_bitcoin_redeemer.ts | 5 +- solidity/hardhat.config.ts | 13 + solidity/package.json | 5 +- solidity/test/helpers/context.ts | 10 +- solidity/test/helpers/contract.ts | 10 +- .../test/integration/MezoAllocator.test.ts | 346 ++++++++++++++++++ 13 files changed, 418 insertions(+), 25 deletions(-) create mode 100644 solidity/test/integration/MezoAllocator.test.ts diff --git a/solidity/.gitignore b/solidity/.gitignore index 1f9e31a2d..5d20b1efc 100644 --- a/solidity/.gitignore +++ b/solidity/.gitignore @@ -5,3 +5,4 @@ export.json export/ gen/ typechain/ +deployments/ diff --git a/solidity/deploy/00_resolve_mezo_portal.ts b/solidity/deploy/00_resolve_mezo_portal.ts index 412c468d6..9e1c3fb4e 100644 --- a/solidity/deploy/00_resolve_mezo_portal.ts +++ b/solidity/deploy/00_resolve_mezo_portal.ts @@ -11,14 +11,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { log } = deployments const { deployer } = await getNamedAccounts() - const mezoPortal = await deployments.getOrNull("MezoPortal") + let mezoPortal = await deployments.getOrNull("MezoPortal") + if (hre.network.name === "integration") { + mezoPortal = await deployments.getArtifact("MezoPortal") + } if (mezoPortal && isNonZeroAddress(mezoPortal.address)) { log(`using MezoPortal contract at ${mezoPortal.address}`) - } else if ( - (hre.network.config as HardhatNetworkConfig)?.forking?.enabled && - hre.network.name !== "hardhat" - ) { + } else if ((hre.network.config as HardhatNetworkConfig)?.forking?.enabled) { throw new Error("deployed MezoPortal contract not found") } else { log("deploying Mezo Portal contract stub") diff --git a/solidity/deploy/00_resolve_tbtc_token.ts b/solidity/deploy/00_resolve_tbtc_token.ts index d1ddf731e..473d77f5d 100644 --- a/solidity/deploy/00_resolve_tbtc_token.ts +++ b/solidity/deploy/00_resolve_tbtc_token.ts @@ -11,7 +11,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { log } = deployments const { deployer } = await getNamedAccounts() - const tbtc = await deployments.getOrNull("TBTC") + let tbtc = await deployments.getOrNull("TBTC") + if (hre.network.name === "integration") { + tbtc = await deployments.getArtifact("TBTC") + } if (tbtc && isNonZeroAddress(tbtc.address)) { log(`using TBTC contract at ${tbtc.address}`) diff --git a/solidity/deploy/00_resolve_tbtc_vault.ts b/solidity/deploy/00_resolve_tbtc_vault.ts index 27034347f..a946044c6 100644 --- a/solidity/deploy/00_resolve_tbtc_vault.ts +++ b/solidity/deploy/00_resolve_tbtc_vault.ts @@ -23,7 +23,11 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { } else { log("deploying TBTCVault contract stub") - const tbtc = await deployments.get("TBTC") + let tbtc = await deployments.getOrNull("TBTC") + if (hre.network.name === "integration") { + tbtc = await deployments.getArtifact("TBTC") + } + const bridge = await deployments.get("Bridge") const deployment = await deployments.deploy("TBTCVault", { @@ -34,12 +38,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { waitConfirmations: waitConfirmationsNumber(hre), }) - await deployments.execute( - "TBTC", - { from: deployer, log: true }, - "setOwner", - deployment.address, - ) + if (hre.network.name === "hardhat") { + await deployments.execute( + "TBTC", + { from: deployer, log: true }, + "setOwner", + deployment.address, + ) + } } } diff --git a/solidity/deploy/01_deploy_stbtc.ts b/solidity/deploy/01_deploy_stbtc.ts index 166e2fc4c..be9afd238 100644 --- a/solidity/deploy/01_deploy_stbtc.ts +++ b/solidity/deploy/01_deploy_stbtc.ts @@ -7,7 +7,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { treasury, governance } = await getNamedAccounts() const { deployer: deployerSigner } = await helpers.signers.getNamedSigners() - const tbtc = await deployments.get("TBTC") + let tbtc = await deployments.getOrNull("TBTC") + if (hre.network.name === "integration") { + tbtc = await deployments.getArtifact("TBTC") + } const [, stbtcDeployment] = await helpers.upgrades.deployProxy("stBTC", { contractName: "stBTC", diff --git a/solidity/deploy/02_deploy_mezo_allocator.ts b/solidity/deploy/02_deploy_mezo_allocator.ts index 694fad100..b3f6d1ef0 100644 --- a/solidity/deploy/02_deploy_mezo_allocator.ts +++ b/solidity/deploy/02_deploy_mezo_allocator.ts @@ -7,9 +7,13 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { governance } = await getNamedAccounts() const { deployer } = await helpers.signers.getNamedSigners() - const tbtc = await deployments.get("TBTC") const stbtc = await deployments.get("stBTC") - const mezoPortal = await deployments.get("MezoPortal") + let tbtc = await deployments.getOrNull("TBTC") + let mezoPortal = await deployments.getOrNull("MezoPortal") + if (hre.network.name === "integration") { + mezoPortal = await deployments.getArtifact("MezoPortal") + tbtc = await deployments.getArtifact("TBTC") + } const [, deployment] = await helpers.upgrades.deployProxy("MezoAllocator", { factoryOpts: { diff --git a/solidity/deploy/03_deploy_bitcoin_depositor.ts b/solidity/deploy/03_deploy_bitcoin_depositor.ts index 7de26abcb..cade3cbf1 100644 --- a/solidity/deploy/03_deploy_bitcoin_depositor.ts +++ b/solidity/deploy/03_deploy_bitcoin_depositor.ts @@ -7,9 +7,12 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { governance } = await getNamedAccounts() const { deployer } = await helpers.signers.getNamedSigners() + let tbtc = await deployments.getOrNull("TBTC") + if (hre.network.name === "integration") { + tbtc = await deployments.getArtifact("TBTC") + } const bridge = await deployments.get("Bridge") const tbtcVault = await deployments.get("TBTCVault") - const tbtc = await deployments.get("TBTC") const stbtc = await deployments.get("stBTC") const [, deployment] = await helpers.upgrades.deployProxy( diff --git a/solidity/deploy/04_deploy_bitcoin_redeemer.ts b/solidity/deploy/04_deploy_bitcoin_redeemer.ts index 7dbc0d847..96a0d0312 100644 --- a/solidity/deploy/04_deploy_bitcoin_redeemer.ts +++ b/solidity/deploy/04_deploy_bitcoin_redeemer.ts @@ -6,7 +6,10 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { deployments, helpers } = hre const { deployer } = await helpers.signers.getNamedSigners() - const tbtc = await deployments.get("TBTC") + let tbtc = await deployments.getOrNull("TBTC") + if (hre.network.name === "integration") { + tbtc = await deployments.getArtifact("TBTC") + } const stbtc = await deployments.get("stBTC") const tbtcVault = await deployments.get("TBTCVault") diff --git a/solidity/hardhat.config.ts b/solidity/hardhat.config.ts index 4db8ae721..1e52823fa 100644 --- a/solidity/hardhat.config.ts +++ b/solidity/hardhat.config.ts @@ -29,6 +29,10 @@ const config: HardhatUserConfig = { hardhat: { tags: ["allowStubs"], }, + integration: { + url: "http://localhost:8545", + tags: ["allowStubs"], + }, sepolia: { url: process.env.CHAIN_API_URL || "", chainId: 11155111, @@ -48,9 +52,18 @@ const config: HardhatUserConfig = { }, external: { + contracts: + process.env.INTEGRATION_TEST === "true" + ? [ + { + artifacts: "./external/mainnet", + }, + ] + : undefined, deployments: { sepolia: ["./external/sepolia"], mainnet: ["./external/mainnet"], + integration: ["./external/mainnet"], }, }, diff --git a/solidity/package.json b/solidity/package.json index 6f867cbaf..7809a84cc 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -16,7 +16,7 @@ "scripts": { "clean": "hardhat clean && rm -rf cache/ export/ gen/ export.json", "build": "hardhat compile", - "deploy": "hardhat deploy --export export.json", + "deployment": "hardhat deploy --export export.json", "docs": "hardhat docgen", "format": "npm run lint:js && npm run lint:sol && npm run lint:config", "format:fix": "npm run lint:js:fix && npm run lint:sol:fix && npm run lint:config:fix", @@ -26,7 +26,8 @@ "lint:sol:fix": "solhint 'contracts/**/*.sol' --fix && prettier --write 'contracts/**/*.sol'", "lint:config": "prettier --check '**/*.@(json)'", "lint:config:fix": "prettier --write '**/*.@(json)'", - "test": "hardhat test" + "test": "hardhat test ./test/*.test.ts", + "test:integration": "INTEGRATION_TEST=true hardhat test ./test/integration/*.test.ts --network integration" }, "devDependencies": { "@keep-network/hardhat-helpers": "^0.7.1", diff --git a/solidity/test/helpers/context.ts b/solidity/test/helpers/context.ts index b4d864fcb..9a9f223dd 100644 --- a/solidity/test/helpers/context.ts +++ b/solidity/test/helpers/context.ts @@ -6,7 +6,7 @@ import type { BridgeStub, TBTCVaultStub, MezoAllocator, - MezoPortalStub, + IMezoPortal, BitcoinDepositor, BitcoinRedeemer, TestTBTC, @@ -14,6 +14,7 @@ import type { // eslint-disable-next-line import/prefer-default-export export async function deployment() { + const isIntegration = deployments.getNetworkName() === "integration" await deployments.fixture() const stbtc: stBTC = await getDeployedContract("stBTC") @@ -22,13 +23,16 @@ export async function deployment() { const bitcoinRedeemer: BitcoinRedeemer = await getDeployedContract("BitcoinRedeemer") - const tbtc: TestTBTC = await getDeployedContract("TBTC") + const tbtc: TestTBTC = await getDeployedContract("TBTC", isIntegration) const tbtcBridge: BridgeStub = await getDeployedContract("Bridge") const tbtcVault: TBTCVaultStub = await getDeployedContract("TBTCVault") const mezoAllocator: MezoAllocator = await getDeployedContract("MezoAllocator") - const mezoPortal: MezoPortalStub = await getDeployedContract("MezoPortal") + const mezoPortal: IMezoPortal = await getDeployedContract( + "MezoPortal", + isIntegration, + ) return { tbtc, diff --git a/solidity/test/helpers/contract.ts b/solidity/test/helpers/contract.ts index 9233529d4..be944e984 100644 --- a/solidity/test/helpers/contract.ts +++ b/solidity/test/helpers/contract.ts @@ -12,9 +12,15 @@ const { getUnnamedSigners } = helpers.signers // eslint-disable-next-line import/prefer-default-export export async function getDeployedContract( deploymentName: string, + isIntegrationTest: boolean = false, ): Promise { - const { address, abi } = await deployments.get(deploymentName) - + let address: string + let abi: string + if (isIntegrationTest) { + ;({ address, abi } = await deployments.getArtifact(deploymentName)) + } else { + ;({ address, abi } = await deployments.get(deploymentName)) + } // Use default unnamed signer from index 0 to initialize the contract runner. const [defaultSigner] = await getUnnamedSigners() diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts new file mode 100644 index 000000000..127d3db2e --- /dev/null +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -0,0 +1,346 @@ +import { helpers } from "hardhat" +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers" +import { expect } from "chai" +import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers" + +import { ContractTransactionResponse } from "ethers" +import { beforeAfterSnapshotWrapper, deployment } from "../helpers" + +import { + StBTC as stBTC, + TestERC20, + MezoAllocator, + IMezoPortal, +} from "../../typechain" + +import { to1e18 } from "../utils" + +const { getNamedSigners, getUnnamedSigners } = helpers.signers +const { impersonateAccount } = helpers.account + +async function fixture() { + const { tbtc, stbtc, mezoAllocator, mezoPortal } = await deployment() + const { governance, maintainer } = await getNamedSigners() + const [depositor, thirdParty] = await getUnnamedSigners() + + return { + governance, + thirdParty, + depositor, + maintainer, + tbtc, + stbtc, + mezoAllocator, + mezoPortal, + } +} + +describe("MezoAllocator", () => { + // This is a random mainnet address of the whale account that holds 100 tBTC + // tokens that can be used for testing purposes after impersonation. + const whaleAddress = "0x84eA3907b9206427F45c7b2614925a2B86D12611" + let tbtc: TestERC20 + let stbtc: stBTC + let mezoAllocator: MezoAllocator + let mezoPortal: IMezoPortal + + let thirdParty: HardhatEthersSigner + let depositor: HardhatEthersSigner + let maintainer: HardhatEthersSigner + let governance: HardhatEthersSigner + let tbtcHolder: HardhatEthersSigner + + before(async () => { + ;({ + thirdParty, + depositor, + maintainer, + governance, + tbtc, + stbtc, + mezoAllocator, + mezoPortal, + } = await loadFixture(fixture)) + + await impersonateAccount(whaleAddress) + // eslint-disable-next-line + tbtcHolder = await ethers.getSigner(whaleAddress) + }) + + describe("allocate", () => { + beforeAfterSnapshotWrapper() + + context("when a caller is not a maintainer", () => { + it("should revert", async () => { + await expect( + mezoAllocator.connect(thirdParty).allocate(), + ).to.be.revertedWithCustomError(mezoAllocator, "CallerNotMaintainer") + }) + }) + + context("when the caller is maintainer", () => { + context("when a first deposit is made", () => { + let tx: ContractTransactionResponse + + before(async () => { + await tbtc + .connect(tbtcHolder) + .transfer(await stbtc.getAddress(), to1e18(6)) + tx = await mezoAllocator.connect(maintainer).allocate() + }) + + it("should deposit and transfer tBTC to Mezo Portal", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [await mezoPortal.getAddress()], + [to1e18(6)], + ) + }) + + it("should not store any tBTC in Mezo Allocator", async () => { + expect( + await tbtc.balanceOf(await mezoAllocator.getAddress()), + ).to.equal(0) + }) + + it("should increment the deposit id", async () => { + const actualDepositId = await mezoAllocator.depositId() + // As of writing this test, the deposit id was 2272 before the new + // allocation. The deposit id should be incremented by 1. + expect(actualDepositId).to.equal(2273) + }) + + it("should increase tracked deposit balance amount", async () => { + const depositBalance = await mezoAllocator.depositBalance() + expect(depositBalance).to.equal(to1e18(6)) + }) + + it("should emit DepositAllocated event", async () => { + await expect(tx) + .to.emit(mezoAllocator, "DepositAllocated") + .withArgs(0, 2273, to1e18(6), to1e18(6)) + }) + }) + + context("when a second deposit is made", () => { + let tx: ContractTransactionResponse + + before(async () => { + await tbtc + .connect(tbtcHolder) + .transfer(await stbtc.getAddress(), to1e18(5)) + + tx = await mezoAllocator.connect(maintainer).allocate() + }) + + it("should increment the deposit id", async () => { + const actualDepositId = await mezoAllocator.depositId() + expect(actualDepositId).to.equal(2274) + }) + + it("should emit DepositAllocated event", async () => { + await expect(tx) + .to.emit(mezoAllocator, "DepositAllocated") + .withArgs(2273, 2274, to1e18(5), to1e18(11)) + }) + + it("should deposit and transfer tBTC to Mezo Portal", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [await mezoPortal.getAddress()], + [to1e18(5)], + ) + }) + + it("should increase tracked deposit balance amount", async () => { + const depositBalance = await mezoAllocator.depositBalance() + expect(depositBalance).to.equal(to1e18(11)) + }) + + it("should not store any tBTC in Mezo Allocator", async () => { + expect( + await tbtc.balanceOf(await mezoAllocator.getAddress()), + ).to.equal(0) + }) + + it("should not store any tBTC in stBTC", async () => { + expect(await tbtc.balanceOf(await stbtc.getAddress())).to.equal(0) + }) + }) + }) + }) + + describe("withdraw", () => { + beforeAfterSnapshotWrapper() + + context("when a caller is not stBTC", () => { + it("should revert", async () => { + await expect( + mezoAllocator.connect(thirdParty).withdraw(1n), + ).to.be.revertedWithCustomError(mezoAllocator, "CallerNotStbtc") + }) + }) + + context("when the caller is stBTC contract", () => { + context("when there is no deposit", () => { + it("should revert", async () => { + // It is reverted because deposit Id is 0 and there is no deposit + // with id 0 in Mezo Portal for Acre. Mezo Portal reverts with the + // "unrecognized custom error" that is why we verify only against + // a generic revert. + await expect(stbtc.withdraw(1n, depositor, depositor)).to.be.reverted + }) + }) + + context("when there is a deposit", () => { + let tx: ContractTransactionResponse + + before(async () => { + await tbtc.connect(tbtcHolder).transfer(depositor.address, to1e18(11)) + await tbtc.approve(await stbtc.getAddress(), to1e18(5)) + await stbtc.connect(depositor).deposit(to1e18(5), depositor) + await mezoAllocator.connect(maintainer).allocate() + }) + + context("when the deposit is not fully withdrawn", () => { + before(async () => { + tx = await stbtc.withdraw(to1e18(2), depositor, depositor) + }) + + it("should transfer 2 tBTC back to a depositor", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [depositor.address], + [to1e18(2)], + ) + }) + + it("should emit DepositWithdrawn event", async () => { + await expect(tx) + .to.emit(mezoAllocator, "DepositWithdrawn") + .withArgs(2273, to1e18(2)) + }) + + it("should decrease tracked deposit balance amount", async () => { + const depositBalance = await mezoAllocator.depositBalance() + expect(depositBalance).to.equal(to1e18(3)) + }) + + it("should decrease Mezo Portal balance", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [await mezoPortal.getAddress()], + [-to1e18(2)], + ) + }) + }) + + context("when the deposit is fully withdrawn", () => { + before(async () => { + tx = await stbtc.withdraw(to1e18(3), depositor, depositor) + }) + + it("should transfer 3 tBTC back to a depositor", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [depositor.address], + [to1e18(3)], + ) + }) + + it("should emit DepositWithdrawn event", async () => { + await expect(tx) + .to.emit(mezoAllocator, "DepositWithdrawn") + .withArgs(2273, to1e18(3)) + }) + + it("should decrease tracked deposit balance amount to zero", async () => { + const depositBalance = await mezoAllocator.depositBalance() + expect(depositBalance).to.equal(0) + }) + + it("should decrease Mezo Portal balance", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [await mezoPortal.getAddress()], + [-to1e18(3)], + ) + }) + }) + }) + }) + }) + + describe("totalAssets", () => { + beforeAfterSnapshotWrapper() + + context("when there is no deposit", () => { + it("should return 0", async () => { + const totalAssets = await mezoAllocator.totalAssets() + expect(totalAssets).to.equal(0) + }) + }) + + context("when there is a deposit", () => { + before(async () => { + await tbtc + .connect(tbtcHolder) + .transfer(await stbtc.getAddress(), to1e18(5)) + await mezoAllocator.connect(maintainer).allocate() + }) + + it("should return the total assets value", async () => { + const totalAssets = await mezoAllocator.totalAssets() + expect(totalAssets).to.equal(to1e18(5)) + }) + }) + }) + + describe("releaseDeposit", () => { + beforeAfterSnapshotWrapper() + + context("when a caller is not governance", () => { + it("should revert", async () => { + await expect( + mezoAllocator.connect(thirdParty).releaseDeposit(), + ).to.be.revertedWithCustomError( + mezoAllocator, + "OwnableUnauthorizedAccount", + ) + }) + }) + + context("when the caller is governance", () => { + context("when there is a deposit", () => { + let tx: ContractTransactionResponse + + before(async () => { + await tbtc + .connect(tbtcHolder) + .transfer(await stbtc.getAddress(), to1e18(5)) + await mezoAllocator.connect(maintainer).allocate() + tx = await mezoAllocator.connect(governance).releaseDeposit() + }) + + it("should emit DepositReleased event", async () => { + await expect(tx) + .to.emit(mezoAllocator, "DepositReleased") + .withArgs(2273, to1e18(5)) + }) + + it("should decrease tracked deposit balance amount to zero", async () => { + const depositBalance = await mezoAllocator.depositBalance() + expect(depositBalance).to.equal(0) + }) + + it("should decrease Mezo Portal balance", async () => { + await expect(tx).to.changeTokenBalances( + tbtc, + [mezoPortal, stbtc], + [-to1e18(5), to1e18(5)], + ) + }) + }) + }) + }) +}) From f7293bde205e39c3bf8342b7b0a89c287b984171 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 22 Apr 2024 15:23:06 +0200 Subject: [PATCH 02/12] Fixing deployment command in CI Changed from "pnpm run deploy" to "pnpm run deployment". The original change was driven by the conflict between hardhat and pnpm "deploy" commands. --- .github/workflows/solidity.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/solidity.yaml b/.github/workflows/solidity.yaml index 7586edb1a..818e93d59 100644 --- a/.github/workflows/solidity.yaml +++ b/.github/workflows/solidity.yaml @@ -140,7 +140,7 @@ jobs: path: solidity/ - name: Deploy - run: pnpm run deploy --no-compile + run: pnpm run deployment --no-compile solidity-deploy-testnet: needs: [solidity-deploy-dry-run] From 2e88d5d1d9434849172fbf83dc7bc64f7ed392a2 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 10:38:24 +0200 Subject: [PATCH 03/12] Reverting ignored deployment dir --- solidity/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/solidity/.gitignore b/solidity/.gitignore index 5d20b1efc..1f9e31a2d 100644 --- a/solidity/.gitignore +++ b/solidity/.gitignore @@ -5,4 +5,3 @@ export.json export/ gen/ typechain/ -deployments/ From 718a7234f6d501835a7ca0a322c7b1f6ede822eb Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 10:38:48 +0200 Subject: [PATCH 04/12] Simplifying artifacts fetching for integration tests We can use the '--deploy-fixture' flag to fetch the mainnet artifacts for integration tests purposes. This can replace dealing with the 'integration' flag and using 'getArtifacts' function. --- solidity/deploy/00_resolve_mezo_portal.ts | 10 +++++----- solidity/deploy/00_resolve_tbtc_token.ts | 6 ++---- solidity/deploy/00_resolve_tbtc_vault.ts | 6 +----- solidity/deploy/01_deploy_stbtc.ts | 5 +---- solidity/deploy/02_deploy_mezo_allocator.ts | 8 ++------ solidity/deploy/03_deploy_bitcoin_depositor.ts | 5 +---- solidity/deploy/04_deploy_bitcoin_redeemer.ts | 5 +---- solidity/hardhat.config.ts | 9 --------- solidity/package.json | 2 +- solidity/test/helpers/context.ts | 8 ++------ solidity/test/helpers/contract.ts | 9 +-------- 11 files changed, 17 insertions(+), 56 deletions(-) diff --git a/solidity/deploy/00_resolve_mezo_portal.ts b/solidity/deploy/00_resolve_mezo_portal.ts index 9e1c3fb4e..d67738a8b 100644 --- a/solidity/deploy/00_resolve_mezo_portal.ts +++ b/solidity/deploy/00_resolve_mezo_portal.ts @@ -11,14 +11,14 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { log } = deployments const { deployer } = await getNamedAccounts() - let mezoPortal = await deployments.getOrNull("MezoPortal") - if (hre.network.name === "integration") { - mezoPortal = await deployments.getArtifact("MezoPortal") - } + const mezoPortal = await deployments.getOrNull("MezoPortal") if (mezoPortal && isNonZeroAddress(mezoPortal.address)) { log(`using MezoPortal contract at ${mezoPortal.address}`) - } else if ((hre.network.config as HardhatNetworkConfig)?.forking?.enabled) { + } else if ( + hre.network.name === "integration" || + (hre.network.config as HardhatNetworkConfig)?.forking?.enabled + ) { throw new Error("deployed MezoPortal contract not found") } else { log("deploying Mezo Portal contract stub") diff --git a/solidity/deploy/00_resolve_tbtc_token.ts b/solidity/deploy/00_resolve_tbtc_token.ts index 473d77f5d..13343a0b3 100644 --- a/solidity/deploy/00_resolve_tbtc_token.ts +++ b/solidity/deploy/00_resolve_tbtc_token.ts @@ -11,14 +11,12 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { log } = deployments const { deployer } = await getNamedAccounts() - let tbtc = await deployments.getOrNull("TBTC") - if (hre.network.name === "integration") { - tbtc = await deployments.getArtifact("TBTC") - } + const tbtc = await deployments.getOrNull("TBTC") if (tbtc && isNonZeroAddress(tbtc.address)) { log(`using TBTC contract at ${tbtc.address}`) } else if ( + hre.network.name === "integration" || !hre.network.tags.allowStubs || (hre.network.config as HardhatNetworkConfig)?.forking?.enabled ) { diff --git a/solidity/deploy/00_resolve_tbtc_vault.ts b/solidity/deploy/00_resolve_tbtc_vault.ts index a946044c6..85ae3bf5a 100644 --- a/solidity/deploy/00_resolve_tbtc_vault.ts +++ b/solidity/deploy/00_resolve_tbtc_vault.ts @@ -23,11 +23,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { } else { log("deploying TBTCVault contract stub") - let tbtc = await deployments.getOrNull("TBTC") - if (hre.network.name === "integration") { - tbtc = await deployments.getArtifact("TBTC") - } - + const tbtc = await deployments.get("TBTC") const bridge = await deployments.get("Bridge") const deployment = await deployments.deploy("TBTCVault", { diff --git a/solidity/deploy/01_deploy_stbtc.ts b/solidity/deploy/01_deploy_stbtc.ts index be9afd238..166e2fc4c 100644 --- a/solidity/deploy/01_deploy_stbtc.ts +++ b/solidity/deploy/01_deploy_stbtc.ts @@ -7,10 +7,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { treasury, governance } = await getNamedAccounts() const { deployer: deployerSigner } = await helpers.signers.getNamedSigners() - let tbtc = await deployments.getOrNull("TBTC") - if (hre.network.name === "integration") { - tbtc = await deployments.getArtifact("TBTC") - } + const tbtc = await deployments.get("TBTC") const [, stbtcDeployment] = await helpers.upgrades.deployProxy("stBTC", { contractName: "stBTC", diff --git a/solidity/deploy/02_deploy_mezo_allocator.ts b/solidity/deploy/02_deploy_mezo_allocator.ts index b3f6d1ef0..2a1bbeb86 100644 --- a/solidity/deploy/02_deploy_mezo_allocator.ts +++ b/solidity/deploy/02_deploy_mezo_allocator.ts @@ -8,12 +8,8 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { deployer } = await helpers.signers.getNamedSigners() const stbtc = await deployments.get("stBTC") - let tbtc = await deployments.getOrNull("TBTC") - let mezoPortal = await deployments.getOrNull("MezoPortal") - if (hre.network.name === "integration") { - mezoPortal = await deployments.getArtifact("MezoPortal") - tbtc = await deployments.getArtifact("TBTC") - } + const tbtc = await deployments.get("TBTC") + const mezoPortal = await deployments.get("MezoPortal") const [, deployment] = await helpers.upgrades.deployProxy("MezoAllocator", { factoryOpts: { diff --git a/solidity/deploy/03_deploy_bitcoin_depositor.ts b/solidity/deploy/03_deploy_bitcoin_depositor.ts index cade3cbf1..af280c9f5 100644 --- a/solidity/deploy/03_deploy_bitcoin_depositor.ts +++ b/solidity/deploy/03_deploy_bitcoin_depositor.ts @@ -7,10 +7,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { governance } = await getNamedAccounts() const { deployer } = await helpers.signers.getNamedSigners() - let tbtc = await deployments.getOrNull("TBTC") - if (hre.network.name === "integration") { - tbtc = await deployments.getArtifact("TBTC") - } + const tbtc = await deployments.get("TBTC") const bridge = await deployments.get("Bridge") const tbtcVault = await deployments.get("TBTCVault") const stbtc = await deployments.get("stBTC") diff --git a/solidity/deploy/04_deploy_bitcoin_redeemer.ts b/solidity/deploy/04_deploy_bitcoin_redeemer.ts index 96a0d0312..7dbc0d847 100644 --- a/solidity/deploy/04_deploy_bitcoin_redeemer.ts +++ b/solidity/deploy/04_deploy_bitcoin_redeemer.ts @@ -6,10 +6,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { const { deployments, helpers } = hre const { deployer } = await helpers.signers.getNamedSigners() - let tbtc = await deployments.getOrNull("TBTC") - if (hre.network.name === "integration") { - tbtc = await deployments.getArtifact("TBTC") - } + const tbtc = await deployments.get("TBTC") const stbtc = await deployments.get("stBTC") const tbtcVault = await deployments.get("TBTCVault") diff --git a/solidity/hardhat.config.ts b/solidity/hardhat.config.ts index 1e52823fa..c72c798e2 100644 --- a/solidity/hardhat.config.ts +++ b/solidity/hardhat.config.ts @@ -31,7 +31,6 @@ const config: HardhatUserConfig = { }, integration: { url: "http://localhost:8545", - tags: ["allowStubs"], }, sepolia: { url: process.env.CHAIN_API_URL || "", @@ -52,14 +51,6 @@ const config: HardhatUserConfig = { }, external: { - contracts: - process.env.INTEGRATION_TEST === "true" - ? [ - { - artifacts: "./external/mainnet", - }, - ] - : undefined, deployments: { sepolia: ["./external/sepolia"], mainnet: ["./external/mainnet"], diff --git a/solidity/package.json b/solidity/package.json index 7809a84cc..180773092 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -27,7 +27,7 @@ "lint:config": "prettier --check '**/*.@(json)'", "lint:config:fix": "prettier --write '**/*.@(json)'", "test": "hardhat test ./test/*.test.ts", - "test:integration": "INTEGRATION_TEST=true hardhat test ./test/integration/*.test.ts --network integration" + "test:integration": "hardhat test --deploy-fixture ./test/integration/*.test.ts --network integration" }, "devDependencies": { "@keep-network/hardhat-helpers": "^0.7.1", diff --git a/solidity/test/helpers/context.ts b/solidity/test/helpers/context.ts index 9a9f223dd..ea8bb6920 100644 --- a/solidity/test/helpers/context.ts +++ b/solidity/test/helpers/context.ts @@ -14,7 +14,6 @@ import type { // eslint-disable-next-line import/prefer-default-export export async function deployment() { - const isIntegration = deployments.getNetworkName() === "integration" await deployments.fixture() const stbtc: stBTC = await getDeployedContract("stBTC") @@ -23,16 +22,13 @@ export async function deployment() { const bitcoinRedeemer: BitcoinRedeemer = await getDeployedContract("BitcoinRedeemer") - const tbtc: TestTBTC = await getDeployedContract("TBTC", isIntegration) + const tbtc: TestTBTC = await getDeployedContract("TBTC") const tbtcBridge: BridgeStub = await getDeployedContract("Bridge") const tbtcVault: TBTCVaultStub = await getDeployedContract("TBTCVault") const mezoAllocator: MezoAllocator = await getDeployedContract("MezoAllocator") - const mezoPortal: IMezoPortal = await getDeployedContract( - "MezoPortal", - isIntegration, - ) + const mezoPortal: IMezoPortal = await getDeployedContract("MezoPortal") return { tbtc, diff --git a/solidity/test/helpers/contract.ts b/solidity/test/helpers/contract.ts index be944e984..5ff70126b 100644 --- a/solidity/test/helpers/contract.ts +++ b/solidity/test/helpers/contract.ts @@ -12,15 +12,8 @@ const { getUnnamedSigners } = helpers.signers // eslint-disable-next-line import/prefer-default-export export async function getDeployedContract( deploymentName: string, - isIntegrationTest: boolean = false, ): Promise { - let address: string - let abi: string - if (isIntegrationTest) { - ;({ address, abi } = await deployments.getArtifact(deploymentName)) - } else { - ;({ address, abi } = await deployments.get(deploymentName)) - } + const { address, abi } = await deployments.get(deploymentName) // Use default unnamed signer from index 0 to initialize the contract runner. const [defaultSigner] = await getUnnamedSigners() From 0a2a2d84ebfd0b01a58d01f7dc1ca91c2c292612 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 10:46:25 +0200 Subject: [PATCH 05/12] Adding README explaining how to run the integration tests --- solidity/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/solidity/README.md b/solidity/README.md index 651236aa9..177801d40 100644 --- a/solidity/README.md +++ b/solidity/README.md @@ -24,6 +24,22 @@ To run the test execute: $ pnpm test ``` +### Integration testing + +To run the integration tests follow these steps: + +- Run the Hardhat Node locally forking Mainnet at block `19680873`: + +``` +$ npx hardhat node --no-deploy --fork https://eth-mainnet.g.alchemy.com/v2/ --fork-block-number 19680873 +``` + +- Once the local node is running you can execute the integration tests: + +``` +$ pnpm test:integration +``` + ### Deploying We deploy our contracts with From 32062d6cb6a02877a70eb546c10a78290b9a7862 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 12:32:22 +0200 Subject: [PATCH 06/12] Reverting 'deployment' command back to 'deploy' Instead of running 'pnpm deploy', you should run 'pnpm run deploy' to bypass the conflict between a custom hardhat command and a build-in pnpm command. --- .github/workflows/solidity.yaml | 2 +- solidity/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/solidity.yaml b/.github/workflows/solidity.yaml index 818e93d59..7586edb1a 100644 --- a/.github/workflows/solidity.yaml +++ b/.github/workflows/solidity.yaml @@ -140,7 +140,7 @@ jobs: path: solidity/ - name: Deploy - run: pnpm run deployment --no-compile + run: pnpm run deploy --no-compile solidity-deploy-testnet: needs: [solidity-deploy-dry-run] diff --git a/solidity/package.json b/solidity/package.json index 180773092..8cb5969e1 100644 --- a/solidity/package.json +++ b/solidity/package.json @@ -16,7 +16,7 @@ "scripts": { "clean": "hardhat clean && rm -rf cache/ export/ gen/ export.json", "build": "hardhat compile", - "deployment": "hardhat deploy --export export.json", + "deploy": "hardhat deploy --export export.json", "docs": "hardhat docgen", "format": "npm run lint:js && npm run lint:sol && npm run lint:config", "format:fix": "npm run lint:js:fix && npm run lint:sol:fix && npm run lint:config:fix", From 962d17355f35fa949968a51405204a84199006f6 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 13:59:22 +0200 Subject: [PATCH 07/12] Simplifying the way we check for network names in the deployment scripts We use stubs only in hardhat network. For all other networks we'd use actual contracts. This way the deployment scripts can be simplified. --- solidity/deploy/00_resolve_mezo_portal.ts | 10 ++-------- solidity/deploy/00_resolve_tbtc_bridge.ts | 7 ++----- solidity/deploy/00_resolve_tbtc_token.ts | 11 ++--------- solidity/deploy/00_resolve_tbtc_vault.ts | 24 ++++++++--------------- solidity/hardhat.config.ts | 3 --- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/solidity/deploy/00_resolve_mezo_portal.ts b/solidity/deploy/00_resolve_mezo_portal.ts index d67738a8b..15569002a 100644 --- a/solidity/deploy/00_resolve_mezo_portal.ts +++ b/solidity/deploy/00_resolve_mezo_portal.ts @@ -1,8 +1,5 @@ import type { DeployFunction } from "hardhat-deploy/types" -import type { - HardhatNetworkConfig, - HardhatRuntimeEnvironment, -} from "hardhat/types" +import type { HardhatRuntimeEnvironment } from "hardhat/types" import { isNonZeroAddress } from "../helpers/address" import { waitConfirmationsNumber } from "../helpers/deployment" @@ -15,10 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (mezoPortal && isNonZeroAddress(mezoPortal.address)) { log(`using MezoPortal contract at ${mezoPortal.address}`) - } else if ( - hre.network.name === "integration" || - (hre.network.config as HardhatNetworkConfig)?.forking?.enabled - ) { + } else if (hre.network.name !== "hardhat") { throw new Error("deployed MezoPortal contract not found") } else { log("deploying Mezo Portal contract stub") diff --git a/solidity/deploy/00_resolve_tbtc_bridge.ts b/solidity/deploy/00_resolve_tbtc_bridge.ts index 4150b696a..98e60c54e 100644 --- a/solidity/deploy/00_resolve_tbtc_bridge.ts +++ b/solidity/deploy/00_resolve_tbtc_bridge.ts @@ -1,8 +1,5 @@ import type { DeployFunction } from "hardhat-deploy/types" -import type { - HardhatNetworkConfig, - HardhatRuntimeEnvironment, -} from "hardhat/types" +import type { HardhatRuntimeEnvironment } from "hardhat/types" import { isNonZeroAddress } from "../helpers/address" import { waitConfirmationsNumber } from "../helpers/deployment" @@ -15,7 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (bridge && isNonZeroAddress(bridge.address)) { log(`using Bridge contract at ${bridge.address}`) - } else if ((hre.network.config as HardhatNetworkConfig)?.forking?.enabled) { + } else if (hre.network.name !== "hardhat") { throw new Error("deployed Bridge contract not found") } else { log("deploying Bridge contract stub") diff --git a/solidity/deploy/00_resolve_tbtc_token.ts b/solidity/deploy/00_resolve_tbtc_token.ts index 13343a0b3..e710fd02a 100644 --- a/solidity/deploy/00_resolve_tbtc_token.ts +++ b/solidity/deploy/00_resolve_tbtc_token.ts @@ -1,8 +1,5 @@ import type { DeployFunction } from "hardhat-deploy/types" -import type { - HardhatNetworkConfig, - HardhatRuntimeEnvironment, -} from "hardhat/types" +import type { HardhatRuntimeEnvironment } from "hardhat/types" import { isNonZeroAddress } from "../helpers/address" import { waitConfirmationsNumber } from "../helpers/deployment" @@ -15,11 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (tbtc && isNonZeroAddress(tbtc.address)) { log(`using TBTC contract at ${tbtc.address}`) - } else if ( - hre.network.name === "integration" || - !hre.network.tags.allowStubs || - (hre.network.config as HardhatNetworkConfig)?.forking?.enabled - ) { + } else if (hre.network.name !== "hardhat") { throw new Error("deployed TBTC contract not found") } else { log("deploying TBTC contract stub") diff --git a/solidity/deploy/00_resolve_tbtc_vault.ts b/solidity/deploy/00_resolve_tbtc_vault.ts index 85ae3bf5a..c8a0f5517 100644 --- a/solidity/deploy/00_resolve_tbtc_vault.ts +++ b/solidity/deploy/00_resolve_tbtc_vault.ts @@ -1,8 +1,5 @@ import type { DeployFunction } from "hardhat-deploy/types" -import type { - HardhatNetworkConfig, - HardhatRuntimeEnvironment, -} from "hardhat/types" +import type { HardhatRuntimeEnvironment } from "hardhat/types" import { isNonZeroAddress } from "../helpers/address" import { waitConfirmationsNumber } from "../helpers/deployment" @@ -15,10 +12,7 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { if (tbtcVault && isNonZeroAddress(tbtcVault.address)) { log(`using TBTCVault contract at ${tbtcVault.address}`) - } else if ( - !hre.network.tags.allowStubs || - (hre.network.config as HardhatNetworkConfig)?.forking?.enabled - ) { + } else if (hre.network.name !== "hardhat") { throw new Error("deployed TBTCVault contract not found") } else { log("deploying TBTCVault contract stub") @@ -34,14 +28,12 @@ const func: DeployFunction = async (hre: HardhatRuntimeEnvironment) => { waitConfirmations: waitConfirmationsNumber(hre), }) - if (hre.network.name === "hardhat") { - await deployments.execute( - "TBTC", - { from: deployer, log: true }, - "setOwner", - deployment.address, - ) - } + await deployments.execute( + "TBTC", + { from: deployer, log: true }, + "setOwner", + deployment.address, + ) } } diff --git a/solidity/hardhat.config.ts b/solidity/hardhat.config.ts index c72c798e2..ac6a1492e 100644 --- a/solidity/hardhat.config.ts +++ b/solidity/hardhat.config.ts @@ -26,9 +26,6 @@ const config: HardhatUserConfig = { }, networks: { - hardhat: { - tags: ["allowStubs"], - }, integration: { url: "http://localhost:8545", }, From bfe755c788ec7e1aeecc3583ecac131a2dbef7aa Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 14:08:23 +0200 Subject: [PATCH 08/12] Importing ethers from HH to make eslint happy --- solidity/test/integration/MezoAllocator.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts index 127d3db2e..62f4b0d27 100644 --- a/solidity/test/integration/MezoAllocator.test.ts +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -1,4 +1,4 @@ -import { helpers } from "hardhat" +import { helpers, ethers } from "hardhat" import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers" import { expect } from "chai" import { loadFixture } from "@nomicfoundation/hardhat-toolbox/network-helpers" @@ -63,7 +63,6 @@ describe("MezoAllocator", () => { } = await loadFixture(fixture)) await impersonateAccount(whaleAddress) - // eslint-disable-next-line tbtcHolder = await ethers.getSigner(whaleAddress) }) From e22155407aef72bddc27df6ebd2fd2cb99c09217 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 14:12:31 +0200 Subject: [PATCH 09/12] Rephrasing the comment for a test --- solidity/test/integration/MezoAllocator.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts index 62f4b0d27..a700dc4f4 100644 --- a/solidity/test/integration/MezoAllocator.test.ts +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -104,7 +104,7 @@ describe("MezoAllocator", () => { it("should increment the deposit id", async () => { const actualDepositId = await mezoAllocator.depositId() - // As of writing this test, the deposit id was 2272 before the new + // As of a forked block 19680873, the deposit id was 2272 before the new // allocation. The deposit id should be incremented by 1. expect(actualDepositId).to.equal(2273) }) From 8c941459469311e8cf22189ae9303c1c654305cf Mon Sep 17 00:00:00 2001 From: Dmitry Date: Wed, 24 Apr 2024 15:48:03 +0200 Subject: [PATCH 10/12] Making withdrawal tests independent from each other --- .../test/integration/MezoAllocator.test.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts index a700dc4f4..4f2f94ea8 100644 --- a/solidity/test/integration/MezoAllocator.test.ts +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -182,6 +182,8 @@ describe("MezoAllocator", () => { context("when the caller is stBTC contract", () => { context("when there is no deposit", () => { + beforeAfterSnapshotWrapper() + it("should revert", async () => { // It is reverted because deposit Id is 0 and there is no deposit // with id 0 in Mezo Portal for Acre. Mezo Portal reverts with the @@ -192,6 +194,8 @@ describe("MezoAllocator", () => { }) context("when there is a deposit", () => { + beforeAfterSnapshotWrapper() + let tx: ContractTransactionResponse before(async () => { @@ -202,6 +206,8 @@ describe("MezoAllocator", () => { }) context("when the deposit is not fully withdrawn", () => { + beforeAfterSnapshotWrapper() + before(async () => { tx = await stbtc.withdraw(to1e18(2), depositor, depositor) }) @@ -235,22 +241,24 @@ describe("MezoAllocator", () => { }) context("when the deposit is fully withdrawn", () => { + beforeAfterSnapshotWrapper() + before(async () => { - tx = await stbtc.withdraw(to1e18(3), depositor, depositor) + tx = await stbtc.withdraw(to1e18(5), depositor, depositor) }) - it("should transfer 3 tBTC back to a depositor", async () => { + it("should transfer 5 tBTC back to a depositor", async () => { await expect(tx).to.changeTokenBalances( tbtc, [depositor.address], - [to1e18(3)], + [to1e18(5)], ) }) it("should emit DepositWithdrawn event", async () => { await expect(tx) .to.emit(mezoAllocator, "DepositWithdrawn") - .withArgs(2273, to1e18(3)) + .withArgs(2273, to1e18(5)) }) it("should decrease tracked deposit balance amount to zero", async () => { @@ -262,7 +270,7 @@ describe("MezoAllocator", () => { await expect(tx).to.changeTokenBalances( tbtc, [await mezoPortal.getAddress()], - [-to1e18(3)], + [-to1e18(5)], ) }) }) From f68e51f620dc1b4ed5b62cbbc1e3704a65845c41 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 25 Apr 2024 10:47:28 +0200 Subject: [PATCH 11/12] Covering a scenario when withdrawing more than deposited Verified that MezoPortal will throw an InsufficientDepositAmount error when a depositor wants to withdraw more than was initially deposited. --- solidity/test/integration/MezoAllocator.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts index 4f2f94ea8..1840815b2 100644 --- a/solidity/test/integration/MezoAllocator.test.ts +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -274,6 +274,19 @@ describe("MezoAllocator", () => { ) }) }) + + context("when withdrawing more than was deposited", () => { + beforeAfterSnapshotWrapper() + + it("should revert", async () => { + await expect(stbtc.withdraw(to1e18(6), depositor, depositor)) + .to.be.revertedWithCustomError( + mezoPortal, + "InsufficientDepositAmount", + ) + .withArgs(to1e18(6), to1e18(5)) + }) + }) }) }) }) From 90f1e642f8bfb4a151f95bb2a48213bcb2391b20 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 25 Apr 2024 11:56:16 +0200 Subject: [PATCH 12/12] Changing a generic error to verify against a custom error DepositNotFound --- solidity/test/integration/MezoAllocator.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solidity/test/integration/MezoAllocator.test.ts b/solidity/test/integration/MezoAllocator.test.ts index 1840815b2..758704827 100644 --- a/solidity/test/integration/MezoAllocator.test.ts +++ b/solidity/test/integration/MezoAllocator.test.ts @@ -185,11 +185,11 @@ describe("MezoAllocator", () => { beforeAfterSnapshotWrapper() it("should revert", async () => { - // It is reverted because deposit Id is 0 and there is no deposit - // with id 0 in Mezo Portal for Acre. Mezo Portal reverts with the - // "unrecognized custom error" that is why we verify only against - // a generic revert. - await expect(stbtc.withdraw(1n, depositor, depositor)).to.be.reverted + // It is reverted because deposit id is 0 and there is no deposit + // with id 0 in Mezo Portal for Acre. + await expect( + stbtc.withdraw(1n, depositor, depositor), + ).to.be.revertedWithCustomError(mezoPortal, "DepositNotFound") }) })