Skip to content

Commit

Permalink
fix: Add event for when a tx is received but message already confirmed
Browse files Browse the repository at this point in the history
  • Loading branch information
sendra committed Jan 8, 2024
1 parent 96623aa commit 72f5a1c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 2 deletions.
15 changes: 13 additions & 2 deletions src/contracts/CrossChainReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,21 @@ contract CrossChainReceiver is OwnableWithGuardian, ICrossChainReceiver {
Errors.CHAIN_ID_MISMATCH
);
bytes32 envelopeId = transaction.getEnvelopeId();
// if envelope was confirmed before, just return
if (_envelopesState[envelopeId] != EnvelopeState.None) return;

bytes32 transactionId = TransactionUtils.getId(encodedTransaction);

// if envelope was confirmed before, just return
if (_envelopesState[envelopeId] != EnvelopeState.None) {
emit TransactionReceivedWhenConfirmed(
transactionId,
envelopeId,
originChainId,
transaction,
msg.sender
);
return;
}

TransactionState storage internalTransaction = _transactionsState[transactionId];
ReceiverConfiguration memory configuration = _configurationsByChain[originChainId]
.configuration;
Expand Down
16 changes: 16 additions & 0 deletions src/contracts/interfaces/ICrossChainReceiver.sol
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,22 @@ interface ICrossChainReceiver {
Delivered
}

/**
* @notice emitted when a transaction has been received after a message has already been confirmed
* @param transactionId id of the transaction
* @param envelopeId id of the envelope
* @param originChainId id of the chain where the envelope originated
* @param transaction the Transaction type data
* @param bridgeAdapter address of the bridge adapter who received the message (deployed on current network)
*/
event TransactionReceivedWhenConfirmed(
bytes32 transactionId,
bytes32 indexed envelopeId,
uint256 indexed originChainId,
Transaction transaction,
address indexed bridgeAdapter
);

/**
* @notice emitted when a transaction has been received successfully
* @param transactionId id of the transaction
Expand Down
99 changes: 99 additions & 0 deletions tests/CrossChainReceiver.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ contract CrossChainReceiverTest is BaseTest {
uint8 confirmations
);

event TransactionReceivedWhenConfirmed(
bytes32 transactionId,
bytes32 indexed envelopeId,
uint256 indexed originChainId,
Transaction transaction,
address indexed bridgeAdapter
);

event EnvelopeDeliveryAttempted(bytes32 envelopeId, Envelope envelope, bool isDelivered);

event NewInvalidation(uint256 invalidTimestamp, uint256 indexed chainId);
Expand Down Expand Up @@ -432,6 +440,97 @@ contract CrossChainReceiverTest is BaseTest {
assertTrue(internalEnvelopeState == ICrossChainReceiver.EnvelopeState.Delivered);
}

function testReceiveCrossChainMessageAfterConfirmation(
uint256 txNonce,
uint256 envelopeNonce
) public {
ExtendedTransaction memory txExtended = _generateExtendedTransaction(
TestParams({
origin: GOVERNANCE_CORE,
destination: VOTING_MACHINE,
originChainId: DEFAULT_ORIGIN_CHAIN_ID,
destinationChainId: block.chainid,
envelopeNonce: envelopeNonce,
transactionNonce: txNonce
})
);

hoax(BRIDGE_ADAPTER);
vm.mockCall(
txExtended.envelope.destination,
abi.encodeWithSelector(IBaseReceiverPortal.receiveCrossChainMessage.selector),
abi.encode()
);
vm.expectCall(
txExtended.envelope.destination,
abi.encodeWithSelector(
IBaseReceiverPortal.receiveCrossChainMessage.selector,
txExtended.envelope.origin,
txExtended.envelope.originChainId,
txExtended.envelope.message
)
);
vm.expectEmit(true, true, true, true);
emit TransactionReceived(
txExtended.transactionId,
txExtended.envelopeId,
txExtended.envelope.originChainId,
txExtended.transaction,
BRIDGE_ADAPTER,
1
);
vm.expectEmit(true, true, true, true);
emit EnvelopeDeliveryAttempted(txExtended.envelopeId, txExtended.envelope, true);
crossChainReceiver.receiveCrossChainMessage(
txExtended.transactionEncoded,
txExtended.envelope.originChainId
);

// check internal transaction
assertEq(
crossChainReceiver.isTransactionReceivedByAdapter(txExtended.transactionId, BRIDGE_ADAPTER),
true
);
ICrossChainReceiver.TransactionStateWithoutAdapters
memory internalTransactionState = crossChainReceiver.getTransactionState(
txExtended.transactionId
);
ICrossChainReceiver.EnvelopeState internalEnvelopeState = crossChainReceiver.getEnvelopeState(
txExtended.envelopeId
);

assertEq(internalTransactionState.confirmations, 1);
assertEq(internalTransactionState.firstBridgedAt, block.timestamp);
assertTrue(internalEnvelopeState == ICrossChainReceiver.EnvelopeState.Delivered);

// receive 2nd cross chain message after its already confirmed
hoax(BRIDGE_ADAPTER_2);
vm.expectEmit(true, true, true, true);
emit TransactionReceivedWhenConfirmed(
txExtended.transactionId,
txExtended.envelopeId,
txExtended.envelope.originChainId,
txExtended.transaction,
BRIDGE_ADAPTER_2
);
crossChainReceiver.receiveCrossChainMessage(
txExtended.transactionEncoded,
txExtended.envelope.originChainId
);

// check internal transaction
assertEq(
crossChainReceiver.isTransactionReceivedByAdapter(txExtended.transactionId, BRIDGE_ADAPTER_2),
false
);
internalTransactionState = crossChainReceiver.getTransactionState(txExtended.transactionId);
internalEnvelopeState = crossChainReceiver.getEnvelopeState(txExtended.envelopeId);

assertEq(internalTransactionState.confirmations, 1);
assertEq(internalTransactionState.firstBridgedAt, block.timestamp);
assertTrue(internalEnvelopeState == ICrossChainReceiver.EnvelopeState.Delivered);
}

function testReceiveCrossChainMessageAfterConfirmationsLowered() public {
// set initial needed confirmation to 2
ICrossChainReceiver.ConfirmationInput memory confirmation = ICrossChainReceiver
Expand Down

0 comments on commit 72f5a1c

Please sign in to comment.