diff --git a/contracts/src/TeleporterTokenDestination.sol b/contracts/src/TeleporterTokenDestination.sol index db9ec9f5..7fe16916 100644 --- a/contracts/src/TeleporterTokenDestination.sol +++ b/contracts/src/TeleporterTokenDestination.sol @@ -62,25 +62,38 @@ abstract contract TeleporterTokenDestination is * @notice Sends tokens to the specified destination token bridge instance. * * @dev Burns the bridged amount, and uses Teleporter to send a cross chain message. + * Tokens can be sent to the same blockchain this bridge instance is deployed on, + * to another destination bridge instance. * Requirements: * - * - `input.destinationBlockchainID` cannot be the same as the current blockchainID * - `input.destinationBridgeAddress` cannot be the zero address * - `input.recipient` cannot be the zero address * - `amount` must be greater than 0 * - `amount` must be greater than `input.primaryFee` */ function _send(SendTokensInput calldata input, uint256 amount) internal virtual { - require( - input.destinationBlockchainID != blockchainID, - "TeleporterTokenDestination: cannot bridge to same chain" - ); require( input.destinationBridgeAddress != address(0), "TeleporterTokenDestination: zero destination bridge address" ); require(input.recipient != address(0), "TeleporterTokenDestination: zero recipient address"); + // If the destination blockchain is the source bridge instance's blockchain, + // the destination bridge address must match the token source address. + if (input.destinationBlockchainID == sourceBlockchainID) { + require( + input.destinationBridgeAddress == tokenSourceAddress, + "TeleporterTokenDestination: invalid destination bridge address" + ); + } + + if (input.destinationBlockchainID == blockchainID) { + require( + input.destinationBridgeAddress != address(this), + "TeleporterTokenDestination: invalid destination bridge address" + ); + } + // Deposit the funds sent from the user to the bridge, // and set to adjusted amount after deposit amount = _deposit(amount); diff --git a/contracts/test/TeleporterTokenDestinationTests.t.sol b/contracts/test/TeleporterTokenDestinationTests.t.sol index 3271ea32..6ba73c7c 100644 --- a/contracts/test/TeleporterTokenDestinationTests.t.sol +++ b/contracts/test/TeleporterTokenDestinationTests.t.sol @@ -102,14 +102,6 @@ contract TeleporterTokenDestinationTest is Test { /** * Send tokens unit tests */ - - function testSendToSameChain() public { - SendTokensInput memory input = _createDefaultSendTokensInput(); - input.destinationBlockchainID = DEFAULT_DESTINATION_BLOCKCHAIN_ID; - vm.expectRevert(_formatTokenDestinationErrorMessage("cannot bridge to same chain")); - app.send(input, 0); - } - function testZeroDestinationBridge() public { SendTokensInput memory input = _createDefaultSendTokensInput(); input.destinationBridgeAddress = address(0); @@ -124,6 +116,21 @@ contract TeleporterTokenDestinationTest is Test { app.send(input, 0); } + function testInvalidSendingBackToSourceBlockchain() public { + SendTokensInput memory input = _createDefaultSendTokensInput(); + input.destinationBridgeAddress = address(this); + vm.expectRevert(_formatTokenDestinationErrorMessage("invalid destination bridge address")); + app.send(input, 0); + } + + function testSendingToSameInstance() public { + SendTokensInput memory input = _createDefaultSendTokensInput(); + input.destinationBlockchainID = app.blockchainID(); + input.destinationBridgeAddress = address(app); + vm.expectRevert(_formatTokenDestinationErrorMessage("invalid destination bridge address")); + app.send(input, 0); + } + function testZeroSendAmount() public { vm.expectRevert(_formatTokenDestinationErrorMessage("zero send amount")); app.send(_createDefaultSendTokensInput(), 0); @@ -148,6 +155,21 @@ contract TeleporterTokenDestinationTest is Test { _sendSuccess(amount, primaryFee); } + function testSendToSameBlockchainDifferentDestination() public { + // Send a transfer to the same app itself + uint256 amount = 2; + SendTokensInput memory input = _createDefaultSendTokensInput(); + input.destinationBlockchainID = app.blockchainID(); + input.destinationBridgeAddress = address(this); + + uint256 bridgedAmount = amount - input.primaryFee; + _checkExpectedTeleporterCalls(input, bridgedAmount); + + vm.expectEmit(true, true, true, true, address(app)); + emit SendTokens(_MOCK_MESSAGE_ID, address(this), bridgedAmount); + app.send(input, amount); + } + /** * Receive tokens unit tests */ diff --git a/tests/flows/basic_erc20_send_receive.go b/tests/flows/basic_erc20_send_receive.go index d3f42102..4200280e 100644 --- a/tests/flows/basic_erc20_send_receive.go +++ b/tests/flows/basic_erc20_send_receive.go @@ -104,9 +104,9 @@ func BasicERC20SendReceive(network interfaces.Network) { utils.CheckERC20DestinationWithdrawal( ctx, erc20Destination, + receipt, recipientAddress, bridgedAmount, - receipt, ) // Check that the recipient received the tokens @@ -158,9 +158,9 @@ func BasicERC20SendReceive(network interfaces.Network) { ctx, erc20SourceAddress, sourceToken, + receipt, recipientAddress, bridgedAmount, - receipt, ) // Check that the recipient received the tokens