From a7f3fd8a1c3ccaee23be107ea0c139c30a12cc79 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 28 Feb 2025 20:36:50 +0400 Subject: [PATCH 01/23] feat: optimism package --- .gitmodules | 3 +++ lib/optimism | 1 + remappings.txt | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) create mode 160000 lib/optimism diff --git a/.gitmodules b/.gitmodules index dbd0a97b..53f75531 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "lib/solady"] path = lib/solady url = https://github.com/vectorized/solady +[submodule "lib/optimism"] + path = lib/optimism + url = https://github.com/ethereum-optimism/optimism diff --git a/lib/optimism b/lib/optimism new file mode 160000 index 00000000..bc6d11a8 --- /dev/null +++ b/lib/optimism @@ -0,0 +1 @@ +Subproject commit bc6d11a854b4d4cd60d9de541eb60673912d4f76 diff --git a/remappings.txt b/remappings.txt index 1cf3bb7d..4688d27f 100644 --- a/remappings.txt +++ b/remappings.txt @@ -1,4 +1,5 @@ ds-test/=lib/forge-std/lib/ds-test/src/ forge-std/=lib/forge-std/src/ solmate/=lib/solmate/src/ -solady/=lib/solady/src/ \ No newline at end of file +solady/=lib/solady/src/ +optimism/=lib/optimism/packages/contracts-bedrock/ \ No newline at end of file From 6c83612ca80aa42fd674a887d197bb61056d2709 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Fri, 28 Feb 2025 20:36:57 +0400 Subject: [PATCH 02/23] feat: interop sb --- .../socket/switchboard/InterOpSwitchboard.sol | 37 +++++++++ .../socket/switchboard/SuperchainEnabled.sol | 78 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 contracts/protocol/socket/switchboard/InterOpSwitchboard.sol create mode 100644 contracts/protocol/socket/switchboard/SuperchainEnabled.sol diff --git a/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol b/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol new file mode 100644 index 00000000..aeaa08ca --- /dev/null +++ b/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol @@ -0,0 +1,37 @@ +pragma solidity ^0.8.13; +import {SuperchainEnabled} from "./SuperchainEnabled.sol"; + +// An LocalAsyncProxy is a local representation of a contract on a remote chain. +// Calling an LocalAsyncProxy triggers an authenticated call to an async function, +// on the remote chain and returns a local Promise contract, +// which will eventually trigger a local callback with the return value of the remote async call. +contract InterOpSwitchboard is SuperchainEnabled { + // address and chainId of the remote contract triggered by calling this local proxy + address internal remoteAddress; + uint256 internal remoteChainId; + uint256 public root; + + constructor(uint256 _chainId) { + remoteChainId = _chainId; + } + + function setRemoteAddress(address _remoteAddress) external { + remoteAddress = _remoteAddress; + } + + function getRemoteDetails() external view returns (address, uint256) { + return (remoteAddress, remoteChainId); + } + + function syncOut(bytes32 root_) external { + _xMessageContract( + remoteChainId, + remoteAddress, + abi.encodeWithSelector(this.syncIn.selector, root_) + ); + } + + function syncIn(uint256 root_) external xOnlyFromContract(remoteAddress, remoteChainId) { + root = root_; + } +} diff --git a/contracts/protocol/socket/switchboard/SuperchainEnabled.sol b/contracts/protocol/socket/switchboard/SuperchainEnabled.sol new file mode 100644 index 00000000..0dddc650 --- /dev/null +++ b/contracts/protocol/socket/switchboard/SuperchainEnabled.sol @@ -0,0 +1,78 @@ +pragma solidity ^0.8.13; + +// SuperchainEnabled provides utilities for cross-chain event validation, +// sending messages, and receiving messages with modifiers. + +import {IL2ToL2CrossDomainMessenger} from "optimism/interfaces/L2/IL2ToL2CrossDomainMessenger.sol"; +import {Predeploys} from "optimism/src/libraries/Predeploys.sol"; + +abstract contract SuperchainEnabled { + // Error definitions + error CallerNotL2ToL2CrossDomainMessenger(); + error InvalidCrossDomainSender(); + error InvalidSourceChain(); + + /// @notice Sends a cross-chain message to a destination address on another chain + /// @param destChainId The chain ID of the destination chain + /// @param destAddress The address of the destination contract + /// @param data The calldata to send to the destination contract + function _xMessageContract( + uint256 destChainId, + address destAddress, + bytes memory data + ) internal { + IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) + .sendMessage(destChainId, destAddress, data); + } + + /// @notice Checks if the cross-domain message is from the expected source + /// @param expectedSource The expected source address + /// @return bool True if the message is from the expected source, false otherwise + function _isValidCrossDomainSender( + address expectedSource + ) internal view returns (bool) { + if (msg.sender != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { + return false; + } + return + IL2ToL2CrossDomainMessenger( + Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER + ).crossDomainMessageSender() == expectedSource; + } + + /// @notice Modifier to validate messages from a specific address + /// @param expectedSource The expected source address + modifier xOnlyFromAddress(address expectedSource) { + if (!_isValidCrossDomainSender(expectedSource)) { + revert InvalidCrossDomainSender(); + } + _; + } + + /// @notice Modifier to validate messages from a specific address on a specific chain + /// @param expectedSource The expected source address + /// @param expectedChainId The expected source chain ID + modifier xOnlyFromContract( + address expectedSource, + uint256 expectedChainId + ) { + if (msg.sender != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { + revert CallerNotL2ToL2CrossDomainMessenger(); + } + if ( + IL2ToL2CrossDomainMessenger( + Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER + ).crossDomainMessageSender() != expectedSource + ) { + revert InvalidCrossDomainSender(); + } + if ( + IL2ToL2CrossDomainMessenger( + Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER + ).crossDomainMessageSource() != expectedChainId + ) { + revert InvalidSourceChain(); + } + _; + } +} From dfa53546e5cd8473f048cac9a279fe0230ccd92f Mon Sep 17 00:00:00 2001 From: arthcp Date: Fri, 28 Feb 2025 20:52:44 +0400 Subject: [PATCH 03/23] feat: op interop sb --- contracts/interfaces/ISocket.sol | 8 ++ contracts/protocol/socket/Socket.sol | 8 +- .../socket/switchboard/FastSwitchboard.sol | 2 +- .../socket/switchboard/InterOpSwitchboard.sol | 37 ------ .../switchboard/OpInteropSwitchboard.sol | 123 ++++++++++++++++++ test/mock/MockSocket.sol | 8 +- 6 files changed, 134 insertions(+), 52 deletions(-) delete mode 100644 contracts/protocol/socket/switchboard/InterOpSwitchboard.sol create mode 100644 contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol diff --git a/contracts/interfaces/ISocket.sol b/contracts/interfaces/ISocket.sol index d46f6eca..2b775c0a 100644 --- a/contracts/interfaces/ISocket.sol +++ b/contracts/interfaces/ISocket.sol @@ -64,6 +64,12 @@ interface ISocket { bytes payload; } + enum ExecutionStatus { + NotExecuted, + Executed, + Reverted + } + /** * @notice To call the appGateway on EVMx. Should only be called by a plug. * @param payload_ bytes to be delivered to the Plug on EVMx @@ -99,4 +105,6 @@ interface ISocket { function getPlugConfig( address plugAddress_ ) external view returns (address appGateway, address switchboard); + + function payloadExecuted(bytes32 payloadId_) external view returns (ExecutionStatus); } diff --git a/contracts/protocol/socket/Socket.sol b/contracts/protocol/socket/Socket.sol index bd70a175..d44af419 100644 --- a/contracts/protocol/socket/Socket.sol +++ b/contracts/protocol/socket/Socket.sol @@ -46,16 +46,10 @@ contract Socket is SocketUtils { //////////////////////////////////////////////////////////// uint64 public callCounter; - enum ExecutionStatus { - NotExecuted, - Executed, - Reverted - } - /** * @dev keeps track of whether a payload has been executed or not using payload id */ - mapping(bytes32 => ExecutionStatus) public payloadExecuted; + mapping(bytes32 => ExecutionStatus) public override payloadExecuted; constructor( uint32 chainSlug_, diff --git a/contracts/protocol/socket/switchboard/FastSwitchboard.sol b/contracts/protocol/socket/switchboard/FastSwitchboard.sol index 874e7d19..513f40f3 100644 --- a/contracts/protocol/socket/switchboard/FastSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/FastSwitchboard.sol @@ -38,7 +38,7 @@ contract FastSwitchboard is SwitchboardBase { * there can be multiple proposals for same digest. To avoid need to re-attest for different proposals * with same digest, we are storing attestations against digest instead of packetId and proposalCount. */ - function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external { + function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external virtual { address watcher = _recoverSigner(keccak256(abi.encode(address(this), digest_)), proof_); if (isAttested[digest_]) revert AlreadyAttested(); diff --git a/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol b/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol deleted file mode 100644 index aeaa08ca..00000000 --- a/contracts/protocol/socket/switchboard/InterOpSwitchboard.sol +++ /dev/null @@ -1,37 +0,0 @@ -pragma solidity ^0.8.13; -import {SuperchainEnabled} from "./SuperchainEnabled.sol"; - -// An LocalAsyncProxy is a local representation of a contract on a remote chain. -// Calling an LocalAsyncProxy triggers an authenticated call to an async function, -// on the remote chain and returns a local Promise contract, -// which will eventually trigger a local callback with the return value of the remote async call. -contract InterOpSwitchboard is SuperchainEnabled { - // address and chainId of the remote contract triggered by calling this local proxy - address internal remoteAddress; - uint256 internal remoteChainId; - uint256 public root; - - constructor(uint256 _chainId) { - remoteChainId = _chainId; - } - - function setRemoteAddress(address _remoteAddress) external { - remoteAddress = _remoteAddress; - } - - function getRemoteDetails() external view returns (address, uint256) { - return (remoteAddress, remoteChainId); - } - - function syncOut(bytes32 root_) external { - _xMessageContract( - remoteChainId, - remoteAddress, - abi.encodeWithSelector(this.syncIn.selector, root_) - ); - } - - function syncIn(uint256 root_) external xOnlyFromContract(remoteAddress, remoteChainId) { - root = root_; - } -} diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol new file mode 100644 index 00000000..7f68bd9a --- /dev/null +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.21; + +import {FastSwitchboard} from "./FastSwitchboard.sol"; +import {SuperchainEnabled} from "./SuperchainEnabled.sol"; +import {ISocket} from "../../../interfaces/ISocket.sol"; + +contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { + mapping(bytes32 => bool) public isSyncedOut; + mapping(bytes32 => bytes32) public payloadIdToDigest; + mapping(bytes32 => bool) public unopenedDigests; + mapping(address => uint256) public unminted; + address public token; + address public remoteAddress; + uint256 public remoteChainId; + + struct PayloadParams { + bytes32 payloadId; + address appGateway; + address transmitter; + address target; + uint256 value; + uint256 deadline; + uint256 executionGasLimit; + bytes payload; + } + + modifier onlyToken() { + if (msg.sender != token) revert OnlyTokenAllowed(); + _; + } + + error OnlyTokenAllowed(); + + constructor( + uint32 chainSlug_, + ISocket socket_, + address owner_ + ) FastSwitchboard(chainSlug_, socket_, owner_) {} + + function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external override { + address watcher = _recoverSigner(keccak256(abi.encode(address(this), digest_)), proof_); + + if (isAttested[digest_]) revert AlreadyAttested(); + if (!_hasRole(WATCHER_ROLE, watcher)) revert WatcherNotFound(); + + isAttested[digest_] = true; + payloadIdToDigest[payloadId_] = digest_; + emit Attested(payloadId_, digest_, watcher); + } + + function syncOut(bytes32 digest_, bytes32 payloadId_) external { + if (isSyncedOut[digest_]) return; + isSyncedOut[digest_] = true; + + if (!isAttested[digest_]) return; + + bytes32 digest = payloadIdToDigest[payloadId_]; + if (digest != digest_) return; + + ISocket.ExecutionStatus isExecuted = socket__.payloadExecuted(payloadId_); + if (isExecuted != ISocket.ExecutionStatus.Executed) return; + + _xMessageContract( + remoteChainId, + remoteAddress, + abi.encodeWithSelector(this.syncIn.selector, digest_) + ); + } + + function syncIn(bytes32 digest_) external xOnlyFromContract(remoteAddress, remoteChainId) { + unopenedDigests[digest_] = true; + } + + function openDigest(bytes32 digest_, PayloadParams calldata payloadParams_) external { + bytes32 expectedDigest = _packPayload(payloadParams_); + if (expectedDigest != digest_) return; + + if (!unopenedDigests[digest_]) return; + unopenedDigests[digest_] = false; + + (address user, uint256 amount) = _decodeMint(payloadParams_.payload); + unminted[user] += amount; + } + + function _decodeMint( + bytes memory payload + ) internal pure returns (address user, uint256 amount) { + return abi.decode(payload, (address, uint256)); + } + + function _packPayload(PayloadParams memory payloadParams_) internal pure returns (bytes32) { + return + keccak256( + abi.encode( + payloadParams_.payloadId, + payloadParams_.appGateway, + payloadParams_.transmitter, + payloadParams_.target, + payloadParams_.value, + payloadParams_.deadline, + payloadParams_.executionGasLimit, + payloadParams_.payload + ) + ); + } + + function checkAndConsume(address user_, uint256 amount_) external onlyToken { + unminted[user_] -= amount_; + } + + function setToken(address token_) external onlyOwner { + token = token_; + } + + function setRemoteAddress(address _remoteAddress) external onlyOwner { + remoteAddress = _remoteAddress; + } + + function setRemoteChainId(uint256 _remoteChainId) external onlyOwner { + remoteChainId = _remoteChainId; + } +} diff --git a/test/mock/MockSocket.sol b/test/mock/MockSocket.sol index 98c87f09..17038fbf 100644 --- a/test/mock/MockSocket.sol +++ b/test/mock/MockSocket.sol @@ -68,16 +68,10 @@ contract MockSocket is ISocket { uint64 public callCounter; uint32 public chainSlug; - enum ExecutionStatus { - NotExecuted, - Executed, - Reverted - } - /** * @dev keeps track of whether a payload has been executed or not using payload id */ - mapping(bytes32 => ExecutionStatus) public payloadExecuted; + mapping(bytes32 => ExecutionStatus) public override payloadExecuted; constructor(uint32 chainSlug_, address, address, address, string memory) { chainSlug = chainSlug_; From ca0081b8951b0b3c1822b753448869eadf228919 Mon Sep 17 00:00:00 2001 From: arthcp Date: Mon, 3 Mar 2025 12:36:17 +0400 Subject: [PATCH 04/23] feat: send full user, amount in sync --- .../switchboard/OpInteropSwitchboard.sol | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol index 7f68bd9a..a9de39e7 100644 --- a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -8,7 +8,6 @@ import {ISocket} from "../../../interfaces/ISocket.sol"; contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { mapping(bytes32 => bool) public isSyncedOut; mapping(bytes32 => bytes32) public payloadIdToDigest; - mapping(bytes32 => bool) public unopenedDigests; mapping(address => uint256) public unminted; address public token; address public remoteAddress; @@ -49,7 +48,11 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { emit Attested(payloadId_, digest_, watcher); } - function syncOut(bytes32 digest_, bytes32 payloadId_) external { + function syncOut( + bytes32 digest_, + bytes32 payloadId_, + PayloadParams calldata payloadParams_ + ) external { if (isSyncedOut[digest_]) return; isSyncedOut[digest_] = true; @@ -58,35 +61,36 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { bytes32 digest = payloadIdToDigest[payloadId_]; if (digest != digest_) return; + bytes32 expectedDigest = _packPayload(payloadParams_); + if (expectedDigest != digest_) return; + ISocket.ExecutionStatus isExecuted = socket__.payloadExecuted(payloadId_); if (isExecuted != ISocket.ExecutionStatus.Executed) return; + (address user, uint256 amount) = _decodeMint(payloadParams_.payload); + _xMessageContract( remoteChainId, remoteAddress, - abi.encodeWithSelector(this.syncIn.selector, digest_) + abi.encodeWithSelector(this.syncIn.selector, user, amount) ); } - function syncIn(bytes32 digest_) external xOnlyFromContract(remoteAddress, remoteChainId) { - unopenedDigests[digest_] = true; - } - - function openDigest(bytes32 digest_, PayloadParams calldata payloadParams_) external { - bytes32 expectedDigest = _packPayload(payloadParams_); - if (expectedDigest != digest_) return; - - if (!unopenedDigests[digest_]) return; - unopenedDigests[digest_] = false; - - (address user, uint256 amount) = _decodeMint(payloadParams_.payload); - unminted[user] += amount; + function syncIn( + address user_, + uint256 amount_ + ) external xOnlyFromContract(remoteAddress, remoteChainId) { + unminted[user_] += amount_; } function _decodeMint( bytes memory payload ) internal pure returns (address user, uint256 amount) { - return abi.decode(payload, (address, uint256)); + (, , uint256 amount, address user) = abi.decode( + payload, + (bytes4, address, uint256, address) + ); + return (user, amount); } function _packPayload(PayloadParams memory payloadParams_) internal pure returns (bytes32) { From 3574174bb2d4406cc895ee26128779bb0b658990 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 3 Mar 2025 13:13:07 +0400 Subject: [PATCH 05/23] feat: token app --- .../switchboard/OpInteropSwitchboard.sol | 6 +- .../super-token-op/ISuperToken.sol | 19 +++++ .../super-token-op/SuperToken.sol | 54 +++++++++++++ .../super-token-op/SuperTokenAppGateway.sol | 79 +++++++++++++++++++ 4 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 test/apps/app-gateways/super-token-op/ISuperToken.sol create mode 100644 test/apps/app-gateways/super-token-op/SuperToken.sol create mode 100644 test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol index a9de39e7..b60faf6b 100644 --- a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -86,11 +86,7 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { function _decodeMint( bytes memory payload ) internal pure returns (address user, uint256 amount) { - (, , uint256 amount, address user) = abi.decode( - payload, - (bytes4, address, uint256, address) - ); - return (user, amount); + (, , amount, user) = abi.decode(payload, (bytes4, address, uint256, address)); } function _packPayload(PayloadParams memory payloadParams_) internal pure returns (bytes32) { diff --git a/test/apps/app-gateways/super-token-op/ISuperToken.sol b/test/apps/app-gateways/super-token-op/ISuperToken.sol new file mode 100644 index 00000000..77dbb353 --- /dev/null +++ b/test/apps/app-gateways/super-token-op/ISuperToken.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +interface ISuperToken { + function burn(address user_, uint256 amount_) external; + + function mint(address receiver_, uint256 amount_) external; + + function lockTokens(address user_, uint256 amount_) external; + + function unlockTokens(address user_, uint256 amount_) external; + + // Public variable + function controller() external returns (address); + + function setController(address controller_) external; + + function balanceOf(address account_) external; +} diff --git a/test/apps/app-gateways/super-token-op/SuperToken.sol b/test/apps/app-gateways/super-token-op/SuperToken.sol new file mode 100644 index 00000000..0ea08bbd --- /dev/null +++ b/test/apps/app-gateways/super-token-op/SuperToken.sol @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.21; + +import "solmate/tokens/ERC20.sol"; +import {Ownable} from "solady/auth/Ownable.sol"; +import "../../../../contracts/base/PlugBase.sol"; + +interface ISwitchboard { + function checkAndConsume(address user_, uint256 amount_) external; +} + +/** + * @title SuperToken + * @notice An ERC20 contract which enables bridging a token to its sibling chains. + */ +contract SuperToken is ERC20, Ownable, PlugBase { + mapping(address => uint256) public lockedTokens; + address public opSwitchboard; + + error InvalidSender(); + + constructor( + string memory name_, + string memory symbol_, + uint8 decimals_, + address initialSupplyHolder_, + uint256 initialSupply_ + ) ERC20(name_, symbol_, decimals_) { + _mint(initialSupplyHolder_, initialSupply_); + } + + function mint(address user_, uint256 amount_) external onlySocket { + _mint(user_, amount_); + } + + function burn(address user_, uint256 amount_) external onlySocket { + ISwitchboard(opSwitchboard).checkAndConsume(user_, amount_); + _burn(user_, amount_); + } + + function setSocket(address newSocket_) external onlyOwner { + _setSocket(newSocket_); + } + + function setOpSwitchboard(address newOpSwitchboard_) external onlyOwner { + opSwitchboard = newOpSwitchboard_; + } + + function setupToken(address owner_, address opSwitchboard_) external { + if (owner() != address(0) && owner() != msg.sender) revert InvalidSender(); + _initializeOwner(owner_); + opSwitchboard = opSwitchboard_; + } +} diff --git a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol new file mode 100644 index 00000000..314c2b04 --- /dev/null +++ b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Unlicense +pragma solidity ^0.8.21; + +import "solady/auth/Ownable.sol"; + +import "../../../../contracts/base/AppGatewayBase.sol"; +import "./ISuperToken.sol"; +import "./SuperToken.sol"; + +contract SuperTokenAppGateway is AppGatewayBase, Ownable { + bytes32 public superToken = _createContractId("superToken"); + + event Transferred(bytes32 asyncId); + + struct ConstructorParams { + string name_; + string symbol_; + uint8 decimals_; + address initialSupplyHolder_; + uint256 initialSupply_; + } + + struct TransferOrder { + address srcToken; + address dstToken; + address user; + uint256 amount; + uint256 deadline; + } + + constructor( + address addressResolver_, + address auctionManager_, + address owner_, + bytes32 sbType_, + Fees memory fees_, + ConstructorParams memory params_ + ) AppGatewayBase(addressResolver_, auctionManager_, sbType_) { + creationCodeWithArgs[superToken] = abi.encodePacked( + type(SuperToken).creationCode, + abi.encode( + params_.name_, + params_.symbol_, + params_.decimals_, + params_.initialSupplyHolder_, + params_.initialSupply_ + ) + ); + + // sets the fees data like max fees, chain and token for all transfers + // they can be updated for each transfer as well + _setOverrides(fees_); + _initializeOwner(owner_); + } + + function deployContracts(uint32 chainSlug_) external async { + address switchboard = watcherPrecompile__().switchboards(chainSlug_, sbType); + bytes memory initData = abi.encodeWithSelector( + SuperToken.setupToken.selector, + owner(), + switchboard + ); + _deploy(superToken, chainSlug_, IsPlug.YES, initData); + } + + // no need to call this directly, will be called automatically after all contracts are deployed. + // check AppGatewayBase._deploy and AppGatewayBase.onBatchComplete + function initialize(uint32) public pure override { + return; + } + + function transfer(bytes memory order_) external async { + TransferOrder memory order = abi.decode(order_, (TransferOrder)); + ISuperToken(order.srcToken).burn(order.user, order.amount); + ISuperToken(order.dstToken).mint(order.user, order.amount); + + emit Transferred(_getCurrentAsyncId()); + } +} From d0125ee14a5ff3e6bcdd365cfdce861638f0c6f0 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 3 Mar 2025 17:06:55 +0400 Subject: [PATCH 06/23] fix: deploy script --- .../WatcherPrecompileConfig.sol | 21 +++--- hardhat-scripts/constants/enums.ts | 1 + hardhat-scripts/deploy/1.deploy.ts | 16 +++++ hardhat-scripts/deploy/2.roles.ts | 4 +- hardhat-scripts/deploy/3.upgradeManagers.ts | 64 +++++++++++++++---- 5 files changed, 83 insertions(+), 23 deletions(-) diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol index ca5e6fac..d08269c4 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol @@ -70,25 +70,24 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { /// @param switchboard_ The address of the switchboard function setOnChainContracts( uint32 chainSlug_, - bytes32 sbType_, - address switchboard_, address socket_, address contractFactoryPlug_, address feesPlug_ ) external override onlyOwner { - switchboards[chainSlug_][sbType_] = switchboard_; sockets[chainSlug_] = socket_; contractFactoryPlug[chainSlug_] = contractFactoryPlug_; feesPlug[chainSlug_] = feesPlug_; - emit OnChainContractSet( - chainSlug_, - sbType_, - switchboard_, - socket_, - contractFactoryPlug_, - feesPlug_ - ); + emit OnChainContractSet(chainSlug_, socket_, contractFactoryPlug_, feesPlug_); + } + + function setSwitchboard( + uint32 chainSlug_, + bytes32 sbType_, + address switchboard_ + ) external override onlyOwner { + switchboards[chainSlug_][sbType_] = switchboard_; + emit SwitchboardSet(chainSlug_, sbType_, switchboard_); } // @dev app gateway can set the valid plugs for each chain slug diff --git a/hardhat-scripts/constants/enums.ts b/hardhat-scripts/constants/enums.ts index 371023e1..68e0de2a 100644 --- a/hardhat-scripts/constants/enums.ts +++ b/hardhat-scripts/constants/enums.ts @@ -2,6 +2,7 @@ export enum CORE_CONTRACTS { Socket = "Socket", SocketBatcher = "SocketBatcher", FastSwitchboard = "FastSwitchboard", + OpInteropSwitchboard = "OpInteropSwitchboard", FeesPlug = "FeesPlug", ContractFactoryPlug = "ContractFactoryPlug", } diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 1b1353e9..09f9d8e9 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -241,6 +241,22 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = sb.address; + if ( + chain.toString() == "420120000" || + chain.toString() == "420120001" + ) { + contractName = CORE_CONTRACTS.OpInteropSwitchboard; + const opSwitchboard: Contract = await getOrDeploy( + contractName, + contractName, + `contracts/protocol/socket/switchboard/${contractName}.sol`, + [chain as ChainSlug, socket.address, socketOwner], + deployUtils + ); + deployUtils.addresses[CORE_CONTRACTS.FastSwitchboard] = + opSwitchboard.address; + } + contractName = CORE_CONTRACTS.FeesPlug; const feesPlug: Contract = await getOrDeploy( contractName, diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index 8aa12732..f81df2b3 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -22,6 +22,7 @@ import { ROLES } from "../constants/roles"; export const REQUIRED_ROLES = { FastSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], + // OpInteropSwitchboard: [ROLES.WATCHER_ROLE, ROLES.RESCUE_ROLE], Socket: [ROLES.GOVERNANCE_ROLE, ROLES.RESCUE_ROLE], FeesPlug: [ROLES.RESCUE_ROLE], ContractFactoryPlug: [ROLES.RESCUE_ROLE], @@ -88,7 +89,8 @@ async function setRolesForOnChain( for (const roleName of roles) { const targetAddress = - contractName === CORE_CONTRACTS.FastSwitchboard && + (contractName === CORE_CONTRACTS.FastSwitchboard || + contractName === CORE_CONTRACTS.OpInteropSwitchboard) && roleName === ROLES.WATCHER_ROLE ? watcher : signer.address; diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts index eaf3592f..21e173a2 100644 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ b/hardhat-scripts/deploy/3.upgradeManagers.ts @@ -52,8 +52,29 @@ export const main = async () => { socketContract ); - await setOnchainContracts(chain, addresses); + await setSwitchboard( + chain, + addresses, + "FAST", + CORE_CONTRACTS.FastSwitchboard + ); + if (chainAddresses[CORE_CONTRACTS.OpInteropSwitchboard]) { + await setSwitchboard( + chain, + addresses, + "OP_INTEROP", + CORE_CONTRACTS.OpInteropSwitchboard + ); + + await registerSb( + chainAddresses[CORE_CONTRACTS.OpInteropSwitchboard], + signer, + socketContract + ); + } + + await setOnchainContracts(chain, addresses); await storeAddresses(chainAddresses, chain, mode); } } catch (error) { @@ -75,24 +96,16 @@ async function setOnchainContracts(chain, addresses) { ) ).connect(signer); - const fastSBtype = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("FAST")); - const sbAddress = addresses[chain][CORE_CONTRACTS.FastSwitchboard]; const socketAddress = addresses[chain][CORE_CONTRACTS.Socket]; const contractFactoryPlugAddress = addresses[chain][CORE_CONTRACTS.ContractFactoryPlug]; const feesPlugAddress = addresses[chain][CORE_CONTRACTS.FeesPlug]; - - const currentSbAddress = await watcherPrecompile.switchboards( - chain, - fastSBtype - ); const currentSocket = await watcherPrecompile.sockets(chain); const currentContractFactoryPlug = await watcherPrecompile.contractFactoryPlug(chain); const currentFeesPlug = await watcherPrecompile.feesPlug(chain); if ( - currentSbAddress.toLowerCase() !== sbAddress.toLowerCase() || currentSocket.toLowerCase() !== socketAddress.toLowerCase() || currentContractFactoryPlug.toLowerCase() !== contractFactoryPlugAddress.toLowerCase() || @@ -102,8 +115,6 @@ async function setOnchainContracts(chain, addresses) { .connect(signer) .setOnChainContracts( chain, - fastSBtype, - sbAddress, socketAddress, contractFactoryPlugAddress, feesPlugAddress @@ -114,6 +125,37 @@ async function setOnchainContracts(chain, addresses) { } } +async function setSwitchboard(chain, addresses, sbType, contractName) { + const providerInstance = getProviderFromChainSlug(EVMX_CHAIN_ID as ChainSlug); + const signer: Wallet = new ethers.Wallet( + process.env.WATCHER_PRIVATE_KEY as string, + providerInstance + ); + const EVMxAddresses = addresses[EVMX_CHAIN_ID]!; + const watcherPrecompile = ( + await getInstance( + EVMxCoreContracts.WatcherPrecompile, + EVMxAddresses[EVMxCoreContracts.WatcherPrecompile] + ) + ).connect(signer); + + const sbTypeHash = ethers.utils.keccak256(ethers.utils.toUtf8Bytes(sbType)); + const sbAddress = addresses[chain][contractName]; + const currentSbAddress = await watcherPrecompile.switchboards( + chain, + sbTypeHash + ); + + if (currentSbAddress.toLowerCase() !== sbAddress.toLowerCase()) { + const tx = await watcherPrecompile + .connect(signer) + .setSwitchboard(chain, sbTypeHash, sbAddress); + + console.log(`Setting switchboard for ${chain}, txHash: `, tx.hash); + await tx.wait(); + } +} + const registerSb = async (sbAddress, signer, socket) => { try { // used fast switchboard here as all have same function signature From 902e2151ea7a454fe0a56477f30599bfa8278818 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 3 Mar 2025 17:07:06 +0400 Subject: [PATCH 07/23] fix: lint --- contracts/base/ProxyFactory.sol | 2 +- .../socket/switchboard/SuperchainEnabled.sol | 31 ++++++++----------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/contracts/base/ProxyFactory.sol b/contracts/base/ProxyFactory.sol index d6dd269f..0f903337 100644 --- a/contracts/base/ProxyFactory.sol +++ b/contracts/base/ProxyFactory.sol @@ -4,4 +4,4 @@ import {ERC1967Factory} from "solady/utils/ERC1967Factory.sol"; contract ProxyFactory is ERC1967Factory { constructor() {} -} \ No newline at end of file +} diff --git a/contracts/protocol/socket/switchboard/SuperchainEnabled.sol b/contracts/protocol/socket/switchboard/SuperchainEnabled.sol index 0dddc650..21105805 100644 --- a/contracts/protocol/socket/switchboard/SuperchainEnabled.sol +++ b/contracts/protocol/socket/switchboard/SuperchainEnabled.sol @@ -21,23 +21,23 @@ abstract contract SuperchainEnabled { address destAddress, bytes memory data ) internal { - IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) - .sendMessage(destChainId, destAddress, data); + IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER).sendMessage( + destChainId, + destAddress, + data + ); } /// @notice Checks if the cross-domain message is from the expected source /// @param expectedSource The expected source address /// @return bool True if the message is from the expected source, false otherwise - function _isValidCrossDomainSender( - address expectedSource - ) internal view returns (bool) { + function _isValidCrossDomainSender(address expectedSource) internal view returns (bool) { if (msg.sender != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { return false; } return - IL2ToL2CrossDomainMessenger( - Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER - ).crossDomainMessageSender() == expectedSource; + IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) + .crossDomainMessageSender() == expectedSource; } /// @notice Modifier to validate messages from a specific address @@ -52,24 +52,19 @@ abstract contract SuperchainEnabled { /// @notice Modifier to validate messages from a specific address on a specific chain /// @param expectedSource The expected source address /// @param expectedChainId The expected source chain ID - modifier xOnlyFromContract( - address expectedSource, - uint256 expectedChainId - ) { + modifier xOnlyFromContract(address expectedSource, uint256 expectedChainId) { if (msg.sender != Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) { revert CallerNotL2ToL2CrossDomainMessenger(); } if ( - IL2ToL2CrossDomainMessenger( - Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER - ).crossDomainMessageSender() != expectedSource + IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) + .crossDomainMessageSender() != expectedSource ) { revert InvalidCrossDomainSender(); } if ( - IL2ToL2CrossDomainMessenger( - Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER - ).crossDomainMessageSource() != expectedChainId + IL2ToL2CrossDomainMessenger(Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER) + .crossDomainMessageSource() != expectedChainId ) { revert InvalidSourceChain(); } From a85255525127939b5b1533ceb53f6146b320a169 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 3 Mar 2025 17:29:36 +0400 Subject: [PATCH 08/23] fix: build --- contracts/interfaces/ISwitchboard.sol | 17 +++++++ contracts/interfaces/IWatcherPrecompile.sol | 4 +- contracts/protocol/socket/SocketBatcher.sol | 45 ++++++++++++++++--- .../socket/switchboard/FastSwitchboard.sol | 6 +++ .../switchboard/OpInteropSwitchboard.sol | 13 +----- .../WatcherPrecompileConfig.sol | 5 --- test/OpBridge.t.sol | 44 ++++++++++++++++++ test/SetupTest.t.sol | 11 +++-- 8 files changed, 118 insertions(+), 27 deletions(-) create mode 100644 test/OpBridge.t.sol diff --git a/contracts/interfaces/ISwitchboard.sol b/contracts/interfaces/ISwitchboard.sol index 394d4044..151a8389 100644 --- a/contracts/interfaces/ISwitchboard.sol +++ b/contracts/interfaces/ISwitchboard.sol @@ -7,6 +7,17 @@ pragma solidity ^0.8.21; * different blockchain networks. */ interface ISwitchboard { + struct PayloadParams { + bytes32 payloadId; + address appGateway; + address transmitter; + address target; + uint256 value; + uint256 deadline; + uint256 executionGasLimit; + bytes payload; + } + /** * @notice Checks if a packet can be allowed to go through the switchboard. * @param digest_ the packet digest. @@ -16,4 +27,10 @@ interface ISwitchboard { function allowPacket(bytes32 digest_, bytes32 packetId_) external view returns (bool); function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external; + + function syncOut( + bytes32 digest_, + bytes32 payloadId_, + PayloadParams calldata payloadParams_ + ) external; } diff --git a/contracts/interfaces/IWatcherPrecompile.sol b/contracts/interfaces/IWatcherPrecompile.sol index 0a54fa6a..9abb3b73 100644 --- a/contracts/interfaces/IWatcherPrecompile.sol +++ b/contracts/interfaces/IWatcherPrecompile.sol @@ -22,13 +22,13 @@ interface IWatcherPrecompile { /// @dev Only callable by authorized addresses function setOnChainContracts( uint32 chainSlug_, - bytes32 sbType_, - address switchboard_, address socket_, address contractFactoryPlug_, address feesPlug_ ) external; + function setSwitchboard(uint32 chainSlug_, bytes32 sbType_, address switchboard_) external; + /// @notice Retrieves plug configuration for a specific network and plug /// @param chainSlug_ The identifier of the network /// @param plug_ The address of the plug diff --git a/contracts/protocol/socket/SocketBatcher.sol b/contracts/protocol/socket/SocketBatcher.sol index 726101e8..d7938c17 100644 --- a/contracts/protocol/socket/SocketBatcher.sol +++ b/contracts/protocol/socket/SocketBatcher.sol @@ -5,6 +5,7 @@ import "solady/auth/Ownable.sol"; import "../../interfaces/ISocket.sol"; import "../../interfaces/ISwitchboard.sol"; import "../utils/RescueFundsLib.sol"; +import {ECDSA} from "solady/utils/ECDSA.sol"; import {AttestAndExecutePayloadParams} from "../../protocol/utils/common/Structs.sol"; /** @@ -15,6 +16,9 @@ contract SocketBatcher is Ownable { // socket contract ISocket public immutable socket__; + uint256 public constant OP_DEVNET_0_CHAIN_ID = 420120000; + uint256 public constant OP_DEVNET_1_CHAIN_ID = 420120001; + /** * @notice Initializes the TransmitManager contract * @param socket_ The address of socket contract @@ -27,7 +31,7 @@ contract SocketBatcher is Ownable { function attestAndExecute( AttestAndExecutePayloadParams calldata params_ - ) external payable returns (bytes memory) { + ) external payable returns (bytes memory returnData) { ISwitchboard(params_.switchboard).attest(params_.payloadId, params_.digest, params_.proof); ISocket.ExecuteParams memory executeParams = ISocket.ExecuteParams({ @@ -37,12 +41,43 @@ contract SocketBatcher is Ownable { deadline: params_.deadline, payload: params_.payload }); - return - socket__.execute{value: msg.value}( - params_.appGateway, - executeParams, + + returnData = socket__.execute{value: msg.value}( + params_.appGateway, + executeParams, + params_.transmitterSignature + ); + + if (block.chainid == OP_DEVNET_0_CHAIN_ID || block.chainid == OP_DEVNET_1_CHAIN_ID) { + address transmitter = _recoverSigner( + keccak256(abi.encode(address(socket__), params_.payloadId)), params_.transmitterSignature ); + ISwitchboard.PayloadParams memory payloadParams = ISwitchboard.PayloadParams({ + payloadId: params_.payloadId, + appGateway: params_.appGateway, + transmitter: transmitter, + target: params_.target, + value: 0, + deadline: params_.deadline, + executionGasLimit: params_.executionGasLimit, + payload: params_.payload + }); + ISwitchboard(params_.switchboard).syncOut( + params_.digest, + params_.payloadId, + payloadParams + ); + } + } + + function _recoverSigner( + bytes32 digest_, + bytes memory signature_ + ) internal view returns (address signer) { + bytes32 digest = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_)); + // recovered signer is checked for the valid roles later + signer = ECDSA.recover(digest, signature_); } function rescueFunds(address token_, address to_, uint256 amount_) external onlyOwner { diff --git a/contracts/protocol/socket/switchboard/FastSwitchboard.sol b/contracts/protocol/socket/switchboard/FastSwitchboard.sol index 513f40f3..acbbce5b 100644 --- a/contracts/protocol/socket/switchboard/FastSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/FastSwitchboard.sol @@ -78,4 +78,10 @@ contract FastSwitchboard is SwitchboardBase { function registerSwitchboard() external onlyOwner { socket__.registerSwitchboard(); } + + function syncOut( + bytes32 digest_, + bytes32 payloadId_, + PayloadParams calldata payloadParams_ + ) external virtual {} } diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol index b60faf6b..660f058c 100644 --- a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -13,17 +13,6 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { address public remoteAddress; uint256 public remoteChainId; - struct PayloadParams { - bytes32 payloadId; - address appGateway; - address transmitter; - address target; - uint256 value; - uint256 deadline; - uint256 executionGasLimit; - bytes payload; - } - modifier onlyToken() { if (msg.sender != token) revert OnlyTokenAllowed(); _; @@ -52,7 +41,7 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { bytes32 digest_, bytes32 payloadId_, PayloadParams calldata payloadParams_ - ) external { + ) external override { if (isSyncedOut[digest_]) return; isSyncedOut[digest_] = true; diff --git a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol index d08269c4..a3481e4b 100644 --- a/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol +++ b/contracts/protocol/watcherPrecompile/WatcherPrecompileConfig.sol @@ -25,15 +25,11 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { /// @notice Emitted when contracts are set for a network /// @param chainSlug The identifier of the network - /// @param sbType The type of switchboard - /// @param switchboard The address of the switchboard /// @param socket The address of the socket /// @param contractFactoryPlug The address of the contract factory plug /// @param feesPlug The address of the fees plug event OnChainContractSet( uint32 chainSlug, - bytes32 sbType, - address switchboard, address socket, address contractFactoryPlug, address feesPlug @@ -67,7 +63,6 @@ abstract contract WatcherPrecompileConfig is WatcherPrecompileLimits { /// @notice Sets the switchboard for a network /// @param chainSlug_ The identifier of the network - /// @param switchboard_ The address of the switchboard function setOnChainContracts( uint32 chainSlug_, address socket_, diff --git a/test/OpBridge.t.sol b/test/OpBridge.t.sol new file mode 100644 index 00000000..9efc510d --- /dev/null +++ b/test/OpBridge.t.sol @@ -0,0 +1,44 @@ +pragma solidity ^0.8.21; + +import "forge-std/Test.sol"; + +import "../contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol"; + +// import "./mocks/MockSocket.sol"; + +// contract OpInteropSwitchboardTest is Test { +// OpInteropSwitchboard public switchboard; +// MockSocket public mockSocket; +// address public owner; +// address public watcher; +// bytes32 constant WATCHER_ROLE = keccak256("WATCHER_ROLE"); + +// function setUp() public { +// owner = address(this); // Test contract is the owner +// mockSocket = new MockSocket(); +// switchboard = new OpInteropSwitchboard(1, address(mockSocket), owner); + +// // Setup roles +// watcher = address(0x1); +// switchboard.grantRole(WATCHER_ROLE, watcher); +// } + +// function testAttest() public { +// // Mock data +// bytes32 payloadId = keccak256("payload1"); +// bytes32 digest = keccak256("digest1"); +// bytes memory proof = abi.encodePacked(watcher); + +// // Simulate calling the attest function +// switchboard.attest(payloadId, digest, proof); + +// // Check if the digest is marked as attested +// assertTrue(switchboard.isAttested(digest)); + +// // Check if the payloadId to digest mapping is correct +// assertEq(switchboard.payloadIdToDigest(payloadId), digest); + +// // Check for event emission, assuming an event Attested is emitted +// // This part requires event handling setup in ds-test, which is not shown here +// } +// } diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 8103bbd6..5c7dea27 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -80,16 +80,21 @@ contract SetupTest is Test { switchboard.grantWatcherRole(watcherEOA); vm.stopPrank(); - hoax(watcherEOA); + vm.startPrank(watcherEOA); watcherPrecompile.setOnChainContracts( chainSlug_, - FAST, - address(switchboard), address(socket), address(contractFactoryPlug), address(feesPlug) ); + watcherPrecompile.setSwitchboard( + chainSlug_, + keccak256("FAST"), + address(switchboard) + ); + vm.stopPrank(); + return SocketContracts({ chainSlug: chainSlug_, From e98b878867e6dedd84384129e8068e34b3ffadd5 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Mon, 3 Mar 2025 17:41:25 +0400 Subject: [PATCH 09/23] fix: remove ids --- contracts/protocol/socket/SocketBatcher.sol | 39 ++++++++------------- hardhat-scripts/deploy/1.deploy.ts | 33 ++++++++--------- 2 files changed, 29 insertions(+), 43 deletions(-) diff --git a/contracts/protocol/socket/SocketBatcher.sol b/contracts/protocol/socket/SocketBatcher.sol index d7938c17..fdff816d 100644 --- a/contracts/protocol/socket/SocketBatcher.sol +++ b/contracts/protocol/socket/SocketBatcher.sol @@ -16,9 +16,6 @@ contract SocketBatcher is Ownable { // socket contract ISocket public immutable socket__; - uint256 public constant OP_DEVNET_0_CHAIN_ID = 420120000; - uint256 public constant OP_DEVNET_1_CHAIN_ID = 420120001; - /** * @notice Initializes the TransmitManager contract * @param socket_ The address of socket contract @@ -48,27 +45,21 @@ contract SocketBatcher is Ownable { params_.transmitterSignature ); - if (block.chainid == OP_DEVNET_0_CHAIN_ID || block.chainid == OP_DEVNET_1_CHAIN_ID) { - address transmitter = _recoverSigner( - keccak256(abi.encode(address(socket__), params_.payloadId)), - params_.transmitterSignature - ); - ISwitchboard.PayloadParams memory payloadParams = ISwitchboard.PayloadParams({ - payloadId: params_.payloadId, - appGateway: params_.appGateway, - transmitter: transmitter, - target: params_.target, - value: 0, - deadline: params_.deadline, - executionGasLimit: params_.executionGasLimit, - payload: params_.payload - }); - ISwitchboard(params_.switchboard).syncOut( - params_.digest, - params_.payloadId, - payloadParams - ); - } + address transmitter = _recoverSigner( + keccak256(abi.encode(address(socket__), params_.payloadId)), + params_.transmitterSignature + ); + ISwitchboard.PayloadParams memory payloadParams = ISwitchboard.PayloadParams({ + payloadId: params_.payloadId, + appGateway: params_.appGateway, + transmitter: transmitter, + target: params_.target, + value: 0, + deadline: params_.deadline, + executionGasLimit: params_.executionGasLimit, + payload: params_.payload + }); + ISwitchboard(params_.switchboard).syncOut(params_.digest, params_.payloadId, payloadParams); } function _recoverSigner( diff --git a/hardhat-scripts/deploy/1.deploy.ts b/hardhat-scripts/deploy/1.deploy.ts index 09f9d8e9..4bb7ef74 100644 --- a/hardhat-scripts/deploy/1.deploy.ts +++ b/hardhat-scripts/deploy/1.deploy.ts @@ -231,31 +231,26 @@ const deploySocketContracts = async () => { ); deployUtils.addresses[contractName] = batcher.address; - contractName = CORE_CONTRACTS.FastSwitchboard; - const sb: Contract = await getOrDeploy( + // contractName = CORE_CONTRACTS.FastSwitchboard; + // const sb: Contract = await getOrDeploy( + // contractName, + // contractName, + // `contracts/protocol/socket/switchboard/${contractName}.sol`, + // [chain as ChainSlug, socket.address, socketOwner], + // deployUtils + // ); + // deployUtils.addresses[contractName] = sb.address; + + contractName = CORE_CONTRACTS.OpInteropSwitchboard; + const opSwitchboard: Contract = await getOrDeploy( contractName, contractName, `contracts/protocol/socket/switchboard/${contractName}.sol`, [chain as ChainSlug, socket.address, socketOwner], deployUtils ); - deployUtils.addresses[contractName] = sb.address; - - if ( - chain.toString() == "420120000" || - chain.toString() == "420120001" - ) { - contractName = CORE_CONTRACTS.OpInteropSwitchboard; - const opSwitchboard: Contract = await getOrDeploy( - contractName, - contractName, - `contracts/protocol/socket/switchboard/${contractName}.sol`, - [chain as ChainSlug, socket.address, socketOwner], - deployUtils - ); - deployUtils.addresses[CORE_CONTRACTS.FastSwitchboard] = - opSwitchboard.address; - } + deployUtils.addresses[CORE_CONTRACTS.FastSwitchboard] = + opSwitchboard.address; contractName = CORE_CONTRACTS.FeesPlug; const feesPlug: Contract = await getOrDeploy( From eb7ffa35200f5bf8122ae756d374073288ed2cc1 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 12:36:11 +0400 Subject: [PATCH 10/23] fix: burn decode --- .../switchboard/OpInteropSwitchboard.sol | 31 ++++++++++--- test/OpBridge.t.sol | 44 ------------------- 2 files changed, 26 insertions(+), 49 deletions(-) delete mode 100644 test/OpBridge.t.sol diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol index 660f058c..65c3ca72 100644 --- a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -24,7 +24,13 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { uint32 chainSlug_, ISocket socket_, address owner_ - ) FastSwitchboard(chainSlug_, socket_, owner_) {} + ) FastSwitchboard(chainSlug_, socket_, owner_) { + if (chainSlug_ == 420120000) { + remoteChainId = 420120001; + } else if (chainSlug_ == 420120001) { + remoteChainId = 420120000; + } + } function attest(bytes32 payloadId_, bytes32 digest_, bytes calldata proof_) external override { address watcher = _recoverSigner(keccak256(abi.encode(address(this), digest_)), proof_); @@ -56,8 +62,9 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { ISocket.ExecutionStatus isExecuted = socket__.payloadExecuted(payloadId_); if (isExecuted != ISocket.ExecutionStatus.Executed) return; - (address user, uint256 amount) = _decodeMint(payloadParams_.payload); + (address user, uint256 amount, bool isBurn) = _decodeBurn(payloadParams_.payload); + if (!isBurn) return; _xMessageContract( remoteChainId, remoteAddress, @@ -72,10 +79,24 @@ contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { unminted[user_] += amount_; } - function _decodeMint( + function _decodeBurn( bytes memory payload - ) internal pure returns (address user, uint256 amount) { - (, , amount, user) = abi.decode(payload, (bytes4, address, uint256, address)); + ) internal pure returns (address user, uint256 amount, bool isBurn) { + // Extract function selector from payload + bytes4 selector; + assembly { + // Load first 4 bytes from payload data + selector := mload(add(payload, 32)) + } + // Check if selector matches burn() + if (selector != bytes4(0x9dc29fac)) return (user, amount, false); + + // Decode the payload after the selector (skip first 4 bytes) + assembly { + user := mload(add(add(payload, 36), 0)) // 32 + 4 bytes offset for first param + amount := mload(add(add(payload, 68), 0)) // 32 + 4 + 32 bytes offset for second param + } + isBurn = true; } function _packPayload(PayloadParams memory payloadParams_) internal pure returns (bytes32) { diff --git a/test/OpBridge.t.sol b/test/OpBridge.t.sol deleted file mode 100644 index 9efc510d..00000000 --- a/test/OpBridge.t.sol +++ /dev/null @@ -1,44 +0,0 @@ -pragma solidity ^0.8.21; - -import "forge-std/Test.sol"; - -import "../contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol"; - -// import "./mocks/MockSocket.sol"; - -// contract OpInteropSwitchboardTest is Test { -// OpInteropSwitchboard public switchboard; -// MockSocket public mockSocket; -// address public owner; -// address public watcher; -// bytes32 constant WATCHER_ROLE = keccak256("WATCHER_ROLE"); - -// function setUp() public { -// owner = address(this); // Test contract is the owner -// mockSocket = new MockSocket(); -// switchboard = new OpInteropSwitchboard(1, address(mockSocket), owner); - -// // Setup roles -// watcher = address(0x1); -// switchboard.grantRole(WATCHER_ROLE, watcher); -// } - -// function testAttest() public { -// // Mock data -// bytes32 payloadId = keccak256("payload1"); -// bytes32 digest = keccak256("digest1"); -// bytes memory proof = abi.encodePacked(watcher); - -// // Simulate calling the attest function -// switchboard.attest(payloadId, digest, proof); - -// // Check if the digest is marked as attested -// assertTrue(switchboard.isAttested(digest)); - -// // Check if the payloadId to digest mapping is correct -// assertEq(switchboard.payloadIdToDigest(payloadId), digest); - -// // Check for event emission, assuming an event Attested is emitted -// // This part requires event handling setup in ds-test, which is not shown here -// } -// } From 271cffa5768d8bfdf2e3bbe44537080e7d06d859 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 12:37:13 +0400 Subject: [PATCH 11/23] fix: script --- hardhat-scripts/deploy/3.upgradeManagers.ts | 48 ++++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts index 21e173a2..53cb9db9 100644 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ b/hardhat-scripts/deploy/3.upgradeManagers.ts @@ -7,7 +7,7 @@ import { import { config as dotenvConfig } from "dotenv"; dotenvConfig(); -import { Wallet } from "ethers"; +import { constants, Wallet } from "ethers"; import { ethers } from "hardhat"; import { chains, EVMX_CHAIN_ID, mode } from "../config"; import { @@ -52,6 +52,19 @@ export const main = async () => { socketContract ); + const remoteChain = + chain.toString() == "420120000" + ? (420120001 as ChainSlug) + : (420120000 as ChainSlug); + + await addRemoteAddress( + chainAddresses[CORE_CONTRACTS.OpInteropSwitchboard], + addresses[remoteChain]?.[CORE_CONTRACTS.OpInteropSwitchboard], + chain, + signer, + socketContract + ); + await setSwitchboard( chain, addresses, @@ -108,7 +121,7 @@ async function setOnchainContracts(chain, addresses) { if ( currentSocket.toLowerCase() !== socketAddress.toLowerCase() || currentContractFactoryPlug.toLowerCase() !== - contractFactoryPlugAddress.toLowerCase() || + contractFactoryPlugAddress.toLowerCase() || currentFeesPlug.toLowerCase() !== feesPlugAddress.toLowerCase() ) { const tx = await watcherPrecompile @@ -180,6 +193,37 @@ const registerSb = async (sbAddress, signer, socket) => { } }; +const addRemoteAddress = async ( + sbAddress, + remoteAddress, + chain, + signer, + socket +) => { + try { + // used fast switchboard here as all have same function signature + const switchboard = ( + await getInstance(CORE_CONTRACTS.OpInteropSwitchboard, sbAddress) + ).connect(signer); + + // send overrides while reading capacitor to avoid errors on mantle chain + // some chains give balance error if gas price is used with from address as zero + // therefore override from address as well + const remoteAddressContract = await socket.remoteAddress(); + if (remoteAddressContract == constants.AddressZero) { + console.log( + `Adding remote address ${remoteAddress} to Switchboard ${sbAddress} on ${chain}` + ); + const registerTx = await switchboard.setRemoteAddress(remoteAddress); + + console.log(`Tx: ${registerTx.hash}`); + await registerTx.wait(); + } + } catch (error) { + throw error; + } +}; + main() .then(() => process.exit(0)) .catch((error: Error) => { From df97c7bb4ede9e3baef454869a915255a770a75e Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 12:38:00 +0400 Subject: [PATCH 12/23] fix: tests --- test/SetupTest.t.sol | 16 +++++++-------- test/apps/SuperToken.t.sol | 20 +++++++++++-------- .../super-token-op/SuperToken.sol | 2 +- .../super-token/SuperTokenAppGateway.sol | 6 +++--- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/test/SetupTest.t.sol b/test/SetupTest.t.sol index 5c7dea27..c1420dd6 100644 --- a/test/SetupTest.t.sol +++ b/test/SetupTest.t.sol @@ -9,6 +9,7 @@ import "../contracts/interfaces/IForwarder.sol"; import "../contracts/protocol/utils/common/AccessRoles.sol"; import {Socket} from "../contracts/protocol/socket/Socket.sol"; import "../contracts/protocol/socket/switchboard/FastSwitchboard.sol"; +import "../contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol"; import "../contracts/protocol/socket/SocketBatcher.sol"; import "../contracts/protocol/AddressResolver.sol"; import {ContractFactoryPlug} from "../contracts/protocol/payload-delivery/ContractFactoryPlug.sol"; @@ -30,8 +31,9 @@ contract SetupTest is Test { address watcherEOA = 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266; address transmitterEOA = 0x70997970C51812dc3A010C7d01b50e0d17dc79C8; - uint32 arbChainSlug = 421614; - uint32 optChainSlug = 11155420; + uint32 arbChainSlug = 420120000; + uint32 optChainSlug = 420120001; + uint32 evmxSlug = 1; uint256 expiryTime = 10000000; @@ -45,7 +47,7 @@ contract SetupTest is Test { struct SocketContracts { uint32 chainSlug; Socket socket; - FastSwitchboard switchboard; + OpInteropSwitchboard switchboard; SocketBatcher socketBatcher; ContractFactoryPlug contractFactoryPlug; FeesPlug feesPlug; @@ -66,7 +68,7 @@ contract SetupTest is Test { function deploySocket(uint32 chainSlug_) internal returns (SocketContracts memory) { Socket socket = new Socket(chainSlug_, owner, "test"); SocketBatcher socketBatcher = new SocketBatcher(owner, socket); - FastSwitchboard switchboard = new FastSwitchboard(chainSlug_, socket, owner); + OpInteropSwitchboard switchboard = new OpInteropSwitchboard(chainSlug_, socket, owner); FeesPlug feesPlug = new FeesPlug(address(socket), owner); ContractFactoryPlug contractFactoryPlug = new ContractFactoryPlug(address(socket), owner); @@ -88,11 +90,7 @@ contract SetupTest is Test { address(feesPlug) ); - watcherPrecompile.setSwitchboard( - chainSlug_, - keccak256("FAST"), - address(switchboard) - ); + watcherPrecompile.setSwitchboard(chainSlug_, keccak256("FAST"), address(switchboard)); vm.stopPrank(); return diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index c3c98bdb..bc6e9cfd 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {SuperTokenAppGateway} from "./app-gateways/super-token/SuperTokenAppGateway.sol"; -import {SuperToken} from "./app-gateways/super-token/SuperToken.sol"; +import {SuperTokenAppGateway} from "./app-gateways/super-token-op/SuperTokenAppGateway.sol"; +import {SuperToken} from "./app-gateways/super-token-op/SuperToken.sol"; import "../DeliveryHelper.t.sol"; import {QUERY, FINALIZE, SCHEDULE} from "../../contracts/protocol/utils/common/Constants.sol"; @@ -36,7 +36,7 @@ contract SuperTokenTest is DeliveryHelperTest { bytes32[] contractIds = new bytes32[](1); /// @dev Test amount for token transfers (0.01 ETH) - uint256 srcAmount = 0.01 ether; + uint256 amount = 0.01 ether; /// @dev Structure holding transfer order details SuperTokenAppGateway.TransferOrder transferOrder; @@ -155,11 +155,15 @@ contract SuperTokenTest is DeliveryHelperTest { uint256 arbBalanceBefore = SuperToken(onChainArb).balanceOf(owner); uint256 optBalanceBefore = SuperToken(onChainOpt).balanceOf(owner); + hoax(owner); + getSocketConfig(optChainSlug).switchboard.setToken(onChainOpt); + getSocketConfig(optChainSlug).switchboard.syncIn(owner, amount); + transferOrder = SuperTokenAppGateway.TransferOrder({ srcToken: forwarderArb, dstToken: forwarderOpt, user: owner, - srcAmount: srcAmount, + amount: amount, deadline: block.timestamp + 1000000 }); bytes memory encodedOrder = abi.encode(transferOrder); @@ -174,13 +178,13 @@ contract SuperTokenTest is DeliveryHelperTest { assertEq( SuperToken(onChainArb).balanceOf(owner), - arbBalanceBefore - srcAmount, - "Arb balance should be decreased by srcAmount" + arbBalanceBefore - amount, + "Arb balance should be decreased by amount" ); assertEq( SuperToken(onChainOpt).balanceOf(owner), - optBalanceBefore + srcAmount, - "Opt balance should be increased by srcAmount" + optBalanceBefore + amount, + "Opt balance should be increased by amount" ); } } diff --git a/test/apps/app-gateways/super-token-op/SuperToken.sol b/test/apps/app-gateways/super-token-op/SuperToken.sol index 0ea08bbd..82f00184 100644 --- a/test/apps/app-gateways/super-token-op/SuperToken.sol +++ b/test/apps/app-gateways/super-token-op/SuperToken.sol @@ -30,11 +30,11 @@ contract SuperToken is ERC20, Ownable, PlugBase { } function mint(address user_, uint256 amount_) external onlySocket { + ISwitchboard(opSwitchboard).checkAndConsume(user_, amount_); _mint(user_, amount_); } function burn(address user_, uint256 amount_) external onlySocket { - ISwitchboard(opSwitchboard).checkAndConsume(user_, amount_); _burn(user_, amount_); } diff --git a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol index 1b73ac90..caa33154 100644 --- a/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token/SuperTokenAppGateway.sol @@ -23,7 +23,7 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { address srcToken; address dstToken; address user; - uint256 srcAmount; + uint256 amount; uint256 deadline; } @@ -65,8 +65,8 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); - ISuperToken(order.srcToken).burn(order.user, order.srcAmount); - ISuperToken(order.dstToken).mint(order.user, order.srcAmount); + ISuperToken(order.srcToken).burn(order.user, order.amount); + ISuperToken(order.dstToken).mint(order.user, order.amount); emit Transferred(_getCurrentAsyncId()); } From 7444044f6bb6fed577b306bc452ecacc314f9830 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 12:49:54 +0400 Subject: [PATCH 13/23] chore: configs --- .env.sample | 2 + deployments/dev_addresses.json | 33 +---- deployments/dev_verification.json | 229 +----------------------------- hardhat-scripts/config/config.ts | 10 +- hardhat.config.ts | 31 +++- 5 files changed, 38 insertions(+), 267 deletions(-) diff --git a/.env.sample b/.env.sample index 607b51c5..55ec0ef1 100644 --- a/.env.sample +++ b/.env.sample @@ -4,6 +4,8 @@ SEPOLIA_RPC="https://rpc.ankr.com/eth_sepolia/" ARBITRUM_SEPOLIA_RPC="https://rpc.ankr.com/arbitrum_sepolia" OPTIMISM_SEPOLIA_RPC="https://rpc.ankr.com/optimism_sepolia" BASE_SEPOLIA_RPC="https://rpc.ankr.com/base_sepolia" +INTEROP_ALPH_0_RPC="https://interop-alpha-0.optimism.io" +INTEROP_ALPH_1_RPC="https://interop-alpha-1.optimism.io" # EVMx key addresses # Find the most up to date addresses in deployments/dev_addresses.json diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 242369d1..0967ef42 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1,32 +1 @@ -{ - "421614": { - "ContractFactoryPlug": "0xCE9aF7Fb0Ee31276Ea64Cd7414d54eC57dA9b675", - "FastSwitchboard": "0x772088727d003f5A6Cf816E745ba6B8F8dEBbCe9", - "FeesPlug": "0xcc38176545fa5f6c2aB970F6d2D62b2D90bBA3Ba", - "Socket": "0xdE177c392Ad47377BA944215A944f530F79E1d87", - "SocketBatcher": "0x6BF08F11bDA6CD571Bc942F23ec38b8652FFfB2D", - "startBlock": 127798344 - }, - "7625382": { - "AddressResolver": "0x403eCBcC4d4bB8Fad09034bf0d197dDC626C832f", - "AddressResolverImpl": "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", - "AuctionManager": "0x7dc45C49650e2914e3fA6E194e2080775c58256E", - "AuctionManagerImpl": "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "DeliveryHelper": "0x0861f0888125e5A243C7af2c3E0F80C357c4c0C0", - "DeliveryHelperImpl": "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "ERC1967Factory": "0x945e9ab4c08c225C10F178a0bd600BcC2bA7Cc78", - "FeesManager": "0x777fAAf1c30Ce8E68262b1cbF0a752d4f1bA652C", - "FeesManagerImpl": "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", - "startBlock": 73062, - "WatcherPrecompile": "0xadA397123A6E80F67b1887895A62B2D9273E50b4", - "WatcherPrecompileImpl": "0x71956F006Ec5434581D3Fd5E7224BB3bae231907" - }, - "11155420": { - "ContractFactoryPlug": "0x289A0413420f812a7b05F931FB0726168121ae5a", - "FastSwitchboard": "0x59D9c8C5515cF9C8A9c83458E3D78C2a246E3e7C", - "FeesPlug": "0x285d1b2e93c1c74E141dC37f759B8aFAcD479b2b", - "Socket": "0xa347A8475d4d218b22e8b0cc90FF76B3e6c8043c", - "SocketBatcher": "0x4a7Ccf2845222172A8B7Fc6E132eDb64cCB4E4a4", - "startBlock": 24425961 - } -} +{} diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 4c11da30..9e26dfee 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1,228 +1 @@ -{ - "84532": [ - [ - "0xA557EBE094F939ae6eE8F18c8F88D06182168786", - "ContractFactoryPlug", - "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", - [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xD78f99D62BeaF0918bB0601C68EB537b6703Ce63", - "FeesPlug", - "contracts/protocol/payload-delivery/FeesPlug.sol", - [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x06234dB2D69Ac158793a3ce59c3764422028E964", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 84532, - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xA944BBe5D4F67a242C9e92d539fF2d55616283a7", - "SocketBatcher", - "contracts/protocol/socket/SocketBatcher.sol", - [ - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F" - ] - ], - [ - "0x6c40Fb39B03e32EC4D23e31DdE6D10283F2C7b4F", - "Socket", - "contracts/protocol/socket/Socket.sol", - [84532, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ], - "421614": [ - [ - "0x29E632aE79107A82C637016CA21030d922De5375", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 421614, - "0xa0E1738a9Fc0698789866e09d7A335d30128C5C5", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ] - ], - "7625382": [ - [ - "0xa07e38cAB46eAA358C3653C63219f1009e8F7789", - "AuctionManager", - "contracts/protocol/payload-delivery/AuctionManager.sol", - [] - ], - [ - "0x9F10A0c71178dbD4d049f2C04fD0e34966134b9e", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0xB423eE3bffc3604F96B59cF419C48AE05b8E9d0b", - "FeesManager", - "contracts/protocol/payload-delivery/FeesManager.sol", - [] - ], - [ - "0x71956F006Ec5434581D3Fd5E7224BB3bae231907", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0xbAeF84edEae864Ff22Bd9c9912AdfF84aD490d82", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x945e9ab4c08c225C10F178a0bd600BcC2bA7Cc78", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] - ], - [ - "0x09B503e744DCB2cA2827ce5AF08Fd49Ba06D17e4", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x6c73961Bfaa2c9c1d0D7F4C213aa85af15b7CB54", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0xd151bD217704F72f717C2111207e6Bb33B609f61", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x8dcEE196AFECe27545687426914d2830ff2dbc35", - "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", - [] - ], - [ - "0xb1F4CbFCE786aA8B553796Fb06c04Dd461967A16", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x23EF7Af3bC1009EA6f95c3389921d5cB19950182", - "AuctionManager", - "contracts/protocol/payload-delivery/app-gateway/AuctionManager.sol", - [] - ], - [ - "0x4CCF8F511A364827E5e6749b196BB26Ea00bF512", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0x39f9b492695375F703450c5653c9D80CFa38e6eD", - "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", - [] - ], - [ - "0x234cA13f5dC4a2467c81E515F57238BF9f53156E", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0xbBfb525ADc6eC38Ef0D4b807d327c2Dd1C286de1", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x208dC31cd6042a09bbFDdB31614A337a51b870ba", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] - ], - [ - "0x4C68058509d754Cc0dE474eBC20aE94e4787E704", - "AuctionManager", - "contracts/protocol/payload-delivery/app-gateway/AuctionManager.sol", - [] - ], - [ - "0x3c9f5172feb0dDfC06176cE67B566EFbb01CCe98", - "DeliveryHelper", - "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", - [] - ], - [ - "0xF4D3BDe438416938217d4624c82AEbEb46CeD371", - "FeesManager", - "contracts/protocol/payload-delivery/app-gateway/FeesManager.sol", - [] - ], - [ - "0x8F18fC10a8b40b548C6F04Fb252481c783A9ace0", - "WatcherPrecompile", - "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", - [] - ], - [ - "0x8662FC08dEC7c61Dd3432fAF45a5bC024BB60B00", - "AddressResolver", - "contracts/protocol/AddressResolver.sol", - [] - ], - [ - "0x234cA13f5dC4a2467c81E515F57238BF9f53156E", - "ERC1967Factory", - "lib/solady/src/utils/ERC1967Factory.sol", - [] - ] - ], - "11155111": [], - "11155420": [ - [ - "0x245C0DCF8eF6e52b4d03c96b563C83a5f78A1E14", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 11155420, - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0xBf9Ec2b0441eeEA9bEb89C6638921c37c15A13E4", - "FastSwitchboard", - "contracts/protocol/socket/switchboard/FastSwitchboard.sol", - [ - 11155420, - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", - "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" - ] - ], - [ - "0x79Ac996De9333956f4980397ED5Bd91f77f10b01", - "Socket", - "contracts/protocol/socket/Socket.sol", - [11155420, "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", "EVMX"] - ] - ] -} +{} \ No newline at end of file diff --git a/hardhat-scripts/config/config.ts b/hardhat-scripts/config/config.ts index 00c7985d..fa12f8e7 100644 --- a/hardhat-scripts/config/config.ts +++ b/hardhat-scripts/config/config.ts @@ -24,10 +24,12 @@ export const logConfig = () => { }; export const chains: Array = [ - ChainSlug.ARBITRUM_SEPOLIA, - ChainSlug.OPTIMISM_SEPOLIA, - ChainSlug.SEPOLIA, - ChainSlug.BASE_SEPOLIA, + // ChainSlug.ARBITRUM_SEPOLIA, + // ChainSlug.OPTIMISM_SEPOLIA, + // ChainSlug.SEPOLIA, + // ChainSlug.BASE_SEPOLIA, + ChainSlug.INTEROP_ALPHA_0, + ChainSlug.INTEROP_ALPHA_1, ]; export const auctionEndDelaySeconds = 0; diff --git a/hardhat.config.ts b/hardhat.config.ts index 72ce85e8..b1ec305e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -24,7 +24,6 @@ import { hardhatChainNameToSlug, } from "@socket.tech/socket-protocol-common"; import { EVMX_CHAIN_ID } from "./hardhat-scripts/config/config"; -import { BASE_SEPOLIA_CHAIN_ID } from "./hardhat-scripts/constants"; const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env"; dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); @@ -66,9 +65,19 @@ let liveNetworks = { }, ["base_sepolia"]: { accounts: [`0x${privateKey}`], - chainId: BASE_SEPOLIA_CHAIN_ID, + chainId: ChainId.BASE_SEPOLIA, url: process.env.BASE_SEPOLIA_RPC, }, + ["interop_alpha_0"]: { + accounts: [`0x${privateKey}`], + chainId: ChainId.INTEROP_ALPHA_0, + url: process.env.INTEROP_ALPHA_0_RPC, + }, + ["interop_alpha_1"]: { + accounts: [`0x${privateKey}`], + chainId: ChainId.INTEROP_ALPHA_1, + url: process.env.INTEROP_ALPHA_1_RPC, + }, }; const config: HardhatUserConfig = { @@ -121,12 +130,28 @@ const config: HardhatUserConfig = { }, { network: "baseTestnet", - chainId: BASE_SEPOLIA_CHAIN_ID, + chainId: ChainId.BASE_SEPOLIA, urls: { apiURL: "https://api-sepolia.basescan.org/api", browserURL: "https://sepolia.basescan.org/", }, }, + { + network: "interopAlpha0", + chainId: ChainId.INTEROP_ALPHA_0, + urls: { + apiURL: "https://optimism-interop-alpha-0.blockscout.com/api", + browserURL: "https://optimism-interop-alpha-0.blockscout.com/", + }, + }, + { + network: "interopAlpha1", + chainId: ChainId.INTEROP_ALPHA_1, + urls: { + apiURL: "https://optimism-interop-alpha-1.blockscout.com/api", + browserURL: "https://optimism-interop-alpha-1.blockscout.com/", + }, + }, { network: "evmx", chainId: EVMX_CHAIN_ID, From e3977bfd516ef6e09636335990ee8a13b7c55ff5 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 14:02:07 +0400 Subject: [PATCH 14/23] fix: add overrides --- hardhat-scripts/deploy/2.roles.ts | 2 +- hardhat-scripts/deploy/3.upgradeManagers.ts | 31 +++++++++++++++------ hardhat-scripts/deploy/4.connect.ts | 7 +++-- hardhat-scripts/utils/overrides.ts | 10 +++++++ package.json | 2 +- yarn.lock | 8 +++--- 6 files changed, 44 insertions(+), 16 deletions(-) diff --git a/hardhat-scripts/deploy/2.roles.ts b/hardhat-scripts/deploy/2.roles.ts index f81df2b3..a9751dbb 100644 --- a/hardhat-scripts/deploy/2.roles.ts +++ b/hardhat-scripts/deploy/2.roles.ts @@ -51,7 +51,7 @@ async function setRoleForContract( if (!hasRole) { let tx = await contract.grantRole(roleHash, targetAddress, { - ...overrides(chain), + ...await overrides(chain), }); console.log( `granting ${roleName} role to ${targetAddress} for ${contractName}`, diff --git a/hardhat-scripts/deploy/3.upgradeManagers.ts b/hardhat-scripts/deploy/3.upgradeManagers.ts index 53cb9db9..38d57486 100644 --- a/hardhat-scripts/deploy/3.upgradeManagers.ts +++ b/hardhat-scripts/deploy/3.upgradeManagers.ts @@ -19,6 +19,7 @@ import { getAddresses, getInstance, getProviderFromChainSlug, + overrides, storeAddresses, } from "../utils"; @@ -48,6 +49,7 @@ export const main = async () => { await registerSb( chainAddresses[CORE_CONTRACTS.FastSwitchboard], + chain, signer, socketContract ); @@ -58,8 +60,8 @@ export const main = async () => { : (420120000 as ChainSlug); await addRemoteAddress( - chainAddresses[CORE_CONTRACTS.OpInteropSwitchboard], - addresses[remoteChain]?.[CORE_CONTRACTS.OpInteropSwitchboard], + chainAddresses[CORE_CONTRACTS.FastSwitchboard], + addresses[remoteChain]?.[CORE_CONTRACTS.FastSwitchboard], chain, signer, socketContract @@ -82,6 +84,7 @@ export const main = async () => { await registerSb( chainAddresses[CORE_CONTRACTS.OpInteropSwitchboard], + chain, signer, socketContract ); @@ -130,7 +133,10 @@ async function setOnchainContracts(chain, addresses) { chain, socketAddress, contractFactoryPlugAddress, - feesPlugAddress + feesPlugAddress, + { + ...await overrides(chain), + } ); console.log(`Setting onchain contracts for ${chain}, txHash: `, tx.hash); @@ -162,14 +168,16 @@ async function setSwitchboard(chain, addresses, sbType, contractName) { if (currentSbAddress.toLowerCase() !== sbAddress.toLowerCase()) { const tx = await watcherPrecompile .connect(signer) - .setSwitchboard(chain, sbTypeHash, sbAddress); + .setSwitchboard(chain, sbTypeHash, sbAddress, { + ...await overrides(chain), + }); console.log(`Setting switchboard for ${chain}, txHash: `, tx.hash); await tx.wait(); } } -const registerSb = async (sbAddress, signer, socket) => { +const registerSb = async (sbAddress, chain, signer, socket) => { try { // used fast switchboard here as all have same function signature const switchboard = ( @@ -184,7 +192,9 @@ const registerSb = async (sbAddress, signer, socket) => { }); if (Number(sb) == 0) { - const registerTx = await switchboard.registerSwitchboard(); + const registerTx = await switchboard.registerSwitchboard({ + ...await overrides(chain), + }); console.log(`Registering Switchboard ${sbAddress}: ${registerTx.hash}`); await registerTx.wait(); } @@ -209,12 +219,17 @@ const addRemoteAddress = async ( // send overrides while reading capacitor to avoid errors on mantle chain // some chains give balance error if gas price is used with from address as zero // therefore override from address as well - const remoteAddressContract = await socket.remoteAddress(); + const remoteAddressContract = await switchboard.remoteAddress(); if (remoteAddressContract == constants.AddressZero) { console.log( `Adding remote address ${remoteAddress} to Switchboard ${sbAddress} on ${chain}` ); - const registerTx = await switchboard.setRemoteAddress(remoteAddress); + const registerTx = await switchboard.setRemoteAddress( + remoteAddress, + { + ...await overrides(chain), + } + ); console.log(`Tx: ${registerTx.hash}`); await registerTx.wait(); diff --git a/hardhat-scripts/deploy/4.connect.ts b/hardhat-scripts/deploy/4.connect.ts index 0de5a503..4c58df71 100644 --- a/hardhat-scripts/deploy/4.connect.ts +++ b/hardhat-scripts/deploy/4.connect.ts @@ -97,7 +97,10 @@ async function connectPlug( const tx = await plug.functions["connectSocket"]( appGateway, socket.address, - switchboard + switchboard, + { + ...await overrides(chain), + } ); console.log( `Connecting ${plugContract} on ${chain} to ${appGateway} tx hash: ${tx.hash}` @@ -210,7 +213,7 @@ export const updateConfigEVMx = async () => { ); const { nonce, signature } = await signWatcherMessage(encodedMessage); const tx = await watcher.setAppGateways(appConfigs, nonce, signature, { - ...overrides(EVMX_CHAIN_ID), + ...await overrides(EVMX_CHAIN_ID), }); console.log(`Updating EVMx Config tx hash: ${tx.hash}`); await tx.wait(); diff --git a/hardhat-scripts/utils/overrides.ts b/hardhat-scripts/utils/overrides.ts index 7d9ccc96..8bbdf786 100644 --- a/hardhat-scripts/utils/overrides.ts +++ b/hardhat-scripts/utils/overrides.ts @@ -32,6 +32,16 @@ export const chainOverrides: { // gasLimit: 1_000_000_000, gasPrice: 0, }, + [ChainSlug.INTEROP_ALPHA_0]: { + // type: 0, + gasLimit: 1_000_000, + // gasPrice: 0, + }, + [ChainSlug.INTEROP_ALPHA_1]: { + // type: 0, + gasLimit: 1_000_000, + // gasPrice: 0, + }, }; export const overrides = async ( diff --git a/package.json b/package.json index aee7ad7e..b142610b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@aws-sdk/client-s3": "^3.670.0", "@nomicfoundation/hardhat-verify": "^2.0.12", "@nomiclabs/hardhat-ethers": "2.2.3", - "@socket.tech/socket-protocol-common": "1.1.31", + "@socket.tech/socket-protocol-common": "1.1.32", "@typechain/ethers-v5": "^10.0.0", "@typechain/hardhat": "6.0.0", "dotenv": "^16.0.3", diff --git a/yarn.lock b/yarn.lock index 3cf308a7..6178a636 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2071,10 +2071,10 @@ "@smithy/types" "^4.1.0" tslib "^2.6.2" -"@socket.tech/socket-protocol-common@1.1.31": - version "1.1.31" - resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol-common/-/socket-protocol-common-1.1.31.tgz#d95b1b6caf69a11c6bd13b18b7871c57e7d283fb" - integrity sha512-Hp1er4kRqCfeuvQFFgxooT0XBbO4nBrpL8/SYB/BNMdWfR9hk6PVE8MUnoIqTUJJTvIePKk+GOajl8MVqPD3VQ== +"@socket.tech/socket-protocol-common@1.1.32": + version "1.1.32" + resolved "https://registry.yarnpkg.com/@socket.tech/socket-protocol-common/-/socket-protocol-common-1.1.32.tgz#02779e83bed9b3cf51a9cdce655f6522aaa20ad4" + integrity sha512-1BUeqFbDrZBn56mBzSivtWWMMMhUqZzGuwmKEu6ZKjJfZhZInVYNs3ZUkhVaZSznpMZSYt6qypWkQHj3nTQZIA== dependencies: "@socket.tech/socket-protocol" "^1.0.15" axios "^1.7.9" From 9eeb1988060e151f17ad7e730b31599f2dd120c8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 14:03:48 +0400 Subject: [PATCH 15/23] feat: core deployments --- deployments/dev_addresses.json | 33 ++++++- deployments/dev_verification.json | 159 +++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 2 deletions(-) diff --git a/deployments/dev_addresses.json b/deployments/dev_addresses.json index 0967ef42..1ceda99f 100644 --- a/deployments/dev_addresses.json +++ b/deployments/dev_addresses.json @@ -1 +1,32 @@ -{} +{ + "7625382": { + "AddressResolver": "0x26FDDCE85557c98C20C7C5077dF44e6f239eDdFD", + "AddressResolverImpl": "0x4106c821Cc5119cE276A58380FD3CD18469c976f", + "AuctionManager": "0xB16d95D5Fd6Ccf80895427455EC9AfEfD2729C99", + "AuctionManagerImpl": "0xcc9486bce931041d1393921b32f7b4C60F6eAA99", + "DeliveryHelper": "0x8be1C218D5e2572D1d324be4833Ee9B62fBFA2ee", + "DeliveryHelperImpl": "0x30b5Cf86f186354C3C82C6b987F1Acb43f420a65", + "ERC1967Factory": "0x311fA7550C52c59AB3Dc3c18Fb11aa566d4b35B9", + "FeesManager": "0x9a2CeEc756013b71C3604C17d7A0B1Ae62E26767", + "FeesManagerImpl": "0xe519FEa99893BFF9334EF0B5253ea330bB73A7Fd", + "startBlock": 497366, + "WatcherPrecompile": "0xB15E7B893E3Ef6819A3570154B75d3A5AeF0081B", + "WatcherPrecompileImpl": "0x5B7600B2D9B14a5Ff79dd20845A88370D3F1Bf74" + }, + "420120000": { + "ContractFactoryPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 1070887 + }, + "420120001": { + "ContractFactoryPlug": "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "FastSwitchboard": "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "FeesPlug": "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "Socket": "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "SocketBatcher": "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "startBlock": 1070909 + } +} diff --git a/deployments/dev_verification.json b/deployments/dev_verification.json index 9e26dfee..75b5366e 100644 --- a/deployments/dev_verification.json +++ b/deployments/dev_verification.json @@ -1 +1,158 @@ -{} \ No newline at end of file +{ + "7625382": [ + [ + "0xcc9486bce931041d1393921b32f7b4C60F6eAA99", + "AuctionManager", + "contracts/protocol/payload-delivery/AuctionManager.sol", + [] + ], + [ + "0x30b5Cf86f186354C3C82C6b987F1Acb43f420a65", + "DeliveryHelper", + "contracts/protocol/payload-delivery/app-gateway/DeliveryHelper.sol", + [] + ], + [ + "0xe519FEa99893BFF9334EF0B5253ea330bB73A7Fd", + "FeesManager", + "contracts/protocol/payload-delivery/FeesManager.sol", + [] + ], + [ + "0x5B7600B2D9B14a5Ff79dd20845A88370D3F1Bf74", + "WatcherPrecompile", + "contracts/protocol/watcherPrecompile/WatcherPrecompile.sol", + [] + ], + [ + "0x4106c821Cc5119cE276A58380FD3CD18469c976f", + "AddressResolver", + "contracts/protocol/AddressResolver.sol", + [] + ], + [ + "0x311fA7550C52c59AB3Dc3c18Fb11aa566d4b35B9", + "ERC1967Factory", + "lib/solady/src/utils/ERC1967Factory.sol", + [] + ] + ], + "420120000": [ + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "OpInteropSwitchboard", + "contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol", + [ + 420120000, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "ContractFactoryPlug", + "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FeesPlug", + "contracts/protocol/payload-delivery/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "OpInteropSwitchboard", + "contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol", + [ + 420120000, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/socket/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/socket/Socket.sol", + [ + 420120000, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ], + "420120001": [ + [ + "0x9EDfb162b725CF6d628D68af200cAe8b624111eD", + "OpInteropSwitchboard", + "contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol", + [ + 420120001, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xee1Aef0b06f63Aa1c881838794Dd0876462c2B0d", + "ContractFactoryPlug", + "contracts/protocol/payload-delivery/ContractFactoryPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0x5F77550E3072c913A20B2fbdAb14026fe0E8B450", + "FeesPlug", + "contracts/protocol/payload-delivery/FeesPlug.sol", + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xbDE0D2da12F703Ccd275d721214745BccDCAD124", + "OpInteropSwitchboard", + "contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol", + [ + 420120001, + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18" + ] + ], + [ + "0xaC61f5696e0E2636dA7bD69827380f2Ab41A3C38", + "SocketBatcher", + "contracts/protocol/socket/SocketBatcher.sol", + [ + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a" + ] + ], + [ + "0x5e1641B190B71ECCc85b1ECe934F31cD9b3dcF7a", + "Socket", + "contracts/protocol/socket/Socket.sol", + [ + 420120001, + "0x3339Cf48f1F9cf31b6F8c2664d144c7444eBBB18", + "EVMX" + ] + ] + ] +} From 541ba233c766f09043764b9e055f8b31cb0ef278 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 14:07:20 +0400 Subject: [PATCH 16/23] chore: prod addr json --- deployments/prod_addresses.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 deployments/prod_addresses.json diff --git a/deployments/prod_addresses.json b/deployments/prod_addresses.json new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/deployments/prod_addresses.json @@ -0,0 +1 @@ +{} \ No newline at end of file From 9f478c3cadbb147152314943487b419ea0793e13 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:09:04 +0400 Subject: [PATCH 17/23] feat: helper scripts --- .../switchboard/OpInteropSwitchboard.sol | 11 ++-- script/helpers/AppGatewayFeeBalance.s.sol | 6 +- script/helpers/PayFeesInArbitrumETH.s.sol | 10 +-- .../WithdrawFeesArbitrumFeesPlug.s.sol | 63 +++++++++++++++++++ script/super-token/Bridge.s.sol | 29 +++++++++ script/super-token/DeployGateway.s.sol | 45 +++++++++++++ script/super-token/DeployToken.s.sol | 25 ++++++++ script/super-token/GetToken.s.sol | 31 +++++++++ script/super-token/SetToken.s.sol | 23 +++++++ .../super-token-op/SuperToken.sol | 10 +-- 10 files changed, 232 insertions(+), 21 deletions(-) create mode 100644 script/helpers/WithdrawFeesArbitrumFeesPlug.s.sol create mode 100644 script/super-token/Bridge.s.sol create mode 100644 script/super-token/DeployGateway.s.sol create mode 100644 script/super-token/DeployToken.s.sol create mode 100644 script/super-token/GetToken.s.sol create mode 100644 script/super-token/SetToken.s.sol diff --git a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol index 65c3ca72..5619c087 100644 --- a/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol +++ b/contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol @@ -6,20 +6,21 @@ import {SuperchainEnabled} from "./SuperchainEnabled.sol"; import {ISocket} from "../../../interfaces/ISocket.sol"; contract OpInteropSwitchboard is FastSwitchboard, SuperchainEnabled { - mapping(bytes32 => bool) public isSyncedOut; - mapping(bytes32 => bytes32) public payloadIdToDigest; - mapping(address => uint256) public unminted; address public token; address public remoteAddress; uint256 public remoteChainId; + mapping(bytes32 => bool) public isSyncedOut; + mapping(bytes32 => bytes32) public payloadIdToDigest; + mapping(address => uint256) public unminted; + + error OnlyTokenAllowed(); + modifier onlyToken() { if (msg.sender != token) revert OnlyTokenAllowed(); _; } - error OnlyTokenAllowed(); - constructor( uint32 chainSlug_, ISocket socket_, diff --git a/script/helpers/AppGatewayFeeBalance.s.sol b/script/helpers/AppGatewayFeeBalance.s.sol index 6637a83b..c87304fa 100644 --- a/script/helpers/AppGatewayFeeBalance.s.sol +++ b/script/helpers/AppGatewayFeeBalance.s.sol @@ -13,16 +13,18 @@ contract CheckDepositedFees is Script { FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); address appGateway = vm.envAddress("APP_GATEWAY"); + uint32 chainSlug = 420120000; + (uint256 deposited, uint256 blocked) = feesManager.appGatewayFeeBalances( appGateway, - 421614, + chainSlug, ETH_ADDRESS ); console.log("App Gateway:", appGateway); console.log("Deposited fees:", deposited); console.log("Blocked fees:", blocked); - uint256 availableFees = feesManager.getAvailableFees(421614, appGateway, ETH_ADDRESS); + uint256 availableFees = feesManager.getAvailableFees(chainSlug, appGateway, ETH_ADDRESS); console.log("Available fees:", availableFees); } } diff --git a/script/helpers/PayFeesInArbitrumETH.s.sol b/script/helpers/PayFeesInArbitrumETH.s.sol index 50da4fc1..a658e356 100644 --- a/script/helpers/PayFeesInArbitrumETH.s.sol +++ b/script/helpers/PayFeesInArbitrumETH.s.sol @@ -9,11 +9,11 @@ import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; contract DepositFees is Script { function run() external { - vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); - - uint256 privateKey = vm.envUint("PRIVATE_KEY"); + vm.createSelectFork(vm.envString("INTEROP_ALPHA_0_RPC")); + uint256 privateKey = vm.envUint("SOCKET_SIGNER_KEY"); vm.startBroadcast(privateKey); - FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("ARBITRUM_FEES_PLUG"))); + + FeesPlug feesPlug = FeesPlug(payable(vm.envAddress("FEES_PLUG"))); address appGateway = vm.envAddress("APP_GATEWAY"); address sender = vm.addr(privateKey); @@ -21,7 +21,7 @@ contract DepositFees is Script { uint256 balance = sender.balance; console.log("Sender balance in wei:", balance); - uint feesAmount = 0.001 ether; + uint feesAmount = 0.0001 ether; feesPlug.deposit{value: feesAmount}(ETH_ADDRESS, appGateway, feesAmount); } } diff --git a/script/helpers/WithdrawFeesArbitrumFeesPlug.s.sol b/script/helpers/WithdrawFeesArbitrumFeesPlug.s.sol new file mode 100644 index 00000000..fc954d26 --- /dev/null +++ b/script/helpers/WithdrawFeesArbitrumFeesPlug.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {FeesManager} from "../../contracts/protocol/payload-delivery/FeesManager.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +import {CounterAppGateway} from "../../test/apps/app-gateways/counter/CounterAppGateway.sol"; + +// @notice This script is used to withdraw fees from EVMX to Arbitrum Sepolia +// @dev Make sure your app has withdrawFeeTokens() function implemented. You can check its implementation in CounterAppGateway.sol +contract WithdrawFees is Script { + function run() external { + // EVMX Check available fees + vm.createSelectFork(vm.envString("EVMX_RPC")); + FeesManager feesManager = FeesManager(payable(vm.envAddress("FEES_MANAGER"))); + address appGatewayAddress = vm.envAddress("APP_GATEWAY"); + + CounterAppGateway appGateway = CounterAppGateway(appGatewayAddress); + uint256 availableFees = feesManager.getAvailableFees( + 421614, + appGatewayAddress, + ETH_ADDRESS + ); + console.log("Available fees:", availableFees); + + if (availableFees > 0) { + // Switch to Arbitrum Sepolia to get gas price + vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + address sender = vm.addr(privateKey); + + // Gas price from Arbitrum + uint256 arbitrumGasPrice = block.basefee + 0.1 gwei; // With buffer + uint256 gasLimit = 5_000_000; // Estimate + uint256 estimatedGasCost = gasLimit * arbitrumGasPrice; + + console.log("Arbitrum gas price (wei):", arbitrumGasPrice); + console.log("Gas limit:", gasLimit); + console.log("Estimated gas cost:", estimatedGasCost); + + // Calculate amount to withdraw + uint256 amountToWithdraw = availableFees > estimatedGasCost + ? availableFees - estimatedGasCost + : 0; + + if (amountToWithdraw > 0) { + // Switch back to EVMX to perform withdrawal + vm.createSelectFork(vm.envString("EVMX_RPC")); + vm.startBroadcast(privateKey); + console.log("Withdrawing amount:", amountToWithdraw); + appGateway.withdrawFeeTokens(421614, ETH_ADDRESS, amountToWithdraw, sender); + vm.stopBroadcast(); + + // Switch back to Arbitrum Sepolia to check final balance + vm.createSelectFork(vm.envString("ARBITRUM_SEPOLIA_RPC")); + console.log("Final sender balance:", sender.balance); + } else { + console.log("Available fees less than estimated gas cost"); + } + } + } +} diff --git a/script/super-token/Bridge.s.sol b/script/super-token/Bridge.s.sol new file mode 100644 index 00000000..ae564fa6 --- /dev/null +++ b/script/super-token/Bridge.s.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol"; + +contract Bridge is Script { + function run() external { + vm.createSelectFork(vm.envString("EVMX_RPC")); + uint256 privateKey = vm.envUint("SOCKET_SIGNER_KEY"); + vm.startBroadcast(privateKey); + + SuperTokenAppGateway.TransferOrder memory order = SuperTokenAppGateway.TransferOrder({ + srcToken: 0x3b0FF0fe7c43f7105CE1E4cE01F51344ceA77Bc0, + dstToken: 0x512E61D0057c7a99b323A080018df5D9618852Aa, + user: 0xb62505feacC486e809392c65614Ce4d7b051923b, + amount: 100000, + deadline: block.timestamp + 1 days + }); + + SuperTokenAppGateway gateway = SuperTokenAppGateway(vm.envAddress("APP_GATEWAY")); + bytes memory payload = abi.encode(order); + console.logBytes(payload); + gateway.transfer(payload); + } +} diff --git a/script/super-token/DeployGateway.s.sol b/script/super-token/DeployGateway.s.sol new file mode 100644 index 00000000..ae9b3b0f --- /dev/null +++ b/script/super-token/DeployGateway.s.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol"; +import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; + +contract DeployTokenGateway is Script { + function run() external { + address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); + string memory rpc = vm.envString("EVMX_RPC"); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + address deployer = vm.addr(deployerPrivateKey); + vm.startBroadcast(deployerPrivateKey); + + // Setting fee payment on Arbitrum Sepolia + Fees memory fees = Fees({ + feePoolChain: 420120000, + feePoolToken: ETH_ADDRESS, + amount: 0.00001 ether + }); + + SuperTokenAppGateway gateway = new SuperTokenAppGateway( + addressResolver, + deployer, + fees, + SuperTokenAppGateway.ConstructorParams({ + name_: "SUPER TOKEN", + symbol_: "SUPER", + decimals_: 18, + initialSupplyHolder_: deployer, + initialSupply_: 1000000000 ether + }) + ); + + console.log("Contracts deployed:"); + console.log("SuperTokenAppGateway:", address(gateway)); + console.log("superTokenId:"); + console.logBytes32(gateway.superToken()); + } +} diff --git a/script/super-token/DeployToken.s.sol b/script/super-token/DeployToken.s.sol new file mode 100644 index 00000000..4f764b16 --- /dev/null +++ b/script/super-token/DeployToken.s.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol"; + +contract SuperTokenDeploy is Script { + function run() external { + string memory rpc = vm.envString("EVMX_RPC"); + address appGatewayAddress = vm.envAddress("APP_GATEWAY"); + vm.createSelectFork(rpc); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + // Setting fee payment on Arbitrum Sepolia + SuperTokenAppGateway gateway = SuperTokenAppGateway(appGatewayAddress); + + gateway.deployContracts(420120000); + gateway.deployContracts(420120001); + + console.log("Tokens deployed"); + } +} diff --git a/script/super-token/GetToken.s.sol b/script/super-token/GetToken.s.sol new file mode 100644 index 00000000..6b76c29f --- /dev/null +++ b/script/super-token/GetToken.s.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {SuperTokenAppGateway} from "../../test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol"; +import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; + +contract GetToken is Script { + function run() external { + address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); + string memory rpc = vm.envString("EVMX_RPC"); + vm.createSelectFork(rpc); + // Setting fee payment on Arbitrum Sepolia + SuperTokenAppGateway gateway = SuperTokenAppGateway(vm.envAddress("APP_GATEWAY")); + bytes32 superTokenId = gateway.superToken(); + + address op0Token = gateway.getOnChainAddress(superTokenId, 420120000); + address op1Token = gateway.getOnChainAddress(superTokenId, 420120001); + + address op0TokenForwarder = gateway.forwarderAddresses(superTokenId, 420120000); + address op1TokenForwarder = gateway.forwarderAddresses(superTokenId, 420120001); + + console.log("Contracts deployed:"); + console.log("Op 0 address:", op0Token); + console.log("Op 1 address:", op1Token); + console.log("Op 0 forwarder:", op0TokenForwarder); + console.log("Op 1 forwarder:", op1TokenForwarder); + } +} diff --git a/script/super-token/SetToken.s.sol b/script/super-token/SetToken.s.sol new file mode 100644 index 00000000..fda30df2 --- /dev/null +++ b/script/super-token/SetToken.s.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script} from "forge-std/Script.sol"; +import {console} from "forge-std/console.sol"; +import {Fees} from "../../contracts/protocol/utils/common/Structs.sol"; +import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; +import {OpInteropSwitchboard} from "../../contracts/protocol/socket/switchboard/OpInteropSwitchboard.sol"; + +contract SetToken is Script { + function run() external { + vm.createSelectFork(vm.envString("INTEROP_ALPHA_1_RPC")); + uint256 privateKey = vm.envUint("SOCKET_SIGNER_KEY"); + vm.startBroadcast(privateKey); + + OpInteropSwitchboard switchboard = OpInteropSwitchboard( + 0x9EDfb162b725CF6d628D68af200cAe8b624111eD + ); + // 0: 0x425b451FE96F427Fd7FCD2a1B58fe70573CcdD56 + // 1: 0xcBA03e3Fe32B41B0B90cf2b113Bc4990b22c4c5F + switchboard.setToken(0xcBA03e3Fe32B41B0B90cf2b113Bc4990b22c4c5F); + } +} diff --git a/test/apps/app-gateways/super-token-op/SuperToken.sol b/test/apps/app-gateways/super-token-op/SuperToken.sol index 82f00184..6b52232e 100644 --- a/test/apps/app-gateways/super-token-op/SuperToken.sol +++ b/test/apps/app-gateways/super-token-op/SuperToken.sol @@ -14,9 +14,7 @@ interface ISwitchboard { * @notice An ERC20 contract which enables bridging a token to its sibling chains. */ contract SuperToken is ERC20, Ownable, PlugBase { - mapping(address => uint256) public lockedTokens; address public opSwitchboard; - error InvalidSender(); constructor( @@ -38,13 +36,7 @@ contract SuperToken is ERC20, Ownable, PlugBase { _burn(user_, amount_); } - function setSocket(address newSocket_) external onlyOwner { - _setSocket(newSocket_); - } - - function setOpSwitchboard(address newOpSwitchboard_) external onlyOwner { - opSwitchboard = newOpSwitchboard_; - } + //// INITIALIZATION //// function setupToken(address owner_, address opSwitchboard_) external { if (owner() != address(0) && owner() != msg.sender) revert InvalidSender(); From ee6cc7a60471ed9c6e1f56856aacd39578847a56 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:18:21 +0400 Subject: [PATCH 18/23] feat: app gateway base --- contracts/base/AppGatewayBase.sol | 2 + .../super-token-op/SuperTokenAppGateway.sol | 41 +++++++++---------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/contracts/base/AppGatewayBase.sol b/contracts/base/AppGatewayBase.sol index 156f98bd..2fd3035d 100644 --- a/contracts/base/AppGatewayBase.sol +++ b/contracts/base/AppGatewayBase.sol @@ -56,11 +56,13 @@ abstract contract AppGatewayBase is AddressResolverUtil, IAppGateway, FeesPlugin _setAddressResolver(addressResolver_); sbType = FAST; } + /// @notice Sets the switchboard type /// @param sbType_ The switchboard type function _setSbType(bytes32 sbType_) internal { sbType = sbType_; } + /// @notice Creates a contract ID /// @param contractName_ The contract name /// @return bytes32 The contract ID diff --git a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol index 314c2b04..3e07b8f4 100644 --- a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol @@ -8,19 +8,12 @@ import "./ISuperToken.sol"; import "./SuperToken.sol"; contract SuperTokenAppGateway is AppGatewayBase, Ownable { - bytes32 public superToken = _createContractId("superToken"); + bytes32 public superToken = _createContractId("superToken") + mapping(uint32 => uint256) public balanceOf; event Transferred(bytes32 asyncId); - struct ConstructorParams { - string name_; - string symbol_; - uint8 decimals_; - address initialSupplyHolder_; - uint256 initialSupply_; - } - - struct TransferOrder { + struct TransferOrder { address srcToken; address dstToken; address user; @@ -30,12 +23,10 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { constructor( address addressResolver_, - address auctionManager_, address owner_, - bytes32 sbType_, Fees memory fees_, ConstructorParams memory params_ - ) AppGatewayBase(addressResolver_, auctionManager_, sbType_) { + ) AppGatewayBase(addressResolver_) { creationCodeWithArgs[superToken] = abi.encodePacked( type(SuperToken).creationCode, abi.encode( @@ -54,26 +45,34 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { } function deployContracts(uint32 chainSlug_) external async { - address switchboard = watcherPrecompile__().switchboards(chainSlug_, sbType); + address opInteropSwitchboard = watcherPrecompile__().switchboards(chainSlug_, sbType); bytes memory initData = abi.encodeWithSelector( SuperToken.setupToken.selector, owner(), - switchboard + opInteropSwitchboard ); _deploy(superToken, chainSlug_, IsPlug.YES, initData); } - // no need to call this directly, will be called automatically after all contracts are deployed. - // check AppGatewayBase._deploy and AppGatewayBase.onBatchComplete - function initialize(uint32) public pure override { - return; - } - function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); ISuperToken(order.srcToken).burn(order.user, order.amount); ISuperToken(order.dstToken).mint(order.user, order.amount); + IPromise(order.dstToken).then(this.readBalance.selector, abi.encode(order.dstToken, order.user)); emit Transferred(_getCurrentAsyncId()); } + + function updateBalance(uint32 chainSlug_, bytes memory returnData_) external onlyPromises { + uint256 balance = abi.decode(returnData_, (uint256)); + balanceOf[chainSlug_] += balance; + } + + function readBalance(address token_, address user_, bytes memory returnData_) internal onlyPromises async { + _setOverrides(Read.ON); + ISuperToken(token_).balanceOf(user_); + IPromise(order.dstToken).then(this.updateBalance.selector, abi.encode(order.dstToken, order.user)); + _setOverrides(Read.OFF); + return balance; + } } From 3b968623fca6a974b4a1b232576d40b07fe8b557 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:26:33 +0400 Subject: [PATCH 19/23] fix: gateway --- .../super-token-op/SuperTokenAppGateway.sol | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol index 3e07b8f4..d7c625b7 100644 --- a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol @@ -9,7 +9,7 @@ import "./SuperToken.sol"; contract SuperTokenAppGateway is AppGatewayBase, Ownable { bytes32 public superToken = _createContractId("superToken") - mapping(uint32 => uint256) public balanceOf; + string public status; event Transferred(bytes32 asyncId); @@ -56,23 +56,16 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); + status = "bridging"; + ISuperToken(order.srcToken).burn(order.user, order.amount); ISuperToken(order.dstToken).mint(order.user, order.amount); - IPromise(order.dstToken).then(this.readBalance.selector, abi.encode(order.dstToken, order.user)); + IPromise(order.dstToken).then(this.updateStatus.selector, abi.encode("bridged")); emit Transferred(_getCurrentAsyncId()); } - function updateBalance(uint32 chainSlug_, bytes memory returnData_) external onlyPromises { - uint256 balance = abi.decode(returnData_, (uint256)); - balanceOf[chainSlug_] += balance; - } - - function readBalance(address token_, address user_, bytes memory returnData_) internal onlyPromises async { - _setOverrides(Read.ON); - ISuperToken(token_).balanceOf(user_); - IPromise(order.dstToken).then(this.updateBalance.selector, abi.encode(order.dstToken, order.user)); - _setOverrides(Read.OFF); - return balance; + function updateStatus(string memory status_, bytes memory ) external onlyPromises { + status = status_; } } From 32299423e527eb5861d0f8b6412ceee3d0fcebfa Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:30:07 +0400 Subject: [PATCH 20/23] fix: build --- script/super-token/DeployGateway.s.sol | 13 +---------- script/super-token/GetToken.s.sol | 1 - test/apps/SuperToken.t.sol | 9 +------- .../super-token-op/SuperTokenAppGateway.sol | 23 +++++++------------ 4 files changed, 10 insertions(+), 36 deletions(-) diff --git a/script/super-token/DeployGateway.s.sol b/script/super-token/DeployGateway.s.sol index ae9b3b0f..caa77795 100644 --- a/script/super-token/DeployGateway.s.sol +++ b/script/super-token/DeployGateway.s.sol @@ -24,18 +24,7 @@ contract DeployTokenGateway is Script { amount: 0.00001 ether }); - SuperTokenAppGateway gateway = new SuperTokenAppGateway( - addressResolver, - deployer, - fees, - SuperTokenAppGateway.ConstructorParams({ - name_: "SUPER TOKEN", - symbol_: "SUPER", - decimals_: 18, - initialSupplyHolder_: deployer, - initialSupply_: 1000000000 ether - }) - ); + SuperTokenAppGateway gateway = new SuperTokenAppGateway(addressResolver, deployer, fees); console.log("Contracts deployed:"); console.log("SuperTokenAppGateway:", address(gateway)); diff --git a/script/super-token/GetToken.s.sol b/script/super-token/GetToken.s.sol index 6b76c29f..3540bd25 100644 --- a/script/super-token/GetToken.s.sol +++ b/script/super-token/GetToken.s.sol @@ -9,7 +9,6 @@ import {ETH_ADDRESS} from "../../contracts/protocol/utils/common/Constants.sol"; contract GetToken is Script { function run() external { - address addressResolver = vm.envAddress("ADDRESS_RESOLVER"); string memory rpc = vm.envString("EVMX_RPC"); vm.createSelectFork(rpc); // Setting fee payment on Arbitrum Sepolia diff --git a/test/apps/SuperToken.t.sol b/test/apps/SuperToken.t.sol index aef90705..a8284537 100644 --- a/test/apps/SuperToken.t.sol +++ b/test/apps/SuperToken.t.sol @@ -65,14 +65,7 @@ contract SuperTokenTest is DeliveryHelperTest { SuperTokenAppGateway superTokenApp = new SuperTokenAppGateway( address(addressResolver), owner, - createFees(maxFees), - SuperTokenAppGateway.ConstructorParams({ - name_: "SUPER TOKEN", - symbol_: "SUPER", - decimals_: 18, - initialSupplyHolder_: owner, - initialSupply_: 1000000000 ether - }) + createFees(maxFees) ); // Enable app gateways to do all operations in the Watcher: Read, Write and Schedule on EVMx // Watcher sets the limits for apps in this SOCKET protocol version diff --git a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol index d7c625b7..fde2c8d5 100644 --- a/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol +++ b/test/apps/app-gateways/super-token-op/SuperTokenAppGateway.sol @@ -8,12 +8,12 @@ import "./ISuperToken.sol"; import "./SuperToken.sol"; contract SuperTokenAppGateway is AppGatewayBase, Ownable { - bytes32 public superToken = _createContractId("superToken") + bytes32 public superToken = _createContractId("superToken"); string public status; event Transferred(bytes32 asyncId); - struct TransferOrder { + struct TransferOrder { address srcToken; address dstToken; address user; @@ -24,18 +24,11 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { constructor( address addressResolver_, address owner_, - Fees memory fees_, - ConstructorParams memory params_ + Fees memory fees_ ) AppGatewayBase(addressResolver_) { creationCodeWithArgs[superToken] = abi.encodePacked( type(SuperToken).creationCode, - abi.encode( - params_.name_, - params_.symbol_, - params_.decimals_, - params_.initialSupplyHolder_, - params_.initialSupply_ - ) + abi.encode("SUPER TOKEN", "SUPER", 18, owner_, 1000000000 ether) ); // sets the fees data like max fees, chain and token for all transfers @@ -56,16 +49,16 @@ contract SuperTokenAppGateway is AppGatewayBase, Ownable { function transfer(bytes memory order_) external async { TransferOrder memory order = abi.decode(order_, (TransferOrder)); - status = "bridging"; - + status = "Bridging"; + ISuperToken(order.srcToken).burn(order.user, order.amount); ISuperToken(order.dstToken).mint(order.user, order.amount); - IPromise(order.dstToken).then(this.updateStatus.selector, abi.encode("bridged")); + IPromise(order.dstToken).then(this.updateStatus.selector, abi.encode("Bridged")); emit Transferred(_getCurrentAsyncId()); } - function updateStatus(string memory status_, bytes memory ) external onlyPromises { + function updateStatus(string memory status_, bytes memory) external onlyPromises { status = status_; } } From 83759c464c0322cc014b17f4c49818e663cae6ba Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:38:18 +0400 Subject: [PATCH 21/23] fix: scripts --- script/super-token/SetToken.s.sol | 8 ++++---- testScript.sh | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/script/super-token/SetToken.s.sol b/script/super-token/SetToken.s.sol index fda30df2..a27af9e6 100644 --- a/script/super-token/SetToken.s.sol +++ b/script/super-token/SetToken.s.sol @@ -9,15 +9,15 @@ import {OpInteropSwitchboard} from "../../contracts/protocol/socket/switchboard/ contract SetToken is Script { function run() external { - vm.createSelectFork(vm.envString("INTEROP_ALPHA_1_RPC")); + vm.createSelectFork(vm.envString("INTEROP_ALPHA_0_RPC")); uint256 privateKey = vm.envUint("SOCKET_SIGNER_KEY"); vm.startBroadcast(privateKey); OpInteropSwitchboard switchboard = OpInteropSwitchboard( 0x9EDfb162b725CF6d628D68af200cAe8b624111eD ); - // 0: 0x425b451FE96F427Fd7FCD2a1B58fe70573CcdD56 - // 1: 0xcBA03e3Fe32B41B0B90cf2b113Bc4990b22c4c5F - switchboard.setToken(0xcBA03e3Fe32B41B0B90cf2b113Bc4990b22c4c5F); + // Op 0 address: 0x46fc6C778E8F69fB97538530D1f4eCe674719604 + // Op 1 address: 0x897f6507bFE6C365394377b86C158Df05e3DD12b + switchboard.setToken(0x46fc6C778E8F69fB97538530D1f4eCe674719604); } } diff --git a/testScript.sh b/testScript.sh index c3a1f30c..4a662500 100644 --- a/testScript.sh +++ b/testScript.sh @@ -59,3 +59,20 @@ source .env && forge script script/admin/UpdateLimits.s.sol --broadcast --skip-s # add fees source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation source .env && forge script script/helpers/AppGatewayFeeBalance.s.sol + + + +source .env && forge script script/super-token/DeployGateway.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY --legacy --with-gas-price 0 +source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY + +source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 420120000 --private-key $PRIVATE_KEY --legacy --gas-price 0 +source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 420120001 --private-key $PRIVATE_KEY --legacy --gas-price 0 + +source .env && forge script script/super-token/GetToken.s.sol --broadcast --skip-simulation +source .env && forge script script/super-token/SetToken.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY + +source .env && forge script script/super-token/Bridge.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY --legacy --with-gas-price 0 + +source .env && cast send $APP_GATEWAY "status()" --legacy --gas-price 0 + +source .env && cast send $APP_GATEWAY "sbType()" --legacy --gas-price 0 From c039fa7568be22c45918bc3eef0dc0c9ecdff5b8 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:45:47 +0400 Subject: [PATCH 22/23] fix: addresses --- script/super-token/Bridge.s.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/super-token/Bridge.s.sol b/script/super-token/Bridge.s.sol index ae564fa6..8e03bd04 100644 --- a/script/super-token/Bridge.s.sol +++ b/script/super-token/Bridge.s.sol @@ -14,8 +14,8 @@ contract Bridge is Script { vm.startBroadcast(privateKey); SuperTokenAppGateway.TransferOrder memory order = SuperTokenAppGateway.TransferOrder({ - srcToken: 0x3b0FF0fe7c43f7105CE1E4cE01F51344ceA77Bc0, - dstToken: 0x512E61D0057c7a99b323A080018df5D9618852Aa, + srcToken: 0x9C79440aD7e70b895d88433D7B268BA4482E406F, + dstToken: 0xD6CE61B9BE8C8aD07b043e61079d66FB10f2E405, user: 0xb62505feacC486e809392c65614Ce4d7b051923b, amount: 100000, deadline: block.timestamp + 1 days From 37aed7afefd2c58d4a151e22757fae17ce9b44b3 Mon Sep 17 00:00:00 2001 From: Ameesha Agrawal Date: Tue, 4 Mar 2025 21:48:21 +0400 Subject: [PATCH 23/23] fix: bridge script --- testScript.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/testScript.sh b/testScript.sh index 4a662500..e0bbbe5c 100644 --- a/testScript.sh +++ b/testScript.sh @@ -55,6 +55,7 @@ source .env && forge script script/mock/FinalizeAndExecution.s.sol --broadcast - source .env && forge script script/admin/checkLimits.s.sol --broadcast --skip-simulation source .env && forge script script/admin/UpdateLimits.s.sol --broadcast --skip-simulation +source .env && forge script script/super-token/Bridge.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY --legacy --with-gas-price 0 # add fees source .env && forge script script/helpers/PayFeesInArbitrumETH.s.sol --broadcast --skip-simulation @@ -71,8 +72,10 @@ source .env && cast send $APP_GATEWAY "deployContracts(uint32)" 420120001 --priv source .env && forge script script/super-token/GetToken.s.sol --broadcast --skip-simulation source .env && forge script script/super-token/SetToken.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY -source .env && forge script script/super-token/Bridge.s.sol --broadcast --skip-simulation --private-key $PRIVATE_KEY --legacy --with-gas-price 0 -source .env && cast send $APP_GATEWAY "status()" --legacy --gas-price 0 -source .env && cast send $APP_GATEWAY "sbType()" --legacy --gas-price 0 + +# // commands +source .env && cast call $APP_GATEWAY "status()" --rpc-url $EVMX_RPC | cast to-ascii + +source .env && cast send $APP_GATEWAY "transfer(bytes)" 0x0000000000000000000000009c79440ad7e70b895d88433d7b268ba4482e406f000000000000000000000000d6ce61b9be8c8ad07b043e61079d66fb10f2e405000000000000000000000000b62505feacc486e809392c65614ce4d7b051923b00000000000000000000000000000000000000000000000000000000000186a00000000000000000000000000000000000000000000000000000000067c88d59 --private-key $PRIVATE_KEY --legacy --gas-price 0