From 40f2ef55fcda52dbe6f459a4d421d498fa9f6522 Mon Sep 17 00:00:00 2001 From: jeremy-then <jeremy.then@iovlabs.org> Date: Tue, 17 Sep 2024 11:21:41 -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-new.js | 93 +++++++++++++++++++++++++++++++++++++++++++ tests/01_01_01-2wp.js | 3 ++ 5 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 lib/tests/2wp-new.js create mode 100644 tests/01_01_01-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-new.js b/lib/tests/2wp-new.js new file mode 100644 index 00000000..7a68d341 --- /dev/null +++ b/lib/tests/2wp-new.js @@ -0,0 +1,93 @@ +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 { 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; + +let btcTxHelper; +let rskTxHelper; +let rskTxHelpers; +let bridge; +let federationAddress; +let minimumPeginValueInBtc; + +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()); + + federationAddress = await bridge.methods.getFederationAddress().call(); + const minimumPeginValueInSatoshis = await bridge.methods.getMinimumLockTxValue().call(); + minimumPeginValueInBtc = Number(satoshisToBtc(minimumPeginValueInSatoshis)); + + await btcTxHelper.importAddress(federationAddress, 'federation'); + await waitAndUpdateBridge(rskTxHelper); + await setupBridgeDonation(rskTxHelpers, btcTxHelper); + + }); + + it('should transfer BTC to RBTC', async () => { + + // Arrange + + 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)); + + // Act + + const btcPeginTxHash = await sendPegin(rskTxHelper, btcTxHelper, senderInfo.btcSenderAddressInfo, minimumPeginValueInBtc); + await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash); + + // Assert + + const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(btcPeginTxHash).call(); + expect(isBtcTxHashAlreadyProcessed).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); + + 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 finalRskRecipientBalance = Number(await rskTxHelper.getBalance(senderInfo.rskRecipientRskAddressInfo.address)); + expect(finalRskRecipientBalance).to.be.equal(initialRskRecipientBalance + Number(btcToWeis(minimumPeginValueInBtc))); + + }); + + }); + +} + +module.exports = { + execute, +}; diff --git a/tests/01_01_01-2wp.js b/tests/01_01_01-2wp.js new file mode 100644 index 00000000..6ee4652d --- /dev/null +++ b/tests/01_01_01-2wp.js @@ -0,0 +1,3 @@ +const twoWpTests = require('../lib/tests/2wp-new'); + +twoWpTests.execute('BTC <=> RSK 2WP', () => Runners.hosts.federate.host);