APE Price: $1.27 (-5.85%)

Contract

0x33FE6f374C4a44C50F4362c93372f0EB09d968F5

Overview

APE Balance

Apechain LogoApechain LogoApechain Logo0 APE

APE Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Force New Epoch52233572024-11-24 12:57:222 days ago1732453042IN
0x33FE6f37...B09d968F5
0 APE0.0030204325.42069
0x60c0604048802962024-11-21 12:55:285 days ago1732193728IN
 Contract Creation
0 APE0.0659139125.42069

Parent Transaction Hash Block From To
View All Internal Transactions

Loading...
Loading

Similar Match Source Code
This contract matches the deployed Bytecode of the Source Code for Contract 0xe8b6d157...a4Eec77D6
The constructor portion of the code might be different and could alter the actual behaviour of the contract

Contract Name:
GTokenOpenPnlFeed

Compiler Version
v0.8.23+commit.f704f362

Optimization Enabled:
Yes with 800 runs

Other Settings:
paris EvmVersion
File 1 of 16 : GTokenOpenPnlFeed.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {ChainlinkClient, Chainlink} from "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import "../interfaces/IGToken.sol";
import "../interfaces/IOwnable.sol";
import "../interfaces/IGTokenOpenPnlFeed.sol";

/**
 * @dev Manages open pnl oracle requests for a gToken vault
 */
contract GTokenOpenPnlFeed is ChainlinkClient, IGTokenOpenPnlFeed {
    using Chainlink for Chainlink.Request;

    // Constants
    uint256 public immutable LINK_FEE_BALANCE_DIVIDER;
    uint256 constant MIN_ANSWERS = 2;
    uint256 constant MIN_REQUESTS_START = 1 hours;
    uint256 constant MAX_REQUESTS_START = 1 weeks;
    uint256 constant MIN_REQUESTS_EVERY = 1 hours;
    uint256 constant MAX_REQUESTS_EVERY = 1 days;
    uint256 constant MIN_REQUESTS_COUNT = 3;
    uint256 constant MAX_REQUESTS_COUNT = 10;

    // Params
    IGToken public immutable gToken;

    uint256 public requestsStart = 2 days;
    uint256 public requestsEvery = 6 hours;
    uint256 public requestsCount = 4;

    address[] public oracles;
    bytes32 public job;
    uint256 public minAnswers;

    // State
    int256[] public nextEpochValues;
    uint256 public nextEpochValuesRequestCount;
    uint256 public nextEpochValuesLastRequest;

    uint256 public lastRequestId;
    mapping(bytes32 => uint256) public requestIds; // chainlink request id => requestId
    mapping(uint256 => Request) public requests; // requestId => request
    mapping(uint256 => int256[]) public requestAnswers; // requestId => open pnl (1e18)

    constructor(
        uint256 _LINK_FEE_BALANCE_DIVIDER,
        address _linkToken,
        IGToken _gToken,
        address[] memory _oracles,
        bytes32 _job,
        uint256 _minAnswers
    ) {
        require(
            _LINK_FEE_BALANCE_DIVIDER > 0 &&
                _linkToken != address(0) &&
                address(_gToken) != address(0) &&
                _oracles.length > 0 &&
                _job != bytes32(0) &&
                _minAnswers >= MIN_ANSWERS &&
                _minAnswers <= _oracles.length / 2,
            "WRONG_PARAMS"
        );

        LINK_FEE_BALANCE_DIVIDER = _LINK_FEE_BALANCE_DIVIDER;

        setChainlinkToken(_linkToken);

        gToken = _gToken;
        oracles = _oracles;
        job = _job;
        minAnswers = _minAnswers;
    }

    // Modifiers
    modifier onlyGTokenOwner() {
        // 2-week timelock
        require(msg.sender == IOwnable(address(gToken)).owner(), "ONLY_OWNER");
        _;
    }

    modifier onlyGTokenManager() {
        // 3-day timelock
        require(msg.sender == gToken.manager(), "ONLY_MANAGER");
        _;
    }

    modifier onlyGTokenAdmin() {
        // bypasses timelock, emergency functions only
        require(msg.sender == gToken.admin(), "ONLY_ADMIN");
        _;
    }

    // Manage parameters
    function updateRequestsStart(uint256 newValue) public onlyGTokenOwner {
        require(newValue >= MIN_REQUESTS_START, "BELOW_MIN");
        require(newValue <= MAX_REQUESTS_START, "ABOVE_MAX");
        requestsStart = newValue;
        emit NumberParamUpdated("requestsStart", newValue);
    }

    function updateRequestsEvery(uint256 newValue) public onlyGTokenOwner {
        require(newValue >= MIN_REQUESTS_EVERY, "BELOW_MIN");
        require(newValue <= MAX_REQUESTS_EVERY, "ABOVE_MAX");
        requestsEvery = newValue;
        emit NumberParamUpdated("requestsEvery", newValue);
    }

    function updateRequestsCount(uint256 newValue) public onlyGTokenOwner {
        require(newValue >= MIN_REQUESTS_COUNT, "BELOW_MIN");
        require(newValue <= MAX_REQUESTS_COUNT, "ABOVE_MAX");
        requestsCount = newValue;
        emit NumberParamUpdated("requestsCount", newValue);
    }

    function updateRequestsInfoBatch(
        uint256 newRequestsStart,
        uint256 newRequestsEvery,
        uint256 newRequestsCount
    ) external onlyGTokenOwner {
        updateRequestsStart(newRequestsStart);
        updateRequestsEvery(newRequestsEvery);
        updateRequestsCount(newRequestsCount);
    }

    function updateMinAnswers(uint256 newValue) external onlyGTokenManager {
        require(newValue >= MIN_ANSWERS, "BELOW_MIN");
        require(newValue <= oracles.length / 2, "ABOVE_MAX");
        minAnswers = newValue;
        emit NumberParamUpdated("minAnswers", newValue);
    }

    function updateOracle(uint256 _index, address newValue) external onlyGTokenOwner {
        require(_index < oracles.length, "INDEX_TOO_BIG");
        require(newValue != address(0), "VALUE_0");
        oracles[_index] = newValue;
        emit OracleUpdated(_index, newValue);
    }

    function updateOracles(address[] memory newValues) external onlyGTokenOwner {
        require(newValues.length >= minAnswers * 2, "ARRAY_TOO_SMALL");
        oracles = newValues;
        emit OraclesUpdated(newValues);
    }

    function updateJob(bytes32 newValue) external onlyGTokenManager {
        require(newValue != bytes32(0), "VALUE_0");
        job = newValue;
        emit JobUpdated(newValue);
    }

    // Emergency function in case of oracle manipulation
    function resetNextEpochValueRequests() external onlyGTokenAdmin {
        uint256 reqToResetCount = nextEpochValuesRequestCount;
        require(reqToResetCount > 0, "NO_REQUEST_TO_RESET");

        delete nextEpochValues;

        nextEpochValuesRequestCount = 0;
        nextEpochValuesLastRequest = 0;

        for (uint256 i; i < reqToResetCount; ++i) {
            requests[lastRequestId - i].active = false;
        }

        emit NextEpochValuesReset(gToken.currentEpoch(), reqToResetCount);
    }

    // Safety function that anyone can call in case the function above is used in an abusive manner,
    // which could theoretically delay withdrawals indefinitely since it prevents new epochs
    function forceNewEpoch() external {
        require(
            block.timestamp - gToken.currentEpochStart() >= requestsStart + requestsEvery * requestsCount,
            "TOO_EARLY"
        );
        uint256 newEpoch = startNewEpoch();
        emit NewEpochForced(newEpoch);
    }

    // Called by gToken contract
    function newOpenPnlRequestOrEpoch() external {
        bool firstRequest = nextEpochValuesLastRequest == 0;

        if (firstRequest && block.timestamp - gToken.currentEpochStart() >= requestsStart) {
            makeOpenPnlRequest();
        } else if (!firstRequest && block.timestamp - nextEpochValuesLastRequest >= requestsEvery) {
            if (nextEpochValuesRequestCount < requestsCount) {
                makeOpenPnlRequest();
            } else if (nextEpochValues.length >= requestsCount) {
                startNewEpoch();
            }
        }
    }

    // Create requests
    function makeOpenPnlRequest() private {
        Chainlink.Request memory linkRequest = buildChainlinkRequest(job, address(this), this.fulfill.selector);

        uint256 linkFeePerNode = IERC20(chainlinkTokenAddress()).balanceOf(address(this)) /
            LINK_FEE_BALANCE_DIVIDER /
            oracles.length;

        requests[++lastRequestId] = Request({initiated: true, active: true, linkFeePerNode: linkFeePerNode});

        nextEpochValuesRequestCount++;
        nextEpochValuesLastRequest = block.timestamp;

        for (uint256 i; i < oracles.length; ++i) {
            requestIds[sendChainlinkRequestTo(oracles[i], linkRequest, linkFeePerNode)] = lastRequestId;
        }

        emit NextEpochValueRequested(gToken.currentEpoch(), lastRequestId, job, oracles.length, linkFeePerNode);
    }

    // Handle answers
    function fulfill(
        bytes32 requestId,
        int256 value // 1e18
    ) external recordChainlinkFulfillment(requestId) {
        uint256 reqId = requestIds[requestId];
        delete requestIds[requestId];

        Request memory r = requests[reqId];
        uint256 currentEpoch = gToken.currentEpoch();

        emit RequestValueReceived(!r.active, currentEpoch, reqId, requestId, msg.sender, value, r.linkFeePerNode);

        if (!r.active) {
            return;
        }

        int256[] storage answers = requestAnswers[reqId];
        answers.push(value);

        if (answers.length == minAnswers) {
            int256 medianValue = median(answers);
            nextEpochValues.push(medianValue);

            emit RequestMedianValueSet(currentEpoch, reqId, answers, medianValue);

            requests[reqId].active = false;
            delete requestAnswers[reqId];
        }
    }

    // Increment epoch and update feed value
    function startNewEpoch() private returns (uint256 newEpoch) {
        nextEpochValuesRequestCount = 0;
        nextEpochValuesLastRequest = 0;

        uint256 currentEpochPositiveOpenPnl = gToken.currentEpochPositiveOpenPnl();

        // If all responses arrived, use mean, otherwise it means we forced a new epoch,
        // so as a safety we use the last epoch value
        int256 newEpochOpenPnl = nextEpochValues.length >= requestsCount
            ? average(nextEpochValues)
            : int256(currentEpochPositiveOpenPnl);

        uint256 finalNewEpochPositiveOpenPnl = gToken.updateAccPnlPerTokenUsed(
            currentEpochPositiveOpenPnl,
            newEpochOpenPnl > 0 ? uint256(newEpochOpenPnl) : 0
        );

        newEpoch = gToken.currentEpoch();

        emit NewEpoch(newEpoch, lastRequestId, nextEpochValues, newEpochOpenPnl, finalNewEpochPositiveOpenPnl);

        delete nextEpochValues;
    }

    // Median function
    function _swap(int256[] memory array, uint256 i, uint256 j) private pure {
        (array[i], array[j]) = (array[j], array[i]);
    }

    function _sort(int256[] memory array, uint256 begin, uint256 end) private pure {
        if (begin >= end) {
            return;
        }

        uint256 j = begin;
        int256 pivot = array[j];

        for (uint256 i = begin + 1; i < end; ++i) {
            if (array[i] < pivot) {
                _swap(array, i, ++j);
            }
        }

        _swap(array, begin, j);
        _sort(array, begin, j);
        _sort(array, j + 1, end);
    }

    function median(int256[] memory array) private pure returns (int256) {
        _sort(array, 0, array.length);

        return
            array.length % 2 == 0
                ? (array[array.length / 2 - 1] + array[array.length / 2]) / 2
                : array[array.length / 2];
    }

    // Average function
    function average(int256[] memory array) private pure returns (int256) {
        int256 sum;
        for (uint256 i; i < array.length; ++i) {
            sum += array[i];
        }

        return sum / int256(array.length);
    }
}

File 2 of 16 : Chainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {CBORChainlink} from "./vendor/CBORChainlink.sol";
import {BufferChainlink} from "./vendor/BufferChainlink.sol";

/**
 * @title Library for common Chainlink functions
 * @dev Uses imported CBOR library for encoding to buffer
 */
library Chainlink {
  uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase

  using CBORChainlink for BufferChainlink.buffer;

  struct Request {
    bytes32 id;
    address callbackAddress;
    bytes4 callbackFunctionId;
    uint256 nonce;
    BufferChainlink.buffer buf;
  }

  /**
   * @notice Initializes a Chainlink request
   * @dev Sets the ID, callback address, and callback function signature on the request
   * @param self The uninitialized request
   * @param jobId The Job Specification ID
   * @param callbackAddr The callback address
   * @param callbackFunc The callback function signature
   * @return The initialized request
   */
  function initialize(
    Request memory self,
    bytes32 jobId,
    address callbackAddr,
    bytes4 callbackFunc
  ) internal pure returns (Chainlink.Request memory) {
    BufferChainlink.init(self.buf, defaultBufferSize);
    self.id = jobId;
    self.callbackAddress = callbackAddr;
    self.callbackFunctionId = callbackFunc;
    return self;
  }

  /**
   * @notice Sets the data for the buffer without encoding CBOR on-chain
   * @dev CBOR can be closed with curly-brackets {} or they can be left off
   * @param self The initialized request
   * @param data The CBOR data
   */
  function setBuffer(Request memory self, bytes memory data) internal pure {
    BufferChainlink.init(self.buf, data.length);
    BufferChainlink.append(self.buf, data);
  }

  /**
   * @notice Adds a string value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The string value to add
   */
  function add(
    Request memory self,
    string memory key,
    string memory value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeString(value);
  }

  /**
   * @notice Adds a bytes value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The bytes value to add
   */
  function addBytes(
    Request memory self,
    string memory key,
    bytes memory value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeBytes(value);
  }

  /**
   * @notice Adds a int256 value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The int256 value to add
   */
  function addInt(
    Request memory self,
    string memory key,
    int256 value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeInt(value);
  }

  /**
   * @notice Adds a uint256 value to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param value The uint256 value to add
   */
  function addUint(
    Request memory self,
    string memory key,
    uint256 value
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.encodeUInt(value);
  }

  /**
   * @notice Adds an array of strings to the request with a given key name
   * @param self The initialized request
   * @param key The name of the key
   * @param values The array of string values to add
   */
  function addStringArray(
    Request memory self,
    string memory key,
    string[] memory values
  ) internal pure {
    self.buf.encodeString(key);
    self.buf.startArray();
    for (uint256 i = 0; i < values.length; i++) {
      self.buf.encodeString(values[i]);
    }
    self.buf.endSequence();
  }
}

File 3 of 16 : ChainlinkClient.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./Chainlink.sol";
import "./interfaces/ENSInterface.sol";
import "./interfaces/LinkTokenInterface.sol";
import "./interfaces/ChainlinkRequestInterface.sol";
import "./interfaces/OperatorInterface.sol";
import "./interfaces/PointerInterface.sol";
import {ENSResolver as ENSResolver_Chainlink} from "./vendor/ENSResolver.sol";

/**
 * @title The ChainlinkClient contract
 * @notice Contract writers can inherit this contract in order to create requests for the
 * Chainlink network
 */
abstract contract ChainlinkClient {
  using Chainlink for Chainlink.Request;

  uint256 internal constant LINK_DIVISIBILITY = 10**18;
  uint256 private constant AMOUNT_OVERRIDE = 0;
  address private constant SENDER_OVERRIDE = address(0);
  uint256 private constant ORACLE_ARGS_VERSION = 1;
  uint256 private constant OPERATOR_ARGS_VERSION = 2;
  bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("link");
  bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle");
  address private constant LINK_TOKEN_POINTER = 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571;

  ENSInterface private s_ens;
  bytes32 private s_ensNode;
  LinkTokenInterface private s_link;
  OperatorInterface private s_oracle;
  uint256 private s_requestCount = 1;
  mapping(bytes32 => address) private s_pendingRequests;

  event ChainlinkRequested(bytes32 indexed id);
  event ChainlinkFulfilled(bytes32 indexed id);
  event ChainlinkCancelled(bytes32 indexed id);

  /**
   * @notice Creates a request that can hold additional parameters
   * @param specId The Job Specification ID that the request will be created for
   * @param callbackAddr address to operate the callback on
   * @param callbackFunctionSignature function signature to use for the callback
   * @return A Chainlink Request struct in memory
   */
  function buildChainlinkRequest(
    bytes32 specId,
    address callbackAddr,
    bytes4 callbackFunctionSignature
  ) internal pure returns (Chainlink.Request memory) {
    Chainlink.Request memory req;
    return req.initialize(specId, callbackAddr, callbackFunctionSignature);
  }

  /**
   * @notice Creates a request that can hold additional parameters
   * @param specId The Job Specification ID that the request will be created for
   * @param callbackFunctionSignature function signature to use for the callback
   * @return A Chainlink Request struct in memory
   */
  function buildOperatorRequest(bytes32 specId, bytes4 callbackFunctionSignature)
    internal
    view
    returns (Chainlink.Request memory)
  {
    Chainlink.Request memory req;
    return req.initialize(specId, address(this), callbackFunctionSignature);
  }

  /**
   * @notice Creates a Chainlink request to the stored oracle address
   * @dev Calls `chainlinkRequestTo` with the stored oracle address
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendChainlinkRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) {
    return sendChainlinkRequestTo(address(s_oracle), req, payment);
  }

  /**
   * @notice Creates a Chainlink request to the specified oracle address
   * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
   * send LINK which creates a request on the target oracle contract.
   * Emits ChainlinkRequested event.
   * @param oracleAddress The address of the oracle for the request
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendChainlinkRequestTo(
    address oracleAddress,
    Chainlink.Request memory req,
    uint256 payment
  ) internal returns (bytes32 requestId) {
    uint256 nonce = s_requestCount;
    s_requestCount = nonce + 1;
    bytes memory encodedRequest = abi.encodeWithSelector(
      ChainlinkRequestInterface.oracleRequest.selector,
      SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
      AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
      req.id,
      address(this),
      req.callbackFunctionId,
      nonce,
      ORACLE_ARGS_VERSION,
      req.buf.buf
    );
    return _rawRequest(oracleAddress, nonce, payment, encodedRequest);
  }

  /**
   * @notice Creates a Chainlink request to the stored oracle address
   * @dev This function supports multi-word response
   * @dev Calls `sendOperatorRequestTo` with the stored oracle address
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendOperatorRequest(Chainlink.Request memory req, uint256 payment) internal returns (bytes32) {
    return sendOperatorRequestTo(address(s_oracle), req, payment);
  }

  /**
   * @notice Creates a Chainlink request to the specified oracle address
   * @dev This function supports multi-word response
   * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
   * send LINK which creates a request on the target oracle contract.
   * Emits ChainlinkRequested event.
   * @param oracleAddress The address of the oracle for the request
   * @param req The initialized Chainlink Request
   * @param payment The amount of LINK to send for the request
   * @return requestId The request ID
   */
  function sendOperatorRequestTo(
    address oracleAddress,
    Chainlink.Request memory req,
    uint256 payment
  ) internal returns (bytes32 requestId) {
    uint256 nonce = s_requestCount;
    s_requestCount = nonce + 1;
    bytes memory encodedRequest = abi.encodeWithSelector(
      OperatorInterface.operatorRequest.selector,
      SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
      AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
      req.id,
      req.callbackFunctionId,
      nonce,
      OPERATOR_ARGS_VERSION,
      req.buf.buf
    );
    return _rawRequest(oracleAddress, nonce, payment, encodedRequest);
  }

  /**
   * @notice Make a request to an oracle
   * @param oracleAddress The address of the oracle for the request
   * @param nonce used to generate the request ID
   * @param payment The amount of LINK to send for the request
   * @param encodedRequest data encoded for request type specific format
   * @return requestId The request ID
   */
  function _rawRequest(
    address oracleAddress,
    uint256 nonce,
    uint256 payment,
    bytes memory encodedRequest
  ) private returns (bytes32 requestId) {
    requestId = keccak256(abi.encodePacked(this, nonce));
    s_pendingRequests[requestId] = oracleAddress;
    emit ChainlinkRequested(requestId);
    require(s_link.transferAndCall(oracleAddress, payment, encodedRequest), "unable to transferAndCall to oracle");
  }

  /**
   * @notice Allows a request to be cancelled if it has not been fulfilled
   * @dev Requires keeping track of the expiration value emitted from the oracle contract.
   * Deletes the request from the `pendingRequests` mapping.
   * Emits ChainlinkCancelled event.
   * @param requestId The request ID
   * @param payment The amount of LINK sent for the request
   * @param callbackFunc The callback function specified for the request
   * @param expiration The time of the expiration for the request
   */
  function cancelChainlinkRequest(
    bytes32 requestId,
    uint256 payment,
    bytes4 callbackFunc,
    uint256 expiration
  ) internal {
    OperatorInterface requested = OperatorInterface(s_pendingRequests[requestId]);
    delete s_pendingRequests[requestId];
    emit ChainlinkCancelled(requestId);
    requested.cancelOracleRequest(requestId, payment, callbackFunc, expiration);
  }

  /**
   * @notice the next request count to be used in generating a nonce
   * @dev starts at 1 in order to ensure consistent gas cost
   * @return returns the next request count to be used in a nonce
   */
  function getNextRequestCount() internal view returns (uint256) {
    return s_requestCount;
  }

  /**
   * @notice Sets the stored oracle address
   * @param oracleAddress The address of the oracle contract
   */
  function setChainlinkOracle(address oracleAddress) internal {
    s_oracle = OperatorInterface(oracleAddress);
  }

  /**
   * @notice Sets the LINK token address
   * @param linkAddress The address of the LINK token contract
   */
  function setChainlinkToken(address linkAddress) internal {
    s_link = LinkTokenInterface(linkAddress);
  }

  /**
   * @notice Sets the Chainlink token address for the public
   * network as given by the Pointer contract
   */
  function setPublicChainlinkToken() internal {
    setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
  }

  /**
   * @notice Retrieves the stored address of the LINK token
   * @return The address of the LINK token
   */
  function chainlinkTokenAddress() internal view returns (address) {
    return address(s_link);
  }

  /**
   * @notice Retrieves the stored address of the oracle contract
   * @return The address of the oracle contract
   */
  function chainlinkOracleAddress() internal view returns (address) {
    return address(s_oracle);
  }

  /**
   * @notice Allows for a request which was created on another contract to be fulfilled
   * on this contract
   * @param oracleAddress The address of the oracle contract that will fulfill the request
   * @param requestId The request ID used for the response
   */
  function addChainlinkExternalRequest(address oracleAddress, bytes32 requestId) internal notPendingRequest(requestId) {
    s_pendingRequests[requestId] = oracleAddress;
  }

  /**
   * @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
   * @dev Accounts for subnodes having different resolvers
   * @param ensAddress The address of the ENS contract
   * @param node The ENS node hash
   */
  function useChainlinkWithENS(address ensAddress, bytes32 node) internal {
    s_ens = ENSInterface(ensAddress);
    s_ensNode = node;
    bytes32 linkSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_TOKEN_SUBNAME));
    ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(linkSubnode));
    setChainlinkToken(resolver.addr(linkSubnode));
    updateChainlinkOracleWithENS();
  }

  /**
   * @notice Sets the stored oracle contract with the address resolved by ENS
   * @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
   */
  function updateChainlinkOracleWithENS() internal {
    bytes32 oracleSubnode = keccak256(abi.encodePacked(s_ensNode, ENS_ORACLE_SUBNAME));
    ENSResolver_Chainlink resolver = ENSResolver_Chainlink(s_ens.resolver(oracleSubnode));
    setChainlinkOracle(resolver.addr(oracleSubnode));
  }

  /**
   * @notice Ensures that the fulfillment is valid for this contract
   * @dev Use if the contract developer prefers methods instead of modifiers for validation
   * @param requestId The request ID for fulfillment
   */
  function validateChainlinkCallback(bytes32 requestId)
    internal
    recordChainlinkFulfillment(requestId)
  // solhint-disable-next-line no-empty-blocks
  {

  }

  /**
   * @dev Reverts if the sender is not the oracle of the request.
   * Emits ChainlinkFulfilled event.
   * @param requestId The request ID for fulfillment
   */
  modifier recordChainlinkFulfillment(bytes32 requestId) {
    require(msg.sender == s_pendingRequests[requestId], "Source must be the oracle of the request");
    delete s_pendingRequests[requestId];
    emit ChainlinkFulfilled(requestId);
    _;
  }

  /**
   * @dev Reverts if the request is already pending
   * @param requestId The request ID for fulfillment
   */
  modifier notPendingRequest(bytes32 requestId) {
    require(s_pendingRequests[requestId] == address(0), "Request is already pending");
    _;
  }
}

File 4 of 16 : ChainlinkRequestInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ChainlinkRequestInterface {
  function oracleRequest(
    address sender,
    uint256 requestPrice,
    bytes32 serviceAgreementID,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 nonce,
    uint256 dataVersion,
    bytes calldata data
  ) external;

  function cancelOracleRequest(
    bytes32 requestId,
    uint256 payment,
    bytes4 callbackFunctionId,
    uint256 expiration
  ) external;
}

File 5 of 16 : ENSInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ENSInterface {
  // Logged when the owner of a node assigns a new owner to a subnode.
  event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);

  // Logged when the owner of a node transfers ownership to a new account.
  event Transfer(bytes32 indexed node, address owner);

  // Logged when the resolver for a node changes.
  event NewResolver(bytes32 indexed node, address resolver);

  // Logged when the TTL of a node changes
  event NewTTL(bytes32 indexed node, uint64 ttl);

  function setSubnodeOwner(
    bytes32 node,
    bytes32 label,
    address owner
  ) external;

  function setResolver(bytes32 node, address resolver) external;

  function setOwner(bytes32 node, address owner) external;

  function setTTL(bytes32 node, uint64 ttl) external;

  function owner(bytes32 node) external view returns (address);

  function resolver(bytes32 node) external view returns (address);

  function ttl(bytes32 node) external view returns (uint64);
}

File 6 of 16 : LinkTokenInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface LinkTokenInterface {
  function allowance(address owner, address spender) external view returns (uint256 remaining);

  function approve(address spender, uint256 value) external returns (bool success);

  function balanceOf(address owner) external view returns (uint256 balance);

  function decimals() external view returns (uint8 decimalPlaces);

  function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);

  function increaseApproval(address spender, uint256 subtractedValue) external;

  function name() external view returns (string memory tokenName);

  function symbol() external view returns (string memory tokenSymbol);

  function totalSupply() external view returns (uint256 totalTokensIssued);

  function transfer(address to, uint256 value) external returns (bool success);

  function transferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  ) external returns (bool success);

  function transferFrom(
    address from,
    address to,
    uint256 value
  ) external returns (bool success);
}

File 7 of 16 : OperatorInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./OracleInterface.sol";
import "./ChainlinkRequestInterface.sol";

interface OperatorInterface is OracleInterface, ChainlinkRequestInterface {
  function operatorRequest(
    address sender,
    uint256 payment,
    bytes32 specId,
    bytes4 callbackFunctionId,
    uint256 nonce,
    uint256 dataVersion,
    bytes calldata data
  ) external;

  function fulfillOracleRequest2(
    bytes32 requestId,
    uint256 payment,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 expiration,
    bytes calldata data
  ) external returns (bool);

  function ownerTransferAndCall(
    address to,
    uint256 value,
    bytes calldata data
  ) external returns (bool success);

  function distributeFunds(address payable[] calldata receivers, uint256[] calldata amounts) external payable;

  function getAuthorizedSenders() external returns (address[] memory);

  function setAuthorizedSenders(address[] calldata senders) external;

  function getForwarder() external returns (address);
}

File 8 of 16 : OracleInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface OracleInterface {
  function fulfillOracleRequest(
    bytes32 requestId,
    uint256 payment,
    address callbackAddress,
    bytes4 callbackFunctionId,
    uint256 expiration,
    bytes32 data
  ) external returns (bool);

  function isAuthorizedSender(address node) external view returns (bool);

  function withdraw(address recipient, uint256 amount) external;

  function withdrawable() external view returns (uint256);
}

File 9 of 16 : PointerInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface PointerInterface {
  function getAddress() external view returns (address);
}

File 10 of 16 : BufferChainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @dev A library for working with mutable byte buffers in Solidity.
 *
 * Byte buffers are mutable and expandable, and provide a variety of primitives
 * for writing to them. At any time you can fetch a bytes object containing the
 * current contents of the buffer. The bytes object should not be stored between
 * operations, as it may change due to resizing of the buffer.
 */
library BufferChainlink {
  /**
   * @dev Represents a mutable buffer. Buffers have a current value (buf) and
   *      a capacity. The capacity may be longer than the current value, in
   *      which case it can be extended without the need to allocate more memory.
   */
  struct buffer {
    bytes buf;
    uint256 capacity;
  }

  /**
   * @dev Initializes a buffer with an initial capacity.
   * @param buf The buffer to initialize.
   * @param capacity The number of bytes of space to allocate the buffer.
   * @return The buffer, for chaining.
   */
  function init(buffer memory buf, uint256 capacity) internal pure returns (buffer memory) {
    if (capacity % 32 != 0) {
      capacity += 32 - (capacity % 32);
    }
    // Allocate space for the buffer data
    buf.capacity = capacity;
    assembly {
      let ptr := mload(0x40)
      mstore(buf, ptr)
      mstore(ptr, 0)
      mstore(0x40, add(32, add(ptr, capacity)))
    }
    return buf;
  }

  /**
   * @dev Initializes a new buffer from an existing bytes object.
   *      Changes to the buffer may mutate the original value.
   * @param b The bytes object to initialize the buffer with.
   * @return A new buffer.
   */
  function fromBytes(bytes memory b) internal pure returns (buffer memory) {
    buffer memory buf;
    buf.buf = b;
    buf.capacity = b.length;
    return buf;
  }

  function resize(buffer memory buf, uint256 capacity) private pure {
    bytes memory oldbuf = buf.buf;
    init(buf, capacity);
    append(buf, oldbuf);
  }

  function max(uint256 a, uint256 b) private pure returns (uint256) {
    if (a > b) {
      return a;
    }
    return b;
  }

  /**
   * @dev Sets buffer length to 0.
   * @param buf The buffer to truncate.
   * @return The original buffer, for chaining..
   */
  function truncate(buffer memory buf) internal pure returns (buffer memory) {
    assembly {
      let bufptr := mload(buf)
      mstore(bufptr, 0)
    }
    return buf;
  }

  /**
   * @dev Writes a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The start offset to write to.
   * @param data The data to append.
   * @param len The number of bytes to copy.
   * @return The original buffer, for chaining.
   */
  function write(
    buffer memory buf,
    uint256 off,
    bytes memory data,
    uint256 len
  ) internal pure returns (buffer memory) {
    require(len <= data.length);

    if (off + len > buf.capacity) {
      resize(buf, max(buf.capacity, len + off) * 2);
    }

    uint256 dest;
    uint256 src;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Start address = buffer address + offset + sizeof(buffer length)
      dest := add(add(bufptr, 32), off)
      // Update buffer length if we're extending it
      if gt(add(len, off), buflen) {
        mstore(bufptr, add(len, off))
      }
      src := add(data, 32)
    }

    // Copy word-length chunks while possible
    for (; len >= 32; len -= 32) {
      assembly {
        mstore(dest, mload(src))
      }
      dest += 32;
      src += 32;
    }

    // Copy remaining bytes
    unchecked {
      uint256 mask = (256**(32 - len)) - 1;
      assembly {
        let srcpart := and(mload(src), not(mask))
        let destpart := and(mload(dest), mask)
        mstore(dest, or(destpart, srcpart))
      }
    }

    return buf;
  }

  /**
   * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @param len The number of bytes to copy.
   * @return The original buffer, for chaining.
   */
  function append(
    buffer memory buf,
    bytes memory data,
    uint256 len
  ) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, len);
  }

  /**
   * @dev Appends a byte string to a buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, data.length);
  }

  /**
   * @dev Writes a byte to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write the byte at.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function writeUint8(
    buffer memory buf,
    uint256 off,
    uint8 data
  ) internal pure returns (buffer memory) {
    if (off >= buf.capacity) {
      resize(buf, buf.capacity * 2);
    }

    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Length of existing buffer data
      let buflen := mload(bufptr)
      // Address = buffer address + sizeof(buffer length) + off
      let dest := add(add(bufptr, off), 32)
      mstore8(dest, data)
      // Update buffer length if we extended it
      if eq(off, buflen) {
        mstore(bufptr, add(buflen, 1))
      }
    }
    return buf;
  }

  /**
   * @dev Appends a byte to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendUint8(buffer memory buf, uint8 data) internal pure returns (buffer memory) {
    return writeUint8(buf, buf.buf.length, data);
  }

  /**
   * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
   *      exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @param len The number of bytes to write (left-aligned).
   * @return The original buffer, for chaining.
   */
  function write(
    buffer memory buf,
    uint256 off,
    bytes32 data,
    uint256 len
  ) private pure returns (buffer memory) {
    if (len + off > buf.capacity) {
      resize(buf, (len + off) * 2);
    }

    unchecked {
      uint256 mask = (256**len) - 1;
      // Right-align data
      data = data >> (8 * (32 - len));
      assembly {
        // Memory address of the buffer data
        let bufptr := mload(buf)
        // Address = buffer address + sizeof(buffer length) + off + len
        let dest := add(add(bufptr, off), len)
        mstore(dest, or(and(mload(dest), not(mask)), data))
        // Update buffer length if we extended it
        if gt(add(off, len), mload(bufptr)) {
          mstore(bufptr, add(off, len))
        }
      }
    }
    return buf;
  }

  /**
   * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
   *      capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function writeBytes20(
    buffer memory buf,
    uint256 off,
    bytes20 data
  ) internal pure returns (buffer memory) {
    return write(buf, off, bytes32(data), 20);
  }

  /**
   * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chhaining.
   */
  function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, bytes32(data), 20);
  }

  /**
   * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer, for chaining.
   */
  function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
    return write(buf, buf.buf.length, data, 32);
  }

  /**
   * @dev Writes an integer to the buffer. Resizes if doing so would exceed
   *      the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param off The offset to write at.
   * @param data The data to append.
   * @param len The number of bytes to write (right-aligned).
   * @return The original buffer, for chaining.
   */
  function writeInt(
    buffer memory buf,
    uint256 off,
    uint256 data,
    uint256 len
  ) private pure returns (buffer memory) {
    if (len + off > buf.capacity) {
      resize(buf, (len + off) * 2);
    }

    uint256 mask = (256**len) - 1;
    assembly {
      // Memory address of the buffer data
      let bufptr := mload(buf)
      // Address = buffer address + off + sizeof(buffer length) + len
      let dest := add(add(bufptr, off), len)
      mstore(dest, or(and(mload(dest), not(mask)), data))
      // Update buffer length if we extended it
      if gt(add(off, len), mload(bufptr)) {
        mstore(bufptr, add(off, len))
      }
    }
    return buf;
  }

  /**
   * @dev Appends a byte to the end of the buffer. Resizes if doing so would
   * exceed the capacity of the buffer.
   * @param buf The buffer to append to.
   * @param data The data to append.
   * @return The original buffer.
   */
  function appendInt(
    buffer memory buf,
    uint256 data,
    uint256 len
  ) internal pure returns (buffer memory) {
    return writeInt(buf, buf.buf.length, data, len);
  }
}

File 11 of 16 : CBORChainlink.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.19;

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

library CBORChainlink {
  using BufferChainlink for BufferChainlink.buffer;

  uint8 private constant MAJOR_TYPE_INT = 0;
  uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
  uint8 private constant MAJOR_TYPE_BYTES = 2;
  uint8 private constant MAJOR_TYPE_STRING = 3;
  uint8 private constant MAJOR_TYPE_ARRAY = 4;
  uint8 private constant MAJOR_TYPE_MAP = 5;
  uint8 private constant MAJOR_TYPE_TAG = 6;
  uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;

  uint8 private constant TAG_TYPE_BIGNUM = 2;
  uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3;

  function encodeFixedNumeric(BufferChainlink.buffer memory buf, uint8 major, uint64 value) private pure {
    if(value <= 23) {
      buf.appendUint8(uint8((major << 5) | value));
    } else if (value <= 0xFF) {
      buf.appendUint8(uint8((major << 5) | 24));
      buf.appendInt(value, 1);
    } else if (value <= 0xFFFF) {
      buf.appendUint8(uint8((major << 5) | 25));
      buf.appendInt(value, 2);
    } else if (value <= 0xFFFFFFFF) {
      buf.appendUint8(uint8((major << 5) | 26));
      buf.appendInt(value, 4);
    } else {
      buf.appendUint8(uint8((major << 5) | 27));
      buf.appendInt(value, 8);
    }
  }

  function encodeIndefiniteLengthType(BufferChainlink.buffer memory buf, uint8 major) private pure {
    buf.appendUint8(uint8((major << 5) | 31));
  }

  function encodeUInt(BufferChainlink.buffer memory buf, uint value) internal pure {
    if(value > 0xFFFFFFFFFFFFFFFF) {
      encodeBigNum(buf, value);
    } else {
      encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(value));
    }
  }

  function encodeInt(BufferChainlink.buffer memory buf, int value) internal pure {
    if(value < -0x10000000000000000) {
      encodeSignedBigNum(buf, value);
    } else if(value > 0xFFFFFFFFFFFFFFFF) {
      encodeBigNum(buf, uint(value));
    } else if(value >= 0) {
      encodeFixedNumeric(buf, MAJOR_TYPE_INT, uint64(uint256(value)));
    } else {
      encodeFixedNumeric(buf, MAJOR_TYPE_NEGATIVE_INT, uint64(uint256(-1 - value)));
    }
  }

  function encodeBytes(BufferChainlink.buffer memory buf, bytes memory value) internal pure {
    encodeFixedNumeric(buf, MAJOR_TYPE_BYTES, uint64(value.length));
    buf.append(value);
  }

  function encodeBigNum(BufferChainlink.buffer memory buf, uint value) internal pure {
    buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM));
    encodeBytes(buf, abi.encode(value));
  }

  function encodeSignedBigNum(BufferChainlink.buffer memory buf, int input) internal pure {
    buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM));
    encodeBytes(buf, abi.encode(uint256(-1 - input)));
  }

  function encodeString(BufferChainlink.buffer memory buf, string memory value) internal pure {
    encodeFixedNumeric(buf, MAJOR_TYPE_STRING, uint64(bytes(value).length));
    buf.append(bytes(value));
  }

  function startArray(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
  }

  function startMap(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
  }

  function endSequence(BufferChainlink.buffer memory buf) internal pure {
    encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
  }
}

File 12 of 16 : ENSResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract ENSResolver {
  function addr(bytes32 node) public view virtual returns (address);
}

File 13 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 14 of 16 : IGToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Interface for GToken contract
 */
interface IGToken {
    struct GnsPriceProvider {
        address addr;
        bytes signature;
    }

    struct LockedDeposit {
        address owner;
        uint256 shares; // collateralConfig.precision
        uint256 assetsDeposited; // collateralConfig.precision
        uint256 assetsDiscount; // collateralConfig.precision
        uint256 atTimestamp; // timestamp
        uint256 lockDuration; // timestamp
    }

    struct ContractAddresses {
        address asset;
        address owner; // 2-week timelock contract
        address manager; // 3-day timelock contract
        address admin; // bypasses timelock, access to emergency functions
        address gnsToken;
        address lockedDepositNft;
        address pnlHandler;
        address openTradesPnlFeed;
        GnsPriceProvider gnsPriceProvider;
    }

    struct Meta {
        string name;
        string symbol;
    }

    function manager() external view returns (address);

    function admin() external view returns (address);

    function currentEpoch() external view returns (uint256);

    function currentEpochStart() external view returns (uint256);

    function currentEpochPositiveOpenPnl() external view returns (uint256);

    function updateAccPnlPerTokenUsed(
        uint256 prevPositiveOpenPnl,
        uint256 newPositiveOpenPnl
    ) external returns (uint256);

    function getLockedDeposit(uint256 depositId) external view returns (LockedDeposit memory);

    function sendAssets(uint256 assets, address receiver) external;

    function receiveAssets(uint256 assets, address user) external;

    function distributeReward(uint256 assets) external;

    function tvl() external view returns (uint256);

    function marketCap() external view returns (uint256);

    function shareToAssetsPrice() external view returns (uint256);

    function collateralConfig() external view returns (uint128, uint128);

    event ManagerUpdated(address newValue);
    event AdminUpdated(address newValue);
    event PnlHandlerUpdated(address newValue);
    event OpenTradesPnlFeedUpdated(address newValue);
    event GnsPriceProviderUpdated(GnsPriceProvider newValue);
    event WithdrawLockThresholdsPUpdated(uint256[2] newValue);
    event MaxAccOpenPnlDeltaUpdated(uint256 newValue);
    event MaxDailyAccPnlDeltaUpdated(uint256 newValue);
    event MaxSupplyIncreaseDailyPUpdated(uint256 newValue);
    event LossesBurnPUpdated(uint256 newValue);
    event MaxGnsSupplyMintDailyPUpdated(uint256 newValue);
    event MaxDiscountPUpdated(uint256 newValue);
    event MaxDiscountThresholdPUpdated(uint256 newValue);

    event CurrentMaxSupplyUpdated(uint256 newValue);
    event DailyAccPnlDeltaReset();
    event ShareToAssetsPriceUpdated(uint256 newValue);
    event OpenTradesPnlFeedCallFailed();

    event WithdrawRequested(
        address indexed sender,
        address indexed owner,
        uint256 shares,
        uint256 currEpoch,
        uint256 indexed unlockEpoch
    );
    event WithdrawCanceled(
        address indexed sender,
        address indexed owner,
        uint256 shares,
        uint256 currEpoch,
        uint256 indexed unlockEpoch
    );

    event DepositLocked(address indexed sender, address indexed owner, uint256 depositId, LockedDeposit d);
    event DepositUnlocked(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 depositId,
        LockedDeposit d
    );

    event RewardDistributed(address indexed sender, uint256 assets);

    event AssetsSent(address indexed sender, address indexed receiver, uint256 assets);
    event AssetsReceived(address indexed sender, address indexed user, uint256 assets, uint256 assetsLessDeplete);

    event Depleted(address indexed sender, uint256 assets, uint256 amountGns);
    event Refilled(address indexed sender, uint256 assets, uint256 amountGns);

    event AccPnlPerTokenUsedUpdated(
        address indexed sender,
        uint256 indexed newEpoch,
        uint256 prevPositiveOpenPnl,
        uint256 newPositiveOpenPnl,
        uint256 newEpochPositiveOpenPnl,
        int256 newAccPnlPerTokenUsed
    );

    error OnlyManager();
    error OnlyTradingPnlHandler();
    error OnlyPnlFeed();
    error AddressZero();
    error PriceZero();
    error ValueZero();
    error BytesZero();
    error NoActiveDiscount();
    error BelowMin();
    error AboveMax();
    error WrongValue();
    error WrongValues();
    error GnsPriceCallFailed();
    error GnsTokenPriceZero();
    error PendingWithdrawal();
    error EndOfEpoch();
    error NotAllowed();
    error NoDiscount();
    error NotUnlocked();
    error NotEnoughAssets();
    error MaxDailyPnl();
    error NotUnderCollateralized();
    error AboveInflationLimit();

    // Ownable
    error OwnableInvalidOwner(address owner);

    // ERC4626
    error ERC4626ExceededMaxDeposit();
    error ERC4626ExceededMaxMint();
    error ERC4626ExceededMaxWithdraw();
    error ERC4626ExceededMaxRedeem();
}

File 15 of 16 : IGTokenOpenPnlFeed.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Interface for GTokenOpenPnlFeed contract
 */
interface IGTokenOpenPnlFeed {
    struct Request {
        bool initiated;
        bool active;
        uint256 linkFeePerNode;
    }

    function nextEpochValuesRequestCount() external view returns (uint256);

    function newOpenPnlRequestOrEpoch() external;

    function fulfill(bytes32 requestId, int256 value) external;

    event NumberParamUpdated(string name, uint256 newValue);
    event OracleUpdated(uint256 index, address newValue);
    event OraclesUpdated(address[] newValues);
    event JobUpdated(bytes32 newValue);

    event NextEpochValuesReset(uint256 indexed currEpoch, uint256 requestsResetCount);

    event NewEpochForced(uint256 indexed newEpoch);

    event NextEpochValueRequested(
        uint256 indexed currEpoch,
        uint256 indexed requestId,
        bytes32 job,
        uint256 oraclesCount,
        uint256 linkFeePerNode
    );

    event NewEpoch(
        uint256 indexed newEpoch,
        uint256 indexed requestId,
        int256[] epochMedianValues,
        int256 epochAverageValue,
        uint256 newEpochPositiveOpenPnl
    );

    event RequestValueReceived(
        bool isLate,
        uint256 indexed currEpoch,
        uint256 indexed requestId,
        bytes32 oracleRequestId,
        address indexed oracle,
        int256 requestValue,
        uint256 linkFee
    );

    event RequestMedianValueSet(
        uint256 indexed currEpoch,
        uint256 indexed requestId,
        int256[] requestValues,
        int256 medianValue
    );
}

File 16 of 16 : IOwnable.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

/**
 * @dev Interface for ownable contracts
 */
interface IOwnable {
    function owner() external view returns (address);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"_LINK_FEE_BALANCE_DIVIDER","type":"uint256"},{"internalType":"address","name":"_linkToken","type":"address"},{"internalType":"contract IGToken","name":"_gToken","type":"address"},{"internalType":"address[]","name":"_oracles","type":"address[]"},{"internalType":"bytes32","name":"_job","type":"bytes32"},{"internalType":"uint256","name":"_minAnswers","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkFulfilled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"id","type":"bytes32"}],"name":"ChainlinkRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"newValue","type":"bytes32"}],"name":"JobUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newEpoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"int256[]","name":"epochMedianValues","type":"int256[]"},{"indexed":false,"internalType":"int256","name":"epochAverageValue","type":"int256"},{"indexed":false,"internalType":"uint256","name":"newEpochPositiveOpenPnl","type":"uint256"}],"name":"NewEpoch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"newEpoch","type":"uint256"}],"name":"NewEpochForced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"currEpoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"job","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"oraclesCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"linkFeePerNode","type":"uint256"}],"name":"NextEpochValueRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"currEpoch","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"requestsResetCount","type":"uint256"}],"name":"NextEpochValuesReset","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"NumberParamUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"address","name":"newValue","type":"address"}],"name":"OracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address[]","name":"newValues","type":"address[]"}],"name":"OraclesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"currEpoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"int256[]","name":"requestValues","type":"int256[]"},{"indexed":false,"internalType":"int256","name":"medianValue","type":"int256"}],"name":"RequestMedianValueSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isLate","type":"bool"},{"indexed":true,"internalType":"uint256","name":"currEpoch","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"requestId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"oracleRequestId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"int256","name":"requestValue","type":"int256"},{"indexed":false,"internalType":"uint256","name":"linkFee","type":"uint256"}],"name":"RequestValueReceived","type":"event"},{"inputs":[],"name":"LINK_FEE_BALANCE_DIVIDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceNewEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"requestId","type":"bytes32"},{"internalType":"int256","name":"value","type":"int256"}],"name":"fulfill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"gToken","outputs":[{"internalType":"contract IGToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"job","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastRequestId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minAnswers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"newOpenPnlRequestOrEpoch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"nextEpochValues","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextEpochValuesLastRequest","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextEpochValuesRequestCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"oracles","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"requestAnswers","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"requestIds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"requests","outputs":[{"internalType":"bool","name":"initiated","type":"bool"},{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"linkFeePerNode","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestsCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestsEvery","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestsStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resetNextEpochValueRequests","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newValue","type":"bytes32"}],"name":"updateJob","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateMinAnswers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"},{"internalType":"address","name":"newValue","type":"address"}],"name":"updateOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"newValues","type":"address[]"}],"name":"updateOracles","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateRequestsCount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateRequestsEvery","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRequestsStart","type":"uint256"},{"internalType":"uint256","name":"newRequestsEvery","type":"uint256"},{"internalType":"uint256","name":"newRequestsCount","type":"uint256"}],"name":"updateRequestsInfoBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newValue","type":"uint256"}],"name":"updateRequestsStart","outputs":[],"stateMutability":"nonpayable","type":"function"}]

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101b95760003560e01c8063a90d67a1116100f9578063cb9945a111610097578063e704fc5111610071578063e704fc51146103c1578063f5ed447c146103c9578063fbfa4b7f146103dc578063fc2a88c3146103e557600080fd5b8063cb9945a114610374578063ce43963214610387578063d5a28da31461039a57600080fd5b8063bda71d04116100d3578063bda71d041461033d578063bea1675814610350578063bef35b7914610359578063c591ff4c1461036157600080fd5b8063a90d67a114610318578063b006812c14610321578063b8feee641461033457600080fd5b806376ffb9bd1161016657806392c3c58b1161014057806392c3c58b146102d75780639496f9e3146102df5780639dbc2686146102f2578063a5c2aafd1461030557600080fd5b806376ffb9bd1461023f57806381d12c58146102665780638645f7a8146102b757600080fd5b80635614a211116101975780635614a211146101f857806358e7ec3c1461020b5780635b69a7d81461021457600080fd5b80632eb64ec4146101be57806334fa54a1146101da578063473d2f21146101ef575b600080fd5b6101c760065481565b6040519081526020015b60405180910390f35b6101ed6101e8366004612407565b6103ee565b005b6101c7600e5481565b6101ed610206366004612407565b6105b2565b6101c7600a5481565b610227610222366004612407565b610767565b6040516001600160a01b0390911681526020016101d1565b6102277f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d86081565b61029a610274366004612407565b6011602052600090815260409020805460019091015460ff808316926101009004169083565b6040805193151584529115156020840152908201526060016101d1565b6101c76102c5366004612407565b60106020526000908152604090205481565b6101ed610791565b6101ed6102ed366004612407565b6109df565b6101ed61030036600461245b565b610b1c565b6101ed610313366004612407565b610c8c565b6101c760075481565b6101c761032f366004612407565b610e44565b6101c7600d5481565b6101ed61034b366004612520565b610e65565b6101c7600b5481565b6101ed6111ac565b6101ed61036f366004612542565b6112a6565b6101c7610382366004612520565b611390565b6101ed61039536600461256e565b6113c1565b6101c77f000000000000000000000000000000000000000000000000000000000000006481565b6101ed61159b565b6101ed6103d7366004612407565b6116cd565b6101c760085481565b6101c7600f5481565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561044c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610470919061259e565b6001600160a01b0316336001600160a01b0316146104c25760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064015b60405180910390fd5b610e108110156105005760405162461bcd60e51b81526020600482015260096024820152682122a627abafa6a4a760b91b60448201526064016104b9565b6201518081111561053f5760405162461bcd60e51b8152602060048201526009602482015268082849eac8abe9a82b60bb1b60448201526064016104b9565b600781905560408051818152600d918101919091527f72657175657374734576657279000000000000000000000000000000000000006060820152602081018290527f127735ae9d047cae55da37db2c8ee184c735aacd68cef068d4e70be6a41661d9906080015b60405180910390a150565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610610573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610634919061259e565b6001600160a01b0316336001600160a01b0316146106815760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064016104b9565b60038110156106be5760405162461bcd60e51b81526020600482015260096024820152682122a627abafa6a4a760b91b60448201526064016104b9565b600a8111156106fb5760405162461bcd60e51b8152602060048201526009602482015268082849eac8abe9a82b60bb1b60448201526064016104b9565b600881905560408051818152600d918101919091527f7265717565737473436f756e74000000000000000000000000000000000000006060820152602081018290527f127735ae9d047cae55da37db2c8ee184c735aacd68cef068d4e70be6a41661d9906080016105a7565b6009818154811061077757600080fd5b6000918252602090912001546001600160a01b0316905081565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107ef573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610813919061259e565b6001600160a01b0316336001600160a01b0316146108735760405162461bcd60e51b815260206004820152600a60248201527f4f4e4c595f41444d494e0000000000000000000000000000000000000000000060448201526064016104b9565b600d54806108c35760405162461bcd60e51b815260206004820152601360248201527f4e4f5f524551554553545f544f5f52455345540000000000000000000000000060448201526064016104b9565b6108cf600c600061236f565b6000600d819055600e8190555b818110156109265760006011600083600f546108f891906125d1565b8152602081019190915260400160002080549115156101000261ff00199092169190911790556001016108dc565b507f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663766718086040518163ffffffff1660e01b8152600401602060405180830381865afa158015610985573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a991906125e4565b6040518281527f605f3f824643ee56deaf2717c1581f7ad3df423365aede8e2d771b6b3a30fd2b9060200160405180910390a250565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a61919061259e565b6001600160a01b0316336001600160a01b031614610ab05760405162461bcd60e51b815260206004820152600c60248201526b27a7262cafa6a0a720a3a2a960a11b60448201526064016104b9565b80610ae75760405162461bcd60e51b8152602060048201526007602482015266056414c55455f360cc1b60448201526064016104b9565b600a8190556040518181527f9f3fa8c139076940687248e93aed7dda099cf9a90cc38c428cf3d5b6b642fdd4906020016105a7565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b9e919061259e565b6001600160a01b0316336001600160a01b031614610beb5760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064016104b9565b600b54610bf99060026125fd565b81511015610c495760405162461bcd60e51b815260206004820152600f60248201527f41525241595f544f4f5f534d414c4c000000000000000000000000000000000060448201526064016104b9565b8051610c5c90600990602084019061238d565b507f4b806663ee384a0ada322e70cdf3fd2046424181359f2470a97a6f0cec328e9c816040516105a79190612614565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610cea573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d0e919061259e565b6001600160a01b0316336001600160a01b031614610d5b5760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064016104b9565b610e10811015610d995760405162461bcd60e51b81526020600482015260096024820152682122a627abafa6a4a760b91b60448201526064016104b9565b62093a80811115610dd85760405162461bcd60e51b8152602060048201526009602482015268082849eac8abe9a82b60bb1b60448201526064016104b9565b600681905560408051818152600d918101919091527f72657175657374735374617274000000000000000000000000000000000000006060820152602081018290527f127735ae9d047cae55da37db2c8ee184c735aacd68cef068d4e70be6a41661d9906080016105a7565b600c8181548110610e5457600080fd5b600091825260209091200154905081565b60008281526005602052604090205482906001600160a01b03163314610ef35760405162461bcd60e51b815260206004820152602860248201527f536f75726365206d75737420626520746865206f7261636c65206f662074686560448201527f207265717565737400000000000000000000000000000000000000000000000060648201526084016104b9565b60008181526005602052604080822080546001600160a01b03191690555182917f7cc135e0cebb02c3480ae5d74d377283180a2601f8f644edf7987b009316c63a91a26000838152601060209081526040808320805490849055808452601183528184208251606081018452815460ff808216151583526101009091041615158186015260019190910154818401528251630ecce30160e31b815292519194909390926001600160a01b037f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d86016926376671808926004808401939192918290030181865afa158015610fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100d91906125e4565b6020808401516040808601518151921583529282018a9052810188905260608101919091529091503390849083907f5e18490ff1cb10067b5d5b0aec04678191bb80c2d229a2578526c389270027bf9060800160405180910390a4816020015161107957505050505050565b6000838152601260209081526040822080546001810182558184529190922001869055600b548154036111a2576000611100828054806020026020016040519081016040528092919081815260200182805480156110f657602002820191906000526020600020905b8154815260200190600101908083116110e2575b5050505050611891565b600c80546001810182556000919091527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c701819055604051909150859084907f2cc31a5acf549ee44228d82c08e88b92b9d332ad5193a2290a79345e113c0b4c9061116e90869086906126a2565b60405180910390a36000858152601160209081526040808320805461ff0019169055601290915281206111a09161236f565b505b505050505b505050565b600e541580801561124a57506006547f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b03166361a8c8c46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611219573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061123d91906125e4565b61124790426125d1565b10155b1561125a57611257611955565b50565b801580156112765750600754600e5461127390426125d1565b10155b1561125757600854600d54101561128f57611257611955565b600854600c5410611257576112a2611bed565b5050565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611304573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611328919061259e565b6001600160a01b0316336001600160a01b0316146113755760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064016104b9565b61137e83610c8c565b611387826103ee565b6111a7816105b2565b601260205281600052604060002081815481106113ac57600080fd5b90600052602060002001600091509150505481565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561141f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611443919061259e565b6001600160a01b0316336001600160a01b0316146114905760405162461bcd60e51b815260206004820152600a60248201526927a7262cafa7aba722a960b11b60448201526064016104b9565b60095482106114e15760405162461bcd60e51b815260206004820152600d60248201527f494e4445585f544f4f5f4249470000000000000000000000000000000000000060448201526064016104b9565b6001600160a01b0381166115215760405162461bcd60e51b8152602060048201526007602482015266056414c55455f360cc1b60448201526064016104b9565b8060098381548110611535576115356126c4565b60009182526020918290200180546001600160a01b0319166001600160a01b0393841617905560408051858152928416918301919091527f8323208263554cf72b3658bcdbd0f96f4ccf2c9c919fa30246aaee34537b5509910160405180910390a15050565b6008546007546115ab91906125fd565b6006546115b891906126da565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b03166361a8c8c46040518163ffffffff1660e01b8152600401602060405180830381865afa158015611616573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061163a91906125e4565b61164490426125d1565b10156116925760405162461bcd60e51b815260206004820152600960248201527f544f4f5f4541524c59000000000000000000000000000000000000000000000060448201526064016104b9565b600061169c611bed565b60405190915081907f446b8726654d216fe9781583f0f34cc8ac84d240bb3ad5293c10e2ff831f1eb290600090a250565b7f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663481c6a756040518163ffffffff1660e01b8152600401602060405180830381865afa15801561172b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174f919061259e565b6001600160a01b0316336001600160a01b03161461179e5760405162461bcd60e51b815260206004820152600c60248201526b27a7262cafa6a0a720a3a2a960a11b60448201526064016104b9565b60028110156117db5760405162461bcd60e51b81526020600482015260096024820152682122a627abafa6a4a760b91b60448201526064016104b9565b6009546117ea90600290612703565b8111156118255760405162461bcd60e51b8152602060048201526009602482015268082849eac8abe9a82b60bb1b60448201526064016104b9565b600b81905560408051818152600a918101919091527f6d696e416e7377657273000000000000000000000000000000000000000000006060820152602081018290527f127735ae9d047cae55da37db2c8ee184c735aacd68cef068d4e70be6a41661d9906080016105a7565b60006118a08260008451611e77565b600282516118ae9190612717565b156118df5781600283516118c29190612703565b815181106118d2576118d26126c4565b602002602001015161194f565b600282600284516118f09190612703565b81518110611900576119006126c4565b6020026020010151836001600286516119199190612703565b61192391906125d1565b81518110611933576119336126c4565b6020026020010151611945919061272b565b61194f9190612753565b92915050565b600061196b600a543063bda71d0460e01b611f32565b6009549091506000907f00000000000000000000000000000000000000000000000000000000000000646119a76002546001600160a01b031690565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156119ed573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a1191906125e4565b611a1b9190612703565b611a259190612703565b905060405180606001604052806001151581526020016001151581526020018281525060116000600f60008154611a5b90612781565b9182905550815260208082019290925260409081016000908120845181549486015161ffff1990951690151561ff0019161761010094151594909402939093178355920151600190910155600d805491611ab483612781565b909155505042600e5560005b600954811015611b1c57600f5460106000611b0360098581548110611ae757611ae76126c4565b6000918252602090912001546001600160a01b03168787611fc3565b8152602081019190915260400160002055600101611ac0565b50600f547f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663766718086040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b7e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba291906125e4565b600a5460095460408051928352602083019190915281018490527fb5f2943c67db1794f39a3b46b95086765f48c7e05d12851dc6607bcdb0bcc7a39060600160405180910390a35050565b600080600d819055506000600e8190555060007f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663faf33f296040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c5e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8291906125e4565b600854600c549192506000911015611c9a5781611cf3565b611cf3600c805480602002602001604051908101604052809291908181526020018280548015611ce957602002820191906000526020600020905b815481526020019060010190808311611cd5575b505050505061206b565b905060007f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b0316637361a5448460008513611d36576000611d38565b845b6040516001600160e01b031960e085901b168152600481019290925260248201526044016020604051808303816000875af1158015611d7b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9f91906125e4565b90507f000000000000000000000000dd9c98e5022af88b9c991ab24f02b4a8be81d8606001600160a01b031663766718086040518163ffffffff1660e01b8152600401602060405180830381865afa158015611dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2391906125e4565b9350600f54847f263c5efc95bb2e2134e3fc52ae914fbd38e2381f37d95ae011a56f996578bf17600c8585604051611e5d9392919061279a565b60405180910390a3611e71600c600061236f565b50505090565b808210611e8357505050565b60008290506000848281518110611e9c57611e9c6126c4565b602002602001015190506000846001611eb591906126da565b90505b83811015611eff5781868281518110611ed357611ed36126c4565b60200260200101511215611ef757611ef78682611eef86612781565b9550856120bd565b600101611eb8565b50611f0b8585846120bd565b611f16858584611e77565b611f2b85611f258460016126da565b85611e77565b5050505050565b611f706040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b611fae6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b611fba81868686612130565b95945050505050565b600454600090611fd48160016126da565b600455835160408086015160808701515191516000936320214ca360e11b9361200c9386938493923092918a91600191602401612805565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166001600160e01b0319909316929092179091529050612061868386846121ac565b9695505050505050565b60008060005b83518110156120a95783818151811061208c5761208c6126c4565b60200260200101518261209f919061272b565b9150600101612071565b5082516120b69082612753565b9392505050565b8281815181106120cf576120cf6126c4565b60200260200101518383815181106120e9576120e96126c4565b6020026020010151848481518110612103576121036126c4565b6020026020010185848151811061211c5761211c6126c4565b602090810291909101019190915252505050565b61216e6040805160a0810182526000808252602080830182905282840182905260608084018390528451808601909552845283015290608082015290565b61217e856080015161010061230a565b50508284526001600160a01b03821660208501526001600160e01b031981166040850152835b949350505050565b6040516bffffffffffffffffffffffff193060601b1660208201526034810184905260009060540160408051808303601f1901815282825280516020918201206000818152600590925291812080546001600160a01b0319166001600160a01b038a1617905590925082917fb5e6e01e79f91267dc17b4e6314d5d4d03593d2ceee0fbb452b750bd70ea5af99190a2600254604051630200057560e51b81526001600160a01b0390911690634000aea09061226f90889087908790600401612868565b6020604051808303816000875af115801561228e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122b29190612890565b6121a45760405162461bcd60e51b815260206004820152602360248201527f756e61626c6520746f207472616e73666572416e6443616c6c20746f206f7261604482015262636c6560e81b60648201526084016104b9565b60408051808201909152606081526000602082015261232a602083612717565b156123525761233a602083612717565b6123459060206125d1565b61234f90836126da565b91505b506020828101829052604080518085526000815290920101905290565b508054600082559060005260206000209081019061125791906123f2565b8280548282559060005260206000209081019282156123e2579160200282015b828111156123e257825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906123ad565b506123ee9291506123f2565b5090565b5b808211156123ee57600081556001016123f3565b60006020828403121561241957600080fd5b5035919050565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b038116811461125757600080fd5b803561245681612436565b919050565b6000602080838503121561246e57600080fd5b823567ffffffffffffffff8082111561248657600080fd5b818501915085601f83011261249a57600080fd5b8135818111156124ac576124ac612420565b8060051b604051601f19603f830116810181811085821117156124d1576124d1612420565b6040529182528482019250838101850191888311156124ef57600080fd5b938501935b82851015612514576125058561244b565b845293850193928501926124f4565b98975050505050505050565b6000806040838503121561253357600080fd5b50508035926020909101359150565b60008060006060848603121561255757600080fd5b505081359360208301359350604090920135919050565b6000806040838503121561258157600080fd5b82359150602083013561259381612436565b809150509250929050565b6000602082840312156125b057600080fd5b81516120b681612436565b634e487b7160e01b600052601160045260246000fd5b8181038181111561194f5761194f6125bb565b6000602082840312156125f657600080fd5b5051919050565b808202811582820484141761194f5761194f6125bb565b6020808252825182820181905260009190848201906040850190845b818110156126555783516001600160a01b031683529284019291840191600101612630565b50909695505050505050565b600081548084526020808501945083600052602060002060005b838110156126975781548752958201956001918201910161267b565b509495945050505050565b6040815260006126b56040830185612661565b90508260208301529392505050565b634e487b7160e01b600052603260045260246000fd5b8082018082111561194f5761194f6125bb565b634e487b7160e01b600052601260045260246000fd5b600082612712576127126126ed565b500490565b600082612726576127266126ed565b500690565b808201828112600083128015821682158216171561274b5761274b6125bb565b505092915050565b600082612762576127626126ed565b600160ff1b82146000198414161561277c5761277c6125bb565b500590565b600060018201612793576127936125bb565b5060010190565b6060815260006127ad6060830186612661565b60208301949094525060400152919050565b6000815180845260005b818110156127e5576020818501810151868301820152016127c9565b506000602082860101526020601f19601f83011685010191505092915050565b60006101006001600160a01b03808c1684528a602085015289604085015280891660608501525063ffffffff60e01b871660808401528560a08401528460c08401528060e0840152612859818401856127bf565b9b9a5050505050505050505050565b6001600160a01b0384168152826020820152606060408201526000611fba60608301846127bf565b6000602082840312156128a257600080fd5b815180151581146120b657600080fdfea2646970667358221220d08392cfc9c2d4f18fb9b50226101320c6c57683907e7dad22867898cddf648564736f6c63430008170033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.