Skip to content

Commit

Permalink
Merge pull request #441 from superform-xyz/broadcastable
Browse files Browse the repository at this point in the history
feat: add broadcastable abstract
  • Loading branch information
0xTimepunk authored Jan 18, 2024
2 parents f761e67 + 58c6115 commit 8e0d104
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 160 deletions.
41 changes: 8 additions & 33 deletions src/SuperPositions.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ pragma solidity ^0.8.23;

import { ERC1155A } from "ERC1155A/ERC1155A.sol";
import { aERC20 } from "ERC1155A/aERC20.sol";
import { Broadcastable } from "src/crosschain-data/utils/Broadcastable.sol";
import { ISuperPositions } from "src/interfaces/ISuperPositions.sol";
import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol";
import { ISuperRBAC } from "src/interfaces/ISuperRBAC.sol";
import { ISuperformFactory } from "src/interfaces/ISuperformFactory.sol";
import { IBaseForm } from "src/interfaces/IBaseForm.sol";
import { IBroadcastRegistry } from "./interfaces/IBroadcastRegistry.sol";
import { IPaymentHelper } from "./interfaces/IPaymentHelper.sol";
import { Error } from "src/libraries/Error.sol";
import { DataLib } from "src/libraries/DataLib.sol";
Expand All @@ -25,7 +25,7 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol
/// @title SuperPositions
/// @dev Cross-chain LP token minted on source chain
/// @author Zeropoint Labs
contract SuperPositions is ISuperPositions, ERC1155A {
contract SuperPositions is ISuperPositions, ERC1155A, Broadcastable {
using DataLib for uint256;

//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -380,43 +380,18 @@ contract SuperPositions is ISuperPositions, ERC1155A {
abi.encode(CHAIN_ID, ++xChainPayloadCounter, id, name, symbol, decimal)
);

_broadcast(abi.encode(transmuterPayload));
_broadcast(
superRegistry.getAddress(keccak256("BROADCAST_REGISTRY")),
superRegistry.getAddress(keccak256("PAYMASTER")),
abi.encode(transmuterPayload),
IPaymentHelper(superRegistry.getAddress(keccak256("PAYMENT_HELPER"))).getRegisterTransmuterAMBData()
);

emit AERC20TokenRegistered(id, aErc20Token);

return aErc20Token;
}

/// @dev interacts with broadcast state registry to broadcasting state changes to all connected remote chains
/// @param message_ is the crosschain message to be sent.
function _broadcast(bytes memory message_) internal {
bytes memory registerTransmuterAMBData =
IPaymentHelper(superRegistry.getAddress(keccak256("PAYMENT_HELPER"))).getRegisterTransmuterAMBData();

(uint8 ambId, bytes memory broadcastParams) = abi.decode(registerTransmuterAMBData, (uint8, bytes));

/// @dev if the broadcastParams are wrong this will revert
(uint256 gasFee, bytes memory extraData) = abi.decode(broadcastParams, (uint256, bytes));

if (msg.value < gasFee) {
revert Error.INVALID_BROADCAST_FEE();
}

/// @dev ambIds are validated inside the broadcast state registry
IBroadcastRegistry(superRegistry.getAddress(keccak256("BROADCAST_REGISTRY"))).broadcastPayload{ value: gasFee }(
msg.sender, ambId, gasFee, message_, extraData
);

if (msg.value > gasFee) {
/// @dev forwards the rest to msg.sender
(bool success,) = payable(msg.sender).call{ value: msg.value - gasFee }("");

if (!success) {
revert Error.FAILED_TO_SEND_NATIVE();
}
}
}

/// @dev deploys new transmuter on broadcasting
function _deployTransmuter(bytes memory message_) internal {
(,, uint256 superformId, string memory name, string memory symbol, uint8 decimal) =
Expand Down
45 changes: 11 additions & 34 deletions src/SuperformFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
pragma solidity ^0.8.23;

import { ISuperformFactory } from "src/interfaces/ISuperformFactory.sol";
import { Broadcastable } from "src/crosschain-data/utils/Broadcastable.sol";
import { BaseForm } from "src/BaseForm.sol";
import { BroadcastMessage } from "src/types/DataTypes.sol";
import { IBaseForm } from "src/interfaces/IBaseForm.sol";
import { IBroadcastRegistry } from "src/interfaces/IBroadcastRegistry.sol";
import { ISuperRBAC } from "src/interfaces/ISuperRBAC.sol";
import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol";
import { DataLib } from "src/libraries/DataLib.sol";
Expand All @@ -17,8 +17,7 @@ import { Clones } from "openzeppelin-contracts/contracts/proxy/Clones.sol";
/// @title SuperformFactory
/// @dev Central point of read & write access for all Superforms on this chain
/// @author Zeropoint Labs
contract SuperformFactory is ISuperformFactory {

contract SuperformFactory is ISuperformFactory, Broadcastable {
using DataLib for uint256;
using Clones for address;

Expand Down Expand Up @@ -95,7 +94,7 @@ contract SuperformFactory is ISuperformFactory {
if (superRegistry_ == address(0)) {
revert Error.ZERO_ADDRESS();
}

if (block.chainid > type(uint64).max) {
revert Error.BLOCK_CHAIN_ID_OUT_OF_BOUNDS();
}
Expand Down Expand Up @@ -233,7 +232,8 @@ contract SuperformFactory is ISuperformFactory {

/// @dev instantiate the superform
superform_ = tFormImplementation.cloneDeterministic(
keccak256(abi.encode(uint256(CHAIN_ID), formImplementationId_, vault_)));
keccak256(abi.encode(uint256(CHAIN_ID), formImplementationId_, vault_))
);

BaseForm(payable(superform_)).initialize(address(superRegistry), vault_, address(IERC4626(vault_).asset()));

Expand Down Expand Up @@ -275,7 +275,12 @@ contract SuperformFactory is ISuperformFactory {
abi.encode(CHAIN_ID, ++xChainPayloadCounter, formImplementationId_, status_)
);

_broadcast(abi.encode(factoryPayload), extraData_);
_broadcast(
superRegistry.getAddress(keccak256("BROADCAST_REGISTRY")),
superRegistry.getAddress(keccak256("PAYMASTER")),
abi.encode(factoryPayload),
extraData_
);
} else if (msg.value != 0) {
revert Error.MSG_VALUE_NOT_ZERO();
}
Expand All @@ -296,34 +301,6 @@ contract SuperformFactory is ISuperformFactory {
// INTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////

/// @dev interacts with broadcast state registry to broadcasting state changes to all connected remote chains
/// @param message_ is the crosschain message to be sent.
/// @param extraData_ is the amb override information.
function _broadcast(bytes memory message_, bytes memory extraData_) internal {
(uint8 ambId, bytes memory broadcastParams) = abi.decode(extraData_, (uint8, bytes));

/// @dev if the broadcastParams are wrong this will revert
(uint256 gasFee, bytes memory extraData) = abi.decode(broadcastParams, (uint256, bytes));

if (msg.value < gasFee) {
revert Error.INVALID_BROADCAST_FEE();
}

/// @dev ambIds are validated inside the broadcast state registry
IBroadcastRegistry(superRegistry.getAddress(keccak256("BROADCAST_REGISTRY"))).broadcastPayload{ value: gasFee }(
msg.sender, ambId, gasFee, message_, extraData
);

if (msg.value > gasFee) {
/// @dev forwards the rest to msg.sender
(bool success,) = payable(msg.sender).call{ value: msg.value - gasFee }("");

if (!success) {
revert Error.FAILED_TO_SEND_NATIVE();
}
}
}

/// @dev synchronize paused status update message from remote chain
/// @notice is a part of broadcasting / dispatching through factory state registry
/// @param message_ is the crosschain message received.
Expand Down
51 changes: 51 additions & 0 deletions src/crosschain-data/utils/Broadcastable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.23;

import { IBroadcastRegistry } from "src/interfaces/IBroadcastRegistry.sol";
import { Error } from "src/libraries/Error.sol";

/// @title Broadcastable
/// @dev Can be inherited in contracts that wish to support broadcasting
/// @author ZeroPoint Labs
abstract contract Broadcastable {
//////////////////////////////////////////////////////////////
// INTERNAL FUNCTIONS //
//////////////////////////////////////////////////////////////

/// @dev broadcasts state changes to all connected remote chains
/// @param broadcastRegistry_ is the address of the broadcast registry contract.
/// @param payMaster_ is the address of the paymaster contract.
/// @param message_ is the crosschain message to be sent.
/// @param extraData_ is the amb override information.
function _broadcast(
address broadcastRegistry_,
address payMaster_,
bytes memory message_,
bytes memory extraData_
)
internal
{
(uint8 ambId, bytes memory broadcastParams) = abi.decode(extraData_, (uint8, bytes));

/// @dev if the broadcastParams are wrong this will revert
(uint256 gasFee, bytes memory extraData) = abi.decode(broadcastParams, (uint256, bytes));

if (msg.value < gasFee) {
revert Error.INVALID_BROADCAST_FEE();
}

/// @dev ambIds are validated inside the broadcast state registry
IBroadcastRegistry(broadcastRegistry_).broadcastPayload{ value: gasFee }(
msg.sender, ambId, gasFee, message_, extraData
);

if (msg.value > gasFee) {
/// @dev forwards the rest to paymaster
(bool success,) = payable(payMaster_).call{ value: msg.value - gasFee }("");

if (!success) {
revert Error.FAILED_TO_SEND_NATIVE();
}
}
}
}
3 changes: 0 additions & 3 deletions src/interfaces/ISuperRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ interface ISuperRegistry {
/// @dev returns the id of the superform factory module
function SUPERFORM_FACTORY() external view returns (bytes32);

/// @dev returns the id of the superform transmuter
function SUPER_TRANSMUTER() external view returns (bytes32);

/// @dev returns the id of the superform paymaster contract
function PAYMASTER() external view returns (bytes32);

Expand Down
40 changes: 8 additions & 32 deletions src/settings/SuperRBAC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.23;

import { ISuperRBAC } from "src/interfaces/ISuperRBAC.sol";
import { IBroadcastRegistry } from "src/interfaces/IBroadcastRegistry.sol";
import { Broadcastable } from "src/crosschain-data/utils/Broadcastable.sol";
import { ISuperRegistry } from "src/interfaces/ISuperRegistry.sol";
import { Error } from "src/libraries/Error.sol";
import { BroadcastMessage } from "src/types/DataTypes.sol";
Expand All @@ -11,8 +11,7 @@ import { AccessControlEnumerable } from "openzeppelin-contracts/contracts/access
/// @title SuperRBAC
/// @dev Contract to manage roles in the Superform protocol
/// @author Zeropoint Labs
contract SuperRBAC is ISuperRBAC, AccessControlEnumerable {

contract SuperRBAC is ISuperRBAC, AccessControlEnumerable, Broadcastable {
//////////////////////////////////////////////////////////////
// CONSTANTS //
//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -181,7 +180,12 @@ contract SuperRBAC is ISuperRBAC, AccessControlEnumerable {
BroadcastMessage memory rolesPayload = BroadcastMessage(
"SUPER_RBAC", SYNC_REVOKE, abi.encode(++xChainPayloadCounter, role_, superRegistryAddressId_)
);
_broadcast(abi.encode(rolesPayload), extraData_);
_broadcast(
superRegistry.getAddress(keccak256("BROADCAST_REGISTRY")),
superRegistry.getAddress(keccak256("PAYMASTER")),
abi.encode(rolesPayload),
extraData_
);
}
} else {
revert Error.ROLE_NOT_ASSIGNED();
Expand Down Expand Up @@ -222,32 +226,4 @@ contract SuperRBAC is ISuperRBAC, AccessControlEnumerable {
}
return super._revokeRole(role_, account_);
}

/// @dev interacts with role state registry to broadcasting state changes to all connected remote chains
/// @param message_ is the crosschain message to be sent.
/// @param extraData_ is the amb override information.
function _broadcast(bytes memory message_, bytes memory extraData_) internal {
(uint8 ambId, bytes memory broadcastParams) = abi.decode(extraData_, (uint8, bytes));

/// @dev if the broadcastParams are wrong this will revert
(uint256 gasFee, bytes memory extraData) = abi.decode(broadcastParams, (uint256, bytes));

if (msg.value < gasFee) {
revert Error.INVALID_BROADCAST_FEE();
}

/// @dev ambIds are validated inside the broadcast state registry
IBroadcastRegistry(superRegistry.getAddress(keccak256("BROADCAST_REGISTRY"))).broadcastPayload{ value: gasFee }(
msg.sender, ambId, gasFee, message_, extraData
);

if (msg.value > gasFee) {
/// @dev forwards the rest to msg.sender
(bool success,) = payable(msg.sender).call{ value: msg.value - gasFee }("");

if (!success) {
revert Error.FAILED_TO_SEND_NATIVE();
}
}
}
}
4 changes: 0 additions & 4 deletions src/settings/SuperRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ contract SuperRegistry is ISuperRegistry, QuorumManager {
/// @notice should not be allowed to be changed
bytes32 public constant override SUPERFORM_FACTORY = keccak256("SUPERFORM_FACTORY");

/// @dev not accessed in protocol
/// @dev could be allowed to be changed
bytes32 public constant override SUPER_TRANSMUTER = keccak256("SUPER_TRANSMUTER");

/// @dev can be used to set a new paymaster to forward payments to
/// @dev could be allowed to be changed
bytes32 public constant override PAYMASTER = keccak256("PAYMASTER");
Expand Down
Loading

0 comments on commit 8e0d104

Please sign in to comment.