From a7cd3ffc2b6e3b88db12d0471ebda11143583747 Mon Sep 17 00:00:00 2001 From: jeremy-then Date: Tue, 17 Sep 2024 11:04:30 -0400 Subject: [PATCH] Adds new 2wp file starting with one pegin test checking events, etc. --- lib/2wp-utils.js | 30 +++- lib/assertions/2wp.js | 13 +- lib/constants.js | 10 +- lib/tests/2wp-legacy.js | 234 ++++++++++++++++++++++++++ lib/tests/2wp.js | 233 +++++-------------------- tests/01_01_01-2wp.js | 3 + tests/01_01_01-pre_orchid_2wp.js | 3 - tests/02_00_01-2wp.js | 2 +- tests/04_00_04-2wp_after_fedchange.js | 2 +- 9 files changed, 335 insertions(+), 195 deletions(-) create mode 100644 lib/tests/2wp-legacy.js create mode 100644 tests/01_01_01-2wp.js delete mode 100644 tests/01_01_01-pre_orchid_2wp.js diff --git a/lib/2wp-utils.js b/lib/2wp-utils.js index 9a915188..70b108e2 100644 --- a/lib/2wp-utils.js +++ b/lib/2wp-utils.js @@ -7,10 +7,11 @@ const { waitForRskMempoolToGetNewTxs, waitAndUpdateBridge } = require('./rsk-utils'); -const { retryWithCheck } = require('./utils'); +const { retryWithCheck, ensure0x } = require('./utils'); const { waitForBitcoinTxToBeInMempool, waitForBitcoinMempoolToGetTxs } = require('./btc-utils'); const { getBridge } = require('./precompiled-abi-forks-util'); const { getBridgeState } = require('@rsksmart/bridge-state-data-parser'); +const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivation'); const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter'); const peginVerifier = require('pegin-address-verificator'); @@ -227,6 +228,31 @@ const disableWhitelisting = async (rskTxHelper, btcTxHelper, blockDelay = 1) => } }; +const createSenderRecipientInfo = async (rskTxHelper, btcTxHelper, type = 'legacy', initialAmountToFundInBtc = 1) => { + const btcSenderAddressInfo = await btcTxHelper.generateBtcAddress(type); + const rskRecipientRskAddressInfo = getDerivedRSKAddressInformation(btcSenderAddressInfo.privateKey, btcTxHelper.btcConfig.network); + await rskTxHelper.importAccount(rskRecipientRskAddressInfo.privateKey); + await rskTxHelper.unlockAccount(rskRecipientRskAddressInfo.address); + initialAmountToFundInBtc && await btcTxHelper.fundAddress(btcSenderAddressInfo.address, initialAmountToFundInBtc); + return { + btcSenderAddressInfo, + rskRecipientRskAddressInfo + }; +}; + +const createExpectedPeginBtcEvent = (partialExpectedEvent, rskRecipientRskAddress, btcPeginTxHash, peginValueInBtc, protocolVersion = '0') => { + const expectedEvent = { + ...partialExpectedEvent, + arguments: { + receiver: ensure0x(rskRecipientRskAddress), + btcTxHash: ensure0x(btcPeginTxHash), + amount: `${btcEthUnitConverter.btcToSatoshis(peginValueInBtc)}`, + protocolVersion, + }, + } + return expectedEvent; +}; + module.exports = { sendTxToBridge, assertRefundUtxosSameAsPeginUtxos, @@ -240,4 +266,6 @@ module.exports = { mineForPeginRegistration, MIN_PEGOUT_VALUE_IN_RBTC, disableWhitelisting, + createSenderRecipientInfo, + createExpectedPeginBtcEvent, }; diff --git a/lib/assertions/2wp.js b/lib/assertions/2wp.js index f6fa6be7..6782cd10 100644 --- a/lib/assertions/2wp.js +++ b/lib/assertions/2wp.js @@ -2,6 +2,9 @@ const expect = require('chai').expect; var {wait, removePrefix0x} = require('../utils'); var bitcoin = require('peglib').bitcoin; var rsk = require('peglib').rsk; +const rskUtils = require('../rsk-utils'); +const CustomError = require('../CustomError'); + const {MAX_ESTIMATED_FEE_PER_PEGOUT, FEE_DIFFERENCE_PER_PEGOUT} = require('../constants'); const {encodeOutpointValuesAsMap, decodeOutpointValues} = require("../varint"); @@ -134,11 +137,19 @@ const assertRejectedPeginEvent = (rejectedPeginTx, expectedRejectionReason, expe expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true; } +const findAndCheckPeginBtcEventAtBlock = async (rskTxHelper, atBlock, expectedEvent) => { + const peginBtcEvent = await rskUtils.findEventInBlock(rskTxHelper, expectedEvent.name, atBlock); + expect(peginBtcEvent).to.exist; + peginBtcEvent.arguments.receiver = peginBtcEvent.arguments.receiver.toLowerCase(); + expect(peginBtcEvent).to.be.deep.equal(expectedEvent); +}; + module.exports = { with: (btcClient, rskClient, pegClient) => ({ assertBitcoinBalance: assertBitcoinBalance(btcClient, rskClient, pegClient), assertLock: assertLock(btcClient, rskClient, pegClient), }), assertCallToPegoutBatchingBridgeMethods, - assertRejectedPeginEvent + assertRejectedPeginEvent, + findAndCheckPeginBtcEventAtBlock, }; diff --git a/lib/constants.js b/lib/constants.js index 193f6fd5..32ab0936 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -55,7 +55,14 @@ const PEGOUT_EVENTS = { BATCH_PEGOUT_CREATED: "batch_pegout_created", PEGOUT_TRANSACTION_CREATED: "pegout_transaction_created", PEGOUT_CONFIRMED: "pegout_confirmed" -} +}; + +const PEGIN_EVENTS = { + PEGIN_BTC: { + name: "pegin_btc", + signature: '0x44cdc782a38244afd68336ab92a0b39f864d6c0b2a50fa1da58cafc93cd2ae5a' + } +}; module.exports = { KEY_TYPE_BTC, @@ -77,4 +84,5 @@ module.exports = { PEGOUT_EVENTS, FUNDS_MIGRATION_AGE_SINCE_ACTIVATION_BEGIN, FUNDS_MIGRATION_AGE_SINCE_ACTIVATION_END, + PEGIN_EVENTS, }; diff --git a/lib/tests/2wp-legacy.js b/lib/tests/2wp-legacy.js new file mode 100644 index 00000000..50333f87 --- /dev/null +++ b/lib/tests/2wp-legacy.js @@ -0,0 +1,234 @@ +const expect = require('chai').expect +const { ensure0x, removePrefix0x} = require('../utils'); +const whitelistingAssertions = require('../assertions/whitelisting'); +const rskUtils = require('../rsk-utils'); +const CustomError = require('../CustomError'); +const { getBridge } = require('../precompiled-abi-forks-util'); +const { getBtcClient } = require('../btc-client-provider'); +const { getRskTransactionHelpers, getRskTransactionHelper } = require('../rsk-tx-helper-provider'); +const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivation'); +const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter'); +const { sendTxToBridge, sendPegin, ensurePeginIsRegistered, donateToBridge } = require('../2wp-utils'); +const { waitAndUpdateBridge } = require('../rsk-utils'); +const { decodeOutpointValues, encodeOutpointValuesAsMap } = require("../varint"); +const {getBridgeState} = require("@rsksmart/bridge-state-data-parser"); +const {PEGOUT_EVENTS} = require("../constants"); + +const DONATION_AMOUNT = 250; +const REJECTED_REASON = 1; + +let btcTxHelper; +let rskTxHelper; +let rskTxHelpers; +let federationAddress; +let minimumPeginValueInBtc; + +const assertPegoutTransactionCreatedEventIsEmitted = async (localRskTxHelper, activeFederationUtxosBeforePegout) => { + const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_TRANSACTION_CREATED); + expect(pegoutTransactionCreatedEvent).to.not.be.null; + const encodedUtxoOutpointValues = Buffer.from(removePrefix0x(pegoutTransactionCreatedEvent.arguments.utxoOutpointValues), 'hex'); + + const federationUtxoValues = encodeOutpointValuesAsMap(activeFederationUtxosBeforePegout); + + const outpointValues = decodeOutpointValues(encodedUtxoOutpointValues); + + expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true; +} + +const execute = (description, getRskHost) => { + + describe(description, () => { + before(async () => { + btcTxHelper = getBtcClient(); + rskTxHelper = getRskTransactionHelper(getRskHost()); + + // Grab the federation address + const bridge = getBridge(rskTxHelper.getClient()); + federationAddress = await bridge.methods.getFederationAddress().call(); + + const minimumPeginValueInSatoshis = await bridge.methods.getMinimumLockTxValue().call(); + minimumPeginValueInBtc = Number(btcEthUnitConverter.satoshisToBtc(minimumPeginValueInSatoshis)); + + await btcTxHelper.importAddress(federationAddress, 'federations'); + + rskTxHelpers = getRskTransactionHelpers(); + + // Update the bridge to sync btc blockchains + await waitAndUpdateBridge(rskTxHelper); + + // At the moment there are a lot of pegout tests that depend on the bridge to have enough balance. + // Those tests are not doing a pegin if needed, so we need to donate to the bridge to ensure it has enough balance. + // This will be removed after all pegout tests are updated to do their own pegin if needed. + const donatingBtcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); + await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, donatingBtcAddressInformation.address, Number(btcEthUnitConverter.btcToSatoshis(DONATION_AMOUNT))); + await rskUtils.mineAndSync(rskTxHelpers); + await btcTxHelper.fundAddress(donatingBtcAddressInformation.address, DONATION_AMOUNT + btcTxHelper.getFee()); + + await donateToBridge(rskTxHelper, btcTxHelper, donatingBtcAddressInformation, DONATION_AMOUNT); + + return federationAddress; + }); + + it('should transfer BTC to RBTC', async () => { + try { + const peginSenderAddressInfo = await btcTxHelper.generateBtcAddress('legacy'); + + await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, peginSenderAddressInfo.address, Number(btcEthUnitConverter.btcToSatoshis(minimumPeginValueInBtc))); + await rskUtils.mineAndSync(rskTxHelpers); + + const recipientRskAddressInfo = getDerivedRSKAddressInformation(peginSenderAddressInfo.privateKey, btcTxHelper.btcConfig.network); + const initialRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + + await btcTxHelper.fundAddress(peginSenderAddressInfo.address, minimumPeginValueInBtc + btcTxHelper.getFee()); + + const peginBtcTxHash = await sendPegin(rskTxHelper, btcTxHelper, peginSenderAddressInfo, minimumPeginValueInBtc); + await ensurePeginIsRegistered(rskTxHelper, peginBtcTxHash); + + const finalRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + + // Asserting that the received pegin amount in rsk is as expected + const peginValueInWeis = Number(btcEthUnitConverter.btcToWeis(minimumPeginValueInBtc)); + expect(finalRskAddressBalanceInWeis).to.equal(initialRskAddressBalanceInWeis + peginValueInWeis); + } catch (err) { + throw new CustomError('Transfer BTC to RBTC', err); + } + }); + + it('should transfer BTC to RBTC with 2 outputs in lock TX', async () => { + try{ + const INITIAL_BTC_BALANCE = 4; + const PEGIN_OUTPUTS_VALUES_IN_BTC = [1, 2]; + const EXPECTED_RSK_BALANCE_IN_RBTC = PEGIN_OUTPUTS_VALUES_IN_BTC.reduce((a, b) => a + b, 0); // 3 + + const peginSenderAddressInfo = await btcTxHelper.generateBtcAddress('legacy'); + + await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, peginSenderAddressInfo.address, Number(btcEthUnitConverter.btcToSatoshis(EXPECTED_RSK_BALANCE_IN_RBTC))); + await rskUtils.mineAndSync(rskTxHelpers); + await btcTxHelper.fundAddress(peginSenderAddressInfo.address, INITIAL_BTC_BALANCE + btcTxHelper.getFee()); + + const recipientRskAddressInfo = getDerivedRSKAddressInformation(peginSenderAddressInfo.privateKey, btcTxHelper.btcConfig.network); + + const initialRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + + const peginBtcTxHash = await sendPegin(rskTxHelper, btcTxHelper, peginSenderAddressInfo, PEGIN_OUTPUTS_VALUES_IN_BTC); + + await ensurePeginIsRegistered(rskTxHelper, peginBtcTxHash, PEGIN_OUTPUTS_VALUES_IN_BTC.length); + + const finalRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + + // Asserting that the received pegin amount in rsk is as expected + const peginValueInWeis = Number(btcEthUnitConverter.btcToWeis(EXPECTED_RSK_BALANCE_IN_RBTC)); + expect(finalRskAddressBalanceInWeis).to.equal(initialRskAddressBalanceInWeis + peginValueInWeis); + + } + catch (err) { + throw new CustomError('Transfer BTC to RBTC with 2 outputs in lock TX failure', err); + } + }); + + it('should transfer RBTC to BTC - Above minimum pegout value', async () => { + + const INITIAL_RSK_BALANCE = 1; + const PEGOUT_VALUE_IN_RBTC = 0.5; + const MAX_EXPECTED_FEE = 0.001; + const pegoutValueInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(PEGOUT_VALUE_IN_RBTC)); + const maxExpectedFeeInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(MAX_EXPECTED_FEE)); + + const initialFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); + + const btcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); + + const recipientRskAddressInfo = getDerivedRSKAddressInformation(btcAddressInformation.privateKey, btcTxHelper.btcConfig.network); + + await rskTxHelper.importAccount(recipientRskAddressInfo.privateKey); + const unlocked = await rskTxHelper.unlockAccount(recipientRskAddressInfo.address); + expect(unlocked, 'Account was not unlocked').to.be.true; + + await rskUtils.sendFromCow(rskTxHelper, recipientRskAddressInfo.address, Number(btcEthUnitConverter.btcToWeis(INITIAL_RSK_BALANCE))); + + const bridgeStateBeforePegout = await getBridgeState(rskTxHelper.getClient()); + const activeFederationUtxosBeforePegout = bridgeStateBeforePegout.activeFederationUtxos; + const pegoutTransaction = await sendTxToBridge(rskTxHelper, PEGOUT_VALUE_IN_RBTC, recipientRskAddressInfo.address); + + const pegoutRequestReceivedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_RECEIVED); + expect(pegoutRequestReceivedEvent).to.not.be.null; + const btcDestinationAddress = pegoutRequestReceivedEvent.arguments.btcDestinationAddress; + expect(pegoutRequestReceivedEvent.arguments.sender.toLowerCase()).to.equal(ensure0x(recipientRskAddressInfo.address)); + expect(Number(pegoutRequestReceivedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); + expect(btcAddressInformation.address).to.equal(btcDestinationAddress); + + const pegoutCreatedValidations = async (localRskTxHelper) => { + + const pegoutRequestedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.RELEASE_REQUESTED); + expect(pegoutRequestedEvent).to.not.be.null; + expect(Number(pegoutRequestedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); + + const batchPegoutCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.BATCH_PEGOUT_CREATED); + expect(batchPegoutCreatedEvent).to.not.be.null; + expect(batchPegoutCreatedEvent.arguments.releaseRskTxHashes.includes(pegoutTransaction.transactionHash)).to.be.true; + + // TODO: Uncomment this line when lovell700 is active. + // await assertPegoutTransactionCreatedEventIsEmitted(localRskTxHelper, activeFederationUtxosBeforePegout); + + }; + + const pegoutConfirmedValidations = async (localRskTxHelper) => { + const pegoutConfirmedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_CONFIRMED); + expect(pegoutConfirmedEvent).to.not.be.null; + }; + + const callbacks = { + pegoutCreatedCallback: pegoutCreatedValidations, + pegoutConfirmedCallback: pegoutConfirmedValidations, + }; + + await rskUtils.triggerRelease(rskTxHelpers, btcTxHelper, callbacks); + const finalFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); + const finalDestinationAddressBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddressInformation.address))); + const difference = pegoutValueInSatoshis - finalDestinationAddressBalanceInSatoshis; + expect(difference).to.be.at.most(maxExpectedFeeInSatoshis); + expect(finalFederationBalanceInSatoshis).to.equal(initialFederationBalanceInSatoshis - pegoutValueInSatoshis); + + }); + + it('should transfer RBTC to BTC - Below minimum pegout value', async() => { + try { + const INITIAL_RSK_BALANCE = 2; + const PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC = 0.002; + + const initialFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); + + const btcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); + const recipientRskAddressInfo = getDerivedRSKAddressInformation(btcAddressInformation.privateKey, btcTxHelper.btcConfig.network); + + await rskTxHelper.importAccount(recipientRskAddressInfo.privateKey); + await rskUtils.sendFromCow(rskTxHelper, recipientRskAddressInfo.address, Number(btcEthUnitConverter.btcToWeis(INITIAL_RSK_BALANCE))); + const initialRskAddressBalance = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + const unlocked = await rskTxHelper.unlockAccount(recipientRskAddressInfo.address); + expect(unlocked, 'Account was not unlocked').to.be.true; + + const pegoutTransaction = await sendTxToBridge(rskTxHelper, PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC, recipientRskAddressInfo.address); + + const pegoutRejectedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_REJECTED); + expect(pegoutRejectedEvent).to.not.be.null; + const pegoutValueInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC)); + expect(Number(pegoutRejectedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); + expect(pegoutRejectedEvent.arguments.sender.toLowerCase()).to.equal(ensure0x(recipientRskAddressInfo.address)); + expect(Number(pegoutRejectedEvent.arguments.reason)).to.equal(REJECTED_REASON); + const finalRskAddressBalance = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + expect(finalRskAddressBalance + pegoutTransaction.gasUsed * 2).to.equal(initialRskAddressBalance); + + const finalFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); + expect(finalFederationBalanceInSatoshis).to.equal(initialFederationBalanceInSatoshis); + } + catch (err) { + throw new CustomError('Transfer RBTC to BTC failure', err); + } + }); + + }); +} + +module.exports = { + execute, +}; diff --git a/lib/tests/2wp.js b/lib/tests/2wp.js index 50333f87..7a68d341 100644 --- a/lib/tests/2wp.js +++ b/lib/tests/2wp.js @@ -1,232 +1,91 @@ -const expect = require('chai').expect -const { ensure0x, removePrefix0x} = require('../utils'); -const whitelistingAssertions = require('../assertions/whitelisting'); -const rskUtils = require('../rsk-utils'); -const CustomError = require('../CustomError'); +const expect = require('chai').expect; const { getBridge } = require('../precompiled-abi-forks-util'); const { getBtcClient } = require('../btc-client-provider'); const { getRskTransactionHelpers, getRskTransactionHelper } = require('../rsk-tx-helper-provider'); -const { getDerivedRSKAddressInformation } = require('@rsksmart/btc-rsk-derivation'); -const btcEthUnitConverter = require('@rsksmart/btc-eth-unit-converter'); -const { sendTxToBridge, sendPegin, ensurePeginIsRegistered, donateToBridge } = require('../2wp-utils'); -const { waitAndUpdateBridge } = require('../rsk-utils'); -const { decodeOutpointValues, encodeOutpointValuesAsMap } = require("../varint"); -const {getBridgeState} = require("@rsksmart/bridge-state-data-parser"); -const {PEGOUT_EVENTS} = require("../constants"); +const { satoshisToBtc, btcToWeis } = require('@rsksmart/btc-eth-unit-converter'); +const { waitAndUpdateBridge, mineAndSync } = require('../rsk-utils'); +const { PEGIN_EVENTS } = require("../constants"); +const { findAndCheckPeginBtcEventAtBlock } = require('../assertions/2wp'); +const { sendPegin, + ensurePeginIsRegistered, + donateToBridge, + createSenderRecipientInfo, + createExpectedPeginBtcEvent +} = require('../2wp-utils'); const DONATION_AMOUNT = 250; -const REJECTED_REASON = 1; let btcTxHelper; let rskTxHelper; let rskTxHelpers; +let bridge; let federationAddress; let minimumPeginValueInBtc; -const assertPegoutTransactionCreatedEventIsEmitted = async (localRskTxHelper, activeFederationUtxosBeforePegout) => { - const pegoutTransactionCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_TRANSACTION_CREATED); - expect(pegoutTransactionCreatedEvent).to.not.be.null; - const encodedUtxoOutpointValues = Buffer.from(removePrefix0x(pegoutTransactionCreatedEvent.arguments.utxoOutpointValues), 'hex'); - - const federationUtxoValues = encodeOutpointValuesAsMap(activeFederationUtxosBeforePegout); - - const outpointValues = decodeOutpointValues(encodedUtxoOutpointValues); - - expect(outpointValues.every(value => value in federationUtxoValues)).to.be.true; -} +const setupBridgeDonation = async (rskTxHelpers, btcTxHelper) => { + const donatingBtcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); + await mineAndSync(rskTxHelpers); + await btcTxHelper.fundAddress(donatingBtcAddressInformation.address, DONATION_AMOUNT + btcTxHelper.getFee()); + await donateToBridge(rskTxHelpers[0], btcTxHelper, donatingBtcAddressInformation, DONATION_AMOUNT); +}; const execute = (description, getRskHost) => { describe(description, () => { + before(async () => { + + rskTxHelpers = getRskTransactionHelpers(); btcTxHelper = getBtcClient(); rskTxHelper = getRskTransactionHelper(getRskHost()); + bridge = getBridge(rskTxHelper.getClient()); - // Grab the federation address - const bridge = getBridge(rskTxHelper.getClient()); federationAddress = await bridge.methods.getFederationAddress().call(); - const minimumPeginValueInSatoshis = await bridge.methods.getMinimumLockTxValue().call(); - minimumPeginValueInBtc = Number(btcEthUnitConverter.satoshisToBtc(minimumPeginValueInSatoshis)); - - await btcTxHelper.importAddress(federationAddress, 'federations'); + minimumPeginValueInBtc = Number(satoshisToBtc(minimumPeginValueInSatoshis)); - rskTxHelpers = getRskTransactionHelpers(); - - // Update the bridge to sync btc blockchains + await btcTxHelper.importAddress(federationAddress, 'federation'); await waitAndUpdateBridge(rskTxHelper); + await setupBridgeDonation(rskTxHelpers, btcTxHelper); - // At the moment there are a lot of pegout tests that depend on the bridge to have enough balance. - // Those tests are not doing a pegin if needed, so we need to donate to the bridge to ensure it has enough balance. - // This will be removed after all pegout tests are updated to do their own pegin if needed. - const donatingBtcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); - await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, donatingBtcAddressInformation.address, Number(btcEthUnitConverter.btcToSatoshis(DONATION_AMOUNT))); - await rskUtils.mineAndSync(rskTxHelpers); - await btcTxHelper.fundAddress(donatingBtcAddressInformation.address, DONATION_AMOUNT + btcTxHelper.getFee()); - - await donateToBridge(rskTxHelper, btcTxHelper, donatingBtcAddressInformation, DONATION_AMOUNT); - - return federationAddress; }); it('should transfer BTC to RBTC', async () => { - try { - const peginSenderAddressInfo = await btcTxHelper.generateBtcAddress('legacy'); - - await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, peginSenderAddressInfo.address, Number(btcEthUnitConverter.btcToSatoshis(minimumPeginValueInBtc))); - await rskUtils.mineAndSync(rskTxHelpers); - - const recipientRskAddressInfo = getDerivedRSKAddressInformation(peginSenderAddressInfo.privateKey, btcTxHelper.btcConfig.network); - const initialRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); - - await btcTxHelper.fundAddress(peginSenderAddressInfo.address, minimumPeginValueInBtc + btcTxHelper.getFee()); - - const peginBtcTxHash = await sendPegin(rskTxHelper, btcTxHelper, peginSenderAddressInfo, minimumPeginValueInBtc); - await ensurePeginIsRegistered(rskTxHelper, peginBtcTxHash); - - const finalRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); - - // Asserting that the received pegin amount in rsk is as expected - const peginValueInWeis = Number(btcEthUnitConverter.btcToWeis(minimumPeginValueInBtc)); - expect(finalRskAddressBalanceInWeis).to.equal(initialRskAddressBalanceInWeis + peginValueInWeis); - } catch (err) { - throw new CustomError('Transfer BTC to RBTC', err); - } - }); - - it('should transfer BTC to RBTC with 2 outputs in lock TX', async () => { - try{ - const INITIAL_BTC_BALANCE = 4; - const PEGIN_OUTPUTS_VALUES_IN_BTC = [1, 2]; - const EXPECTED_RSK_BALANCE_IN_RBTC = PEGIN_OUTPUTS_VALUES_IN_BTC.reduce((a, b) => a + b, 0); // 3 - - const peginSenderAddressInfo = await btcTxHelper.generateBtcAddress('legacy'); - - await whitelistingAssertions.assertAddLimitedLockWhitelistAddress(rskTxHelper, peginSenderAddressInfo.address, Number(btcEthUnitConverter.btcToSatoshis(EXPECTED_RSK_BALANCE_IN_RBTC))); - await rskUtils.mineAndSync(rskTxHelpers); - await btcTxHelper.fundAddress(peginSenderAddressInfo.address, INITIAL_BTC_BALANCE + btcTxHelper.getFee()); - - const recipientRskAddressInfo = getDerivedRSKAddressInformation(peginSenderAddressInfo.privateKey, btcTxHelper.btcConfig.network); - - const initialRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); - const peginBtcTxHash = await sendPegin(rskTxHelper, btcTxHelper, peginSenderAddressInfo, PEGIN_OUTPUTS_VALUES_IN_BTC); - - await ensurePeginIsRegistered(rskTxHelper, peginBtcTxHash, PEGIN_OUTPUTS_VALUES_IN_BTC.length); + // Arrange - const finalRskAddressBalanceInWeis = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); + const senderInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper); + const initialFederationAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(federationAddress)); + const initialSenderAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(senderInfo.btcSenderAddressInfo.address)); + const initialRskRecipientBalance = Number(await rskTxHelper.getBalance(senderInfo.rskRecipientRskAddressInfo.address)); - // Asserting that the received pegin amount in rsk is as expected - const peginValueInWeis = Number(btcEthUnitConverter.btcToWeis(EXPECTED_RSK_BALANCE_IN_RBTC)); - expect(finalRskAddressBalanceInWeis).to.equal(initialRskAddressBalanceInWeis + peginValueInWeis); + // Act - } - catch (err) { - throw new CustomError('Transfer BTC to RBTC with 2 outputs in lock TX failure', err); - } - }); - - it('should transfer RBTC to BTC - Above minimum pegout value', async () => { - - const INITIAL_RSK_BALANCE = 1; - const PEGOUT_VALUE_IN_RBTC = 0.5; - const MAX_EXPECTED_FEE = 0.001; - const pegoutValueInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(PEGOUT_VALUE_IN_RBTC)); - const maxExpectedFeeInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(MAX_EXPECTED_FEE)); - - const initialFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); - - const btcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); - - const recipientRskAddressInfo = getDerivedRSKAddressInformation(btcAddressInformation.privateKey, btcTxHelper.btcConfig.network); - - await rskTxHelper.importAccount(recipientRskAddressInfo.privateKey); - const unlocked = await rskTxHelper.unlockAccount(recipientRskAddressInfo.address); - expect(unlocked, 'Account was not unlocked').to.be.true; - - await rskUtils.sendFromCow(rskTxHelper, recipientRskAddressInfo.address, Number(btcEthUnitConverter.btcToWeis(INITIAL_RSK_BALANCE))); - - const bridgeStateBeforePegout = await getBridgeState(rskTxHelper.getClient()); - const activeFederationUtxosBeforePegout = bridgeStateBeforePegout.activeFederationUtxos; - const pegoutTransaction = await sendTxToBridge(rskTxHelper, PEGOUT_VALUE_IN_RBTC, recipientRskAddressInfo.address); - - const pegoutRequestReceivedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_RECEIVED); - expect(pegoutRequestReceivedEvent).to.not.be.null; - const btcDestinationAddress = pegoutRequestReceivedEvent.arguments.btcDestinationAddress; - expect(pegoutRequestReceivedEvent.arguments.sender.toLowerCase()).to.equal(ensure0x(recipientRskAddressInfo.address)); - expect(Number(pegoutRequestReceivedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); - expect(btcAddressInformation.address).to.equal(btcDestinationAddress); + const btcPeginTxHash = await sendPegin(rskTxHelper, btcTxHelper, senderInfo.btcSenderAddressInfo, minimumPeginValueInBtc); + await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash); - const pegoutCreatedValidations = async (localRskTxHelper) => { + // Assert - const pegoutRequestedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.RELEASE_REQUESTED); - expect(pegoutRequestedEvent).to.not.be.null; - expect(Number(pegoutRequestedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); + const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(btcPeginTxHash).call(); + expect(isBtcTxHashAlreadyProcessed).to.be.true; - const batchPegoutCreatedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.BATCH_PEGOUT_CREATED); - expect(batchPegoutCreatedEvent).to.not.be.null; - expect(batchPegoutCreatedEvent.arguments.releaseRskTxHashes.includes(pegoutTransaction.transactionHash)).to.be.true; + const expectedEvent = createExpectedPeginBtcEvent(PEGIN_EVENTS.PEGIN_BTC, senderInfo.rskRecipientRskAddressInfo.address, btcPeginTxHash, minimumPeginValueInBtc, '0'); + const btcTxHashProcessedHeight = Number(await bridge.methods.getBtcTxHashProcessedHeight(btcPeginTxHash).call()); + await findAndCheckPeginBtcEventAtBlock(rskTxHelper, btcTxHashProcessedHeight, expectedEvent); - // TODO: Uncomment this line when lovell700 is active. - // await assertPegoutTransactionCreatedEventIsEmitted(localRskTxHelper, activeFederationUtxosBeforePegout); + const finalFederationAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(federationAddress)); + expect(finalFederationAddressBalanceInBtc).to.be.equal(initialFederationAddressBalanceInBtc + minimumPeginValueInBtc); - }; + const finalSenderAddressBalanceInBtc = Number(await btcTxHelper.getAddressBalance(senderInfo.btcSenderAddressInfo.address)); + expect(finalSenderAddressBalanceInBtc).to.be.equal(initialSenderAddressBalanceInBtc - minimumPeginValueInBtc - btcTxHelper.getFee()); - const pegoutConfirmedValidations = async (localRskTxHelper) => { - const pegoutConfirmedEvent = await rskUtils.findEventInBlock(localRskTxHelper, PEGOUT_EVENTS.PEGOUT_CONFIRMED); - expect(pegoutConfirmedEvent).to.not.be.null; - }; + const finalRskRecipientBalance = Number(await rskTxHelper.getBalance(senderInfo.rskRecipientRskAddressInfo.address)); + expect(finalRskRecipientBalance).to.be.equal(initialRskRecipientBalance + Number(btcToWeis(minimumPeginValueInBtc))); - const callbacks = { - pegoutCreatedCallback: pegoutCreatedValidations, - pegoutConfirmedCallback: pegoutConfirmedValidations, - }; - - await rskUtils.triggerRelease(rskTxHelpers, btcTxHelper, callbacks); - const finalFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); - const finalDestinationAddressBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddressInformation.address))); - const difference = pegoutValueInSatoshis - finalDestinationAddressBalanceInSatoshis; - expect(difference).to.be.at.most(maxExpectedFeeInSatoshis); - expect(finalFederationBalanceInSatoshis).to.equal(initialFederationBalanceInSatoshis - pegoutValueInSatoshis); - - }); - - it('should transfer RBTC to BTC - Below minimum pegout value', async() => { - try { - const INITIAL_RSK_BALANCE = 2; - const PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC = 0.002; - - const initialFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); - - const btcAddressInformation = await btcTxHelper.generateBtcAddress('legacy'); - const recipientRskAddressInfo = getDerivedRSKAddressInformation(btcAddressInformation.privateKey, btcTxHelper.btcConfig.network); - - await rskTxHelper.importAccount(recipientRskAddressInfo.privateKey); - await rskUtils.sendFromCow(rskTxHelper, recipientRskAddressInfo.address, Number(btcEthUnitConverter.btcToWeis(INITIAL_RSK_BALANCE))); - const initialRskAddressBalance = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); - const unlocked = await rskTxHelper.unlockAccount(recipientRskAddressInfo.address); - expect(unlocked, 'Account was not unlocked').to.be.true; - - const pegoutTransaction = await sendTxToBridge(rskTxHelper, PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC, recipientRskAddressInfo.address); - - const pegoutRejectedEvent = await rskUtils.findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_REJECTED); - expect(pegoutRejectedEvent).to.not.be.null; - const pegoutValueInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(PEGOUT_UNDER_MINIMUM_VALUE_IN_BTC)); - expect(Number(pegoutRejectedEvent.arguments.amount)).to.equal(pegoutValueInSatoshis); - expect(pegoutRejectedEvent.arguments.sender.toLowerCase()).to.equal(ensure0x(recipientRskAddressInfo.address)); - expect(Number(pegoutRejectedEvent.arguments.reason)).to.equal(REJECTED_REASON); - const finalRskAddressBalance = Number(await rskTxHelper.getBalance(recipientRskAddressInfo.address)); - expect(finalRskAddressBalance + pegoutTransaction.gasUsed * 2).to.equal(initialRskAddressBalance); - - const finalFederationBalanceInSatoshis = Number(btcEthUnitConverter.btcToSatoshis(await btcTxHelper.getAddressBalance(federationAddress))); - expect(finalFederationBalanceInSatoshis).to.equal(initialFederationBalanceInSatoshis); - } - catch (err) { - throw new CustomError('Transfer RBTC to BTC failure', err); - } }); }); + } module.exports = { diff --git a/tests/01_01_01-2wp.js b/tests/01_01_01-2wp.js new file mode 100644 index 00000000..5e39c8c5 --- /dev/null +++ b/tests/01_01_01-2wp.js @@ -0,0 +1,3 @@ +const twoWpTests = require('../lib/tests/2wp'); + +twoWpTests.execute('BTC <=> RSK 2WP', () => Runners.hosts.federate.host); diff --git a/tests/01_01_01-pre_orchid_2wp.js b/tests/01_01_01-pre_orchid_2wp.js deleted file mode 100644 index bc277430..00000000 --- a/tests/01_01_01-pre_orchid_2wp.js +++ /dev/null @@ -1,3 +0,0 @@ -const twoWpTests = require('../lib/tests/2wp'); - -twoWpTests.execute('BTC <=> RSK 2WP (pre-orchid)', () => Runners.hosts.federate.host); diff --git a/tests/02_00_01-2wp.js b/tests/02_00_01-2wp.js index 5e39c8c5..a958346a 100644 --- a/tests/02_00_01-2wp.js +++ b/tests/02_00_01-2wp.js @@ -1,3 +1,3 @@ -const twoWpTests = require('../lib/tests/2wp'); +const twoWpTests = require('../lib/tests/2wp-legacy'); twoWpTests.execute('BTC <=> RSK 2WP', () => Runners.hosts.federate.host); diff --git a/tests/04_00_04-2wp_after_fedchange.js b/tests/04_00_04-2wp_after_fedchange.js index e999abdc..bb884c32 100644 --- a/tests/04_00_04-2wp_after_fedchange.js +++ b/tests/04_00_04-2wp_after_fedchange.js @@ -1,4 +1,4 @@ -const twoWpTests = require('../lib/tests/2wp'); +const twoWpTests = require('../lib/tests/2wp-legacy'); twoWpTests.execute( 'BTC <=> RSK 2WP after federation change',