Skip to content

Commit

Permalink
Adds legacy pegin test with multiple inputs from multiple accounts.
Browse files Browse the repository at this point in the history
  • Loading branch information
jeremy-then committed Sep 24, 2024
1 parent be67f49 commit 1ed66c5
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 3 deletions.
4 changes: 3 additions & 1 deletion lib/2wp-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,9 @@ const createSenderRecipientInfo = async (rskTxHelper, btcTxHelper, type = 'legac
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);
if(Number(initialAmountToFundInBtc) > 0) {
await btcTxHelper.fundAddress(btcSenderAddressInfo.address, initialAmountToFundInBtc);
}
return {
btcSenderAddressInfo,
rskRecipientRskAddressInfo
Expand Down
117 changes: 115 additions & 2 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ const { sendPegin,
ensurePeginIsRegistered,
donateToBridge,
createSenderRecipientInfo,
createExpectedPeginBtcEvent
createExpectedPeginBtcEvent,
mineForPeginRegistration
} = require('../2wp-utils');
const { ensure0x } = require('../utils');
const { getBtcAddressBalanceInSatoshis } = require('../btc-utils');
const { getBtcAddressBalanceInSatoshis, waitForBitcoinMempoolToGetTxs } = require('../btc-utils');
const bitcoinJsLib = require('bitcoinjs-lib');

const DONATION_AMOUNT = 250;

Expand All @@ -32,6 +34,39 @@ const setupBridgeDonation = async (rskTxHelpers, btcTxHelper) => {
await donateToBridge(rskTxHelpers[0], btcTxHelper, donatingBtcAddressInformation, DONATION_AMOUNT);
};


const getSenderUtxosInfo = async (senderInfo, btcSenderAmountToSendToFed) => {
return await btcTxHelper.selectSpendableUTXOsFromAddress(senderInfo.btcSenderAddressInfo.address, btcSenderAmountToSendToFed);
};

const addInputs = (tx, senderUtxosInfo) => {
senderUtxosInfo.utxos.forEach(utxo => {
tx.addInput(Buffer.from(utxo.txid, 'hex').reverse(), utxo.vout);
});
};

const addChangeOutputs = (tx, changeAddress, changeInSatoshis) => {
if(changeInSatoshis > 0) {
tx.addOutput(
bitcoinJsLib.address.toOutputScript(changeAddress, btcTxHelper.btcConfig.network),
changeInSatoshis - btcFeeInSatoshis
);
}
};

const pushPegin = async (btcPeginTxHash, expectedUtxosCount = 1) => {
await waitForBitcoinMempoolToGetTxs(btcTxHelper, btcPeginTxHash);
await mineForPeginRegistration(rskTxHelper, btcTxHelper);
await ensurePeginIsRegistered(rskTxHelper, btcPeginTxHash, expectedUtxosCount);
};

const addOutputToFed = (tx, outputValueInSatoshis) => {
tx.addOutput(
bitcoinJsLib.address.toOutputScript(federationAddress, btcTxHelper.btcConfig.network),
outputValueInSatoshis
);
};

const execute = (description, getRskHost) => {

describe(description, () => {
Expand Down Expand Up @@ -137,6 +172,84 @@ const execute = (description, getRskHost) => {

});

it('should do legacy pegin with multiple inputs from different accounts and one output to the federation with value exactly minimum', async () => {

// Arrange

const initialFederationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
const sender1RecipientInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper);
const sender2RecipientInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper);
const initialSender1AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, sender1RecipientInfo.btcSenderAddressInfo.address);
const initialSender2AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, sender2RecipientInfo.btcSenderAddressInfo.address);

const sender1PeginValueInSatoshis = minimumPeginValueInSatoshis;
const sender2PeginValueInSatoshis = minimumPeginValueInSatoshis;
const peginValueInSatoshis = sender1PeginValueInSatoshis + sender2PeginValueInSatoshis;

const sender1UtxosInfo = await getSenderUtxosInfo(sender1RecipientInfo, satoshisToBtc(sender1PeginValueInSatoshis));
const sender2UtxosInfo = await getSenderUtxosInfo(sender2RecipientInfo, satoshisToBtc(sender2PeginValueInSatoshis));

const sender1ChangeInSatoshis = btcToSatoshis(sender1UtxosInfo.change);
const sender2ChangeInSatoshis = btcToSatoshis(sender2UtxosInfo.change);

const tx = new bitcoinJsLib.Transaction();

// Adding inputs
addInputs(tx, sender1UtxosInfo);
addInputs(tx, sender2UtxosInfo);

// Adding output to federation
addOutputToFed(tx, peginValueInSatoshis);

// Adding change outputs
addChangeOutputs(tx, sender1RecipientInfo.btcSenderAddressInfo.address, sender1ChangeInSatoshis);
addChangeOutputs(tx, sender2RecipientInfo.btcSenderAddressInfo.address, sender2ChangeInSatoshis);

// Signing the transaction
const sender1PrivateKey = sender1RecipientInfo.btcSenderAddressInfo.privateKey;
const sender2PrivateKey = sender2RecipientInfo.btcSenderAddressInfo.privateKey;
const sendersPrivateKeys = [sender1PrivateKey, sender2PrivateKey];
const signedTx = await btcTxHelper.nodeClient.signTransaction(tx.toHex(), [], sendersPrivateKeys);

// Act

// Sending the pegin and ensuring the pegin is registered
const btcPeginTxHash = await btcTxHelper.nodeClient.sendTransaction(signedTx);
await pushPegin(btcPeginTxHash);

// Assert

const isBtcTxHashAlreadyProcessed = await bridge.methods.isBtcTxHashAlreadyProcessed(btcPeginTxHash).call();
expect(isBtcTxHashAlreadyProcessed).to.be.true;

// The expected pegin_btc event should be emitted with the expected values
const recipient1RskAddressChecksumed = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(sender1RecipientInfo.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 address should have received the total amount sent by the senders
const finalFederationAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, federationAddress);
expect(finalFederationAddressBalanceInSatoshis).to.be.equal(initialFederationAddressBalanceInSatoshis + peginValueInSatoshis);

// The senders should have their balances reduced by the amount sent to the federation and the fee
const finalSender1AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, sender1RecipientInfo.btcSenderAddressInfo.address);
expect(finalSender1AddressBalanceInSatoshis).to.be.equal(initialSender1AddressBalanceInSatoshis - sender1PeginValueInSatoshis - btcFeeInSatoshis);

const finalSender2AddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, sender2RecipientInfo.btcSenderAddressInfo.address);
expect(finalSender2AddressBalanceInSatoshis).to.be.equal(initialSender2AddressBalanceInSatoshis - sender2PeginValueInSatoshis - btcFeeInSatoshis);

// Only the first sender should have the total amount in rsk since in legacy pegins the rsk address is derived from the first input.
const finalRskRecipient1Balance = Number(await rskTxHelper.getBalance(sender1RecipientInfo.rskRecipientRskAddressInfo.address));
expect(finalRskRecipient1Balance).to.be.equal(Number(satoshisToWeis(peginValueInSatoshis)));

// Other senders should have 0 balance in rsk.
const finalRskRecipient2Balance = Number(await rskTxHelper.getBalance(sender2RecipientInfo.rskRecipientRskAddressInfo.address));
expect(finalRskRecipient2Balance).to.be.equal(0);

});

});

}
Expand Down

0 comments on commit 1ed66c5

Please sign in to comment.