diff --git a/helix-contract/address/ln-dev.json b/helix-contract/address/ln-dev.json index a2c922f7..3b1b88a8 100644 --- a/helix-contract/address/ln-dev.json +++ b/helix-contract/address/ln-dev.json @@ -19,7 +19,7 @@ }, "ProxyAdmin": "0xE3979fFa68BBa1F53c6F502c8F5788B370d28730", "LnDefaultBridgeLogic": "0x43ae847d170e8AB26901a80b474d356Aaa30CEE1", - "LnOppositeBridgeLogic": "0xdE4667Fa1Db7a73914d13aF664933a027e5F9f54", + "LnOppositeBridgeLogic": "0x5ae6AF7b7fb6c869219289ba2570C6D4eF20Be2a", "LnDefaultBridgeProxy": "0x54cc9716905ba8ebdD01E6364125cA338Cd0054E", "LnOppositeBridgeProxy": "0x79e6f452f1e491a7aF0382FA0a6EF9368691960D" } diff --git a/helix-contract/contracts/ln/base/LnDefaultBridgeSource.sol b/helix-contract/contracts/ln/base/LnDefaultBridgeSource.sol index 13bdb97e..783612a9 100644 --- a/helix-contract/contracts/ln/base/LnDefaultBridgeSource.sol +++ b/helix-contract/contracts/ln/base/LnDefaultBridgeSource.sol @@ -184,6 +184,7 @@ contract LnDefaultBridgeSource { require(_snapshot.totalFee >= providerFee + tokenInfo.protocolFee && providerFee > 0, "fee is invalid"); uint112 targetAmount = LnBridgeHelper.sourceAmountToTargetAmount(tokenInfo, _amount); + require(targetAmount > 0, "invalid target amount"); require(block.timestamp < type(uint32).max, "timestamp overflow"); bytes32 transferId = keccak256(abi.encodePacked( block.chainid, diff --git a/helix-contract/contracts/ln/base/LnOppositeBridgeSource.sol b/helix-contract/contracts/ln/base/LnOppositeBridgeSource.sol index a4fa0e6d..25622227 100644 --- a/helix-contract/contracts/ln/base/LnOppositeBridgeSource.sol +++ b/helix-contract/contracts/ln/base/LnOppositeBridgeSource.sol @@ -202,6 +202,7 @@ contract LnOppositeBridgeSource { require(_snapshot.totalFee >= tokenInfo.protocolFee + providerFee, "fee is invalid"); uint112 targetAmount = LnBridgeHelper.sourceAmountToTargetAmount(tokenInfo, _amount); + require(targetAmount > 0, "invalid amount"); require(block.timestamp < type(uint32).max, "timestamp overflow"); bytes32 transferId = keccak256(abi.encodePacked( block.chainid, @@ -250,7 +251,7 @@ contract LnOppositeBridgeSource { _snapshot.provider, _snapshot.sourceToken, _snapshot.targetToken, - _amount, + targetAmount, providerFee, uint64(block.timestamp), _receiver); diff --git a/helix-contract/deploy/deploy_ln_logic.js b/helix-contract/deploy/deploy_ln_logic.js index 7e095ab7..cfe84f12 100644 --- a/helix-contract/deploy/deploy_ln_logic.js +++ b/helix-contract/deploy/deploy_ln_logic.js @@ -53,8 +53,8 @@ async function main() { //const network = arbitrumNetwork; const network = lineaNetwork; const w = wallet(network.url); - await deployLnDefaultBridge(w, network.deployer, "ln-default-logic-v1.0.1"); - await deployLnOppositeBridge(w, network.deployer, "ln-opposite-logic-v1.0.1"); + //await deployLnDefaultBridge(w, network.deployer, "ln-default-logic-v1.0.1"); + await deployLnOppositeBridge(w, network.deployer, "ln-opposite-logic-v1.0.2"); } main() diff --git a/helix-contract/flatten/lnv2/Eth2LineaReceiveService.sol b/helix-contract/flatten/lnv2/Eth2LineaReceiveService.sol index 65b3b9a7..eeb0fe9f 100644 --- a/helix-contract/flatten/lnv2/Eth2LineaReceiveService.sol +++ b/helix-contract/flatten/lnv2/Eth2LineaReceiveService.sol @@ -14,7 +14,7 @@ * '----------------' '----------------' '----------------' '----------------' '----------------' ' * * - * 9/7/2023 + * 9/11/2023 **/ pragma solidity ^0.8.10; diff --git a/helix-contract/flatten/lnv2/Eth2LineaSendService.sol b/helix-contract/flatten/lnv2/Eth2LineaSendService.sol index 8ddf0561..1ea4869a 100644 --- a/helix-contract/flatten/lnv2/Eth2LineaSendService.sol +++ b/helix-contract/flatten/lnv2/Eth2LineaSendService.sol @@ -14,7 +14,7 @@ * '----------------' '----------------' '----------------' '----------------' '----------------' ' * * - * 9/7/2023 + * 9/11/2023 **/ pragma solidity ^0.8.10; diff --git a/helix-contract/flatten/lnv2/LnDefaultBridge.sol b/helix-contract/flatten/lnv2/LnDefaultBridge.sol index 35a84b29..5f08b155 100644 --- a/helix-contract/flatten/lnv2/LnDefaultBridge.sol +++ b/helix-contract/flatten/lnv2/LnDefaultBridge.sol @@ -14,7 +14,7 @@ * '----------------' '----------------' '----------------' '----------------' '----------------' ' * * - * 9/7/2023 + * 9/11/2023 **/ pragma solidity ^0.8.10; @@ -293,6 +293,7 @@ contract LnDefaultBridgeSource { bytes32 transferId, address provider, address sourceToken, + address targetToken, uint112 amount, uint112 fee, uint64 timestamp, @@ -396,8 +397,9 @@ contract LnDefaultBridgeSource { address _receiver ) external payable { require(_amount > 0, "invalid amount"); - bytes32 tokenKey = LnBridgeHelper.getTokenKey(_snapshot.remoteChainId, _snapshot.sourceToken, _snapshot.targetToken); - LnBridgeHelper.TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + LnBridgeHelper.TokenInfo memory tokenInfo = tokenInfos[ + LnBridgeHelper.getTokenKey(_snapshot.remoteChainId, _snapshot.sourceToken, _snapshot.targetToken) + ]; require(tokenInfo.isRegistered, "token not registered"); bytes32 providerKey = LnBridgeHelper.getProviderKey(_snapshot.remoteChainId, _snapshot.provider, _snapshot.sourceToken, _snapshot.targetToken); @@ -412,6 +414,7 @@ contract LnDefaultBridgeSource { require(_snapshot.totalFee >= providerFee + tokenInfo.protocolFee && providerFee > 0, "fee is invalid"); uint112 targetAmount = LnBridgeHelper.sourceAmountToTargetAmount(tokenInfo, _amount); + require(targetAmount > 0, "invalid target amount"); require(block.timestamp < type(uint32).max, "timestamp overflow"); bytes32 transferId = keccak256(abi.encodePacked( block.chainid, @@ -462,6 +465,7 @@ contract LnDefaultBridgeSource { transferId, _snapshot.provider, _snapshot.sourceToken, + _snapshot.targetToken, targetAmount, providerFee, uint64(block.timestamp), @@ -603,175 +607,17 @@ contract LnDefaultBridgeSource { } } -// File @zeppelin-solidity/contracts/utils/Context.sol@v4.7.3 -// License-Identifier: MIT -// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) - - -/** - * @dev Provides information about the current execution context, including the - * sender of the transaction and its data. While these are generally available - * via msg.sender and msg.data, they should not be accessed in such a direct - * manner, since when dealing with meta-transactions the account sending and - * paying for execution may not be the actual sender (as far as an application - * is concerned). - * - * This contract is only required for intermediate, library-like contracts. - */ -abstract contract Context { - function _msgSender() internal view virtual returns (address) { - return msg.sender; - } - - function _msgData() internal view virtual returns (bytes calldata) { - return msg.data; - } -} - -// File @zeppelin-solidity/contracts/security/Pausable.sol@v4.7.3 +// File contracts/ln/interface/ILowLevelMessager.sol // License-Identifier: MIT -// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) - -/** - * @dev Contract module which allows children to implement an emergency stop - * mechanism that can be triggered by an authorized account. - * - * This module is used through inheritance. It will make available the - * modifiers `whenNotPaused` and `whenPaused`, which can be applied to - * the functions of your contract. Note that they will not be pausable by - * simply including this module, only once the modifiers are put in place. - */ -abstract contract Pausable is Context { - /** - * @dev Emitted when the pause is triggered by `account`. - */ - event Paused(address account); - - /** - * @dev Emitted when the pause is lifted by `account`. - */ - event Unpaused(address account); - - bool private _paused; - - /** - * @dev Initializes the contract in unpaused state. - */ - constructor() { - _paused = false; - } - - /** - * @dev Modifier to make a function callable only when the contract is not paused. - * - * Requirements: - * - * - The contract must not be paused. - */ - modifier whenNotPaused() { - _requireNotPaused(); - _; - } - - /** - * @dev Modifier to make a function callable only when the contract is paused. - * - * Requirements: - * - * - The contract must be paused. - */ - modifier whenPaused() { - _requirePaused(); - _; - } - - /** - * @dev Returns true if the contract is paused, and false otherwise. - */ - function paused() public view virtual returns (bool) { - return _paused; - } - - /** - * @dev Throws if the contract is paused. - */ - function _requireNotPaused() internal view virtual { - require(!paused(), "Pausable: paused"); - } - - /** - * @dev Throws if the contract is not paused. - */ - function _requirePaused() internal view virtual { - require(paused(), "Pausable: not paused"); - } - - /** - * @dev Triggers stopped state. - * - * Requirements: - * - * - The contract must not be paused. - */ - function _pause() internal virtual whenNotPaused { - _paused = true; - emit Paused(_msgSender()); - } - - /** - * @dev Returns to normal state. - * - * Requirements: - * - * - The contract must be paused. - */ - function _unpause() internal virtual whenPaused { - _paused = false; - emit Unpaused(_msgSender()); - } +interface ILowLevelMessageSender { + function registerRemoteReceiver(uint256 remoteChainId, address remoteBridge) external; + function sendMessage(uint256 remoteChainId, bytes memory message, bytes memory params) external payable; } -// File contracts/ln/base/LnAccessController.sol -// License-Identifier: MIT - -/// @title LnAccessController -/// @notice LnAccessController is a contract to control the access permission -/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract -contract LnAccessController is Pausable { - address public dao; - address public operator; - - modifier onlyDao() { - require(msg.sender == dao, "!dao"); - _; - } - - modifier onlyOperator() { - require(msg.sender == operator, "!operator"); - _; - } - - function _initialize(address _dao) internal { - dao = _dao; - operator = msg.sender; - } - - function setOperator(address _operator) onlyDao external { - operator = _operator; - } - - function transferOwnership(address _dao) onlyDao external { - dao = _dao; - } - - function unpause() external onlyOperator { - _unpause(); - } - - function pause() external onlyOperator { - _pause(); - } +interface ILowLevelMessageReceiver { + function registerRemoteSender(uint256 remoteChainId, address remoteBridge) external; + function recvMessage(address remoteSender, address localReceiver, bytes memory payload) external; } // File contracts/ln/base/LnDefaultBridgeTarget.sol @@ -801,10 +647,10 @@ contract LnDefaultBridgeTarget { // transferId => FillTransfer mapping(bytes32 => FillTransfer) public fillTransfers; - event TransferFilled(address provider, bytes32 transferId); - event Slash(bytes32 transferId, address provider, address token, uint256 margin, address slasher); - event MarginUpdated(address provider, address token, uint256 amount, uint64 withdrawNonce); - event SlashReserveUpdated(address provider, address token, uint256 amount); + event TransferFilled(bytes32 transferId, address provider); + event Slash(bytes32 transferId, uint256 remoteChainId, address provider, address sourceToken, address targetToken, uint256 margin, address slasher); + event MarginUpdated(uint256 remoteChainId, address provider, address sourceToken, address targetToken, uint256 amount, uint64 withdrawNonce); + event SlashReserveUpdated(address provider, address sourceToken, address targetToken, uint256 amount); modifier allowRemoteCall(uint256 _remoteChainId) { _verifyRemote(_remoteChainId); @@ -829,7 +675,7 @@ contract LnDefaultBridgeTarget { } else { LnBridgeHelper.safeTransferFrom(_targetToken, msg.sender, address(this), _margin); } - emit MarginUpdated(msg.sender, _sourceToken, updatedMargin, providerInfo.withdrawNonce); + emit MarginUpdated(_remoteChainId, msg.sender, _sourceToken, _targetToken, updatedMargin, providerInfo.withdrawNonce); } function transferAndReleaseMargin( @@ -866,7 +712,7 @@ contract LnDefaultBridgeTarget { } else { LnBridgeHelper.safeTransferFrom(_params.targetToken, msg.sender, _params.receiver, uint256(_params.amount)); } - emit TransferFilled(_params.provider, transferId); + emit TransferFilled(transferId, _params.provider); } function depositSlashFundReserve( @@ -884,7 +730,7 @@ contract LnDefaultBridgeTarget { } else { LnBridgeHelper.safeTransferFrom(_targetToken, msg.sender, address(this), _amount); } - emit SlashReserveUpdated(msg.sender, _sourceToken, updatedAmount); + emit SlashReserveUpdated(msg.sender, _sourceToken, _targetToken, updatedAmount); } // withdraw slash fund @@ -906,7 +752,7 @@ contract LnDefaultBridgeTarget { } else { LnBridgeHelper.safeTransfer(_targetToken, msg.sender, _amount); } - emit SlashReserveUpdated(msg.sender, _sourceToken, updatedAmount); + emit SlashReserveUpdated(msg.sender, _sourceToken, _targetToken, updatedAmount); } function withdraw( @@ -937,7 +783,7 @@ contract LnDefaultBridgeTarget { } else { LnBridgeHelper.safeTransfer(_targetToken, _provider, _amount); } - emit MarginUpdated(_provider, _sourceToken, updatedMargin, _withdrawNonce); + emit MarginUpdated(_remoteChainId, _provider, _sourceToken, _targetToken, updatedMargin, _withdrawNonce); } function slash( @@ -997,21 +843,179 @@ contract LnDefaultBridgeTarget { LnBridgeHelper.safeTransfer(_params.targetToken, _slasher, slashRefund); } } - emit Slash(transferId, _params.provider, _params.sourceToken, updatedMargin, _slasher); + emit Slash(transferId, _remoteChainId, _params.provider, _params.sourceToken, _params.targetToken, updatedMargin, _slasher); } } -// File contracts/ln/interface/ILowLevelMessager.sol +// File @zeppelin-solidity/contracts/utils/Context.sol@v4.7.3 // License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) -interface ILowLevelMessageSender { - function registerRemoteReceiver(uint256 remoteChainId, address remoteBridge) external; - function sendMessage(uint256 remoteChainId, bytes memory message, bytes memory params) external payable; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } } -interface ILowLevelMessageReceiver { - function registerRemoteSender(uint256 remoteChainId, address remoteBridge) external; - function recvMessage(address remoteSender, address localReceiver, bytes memory payload) external; +// File @zeppelin-solidity/contracts/security/Pausable.sol@v4.7.3 +// License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol) + + +/** + * @dev Contract module which allows children to implement an emergency stop + * mechanism that can be triggered by an authorized account. + * + * This module is used through inheritance. It will make available the + * modifiers `whenNotPaused` and `whenPaused`, which can be applied to + * the functions of your contract. Note that they will not be pausable by + * simply including this module, only once the modifiers are put in place. + */ +abstract contract Pausable is Context { + /** + * @dev Emitted when the pause is triggered by `account`. + */ + event Paused(address account); + + /** + * @dev Emitted when the pause is lifted by `account`. + */ + event Unpaused(address account); + + bool private _paused; + + /** + * @dev Initializes the contract in unpaused state. + */ + constructor() { + _paused = false; + } + + /** + * @dev Modifier to make a function callable only when the contract is not paused. + * + * Requirements: + * + * - The contract must not be paused. + */ + modifier whenNotPaused() { + _requireNotPaused(); + _; + } + + /** + * @dev Modifier to make a function callable only when the contract is paused. + * + * Requirements: + * + * - The contract must be paused. + */ + modifier whenPaused() { + _requirePaused(); + _; + } + + /** + * @dev Returns true if the contract is paused, and false otherwise. + */ + function paused() public view virtual returns (bool) { + return _paused; + } + + /** + * @dev Throws if the contract is paused. + */ + function _requireNotPaused() internal view virtual { + require(!paused(), "Pausable: paused"); + } + + /** + * @dev Throws if the contract is not paused. + */ + function _requirePaused() internal view virtual { + require(paused(), "Pausable: not paused"); + } + + /** + * @dev Triggers stopped state. + * + * Requirements: + * + * - The contract must not be paused. + */ + function _pause() internal virtual whenNotPaused { + _paused = true; + emit Paused(_msgSender()); + } + + /** + * @dev Returns to normal state. + * + * Requirements: + * + * - The contract must be paused. + */ + function _unpause() internal virtual whenPaused { + _paused = false; + emit Unpaused(_msgSender()); + } +} + +// File contracts/ln/base/LnAccessController.sol +// License-Identifier: MIT + +/// @title LnAccessController +/// @notice LnAccessController is a contract to control the access permission +/// @dev See https://github.com/helix-bridge/contracts/tree/master/helix-contract +contract LnAccessController is Pausable { + address public dao; + address public operator; + + modifier onlyDao() { + require(msg.sender == dao, "!dao"); + _; + } + + modifier onlyOperator() { + require(msg.sender == operator, "!operator"); + _; + } + + function _initialize(address _dao) internal { + dao = _dao; + operator = msg.sender; + } + + function setOperator(address _operator) onlyDao external { + operator = _operator; + } + + function transferOwnership(address _dao) onlyDao external { + dao = _dao; + } + + function unpause() external onlyOperator { + _unpause(); + } + + function pause() external onlyOperator { + _pause(); + } } // File @zeppelin-solidity/contracts/utils/Address.sol@v4.7.3 diff --git a/helix-contract/flatten/lnv2/LnOppositeBridge.sol b/helix-contract/flatten/lnv2/LnOppositeBridge.sol index 4f5d3b21..4ea95370 100644 --- a/helix-contract/flatten/lnv2/LnOppositeBridge.sol +++ b/helix-contract/flatten/lnv2/LnOppositeBridge.sol @@ -14,7 +14,7 @@ * '----------------' '----------------' '----------------' '----------------' '----------------' ' * * - * 9/7/2023 + * 9/11/2023 **/ pragma solidity ^0.8.10; @@ -442,12 +442,13 @@ contract LnOppositeBridgeSource { bytes32 transferId, address provider, address sourceToken, + address targetToken, uint112 amount, uint112 fee, uint64 timestamp, address receiver); - event LiquidityWithdrawn(address provider, address token, uint112 amount); - event Slash(bytes32 transferId, address provider, address token, uint112 margin, address slasher); + event LiquidityWithdrawn(uint256 remoteChainId, address provider, address sourceToken, address targetToken, uint112 amount); + event Slash(uint256 remoteChainId, bytes32 transferId, address provider, address sourceToken, address targetToken, uint112 margin, address slasher); // relayer event LnProviderUpdated(uint256 remoteChainId, address provider, address sourceToken, address targetToken, uint112 margin, uint112 baseFee, uint16 liquidityfeeRate); @@ -564,8 +565,9 @@ contract LnOppositeBridgeSource { require(!providerInfo.config.pause, "provider paused"); - bytes32 tokenKey = LnBridgeHelper.getTokenKey(_snapshot.remoteChainId, _snapshot.sourceToken, _snapshot.targetToken); - LnBridgeHelper.TokenInfo memory tokenInfo = tokenInfos[tokenKey]; + LnBridgeHelper.TokenInfo memory tokenInfo = tokenInfos[ + LnBridgeHelper.getTokenKey(_snapshot.remoteChainId, _snapshot.sourceToken, _snapshot.targetToken) + ]; uint112 providerFee = LnBridgeHelper.calculateProviderFee(providerInfo.config.baseFee, providerInfo.config.liquidityFeeRate, _amount); @@ -577,6 +579,7 @@ contract LnOppositeBridgeSource { require(_snapshot.totalFee >= tokenInfo.protocolFee + providerFee, "fee is invalid"); uint112 targetAmount = LnBridgeHelper.sourceAmountToTargetAmount(tokenInfo, _amount); + require(targetAmount > 0, "invalid amount"); require(block.timestamp < type(uint32).max, "timestamp overflow"); bytes32 transferId = keccak256(abi.encodePacked( block.chainid, @@ -624,7 +627,8 @@ contract LnOppositeBridgeSource { transferId, _snapshot.provider, _snapshot.sourceToken, - _amount, + _snapshot.targetToken, + targetAmount, providerFee, uint64(block.timestamp), _receiver); @@ -670,7 +674,7 @@ contract LnOppositeBridgeSource { LnBridgeHelper.safeTransfer(_sourceToken, _slasher, slashAmount); } - emit Slash(_transferId, _provider, _sourceToken, updatedMargin, _slasher); + emit Slash(_remoteChainId, _transferId, _provider, _sourceToken, _targetToken, updatedMargin, _slasher); } // lastTransfer is the latest slash transfer, all transfer must be relayed or slashed @@ -704,10 +708,23 @@ contract LnOppositeBridgeSource { } else { LnBridgeHelper.safeTransfer(_sourceToken, _provider, _amount); } - emit LiquidityWithdrawn(_provider, _sourceToken, updatedMargin); + emit LiquidityWithdrawn(_remoteChainId, _provider, _sourceToken, _targetToken, updatedMargin); } } +// File contracts/ln/interface/ILowLevelMessager.sol +// License-Identifier: MIT + +interface ILowLevelMessageSender { + function registerRemoteReceiver(uint256 remoteChainId, address remoteBridge) external; + function sendMessage(uint256 remoteChainId, bytes memory message, bytes memory params) external payable; +} + +interface ILowLevelMessageReceiver { + function registerRemoteSender(uint256 remoteChainId, address remoteBridge) external; + function recvMessage(address remoteSender, address localReceiver, bytes memory payload) external; +} + // File contracts/ln/interface/ILnOppositeBridgeSource.sol // License-Identifier: MIT @@ -973,19 +990,6 @@ contract LnOppositeBridgeTarget { } } -// File contracts/ln/interface/ILowLevelMessager.sol -// License-Identifier: MIT - -interface ILowLevelMessageSender { - function registerRemoteReceiver(uint256 remoteChainId, address remoteBridge) external; - function sendMessage(uint256 remoteChainId, bytes memory message, bytes memory params) external payable; -} - -interface ILowLevelMessageReceiver { - function registerRemoteSender(uint256 remoteChainId, address remoteBridge) external; - function recvMessage(address remoteSender, address localReceiver, bytes memory payload) external; -} - // File @zeppelin-solidity/contracts/utils/Address.sol@v4.7.3 // License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)