From 8380f5be1ab559568fbe430bbf91a2446124f50f Mon Sep 17 00:00:00 2001 From: Tomasz Slabon Date: Thu, 13 Jul 2023 13:00:17 +0200 Subject: [PATCH] Added additional system test scenario --- system-tests/test/deposit-redemption.test.ts | 276 ++++++++++++++++++- 1 file changed, 275 insertions(+), 1 deletion(-) diff --git a/system-tests/test/deposit-redemption.test.ts b/system-tests/test/deposit-redemption.test.ts index f72a13894..f2e5310e0 100644 --- a/system-tests/test/deposit-redemption.test.ts +++ b/system-tests/test/deposit-redemption.test.ts @@ -47,6 +47,7 @@ describe("System Test - Deposit and redemption", () => { let systemTestsContext: SystemTestsContext let electrumClient: ElectrumClient let bridgeAddress: string + let vaultAddress: string let maintainerBridgeHandle: EthereumBridge let depositorBridgeHandle: EthereumBridge let bank: Contract @@ -77,6 +78,7 @@ describe("System Test - Deposit and redemption", () => { ) bridgeAddress = deployedContracts.Bridge.address + vaultAddress = deployedContracts.TBTCVault.address maintainerBridgeHandle = new EthereumBridge({ address: bridgeAddress, @@ -103,7 +105,7 @@ describe("System Test - Deposit and redemption", () => { ) }) - context("when deposit is made and revealed", () => { + context("when deposit is made and revealed without a vault", () => { before("make and reveal deposit", async () => { deposit = generateDeposit( systemTestsContext.depositor.address, @@ -372,4 +374,276 @@ describe("System Test - Deposit and redemption", () => { }) }) }) + + context("when deposit is made and revealed with a vault", () => { + before("make and reveal deposit", async () => { + deposit = generateDeposit( + systemTestsContext.depositor.address, + depositAmount, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + vaultAddress, + ) + + console.log(` + Generated deposit data: + ${JSON.stringify(deposit)} + `) + ;({ depositUtxo } = await submitDepositTransaction( + deposit, + systemTestsContext.depositorBitcoinKeyPair.wif, + electrumClient, + true + )) + + console.log(` + Deposit made on BTC chain: + - Transaction hash: ${depositUtxo.transactionHash} + - Output index: ${depositUtxo.outputIndex} + `) + + // Since the reveal deposit logic does not perform SPV proof, we + // can reveal the deposit transaction immediately without waiting + // for confirmations. + await TBTC.revealDeposit( + depositUtxo, + deposit, + electrumClient, + depositorBridgeHandle, + deposit.vault, + ) + + console.log(` + Deposit revealed on Ethereum chain + `) + }) + + it("should broadcast the deposit transaction on the Bitcoin network", async () => { + expect( + (await electrumClient.getRawTransaction(depositUtxo.transactionHash)) + .transactionHex.length + ).to.be.greaterThan(0) + }) + + it("should reveal the deposit to the bridge", async () => { + const { revealedAt } = await TBTC.getRevealedDeposit( + depositUtxo, + maintainerBridgeHandle + ) + expect(revealedAt).to.be.greaterThan(0) + }) + + context("when deposit is swept and sweep proof submitted", () => { + before("sweep the deposit and submit sweep proof", async () => { + ;({ newMainUtxo: sweepUtxo } = await submitDepositSweepTransaction( + electrumClient, + depositSweepTxFee, + systemTestsContext.walletBitcoinKeyPair.wif, + true, + [depositUtxo], + [deposit] + )) + + console.log(` + Deposit swept on Bitcoin chain: + - Transaction hash: ${sweepUtxo.transactionHash} + `) + + // Unlike in the deposit transaction case, we must wait for the sweep + // transaction to have an enough number of confirmations. This is + // because the bridge performs the SPV proof of that transaction. + await waitTransactionConfirmed( + electrumClient, + sweepUtxo.transactionHash + ) + + await fakeRelayDifficulty( + relay, + electrumClient, + sweepUtxo.transactionHash + ) + + // TODO: Consider fetching the current wallet main UTXO and passing it + // here. This will allow running this test scenario multiple + // times for the same wallet. + await SpvMaintainer.submitDepositSweepProof( + sweepUtxo.transactionHash, + // This is the first sweep of the given wallet so there is no main UTXO. + { + // The function expects an unprefixed hash. + transactionHash: BitcoinTransactionHash.from(constants.HashZero), + outputIndex: 0, + value: BigNumber.from(0), + }, + maintainerBridgeHandle, + electrumClient + ) + + console.log(` + Deposit sweep proved on the bridge + `) + }) + + it("should broadcast the sweep transaction on the Bitcoin network", async () => { + expect( + (await electrumClient.getRawTransaction(sweepUtxo.transactionHash)) + .transactionHex.length + ).to.be.greaterThan(0) + }) + + it("should sweep the deposit on the bridge", async () => { + const { sweptAt } = await TBTC.getRevealedDeposit( + depositUtxo, + maintainerBridgeHandle + ) + expect(sweptAt).to.be.greaterThan(0) + }) + + it("should increase depositor's balance in the bank", async () => { + const { treasuryFee } = await TBTC.getRevealedDeposit( + depositUtxo, + maintainerBridgeHandle + ) + + const expectedBalance = depositAmount + .sub(treasuryFee) + .sub(depositSweepTxFee) + + const actualBalance = await bank.balanceOf( + systemTestsContext.depositor.address + ) + + expect(actualBalance).to.be.equal(expectedBalance) + }) + + context("when redemption is requested", () => { + let requestedAmount: BigNumber + let redeemerOutputScript: string + let redemptionRequest: RedemptionRequest + + before("request the redemption", async () => { + // Redeem the full depositor's balance. + requestedAmount = await bank.balanceOf( + systemTestsContext.depositor.address + ) + + // Allow the bridge to take the redeemed bank balance. + await bank + .connect(systemTestsContext.depositor) + .approveBalance(bridgeAddress, requestedAmount) + + // Request redemption to depositor's address. + redeemerOutputScript = `0014${computeHash160( + systemTestsContext.depositorBitcoinKeyPair.publicKey.compressed + )}` + + await depositorBridgeHandle.requestRedemption( + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + sweepUtxo, + redeemerOutputScript, + requestedAmount, + ) + + console.log( + `Requested redemption of amount ${requestedAmount} to script ${redeemerOutputScript} on the bridge` + ) + + redemptionRequest = await TBTC.getRedemptionRequest( + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + redeemerOutputScript, + "pending", + maintainerBridgeHandle + ) + }) + + it("should transfer depositor's bank balance to the Bridge", async () => { + expect( + await bank.balanceOf(systemTestsContext.depositor.address) + ).to.be.equal(0) + + expect(await bank.balanceOf(bridgeAddress)).to.be.equal( + requestedAmount + ) + }) + + it("should register the redemption request on the bridge", async () => { + expect(redemptionRequest.requestedAt).to.be.greaterThan(0) + expect(redemptionRequest.requestedAmount).to.be.equal(requestedAmount) + expect(redemptionRequest.redeemerOutputScript).to.be.equal( + redeemerOutputScript + ) + }) + + context( + "when redemption is made and redemption proof submitted", + () => { + let redemptionTxHash: BitcoinTransactionHash + + before( + "make the redemption and submit redemption proof", + async () => { + ;({ transactionHash: redemptionTxHash } = + await submitRedemptionTransaction( + electrumClient, + maintainerBridgeHandle, + systemTestsContext.walletBitcoinKeyPair.wif, + sweepUtxo, + [redemptionRequest.redeemerOutputScript], + true + )) + + console.log( + "Redemption made on Bitcoin chain:\n" + + `- Transaction hash: ${redemptionTxHash}` + ) + + await waitTransactionConfirmed(electrumClient, redemptionTxHash) + + await fakeRelayDifficulty( + relay, + electrumClient, + redemptionTxHash + ) + + await SpvMaintainer.submitRedemptionProof( + redemptionTxHash, + sweepUtxo, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + maintainerBridgeHandle, + electrumClient + ) + + console.log("Redemption proved on the bridge") + } + ) + + it("should broadcast the redemption transaction on the Bitcoin network", async () => { + expect( + (await electrumClient.getRawTransaction(redemptionTxHash)) + .transactionHex.length + ).to.be.greaterThan(0) + }) + + it("should close the redemption request on the bridge", async () => { + await expect( + TBTC.getRedemptionRequest( + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + redemptionRequest.redeemerOutputScript, + "pending", + maintainerBridgeHandle + ) + ).to.be.rejectedWith( + "Provided redeemer output script and wallet public key do not identify a redemption request" + ) + }) + + it("should decrease Bridge's balance in the bank", async () => { + const actualBalance = await bank.balanceOf(bridgeAddress) + + expect(actualBalance).to.be.equal(0) + }) + } + ) + }) + }) + }) })