Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0x1740FeBb8aA05Ae57D7b1654EF69472Dcb365e47
Balance 0 ETH
Nonce 1
Code Size 5337 bytes
Proxy EIP-1967 Proxy Implementation: 0x5F793Ec4...0Bf9
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

5337 bytes
0x6080604052600436101561001d575b366103b05761001b61146d565b005b60003560e01c8063021a5fe5146100cd5780633c231166146100c85780634c6c848f146100c35780634ee8f858146100be5780638426b968146100b957806399e80f3b146100b45780639aa9019e146100af578063a7fdd047146100aa578063cc5b7450146100a5578063daba7ef7146100a05763e7e5db4f0361000e57610395565b61037d565b610365565b61034d565b610238565b61021d565b610205565b6101ed565b6101d0565b61017f565b61011e565b6001600160e01b03191690565b6100e8816100d2565b036100ef57565b600080fd5b90503590610101826100df565b565b906020828203126100ef57610117916100f4565b90565b9052565b346100ef5761014b610139610134366004610103565b611437565b60405191829182901515815260200190565b0390f35b60009103126100ef57565b6001600160a01b031690565b61011a9061015a565b6020810192916101019190610166565b346100ef5761018f36600461014f565b61014b61019a610544565b6040519182918261016f565b6100e88161015a565b90503590610101826101a6565b906020828203126100ef57610117916101af565b346100ef576101e86101e33660046101bc565b61084b565b604051005b346100ef576101e86102003660046101bc565b61078c565b346100ef5761021536600461014f565b6101e86106bc565b346100ef5761022d36600461014f565b61014b61019a6104d0565b346100ef5761024836600461014f565b61014b61019a610492565b634e487b7160e01b600052604160045260246000fd5b90601f01601f191681019081106001600160401b0382111761028a57604052565b610253565b9061010161029c60405190565b9283610269565b6001600160401b03811161028a5760051b60200190565b909291926102cf6102ca826102a3565b61028f565b93602085838152019160051b8301928184116100ef57915b8383106102f45750505050565b6020809161030284866100f4565b8152019201916102e7565b9080601f830112156100ef57816020610117933591016102ba565b906020828203126100ef5781356001600160401b0381116100ef57610117920161030d565b346100ef576101e8610360366004610328565b61142e565b346100ef576101e8610378366004610328565b61130f565b346100ef576101e86103903660046101bc565b610642565b346100ef576103a536600461014f565b61014b61019a61050a565b6103b86103bd565b610418565b610117610405565b6101176101176101179290565b6101177f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc6103c5565b610117905461015a565b6101176104136101176103d2565b6103fb565b6109d6565b610117906103c5565b6103c5565b634e487b7160e01b600052601160045260246000fd5b9190820391821161044e57565b61042b565b6101176104266104827f3a517dd736309b905c692160a21b5439bdc56db1dc77d6982b66d44814e3fa9761041d565b61048c60016103c5565b90610441565b61011761049d610453565b5490565b6101176104266104827fca334bf49ef20e9cbff039feda3bc1c2a853aff17b1b5187e4aa1380ec55829d61041d565b61011761049d6104a1565b6101176104266104827fadf90d75f0f2d657d5a22fa0f6e4dabb83c4598b77158eb4119cb38f1d86446361041d565b61011761049d6104db565b6101176104266104827f1777adabd324f814e2b0e28f6edf876dce01d7d66358c9acfe87b1b5f38338d661041d565b61011761049d610515565b0190565b1561055a57565b60405162461bcd60e51b815260206004820152601d60248201527f53706865726558206572726f723a2061646d696e2072657175697265640000006044820152606490fd5b0390fd5b610101906105cc6105bd6105b861049d6104a1565b61015a565b6105c63361015a565b14610553565b6105ef565b9160206101019294936105e8816040810197610166565b0190610166565b7f5778f1547abbbb86090a43c32aec38334b31df4beeb6f8f3fa063f593b53a526906106208161061d610453565b55565b6106286104d0565b61063d61063460405190565b928392836105d1565b0390a1565b610101906105a3565b1561065257565b60405162461bcd60e51b815260206004820152602660248201527f53706865726558206572726f723a206e6f74207468652070656e64696e67206160448201526518d8dbdd5b9d60d21b6064820152608490fd5b61015a6101176101179290565b610117906106a6565b6106df6106c7610492565b6106d96106d33361015a565b9161015a565b1461064b565b7f67ebaebcd2ca5a91a404e898110f221747e8d15567f2388a34794aab151cf3e661063d61070b6104d0565b6107173361061d6104a1565b610730610722610453565b61072c60006106b3565b9055565b6040519182913390836105d1565b610101906107536105bd6105b861049d6104a1565b7f2ac55ae7ba47db34b5334622acafeb34a65daf143b47019273185d64c73a35a59061078061049d6104db565b6106288261061d6104db565b6101019061073e565b1561079c57565b60405162461bcd60e51b81528061059f600482016020808252818101527f53706865726558206572726f723a206f70657261746f72207265717569726564604082015260600190565b610101906108096107fa6105b861049d6104db565b6108033361015a565b14610795565b7ff33499cccaa0611882086224cc48cd82ef54b66a4d2edf4ed67108dd516896d5906108348161091f565b61083f61049d610515565b6106288261061d610515565b610101906107e5565b6101179061015a906001600160a01b031682565b61011790610854565b61011790610868565b8015156100e8565b905051906101018261087a565b906020828203126100ef5761011791610882565b61011a906100d2565b60208101929161010191906108a3565b6040513d6000823e3d90fd5b156108cf57565b60405162461bcd60e51b815260206004820152602260248201527f53706865726558206572726f723a206e6f7420612053706865726558456e67696044820152616e6560f01b6064820152608490fd5b61092c6105b860006106b3565b6109358261015a565b148015610947575b61010191506108c8565b5061095461095991610871565b610871565b602061096460405190565b9182906301ffc9a760e01b825281806109876329f20dd560e11b600483016108ac565b03915afa80156109d157610101916000916109a3575b5061093d565b6109c4915060203d81116109ca575b6109bc8183610269565b81019061088f565b3861099d565b503d6109b2565b6108bc565b6109eb6000356001600160e01b031916611437565b15610a07576109f990610b33565b6020610a03825190565b9101f35b60008091368280378136915af43d6000803e15610a23573d6000f35b3d6000fd5b610a3b6101176101179263ffffffff1690565b63ffffffff1690565b6101179060e01c610a28565b6101176101176101179263ffffffff1690565b600160ff1b811461044e5760000390565b909190610101906001610aba610ab4610aa3610426610a9e6000356001600160e01b031916610a44565b610a50565b96610aae8489610f85565b94610b1d565b95610a63565b611133565b6001600160401b03811161028a57602090601f01601f19160190565b90826000939282370152565b90929192610af76102ca82610abf565b918294828452828201116100ef576020610101930190610adb565b610117913691610ae7565b5061011790610b2d366000610b12565b90610b9b565b610117906060610a74565b90610b4b6102ca83610abf565b918252565b610b5a6027610b3e565b7f416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c6020820152660819985a5b195960ca1b604082015290565b610117610b50565b61011791610ba7610b93565b91610bcc565b3d15610bc757610bbc3d610b3e565b903d6000602084013e565b606090565b6000806101179493602081519101845af4610be5610bad565b91610c37565b15610bf257565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b91929015610c6d57508151610c53610c4f60006103c5565b9190565b14610c5c575090565b610c6861011791610c73565b610beb565b82610ced565b3b610c81610c4f60006103c5565b1190565b60005b838110610c985750506000910152565b8181015183820152602001610c88565b610cc9610cd260209361054f93610cbd815190565b80835293849260200190565b95869101610c85565b601f01601f191690565b906020610117928181520190610ca8565b90610cf6825190565b610d03610c4f60006103c5565b1115610d125750805190602001fd5b61059f90610d1f60405190565b62461bcd60e51b815291829160048301610cdc565b610117606061028f565b610d46610d34565b606080825260208201526000604082015290565b610117610d3e565b92919083610d71610954610f97565b610d816106d36105b860006106b3565b14610d9157610117939450610e7e565b505050565b806100e8565b9050519061010182610d96565b90929192610db96102ca826102a3565b93602085838152019160051b8301928184116100ef57915b838310610dde5750505050565b60208091610dec8486610d9c565b815201920191610dd1565b9080601f830112156100ef57815161011792602001610da9565b906020828203126100ef5781516001600160401b0381116100ef576101179201610df7565b9190610cd281610e4d8161054f9560209181520190565b8095610adb565b610e716101179593610e67836060959052565b6020830190610166565b8160408201520191610e36565b91600091908291610e8d610f97565b918314610f1c57610ea0610eca92610871565b90610eaa60405190565b9485938492839190634492e52d60e11b8352833691339060048601610e54565b03925af19081156109d157600091610efb575b5081525b610eeb81516111b3565b60208201526101175a6040830152565b610f16913d8091833e610f0e8183610269565b810190610e11565b38610edd565b610f28610f5192610871565b90610f3260405190565b9485938492839190633e88494360e01b83526004830190815260200190565b03925af19081156109d157600091610f6c575b508152610ee1565b610f7f913d8091833e610f0e8183610269565b38610f64565b9061011791610f92610d5a565b610d62565b61011761095461049d610515565b9190610fb2610954610f97565b610fc26106d36105b860006106b3565b14610d915761010192611061565b90610ff0610fe9610fdf845190565b8084529260200190565b9260200190565b9060005b8181106110015750505090565b90919261101e6110176001928651815260200190565b9460200190565b929101610ff4565b92611042610117959361103b86611053959052565b6020860152565b608060408501526080840190610fd0565b916060818403910152610fd0565b9091611078611071604083015190565b5a90610441565b906020611083610f97565b61108d83516111b3565b95156110fb5761109c90610871565b91015191813b156100ef57600080946110d26110b760405190565b97889687958694631e17b28d60e31b5b865260048601611026565b03925af180156109d1576110e35750565b6101019060006110f38183610269565b81019061014f565b61110490610871565b91015191813b156100ef57600080946110d261111f60405190565b9788968795869463027313cd60e11b6110c7565b906101019291610fa5565b90610b4b6102ca836102a3565b369037565b9061010161115d8361113e565b6020819461116d601f19916102a3565b01910161114b565b600019811461044e5760010190565b634e487b7160e01b600052603260045260246000fd5b80518210156111ae5760209160051b010190565b611184565b906111bc825190565b916111c683611150565b916111d86111d460006103c5565b9490565b935b8481101561121257806112086111fa6111f661120d948761119a565b5190565b54611205838861119a565b52565b611175565b6111da565b5092505090565b6101019061122e6107fa6105b861049d6104db565b611296565b61011790516100d2565b9061054f816020936108a3565b90611259610fe9610fdf845190565b9060005b81811061126a5750505090565b90919261127d611017600192865161123d565b92910161125d565b90602061011792818152019061124a565b6112a060006103c5565b6112ab610117835190565b8110156112d7578061120860016112cd6112c86112d2958761119a565b611233565b61136b565b6112a0565b5061063d7f45fc6a4de33dfc2fa6f40e48f353bf7ff006086db3ecf80c077f788082cc7d5a9161130660405190565b91829182611285565b61010190611219565b6101176104266104827f9a7afc584486ebd3e91191a9ac2c2e986b3aaa4084656fc915fe0843ff009c6b61041d565b61011761011a916100d2565b906024926113648361054f93611347565b6004830152565b61139d611376611318565b9161138f61138360405190565b93849260208401611353565b03601f198101835282610269565b6113af6113a8825190565b9160200190565b2055565b610101906113c86107fa6105b861049d6104db565b6113d260006103c5565b6113dd610117835190565b8110156113ff578061120860006112cd6112c86113fa958761119a565b6113d2565b5061063d7f754b9f3148ad4cf227ecdf9a64810fa2d0b8682a2de15dfad5310a12b7281a5f9161130660405190565b610101906113b3565b611442611376611318565b61144d6113a8825190565b205490565b916020610101929493611469816040810197610166565b0152565b7f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f8852587461149760405190565b8061063d34338361145256fea264697066735822122005ef6e55d57090c6b831f2423349fe2a8f7bb56380e7429b67eb41542458e0e164736f6c63430008140033

Verified Source Code Partial Match

Compiler: v0.8.20+commit.a1b79de6 EVM: paris
Proxy.sol 86 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)

pragma solidity ^0.8.0;

/**
 * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
 * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
 * be specified by overriding the virtual {_implementation} function.
 *
 * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 * different contract through the {_delegate} function.
 *
 * The success and return data of the delegated call will be returned back to the caller of the proxy.
 */
abstract contract Proxy {
    /**
     * @dev Delegates the current call to `implementation`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _delegate(address implementation) internal virtual {
        assembly {
            // Copy msg.data. We take full control of memory in this inline assembly
            // block because it will not return to Solidity code. We overwrite the
            // Solidity scratch pad at memory position 0.
            calldatacopy(0, 0, calldatasize())

            // Call the implementation.
            // out and outsize are 0 because we don't know the size yet.
            let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)

            // Copy the returned data.
            returndatacopy(0, 0, returndatasize())

            switch result
            // delegatecall returns 0 on error.
            case 0 {
                revert(0, returndatasize())
            }
            default {
                return(0, returndatasize())
            }
        }
    }

    /**
     * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
     * and {_fallback} should delegate.
     */
    function _implementation() internal view virtual returns (address);

    /**
     * @dev Delegates the current call to the address returned by `_implementation()`.
     *
     * This function does not return to its internal call site, it will return directly to the external caller.
     */
    function _fallback() internal virtual {
        _beforeFallback();
        _delegate(_implementation());
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
     * function in the contract matches the call data.
     */
    fallback() external payable virtual {
        _fallback();
    }

    /**
     * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
     * is empty.
     */
    receive() external payable virtual {
        _fallback();
    }

    /**
     * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
     * call, or as part of the Solidity `fallback` or `receive` functions.
     *
     * If overridden should call `super._beforeFallback()`.
     */
    function _beforeFallback() internal virtual {}
}
Address.sol 244 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}
StorageSlot.sol 88 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }
}
ISphereXEngine.sol 52 lines
// SPDX-License-Identifier: UNLICENSED
// (c) SphereX 2023 Terms&Conditions

pragma solidity ^0.8.0;

/**
 * @title Interface for SphereXEngine - definitions of core functionality
 * @author SphereX Technologies ltd
 * @notice This interface is imported by SphereXProtected, so that SphereXProtected can call functions from SphereXEngine
 * @dev Full docs of these functions can be found in SphereXEngine
 */

interface ISphereXEngine {
    function sphereXValidatePre(int256 num, address sender, bytes calldata data) external returns (bytes32[] memory);
    function sphereXValidatePost(
        int256 num,
        uint256 gas,
        bytes32[] calldata valuesBefore,
        bytes32[] calldata valuesAfter
    ) external;
    function sphereXValidateInternalPre(int256 num) external returns (bytes32[] memory);
    function sphereXValidateInternalPost(
        int256 num,
        uint256 gas,
        bytes32[] calldata valuesBefore,
        bytes32[] calldata valuesAfter
    ) external;

    function addAllowedSenderOnChain(address sender) external;

    /**
     * This function is taken as is from OZ IERC165, we don't inherit from OZ
     * to avoid collisions with the customer OZ version.
     *
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

/**
 * @dev this struct is used to reduce the stack usage of the modifiers.
 */
struct ModifierLocals {
    bytes32[] storageSlots;
    bytes32[] valuesBefore;
    uint256 gas;
}
IBeacon.sol 16 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}
SphereXProxyStorage.sol 65 lines
// SPDX-License-Identifier: UNLICENSED
// (c) SphereX 2023 Terms&Conditions

pragma solidity ^0.8.0;

import {SphereXProtectedBase} from "./SphereXProtectedBase.sol";

contract SphereXProxyBase is SphereXProtectedBase {
    constructor(address admin, address operator, address engine) SphereXProtectedBase(admin, operator, engine) {}

    event AddedProtectedFuncSigs(bytes4[] patterns);
    event RemovedProtectedFuncSigs(bytes4[] patterns);

    /**
     * @dev As we dont want to conflict with the imp's storage we implenment the protected
     * @dev functions map in an arbitrary slot.
     */
    bytes32 private constant PROTECTED_FUNC_SIG_BASE_POSITION =
        bytes32(uint256(keccak256("eip1967.spherex.protection_sig_base")) - 1);

    /**
     * Sets the value of a functions signature in the protected functions map stored in an arbitrary slot
     * @param func_sig of the wanted function
     * @param value bool value to set for the given function signature
     */
    function _setProtectedFuncSig(bytes4 func_sig, bool value) internal {
        bytes32 position = keccak256(abi.encodePacked(func_sig, PROTECTED_FUNC_SIG_BASE_POSITION));
        assembly {
            sstore(position, value)
        }
    }

    /**
     * Adds several functions' signature to the protected functions map stored in an arbitrary slot
     * @param keys of the functions added to the protected map
     */
    function addProtectedFuncSigs(bytes4[] memory keys) public spherexOnlyOperator {
        for (uint256 i = 0; i < keys.length; ++i) {
            _setProtectedFuncSig(keys[i], true);
        }
        emit AddedProtectedFuncSigs(keys);
    }

    /**
     * Removes given functions' signature from the protected functions map
     * @param keys of the functions removed from the protected map
     */
    function removeProtectedFuncSigs(bytes4[] memory keys) public spherexOnlyOperator {
        for (uint256 i = 0; i < keys.length; ++i) {
            _setProtectedFuncSig(keys[i], false);
        }
        emit RemovedProtectedFuncSigs(keys);
    }

    /**
     * Getter for a specific function signature in the protected map
     * @param func_sig of the wanted function
     */
    function isProtectedFuncSig(bytes4 func_sig) public view virtual returns (bool value) {
        bytes32 position = keccak256(abi.encodePacked(func_sig, PROTECTED_FUNC_SIG_BASE_POSITION));
        assembly {
            value := sload(position)
        }
    }
}
SphereXProtectedBase.sol 329 lines
// SPDX-License-Identifier: UNLICENSED
// (c) SphereX 2023 Terms&Conditions

pragma solidity ^0.8.0;

import {ISphereXEngine, ModifierLocals} from "./ISphereXEngine.sol";

/**
 * @title SphereX base Customer contract template
 */
abstract contract SphereXProtectedBase {
    /**
     * @dev we would like to avoid occupying storage slots
     * @dev to easily incorporate with existing contracts
     */
    bytes32 private constant SPHEREX_ADMIN_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.spherex")) - 1);
    bytes32 private constant SPHEREX_PENDING_ADMIN_STORAGE_SLOT =
        bytes32(uint256(keccak256("eip1967.spherex.pending")) - 1);
    bytes32 private constant SPHEREX_OPERATOR_STORAGE_SLOT = bytes32(uint256(keccak256("eip1967.spherex.operator")) - 1);
    bytes32 private constant SPHEREX_ENGINE_STORAGE_SLOT =
        bytes32(uint256(keccak256("eip1967.spherex.spherex_engine")) - 1);

    event ChangedSpherexOperator(address oldSphereXAdmin, address newSphereXAdmin);
    event ChangedSpherexEngineAddress(address oldEngineAddress, address newEngineAddress);
    event SpherexAdminTransferStarted(address currentAdmin, address pendingAdmin);
    event SpherexAdminTransferCompleted(address oldAdmin, address newAdmin);

    /**
     * @dev used when the client doesn't use a proxy
     * @notice constructor visibility is required to support all compiler versions
     */
    constructor(address admin, address operator, address engine) {
        __SphereXProtectedBase_init(admin, operator, engine);
    }

    /**
     * @dev used when the client uses a proxy - should be called by the inhereter initialization
     */
    function __SphereXProtectedBase_init(address admin, address operator, address engine) internal virtual {
        _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, admin);
        emit SpherexAdminTransferCompleted(address(0), admin);

        _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, operator);
        emit ChangedSpherexOperator(address(0), operator);

        _checkSphereXEngine(engine);
        _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, engine);
        emit ChangedSpherexEngineAddress(address(0), engine);
    }

    // ============ Helper functions ============

    function _sphereXEngine() private view returns (ISphereXEngine) {
        return ISphereXEngine(_getAddress(SPHEREX_ENGINE_STORAGE_SLOT));
    }

    /**
     * Stores a new address in an arbitrary slot
     * @param slot where to store the address
     * @param newAddress address to store in given slot
     */
    function _setAddress(bytes32 slot, address newAddress) internal {
        // solhint-disable-next-line no-inline-assembly
        // slither-disable-next-line assembly
        assembly {
            sstore(slot, newAddress)
        }
    }

    /**
     * Returns an address from an arbitrary slot.
     * @param slot to read an address from
     */
    function _getAddress(bytes32 slot) internal view returns (address addr) {
        // solhint-disable-next-line no-inline-assembly
        // slither-disable-next-line assembly
        assembly {
            addr := sload(slot)
        }
    }

    // ============ Local modifiers ============

    modifier onlySphereXAdmin() {
        require(msg.sender == _getAddress(SPHEREX_ADMIN_STORAGE_SLOT), "SphereX error: admin required");
        _;
    }

    modifier spherexOnlyOperator() {
        require(msg.sender == _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT), "SphereX error: operator required");
        _;
    }

    modifier returnsIfNotActivated() {
        if (address(_sphereXEngine()) == address(0)) {
            return;
        }

        _;
    }

    // ============ Management ============

    /**
     * Returns the currently pending admin address, the one that can call acceptSphereXAdminRole to become the admin.
     * @dev Could not use OZ Ownable2Step because the client's contract might use it.
     */
    function pendingSphereXAdmin() public view returns (address) {
        return _getAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT);
    }

    /**
     * Returns the current admin address, the one that can call acceptSphereXAdminRole to become the admin.
     * @dev Could not use OZ Ownable2Step because the client's contract might use it.
     */
    function sphereXAdmin() public view returns (address) {
        return _getAddress(SPHEREX_ADMIN_STORAGE_SLOT);
    }

    /**
     * Returns the current operator address.
     */
    function sphereXOperator() public view returns (address) {
        return _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT);
    }

    /**
     * Returns the current engine address.
     */
    function sphereXEngine() public view returns (address) {
        return _getAddress(SPHEREX_ENGINE_STORAGE_SLOT);
    }

    /**
     * Setting the address of the next admin. this address will have to accept the role to become the new admin.
     * @dev Could not use OZ Ownable2Step because the client's contract might use it.
     */
    function transferSphereXAdminRole(address newAdmin) public virtual onlySphereXAdmin {
        _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, newAdmin);
        emit SpherexAdminTransferStarted(sphereXAdmin(), newAdmin);
    }

    /**
     * Accepting the admin role and completing the transfer.
     * @dev Could not use OZ Ownable2Step because the client's contract might use it.
     */
    function acceptSphereXAdminRole() public virtual {
        require(pendingSphereXAdmin() == msg.sender, "SphereX error: not the pending account");
        address oldAdmin = sphereXAdmin();
        _setAddress(SPHEREX_ADMIN_STORAGE_SLOT, msg.sender);
        _setAddress(SPHEREX_PENDING_ADMIN_STORAGE_SLOT, address(0));
        emit SpherexAdminTransferCompleted(oldAdmin, msg.sender);
    }

    /**
     *
     * @param newSphereXOperator new address of the new operator account
     */
    function changeSphereXOperator(address newSphereXOperator) external onlySphereXAdmin {
        address oldSphereXOperator = _getAddress(SPHEREX_OPERATOR_STORAGE_SLOT);
        _setAddress(SPHEREX_OPERATOR_STORAGE_SLOT, newSphereXOperator);
        emit ChangedSpherexOperator(oldSphereXOperator, newSphereXOperator);
    }

    /**
     * Checks the given address implements ISphereXEngine or is address(0)
     * @param newSphereXEngine new address of the spherex engine
     */
    function _checkSphereXEngine(address newSphereXEngine) private view {
        require(
            newSphereXEngine == address(0)
                || ISphereXEngine(newSphereXEngine).supportsInterface(type(ISphereXEngine).interfaceId),
            "SphereX error: not a SphereXEngine"
        );
    }

    /**
     *
     * @param newSphereXEngine new address of the spherex engine
     * @dev this is also used to actually enable the defense
     * (because as long is this address is 0, the protection is disabled).
     */
    function changeSphereXEngine(address newSphereXEngine) external spherexOnlyOperator {
        _checkSphereXEngine(newSphereXEngine);
        address oldEngine = _getAddress(SPHEREX_ENGINE_STORAGE_SLOT);
        _setAddress(SPHEREX_ENGINE_STORAGE_SLOT, newSphereXEngine);
        emit ChangedSpherexEngineAddress(oldEngine, newSphereXEngine);
    }
    // ============ Engine interaction ============

    function _addAllowedSenderOnChain(address newSender) internal {
        ISphereXEngine engine = _sphereXEngine();
        if (address(engine) != address(0)) {
            engine.addAllowedSenderOnChain(newSender);
        }
    }

    // ============ Hooks ============

    /**
     * @dev internal function for engine communication. We use it to reduce contract size.
     *  Should be called before the code of a function.
     * @param num function identifier
     * @param isExternalCall set to true if this was called externally
     *  or a 'public' function from another address
     */
    function _sphereXValidatePre(int256 num, bool isExternalCall)
        private
        returnsIfNotActivated
        returns (ModifierLocals memory locals)
    {
        ISphereXEngine sphereXEngine = _sphereXEngine();
        if (isExternalCall) {
            locals.storageSlots = sphereXEngine.sphereXValidatePre(num, msg.sender, msg.data);
        } else {
            locals.storageSlots = sphereXEngine.sphereXValidateInternalPre(num);
        }
        locals.valuesBefore = _readStorage(locals.storageSlots);
        locals.gas = gasleft();
        return locals;
    }

    /**
     * @dev internal function for engine communication. We use it to reduce contract size.
     *  Should be called after the code of a function.
     * @param num function identifier
     * @param isExternalCall set to true if this was called externally
     *  or a 'public' function from another address
     */
    function _sphereXValidatePost(int256 num, bool isExternalCall, ModifierLocals memory locals)
        private
        returnsIfNotActivated
    {
        uint256 gas = locals.gas - gasleft();

        ISphereXEngine sphereXEngine = _sphereXEngine();

        bytes32[] memory valuesAfter;
        valuesAfter = _readStorage(locals.storageSlots);

        if (isExternalCall) {
            sphereXEngine.sphereXValidatePost(num, gas, locals.valuesBefore, valuesAfter);
        } else {
            sphereXEngine.sphereXValidateInternalPost(num, gas, locals.valuesBefore, valuesAfter);
        }
    }

    /**
     * @dev internal function for engine communication. We use it to reduce contract size.
     *  Should be called before the code of a function.
     * @param num function identifier
     * @return locals ModifierLocals
     */
    function _sphereXValidateInternalPre(int256 num)
        internal
        returnsIfNotActivated
        returns (ModifierLocals memory locals)
    {
        locals.storageSlots = _sphereXEngine().sphereXValidateInternalPre(num);
        locals.valuesBefore = _readStorage(locals.storageSlots);
        locals.gas = gasleft();
        return locals;
    }

    /**
     * @dev internal function for engine communication. We use it to reduce contract size.
     *  Should be called after the code of a function.
     * @param num function identifier
     * @param locals ModifierLocals
     */
    function _sphereXValidateInternalPost(int256 num, ModifierLocals memory locals) internal returnsIfNotActivated {
        bytes32[] memory valuesAfter;
        valuesAfter = _readStorage(locals.storageSlots);
        _sphereXEngine().sphereXValidateInternalPost(num, locals.gas - gasleft(), locals.valuesBefore, valuesAfter);
    }

    /**
     *  @dev Modifier to be incorporated in all internal protected non-view functions
     */
    modifier sphereXGuardInternal(int256 num) {
        ModifierLocals memory locals = _sphereXValidateInternalPre(num);
        _;
        _sphereXValidateInternalPost(-num, locals);
    }

    /**
     *  @dev Modifier to be incorporated in all external protected non-view functions
     */
    modifier sphereXGuardExternal(int256 num) {
        ModifierLocals memory locals = _sphereXValidatePre(num, true);
        _;
        _sphereXValidatePost(-num, true, locals);
    }

    /**
     *  @dev Modifier to be incorporated in all public protected non-view functions
     */
    modifier sphereXGuardPublic(int256 num, bytes4 selector) {
        ModifierLocals memory locals = _sphereXValidatePre(num, msg.sig == selector);
        _;
        _sphereXValidatePost(-num, msg.sig == selector, locals);
    }

    // ============ Internal Storage logic ============

    /**
     * Internal function that reads values from given storage slots and returns them
     * @param storageSlots list of storage slots to read
     * @return list of values read from the various storage slots
     */
    function _readStorage(bytes32[] memory storageSlots) internal view returns (bytes32[] memory) {
        uint256 arrayLength = storageSlots.length;
        bytes32[] memory values = new bytes32[](arrayLength);
        // create the return array data

        for (uint256 i = 0; i < arrayLength; i++) {
            bytes32 slot = storageSlots[i];
            bytes32 temp_value;
            // solhint-disable-next-line no-inline-assembly
            // slither-disable-next-line assembly
            assembly {
                temp_value := sload(slot)
            }

            values[i] = temp_value;
        }
        return values;
    }
}
SphereXProtectedProxy.sol 45 lines
// SPDX-License-Identifier: UNLICENSED
// (c) SphereX 2023 Terms&Conditions

pragma solidity ^0.8.0;

import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

import {SphereXProxyBase} from "./SphereXProxyStorage.sol";

/**
 * @title SphereX abstract proxt contract which implements OZ's Proxy intereface.
 */
abstract contract SphereXProtectedProxy is SphereXProxyBase, Proxy {
    constructor(address admin, address operator, address engine) SphereXProxyBase(admin, operator, engine) {}

    /**
     * The main point of the contract, wrap the delegate operation with SphereX's protection modfifier
     * @param implementation delegate dst
     */
    function _protectedDelegate(address implementation)
        private
        sphereXGuardExternal(int256(uint256(uint32(msg.sig))))
        returns (bytes memory)
    {
        return Address.functionDelegateCall(implementation, msg.data);
    }

    /**
     * Override Proxy.sol _delegate to make every inheriting proxy delegate with sphere'x protection
     * @param implementation delegate dst
     */
    function _delegate(address implementation) internal virtual override {
        if (isProtectedFuncSig(msg.sig)) {
            bytes memory ret_data = _protectedDelegate(implementation);
            uint256 ret_size = ret_data.length;

            assembly {
                return(add(ret_data, 0x20), ret_size)
            }
        } else {
            super._delegate(implementation);
        }
    }
}
draft-IERC1822.sol 20 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)

pragma solidity ^0.8.0;

/**
 * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
 * proxy whose upgrades are fully controlled by the current implementation.
 */
interface IERC1822Proxiable {
    /**
     * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
     * address.
     *
     * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
     * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
     * function revert if invoked through a proxy.
     */
    function proxiableUUID() external view returns (bytes32);
}
ERC1967Proxy.sol 32 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)

pragma solidity ^0.8.0;

import "../Proxy.sol";
import "./ERC1967Upgrade.sol";

/**
 * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
 * implementation address that can be changed. This address is stored in storage in the location specified by
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
 * implementation behind the proxy.
 */
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
    /**
     * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
     *
     * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
     * function call, and allows initializing the storage of the proxy like a Solidity constructor.
     */
    constructor(address _logic, bytes memory _data) payable {
        _upgradeToAndCall(_logic, _data, false);
    }

    /**
     * @dev Returns the current implementation address.
     */
    function _implementation() internal view virtual override returns (address impl) {
        return ERC1967Upgrade._getImplementation();
    }
}
ERC1967Upgrade.sol 185 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967Upgrade {
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallUUPS(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        // Upgrades from old implementations will perform a rollback test. This test requires the new
        // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
        // this special case will break upgrade paths from old UUPS implementation to new ones.
        if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
            _setImplementation(newImplementation);
        } else {
            try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
                require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
            } catch {
                revert("ERC1967Upgrade: new implementation is not UUPS");
            }
            _upgradeToAndCall(newImplementation, data, forceCall);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}
ProtectedERC1967ProxyNativeReceivable.sol 14 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@spherex-xyz/contracts/src/ProtectedProxies/ProtectedERC1967Proxy.sol";

contract ProtectedERC1967ProxyNativeReceivable is ProtectedERC1967Proxy {
    constructor(address _logic, bytes memory _data) ProtectedERC1967Proxy(_logic, _data) {}

    receive() external payable override {
        emit Received(msg.sender, msg.value);
    }

    event Received(address, uint256);
}
ProtectedERC1967Proxy.sol 25 lines
// SPDX-License-Identifier: UNLICENSED
// (c) SphereX 2023 Terms&Conditions

pragma solidity ^0.8.0;

import {ERC1967Proxy, Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

import {SphereXProtectedProxy} from "../SphereXProtectedProxy.sol";

/**
 * @title ERC1967Proxy implementation with spherex's protection
 */
contract ProtectedERC1967Proxy is SphereXProtectedProxy, ERC1967Proxy {
    constructor(address _logic, bytes memory _data)
        SphereXProtectedProxy(tx.origin, address(0), address(0))
        ERC1967Proxy(_logic, _data)
    {}

    /**
     * @dev This is used since both SphereXProtectedProxy and ERC1967Proxy implements Proxy.sol _delegate.
     */
    function _delegate(address implementation) internal virtual override(Proxy, SphereXProtectedProxy) {
        SphereXProtectedProxy._delegate(implementation);
    }
}

Read Contract

isProtectedFuncSig 0x021a5fe5 → bool
pendingSphereXAdmin 0x9aa9019e → address
sphereXAdmin 0x99e80f3b → address
sphereXEngine 0x3c231166 → address
sphereXOperator 0xe7e5db4f → address

Write Contract 6 functions

These functions modify contract state and require a wallet transaction to execute.

acceptSphereXAdminRole 0x8426b968
No parameters
addProtectedFuncSigs 0xcc5b7450
bytes4[] keys
changeSphereXEngine 0x4c6c848f
address newSphereXEngine
changeSphereXOperator 0x4ee8f858
address newSphereXOperator
removeProtectedFuncSigs 0xa7fdd047
bytes4[] keys
transferSphereXAdminRole 0xdaba7ef7
address newAdmin

Recent Transactions

No transactions found for this address