diff --git a/system-tests/test/deposit-redemption.test.ts b/system-tests/test/deposit-redemption.test.ts index a50903c8c..df3f63075 100644 --- a/system-tests/test/deposit-redemption.test.ts +++ b/system-tests/test/deposit-redemption.test.ts @@ -12,48 +12,43 @@ import { BitcoinAddressConverter, WalletTx, EthereumWalletRegistry, - MaintenanceService, BitcoinHashUtils, EthereumAddress, + TBTC, } from "@keep-network/tbtc-v2.ts" import { BigNumber, constants, Contract } from "ethers" import chai, { expect } from "chai" import chaiAsPromised from "chai-as-promised" import { setupSystemTestsContext } from "./utils/context" -import { createDepositReceipt, printDepositReceipt } from "./utils/deposit" import { fakeRelayDifficulty, waitTransactionConfirmed } from "./utils/bitcoin" import type { RedemptionRequest, BitcoinUtxo, - DepositReceipt, TBTCContracts, + DepositReceipt, } from "@keep-network/tbtc-v2.ts" import type { SystemTestsContext } from "./utils/context" chai.use(chaiAsPromised) describe("System Test - Deposit and redemption", () => { - let systemTestsContext: SystemTestsContext - let electrumClient: ElectrumClient let tbtcTokenAddress: string let bridgeAddress: string let vaultAddress: string let walletRegistryAddress: string - let tbtcTokenHandle: EthereumTBTCToken - let vaultHandle: EthereumTBTCVault - let maintainerBridgeHandle: EthereumBridge - let depositorBridgeHandle: EthereumBridge - let walletRegistryHandle: EthereumWalletRegistry - - let walletTx: WalletTx - let maintenanceService: MaintenanceService let bank: Contract let relay: Contract let tbtc: Contract + let electrumClient: ElectrumClient + let systemTestsContext: SystemTestsContext + let depositorTbtc: TBTC + let maintainerTbtc: TBTC + let walletTx: WalletTx + const depositAmount = BigNumber.from(2000000) const depositSweepTxFee = BigNumber.from(10000) const depositTxFee = BigNumber.from(1500) @@ -70,11 +65,34 @@ describe("System Test - Deposit and redemption", () => { let sweepUtxo: BitcoinUtxo let redemptionUtxo: BitcoinUtxo | undefined + let depositorBitcoinAddress: string + before(async () => { systemTestsContext = await setupSystemTestsContext() const { electrumUrl, maintainer, depositor, deployedContracts } = systemTestsContext + const relayDeploymentInfo = deployedContracts.LightRelay + relay = new Contract( + relayDeploymentInfo.address, + relayDeploymentInfo.abi, + maintainer + ) + + const bankDeploymentInfo = deployedContracts.Bank + bank = new Contract( + bankDeploymentInfo.address, + bankDeploymentInfo.abi, + maintainer + ) + + const tbtcDeploymentInfo = deployedContracts.TBTC + tbtc = new Contract( + tbtcDeploymentInfo.address, + tbtcDeploymentInfo.abi, + maintainer + ) + electrumClient = ElectrumClient.fromUrl( electrumUrl, undefined, @@ -87,60 +105,59 @@ describe("System Test - Deposit and redemption", () => { vaultAddress = deployedContracts.TBTCVault.address walletRegistryAddress = deployedContracts.WalletRegistry.address - tbtcTokenHandle = new EthereumTBTCToken({ - address: tbtcTokenAddress, - signerOrProvider: depositor, - }) - - vaultHandle = new EthereumTBTCVault({ - address: vaultAddress, - signerOrProvider: depositor, - }) - - maintainerBridgeHandle = new EthereumBridge({ - address: bridgeAddress, - signerOrProvider: maintainer, - }) - - depositorBridgeHandle = new EthereumBridge({ - address: bridgeAddress, - signerOrProvider: depositor, - }) + const depositorTbtcContracts: TBTCContracts = { + bridge: new EthereumBridge({ + address: bridgeAddress, + signerOrProvider: depositor, + }), + tbtcToken: new EthereumTBTCToken({ + address: tbtcTokenAddress, + signerOrProvider: depositor, + }), + tbtcVault: new EthereumTBTCVault({ + address: vaultAddress, + signerOrProvider: depositor, + }), + walletRegistry: new EthereumWalletRegistry({ + address: walletRegistryAddress, + signerOrProvider: depositor, + }), + } - walletRegistryHandle = new EthereumWalletRegistry({ - address: walletRegistryAddress, - signerOrProvider: depositor, - }) + depositorTbtc = await TBTC.initializeCustom( + depositorTbtcContracts, + electrumClient + ) - const tbtcContracts: TBTCContracts = { - bridge: maintainerBridgeHandle, - tbtcToken: tbtcTokenHandle, - tbtcVault: vaultHandle, - walletRegistry: walletRegistryHandle, + const maintainerTbtcContracts: TBTCContracts = { + bridge: new EthereumBridge({ + address: bridgeAddress, + signerOrProvider: maintainer, + }), + tbtcToken: new EthereumTBTCToken({ + address: tbtcTokenAddress, + signerOrProvider: maintainer, + }), + tbtcVault: new EthereumTBTCVault({ + address: vaultAddress, + signerOrProvider: maintainer, + }), + walletRegistry: new EthereumWalletRegistry({ + address: walletRegistryAddress, + signerOrProvider: maintainer, + }), } - walletTx = new WalletTx(tbtcContracts, electrumClient) - maintenanceService = new MaintenanceService(tbtcContracts, electrumClient) - - const bankDeploymentInfo = deployedContracts.Bank - bank = new Contract( - bankDeploymentInfo.address, - bankDeploymentInfo.abi, - maintainer + maintainerTbtc = await TBTC.initializeCustom( + maintainerTbtcContracts, + electrumClient ) - const relayDeploymentInfo = deployedContracts.LightRelay - relay = new Contract( - relayDeploymentInfo.address, - relayDeploymentInfo.abi, - maintainer - ) + walletTx = new WalletTx(maintainerTbtcContracts, electrumClient) - const tbtcDeploymentInfo = deployedContracts.TBTC - tbtc = new Contract( - tbtcDeploymentInfo.address, - tbtcDeploymentInfo.abi, - maintainer + depositorBitcoinAddress = BitcoinAddressConverter.publicKeyToAddress( + systemTestsContext.depositorBitcoinKeyPair.publicKey.compressed, + BitcoinNetwork.Testnet ) }) @@ -165,28 +182,28 @@ describe("System Test - Deposit and redemption", () => { * the bridge */ before("make and reveal deposit", async () => { - depositReceipt = createDepositReceipt( - systemTestsContext.depositor.address, - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed + const deposit = await depositorTbtc.deposits.initiateDeposit( + // Use the depositor's address as the recovery address. + depositorBitcoinAddress ) + depositReceipt = deposit.getReceipt() + const depositScript = DepositScript.fromReceipt(depositReceipt) + const depositFunding = DepositFunding.fromScript(depositScript) - printDepositReceipt(depositReceipt) - - const depositorBitcoinAddress = - BitcoinAddressConverter.publicKeyToAddress( - systemTestsContext.depositorBitcoinKeyPair.publicKey.compressed, - BitcoinNetwork.Testnet - ) + console.log(` + Deposit receipt generated: + - depositor: ${depositReceipt.depositor.identifierHex} + - walletPublicKeyHash: ${depositReceipt.walletPublicKeyHash} + - refundPublicKeyHash: ${depositReceipt.refundPublicKeyHash} + - blindingFactor: ${depositReceipt.blindingFactor} + - refundLocktime: ${depositReceipt.refundLocktime} + `) const depositorUtxos = await electrumClient.findAllUnspentTransactionOutputs( depositorBitcoinAddress ) - const depositFunding = DepositFunding.fromScript( - DepositScript.fromReceipt(depositReceipt, true) - ) - ;({ depositUtxo } = await depositFunding.submitTransaction( depositAmount, depositorUtxos, @@ -210,7 +227,9 @@ describe("System Test - Deposit and redemption", () => { const depositRawTxVectors = extractBitcoinRawTxVectors( rawDepositTransaction ) - await depositorBridgeHandle.revealDeposit( + + // Reveal without providing the vault address. + await depositorTbtc.tbtcContracts.bridge.revealDeposit( depositRawTxVectors, depositUtxo.outputIndex, depositReceipt @@ -229,7 +248,7 @@ describe("System Test - Deposit and redemption", () => { }) it("should reveal the deposit to the bridge", async () => { - const { revealedAt } = await maintainerBridgeHandle.deposits( + const { revealedAt } = await maintainerTbtc.tbtcContracts.bridge.deposits( depositUtxo.transactionHash, depositUtxo.outputIndex ) @@ -268,7 +287,7 @@ describe("System Test - Deposit and redemption", () => { // 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 maintenanceService.spv.submitDepositSweepProof( + await maintainerTbtc.maintenance.spv.submitDepositSweepProof( sweepUtxo.transactionHash, // This is the first sweep of the given wallet so there is no main UTXO. { @@ -292,7 +311,7 @@ describe("System Test - Deposit and redemption", () => { }) it("should sweep the deposit on the bridge", async () => { - const { sweptAt } = await maintainerBridgeHandle.deposits( + const { sweptAt } = await maintainerTbtc.tbtcContracts.bridge.deposits( depositUtxo.transactionHash, depositUtxo.outputIndex ) @@ -300,10 +319,11 @@ describe("System Test - Deposit and redemption", () => { }) it("should increase depositor's balance in the bank", async () => { - const { treasuryFee } = await maintainerBridgeHandle.deposits( - depositUtxo.transactionHash, - depositUtxo.outputIndex - ) + const { treasuryFee } = + await maintainerTbtc.tbtcContracts.bridge.deposits( + depositUtxo.transactionHash, + depositUtxo.outputIndex + ) const expectedBalance = depositAmount .sub(treasuryFee) @@ -339,10 +359,9 @@ describe("System Test - Deposit and redemption", () => { )}` ) - await depositorBridgeHandle.requestRedemption( - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, - sweepUtxo, - redeemerOutputScript, + await depositorTbtc.redemptions.requestRedemption( + // Use the depositor's address as the redeemer's address. + depositorBitcoinAddress, requestedAmount ) @@ -350,10 +369,12 @@ describe("System Test - Deposit and redemption", () => { `Requested redemption of amount ${requestedAmount} to script ${redeemerOutputScript} on the bridge` ) - redemptionRequest = await maintainerBridgeHandle.pendingRedemptions( - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, - redeemerOutputScript - ) + redemptionRequest = + await maintainerTbtc.redemptions.getRedemptionRequests( + depositorBitcoinAddress, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + "pending" + ) }) it("should transfer depositor's bank balance to the Bridge", async () => { @@ -404,7 +425,7 @@ describe("System Test - Deposit and redemption", () => { redemptionTxHash ) - await maintenanceService.spv.submitRedemptionProof( + await maintainerTbtc.maintenance.spv.submitRedemptionProof( redemptionTxHash, sweepUtxo, systemTestsContext.walletBitcoinKeyPair.publicKey.compressed @@ -422,10 +443,12 @@ describe("System Test - Deposit and redemption", () => { }) it("should close the redemption request on the bridge", async () => { - const request = await maintainerBridgeHandle.pendingRedemptions( - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, - redemptionRequest.redeemerOutputScript - ) + const request = + await maintainerTbtc.redemptions.getRedemptionRequests( + depositorBitcoinAddress, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + "pending" + ) expect(request.requestedAt).to.be.equal(0) }) @@ -461,28 +484,28 @@ describe("System Test - Deposit and redemption", () => { * be registered in the bridge */ before("make and reveal deposit", async () => { - depositReceipt = createDepositReceipt( - systemTestsContext.depositor.address, - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed + const deposit = await depositorTbtc.deposits.initiateDeposit( + // Use the depositor's address as the recovery address. + depositorBitcoinAddress ) + depositReceipt = deposit.getReceipt() + const depositScript = DepositScript.fromReceipt(depositReceipt) + const depositFunding = DepositFunding.fromScript(depositScript) - printDepositReceipt(depositReceipt) - - const depositorBitcoinAddress = - BitcoinAddressConverter.publicKeyToAddress( - systemTestsContext.depositorBitcoinKeyPair.publicKey.compressed, - BitcoinNetwork.Testnet - ) + console.log(` + Deposit receipt generated: + - depositor: ${depositReceipt.depositor.identifierHex} + - walletPublicKeyHash: ${depositReceipt.walletPublicKeyHash} + - refundPublicKeyHash: ${depositReceipt.refundPublicKeyHash} + - blindingFactor: ${depositReceipt.blindingFactor} + - refundLocktime: ${depositReceipt.refundLocktime} + `) const depositorUtxos = await electrumClient.findAllUnspentTransactionOutputs( depositorBitcoinAddress ) - const depositFunding = DepositFunding.fromScript( - DepositScript.fromReceipt(depositReceipt, true) - ) - ;({ depositUtxo } = await depositFunding.submitTransaction( depositAmount, depositorUtxos, @@ -497,21 +520,7 @@ describe("System Test - Deposit and redemption", () => { - 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. - const rawDepositTransaction = await electrumClient.getRawTransaction( - depositUtxo.transactionHash - ) - const depositRawTxVectors = extractBitcoinRawTxVectors( - rawDepositTransaction - ) - await depositorBridgeHandle.revealDeposit( - depositRawTxVectors, - depositUtxo.outputIndex, - depositReceipt, - EthereumAddress.from(vaultAddress) - ) + await deposit.initiateMinting() console.log(` Deposit revealed on Ethereum chain @@ -526,7 +535,7 @@ describe("System Test - Deposit and redemption", () => { }) it("should reveal the deposit to the bridge", async () => { - const { revealedAt } = await maintainerBridgeHandle.deposits( + const { revealedAt } = await maintainerTbtc.tbtcContracts.bridge.deposits( depositUtxo.transactionHash, depositUtxo.outputIndex ) @@ -570,7 +579,7 @@ describe("System Test - Deposit and redemption", () => { outputIndex: 0, value: BigNumber.from(0), } - await maintenanceService.spv.submitDepositSweepProof( + await maintainerTbtc.maintenance.spv.submitDepositSweepProof( sweepUtxo.transactionHash, mainUtxo, EthereumAddress.from(vaultAddress) @@ -589,7 +598,7 @@ describe("System Test - Deposit and redemption", () => { }) it("should sweep the deposit on the bridge", async () => { - const { sweptAt } = await maintainerBridgeHandle.deposits( + const { sweptAt } = await maintainerTbtc.tbtcContracts.bridge.deposits( depositUtxo.transactionHash, depositUtxo.outputIndex ) @@ -597,10 +606,11 @@ describe("System Test - Deposit and redemption", () => { }) it("should increase vault's balance in the bank", async () => { - const { treasuryFee } = await maintainerBridgeHandle.deposits( - depositUtxo.transactionHash, - depositUtxo.outputIndex - ) + const { treasuryFee } = + await maintainerTbtc.tbtcContracts.bridge.deposits( + depositUtxo.transactionHash, + depositUtxo.outputIndex + ) const expectedBalance = depositAmount .sub(treasuryFee) @@ -612,10 +622,11 @@ describe("System Test - Deposit and redemption", () => { }) it("should mint TBTC tokens for the depositor", async () => { - const { treasuryFee } = await maintainerBridgeHandle.deposits( - depositUtxo.transactionHash, - depositUtxo.outputIndex - ) + const { treasuryFee } = + await maintainerTbtc.tbtcContracts.bridge.deposits( + depositUtxo.transactionHash, + depositUtxo.outputIndex + ) const balanceInSatoshis = depositAmount .sub(treasuryFee) @@ -651,7 +662,7 @@ describe("System Test - Deposit and redemption", () => { )}` ) - await tbtcTokenHandle.requestRedemption( + depositorTbtc.tbtcContracts.tbtcToken.requestRedemption( systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, sweepUtxo, redeemerOutputScript, @@ -662,10 +673,12 @@ describe("System Test - Deposit and redemption", () => { `Requested redemption of ${tbtcBalanceOfDepositor} TBTC tokens to script ${redeemerOutputScript} on the bridge` ) - redemptionRequest = await maintainerBridgeHandle.pendingRedemptions( - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, - redeemerOutputScript - ) + redemptionRequest = + await maintainerTbtc.redemptions.getRedemptionRequests( + depositorBitcoinAddress, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + "pending" + ) }) it("should unmint depositor's TBTC tokens", async () => { @@ -722,7 +735,7 @@ describe("System Test - Deposit and redemption", () => { redemptionTxHash ) - await maintenanceService.spv.submitRedemptionProof( + await maintainerTbtc.maintenance.spv.submitRedemptionProof( redemptionTxHash, sweepUtxo, systemTestsContext.walletBitcoinKeyPair.publicKey.compressed @@ -740,10 +753,12 @@ describe("System Test - Deposit and redemption", () => { }) it("should close the redemption request on the bridge", async () => { - const request = await maintainerBridgeHandle.pendingRedemptions( - systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, - redemptionRequest.redeemerOutputScript - ) + const request = + await maintainerTbtc.redemptions.getRedemptionRequests( + depositorBitcoinAddress, + systemTestsContext.walletBitcoinKeyPair.publicKey.compressed, + "pending" + ) expect(request.requestedAt).to.be.equal(0) }) diff --git a/system-tests/test/utils/deposit.ts b/system-tests/test/utils/deposit.ts deleted file mode 100644 index 10a8fac15..000000000 --- a/system-tests/test/utils/deposit.ts +++ /dev/null @@ -1,70 +0,0 @@ -import crypto from "crypto" - -import { - BitcoinLocktimeUtils, - BitcoinHashUtils, - EthereumAddress, - Hex, -} from "@keep-network/tbtc-v2.ts" - -import type { DepositReceipt } from "@keep-network/tbtc-v2.ts" - -/** - * Default refund public key used for deposits. Their corresponding private key: - * 7c246a5d2fcf476fd6f805cb8174b1cf441b13ea414e5560ca2bdc963aeb7d0c - */ -export const DEFAULT_REFUND_PUBLIC_KEY = Hex.from( - "03989d253b17a6a0f41838b84ff0d20e8898f9d7b1a98f2564da4cc29dcf8581d9" -) - -/** - * Creates a deposit receipt based on the given parameters. - * @param depositorAddress Ethereum address of the depositor. - * @param walletPublicKey Compressed ECDSA public key of the target wallet. - * @param refundPublicKey Compressed ECDSA public key that can be used for - * refund. Optional parameter, default value is used if not set - * @see {DEFAULT_REFUND_PUBLIC_KEY}. - * @returns Deposit receipt. - */ -export function createDepositReceipt( - depositorAddress: string, - walletPublicKey: Hex, - refundPublicKey?: Hex -): DepositReceipt { - const walletPublicKeyHash = BitcoinHashUtils.computeHash160(walletPublicKey) - - const resolvedRefundPublicKey = refundPublicKey || DEFAULT_REFUND_PUBLIC_KEY - const refundPublicKeyHash = BitcoinHashUtils.computeHash160( - resolvedRefundPublicKey - ) - - const blindingFactor = Hex.from(crypto.randomBytes(8).toString("hex")) - - const refundLocktime = BitcoinLocktimeUtils.calculateLocktime( - Math.floor(Date.now() / 1000), - 2592000 // 30 days - ) - return { - depositor: EthereumAddress.from(depositorAddress), - walletPublicKeyHash, - refundPublicKeyHash, - blindingFactor, - refundLocktime, - } -} - -/** - * Prints a formatted deposit receipt to the console. - * @param receipt Deposit receipt object containing information to be printed. - * @returns {void} This function does not return any value. - */ -export function printDepositReceipt(receipt: DepositReceipt): void { - console.log(` - Deposit receipt: - - depositor: ${receipt.depositor.identifierHex} - - walletPublicKeyHash: ${receipt.walletPublicKeyHash} - - refundPublicKeyHash: ${receipt.refundPublicKeyHash} - - blindingFactor: ${receipt.blindingFactor} - - refundLocktime: ${receipt.refundLocktime} - `) -}