diff --git a/scripts/deployment-utils/deploy-lbc-implementation.ts b/scripts/deployment-utils/deploy-lbc-implementation.ts new file mode 100644 index 0000000..73e2671 --- /dev/null +++ b/scripts/deployment-utils/deploy-lbc-implementation.ts @@ -0,0 +1,56 @@ +import { ethers, upgrades } from "hardhat"; +import { DeployedContractInfo, read } from "./deploy"; +import { deployUpgradeLibraries } from "./upgrade-proxy"; + +/** + * This function deploys a LBC implementation contract **without** redirecting the LBC proxy. This function + * should be used when the deployment of the implementation contract is not going to be performed by the + * proxy admin owner. The deployment includes deploying the required libraries and linking them to the contract. + * + * @param network The name of the network to deploy the contract to as it appears in the addresses.json file. + * @param opts Options object, currently only has a verbose flag. + * + * @returns { Promise } The information of the deployed contract. + */ +export async function deployLbcImplementation( + network: string, + opts = { verbose: true } +): Promise> { + const libs = await deployUpgradeLibraries(network, opts); + const proxyName = "LiquidityBridgeContract"; + const upgradeName = "LiquidityBridgeContractV2"; + const LiquidityBridgeContractV2 = await ethers.getContractFactory( + upgradeName, + { + libraries: { + QuotesV2: libs.quotesV2, + BtcUtils: libs.btcUtils, + SignatureValidator: libs.signatureValidator, + }, + } + ); + + const proxyAddress = read()[network][proxyName].address; + if (!proxyAddress) { + throw new Error(`Proxy ${proxyName} not deployed on network ${network}`); + } + + if (opts.verbose) { + console.info(`Deploying implementation with libs:`, libs); + } + const implementationAddress = (await upgrades.prepareUpgrade( + proxyAddress, + LiquidityBridgeContractV2, + { + unsafeAllow: ["external-library-linking"], + } + )) as string; + if (opts.verbose) { + console.info(`Implementation deployed at ${implementationAddress}`); + } + + return { + deployed: true, + address: implementationAddress, + }; +} diff --git a/scripts/deployment-utils/upgrade-proxy.ts b/scripts/deployment-utils/upgrade-proxy.ts index 01456ae..1be1038 100644 --- a/scripts/deployment-utils/upgrade-proxy.ts +++ b/scripts/deployment-utils/upgrade-proxy.ts @@ -8,7 +8,7 @@ interface LiquidityBridgeContractLibraries { signatureValidator: string; } -async function deployUpgradeLibraries( +export async function deployUpgradeLibraries( network: string, opts: { verbose: boolean } ): Promise { diff --git a/scripts/deployment/prepare-upgrade.ts b/scripts/deployment/prepare-upgrade.ts new file mode 100644 index 0000000..676608a --- /dev/null +++ b/scripts/deployment/prepare-upgrade.ts @@ -0,0 +1,13 @@ +import hre from "hardhat"; +import { deployLbcImplementation } from "../deployment-utils/deploy-lbc-implementation"; + +async function main() { + const network = hre.network.name; + const deploymentInfo = await deployLbcImplementation(network); + console.info("IMPLEMENTATION ADDRESS: ", deploymentInfo.address); +} + +main().catch((error: unknown) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/test/deployment.test.ts b/test/deployment.test.ts index 016c370..05c742e 100644 --- a/test/deployment.test.ts +++ b/test/deployment.test.ts @@ -5,6 +5,7 @@ import { deployLbcProxy } from "../scripts/deployment-utils/deploy-proxy"; import { upgradeLbcProxy } from "../scripts/deployment-utils/upgrade-proxy"; import { ZERO_ADDRESS } from "./utils/constants"; import { BRIDGE_ADDRESS } from "../scripts/deployment-utils/constants"; +import { deployLbcImplementation } from "../scripts/deployment-utils/deploy-lbc-implementation"; describe("LiquidityBridgeContract deployment process should", function () { let proxyAddress: string; @@ -147,4 +148,38 @@ describe("LiquidityBridgeContract deployment process should", function () { } } }); + + it("deploy implementation without upgrading proxy", async () => { + const proxy = await deployLbcProxy(hre.network.name, { verbose: false }); + proxyAddress = proxy.address; + const lbcProxy = await ethers.getContractAt( + "LiquidityBridgeContractV2", + proxy.address + ); + const initializedQuery = await lbcProxy.queryFilter( + lbcProxy.getEvent("Initialized") + ); + + const implementation = await deployLbcImplementation(hre.network.name, { + verbose: false, + }); + const lbcImplementation = await ethers.getContractAt( + "LiquidityBridgeContractV2", + implementation.address + ); + + expect(proxy.deployed).to.be.eq(true); + expect(implementation.deployed).to.be.eq(true); + expect(initializedQuery.length).length.equal(1); + expect(proxy.address).not.to.eq(implementation.address); + + // this is to ensure implementation does not have state + await expect(lbcProxy.getMinCollateral()).to.eventually.eq( + ethers.parseEther("0.03") + ); + await expect(lbcImplementation.getMinCollateral()).to.eventually.eq(0n); + + await expect(lbcProxy.version()).to.be.reverted; + await expect(lbcImplementation.version()).to.eventually.eq("1.3.0"); + }); }); diff --git a/test/pegin.test.ts b/test/pegin.test.ts index a18a6ad..d273c5e 100644 --- a/test/pegin.test.ts +++ b/test/pegin.test.ts @@ -547,7 +547,7 @@ describe("LiquidityBridgeContractV2 pegin process should", () => { productFeeAmount: BigInt("6000000000000000"), gasFee: BigInt("3000000000000000"), }, - address: "2Mvz5NDrXSSBCXzhrxnuo9TDS8Co4Wk1t8N", + address: "2NAXHKYRnTme4oDCk9mSPfdf4ga2tZ1xM5B", }, { quote: { @@ -579,7 +579,7 @@ describe("LiquidityBridgeContractV2 pegin process should", () => { productFeeAmount: BigInt("7000000000000000"), gasFee: BigInt("4000000000000000"), }, - address: "2Mxb4NdDaDBX4kjxhBrzjMG5WbCjok6LWab", + address: "2NCDJzPze5eosHN5Tx4pf5GF2zXtaKDUHzX", }, { quote: { @@ -611,7 +611,7 @@ describe("LiquidityBridgeContractV2 pegin process should", () => { productFeeAmount: BigInt("8000000000000000"), gasFee: BigInt("5000000000000000"), }, - address: "2NCx9M8j7nZTp3GmP36CFvFgYNLBQwQPwDR", + address: "2N7rxjtHjbxr8W3U3HVncyHJhEhBQ3tBa9w", }, ];