Contract Name:
SygmaHeaderReporter
Contract Source Code:
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
/**
@title Interface for Bridge contract.
@author ChainSafe Systems.
*/
interface IBridge {
/**
@notice Initiates a transfer using a specified handler contract.
@notice Only callable when Bridge is not paused.
@param destinationDomainID ID of chain deposit will be bridged to.
@param resourceID ResourceID used to find address of handler to be used for deposit.
@param depositData Additional data to be passed to specified handler.
@param feeData Additional data to be passed to the fee handler.
@notice Emits {Deposit} event with all necessary parameters.
*/
function deposit(
uint8 destinationDomainID,
bytes32 resourceID,
bytes calldata depositData,
bytes calldata feeData
) external payable returns (uint64 depositNonce, bytes memory handlerResponse);
}
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.17;
interface ISygmaAdapter {
function storeHashes(address reporter, uint256[] memory ids, bytes32[] memory _hashes) external;
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
import { SygmaReporter } from "./SygmaReporter.sol";
import { HeaderStorage } from "../../utils/HeaderStorage.sol";
contract SygmaHeaderReporter is SygmaReporter {
HeaderStorage public immutable _headerStorage;
event HeaderReported(address indexed emitter, uint256 indexed blockNumber, bytes32 indexed blockHeader);
constructor(
address bridge,
HeaderStorage headerStorage,
bytes32 resourceID,
uint8 defaultDestinationDomainID,
address defaultSygmaAdapter
) SygmaReporter(bridge, resourceID, defaultDestinationDomainID, defaultSygmaAdapter) {
_headerStorage = headerStorage;
}
/**
@dev Reports the given block headers to the oracleAdapter via the Sygma bridge to default domain.
@param blockNumbers Uint256 array of block numbers to pass over the Sygma bridge.
@param feeData Additional data to be passed to the fee handler.
*/
function reportHeaders(uint256[] memory blockNumbers, bytes calldata feeData) public payable {
_reportHeaders(blockNumbers, _defaultSygmaAdapter, _defaultDestinationDomainID, feeData);
}
/**
@dev Reports the given block headers to the oracleAdapter via the Sygma bridge to specified domain.
@param blockNumbers Uint256 array of block numbers to pass over the Sygma bridge.
@param sygmaAdapter Address of the Sygma adapter on the target chain.
@param destinationDomainID Destination domain ID.
@param feeData Additional data to be passed to the fee handler.
*/
function reportHeadersToDomain(
uint256[] memory blockNumbers,
address sygmaAdapter,
uint8 destinationDomainID,
bytes memory feeData
) public payable {
_reportHeaders(blockNumbers, sygmaAdapter, destinationDomainID, feeData);
}
function _reportHeaders(
uint256[] memory blockNumbers,
address sygmaAdapter,
uint8 destinationDomainID,
bytes memory feeData
) internal {
bytes32[] memory blockHeaders = _headerStorage.storeBlockHeaders(blockNumbers);
_reportData(blockNumbers, blockHeaders, sygmaAdapter, destinationDomainID, feeData);
for (uint i = 0; i < blockNumbers.length; i++) {
emit HeaderReported(address(this), blockNumbers[i], blockHeaders[i]);
}
}
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
import "./interfaces/ISygmaAdapter.sol";
import "./interfaces/IBridge.sol";
contract SygmaReporter {
address public immutable _bridge;
bytes32 public immutable _resourceID;
uint8 public immutable _defaultDestinationDomainID;
address public immutable _defaultSygmaAdapter;
constructor(address bridge, bytes32 resourceID, uint8 defaultDestinationDomainID, address defaultSygmaAdapter) {
_bridge = bridge;
_resourceID = resourceID;
_defaultDestinationDomainID = defaultDestinationDomainID;
_defaultSygmaAdapter = defaultSygmaAdapter;
}
function _reportData(
uint256[] memory messageIds,
bytes32[] memory hashes,
address sygmaAdapter,
uint8 destinationDomainID,
bytes memory feeData
) internal returns (uint64 depositNonce, bytes memory handlerResponse) {
bytes memory depositData = abi.encodePacked(
// uint256 maxFee
uint256(950000),
// uint16 len(executeFuncSignature)
uint16(4),
// bytes executeFuncSignature
ISygmaAdapter(address(0)).storeHashes.selector,
// uint8 len(executeContractAddress)
uint8(20),
// bytes executeContractAddress
sygmaAdapter,
// uint8 len(executionDataDepositor)
uint8(20),
// bytes executionDataDepositor
address(this),
// bytes executionDataDepositor + executionData
prepareDepositData(messageIds, hashes)
);
return IBridge(_bridge).deposit{ value: msg.value }(destinationDomainID, _resourceID, depositData, feeData);
}
function slice(bytes calldata input, uint256 position) public pure returns (bytes memory) {
return input[position:];
}
function prepareDepositData(
uint256[] memory messageIds,
bytes32[] memory hashes
) public view returns (bytes memory) {
bytes memory encoded = abi.encode(address(0), messageIds, hashes);
return this.slice(encoded, 32);
}
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
interface IHeaderStorage {
event HeaderStored(uint256 indexed blockNumber, bytes32 indexed blockHeader);
error HeaderOutOfRange(address emitter, uint256 blockNumber);
function storeBlockHeader(uint256 blockNumber) external returns (bytes32 blockHeader);
function storeBlockHeaders(uint256[] memory blockNumbers) external returns (bytes32[] memory);
}
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity ^0.8.17;
import { IHeaderStorage } from "../interfaces/IHeaderStorage.sol";
contract HeaderStorage is IHeaderStorage {
mapping(uint256 => bytes32) public headers;
/// @dev Stores and returns the header for the given block.
/// @param blockNumber Block number.
/// @return blockHeader Block header stored.
/// @notice Reverts if the given block header was not previously stored and is now out of range.
function storeBlockHeader(uint256 blockNumber) public returns (bytes32 blockHeader) {
blockHeader = headers[blockNumber];
if (blockHeader == 0) {
blockHeader = blockhash(blockNumber);
if (blockHeader == 0) revert HeaderOutOfRange(address(this), blockNumber);
headers[blockNumber] = blockHeader;
emit HeaderStored(blockNumber, blockHeader);
}
}
/// @dev Stores and returns the header for an array of given blocks.
/// @param blockNumbers Array of block numbers.
/// @return Array of block headers.
/// @notice Reverts if the given block header was not previously stored and is now out of range.
function storeBlockHeaders(uint256[] memory blockNumbers) public returns (bytes32[] memory) {
bytes32[] memory blockHeaders = new bytes32[](blockNumbers.length);
for (uint256 i = 0; i < blockNumbers.length; i++) {
blockHeaders[i] = storeBlockHeader(blockNumbers[i]);
}
return blockHeaders;
}
}