// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {IWormhole} from "../interfaces/IWormhole.sol";

/// @title UsesCore
/// @author The Warp Team <contact@warp.inc>
/// @notice This contract manages a eip1967 stored Wormhole core contract
///         address.
/// @dev This contract is intended to be inherited by any contract that needs
///      to access the Wormhole core system.
abstract contract UsesCore {
    /// @notice Contract is already init, and cannot be initialized again.
    /// @dev Selector 0xef34ca5c.
    error AlreadyInit();

    /// @notice Attempting to set Core address to zero.
    /// @dev Selector 0xf71b2b01.
    error NullCore();

    /// @notice The slot at which the core contract address is stored.
    /// @dev 0xc6a342a8a7e6992aa2a41ce922cb4520fcb72f46fb4f9e41cdd65930adc9ca4c.
    bytes32 public constant CORE_SLOT = bytes32(uint256(keccak256("eip1967.proxy.accumulate.core")) - 1);

    /// @notice Read the core contract address.
    /// @return _core The Wormhole core contract.
    function core() public view returns (IWormhole _core) {
        uint256 slot = uint256(CORE_SLOT);
        assembly ("memory-safe") {
            _core := sload(slot)
        }
    }

    /// @notice Set the core contract address.
    /// @dev This function can only be called once.
    /// @param _core The new core contract.
    /// @custom:reverts AlreadyInit() when core has already been initialized.
    /// @custom:reverts NullCore() when core is address(0).
    /// @custom:reverts if core doesn't implement chainId() function.
    function setCore(address _core) internal {
        if (address(core()) != address(0)) revert AlreadyInit();
        // assert _core is not zero
        if (_core == address(0)) revert NullCore();
        // call chainId() to check that _core implements IWormhole
        IWormhole(_core).chainId();
        // store _core in CORE_SLOT
        uint256 slot = uint256(CORE_SLOT);
        assembly ("memory-safe") {
            sstore(slot, _core)
        }
    }
}
[{"inputs":[{"internalType":"address","name":"attestor","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ATTESTOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"core","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"deploy","outputs":[],"stateMutability":"nonpayable","type":"function"}]