pragma solidity 0.4.24; import "./BasicAMBMediator.sol"; import "./BasicTokenBridge.sol"; import "./TransferInfoStorage.sol"; /** * @title TokenBridgeMediator * @dev Common mediator functionality to handle operations related to token bridge messages sent to AMB bridge. */ contract TokenBridgeMediator is BasicAMBMediator, BasicTokenBridge, TransferInfoStorage { event FailedMessageFixed(bytes32 indexed messageId, address recipient, uint256 value); event TokensBridgingInitiated(address indexed sender, uint256 value, bytes32 indexed messageId); event TokensBridged(address indexed recipient, uint256 value, bytes32 indexed messageId); /** * @dev Call AMB bridge to require the invocation of handleBridgedTokens method of the mediator on the other network. * Store information related to the bridged tokens in case the message execution fails on the other network * and the action needs to be fixed/rolled back. * @param _from address of sender, if bridge operation fails, tokens will be returned to this address * @param _receiver address of receiver on the other side, will eventually receive bridged tokens * @param _value bridged amount of tokens */ function passMessage(address _from, address _receiver, uint256 _value) internal { bytes4 methodSelector = this.handleBridgedTokens.selector; bytes memory data = abi.encodeWithSelector(methodSelector, _receiver, _value); bytes32 _messageId = bridgeContract().requireToPassMessage( mediatorContractOnOtherSide(), data, requestGasLimit() ); setMessageValue(_messageId, _value); setMessageRecipient(_messageId, _from); emit TokensBridgingInitiated(_from, _value, _messageId); } /** * @dev Handles the bridged tokens. Checks that the value is inside the execution limits and invokes the method * to execute the Mint or Unlock accordingly. * @param _recipient address that will receive the tokens * @param _value amount of tokens to be received */ function handleBridgedTokens(address _recipient, uint256 _value) external onlyMediator { if (withinExecutionLimit(_value)) { addTotalExecutedPerDay(getCurrentDay(), _value); executeActionOnBridgedTokens(_recipient, _value); } else { executeActionOnBridgedTokensOutOfLimit(_recipient, _value); } } /** * @dev Method to be called when a bridged message execution failed. It will generate a new message requesting to * fix/roll back the transferred assets on the other network. * @param _messageId id of the message which execution failed. */ function requestFailedMessageFix(bytes32 _messageId) external { require(!bridgeContract().messageCallStatus(_messageId)); require(bridgeContract().failedMessageReceiver(_messageId) == address(this)); require(bridgeContract().failedMessageSender(_messageId) == mediatorContractOnOtherSide()); bytes4 methodSelector = this.fixFailedMessage.selector; bytes memory data = abi.encodeWithSelector(methodSelector, _messageId); bridgeContract().requireToPassMessage(mediatorContractOnOtherSide(), data, requestGasLimit()); } /** * @dev Handles the request to fix transferred assets which bridged message execution failed on the other network. * It uses the information stored by passMessage method when the assets were initially transferred * @param _messageId id of the message which execution failed on the other network. */ function fixFailedMessage(bytes32 _messageId) external onlyMediator { require(!messageFixed(_messageId)); address recipient = messageRecipient(_messageId); uint256 value = messageValue(_messageId); setMessageFixed(_messageId); executeActionOnFixedTokens(recipient, value); emit FailedMessageFixed(_messageId, recipient, value); } /* solcov ignore next */ function executeActionOnBridgedTokensOutOfLimit(address _recipient, uint256 _value) internal; /* solcov ignore next */ function executeActionOnBridgedTokens(address _recipient, uint256 _value) internal; /* solcov ignore next */ function executeActionOnFixedTokens(address _recipient, uint256 _value) internal; }