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

Refactors federation and bridge balances checks and pegin btc event. #101

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 30 additions & 3 deletions lib/2wp-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const {
waitAndUpdateBridge
} = require('./rsk-utils');
const { retryWithCheck, ensure0x } = require('./utils');
const { waitForBitcoinTxToBeInMempool, waitForBitcoinMempoolToGetTxs } = require('./btc-utils');
const { waitForBitcoinTxToBeInMempool, waitForBitcoinMempoolToGetTxs, getBtcAddressBalanceInSatoshis } = 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');
Expand Down Expand Up @@ -182,7 +182,10 @@ const ensurePeginIsRegistered = async (rskTxHelper, peginBtcTxHash, expectedUtxo

const { result: utxoIsRegisteredInTheBridge } = await retryWithCheck(method, check, MAX_ATTEMPTS, CHECK_EVERY_MILLISECONDS);

if(utxoIsRegisteredInTheBridge) {
const bridge = getBridge(rskTxHelper.getClient())
const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(peginBtcTxHash).call();

if(utxoIsRegisteredInTheBridge && isBtcTxHashAlreadyProcessed) {
logger.debug(`[${ensurePeginIsRegistered.name}] Found pegin ${peginBtcTxHash} registered in the bridge.`);
// The pegin is already registered in the bridge, but the balance may still not be reflected on the user's rsk address
// So we need to update the bridge and mine one more block so the balance is reflected on the user's rsk address
Expand Down Expand Up @@ -279,7 +282,30 @@ const getBridgeUtxosBalance = async (rskTxHelper) => {
const bridgeState = await getBridgeState(rskTxHelper.getClient());
const utxosSum = bridgeState.activeFederationUtxos.reduce((sum, utxo) => sum + utxo.valueInSatoshis, 0);
return utxosSum;
};
};

/**
* Gets the active Federation balance in satoshis, Bridge utxos balance in Satoshis and the Bridge rsk balance in weis BN (BigNumber)
* @param {RskTransactionHelper} rskTxHelper to make transactions to the rsk network
* @param {BtcTransactionHelper} btcTxHelper to make transactions to the bitcoin network
* @returns {Promise<{federationAddressBalanceInSatoshis: number, bridgeUtxosBalanceInSatoshis: number, bridgeBalanceInWeisBN: BN}>}
*/
const get2wpBalances = async (rskTxHelper, btcTxHelper) => {

const bridge = getBridge(rskTxHelper.getClient());
const federationAddress = await bridge.methods.getFederationAddress().call();

const federationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
const bridgeUtxosBalanceInSatoshis = await getBridgeUtxosBalance(rskTxHelper);
const bridgeBalanceInWeisBN = await rskTxHelper.getBalance(BRIDGE_ADDRESS);

return {
federationAddressBalanceInSatoshis,
bridgeUtxosBalanceInSatoshis,
bridgeBalanceInWeisBN,
};

};

module.exports = {
sendTxToBridge,
Expand All @@ -297,4 +323,5 @@ module.exports = {
createSenderRecipientInfo,
createExpectedPeginBtcEvent,
getBridgeUtxosBalance,
get2wpBalances,
};
71 changes: 39 additions & 32 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const expect = require('chai').expect;
const BN = require('bn.js');
const { getBridge } = require('../precompiled-abi-forks-util');
const { getBtcClient } = require('../btc-client-provider');
const { getRskTransactionHelpers, getRskTransactionHelper } = require('../rsk-tx-helper-provider');
Expand All @@ -9,8 +10,7 @@ const { sendPegin,
ensurePeginIsRegistered,
createSenderRecipientInfo,
createExpectedPeginBtcEvent,
BRIDGE_ADDRESS,
getBridgeUtxosBalance,
get2wpBalances,
} = require('../2wp-utils');
const { ensure0x } = require('../utils');
const { getBtcAddressBalanceInSatoshis } = require('../btc-utils');
Expand All @@ -21,9 +21,36 @@ let rskTxHelpers;
let bridge;
let federationAddress;
let minimumPeginValueInSatoshis;
let minimumPeginValueInBtc;
let btcFeeInSatoshis;

const assertExpectedPeginBtcEventIsEmitted = async (btcPeginTxHash, rskRecipientAddress, peginValueInSatoshis) => {
const recipient1RskAddressChecksumed = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(rskRecipientAddress));
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);
};

/**
* Gets the final 2wp balances (Federation, Bridge utxos and bridge rsk balances) and compares them to the `initial2wpBalances` to assert the expected values based on a successful pegin.
* Checks that after a successful pegin, the federation and Bridge utxos balances are increased and the Bridge rsk balance is decreased, by the `peginValueInSatoshis` amount.
* @param {{federationAddressBalanceInSatoshis: number, bridgeUtxosBalanceInSatoshis: number, bridgeBalanceInWeisBN: BN}} initial2wpBalances
* @param {number} peginValueInSatoshis the value of the pegin in satoshis by which the 2wp balances are expected to be updated
* @returns {Promise<void>}
*/
const assert2wpBalancesAfterSuccessfulPegin = async (initial2wpBalances, peginValueInSatoshis) => {

const final2wpBalances = await get2wpBalances(rskTxHelper, btcTxHelper);

expect(final2wpBalances.federationAddressBalanceInSatoshis).to.be.equal(initial2wpBalances.federationAddressBalanceInSatoshis + peginValueInSatoshis);

expect(final2wpBalances.bridgeUtxosBalanceInSatoshis).to.be.equal(initial2wpBalances.bridgeUtxosBalanceInSatoshis + peginValueInSatoshis);

const expectedFinalBridgeBalancesInWeisBN = initial2wpBalances.bridgeBalanceInWeisBN.sub(new BN(satoshisToWeis(peginValueInSatoshis)));
expect(final2wpBalances.bridgeBalanceInWeisBN.eq(expectedFinalBridgeBalancesInWeisBN)).to.be.true;

};

const execute = (description, getRskHost) => {

describe(description, () => {
Expand All @@ -37,7 +64,6 @@ const execute = (description, getRskHost) => {

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');
Expand All @@ -48,50 +74,31 @@ const execute = (description, getRskHost) => {

// Arrange

const initialBridgeBalance = Number(await rskTxHelper.getBalance(BRIDGE_ADDRESS));
const initialBridgeUtxosBalance = await getBridgeUtxosBalance(rskTxHelper);
const initialFederationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
const initial2wpBalances = await get2wpBalances(rskTxHelper, btcTxHelper);
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;
await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash);

// 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);
await assertExpectedPeginBtcEventIsEmitted(btcPeginTxHash, senderRecipientInfo.rskRecipientRskAddressInfo.address, peginValueInSatoshis);

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

// The sender address balance is decreased by the pegin value and the btc fee
// The btc 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);
const finalRskRecipientBalanceInWeisBN = await rskTxHelper.getBalance(senderRecipientInfo.rskRecipientRskAddressInfo.address);
const expectedRskRecipientBalancesInWeisBN = new BN(satoshisToWeis(peginValueInSatoshis));
expect(finalRskRecipientBalanceInWeisBN.eq(expectedRskRecipientBalancesInWeisBN)).to.be.true;

});

Expand Down