Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds new 2wp file starting with one pegin test checking event #87

Merged
merged 10 commits into from
Sep 25, 2024
61 changes: 59 additions & 2 deletions lib/2wp-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -198,7 +199,7 @@ const ensurePeginIsRegistered = async (rskTxHelper, peginBtcTxHash, expectedUtxo
* @param {RskTransactionHelper} rskTxHelper
* @param {BtcTransactionHelper} btcTxHelper
* @param {number} amountInBtc
* @returns {string} the pegin tx hash
* @returns {Promise<string>} the pegin tx hash
*/
const donateToBridge = async (rskTxHelper, btcTxHelper, donatingBtcAddressInformation, amountInBtc) => {
const data = [];
Expand Down Expand Up @@ -227,6 +228,59 @@ const disableWhitelisting = async (rskTxHelper, btcTxHelper, blockDelay = 1) =>
}
};

/**
* Creates a btc sender and rsk recipient information (private keys and addresses) and funds the btc sender address with the specified amount.
* @param {RskTransactionHelper} rskTxHelper to make transactions to the rsk network.
* @param {BtcTransactionHelper} btcTxHelper to make transactions to the bitcoin network.
* @param {string} type the btc address type to generate. Defaults to 'legacy'.
* @param {number} initialAmountToFundInBtc the initial amount to fund the btc sender address. Defaults to 1.
* @returns {Promise<{btcSenderAddressInfo: {address: string, privateKey: string}, rskRecipientRskAddressInfo: {address: string, privateKey: string}>}}
*/
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
};
};

/**
* Creates a pegin_btc event with the specified parameters.
* @param {Object} partialExpectedEvent an object with some pegin_btc event default values.
* @param {string} rskRecipientRskAddress the rsk address that receives the funds expected to be in the event.
* @param {string} btcPeginTxHash the pegin btc tx hash expected to be in the event.
* @param {number} peginValueInSatoshis the pegin value in satoshis expected to be in the event.
* @param {string} protocolVersion the pegin protocol version expected to be in the event. Defaults to '0'.
* @returns {BridgeEvent}
*/
const createExpectedPeginBtcEvent = (partialExpectedEvent, rskRecipientRskAddress, btcPeginTxHash, peginValueInSatoshis, protocolVersion = '0') => {
const expectedEvent = {
...partialExpectedEvent,
arguments: {
receiver: ensure0x(rskRecipientRskAddress),
btcTxHash: ensure0x(btcPeginTxHash),
amount: `${peginValueInSatoshis}`,
protocolVersion,
},
}
return expectedEvent;
};

/**
* Gets the Bridge state and sums the utxos amount
* @param {RskTransactionHelper} rskTxHelper to make transactions to the rsk network
* @returns {Promise<number>} the sum of the utxos in the Bridge
*/
const getBridgeUtxosBalance = async (rskTxHelper) => {
const bridgeState = await getBridgeState(rskTxHelper.getClient());
const utxosSum = bridgeState.activeFederationUtxos.reduce((sum, utxo) => sum + utxo.valueInSatoshis, 0);
return utxosSum;
};

module.exports = {
sendTxToBridge,
assertRefundUtxosSameAsPeginUtxos,
Expand All @@ -240,4 +294,7 @@ module.exports = {
mineForPeginRegistration,
MIN_PEGOUT_VALUE_IN_RBTC,
disableWhitelisting,
createSenderRecipientInfo,
createExpectedPeginBtcEvent,
getBridgeUtxosBalance,
};
3 changes: 2 additions & 1 deletion lib/assertions/2wp.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const expect = require('chai').expect;
var {wait, removePrefix0x} = require('../utils');
var bitcoin = require('peglib').bitcoin;
var rsk = require('peglib').rsk;

const {MAX_ESTIMATED_FEE_PER_PEGOUT, FEE_DIFFERENCE_PER_PEGOUT} = require('../constants');
const {encodeOutpointValuesAsMap, decodeOutpointValues} = require("../varint");

Expand Down Expand Up @@ -140,5 +141,5 @@ module.exports = {
assertLock: assertLock(btcClient, rskClient, pegClient),
}),
assertCallToPegoutBatchingBridgeMethods,
assertRejectedPeginEvent
assertRejectedPeginEvent,
};
8 changes: 7 additions & 1 deletion lib/btc-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const merkleLib = require('merkle-lib');
const pmtBuilder = require('@rsksmart/pmt-builder');
const { retryWithCheck } = require('./utils');
const { getLogger } = require('../logger');
const { btcToSatoshis } = require('@rsksmart/btc-eth-unit-converter');

const logger = getLogger();

Expand Down Expand Up @@ -181,10 +182,15 @@ const waitForBitcoinMempoolToGetTxs = async (btcTxHelper, maxAttempts = 3, check
return bitcoinMempoolHasTx;
}

const getBtcAddressBalanceInSatoshis = async (btcTxHelper, btcAddress) => {
return Number(btcToSatoshis(await btcTxHelper.getAddressBalance(btcAddress)));
};

module.exports = {
publicKeyToCompressed,
fundAddressAndGetData,
getBitcoinTransactionsInMempool,
waitForBitcoinTxToBeInMempool,
waitForBitcoinMempoolToGetTxs
waitForBitcoinMempoolToGetTxs,
getBtcAddressBalanceInSatoshis,
}
10 changes: 9 additions & 1 deletion lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not for now, but I would consider splitting this file before it grows too much. 2wpConstants, BrideEvents, FedChangeConstants, etc

PEGIN_BTC: {
name: "pegin_btc",
signature: '0x44cdc782a38244afd68336ab92a0b39f864d6c0b2a50fa1da58cafc93cd2ae5a'
}
};

module.exports = {
KEY_TYPE_BTC,
Expand All @@ -77,4 +84,5 @@ module.exports = {
PEGOUT_EVENTS,
FUNDS_MIGRATION_AGE_SINCE_ACTIVATION_BEGIN,
FUNDS_MIGRATION_AGE_SINCE_ACTIVATION_END,
PEGIN_EVENTS,
};
104 changes: 104 additions & 0 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
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, btcToSatoshis, satoshisToWeis } = require('@rsksmart/btc-eth-unit-converter');
const { findEventInBlock } = require('../rsk-utils');
const { PEGIN_EVENTS } = require("../constants");
const { sendPegin,
ensurePeginIsRegistered,
createSenderRecipientInfo,
createExpectedPeginBtcEvent,
BRIDGE_ADDRESS,
getBridgeUtxosBalance,
} = require('../2wp-utils');
const { ensure0x } = require('../utils');
const { getBtcAddressBalanceInSatoshis } = require('../btc-utils');

let btcTxHelper;
let rskTxHelper;
let rskTxHelpers;
let bridge;
let federationAddress;
let minimumPeginValueInSatoshis;
let minimumPeginValueInBtc;
let btcFeeInSatoshis;

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();
minimumPeginValueInSatoshis = Number(await bridge.methods.getMinimumLockTxValue().call());
minimumPeginValueInBtc = Number(satoshisToBtc(minimumPeginValueInSatoshis));
btcFeeInSatoshis = btcToSatoshis(await btcTxHelper.getFee());

await btcTxHelper.importAddress(federationAddress, 'federation');

});

it('should do a basic legacy pegin with the exact minimum value', async () => {

// Arrange

const initialBridgeBalance = Number(await rskTxHelper.getBalance(BRIDGE_ADDRESS));
const initialBridgeUtxosBalance = await getBridgeUtxosBalance(rskTxHelper);
const initialFederationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
const senderRecipientInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper);
const initialSenderAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo.btcSenderAddressInfo.address);
const peginValueInSatoshis = minimumPeginValueInSatoshis;

// Act

const btcPeginTxHash = await sendPegin(rskTxHelper, btcTxHelper, senderRecipientInfo.btcSenderAddressInfo, satoshisToBtc(peginValueInSatoshis));
await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash);

// Assert

// The btc pegin tx is already marked as processed by the bridge
const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(btcPeginTxHash).call();
expect(isBtcTxHashAlreadyProcessed).to.be.true;

// The pegin_btc event is emitted with the expected values
const recipient1RskAddressChecksumed = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(senderRecipientInfo.rskRecipientRskAddressInfo.address));
const expectedEvent = createExpectedPeginBtcEvent(PEGIN_EVENTS.PEGIN_BTC, recipient1RskAddressChecksumed, btcPeginTxHash, peginValueInSatoshis);
const btcTxHashProcessedHeight = Number(await bridge.methods.getBtcTxHashProcessedHeight(btcPeginTxHash).call());
const peginBtcEvent = await findEventInBlock(rskTxHelper, expectedEvent.name, btcTxHashProcessedHeight);
expect(peginBtcEvent).to.be.deep.equal(expectedEvent);

// The federation balance is increased by the pegin value
const finalFederationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
expect(finalFederationAddressBalanceInSatoshis).to.be.equal(initialFederationAddressBalanceInSatoshis + peginValueInSatoshis);

// The sender address balance is decreased by the pegin value and the btc fee
const finalSenderAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo.btcSenderAddressInfo.address);
expect(finalSenderAddressBalanceInSatoshis).to.be.equal(initialSenderAddressBalanceInSatoshis - peginValueInSatoshis - btcFeeInSatoshis);

// The recipient rsk address balance is increased by the pegin value
const finalRskRecipientBalance = Number(await rskTxHelper.getBalance(senderRecipientInfo.rskRecipientRskAddressInfo.address));
expect(finalRskRecipientBalance).to.be.equal(Number(satoshisToWeis(peginValueInSatoshis)));

// After the successful pegin, the Bridge balance should be reduced by the pegin value
const finalBridgeBalance = Number(await rskTxHelper.getBalance(BRIDGE_ADDRESS));
expect(finalBridgeBalance).to.be.equal(initialBridgeBalance - satoshisToWeis(peginValueInSatoshis));

// After the successful pegin, the Bridge utxos sum should be incremented by the pegin value
const finalBridgeUtxosBalance = await getBridgeUtxosBalance(rskTxHelper);
expect(finalBridgeUtxosBalance).to.be.equal(initialBridgeUtxosBalance + peginValueInSatoshis);

});

});

}

module.exports = {
execute,
};
3 changes: 3 additions & 0 deletions tests/01_01_01-2wp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const twoWpTests = require('../lib/tests/2wp');

twoWpTests.execute('BTC <=> RSK 2WP', () => Runners.hosts.federate.host);