Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add broadcastable abstract #441

Merged
merged 2 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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