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 'should reject and refund a pegout with value exactly below mini… #139

15 changes: 14 additions & 1 deletion lib/2wp-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ 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 { PEGIN_EVENTS, DEFAULT_RSK_ADDRESS_FUNDING_IN_BTC } = require("./constants");
const { PEGIN_EVENTS, DEFAULT_RSK_ADDRESS_FUNDING_IN_BTC, PEGOUT_EVENTS } = require("./constants");

const peginVerifier = require('pegin-address-verificator');
const { getRskTransactionHelpers } = require('../lib/rsk-tx-helper-provider');
Expand Down Expand Up @@ -352,6 +352,18 @@ const fundRskAccountThroughAPegin = async (rskTxHelper, btcTxHelper, btcSenderAd
return btcPeginTxHash;
};

const createExpectedReleaseRequestRejectedEvent = (rskSenderAddress, amountInSatoshis, rejectionReason) => {
const expectedEvent = {
...PEGOUT_EVENTS.RELEASE_REQUEST_REJECTED,
arguments: {
sender: rskSenderAddress,
amount: amountInSatoshis.toString(),
reason: rejectionReason,
},
}
return expectedEvent;
};

module.exports = {
sendTxToBridge,
assertRefundUtxosSameAsPeginUtxos,
Expand All @@ -372,4 +384,5 @@ module.exports = {
createExpectedRejectedPeginEvent,
createExpectedUnrefundablePeginEvent,
fundRskAccountThroughAPegin,
createExpectedReleaseRequestRejectedEvent,
};
7 changes: 7 additions & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ const PEGIN_UNREFUNDABLE_REASONS = {
INVALID_AMOUNT: '3',
};

const PEGOUT_REJECTION_REASONS = {

Choose a reason for hiding this comment

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

Just for my understanding, these are the codes found in rskj right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

LOW_AMOUNT: '1',
CALLER_CONTRACT: '2',
FEE_ABOVE_VALUE: '3',
};

const PEGOUT_EVENTS = {
RELEASE_REQUEST_RECEIVED: {
name: 'release_request_received',
Expand Down Expand Up @@ -136,4 +142,5 @@ module.exports = {
PEGIN_V1_RSKT_PREFIX_HEX,
MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS,
DEFAULT_RSK_ADDRESS_FUNDING_IN_BTC,
PEGOUT_REJECTION_REASONS,
};
55 changes: 50 additions & 5 deletions lib/tests/2wp.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
PEGOUT_EVENTS,
PEGIN_V1_RSKT_PREFIX_HEX,
MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS,
PEGOUT_REJECTION_REASONS,
} = require("../constants");
const { sendPegin,
ensurePeginIsRegistered,
Expand All @@ -23,6 +24,7 @@ const { sendPegin,
assertRefundUtxosSameAsPeginUtxos,
sendTxToBridge,
fundRskAccountThroughAPegin,
createExpectedReleaseRequestRejectedEvent,
} = require('../2wp-utils');
const { getBtcAddressBalanceInSatoshis } = require('../btc-utils');
const { ensure0x, removePrefix0x } = require('../utils');
Expand Down Expand Up @@ -693,7 +695,7 @@ const execute = (description, getRskHost) => {

// Arrange

// Create a pegin for the serder to ensure there is enough funds to pegout and because this is the natural process
// Create a pegin for the sender to ensure there is enough funds to pegout and because this is the natural process
const senderRecipientInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper);
await fundRskAccountThroughAPegin(rskTxHelper, btcTxHelper, senderRecipientInfo.btcSenderAddressInfo);

Expand Down Expand Up @@ -736,6 +738,42 @@ const execute = (description, getRskHost) => {

});

it('should reject and refund a pegout with value exactly below minimum', async () => {

// Arrange

// Create a pegin for the sender to ensure there is enough funds to pegout and because this is the natural process
const senderRecipientInfo = await createSenderRecipientInfo(rskTxHelper, btcTxHelper);
await fundRskAccountThroughAPegin(rskTxHelper, btcTxHelper, senderRecipientInfo.btcSenderAddressInfo);

const initial2wpBalances = await get2wpBalances(rskTxHelper, btcTxHelper);
const initialBtcRecipientAddressBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo.btcSenderAddressInfo.address);
const initialRskSenderBalanceInWeisBN = await rskTxHelper.getBalance(senderRecipientInfo.rskRecipientRskAddressInfo.address);
// Value exactly below minimum
const pegoutValueInSatoshis = MINIMUM_PEGOUT_AMOUNT_IN_SATOSHIS - 1;

// Act

const pegoutTransaction = await sendTxToBridge(rskTxHelper, new BN(satoshisToWeis(pegoutValueInSatoshis)), senderRecipientInfo.rskRecipientRskAddressInfo.address);

// Assert

await assertExpectedReleaseRequestRejectedEventIsEmitted(senderRecipientInfo.rskRecipientRskAddressInfo.address, pegoutValueInSatoshis, PEGOUT_REJECTION_REASONS.LOW_AMOUNT);

await assert2wpBalanceIsUnchanged(initial2wpBalances);

// The rsk sender balance is the same as the initial balance minus the gas fee, because the pegout amount was refunded.
const finalRskSenderBalanceInWeisBN = await rskTxHelper.getBalance(senderRecipientInfo.rskRecipientRskAddressInfo.address);
const gasFee = pegoutTransaction.gasUsed * pegoutTransaction.effectiveGasPrice;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Super nice, well done!

const expectedRskSenderBalanceInWeisBN = initialRskSenderBalanceInWeisBN.sub(new BN(`${gasFee}`));
expect(finalRskSenderBalanceInWeisBN.eq(expectedRskSenderBalanceInWeisBN)).to.be.true;

// The btc recipient address balance is the same as the initial balance, because the pegout didn't go though.
const finalBtcRecipientBalanceInSatoshis = await getBtcAddressBalanceInSatoshis(btcTxHelper, senderRecipientInfo.btcSenderAddressInfo.address);
expect(finalBtcRecipientBalanceInSatoshis).to.be.equal(initialBtcRecipientAddressBalanceInSatoshis);

});

});

};
Expand Down Expand Up @@ -838,15 +876,15 @@ const assertSuccessfulPegoutEventsAreEmitted = async (pegoutsEvents, pegoutReque
// release_request_received event
const releaseRequestReceivedEvent = pegoutsEvents[0];
expect(releaseRequestReceivedEvent.arguments.sender).to.be.equal(rskSenderAddress);
expect(releaseRequestReceivedEvent.arguments.amount).to.be.equal(pegoutValueInSatoshis);
expect(Number(releaseRequestReceivedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis);
expect(releaseRequestReceivedEvent.arguments.btcDestinationAddress).to.be.equal(senderRecipientInfo.btcSenderAddressInfo.address);

// release_requested event
const pegoutCreationRskTransactionHash = ensure0x(pegoutWaitingForConfirmationWhenPegoutWasCreated.rskTxHash.padStart(64, '0'));
const releaseRequestedEvent = pegoutsEvents[1];
expect(releaseRequestedEvent.arguments.rskTxHash).to.be.equal(pegoutCreationRskTransactionHash);
expect(removePrefix0x(releaseRequestedEvent.arguments.btcTxHash)).to.be.equal(btcTransaction.getId());
expect(releaseRequestReceivedEvent.arguments.amount).to.be.equal(pegoutValueInSatoshis);
expect(Number(releaseRequestReceivedEvent.arguments.amount)).to.be.equal(pegoutValueInSatoshis);

// batch_pegout_created event
const batchPegoutCreatedEvent = pegoutsEvents[2];
Expand Down Expand Up @@ -883,13 +921,20 @@ const assert2wpBalanceAfterSuccessfulPegout = async (initial2wpBalances, pegoutV

const final2wpBalances = await get2wpBalances(rskTxHelper, btcTxHelper);

expect(final2wpBalances.federationAddressBalanceInSatoshis).to.be.equal(initial2wpBalances.federationAddressBalanceInSatoshis - btcToSatoshis(pegoutValueInRbtc));
expect(final2wpBalances.federationAddressBalanceInSatoshis).to.be.equal(initial2wpBalances.federationAddressBalanceInSatoshis - pegoutValueInSatoshis);

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

expect(final2wpBalances.bridgeUtxosBalanceInSatoshis).to.be.equal(initial2wpBalances.bridgeUtxosBalanceInSatoshis - btcToSatoshis(pegoutValueInRbtc));
expect(final2wpBalances.bridgeUtxosBalanceInSatoshis).to.be.equal(initial2wpBalances.bridgeUtxosBalanceInSatoshis - pegoutValueInSatoshis);

};

const assertExpectedReleaseRequestRejectedEventIsEmitted = async (rskSenderAddress, amountInSatoshis, rejectionReason) => {
const rskSenderAddressChecksummed = rskTxHelper.getClient().utils.toChecksumAddress(ensure0x(rskSenderAddress));
const expectedEvent = createExpectedReleaseRequestRejectedEvent(rskSenderAddressChecksummed, amountInSatoshis, rejectionReason);
const releaseRequestRejectedEvent = await findEventInBlock(rskTxHelper, PEGOUT_EVENTS.RELEASE_REQUEST_REJECTED.name);
expect(releaseRequestRejectedEvent).to.be.deep.equal(expectedEvent);
};

module.exports = {
Expand Down
Loading
Loading