From 05362b7158387c739011f08384819771baa94936 Mon Sep 17 00:00:00 2001 From: xiaoch05 Date: Wed, 20 Sep 2023 10:53:30 +0800 Subject: [PATCH] add whitelist for messager caller --- .../contracts/ln/base/LnAccessController.sol | 13 ++++++++++++- .../contracts/ln/messager/AxelarMessager.sol | 6 +++--- .../ln/messager/Eth2ArbReceiveService.sol | 12 ++++++------ .../contracts/ln/messager/Eth2ArbSendService.sol | 14 +++++++------- .../ln/messager/Eth2LineaReceiveService.sol | 12 ++++++------ .../ln/messager/Eth2LineaSendService.sol | 15 +++++++-------- .../ln/messager/Eth2ZkSyncReceiveService.sol | 11 ++++++----- .../ln/messager/Eth2ZkSyncSendService.sol | 14 +++++++------- .../contracts/ln/messager/LayerZeroMessager.sol | 12 ++++++++---- .../ln/test/MockEth2ArbReceiveService.sol | 2 +- helix-contract/test/3_test_ln_opposite.js | 10 ++++++++-- helix-contract/test/4_test_ln_layerzero.js | 8 +++++--- 12 files changed, 76 insertions(+), 53 deletions(-) diff --git a/helix-contract/contracts/ln/base/LnAccessController.sol b/helix-contract/contracts/ln/base/LnAccessController.sol index 21ce9453..7b234d2c 100644 --- a/helix-contract/contracts/ln/base/LnAccessController.sol +++ b/helix-contract/contracts/ln/base/LnAccessController.sol @@ -10,6 +10,8 @@ contract LnAccessController is Pausable { address public dao; address public operator; + mapping(address=>bool) public callerWhiteList; + modifier onlyDao() { require(msg.sender == dao, "!dao"); _; @@ -20,15 +22,24 @@ contract LnAccessController is Pausable { _; } + modifier onlyWhiteListCaller() { + require(callerWhiteList[msg.sender], "caller not in white list"); + _; + } + function _initialize(address _dao) internal { dao = _dao; - operator = msg.sender; + operator = _dao; } function setOperator(address _operator) onlyDao external { operator = _operator; } + function authoriseAppCaller(address appAddress, bool enable) onlyOperator external { + callerWhiteList[appAddress] = enable; + } + function transferOwnership(address _dao) onlyDao external { dao = _dao; } diff --git a/helix-contract/contracts/ln/messager/AxelarMessager.sol b/helix-contract/contracts/ln/messager/AxelarMessager.sol index d963ad44..61d6ec1b 100644 --- a/helix-contract/contracts/ln/messager/AxelarMessager.sol +++ b/helix-contract/contracts/ln/messager/AxelarMessager.sol @@ -61,21 +61,21 @@ contract AxelarMessager is LnAccessController { trustedRemotes[_remoteChainName] = _remoteMessager; } - function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); bytes32 key = keccak256(abi.encodePacked(remoteMessager.axRemoteChainName, msg.sender)); remoteAppReceivers[key] = _remoteBridge; } - function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); bytes32 key = keccak256(abi.encodePacked(remoteMessager.axRemoteChainName, msg.sender)); remoteAppSenders[key] = _remoteBridge; } - function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) external payable { + function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) onlyWhiteListCaller external payable { address refunder = address(bytes20(_params)); RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); diff --git a/helix-contract/contracts/ln/messager/Eth2ArbReceiveService.sol b/helix-contract/contracts/ln/messager/Eth2ArbReceiveService.sol index c4b57aaa..29b8560e 100644 --- a/helix-contract/contracts/ln/messager/Eth2ArbReceiveService.sol +++ b/helix-contract/contracts/ln/messager/Eth2ArbReceiveService.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.10; import "@arbitrum/nitro-contracts/src/libraries/AddressAliasHelper.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to arbitrum messager -contract Eth2ArbReceiveService is ILowLevelMessageReceiver { +contract Eth2ArbReceiveService is ILowLevelMessageReceiver, LnAccessController { uint256 immutable public REMOTE_CHAINID; address public remoteMessagerAlias; @@ -16,17 +17,16 @@ contract Eth2ArbReceiveService is ILowLevelMessageReceiver { _; } - constructor(uint256 _remoteChainId) { + constructor(address _dao, uint256 _remoteChainId) { + _initialize(_dao); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { - require(remoteMessagerAlias == address(0), "remote exist"); + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessagerAlias = AddressAliasHelper.applyL1ToL2Alias(_remoteMessager); } - function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } diff --git a/helix-contract/contracts/ln/messager/Eth2ArbSendService.sol b/helix-contract/contracts/ln/messager/Eth2ArbSendService.sol index 51498d22..2aca06ae 100644 --- a/helix-contract/contracts/ln/messager/Eth2ArbSendService.sol +++ b/helix-contract/contracts/ln/messager/Eth2ArbSendService.sol @@ -2,32 +2,32 @@ pragma solidity ^0.8.10; import "@arbitrum/nitro-contracts/src/bridge/IInbox.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to arbitrum messager -contract Eth2ArbSendService is ILowLevelMessageSender { +contract Eth2ArbSendService is ILowLevelMessageSender, LnAccessController { uint256 immutable public REMOTE_CHAINID; IInbox public inbox; address public remoteMessager; mapping(address=>address) public appPairs; - constructor(address _inbox, uint256 _remoteChainId) { + constructor(address _dao, address _inbox, uint256 _remoteChainId) { + _initialize(_dao); inbox = IInbox(_inbox); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { - require(remoteMessager == address(0), "remote exist"); + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessager = _remoteMessager; } - function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } - function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) external payable { + function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) onlyWhiteListCaller external payable { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); address remoteAppAddress = appPairs[msg.sender]; require(remoteAppAddress != address(0), "app not registered"); diff --git a/helix-contract/contracts/ln/messager/Eth2LineaReceiveService.sol b/helix-contract/contracts/ln/messager/Eth2LineaReceiveService.sol index 60ada98f..f91a8971 100644 --- a/helix-contract/contracts/ln/messager/Eth2LineaReceiveService.sol +++ b/helix-contract/contracts/ln/messager/Eth2LineaReceiveService.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.10; import "./interface/ILineaMessageService.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to linea messager -contract Eth2LineaReceiveService is ILowLevelMessageReceiver { +contract Eth2LineaReceiveService is ILowLevelMessageReceiver, LnAccessController { uint256 immutable public REMOTE_CHAINID; ILineaMessageService public messageService; address public remoteMessager; @@ -18,18 +19,17 @@ contract Eth2LineaReceiveService is ILowLevelMessageReceiver { _; } - constructor(address _messageService, uint256 _remoteChainId) { + constructor(address _dao, address _messageService, uint256 _remoteChainId) { + _initialize(_dao); messageService = ILineaMessageService(_messageService); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { - require(remoteMessager == address(0), "remote exist"); + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessager = _remoteMessager; } - function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } diff --git a/helix-contract/contracts/ln/messager/Eth2LineaSendService.sol b/helix-contract/contracts/ln/messager/Eth2LineaSendService.sol index c7819bc4..caa18cbc 100644 --- a/helix-contract/contracts/ln/messager/Eth2LineaSendService.sol +++ b/helix-contract/contracts/ln/messager/Eth2LineaSendService.sol @@ -2,33 +2,33 @@ pragma solidity ^0.8.10; import "./interface/ILineaMessageService.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to linea messager -contract Eth2LineaSendService is ILowLevelMessageSender { +contract Eth2LineaSendService is ILowLevelMessageSender, LnAccessController { uint256 immutable public REMOTE_CHAINID; ILineaMessageService public messageService; address public remoteMessager; mapping(address=>address) public appPairs; - constructor(address _messageService, uint256 _remoteChainId) { + constructor(address _dao, address _messageService, uint256 _remoteChainId) { + _initialize(_dao); messageService = ILineaMessageService(_messageService); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { - require(remoteMessager == address(0), "remote exist"); + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessager = _remoteMessager; } - function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } - function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory) external payable { + function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory) onlyWhiteListCaller external payable { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); address remoteAppAddress = appPairs[msg.sender]; require(remoteAppAddress != address(0), "app not registered"); @@ -46,4 +46,3 @@ contract Eth2LineaSendService is ILowLevelMessageSender { ); } } - diff --git a/helix-contract/contracts/ln/messager/Eth2ZkSyncReceiveService.sol b/helix-contract/contracts/ln/messager/Eth2ZkSyncReceiveService.sol index 9252ad45..cecd7345 100644 --- a/helix-contract/contracts/ln/messager/Eth2ZkSyncReceiveService.sol +++ b/helix-contract/contracts/ln/messager/Eth2ZkSyncReceiveService.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.10; import "./interface/IZksyncMailbox.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to zkSync messager -contract Eth2ZkSyncReceiveService is ILowLevelMessageReceiver { +contract Eth2ZkSyncReceiveService is ILowLevelMessageReceiver, LnAccessController { uint160 constant offset = uint160(0x1111000000000000000000000000000000001111); uint256 immutable public REMOTE_CHAINID; IMailbox public mailbox; @@ -18,17 +19,17 @@ contract Eth2ZkSyncReceiveService is ILowLevelMessageReceiver { _; } - constructor(address _mailbox, uint256 _remoteChainId) { + constructor(address _dao, address _mailbox, uint256 _remoteChainId) { + _initialize(_dao); mailbox = IMailbox(_mailbox); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessagerAlias = address(uint160(_remoteMessager) + offset); } - function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } diff --git a/helix-contract/contracts/ln/messager/Eth2ZkSyncSendService.sol b/helix-contract/contracts/ln/messager/Eth2ZkSyncSendService.sol index 64e6ceb0..b2a8d916 100644 --- a/helix-contract/contracts/ln/messager/Eth2ZkSyncSendService.sol +++ b/helix-contract/contracts/ln/messager/Eth2ZkSyncSendService.sol @@ -2,33 +2,33 @@ pragma solidity ^0.8.10; import "./interface/IZksyncMailbox.sol"; +import "../base/LnAccessController.sol"; import "../interface/ILowLevelMessager.sol"; // from ethereum to zkSync messager -contract Eth2ZkSyncSendService is ILowLevelMessageSender { +contract Eth2ZkSyncSendService is ILowLevelMessageSender, LnAccessController { uint256 immutable public REMOTE_CHAINID; IMailbox public mailbox; address public remoteMessager; mapping(address=>address) public appPairs; - constructor(address _mailbox, uint256 _remoteChainId) { + constructor(address _dao, address _mailbox, uint256 _remoteChainId) { + _initialize(_dao); mailbox = IMailbox(_mailbox); REMOTE_CHAINID = _remoteChainId; } - // only can be set once - function setRemoteMessager(address _remoteMessager) external { - require(remoteMessager == address(0), "remote exist"); + function setRemoteMessager(address _remoteMessager) onlyOperator external { remoteMessager = _remoteMessager; } - function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); appPairs[msg.sender] = _remoteBridge; } - function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) external payable { + function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) onlyWhiteListCaller external payable { require(_remoteChainId == REMOTE_CHAINID, "invalid remote chainId"); address remoteAppAddress = appPairs[msg.sender]; require(remoteAppAddress != address(0), "app not registered"); diff --git a/helix-contract/contracts/ln/messager/LayerZeroMessager.sol b/helix-contract/contracts/ln/messager/LayerZeroMessager.sol index e03a316d..80e2a397 100644 --- a/helix-contract/contracts/ln/messager/LayerZeroMessager.sol +++ b/helix-contract/contracts/ln/messager/LayerZeroMessager.sol @@ -24,6 +24,7 @@ contract LayerZeroMessager is LnAccessController { mapping(bytes32=>address) public remoteAppSenders; event CallResult(uint16 lzRemoteChainId, bytes srcAddress, bool successed); + event CallerUnMatched(uint16 lzRemoteChainId, bytes srcAddress, address remoteAppAddress); constructor(address _dao, address _endpoint) { _initialize(_dao); @@ -41,21 +42,21 @@ contract LayerZeroMessager is LnAccessController { trustedRemotes[_lzRemoteChainId] = keccak256(abi.encodePacked(_remoteMessager, address(this))); } - function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteReceiver(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); bytes32 key = keccak256(abi.encodePacked(remoteMessager.lzRemoteChainId, msg.sender)); remoteAppReceivers[key] = _remoteBridge; } - function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) external { + function registerRemoteSender(uint256 _remoteChainId, address _remoteBridge) onlyWhiteListCaller external { RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); bytes32 key = keccak256(abi.encodePacked(remoteMessager.lzRemoteChainId, msg.sender)); remoteAppSenders[key] = _remoteBridge; } - function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) external payable { + function sendMessage(uint256 _remoteChainId, bytes memory _message, bytes memory _params) onlyWhiteListCaller external payable { address refunder = address(bytes20(_params)); RemoteMessager memory remoteMessager = remoteMessagers[_remoteChainId]; require(remoteMessager.messager != address(0), "remote not configured"); @@ -86,7 +87,10 @@ contract LayerZeroMessager is LnAccessController { // call (address remoteAppAddress, address localAppAddress, bytes memory message) = abi.decode(_payload, (address, address, bytes)); bytes32 key = keccak256(abi.encodePacked(_srcChainId, localAppAddress)); - require(remoteAppAddress == remoteAppSenders[key], "invalid remote address"); + if (remoteAppAddress != remoteAppSenders[key]) { + emit CallerUnMatched(_srcChainId, _srcAddress, remoteAppAddress); + return; + } (bool success,) = localAppAddress.call(message); // don't revert to prevent message block emit CallResult(_srcChainId, _srcAddress, success); diff --git a/helix-contract/contracts/ln/test/MockEth2ArbReceiveService.sol b/helix-contract/contracts/ln/test/MockEth2ArbReceiveService.sol index 7180c528..44de548b 100644 --- a/helix-contract/contracts/ln/test/MockEth2ArbReceiveService.sol +++ b/helix-contract/contracts/ln/test/MockEth2ArbReceiveService.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.10; import "../messager/Eth2ArbReceiveService.sol"; contract MockEth2ArbReceiveService is Eth2ArbReceiveService { - constructor(uint256 _remoteChainId) Eth2ArbReceiveService(_remoteChainId) {} + constructor(address _dao, uint256 _remoteChainId) Eth2ArbReceiveService(_dao, _remoteChainId) {} function setRemoteMessagerAlias(address _remoteMessagerAlias) external { remoteMessagerAlias = _remoteMessagerAlias; diff --git a/helix-contract/test/3_test_ln_opposite.js b/helix-contract/test/3_test_ln_opposite.js index e35a0d02..1471d939 100644 --- a/helix-contract/test/3_test_ln_opposite.js +++ b/helix-contract/test/3_test_ln_opposite.js @@ -122,10 +122,10 @@ describe("eth->arb lnv2 positive bridge tests", () => { // eth -> arb messager service console.log("deploy etherum to arbitrum l1->l2 message service"); const eth2arbSendServiceContract = await ethers.getContractFactory("Eth2ArbSendService"); - const eth2arbSendService = await eth2arbSendServiceContract.deploy(inbox.address, arbChainId); + const eth2arbSendService = await eth2arbSendServiceContract.deploy(dao, inbox.address, arbChainId); await eth2arbSendService.deployed(); const eth2arbRecvServiceContract = await ethers.getContractFactory("MockEth2ArbReceiveService"); - const eth2arbRecvService = await eth2arbRecvServiceContract.deploy(ethChainId); + const eth2arbRecvService = await eth2arbRecvServiceContract.deploy(dao, ethChainId); await eth2arbRecvService.deployed(); await eth2arbSendService.setRemoteMessager(eth2arbRecvService.address); @@ -151,6 +151,12 @@ describe("eth->arb lnv2 positive bridge tests", () => { console.log("messager service deploy finished"); console.log("configure message service for token bridge"); + // authorise + await eth2arbSendService.authoriseAppCaller(ethBridge.address, true); + await eth2arbRecvService.authoriseAppCaller(arbBridge.address, true); + await lzMessagerEth.authoriseAppCaller(ethBridge.address, true); + await lzMessagerArb.authoriseAppCaller(arbBridge.address, true); + await ethBridge.setSendService(arbChainId, arbBridge.address, eth2arbSendService.address); await ethBridge.setReceiveService(arbChainId, arbBridge.address, lzMessagerEth.address); await arbBridge.setSendService(ethChainId, ethBridge.address, lzMessagerArb.address); diff --git a/helix-contract/test/4_test_ln_layerzero.js b/helix-contract/test/4_test_ln_layerzero.js index 4db597d3..79fd0be3 100644 --- a/helix-contract/test/4_test_ln_layerzero.js +++ b/helix-contract/test/4_test_ln_layerzero.js @@ -152,8 +152,10 @@ describe("eth->arb lnv2 layerzero bridge tests", () => { // ******************* register token ************** // set bridge infos - lnDefaultBridgeEth.setSendService(arbChainId, lnDefaultBridgeArb.address, lzMessagerEth.address); - lnDefaultBridgeArb.setReceiveService(ethChainId, lnDefaultBridgeEth.address, lzMessagerArb.address); + await lzMessagerEth.authoriseAppCaller(lnDefaultBridgeEth.address, true); + await lzMessagerArb.authoriseAppCaller(lnDefaultBridgeArb.address, true); + await lnDefaultBridgeEth.setSendService(arbChainId, lnDefaultBridgeArb.address, lzMessagerEth.address); + await lnDefaultBridgeArb.setReceiveService(ethChainId, lnDefaultBridgeEth.address, lzMessagerArb.address); console.log("deploy bridge finished"); // provider @@ -303,7 +305,7 @@ describe("eth->arb lnv2 layerzero bridge tests", () => { )); expect(fillInfo.timestamp).to.equal(relayTimestamp); expect(balanceOfUserAfter - balanceOfUser).to.equal(transferAmount); - expect(balanceOfSlasherAfter - balanceOfSlasher).to.equal(penalty + totalFee); + expect(balanceOfSlasherAfter - balanceOfSlasher).to.equal(penalty + totalFee - protocolFee); } expect(fillInfo.slasher).to.equal(slasher.address); return slashTransaction;