From 4b53b6b225b4d589e248ae56fafd0c73c41ec2f0 Mon Sep 17 00:00:00 2001 From: Stanley Date: Tue, 30 Jul 2024 17:29:50 -0400 Subject: [PATCH 01/19] forge install: lxly-bridge-and-call --- .gitmodules | 3 +++ lib/lxly-bridge-and-call | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/lxly-bridge-and-call diff --git a/.gitmodules b/.gitmodules index 86d572d1..e230d117 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "lib/PermitC"] path = lib/PermitC url = https://github.com/limitbreakinc/PermitC +[submodule "lib/lxly-bridge-and-call"] + path = lib/lxly-bridge-and-call + url = https://github.com/agglayer/lxly-bridge-and-call diff --git a/lib/lxly-bridge-and-call b/lib/lxly-bridge-and-call new file mode 160000 index 00000000..b765fb4a --- /dev/null +++ b/lib/lxly-bridge-and-call @@ -0,0 +1 @@ +Subproject commit b765fb4a98bf947b6fa4a62f41da7b7657d10783 From 916976d34709b8b4d4ea414a95f75a01d37765ce Mon Sep 17 00:00:00 2001 From: Stanley Date: Tue, 30 Jul 2024 17:35:41 -0400 Subject: [PATCH 02/19] implemented PoC of bridge and call module --- remappings.txt | 1 + .../transferable/BridgeAndCallERC721.sol | 126 ++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 src/module/token/transferable/BridgeAndCallERC721.sol diff --git a/remappings.txt b/remappings.txt index 413cecc2..3f5f9b65 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,3 +5,4 @@ forge-std/=lib/forge-std/src/ @erc721a-upgradeable/=lib/ERC721A-Upgradeable/contracts/ @limitbreak/creator-token-standards/=lib/creator-token-standards/src/ @limitbreak/permit-c/=lib/PermitC/src/ +@lxly-bridge-and-call/=lib/lxly-bridge-and-call/src/ diff --git a/src/module/token/transferable/BridgeAndCallERC721.sol b/src/module/token/transferable/BridgeAndCallERC721.sol new file mode 100644 index 00000000..ab4bf71e --- /dev/null +++ b/src/module/token/transferable/BridgeAndCallERC721.sol @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {ModularExtension} from "../../../ModularExtension.sol"; +import {Role} from "../../../Role.sol"; +import {BeforeTransferCallbackERC721} from "../../../callback/BeforeTransferCallbackERC721.sol"; +import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; + +library BridgeAndCallStorage { + /// @custom:storage-location erc7201:token.bridgeAndCall + bytes32 public constant BRIDGE_AND_CALL_STORAGE_POSITION = + keccak256(abi.encode(uint256(keccak256("token.bridgeAndCall")) - 1)) & + ~bytes32(uint256(0xff)); + + struct Data { + address bridgeExtension; + } + + function data() internal pure returns (Data storage data_) { + bytes32 position = BRIDGE_AND_CALL_STORAGE_POSITION; + assembly { + data_.slot := position + } + } +} + +contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { + /*////////////////////////////////////////////////////////////// + ERRORS + //////////////////////////////////////////////////////////////*/ + + /// @notice Emitted on attempt to transfer a token when the bridge extension is not set. + error bridgeExtensionNotSet(); + + /*////////////////////////////////////////////////////////////// + EXTENSION CONFIG + //////////////////////////////////////////////////////////////*/ + + /// @notice Returns all implemented callback and extension functions. + function getExtensionConfig() + external + pure + override + returns (ExtensionConfig memory config) + { + config.fallbackFunctions = new FallbackFunction[](4); + + config.fallbackFunctions[0] = FallbackFunction({ + selector: this.getBridgeExtension.selector, + permissionBits: 0 + }); + config.fallbackFunctions[1] = FallbackFunction({ + selector: this.setBridgeExtension.selector, + permissionBits: Role._MANAGER_ROLE + }); + config.fallbackFunctions[2] = FallbackFunction({ + selector: this.bridgeAndCall.selector, + permissionBits: 0 + }); + + config.requiredInterfaces = new bytes4[](1); + config.requiredInterfaces[0] = 0x80ac58cd; // ERC721. + + config.registerInstallationCallback = true; + } + + /// @dev Called by a Core into an Extension during the installation of the Extension. + function onInstall(bytes calldata data) external { + address bridgeExtension = abi.decode(data, (address)); + _bridgeAndCallStorage().bridgeExtension = bridgeExtension; + } + + /// @dev Called by a Core into an Extension during the uninstallation of the Extension. + function onUninstall(bytes calldata data) external {} + + /*////////////////////////////////////////////////////////////// + FALLBACK FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + /// @notice Returns whether transfers is enabled for the token. + function getBridgeExtension() external view returns (address) { + return _bridgeAndCallStorage().bridgeExtension; + } + + /// @notice Set transferability for a token. + function setBridgeExtension(address enableTransfer) external { + _bridgeAndCallStorage().bridgeExtension = enableTransfer; + } + + /// @notice Set transferability for a token. + function bridgeAndCall( + uint256 amount, + uint32 destinationNetwork, + address callAddress, + address fallbackAddress, + bytes calldata callData, + bool forceUpdateGlobalExitRoot + ) external { + address bridgeExtension = _bridgeAndCallStorage().bridgeExtension; + if (bridgeExtension == address(0)) { + revert bridgeExtensionNotSet(); + } + + IBridgeAndCall(bridgeExtension).bridgeAndCall( + address(this), + amount, + destinationNetwork, + callAddress, + fallbackAddress, + callData, + forceUpdateGlobalExitRoot + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function _bridgeAndCallStorage() + internal + pure + returns (BridgeAndCallStorage.Data storage) + { + return BridgeAndCallStorage.data(); + } +} From 7015bc573176f3fb23aefb82515eacc7713bbdd6 Mon Sep 17 00:00:00 2001 From: Stanley Date: Fri, 23 Aug 2024 14:20:56 -0400 Subject: [PATCH 03/19] updated from extension to module --- .../transferable/BridgeAndCallERC721.sol | 76 +++++++------------ 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/src/module/token/transferable/BridgeAndCallERC721.sol b/src/module/token/transferable/BridgeAndCallERC721.sol index ab4bf71e..d24539ea 100644 --- a/src/module/token/transferable/BridgeAndCallERC721.sol +++ b/src/module/token/transferable/BridgeAndCallERC721.sol @@ -1,19 +1,19 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {ModularExtension} from "../../../ModularExtension.sol"; +import {ModularModule} from "../../../ModularModule.sol"; import {Role} from "../../../Role.sol"; import {BeforeTransferCallbackERC721} from "../../../callback/BeforeTransferCallbackERC721.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; library BridgeAndCallStorage { + /// @custom:storage-location erc7201:token.bridgeAndCall bytes32 public constant BRIDGE_AND_CALL_STORAGE_POSITION = - keccak256(abi.encode(uint256(keccak256("token.bridgeAndCall")) - 1)) & - ~bytes32(uint256(0xff)); + keccak256(abi.encode(uint256(keccak256("token.bridgeAndCall")) - 1)) & ~bytes32(uint256(0xff)); struct Data { - address bridgeExtension; + address bridgeModule; } function data() internal pure returns (Data storage data_) { @@ -22,41 +22,30 @@ library BridgeAndCallStorage { data_.slot := position } } + } -contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { +contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { + /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ /// @notice Emitted on attempt to transfer a token when the bridge extension is not set. - error bridgeExtensionNotSet(); + error bridgeModuleNotSet(); /*////////////////////////////////////////////////////////////// EXTENSION CONFIG //////////////////////////////////////////////////////////////*/ /// @notice Returns all implemented callback and extension functions. - function getExtensionConfig() - external - pure - override - returns (ExtensionConfig memory config) - { + function getModuleConfig() external pure override returns (ModuleConfig memory config) { config.fallbackFunctions = new FallbackFunction[](4); - config.fallbackFunctions[0] = FallbackFunction({ - selector: this.getBridgeExtension.selector, - permissionBits: 0 - }); - config.fallbackFunctions[1] = FallbackFunction({ - selector: this.setBridgeExtension.selector, - permissionBits: Role._MANAGER_ROLE - }); - config.fallbackFunctions[2] = FallbackFunction({ - selector: this.bridgeAndCall.selector, - permissionBits: 0 - }); + config.fallbackFunctions[0] = FallbackFunction({selector: this.getBridgeModule.selector, permissionBits: 0}); + config.fallbackFunctions[1] = + FallbackFunction({selector: this.setBridgeModule.selector, permissionBits: Role._MANAGER_ROLE}); + config.fallbackFunctions[2] = FallbackFunction({selector: this.bridgeAndCall.selector, permissionBits: 0}); config.requiredInterfaces = new bytes4[](1); config.requiredInterfaces[0] = 0x80ac58cd; // ERC721. @@ -64,13 +53,13 @@ contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { config.registerInstallationCallback = true; } - /// @dev Called by a Core into an Extension during the installation of the Extension. + /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - address bridgeExtension = abi.decode(data, (address)); - _bridgeAndCallStorage().bridgeExtension = bridgeExtension; + address bridgeModule = abi.decode(data, (address)); + _bridgeAndCallStorage().bridgeModule = bridgeModule; } - /// @dev Called by a Core into an Extension during the uninstallation of the Extension. + /// @dev Called by a Core into an Module during the uninstallation of the Module. function onUninstall(bytes calldata data) external {} /*////////////////////////////////////////////////////////////// @@ -78,13 +67,13 @@ contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { //////////////////////////////////////////////////////////////*/ /// @notice Returns whether transfers is enabled for the token. - function getBridgeExtension() external view returns (address) { - return _bridgeAndCallStorage().bridgeExtension; + function getBridgeModule() external view returns (address) { + return _bridgeAndCallStorage().bridgeModule; } /// @notice Set transferability for a token. - function setBridgeExtension(address enableTransfer) external { - _bridgeAndCallStorage().bridgeExtension = enableTransfer; + function setBridgeModule(address enableTransfer) external { + _bridgeAndCallStorage().bridgeModule = enableTransfer; } /// @notice Set transferability for a token. @@ -96,19 +85,13 @@ contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { bytes calldata callData, bool forceUpdateGlobalExitRoot ) external { - address bridgeExtension = _bridgeAndCallStorage().bridgeExtension; - if (bridgeExtension == address(0)) { - revert bridgeExtensionNotSet(); + address bridgeModule = _bridgeAndCallStorage().bridgeModule; + if (bridgeModule == address(0)) { + revert bridgeModuleNotSet(); } - IBridgeAndCall(bridgeExtension).bridgeAndCall( - address(this), - amount, - destinationNetwork, - callAddress, - fallbackAddress, - callData, - forceUpdateGlobalExitRoot + IBridgeAndCall(bridgeModule).bridgeAndCall( + address(this), amount, destinationNetwork, callAddress, fallbackAddress, callData, forceUpdateGlobalExitRoot ); } @@ -116,11 +99,8 @@ contract BridgeAndCallERC721 is ModularExtension, BeforeTransferCallbackERC721 { INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ - function _bridgeAndCallStorage() - internal - pure - returns (BridgeAndCallStorage.Data storage) - { + function _bridgeAndCallStorage() internal pure returns (BridgeAndCallStorage.Data storage) { return BridgeAndCallStorage.data(); } + } From 300ccae13a7520a34e5eb4c3c4d4cde6078145d3 Mon Sep 17 00:00:00 2001 From: Stanley Date: Mon, 16 Sep 2024 17:06:17 -0400 Subject: [PATCH 04/19] updated to align with unified crosschain interface --- .../PolygonAgglayer.sol} | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) rename src/module/token/{transferable/BridgeAndCallERC721.sol => crosschain/PolygonAgglayer.sol} (70%) diff --git a/src/module/token/transferable/BridgeAndCallERC721.sol b/src/module/token/crosschain/PolygonAgglayer.sol similarity index 70% rename from src/module/token/transferable/BridgeAndCallERC721.sol rename to src/module/token/crosschain/PolygonAgglayer.sol index d24539ea..9d3c0516 100644 --- a/src/module/token/transferable/BridgeAndCallERC721.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,7 +6,7 @@ import {Role} from "../../../Role.sol"; import {BeforeTransferCallbackERC721} from "../../../callback/BeforeTransferCallbackERC721.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; -library BridgeAndCallStorage { +library PolygonAgglayerCrossChainStorage { /// @custom:storage-location erc7201:token.bridgeAndCall bytes32 public constant BRIDGE_AND_CALL_STORAGE_POSITION = @@ -25,7 +25,7 @@ library BridgeAndCallStorage { } -contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { +contract PolygonAgglayerCrossChainERC721 is ModularModule, BeforeTransferCallbackERC721 { /*////////////////////////////////////////////////////////////// ERRORS @@ -45,7 +45,8 @@ contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { config.fallbackFunctions[0] = FallbackFunction({selector: this.getBridgeModule.selector, permissionBits: 0}); config.fallbackFunctions[1] = FallbackFunction({selector: this.setBridgeModule.selector, permissionBits: Role._MANAGER_ROLE}); - config.fallbackFunctions[2] = FallbackFunction({selector: this.bridgeAndCall.selector, permissionBits: 0}); + config.fallbackFunctions[2] = + FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); config.requiredInterfaces = new bytes4[](1); config.requiredInterfaces[0] = 0x80ac58cd; // ERC721. @@ -56,7 +57,7 @@ contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { address bridgeModule = abi.decode(data, (address)); - _bridgeAndCallStorage().bridgeModule = bridgeModule; + _polygonAgglayerStorage().bridgeModule = bridgeModule; } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -68,30 +69,37 @@ contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { /// @notice Returns whether transfers is enabled for the token. function getBridgeModule() external view returns (address) { - return _bridgeAndCallStorage().bridgeModule; + return _polygonAgglayerStorage().bridgeModule; } /// @notice Set transferability for a token. - function setBridgeModule(address enableTransfer) external { - _bridgeAndCallStorage().bridgeModule = enableTransfer; + function setBridgeModule(address bridgeModule) external { + _polygonAgglayerStorage().bridgeModule = bridgeModule; } - /// @notice Set transferability for a token. - function bridgeAndCall( - uint256 amount, - uint32 destinationNetwork, - address callAddress, - address fallbackAddress, - bytes calldata callData, - bool forceUpdateGlobalExitRoot + function sendCrossChainTransaction( + uint64 _destinationChain, + address _callAddress, + address _recipient, + address _token, + uint256 _amount, + bytes calldata _data, + bytes calldata _extraArgs ) external { - address bridgeModule = _bridgeAndCallStorage().bridgeModule; + address bridgeModule = _polygonAgglayerStorage().bridgeModule; if (bridgeModule == address(0)) { revert bridgeModuleNotSet(); } + (address _fallbackAddress, bool _forceUpdateGlobalExitRoot) = abi.decode(_extraArgs, (address, bool)); IBridgeAndCall(bridgeModule).bridgeAndCall( - address(this), amount, destinationNetwork, callAddress, fallbackAddress, callData, forceUpdateGlobalExitRoot + address(this), + _amount, + uint32(_destinationChain), + _callAddress, + _fallbackAddress, + _data, + _forceUpdateGlobalExitRoot ); } @@ -99,8 +107,8 @@ contract BridgeAndCallERC721 is ModularModule, BeforeTransferCallbackERC721 { INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ - function _bridgeAndCallStorage() internal pure returns (BridgeAndCallStorage.Data storage) { - return BridgeAndCallStorage.data(); + function _polygonAgglayerStorage() internal pure returns (PolygonAgglayerCrossChainStorage.Data storage) { + return PolygonAgglayerCrossChainStorage.data(); } } From d02912e1e1a92bbcbc7600e6312973d7120b3c00 Mon Sep 17 00:00:00 2001 From: Stanley Date: Tue, 8 Oct 2024 14:56:49 -0400 Subject: [PATCH 05/19] updated to align with CrossChain contract --- .../token/crosschain/PolygonAgglayer.sol | 92 +++++++++++-------- 1 file changed, 53 insertions(+), 39 deletions(-) diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index 9d3c0516..ddbfeaa1 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {ModularModule} from "../../../ModularModule.sol"; +import {Module} from "../../../Module.sol"; import {Role} from "../../../Role.sol"; -import {BeforeTransferCallbackERC721} from "../../../callback/BeforeTransferCallbackERC721.sol"; + +import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; library PolygonAgglayerCrossChainStorage { @@ -13,7 +14,7 @@ library PolygonAgglayerCrossChainStorage { keccak256(abi.encode(uint256(keccak256("token.bridgeAndCall")) - 1)) & ~bytes32(uint256(0xff)); struct Data { - address bridgeModule; + address router; } function data() internal pure returns (Data storage data_) { @@ -25,88 +26,101 @@ library PolygonAgglayerCrossChainStorage { } -contract PolygonAgglayerCrossChainERC721 is ModularModule, BeforeTransferCallbackERC721 { - - /*////////////////////////////////////////////////////////////// - ERRORS - //////////////////////////////////////////////////////////////*/ - - /// @notice Emitted on attempt to transfer a token when the bridge extension is not set. - error bridgeModuleNotSet(); +contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { /*////////////////////////////////////////////////////////////// EXTENSION CONFIG //////////////////////////////////////////////////////////////*/ - /// @notice Returns all implemented callback and extension functions. + /// @notice Returns all implemented callback and fallback functions. function getModuleConfig() external pure override returns (ModuleConfig memory config) { - config.fallbackFunctions = new FallbackFunction[](4); + config.fallbackFunctions = new FallbackFunction[](3); - config.fallbackFunctions[0] = FallbackFunction({selector: this.getBridgeModule.selector, permissionBits: 0}); + config.fallbackFunctions[0] = FallbackFunction({selector: this.getRouter.selector, permissionBits: 0}); config.fallbackFunctions[1] = - FallbackFunction({selector: this.setBridgeModule.selector, permissionBits: Role._MANAGER_ROLE}); + FallbackFunction({selector: this.setRouter.selector, permissionBits: Role._MANAGER_ROLE}); config.fallbackFunctions[2] = FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); - - config.requiredInterfaces = new bytes4[](1); - config.requiredInterfaces[0] = 0x80ac58cd; // ERC721. - - config.registerInstallationCallback = true; } /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - address bridgeModule = abi.decode(data, (address)); - _polygonAgglayerStorage().bridgeModule = bridgeModule; + address router = abi.decode(data, (address)); + _polygonAgglayerStorage().router = router; } /// @dev Called by a Core into an Module during the uninstallation of the Module. function onUninstall(bytes calldata data) external {} + /// @dev Returns bytes encoded install params, to be sent to `onInstall` function + function encodeBytesOnInstall(address router) external pure returns (bytes memory) { + return abi.encode(router); + } + + /// @dev Returns bytes encoded uninstall params, to be sent to `onUninstall` function + function encodeBytesOnUninstall() external pure returns (bytes memory) { + return ""; + } + /*////////////////////////////////////////////////////////////// FALLBACK FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @notice Returns whether transfers is enabled for the token. - function getBridgeModule() external view returns (address) { - return _polygonAgglayerStorage().bridgeModule; + function getRouter() external view override returns (address) { + return _polygonAgglayerStorage().router; } /// @notice Set transferability for a token. - function setBridgeModule(address bridgeModule) external { - _polygonAgglayerStorage().bridgeModule = bridgeModule; + function setRouter(address router) external override { + _polygonAgglayerStorage().router = router; } function sendCrossChainTransaction( uint64 _destinationChain, address _callAddress, - address _recipient, - address _token, - uint256 _amount, - bytes calldata _data, + bytes calldata _payload, bytes calldata _extraArgs - ) external { - address bridgeModule = _polygonAgglayerStorage().bridgeModule; - if (bridgeModule == address(0)) { - revert bridgeModuleNotSet(); - } - (address _fallbackAddress, bool _forceUpdateGlobalExitRoot) = abi.decode(_extraArgs, (address, bool)); + ) external payable override { + address router = _polygonAgglayerStorage().router; + (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount) = + abi.decode(_extraArgs, (address, bool, address, uint256)); - IBridgeAndCall(bridgeModule).bridgeAndCall( - address(this), + IBridgeAndCall(router).bridgeAndCall( + _token, _amount, uint32(_destinationChain), _callAddress, _fallbackAddress, - _data, + _payload, _forceUpdateGlobalExitRoot ); + + onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ + function onCrossChainTransactionSent( + uint64 _destinationChain, + address _callAddress, + bytes calldata _payload, + bytes calldata _extraArgs + ) internal override { + /// post cross chain transaction sent logic goes here + } + + function onCrossChainTransactionReceived( + uint64 _sourceChain, + address _sourceAddress, + bytes memory _payload, + bytes memory _extraArgs + ) internal override { + /// post cross chain transaction received logic goes here + } + function _polygonAgglayerStorage() internal pure returns (PolygonAgglayerCrossChainStorage.Data storage) { return PolygonAgglayerCrossChainStorage.data(); } From 5ed97bd3385fa2be2b2dcba937c83803cb34b0d8 Mon Sep 17 00:00:00 2001 From: Stanley Date: Thu, 31 Oct 2024 18:30:25 -0400 Subject: [PATCH 06/19] updated to incorporate bridgeAsset and bridgeMessage --- remappings.txt | 1 + .../token/crosschain/PolygonAgglayer.sol | 39 ++++++++++++------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/remappings.txt b/remappings.txt index 3f5f9b65..22272ee9 100644 --- a/remappings.txt +++ b/remappings.txt @@ -6,3 +6,4 @@ forge-std/=lib/forge-std/src/ @limitbreak/creator-token-standards/=lib/creator-token-standards/src/ @limitbreak/permit-c/=lib/PermitC/src/ @lxly-bridge-and-call/=lib/lxly-bridge-and-call/src/ +@zkevm-contracts/=lib/lxly-bridge-and-call/lib/zkevm-contracts/contracts/ diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index ddbfeaa1..5fc0095b 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,6 +6,7 @@ import {Role} from "../../../Role.sol"; import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; +import {PolygonZkEVMBridgeV2} from "@zkevm-contracts/v2/PolygonZkEVMBridgeV2.sol"; library PolygonAgglayerCrossChainStorage { @@ -15,6 +16,7 @@ library PolygonAgglayerCrossChainStorage { struct Data { address router; + address bridge; } function data() internal pure returns (Data storage data_) { @@ -45,8 +47,9 @@ contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - address router = abi.decode(data, (address)); + (address router, address bridge) = abi.decode(data, (address, address)); _polygonAgglayerStorage().router = router; + _polygonAgglayerStorage().bridge = bridge; } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -83,18 +86,28 @@ contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { bytes calldata _extraArgs ) external payable override { address router = _polygonAgglayerStorage().router; - (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount) = - abi.decode(_extraArgs, (address, bool, address, uint256)); - - IBridgeAndCall(router).bridgeAndCall( - _token, - _amount, - uint32(_destinationChain), - _callAddress, - _fallbackAddress, - _payload, - _forceUpdateGlobalExitRoot - ); + (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount, bytes memory permitData) = + abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); + + if (_token == address(0) && _amount == 0) { + PolygonZkEVMBridgeV2(router).bridgeMessage( + uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload + ); + } else if (_payload.length == 0) { + PolygonZkEVMBridgeV2(router).bridgeAsset( + uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, _permitData) + ); + } else { + IBridgeAndCall(router).bridgeAndCall( + _token, + _amount, + uint32(_destinationChain), + _callAddress, + _fallbackAddress, + _payload, + _forceUpdateGlobalExitRoot + ); + } onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } From 8d76cce1887e9bf0a3614b01123f2db6580fbdaf Mon Sep 17 00:00:00 2001 From: Stanley Date: Sun, 10 Nov 2024 12:40:51 -0500 Subject: [PATCH 07/19] WIP: middle of testing out agglayer content --- script/agglayer/Agglayer.s.sol | 61 +++++++++++++++++++ script/agglayer/TestNFT.sol | 17 ++++++ .../token/crosschain/PolygonAgglayer.sol | 41 +++++-------- 3 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 script/agglayer/Agglayer.s.sol create mode 100644 script/agglayer/TestNFT.sol diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol new file mode 100644 index 00000000..ad0d74bc --- /dev/null +++ b/script/agglayer/Agglayer.s.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {Script} from "forge-std/Script.sol"; +import {TestNFT} from "./TestNFT.sol"; +import {console} from "forge-std/console.sol"; +import {Role} from "src/Role.sol"; +import {PolygonAgglayerCrossChain} from "src/module/token/crosschain/PolygonAgglayer.sol"; +import {ERC20Base} from "src/core/token/ERC20Base.sol"; +import {OwnableRoles} from "@solady/auth/OwnableRoles.sol"; + +contract DeployTestNFT is Script { + TestNFT public testNFT; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + testNFT = new TestNFT("TestNFT", "TNFT"); + console.log("TestNFT deployed to:", address(testNFT)); + + vm.stopBroadcast(); + } +} + +contract MintTestNFT is Script { + TestNFT public testNFT; + ERC20Base public testToken; + + function run() external { + uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); + address deployerAddress = vm.addr(deployerPrivateKey); + address testNFTAddress = vm.envAddress("TEST_NFT_ADDRESS"); + address testTokenAddress = vm.envAddress("TEST_TOKEN_ADDRESS"); + uint64 destinationChain = 2442; + vm.startBroadcast(deployerPrivateKey); + + testNFT = TestNFT(testNFTAddress); + testToken = ERC20Base(payable(testTokenAddress)); + + OwnableRoles(testTokenAddress).grantRoles(deployerAddress, Role._MINTER_ROLE); + testToken.mint(deployerAddress, 100, ""); + console.log("Minted test tokens to deployer"); + + bytes memory extraArgs = abi.encode(address(0), false, testToken, 100); + bytes memory payload = abi.encodeWithSelector( + bytes4(keccak256("mint(address,uint256)")), + deployerAddress, + 1 + ); + + PolygonAgglayerCrossChain(testTokenAddress).sendCrossChainTransaction( + destinationChain, + address(testNFT), + payload, + extraArgs + ); + + vm.stopBroadcast(); + } +} diff --git a/script/agglayer/TestNFT.sol b/script/agglayer/TestNFT.sol new file mode 100644 index 00000000..41737494 --- /dev/null +++ b/script/agglayer/TestNFT.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import {ERC721A} from "@erc721a/ERC721A.sol"; + +contract TestNFT is ERC721A { + constructor( + string memory _name, + string memory _symbol + ) ERC721A(_name, _symbol) {} + + function mint(address to, uint256 amount) public { + _mint(to, amount); + } +} + + diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index 5fc0095b..237145ff 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,7 +6,6 @@ import {Role} from "../../../Role.sol"; import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; -import {PolygonZkEVMBridgeV2} from "@zkevm-contracts/v2/PolygonZkEVMBridgeV2.sol"; library PolygonAgglayerCrossChainStorage { @@ -16,7 +15,6 @@ library PolygonAgglayerCrossChainStorage { struct Data { address router; - address bridge; } function data() internal pure returns (Data storage data_) { @@ -28,7 +26,7 @@ library PolygonAgglayerCrossChainStorage { } -contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { +contract PolygonAgglayerCrossChain is Module, CrossChain { /*////////////////////////////////////////////////////////////// EXTENSION CONFIG @@ -47,9 +45,8 @@ contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - (address router, address bridge) = abi.decode(data, (address, address)); + address router = abi.decode(data, (address)); _polygonAgglayerStorage().router = router; - _polygonAgglayerStorage().bridge = bridge; } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -86,28 +83,18 @@ contract PolygonAgglayerCrossChainERC721 is Module, CrossChain { bytes calldata _extraArgs ) external payable override { address router = _polygonAgglayerStorage().router; - (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount, bytes memory permitData) = - abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); - - if (_token == address(0) && _amount == 0) { - PolygonZkEVMBridgeV2(router).bridgeMessage( - uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload - ); - } else if (_payload.length == 0) { - PolygonZkEVMBridgeV2(router).bridgeAsset( - uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, _permitData) - ); - } else { - IBridgeAndCall(router).bridgeAndCall( - _token, - _amount, - uint32(_destinationChain), - _callAddress, - _fallbackAddress, - _payload, - _forceUpdateGlobalExitRoot - ); - } + (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount) = + abi.decode(_extraArgs, (address, bool, address, uint256)); + + IBridgeAndCall(router).bridgeAndCall( + _token, + _amount, + uint32(_destinationChain), + _callAddress, + _fallbackAddress, + _payload, + _forceUpdateGlobalExitRoot + ); onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } From bf0569df9dea0a004f463f446a7023d4c8deb3a4 Mon Sep 17 00:00:00 2001 From: Stanley Date: Sun, 10 Nov 2024 13:21:00 -0500 Subject: [PATCH 08/19] WIP: more agglayer testing --- script/agglayer/Agglayer.s.sol | 47 ++++++++++++++----- .../token/crosschain/PolygonAgglayer.sol | 8 ++++ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index ad0d74bc..37122e54 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -6,7 +6,8 @@ import {TestNFT} from "./TestNFT.sol"; import {console} from "forge-std/console.sol"; import {Role} from "src/Role.sol"; import {PolygonAgglayerCrossChain} from "src/module/token/crosschain/PolygonAgglayer.sol"; -import {ERC20Base} from "src/core/token/ERC20Base.sol"; +import {ERC20Core} from "src/core/token/ERC20Core.sol"; +import {MintableERC20} from "src/module/token/minting/MintableERC20.sol"; import {OwnableRoles} from "@solady/auth/OwnableRoles.sol"; contract DeployTestNFT is Script { @@ -25,33 +26,57 @@ contract DeployTestNFT is Script { contract MintTestNFT is Script { TestNFT public testNFT; - ERC20Base public testToken; + MintableERC20 public mintableModule; + PolygonAgglayerCrossChain public polygonAgglayer; + ERC20Core public core; + + address agglayerBridgeExtension = 0x2311BFA86Ae27FC10E1ad3f805A2F9d22Fc8a6a1; function run() external { uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY"); address deployerAddress = vm.addr(deployerPrivateKey); + // address coreAddress = vm.envAddress("TEST_TOKEN_ADDRESS"); address testNFTAddress = vm.envAddress("TEST_NFT_ADDRESS"); - address testTokenAddress = vm.envAddress("TEST_TOKEN_ADDRESS"); uint64 destinationChain = 2442; vm.startBroadcast(deployerPrivateKey); - testNFT = TestNFT(testNFTAddress); - testToken = ERC20Base(payable(testTokenAddress)); + address[] memory modules = new address[](2); + bytes[] memory moduleData = new bytes[](2); - OwnableRoles(testTokenAddress).grantRoles(deployerAddress, Role._MINTER_ROLE); - testToken.mint(deployerAddress, 100, ""); + mintableModule = new MintableERC20(address(0x0)); + polygonAgglayer = new PolygonAgglayerCrossChain(); + console.log("mintableModule deployed to:", address(mintableModule)); + console.log("polygonAgglayer deployed to:", address(polygonAgglayer)); + + bytes memory mintableEncodedInstallParams = abi.encode(deployerAddress); + bytes memory polygonAgglayerEncodedInstallParams = abi.encode(address(polygonAgglayer)); + + modules[0] = address(mintableModule); + modules[1] = address(polygonAgglayer); + + moduleData[0] = mintableEncodedInstallParams; + moduleData[1] = polygonAgglayerEncodedInstallParams; + + core = new ERC20Core("test", "TEST", "", deployerAddress, modules, moduleData); + console.log("core deployed to:", address(core)); + + core.grantRoles(deployerAddress, Role._MINTER_ROLE); + core.mint(deployerAddress, 100, ""); console.log("Minted test tokens to deployer"); - bytes memory extraArgs = abi.encode(address(0), false, testToken, 100); + core.approve(agglayerBridgeExtension, 100); + console.log("Approved agglayer bridge extension"); + + bytes memory extraArgs = abi.encode(deployerAddress, true, address(core), 100); bytes memory payload = abi.encodeWithSelector( bytes4(keccak256("mint(address,uint256)")), deployerAddress, 1 ); - - PolygonAgglayerCrossChain(testTokenAddress).sendCrossChainTransaction( + + PolygonAgglayerCrossChain(address(core)).sendCrossChainTransaction( destinationChain, - address(testNFT), + testNFTAddress, payload, extraArgs ); diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index 237145ff..8dc37086 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,6 +6,7 @@ import {Role} from "../../../Role.sol"; import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; +import {console} from "forge-std/console.sol"; library PolygonAgglayerCrossChainStorage { @@ -85,6 +86,12 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { address router = _polygonAgglayerStorage().router; (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount) = abi.decode(_extraArgs, (address, bool, address, uint256)); + console.log("token address", _token); + console.log("amount", _amount); + console.log("destinationChain", _destinationChain); + console.log("callAddress", _callAddress); + console.log("fallbackAddress", _fallbackAddress); + console.log("forceUpdateGlobalExitRoot", _forceUpdateGlobalExitRoot); IBridgeAndCall(router).bridgeAndCall( _token, @@ -95,6 +102,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { _payload, _forceUpdateGlobalExitRoot ); + console.log("bridgeAndCall called successfully"); onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } From def4c3d4ca91c32696bb160bf31aa4a17f51137b Mon Sep 17 00:00:00 2001 From: Stanley Date: Sun, 10 Nov 2024 13:22:54 -0500 Subject: [PATCH 09/19] forge install: lxly-bridge-and-call ccd84985f39a320a5d7775e0092822dd89afb4cb --- lib/lxly-bridge-and-call | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lxly-bridge-and-call b/lib/lxly-bridge-and-call index b765fb4a..ccd84985 160000 --- a/lib/lxly-bridge-and-call +++ b/lib/lxly-bridge-and-call @@ -1 +1 @@ -Subproject commit b765fb4a98bf947b6fa4a62f41da7b7657d10783 +Subproject commit ccd84985f39a320a5d7775e0092822dd89afb4cb From 89513413e435b73151675c7c0faef4442127b932 Mon Sep 17 00:00:00 2001 From: Stanley Date: Sun, 10 Nov 2024 14:03:39 -0500 Subject: [PATCH 10/19] WIP: even more agglayer testing --- remappings.txt | 26 ++++++++++++++ script/agglayer/Agglayer.s.sol | 14 ++++++-- .../token/crosschain/PolygonAgglayer.sol | 34 +++++++++++++++---- 3 files changed, 66 insertions(+), 8 deletions(-) diff --git a/remappings.txt b/remappings.txt index 22272ee9..7eace379 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,3 +1,29 @@ +@ensdomains/=lib/creator-token-contracts/node_modules/@ensdomains/ + +@opensea/tstorish/=lib/creator-token-standards/lib/tstorish/src/ +@openzeppelin/contracts-upgradeable/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts-upgradeable/contracts/ +@openzeppelin/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/contracts/ + +@rari-capital/solmate/=lib/PermitC/lib/solmate/ +@zkevm/=lib/lxly-bridge-and-call/lib/zkevm-contracts/contracts/ +ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/ +PermitC/=lib/PermitC/src/ +creator-token-contracts/=lib/creator-token-contracts/contracts/ +creator-token-standards/=lib/creator-token-standards/src/ +erc4626-tests/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/lib/erc4626-tests/ +erc721a/=lib/erc721a/contracts/ +eth-gas-reporter/=lib/creator-token-contracts/node_modules/eth-gas-reporter/ +forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/ +hardhat/=lib/creator-token-contracts/node_modules/hardhat/ +lxly-bridge-and-call/=lib/lxly-bridge-and-call/ +murky/=lib/creator-token-contracts/lib/murky/src/ +openzeppelin-contracts-upgradeable/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts-upgradeable/ +openzeppelin-contracts/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/ +openzeppelin/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/contracts/ +solady/=lib/solady/src/ +zkevm-contracts/=lib/lxly-bridge-and-call/lib/zkevm-contracts/contracts/ + + ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @solady/=lib/solady/src/ diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index 37122e54..abdc1caa 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -49,7 +49,9 @@ contract MintTestNFT is Script { console.log("polygonAgglayer deployed to:", address(polygonAgglayer)); bytes memory mintableEncodedInstallParams = abi.encode(deployerAddress); - bytes memory polygonAgglayerEncodedInstallParams = abi.encode(address(polygonAgglayer)); + bytes memory polygonAgglayerEncodedInstallParams = abi.encode(agglayerBridgeExtension); + console.log("polygonAgglayerEncodedInstallParams"); + console.logBytes(polygonAgglayerEncodedInstallParams); modules[0] = address(mintableModule); modules[1] = address(polygonAgglayer); @@ -57,6 +59,14 @@ contract MintTestNFT is Script { moduleData[0] = mintableEncodedInstallParams; moduleData[1] = polygonAgglayerEncodedInstallParams; + console.log("moduleData"); + console.logBytes(moduleData[0]); + console.logBytes(moduleData[1]); + + console.log("modules"); + console.logAddress(modules[0]); + console.logAddress(modules[1]); + core = new ERC20Core("test", "TEST", "", deployerAddress, modules, moduleData); console.log("core deployed to:", address(core)); @@ -67,7 +77,7 @@ contract MintTestNFT is Script { core.approve(agglayerBridgeExtension, 100); console.log("Approved agglayer bridge extension"); - bytes memory extraArgs = abi.encode(deployerAddress, true, address(core), 100); + bytes memory extraArgs = abi.encode(deployerAddress, true, address(core), 100, ""); bytes memory payload = abi.encodeWithSelector( bytes4(keccak256("mint(address,uint256)")), deployerAddress, diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index 8dc37086..66ddfd09 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -42,11 +42,14 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { FallbackFunction({selector: this.setRouter.selector, permissionBits: Role._MANAGER_ROLE}); config.fallbackFunctions[2] = FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); + + config.registerInstallationCallback = true; } /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { address router = abi.decode(data, (address)); + console.log("router in onInstall: ", router); _polygonAgglayerStorage().router = router; } @@ -83,19 +86,23 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bytes calldata _payload, bytes calldata _extraArgs ) external payable override { - address router = _polygonAgglayerStorage().router; - (address _fallbackAddress, bool _forceUpdateGlobalExitRoot, address _token, uint256 _amount) = - abi.decode(_extraArgs, (address, bool, address, uint256)); + ( + address _fallbackAddress, + bool _forceUpdateGlobalExitRoot, + address _token, + uint256 _amount, + bytes memory permitData + ) = abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); console.log("token address", _token); console.log("amount", _amount); console.log("destinationChain", _destinationChain); console.log("callAddress", _callAddress); - console.log("fallbackAddress", _fallbackAddress); - console.log("forceUpdateGlobalExitRoot", _forceUpdateGlobalExitRoot); - IBridgeAndCall(router).bridgeAndCall( + // IBridgeAndCall(_polygonAgglayerStorage().router).bridgeAndCall( + _bridgeAndCall( _token, _amount, + permitData, uint32(_destinationChain), _callAddress, _fallbackAddress, @@ -107,6 +114,21 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } + function _bridgeAndCall(address _token, uint256 _amount, bytes memory permitData, uint32 _destinationChain, address _callAddress, address _fallbackAddress, bytes memory _payload, bool _forceUpdateGlobalExitRoot) internal { + console.log("router: ", _polygonAgglayerStorage().router); + IBridgeAndCall(_polygonAgglayerStorage().router).bridgeAndCall( + _token, + _amount, + permitData, + _destinationChain, + _callAddress, + _fallbackAddress, + _payload, + _forceUpdateGlobalExitRoot + ); + } + + /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ From 217342bf7ef03a999f1f4d7785791aafdb391026 Mon Sep 17 00:00:00 2001 From: Stanley Date: Sun, 10 Nov 2024 16:13:48 -0500 Subject: [PATCH 11/19] the script works --- script/agglayer/Agglayer.s.sol | 30 +++++++++---------- src/core/token/ERC20Base.sol | 2 ++ .../token/crosschain/PolygonAgglayer.sol | 25 +++++++++------- 3 files changed, 30 insertions(+), 27 deletions(-) diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index abdc1caa..76e7f326 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -1,16 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import {Script} from "forge-std/Script.sol"; import {TestNFT} from "./TestNFT.sol"; + +import {OwnableRoles} from "@solady/auth/OwnableRoles.sol"; +import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {Role} from "src/Role.sol"; -import {PolygonAgglayerCrossChain} from "src/module/token/crosschain/PolygonAgglayer.sol"; import {ERC20Core} from "src/core/token/ERC20Core.sol"; +import {PolygonAgglayerCrossChain} from "src/module/token/crosschain/PolygonAgglayer.sol"; import {MintableERC20} from "src/module/token/minting/MintableERC20.sol"; -import {OwnableRoles} from "@solady/auth/OwnableRoles.sol"; contract DeployTestNFT is Script { + TestNFT public testNFT; function run() external { @@ -22,9 +24,11 @@ contract DeployTestNFT is Script { vm.stopBroadcast(); } + } contract MintTestNFT is Script { + TestNFT public testNFT; MintableERC20 public mintableModule; PolygonAgglayerCrossChain public polygonAgglayer; @@ -42,7 +46,7 @@ contract MintTestNFT is Script { address[] memory modules = new address[](2); bytes[] memory moduleData = new bytes[](2); - + mintableModule = new MintableERC20(address(0x0)); polygonAgglayer = new PolygonAgglayerCrossChain(); console.log("mintableModule deployed to:", address(mintableModule)); @@ -74,23 +78,17 @@ contract MintTestNFT is Script { core.mint(deployerAddress, 100, ""); console.log("Minted test tokens to deployer"); - core.approve(agglayerBridgeExtension, 100); - console.log("Approved agglayer bridge extension"); + core.approve(address(core), 100); + console.log("Approved core"); bytes memory extraArgs = abi.encode(deployerAddress, true, address(core), 100, ""); - bytes memory payload = abi.encodeWithSelector( - bytes4(keccak256("mint(address,uint256)")), - deployerAddress, - 1 - ); - + bytes memory payload = abi.encodeWithSelector(bytes4(keccak256("mint(address,uint256)")), deployerAddress, 1); + PolygonAgglayerCrossChain(address(core)).sendCrossChainTransaction( - destinationChain, - testNFTAddress, - payload, - extraArgs + destinationChain, testNFTAddress, payload, extraArgs ); vm.stopBroadcast(); } + } diff --git a/src/core/token/ERC20Base.sol b/src/core/token/ERC20Base.sol index 95f61514..4272c6ce 100644 --- a/src/core/token/ERC20Base.sol +++ b/src/core/token/ERC20Base.sol @@ -204,6 +204,8 @@ contract ERC20Base is ERC20, Multicallable, Core, EIP712 { return super.transfer(to, amount); } + receive() external payable {} + /** * @notice Transfers tokens from a sender to a recipient. * @param from The address to transfer tokens from. diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index 66ddfd09..e681c2ad 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,7 +6,7 @@ import {Role} from "../../../Role.sol"; import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; -import {console} from "forge-std/console.sol"; +import {IERC20} from "src/interface/IERC20.sol"; library PolygonAgglayerCrossChainStorage { @@ -49,7 +49,6 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { address router = abi.decode(data, (address)); - console.log("router in onInstall: ", router); _polygonAgglayerStorage().router = router; } @@ -93,12 +92,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { uint256 _amount, bytes memory permitData ) = abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); - console.log("token address", _token); - console.log("amount", _amount); - console.log("destinationChain", _destinationChain); - console.log("callAddress", _callAddress); - // IBridgeAndCall(_polygonAgglayerStorage().router).bridgeAndCall( _bridgeAndCall( _token, _amount, @@ -109,13 +103,23 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { _payload, _forceUpdateGlobalExitRoot ); - console.log("bridgeAndCall called successfully"); onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } - function _bridgeAndCall(address _token, uint256 _amount, bytes memory permitData, uint32 _destinationChain, address _callAddress, address _fallbackAddress, bytes memory _payload, bool _forceUpdateGlobalExitRoot) internal { - console.log("router: ", _polygonAgglayerStorage().router); + function _bridgeAndCall( + address _token, + uint256 _amount, + bytes memory permitData, + uint32 _destinationChain, + address _callAddress, + address _fallbackAddress, + bytes memory _payload, + bool _forceUpdateGlobalExitRoot + ) internal { + IERC20(_token).transferFrom(msg.sender, address(this), _amount); + IERC20(_token).approve(_polygonAgglayerStorage().router, _amount); + IBridgeAndCall(_polygonAgglayerStorage().router).bridgeAndCall( _token, _amount, @@ -127,7 +131,6 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { _forceUpdateGlobalExitRoot ); } - /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS From 7e1ee97b8f434ebef705e188ad1a62c365b5d4ed Mon Sep 17 00:00:00 2001 From: Stanley Date: Thu, 14 Nov 2024 11:11:16 -0500 Subject: [PATCH 12/19] implemented both bridge and claim message & asset functionality respecitively --- remappings.txt | 26 ---- src/core/token/ERC20Base.sol | 2 - .../token/crosschain/PolygonAgglayer.sol | 145 +++++++++++++++--- 3 files changed, 124 insertions(+), 49 deletions(-) diff --git a/remappings.txt b/remappings.txt index 7eace379..22272ee9 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,29 +1,3 @@ -@ensdomains/=lib/creator-token-contracts/node_modules/@ensdomains/ - -@opensea/tstorish/=lib/creator-token-standards/lib/tstorish/src/ -@openzeppelin/contracts-upgradeable/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts-upgradeable/contracts/ -@openzeppelin/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/contracts/ - -@rari-capital/solmate/=lib/PermitC/lib/solmate/ -@zkevm/=lib/lxly-bridge-and-call/lib/zkevm-contracts/contracts/ -ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/ -PermitC/=lib/PermitC/src/ -creator-token-contracts/=lib/creator-token-contracts/contracts/ -creator-token-standards/=lib/creator-token-standards/src/ -erc4626-tests/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/lib/erc4626-tests/ -erc721a/=lib/erc721a/contracts/ -eth-gas-reporter/=lib/creator-token-contracts/node_modules/eth-gas-reporter/ -forge-gas-metering/=lib/PermitC/lib/forge-gas-metering/ -hardhat/=lib/creator-token-contracts/node_modules/hardhat/ -lxly-bridge-and-call/=lib/lxly-bridge-and-call/ -murky/=lib/creator-token-contracts/lib/murky/src/ -openzeppelin-contracts-upgradeable/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts-upgradeable/ -openzeppelin-contracts/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/ -openzeppelin/=lib/lxly-bridge-and-call/lib/openzeppelin-contracts/contracts/ -solady/=lib/solady/src/ -zkevm-contracts/=lib/lxly-bridge-and-call/lib/zkevm-contracts/contracts/ - - ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ @solady/=lib/solady/src/ diff --git a/src/core/token/ERC20Base.sol b/src/core/token/ERC20Base.sol index 4272c6ce..95f61514 100644 --- a/src/core/token/ERC20Base.sol +++ b/src/core/token/ERC20Base.sol @@ -204,8 +204,6 @@ contract ERC20Base is ERC20, Multicallable, Core, EIP712 { return super.transfer(to, amount); } - receive() external payable {} - /** * @notice Transfers tokens from a sender to a recipient. * @param from The address to transfer tokens from. diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/PolygonAgglayer.sol index e681c2ad..76bfe853 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/PolygonAgglayer.sol @@ -6,6 +6,7 @@ import {Role} from "../../../Role.sol"; import {CrossChain} from "./CrossChain.sol"; import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; +import {IPolygonZkEVMBridge} from "@zkevm-contracts/interfaces/IPolygonZkEVMBridge.sol"; import {IERC20} from "src/interface/IERC20.sol"; library PolygonAgglayerCrossChainStorage { @@ -16,6 +17,7 @@ library PolygonAgglayerCrossChainStorage { struct Data { address router; + address bridge; } function data() internal pure returns (Data storage data_) { @@ -35,21 +37,27 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { /// @notice Returns all implemented callback and fallback functions. function getModuleConfig() external pure override returns (ModuleConfig memory config) { - config.fallbackFunctions = new FallbackFunction[](3); + config.fallbackFunctions = new FallbackFunction[](7); config.fallbackFunctions[0] = FallbackFunction({selector: this.getRouter.selector, permissionBits: 0}); config.fallbackFunctions[1] = FallbackFunction({selector: this.setRouter.selector, permissionBits: Role._MANAGER_ROLE}); - config.fallbackFunctions[2] = + config.fallbackFunctions[2] = FallbackFunction({selector: this.getBridge.selector, permissionBits: 0}); + config.fallbackFunctions[3] = + FallbackFunction({selector: this.setBridge.selector, permissionBits: Role._MANAGER_ROLE}); + config.fallbackFunctions[4] = FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); + config.fallbackFunctions[5] = FallbackFunction({selector: this.claimMessage.selector, permissionBits: 0}); + config.fallbackFunctions[6] = FallbackFunction({selector: this.claimAsset.selector, permissionBits: 0}); config.registerInstallationCallback = true; } /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - address router = abi.decode(data, (address)); + (address router, address bridge) = abi.decode(data, (address, address)); _polygonAgglayerStorage().router = router; + _polygonAgglayerStorage().bridge = bridge; } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -69,16 +77,22 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { FALLBACK FUNCTIONS //////////////////////////////////////////////////////////////*/ - /// @notice Returns whether transfers is enabled for the token. function getRouter() external view override returns (address) { return _polygonAgglayerStorage().router; } - /// @notice Set transferability for a token. function setRouter(address router) external override { _polygonAgglayerStorage().router = router; } + function getBridge() external view returns (address) { + return _polygonAgglayerStorage().bridge; + } + + function setBridge(address bridge) external { + _polygonAgglayerStorage().bridge = bridge; + } + function sendCrossChainTransaction( uint64 _destinationChain, address _callAddress, @@ -93,20 +107,112 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bytes memory permitData ) = abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); - _bridgeAndCall( - _token, - _amount, - permitData, - uint32(_destinationChain), - _callAddress, - _fallbackAddress, - _payload, - _forceUpdateGlobalExitRoot - ); + if (_token == address(0) && _amount == 0) { + _bridgeMessage(uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload); + } else if (_payload.length == 0) { + _bridgeAsset( + uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData + ); + } else { + _bridgeAndCall( + _token, + _amount, + permitData, + uint32(_destinationChain), + _callAddress, + _fallbackAddress, + _payload, + _forceUpdateGlobalExitRoot + ); + } onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); } + function claimMessage( + bytes32[32] calldata smtProof, + uint32 index, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).claimMessage( + smtProof, + index, + mainnetExitRoot, + rollupExitRoot, + originNetwork, + originAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ); + } + + function claimAsset( + bytes32[32] calldata smtProof, + uint32 index, + bytes32 mainnetExitRoot, + bytes32 rollupExitRoot, + uint32 originNetwork, + address originTokenAddress, + uint32 destinationNetwork, + address destinationAddress, + uint256 amount, + bytes calldata metadata + ) external { + IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).claimAsset( + smtProof, + index, + mainnetExitRoot, + rollupExitRoot, + originNetwork, + originTokenAddress, + destinationNetwork, + destinationAddress, + amount, + metadata + ); + } + + /*////////////////////////////////////////////////////////////// + INTERNAL FUNCTIONS + //////////////////////////////////////////////////////////////*/ + + function _bridgeMessage( + uint32 _destinationChain, + address _callAddress, + bool _forceUpdateGlobalExitRoot, + bytes memory _payload + ) internal { + IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).bridgeMessage( + uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload + ); + } + + function _bridgeAsset( + uint32 _destinationChain, + address _callAddress, + uint256 _amount, + address _token, + bool _forceUpdateGlobalExitRoot, + bytes memory permitData + ) internal { + address bridge = _polygonAgglayerStorage().bridge; + IERC20(_token).transferFrom(msg.sender, address(this), _amount); + IERC20(_token).approve(bridge, _amount); + + IPolygonZkEVMBridge(bridge).bridgeAsset( + uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData + ); + } + function _bridgeAndCall( address _token, uint256 _amount, @@ -117,10 +223,11 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bytes memory _payload, bool _forceUpdateGlobalExitRoot ) internal { + address router = _polygonAgglayerStorage().router; IERC20(_token).transferFrom(msg.sender, address(this), _amount); - IERC20(_token).approve(_polygonAgglayerStorage().router, _amount); + IERC20(_token).approve(router, _amount); - IBridgeAndCall(_polygonAgglayerStorage().router).bridgeAndCall( + IBridgeAndCall(router).bridgeAndCall( _token, _amount, permitData, @@ -132,10 +239,6 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { ); } - /*////////////////////////////////////////////////////////////// - INTERNAL FUNCTIONS - //////////////////////////////////////////////////////////////*/ - function onCrossChainTransactionSent( uint64 _destinationChain, address _callAddress, From 565d8ae1646669b9f05703a0e883d99d68c60c90 Mon Sep 17 00:00:00 2001 From: Stanley Date: Tue, 19 Nov 2024 13:26:57 -0500 Subject: [PATCH 13/19] removed instances of polygon naming from agglayer --- script/agglayer/Agglayer.s.sol | 20 ++++++------- .../{PolygonAgglayer.sol => Agglayer.sol} | 30 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) rename src/module/token/crosschain/{PolygonAgglayer.sol => Agglayer.sol} (90%) diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index 76e7f326..b61e650e 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -8,7 +8,7 @@ import {Script} from "forge-std/Script.sol"; import {console} from "forge-std/console.sol"; import {Role} from "src/Role.sol"; import {ERC20Core} from "src/core/token/ERC20Core.sol"; -import {PolygonAgglayerCrossChain} from "src/module/token/crosschain/PolygonAgglayer.sol"; +import {AgglayerCrossChain} from "src/module/token/crosschain/Agglayer.sol"; import {MintableERC20} from "src/module/token/minting/MintableERC20.sol"; contract DeployTestNFT is Script { @@ -31,7 +31,7 @@ contract MintTestNFT is Script { TestNFT public testNFT; MintableERC20 public mintableModule; - PolygonAgglayerCrossChain public polygonAgglayer; + AgglayerCrossChain public agglayer; ERC20Core public core; address agglayerBridgeExtension = 0x2311BFA86Ae27FC10E1ad3f805A2F9d22Fc8a6a1; @@ -48,20 +48,20 @@ contract MintTestNFT is Script { bytes[] memory moduleData = new bytes[](2); mintableModule = new MintableERC20(address(0x0)); - polygonAgglayer = new PolygonAgglayerCrossChain(); + agglayer = new AgglayerCrossChain(); console.log("mintableModule deployed to:", address(mintableModule)); - console.log("polygonAgglayer deployed to:", address(polygonAgglayer)); + console.log("agglayer deployed to:", address(agglayer)); bytes memory mintableEncodedInstallParams = abi.encode(deployerAddress); - bytes memory polygonAgglayerEncodedInstallParams = abi.encode(agglayerBridgeExtension); - console.log("polygonAgglayerEncodedInstallParams"); - console.logBytes(polygonAgglayerEncodedInstallParams); + bytes memory agglayerEncodedInstallParams = abi.encode(agglayerBridgeExtension); + console.log("agglayerEncodedInstallParams"); + console.logBytes(agglayerEncodedInstallParams); modules[0] = address(mintableModule); - modules[1] = address(polygonAgglayer); + modules[1] = address(agglayer); moduleData[0] = mintableEncodedInstallParams; - moduleData[1] = polygonAgglayerEncodedInstallParams; + moduleData[1] = agglayerEncodedInstallParams; console.log("moduleData"); console.logBytes(moduleData[0]); @@ -84,7 +84,7 @@ contract MintTestNFT is Script { bytes memory extraArgs = abi.encode(deployerAddress, true, address(core), 100, ""); bytes memory payload = abi.encodeWithSelector(bytes4(keccak256("mint(address,uint256)")), deployerAddress, 1); - PolygonAgglayerCrossChain(address(core)).sendCrossChainTransaction( + AgglayerCrossChain(address(core)).sendCrossChainTransaction( destinationChain, testNFTAddress, payload, extraArgs ); diff --git a/src/module/token/crosschain/PolygonAgglayer.sol b/src/module/token/crosschain/Agglayer.sol similarity index 90% rename from src/module/token/crosschain/PolygonAgglayer.sol rename to src/module/token/crosschain/Agglayer.sol index 76bfe853..f2a6f291 100644 --- a/src/module/token/crosschain/PolygonAgglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -9,7 +9,7 @@ import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; import {IPolygonZkEVMBridge} from "@zkevm-contracts/interfaces/IPolygonZkEVMBridge.sol"; import {IERC20} from "src/interface/IERC20.sol"; -library PolygonAgglayerCrossChainStorage { +library AgglayerCrossChainStorage { /// @custom:storage-location erc7201:token.bridgeAndCall bytes32 public constant BRIDGE_AND_CALL_STORAGE_POSITION = @@ -29,7 +29,7 @@ library PolygonAgglayerCrossChainStorage { } -contract PolygonAgglayerCrossChain is Module, CrossChain { +contract AgglayerCrossChain is Module, CrossChain { /*////////////////////////////////////////////////////////////// EXTENSION CONFIG @@ -56,8 +56,8 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { (address router, address bridge) = abi.decode(data, (address, address)); - _polygonAgglayerStorage().router = router; - _polygonAgglayerStorage().bridge = bridge; + _agglayerStorage().router = router; + _agglayerStorage().bridge = bridge; } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -78,19 +78,19 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { //////////////////////////////////////////////////////////////*/ function getRouter() external view override returns (address) { - return _polygonAgglayerStorage().router; + return _agglayerStorage().router; } function setRouter(address router) external override { - _polygonAgglayerStorage().router = router; + _agglayerStorage().router = router; } function getBridge() external view returns (address) { - return _polygonAgglayerStorage().bridge; + return _agglayerStorage().bridge; } function setBridge(address bridge) external { - _polygonAgglayerStorage().bridge = bridge; + _agglayerStorage().bridge = bridge; } function sendCrossChainTransaction( @@ -141,7 +141,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { uint256 amount, bytes calldata metadata ) external { - IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).claimMessage( + IPolygonZkEVMBridge(_agglayerStorage().bridge).claimMessage( smtProof, index, mainnetExitRoot, @@ -167,7 +167,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { uint256 amount, bytes calldata metadata ) external { - IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).claimAsset( + IPolygonZkEVMBridge(_agglayerStorage().bridge).claimAsset( smtProof, index, mainnetExitRoot, @@ -191,7 +191,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bool _forceUpdateGlobalExitRoot, bytes memory _payload ) internal { - IPolygonZkEVMBridge(_polygonAgglayerStorage().bridge).bridgeMessage( + IPolygonZkEVMBridge(_agglayerStorage().bridge).bridgeMessage( uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload ); } @@ -204,7 +204,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bool _forceUpdateGlobalExitRoot, bytes memory permitData ) internal { - address bridge = _polygonAgglayerStorage().bridge; + address bridge = _agglayerStorage().bridge; IERC20(_token).transferFrom(msg.sender, address(this), _amount); IERC20(_token).approve(bridge, _amount); @@ -223,7 +223,7 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { bytes memory _payload, bool _forceUpdateGlobalExitRoot ) internal { - address router = _polygonAgglayerStorage().router; + address router = _agglayerStorage().router; IERC20(_token).transferFrom(msg.sender, address(this), _amount); IERC20(_token).approve(router, _amount); @@ -257,8 +257,8 @@ contract PolygonAgglayerCrossChain is Module, CrossChain { /// post cross chain transaction received logic goes here } - function _polygonAgglayerStorage() internal pure returns (PolygonAgglayerCrossChainStorage.Data storage) { - return PolygonAgglayerCrossChainStorage.data(); + function _agglayerStorage() internal pure returns (AgglayerCrossChainStorage.Data storage) { + return AgglayerCrossChainStorage.data(); } } From b20864bc57bb0d44a5e1539c116f716ab9176fa0 Mon Sep 17 00:00:00 2001 From: Yash Date: Mon, 20 Jan 2025 20:08:57 +0530 Subject: [PATCH 14/19] fix networkId and router install params --- script/agglayer/Agglayer.s.sol | 9 ++- src/module/token/crosschain/Agglayer.sol | 80 +++++++++++++----------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index b61e650e..18894584 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -27,6 +27,10 @@ contract DeployTestNFT is Script { } +interface IBridge { + function bridge() external view returns(address); +} + contract MintTestNFT is Script { TestNFT public testNFT; @@ -41,7 +45,7 @@ contract MintTestNFT is Script { address deployerAddress = vm.addr(deployerPrivateKey); // address coreAddress = vm.envAddress("TEST_TOKEN_ADDRESS"); address testNFTAddress = vm.envAddress("TEST_NFT_ADDRESS"); - uint64 destinationChain = 2442; + uint64 destinationNetwork = 1; vm.startBroadcast(deployerPrivateKey); address[] memory modules = new address[](2); @@ -56,6 +60,7 @@ contract MintTestNFT is Script { bytes memory agglayerEncodedInstallParams = abi.encode(agglayerBridgeExtension); console.log("agglayerEncodedInstallParams"); console.logBytes(agglayerEncodedInstallParams); + console.log(IBridge(agglayerBridgeExtension).bridge()); modules[0] = address(mintableModule); modules[1] = address(agglayer); @@ -85,7 +90,7 @@ contract MintTestNFT is Script { bytes memory payload = abi.encodeWithSelector(bytes4(keccak256("mint(address,uint256)")), deployerAddress, 1); AgglayerCrossChain(address(core)).sendCrossChainTransaction( - destinationChain, testNFTAddress, payload, extraArgs + destinationNetwork, testNFTAddress, payload, extraArgs ); vm.stopBroadcast(); diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index f2a6f291..290fa331 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -3,12 +3,29 @@ pragma solidity ^0.8.20; import {Module} from "../../../Module.sol"; import {Role} from "../../../Role.sol"; - import {CrossChain} from "./CrossChain.sol"; -import {IBridgeAndCall} from "@lxly-bridge-and-call/IBridgeAndCall.sol"; import {IPolygonZkEVMBridge} from "@zkevm-contracts/interfaces/IPolygonZkEVMBridge.sol"; import {IERC20} from "src/interface/IERC20.sol"; +interface IBridge is IPolygonZkEVMBridge { + function networkID() external view returns(uint32); +} + +interface IBridgeExtension { + function bridge() external view returns(address); + + function bridgeAndCall( + address token, + uint256 amount, + bytes calldata permitData, + uint32 destinationNetwork, + address callAddress, + address fallbackAddress, + bytes calldata callData, + bool forceUpdateGlobalExitRoot + ) external payable; +} + library AgglayerCrossChainStorage { /// @custom:storage-location erc7201:token.bridgeAndCall @@ -18,6 +35,7 @@ library AgglayerCrossChainStorage { struct Data { address router; address bridge; + uint32 networkId; } function data() internal pure returns (Data storage data_) { @@ -37,27 +55,27 @@ contract AgglayerCrossChain is Module, CrossChain { /// @notice Returns all implemented callback and fallback functions. function getModuleConfig() external pure override returns (ModuleConfig memory config) { - config.fallbackFunctions = new FallbackFunction[](7); + config.fallbackFunctions = new FallbackFunction[](5); config.fallbackFunctions[0] = FallbackFunction({selector: this.getRouter.selector, permissionBits: 0}); config.fallbackFunctions[1] = FallbackFunction({selector: this.setRouter.selector, permissionBits: Role._MANAGER_ROLE}); - config.fallbackFunctions[2] = FallbackFunction({selector: this.getBridge.selector, permissionBits: 0}); - config.fallbackFunctions[3] = - FallbackFunction({selector: this.setBridge.selector, permissionBits: Role._MANAGER_ROLE}); - config.fallbackFunctions[4] = + config.fallbackFunctions[2] = FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); - config.fallbackFunctions[5] = FallbackFunction({selector: this.claimMessage.selector, permissionBits: 0}); - config.fallbackFunctions[6] = FallbackFunction({selector: this.claimAsset.selector, permissionBits: 0}); + config.fallbackFunctions[3] = FallbackFunction({selector: this.claimMessage.selector, permissionBits: 0}); + config.fallbackFunctions[4] = FallbackFunction({selector: this.claimAsset.selector, permissionBits: 0}); config.registerInstallationCallback = true; } /// @dev Called by a Core into an Module during the installation of the Module. function onInstall(bytes calldata data) external { - (address router, address bridge) = abi.decode(data, (address, address)); + (address router) = abi.decode(data, (address)); + address bridge = IBridgeExtension(router).bridge(); + _agglayerStorage().router = router; _agglayerStorage().bridge = bridge; + _agglayerStorage().networkId = IBridge(bridge).networkID(); } /// @dev Called by a Core into an Module during the uninstallation of the Module. @@ -85,16 +103,8 @@ contract AgglayerCrossChain is Module, CrossChain { _agglayerStorage().router = router; } - function getBridge() external view returns (address) { - return _agglayerStorage().bridge; - } - - function setBridge(address bridge) external { - _agglayerStorage().bridge = bridge; - } - function sendCrossChainTransaction( - uint64 _destinationChain, + uint64 _destinationNetwork, address _callAddress, bytes calldata _payload, bytes calldata _extraArgs @@ -108,17 +118,17 @@ contract AgglayerCrossChain is Module, CrossChain { ) = abi.decode(_extraArgs, (address, bool, address, uint256, bytes)); if (_token == address(0) && _amount == 0) { - _bridgeMessage(uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload); + _bridgeMessage(uint32(_destinationNetwork), _callAddress, _forceUpdateGlobalExitRoot, _payload); } else if (_payload.length == 0) { _bridgeAsset( - uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData + uint32(_destinationNetwork), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData ); } else { _bridgeAndCall( _token, _amount, permitData, - uint32(_destinationChain), + uint32(_destinationNetwork), _callAddress, _fallbackAddress, _payload, @@ -126,7 +136,7 @@ contract AgglayerCrossChain is Module, CrossChain { ); } - onCrossChainTransactionSent(_destinationChain, _callAddress, _payload, _extraArgs); + onCrossChainTransactionSent(_destinationNetwork, _callAddress, _payload, _extraArgs); } function claimMessage( @@ -141,7 +151,7 @@ contract AgglayerCrossChain is Module, CrossChain { uint256 amount, bytes calldata metadata ) external { - IPolygonZkEVMBridge(_agglayerStorage().bridge).claimMessage( + IBridge(_agglayerStorage().bridge).claimMessage( smtProof, index, mainnetExitRoot, @@ -167,7 +177,7 @@ contract AgglayerCrossChain is Module, CrossChain { uint256 amount, bytes calldata metadata ) external { - IPolygonZkEVMBridge(_agglayerStorage().bridge).claimAsset( + IBridge(_agglayerStorage().bridge).claimAsset( smtProof, index, mainnetExitRoot, @@ -186,18 +196,18 @@ contract AgglayerCrossChain is Module, CrossChain { //////////////////////////////////////////////////////////////*/ function _bridgeMessage( - uint32 _destinationChain, + uint32 _destinationNetwork, address _callAddress, bool _forceUpdateGlobalExitRoot, bytes memory _payload ) internal { - IPolygonZkEVMBridge(_agglayerStorage().bridge).bridgeMessage( - uint32(_destinationChain), _callAddress, _forceUpdateGlobalExitRoot, _payload + IBridge(_agglayerStorage().bridge).bridgeMessage( + uint32(_destinationNetwork), _callAddress, _forceUpdateGlobalExitRoot, _payload ); } function _bridgeAsset( - uint32 _destinationChain, + uint32 _destinationNetwork, address _callAddress, uint256 _amount, address _token, @@ -208,8 +218,8 @@ contract AgglayerCrossChain is Module, CrossChain { IERC20(_token).transferFrom(msg.sender, address(this), _amount); IERC20(_token).approve(bridge, _amount); - IPolygonZkEVMBridge(bridge).bridgeAsset( - uint32(_destinationChain), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData + IBridge(bridge).bridgeAsset( + uint32(_destinationNetwork), _callAddress, _amount, _token, _forceUpdateGlobalExitRoot, permitData ); } @@ -217,7 +227,7 @@ contract AgglayerCrossChain is Module, CrossChain { address _token, uint256 _amount, bytes memory permitData, - uint32 _destinationChain, + uint32 _destinationNetwork, address _callAddress, address _fallbackAddress, bytes memory _payload, @@ -227,11 +237,11 @@ contract AgglayerCrossChain is Module, CrossChain { IERC20(_token).transferFrom(msg.sender, address(this), _amount); IERC20(_token).approve(router, _amount); - IBridgeAndCall(router).bridgeAndCall( + IBridgeExtension(router).bridgeAndCall( _token, _amount, permitData, - _destinationChain, + _destinationNetwork, _callAddress, _fallbackAddress, _payload, @@ -240,7 +250,7 @@ contract AgglayerCrossChain is Module, CrossChain { } function onCrossChainTransactionSent( - uint64 _destinationChain, + uint64 _destinationNetwork, address _callAddress, bytes calldata _payload, bytes calldata _extraArgs From 1266ea517b9c348197dc0047eb54f46c29828d09 Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 5 Feb 2025 04:33:05 +0530 Subject: [PATCH 15/19] bridgeTokens function --- script/agglayer/Agglayer.s.sol | 4 +++- script/agglayer/TestNFT.sol | 9 +++------ src/module/token/crosschain/Agglayer.sol | 23 ++++++++++++++++++++--- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/script/agglayer/Agglayer.s.sol b/script/agglayer/Agglayer.s.sol index 18894584..e62e05b8 100644 --- a/script/agglayer/Agglayer.s.sol +++ b/script/agglayer/Agglayer.s.sol @@ -28,7 +28,9 @@ contract DeployTestNFT is Script { } interface IBridge { - function bridge() external view returns(address); + + function bridge() external view returns (address); + } contract MintTestNFT is Script { diff --git a/script/agglayer/TestNFT.sol b/script/agglayer/TestNFT.sol index 41737494..60df5a0d 100644 --- a/script/agglayer/TestNFT.sol +++ b/script/agglayer/TestNFT.sol @@ -4,14 +4,11 @@ pragma solidity ^0.8.20; import {ERC721A} from "@erc721a/ERC721A.sol"; contract TestNFT is ERC721A { - constructor( - string memory _name, - string memory _symbol - ) ERC721A(_name, _symbol) {} + + constructor(string memory _name, string memory _symbol) ERC721A(_name, _symbol) {} function mint(address to, uint256 amount) public { _mint(to, amount); } -} - +} diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index 290fa331..f7d0532a 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -8,11 +8,14 @@ import {IPolygonZkEVMBridge} from "@zkevm-contracts/interfaces/IPolygonZkEVMBrid import {IERC20} from "src/interface/IERC20.sol"; interface IBridge is IPolygonZkEVMBridge { - function networkID() external view returns(uint32); + + function networkID() external view returns (uint32); + } interface IBridgeExtension { - function bridge() external view returns(address); + + function bridge() external view returns (address); function bridgeAndCall( address token, @@ -24,6 +27,7 @@ interface IBridgeExtension { bytes calldata callData, bool forceUpdateGlobalExitRoot ) external payable; + } library AgglayerCrossChainStorage { @@ -72,7 +76,7 @@ contract AgglayerCrossChain is Module, CrossChain { function onInstall(bytes calldata data) external { (address router) = abi.decode(data, (address)); address bridge = IBridgeExtension(router).bridge(); - + _agglayerStorage().router = router; _agglayerStorage().bridge = bridge; _agglayerStorage().networkId = IBridge(bridge).networkID(); @@ -139,6 +143,19 @@ contract AgglayerCrossChain is Module, CrossChain { onCrossChainTransactionSent(_destinationNetwork, _callAddress, _payload, _extraArgs); } + function bridgeTokens(uint64 _destinationNetwork, address _callAddress, uint256 _amount) + external + payable + override + { + address bridge = _agglayerStorage().bridge; + IERC20(address(this)).approve(bridge, _amount); + + IBridge(bridge).bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), false, ""); + + onCrossChainTransactionSent(_destinationNetwork, _callAddress, _payload, _extraArgs); + } + function claimMessage( bytes32[32] calldata smtProof, uint32 index, From 1eff83a10530544e3935d61d1271e43de46db304 Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 5 Feb 2025 04:37:19 +0530 Subject: [PATCH 16/19] remove unused --- src/module/token/crosschain/Agglayer.sol | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index f7d0532a..12127ef2 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -146,14 +146,11 @@ contract AgglayerCrossChain is Module, CrossChain { function bridgeTokens(uint64 _destinationNetwork, address _callAddress, uint256 _amount) external payable - override { address bridge = _agglayerStorage().bridge; IERC20(address(this)).approve(bridge, _amount); IBridge(bridge).bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), false, ""); - - onCrossChainTransactionSent(_destinationNetwork, _callAddress, _payload, _extraArgs); } function claimMessage( From 1c7f600bd6d573c49a1ef90d61fe8e7ad44740eb Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 5 Feb 2025 05:52:20 +0530 Subject: [PATCH 17/19] add fallback --- src/module/token/crosschain/Agglayer.sol | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index 12127ef2..2ea27575 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -59,7 +59,7 @@ contract AgglayerCrossChain is Module, CrossChain { /// @notice Returns all implemented callback and fallback functions. function getModuleConfig() external pure override returns (ModuleConfig memory config) { - config.fallbackFunctions = new FallbackFunction[](5); + config.fallbackFunctions = new FallbackFunction[](6); config.fallbackFunctions[0] = FallbackFunction({selector: this.getRouter.selector, permissionBits: 0}); config.fallbackFunctions[1] = @@ -68,6 +68,7 @@ contract AgglayerCrossChain is Module, CrossChain { FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); config.fallbackFunctions[3] = FallbackFunction({selector: this.claimMessage.selector, permissionBits: 0}); config.fallbackFunctions[4] = FallbackFunction({selector: this.claimAsset.selector, permissionBits: 0}); + config.fallbackFunctions[5] = FallbackFunction({selector: this.bridgeTokens.selector, permissionBits: 0}); config.registerInstallationCallback = true; } @@ -148,6 +149,7 @@ contract AgglayerCrossChain is Module, CrossChain { payable { address bridge = _agglayerStorage().bridge; + IERC20(address(this)).transferFrom(msg.sender, address(this), _amount); IERC20(address(this)).approve(bridge, _amount); IBridge(bridge).bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), false, ""); From 6c1388559a69af6d2b9ef11d5eb20b491d253aec Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 12 Feb 2025 18:14:12 +0530 Subject: [PATCH 18/19] clean up --- src/module/token/crosschain/Agglayer.sol | 58 +----------------------- 1 file changed, 2 insertions(+), 56 deletions(-) diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index 2ea27575..12aef998 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -59,16 +59,14 @@ contract AgglayerCrossChain is Module, CrossChain { /// @notice Returns all implemented callback and fallback functions. function getModuleConfig() external pure override returns (ModuleConfig memory config) { - config.fallbackFunctions = new FallbackFunction[](6); + config.fallbackFunctions = new FallbackFunction[](4); config.fallbackFunctions[0] = FallbackFunction({selector: this.getRouter.selector, permissionBits: 0}); config.fallbackFunctions[1] = FallbackFunction({selector: this.setRouter.selector, permissionBits: Role._MANAGER_ROLE}); config.fallbackFunctions[2] = FallbackFunction({selector: this.sendCrossChainTransaction.selector, permissionBits: 0}); - config.fallbackFunctions[3] = FallbackFunction({selector: this.claimMessage.selector, permissionBits: 0}); - config.fallbackFunctions[4] = FallbackFunction({selector: this.claimAsset.selector, permissionBits: 0}); - config.fallbackFunctions[5] = FallbackFunction({selector: this.bridgeTokens.selector, permissionBits: 0}); + config.fallbackFunctions[3] = FallbackFunction({selector: this.bridgeTokens.selector, permissionBits: 0}); config.registerInstallationCallback = true; } @@ -155,58 +153,6 @@ contract AgglayerCrossChain is Module, CrossChain { IBridge(bridge).bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), false, ""); } - function claimMessage( - bytes32[32] calldata smtProof, - uint32 index, - bytes32 mainnetExitRoot, - bytes32 rollupExitRoot, - uint32 originNetwork, - address originAddress, - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - bytes calldata metadata - ) external { - IBridge(_agglayerStorage().bridge).claimMessage( - smtProof, - index, - mainnetExitRoot, - rollupExitRoot, - originNetwork, - originAddress, - destinationNetwork, - destinationAddress, - amount, - metadata - ); - } - - function claimAsset( - bytes32[32] calldata smtProof, - uint32 index, - bytes32 mainnetExitRoot, - bytes32 rollupExitRoot, - uint32 originNetwork, - address originTokenAddress, - uint32 destinationNetwork, - address destinationAddress, - uint256 amount, - bytes calldata metadata - ) external { - IBridge(_agglayerStorage().bridge).claimAsset( - smtProof, - index, - mainnetExitRoot, - rollupExitRoot, - originNetwork, - originTokenAddress, - destinationNetwork, - destinationAddress, - amount, - metadata - ); - } - /*////////////////////////////////////////////////////////////// INTERNAL FUNCTIONS //////////////////////////////////////////////////////////////*/ From 975736ac3f67a475915b1a4ee175acd9ef314a78 Mon Sep 17 00:00:00 2001 From: Yash Date: Wed, 12 Feb 2025 18:17:31 +0530 Subject: [PATCH 19/19] clean up --- src/module/token/crosschain/Agglayer.sol | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/module/token/crosschain/Agglayer.sol b/src/module/token/crosschain/Agglayer.sol index 12aef998..1fa5e819 100644 --- a/src/module/token/crosschain/Agglayer.sol +++ b/src/module/token/crosschain/Agglayer.sol @@ -146,11 +146,7 @@ contract AgglayerCrossChain is Module, CrossChain { external payable { - address bridge = _agglayerStorage().bridge; - IERC20(address(this)).transferFrom(msg.sender, address(this), _amount); - IERC20(address(this)).approve(bridge, _amount); - - IBridge(bridge).bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), false, ""); + _bridgeAsset(uint32(_destinationNetwork), _callAddress, _amount, address(this), true, ""); } /*//////////////////////////////////////////////////////////////