ETH Price: $2,095.61 (+0.80%)

Transaction Decoder

Block:
22248770 at Apr-11-2025 10:44:35 PM +UTC
Transaction Fee:
0.000040511991552784 ETH $0.08
Gas Used:
76,952 Gas / 0.526457942 Gwei

Emitted Events:

288 MutuumPresale.BuyToken( buyer=[Sender] 0x84fe4da5b87d1f9514134978d1c65d57981e3d9a, token=0x00000000...000000000, amountIn=478474210814206213, amountOut=30000000000000002867575 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
11.500078622394972361 Eth11.500086317594972361 Eth0.0000076952
0x84FE4da5...7981E3d9A
0.96842336636511952 Eth
Nonce: 2
0.489908643559360523 Eth
Nonce: 3
0.478514722805758997
0xa4Ca34e7...B9547b84E
(Mutuum: Presale)
0xdBfBaBc3...a0d8Fe864 2,190.918503900157665768 Eth2,191.396978110971871981 Eth0.478474210814206213

Execution Trace

ETH 0.478474210814206213 MutuumPresale.buyToken( _token=0x0000000000000000000000000000000000000000, _amount=478474210814206213 )
  • EACAggregatorProxy.STATICCALL( )
    • 0x7d4e742018fb52e48b08be73d041c18b21de6fb5.STATICCALL( )
    • ETH 0.478474210814206213 0xdbfbabc3029754c960d055f4d0410c8a0d8fe864.CALL( )
      File 1 of 2: MutuumPresale
      /**
       *Submitted for verification at testnet.bscscan.com on 2024-10-04
       */
      
      // Sources flattened with hardhat v2.22.12 https://hardhat.org
      
      // SPDX-License-Identifier: MIT
      
      // File @openzeppelin/contracts/utils/Context.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      abstract contract Context {
          function _msgSender() internal view virtual returns (address) {
              return msg.sender;
          }
      
          function _msgData() internal view virtual returns (bytes calldata) {
              return msg.data;
          }
      
          function _contextSuffixLength() internal view virtual returns (uint256) {
              return 0;
          }
      }
      
      // File @openzeppelin/contracts/access/Ownable.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * The initial owner is set to the address provided by the deployer. This can
       * later be changed with {transferOwnership}.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      abstract contract Ownable is Context {
          address private _owner;
      
          /**
           * @dev The caller account is not authorized to perform an operation.
           */
          error OwnableUnauthorizedAccount(address account);
      
          /**
           * @dev The owner is not a valid owner account. (eg. `address(0)`)
           */
          error OwnableInvalidOwner(address owner);
      
          event OwnershipTransferred(
              address indexed previousOwner,
              address indexed newOwner
          );
      
          /**
           * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
           */
          constructor(address initialOwner) {
              if (initialOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(initialOwner);
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              _checkOwner();
              _;
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view virtual returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if the sender is not the owner.
           */
          function _checkOwner() internal view virtual {
              if (owner() != _msgSender()) {
                  revert OwnableUnauthorizedAccount(_msgSender());
              }
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby disabling any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
              _transferOwnership(address(0));
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
              if (newOwner == address(0)) {
                  revert OwnableInvalidOwner(address(0));
              }
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Internal function without access restriction.
           */
          function _transferOwnership(address newOwner) internal virtual {
              address oldOwner = _owner;
              _owner = newOwner;
              emit OwnershipTransferred(oldOwner, newOwner);
          }
      }
      
      // File @openzeppelin/contracts/token/ERC20/IERC20.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @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 value of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
      
          /**
           * @dev Returns the value of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
      
          /**
           * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
      
          /**
           * @dev Moves a `value` amount of tokens from `from` to `to` using the
           * allowance mechanism. `value` 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 value
          ) external returns (bool);
      }
      
      // File @openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @dev Interface for the optional metadata functions from the ERC20 standard.
       */
      interface IERC20Metadata is IERC20 {
          /**
           * @dev Returns the name of the token.
           */
          function name() external view returns (string memory);
      
          /**
           * @dev Returns the symbol of the token.
           */
          function symbol() external view returns (string memory);
      
          /**
           * @dev Returns the decimals places of the token.
           */
          function decimals() external view returns (uint8);
      }
      
      // File @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
       * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
       *
       * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
       * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
       * need to send a transaction, and thus is not required to hold Ether at all.
       *
       * ==== Security Considerations
       *
       * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
       * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
       * considered as an intention to spend the allowance in any specific way. The second is that because permits have
       * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
       * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
       * generally recommended is:
       *
       * ```solidity
       * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
       *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
       *     doThing(..., value);
       * }
       *
       * function doThing(..., uint256 value) public {
       *     token.safeTransferFrom(msg.sender, address(this), value);
       *     ...
       * }
       * ```
       *
       * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
       * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
       * {SafeERC20-safeTransferFrom}).
       *
       * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
       * contracts should have entry points that don't rely on permit.
       */
      interface IERC20Permit {
          /**
           * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
           * given ``owner``'s signed approval.
           *
           * IMPORTANT: The same issues {IERC20-approve} has related to transaction
           * ordering also apply here.
           *
           * Emits an {Approval} event.
           *
           * Requirements:
           *
           * - `spender` cannot be the zero address.
           * - `deadline` must be a timestamp in the future.
           * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
           * over the EIP712-formatted function arguments.
           * - the signature must use ``owner``'s current nonce (see {nonces}).
           *
           * For more information on the signature format, see the
           * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
           * section].
           *
           * CAUTION: See Security Considerations above.
           */
          function permit(
              address owner,
              address spender,
              uint256 value,
              uint256 deadline,
              uint8 v,
              bytes32 r,
              bytes32 s
          ) external;
      
          /**
           * @dev Returns the current nonce for `owner`. This value must be
           * included whenever a signature is generated for {permit}.
           *
           * Every successful call to {permit} increases ``owner``'s nonce by one. This
           * prevents a signature from being used multiple times.
           */
          function nonces(address owner) external view returns (uint256);
      
          /**
           * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
           */
          // solhint-disable-next-line func-name-mixedcase
          function DOMAIN_SEPARATOR() external view returns (bytes32);
      }
      
      // File @openzeppelin/contracts/utils/Address.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev The ETH balance of the account is not enough to perform the operation.
           */
          error AddressInsufficientBalance(address account);
      
          /**
           * @dev There's no code at `target` (it is not a contract).
           */
          error AddressEmptyCode(address target);
      
          /**
           * @dev A call to an address target failed. The target may have reverted.
           */
          error FailedInnerCall();
      
          /**
           * @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://consensys.net/diligence/blog/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.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              if (address(this).balance < amount) {
                  revert AddressInsufficientBalance(address(this));
              }
      
              (bool success, ) = recipient.call{value: amount}("");
              if (!success) {
                  revert FailedInnerCall();
              }
          }
      
          /**
           * @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 or custom error, it is bubbled
           * up by this function (like regular Solidity function calls). However, if
           * the call reverted with no returned reason, this function reverts with a
           * {FailedInnerCall} error.
           *
           * 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.
           */
          function functionCall(address target, bytes memory data)
              internal
              returns (bytes memory)
          {
              return functionCallWithValue(target, data, 0);
          }
      
          /**
           * @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`.
           */
          function functionCallWithValue(
              address target,
              bytes memory data,
              uint256 value
          ) internal returns (bytes memory) {
              if (address(this).balance < value) {
                  revert AddressInsufficientBalance(address(this));
              }
              (bool success, bytes memory returndata) = target.call{value: value}(
                  data
              );
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a static call.
           */
          function functionStaticCall(address target, bytes memory data)
              internal
              view
              returns (bytes memory)
          {
              (bool success, bytes memory returndata) = target.staticcall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
           * but performing a delegate call.
           */
          function functionDelegateCall(address target, bytes memory data)
              internal
              returns (bytes memory)
          {
              (bool success, bytes memory returndata) = target.delegatecall(data);
              return verifyCallResultFromTarget(target, success, returndata);
          }
      
          /**
           * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
           * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
           * unsuccessful call.
           */
          function verifyCallResultFromTarget(
              address target,
              bool success,
              bytes memory returndata
          ) internal view returns (bytes memory) {
              if (!success) {
                  _revert(returndata);
              } else {
                  // only check if target is a contract if the call was successful and the return data is empty
                  // otherwise we already know that it was a contract
                  if (returndata.length == 0 && target.code.length == 0) {
                      revert AddressEmptyCode(target);
                  }
                  return returndata;
              }
          }
      
          /**
           * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
           * revert reason or with a default {FailedInnerCall} error.
           */
          function verifyCallResult(bool success, bytes memory returndata)
              internal
              pure
              returns (bytes memory)
          {
              if (!success) {
                  _revert(returndata);
              } else {
                  return returndata;
              }
          }
      
          /**
           * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
           */
          function _revert(bytes memory returndata) 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 FailedInnerCall();
              }
          }
      }
      
      // File @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol@v5.0.2
      
      // Original license: SPDX_License_Identifier: MIT
      // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
      
      pragma solidity ^0.8.20;
      
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using Address for address;
      
          /**
           * @dev An operation with an ERC20 token failed.
           */
          error SafeERC20FailedOperation(address token);
      
          /**
           * @dev Indicates a failed `decreaseAllowance` request.
           */
          error SafeERC20FailedDecreaseAllowance(
              address spender,
              uint256 currentAllowance,
              uint256 requestedDecrease
          );
      
          /**
           * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeTransfer(
              IERC20 token,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
          }
      
          /**
           * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
           * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
           */
          function safeTransferFrom(
              IERC20 token,
              address from,
              address to,
              uint256 value
          ) internal {
              _callOptionalReturn(
                  token,
                  abi.encodeCall(token.transferFrom, (from, to, value))
              );
          }
      
          /**
           * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful.
           */
          function safeIncreaseAllowance(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              uint256 oldAllowance = token.allowance(address(this), spender);
              forceApprove(token, spender, oldAllowance + value);
          }
      
          /**
           * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
           * value, non-reverting calls are assumed to be successful.
           */
          function safeDecreaseAllowance(
              IERC20 token,
              address spender,
              uint256 requestedDecrease
          ) internal {
              unchecked {
                  uint256 currentAllowance = token.allowance(address(this), spender);
                  if (currentAllowance < requestedDecrease) {
                      revert SafeERC20FailedDecreaseAllowance(
                          spender,
                          currentAllowance,
                          requestedDecrease
                      );
                  }
                  forceApprove(token, spender, currentAllowance - requestedDecrease);
              }
          }
      
          /**
           * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
           * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
           * to be set to zero before setting it to a non-zero value, such as USDT.
           */
          function forceApprove(
              IERC20 token,
              address spender,
              uint256 value
          ) internal {
              bytes memory approvalCall = abi.encodeCall(
                  token.approve,
                  (spender, value)
              );
      
              if (!_callOptionalReturnBool(token, approvalCall)) {
                  _callOptionalReturn(
                      token,
                      abi.encodeCall(token.approve, (spender, 0))
                  );
                  _callOptionalReturn(token, approvalCall);
              }
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function _callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
              // the target address contains contract code and also asserts for success in the low-level call.
      
              bytes memory returndata = address(token).functionCall(data);
              if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
                  revert SafeERC20FailedOperation(address(token));
              }
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           *
           * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
           */
          function _callOptionalReturnBool(IERC20 token, bytes memory data)
              private
              returns (bool)
          {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
              // and not revert is the subcall reverts.
      
              (bool success, bytes memory returndata) = address(token).call(data);
              return
                  success &&
                  (returndata.length == 0 || abi.decode(returndata, (bool))) &&
                  address(token).code.length > 0;
          }
      }
      
      // File @chainlink/contracts/src/v0.8/shared/interfaces/AggregatorV3Interface.sol@v1.2.0
      
      // Original license: SPDX_License_Identifier: MIT
      pragma solidity ^0.8.0;
      
      // solhint-disable-next-line interface-starts-with-i
      interface AggregatorV3Interface {
          function decimals() external view returns (uint8);
      
          function description() external view returns (string memory);
      
          function version() external view returns (uint256);
      
          function getRoundData(uint80 _roundId)
              external
              view
              returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
              );
      
          function latestRoundData()
              external
              view
              returns (
                  uint80 roundId,
                  int256 answer,
                  uint256 startedAt,
                  uint256 updatedAt,
                  uint80 answeredInRound
              );
      }
      
      // Original license: SPDX_License_Identifier: MIT
      pragma solidity ^0.8.27;
      
      contract MutuumPresale is Ownable {
          using SafeERC20 for IERC20;
      
          uint256 public priceInUSD; // price of 1 token in USD
      
          struct BuyerDetails {
              address buyer;
              uint256 amount;
          }
      
          AggregatorV3Interface public priceFeed;
          uint8 public priceFeedDec;
      
          address public teamWallet;
      
          // address public saleToken;
          uint8 public constant saleTokenDec = 18;
      
          uint256 public totalBuyers = 0;
          address[] public buyers;
          mapping(address => bool) public isBuyer;
          mapping(address => uint256) public balanceOf;
      
          // uint256 public totalTokensForSale = 0;
          uint256 public totalTokensSold = 0;
      
          mapping(address => bool) public isPayableToken;
      
          bool public isLive = false;
          bool public isFinished = false;
      
          event BuyToken(
              address indexed buyer,
              address indexed token,
              uint256 amountIn,
              uint256 amountOut
          );
      
          event ClaimToken(address indexed buyer, uint256 amount);
      
          address public phaseChangeAuthority;
      
          constructor(address _aggregatorAddress, address _phaseChangeAuthority) Ownable(msg.sender) {
              isPayableToken[address(0)] = true;
      
              priceFeed = AggregatorV3Interface(_aggregatorAddress);
              priceFeedDec = priceFeed.decimals();
              phaseChangeAuthority = _phaseChangeAuthority;
      
              teamWallet = msg.sender;
          }
      
          modifier onlyBuyer() {
              require(isBuyer[msg.sender], "You are not a investor");
              _;
          }
      
          modifier onlyLive() {
              require(isLive, "Presale is not live");
              _;
          }
      
          modifier onlyFinished() {
              require(isFinished, "Presale is not finished");
              _;
          }
      
          // Modifier to restrict access to only authorities (owner or phaseChangeAuthority)
          modifier onlyAuthorities() {
              require(
                  msg.sender == owner() || msg.sender == phaseChangeAuthority,
                  "Caller is not an authority"
              );
              _;
          }
      
          function setPhaseChangeAuthority(address newAuthority) public onlyOwner {
              require(
                  newAuthority != address(0),
                  "New authority cannot be the zero address"
              );
              phaseChangeAuthority = newAuthority;
          }
      
          function pause() external onlyOwner {
              isLive = false;
          }
      
          function resume() external onlyOwner {
              isLive = true;
          }
      
          function _finish() internal {
              isFinished = true;
              isLive = false;
          }
      
          function finish() external onlyOwner {
              _finish();
          }
      
          function unfinish() external onlyOwner {
              isFinished = false;
              isLive = true;
          }
      
          function setSaleParams(uint256 _priceInUSD)
              external
              onlyAuthorities
          {
              require(_priceInUSD != 0, "price can not be zero");
              if (msg.sender == phaseChangeAuthority) {
                  require(_priceInUSD > priceInUSD, "Can not set less price");
              }
              priceInUSD = _priceInUSD;
              // totalTokensForSale = _totalTokensForSale;
      
              isLive = true;
          }
      
          function addPayableToken(address _token) external onlyOwner {
              isPayableToken[_token] = true;
          }
      
          function removePayableToken(address _token) external onlyOwner {
              isPayableToken[_token] = false;
          }
      
          function setTeamWallet(address _teamWallet) external onlyOwner {
              teamWallet = _teamWallet;
          }
      
          function getETHPrice() public view returns (uint256) {
              // prettier-ignore
              (
                  /* uint80 roundID */,
                  int answer,
                  /*uint startedAt*/,
                  /*uint timeStamp*/,
                  /*uint80 answeredInRound*/
              ) = priceFeed.latestRoundData();
      
              return uint256(answer) * (10**(18 - priceFeedDec));
          }
      
          function getTokenAmount(address _token, uint256 _amount)
              public
              view
              returns (uint256)
          {
              uint256 amtOut;
              if (priceInUSD == 0) return 0;
      
              if (_token != address(0)) {
                  require(isPayableToken[_token], "Token is not payable");
                  uint8 tokenDec = IERC20Metadata(_token).decimals();
      
                  amtOut =(_amount * (10**((saleTokenDec * 2) - tokenDec))) / priceInUSD;
              } else {
                  uint256 ethPrice = getETHPrice();
      
                  amtOut =
                      ((_amount * (10**(18 - saleTokenDec))) * ethPrice) /
                      priceInUSD;
              }
              return amtOut;
          }
      
          function buyToken(address _token, uint256 _amount)
              external
              payable
              onlyLive
          {
              uint256 amtOut = getTokenAmount(_token, _amount);
              require(amtOut > 0, "Invalid amount");
      
              // // transfer tokens to contract
              if (_token != address(0)) {
                  IERC20(_token).safeTransferFrom(msg.sender, teamWallet, _amount);
              } else {
                  require(msg.value == _amount, "Invalid amount");
                  payable(teamWallet).transfer(msg.value);
              }
      
              balanceOf[msg.sender] += amtOut;
              totalTokensSold += amtOut;
      
              if (!isBuyer[msg.sender]) {
                  isBuyer[msg.sender] = true;
                  buyers.push(msg.sender);
                  totalBuyers++;
              }
      
              // if (totalTokensSold >= totalTokensForSale) {
              //     _finish();
              // }
      
              emit BuyToken(msg.sender, _token, _amount, amtOut);
          }
      
          function getBuyerDetails(address _buyer)
              public
              view
              returns (BuyerDetails memory)
          {
              require(isBuyer[_buyer], "You are not a investor");
      
              return BuyerDetails(_buyer, balanceOf[_buyer]);
          }
      
          function getBuyersDetailsList(uint256 _from, uint256 _to)
              external
              view
              returns (BuyerDetails[] memory)
          {
              require(_from < _to, "Invalid range");
      
              uint256 to = _to > totalBuyers ? totalBuyers : _to;
              uint256 from = _from > totalBuyers ? totalBuyers : _from;
      
              BuyerDetails[] memory buyersAmt = new BuyerDetails[](to - from);
      
              for (uint256 i = from; i < to; i += 1) {
                  buyersAmt[i] = getBuyerDetails(buyers[i]);
              }
      
              return buyersAmt;
          }
      
          function emergencyWithdrawToken(address _token) external onlyOwner {
              IERC20(_token).safeTransfer(
                  msg.sender,
                  IERC20(_token).balanceOf(address(this))
              );
          }
      
          function emergencyWithdrawETH() external onlyOwner {
              payable(msg.sender).transfer(address(this).balance);
          }
      }

      File 2 of 2: EACAggregatorProxy
      pragma solidity 0.6.6;
      
      
      /**
       * @title The Owned contract
       * @notice A contract with helpers for basic contract ownership.
       */
      contract Owned {
      
        address payable public owner;
        address private pendingOwner;
      
        event OwnershipTransferRequested(
          address indexed from,
          address indexed to
        );
        event OwnershipTransferred(
          address indexed from,
          address indexed to
        );
      
        constructor() public {
          owner = msg.sender;
        }
      
        /**
         * @dev Allows an owner to begin transferring ownership to a new address,
         * pending.
         */
        function transferOwnership(address _to)
          external
          onlyOwner()
        {
          pendingOwner = _to;
      
          emit OwnershipTransferRequested(owner, _to);
        }
      
        /**
         * @dev Allows an ownership transfer to be completed by the recipient.
         */
        function acceptOwnership()
          external
        {
          require(msg.sender == pendingOwner, "Must be proposed owner");
      
          address oldOwner = owner;
          owner = msg.sender;
          pendingOwner = address(0);
      
          emit OwnershipTransferred(oldOwner, msg.sender);
        }
      
        /**
         * @dev Reverts if called by anyone other than the contract owner.
         */
        modifier onlyOwner() {
          require(msg.sender == owner, "Only callable by owner");
          _;
        }
      
      }
      
      interface AggregatorInterface {
        function latestAnswer() external view returns (int256);
        function latestTimestamp() external view returns (uint256);
        function latestRound() external view returns (uint256);
        function getAnswer(uint256 roundId) external view returns (int256);
        function getTimestamp(uint256 roundId) external view returns (uint256);
      
        event AnswerUpdated(int256 indexed current, uint256 indexed roundId, uint256 updatedAt);
        event NewRound(uint256 indexed roundId, address indexed startedBy, uint256 startedAt);
      }
      
      interface AggregatorV3Interface {
      
        function decimals() external view returns (uint8);
        function description() external view returns (string memory);
        function version() external view returns (uint256);
      
        // getRoundData and latestRoundData should both raise "No data present"
        // if they do not have data to report, instead of returning unset values
        // which could be misinterpreted as actual reported values.
        function getRoundData(uint80 _roundId)
          external
          view
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          );
        function latestRoundData()
          external
          view
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          );
      
      }
      
      interface AggregatorV2V3Interface is AggregatorInterface, AggregatorV3Interface
      {
      }
      
      /**
       * @title A trusted proxy for updating where current answers are read from
       * @notice This contract provides a consistent address for the
       * CurrentAnwerInterface but delegates where it reads from to the owner, who is
       * trusted to update it.
       */
      contract AggregatorProxy is AggregatorV2V3Interface, Owned {
      
        struct Phase {
          uint16 id;
          AggregatorV2V3Interface aggregator;
        }
        Phase private currentPhase;
        AggregatorV2V3Interface public proposedAggregator;
        mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators;
      
        uint256 constant private PHASE_OFFSET = 64;
        uint256 constant private PHASE_SIZE = 16;
        uint256 constant private MAX_ID = 2**(PHASE_OFFSET+PHASE_SIZE) - 1;
      
        constructor(address _aggregator) public Owned() {
          setAggregator(_aggregator);
        }
      
        /**
         * @notice Reads the current answer from aggregator delegated to.
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestAnswer()
          public
          view
          virtual
          override
          returns (int256 answer)
        {
          return currentPhase.aggregator.latestAnswer();
        }
      
        /**
         * @notice Reads the last updated height from aggregator delegated to.
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestTimestamp()
          public
          view
          virtual
          override
          returns (uint256 updatedAt)
        {
          return currentPhase.aggregator.latestTimestamp();
        }
      
        /**
         * @notice get past rounds answers
         * @param _roundId the answer number to retrieve the answer for
         *
         * @dev #[deprecated] Use getRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended getRoundData
         * instead which includes better verification information.
         */
        function getAnswer(uint256 _roundId)
          public
          view
          virtual
          override
          returns (int256 answer)
        {
          if (_roundId > MAX_ID) return 0;
      
          (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
          AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
          if (address(aggregator) == address(0)) return 0;
      
          return aggregator.getAnswer(aggregatorRoundId);
        }
      
        /**
         * @notice get block timestamp when an answer was last updated
         * @param _roundId the answer number to retrieve the updated timestamp for
         *
         * @dev #[deprecated] Use getRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended getRoundData
         * instead which includes better verification information.
         */
        function getTimestamp(uint256 _roundId)
          public
          view
          virtual
          override
          returns (uint256 updatedAt)
        {
          if (_roundId > MAX_ID) return 0;
      
          (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
          AggregatorV2V3Interface aggregator = phaseAggregators[phaseId];
          if (address(aggregator) == address(0)) return 0;
      
          return aggregator.getTimestamp(aggregatorRoundId);
        }
      
        /**
         * @notice get the latest completed round where the answer was updated. This
         * ID includes the proxy's phase, to make sure round IDs increase even when
         * switching to a newly deployed aggregator.
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestRound()
          public
          view
          virtual
          override
          returns (uint256 roundId)
        {
          Phase memory phase = currentPhase; // cache storage reads
          return addPhase(phase.id, uint64(phase.aggregator.latestRound()));
        }
      
        /**
         * @notice get data about a round. Consumers are encouraged to check
         * that they're receiving fresh data by inspecting the updatedAt and
         * answeredInRound return values.
         * Note that different underlying implementations of AggregatorV3Interface
         * have slightly different semantics for some of the return values. Consumers
         * should determine what implementations they expect to receive
         * data from and validate that they can properly handle return data from all
         * of them.
         * @param _roundId the requested round ID as presented through the proxy, this
         * is made up of the aggregator's round ID with the phase ID encoded in the
         * two highest order bytes
         * @return roundId is the round ID from the aggregator for which the data was
         * retrieved combined with an phase to ensure that round IDs get larger as
         * time moves forward.
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @dev Note that answer and updatedAt may change between queries.
         */
        function getRoundData(uint80 _roundId)
          public
          view
          virtual
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId);
      
          (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 ansIn
          ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId);
      
          return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, phaseId);
        }
      
        /**
         * @notice get data about the latest round. Consumers are encouraged to check
         * that they're receiving fresh data by inspecting the updatedAt and
         * answeredInRound return values.
         * Note that different underlying implementations of AggregatorV3Interface
         * have slightly different semantics for some of the return values. Consumers
         * should determine what implementations they expect to receive
         * data from and validate that they can properly handle return data from all
         * of them.
         * @return roundId is the round ID from the aggregator for which the data was
         * retrieved combined with an phase to ensure that round IDs get larger as
         * time moves forward.
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @dev Note that answer and updatedAt may change between queries.
         */
        function latestRoundData()
          public
          view
          virtual
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          Phase memory current = currentPhase; // cache storage reads
      
          (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 ansIn
          ) = current.aggregator.latestRoundData();
      
          return addPhaseIds(roundId, answer, startedAt, updatedAt, ansIn, current.id);
        }
      
        /**
         * @notice Used if an aggregator contract has been proposed.
         * @param _roundId the round ID to retrieve the round data for
         * @return roundId is the round ID for which data was retrieved
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
        */
        function proposedGetRoundData(uint80 _roundId)
          public
          view
          virtual
          hasProposal()
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return proposedAggregator.getRoundData(_roundId);
        }
      
        /**
         * @notice Used if an aggregator contract has been proposed.
         * @return roundId is the round ID for which data was retrieved
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
        */
        function proposedLatestRoundData()
          public
          view
          virtual
          hasProposal()
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return proposedAggregator.latestRoundData();
        }
      
        /**
         * @notice returns the current phase's aggregator address.
         */
        function aggregator()
          external
          view
          returns (address)
        {
          return address(currentPhase.aggregator);
        }
      
        /**
         * @notice returns the current phase's ID.
         */
        function phaseId()
          external
          view
          returns (uint16)
        {
          return currentPhase.id;
        }
      
        /**
         * @notice represents the number of decimals the aggregator responses represent.
         */
        function decimals()
          external
          view
          override
          returns (uint8)
        {
          return currentPhase.aggregator.decimals();
        }
      
        /**
         * @notice the version number representing the type of aggregator the proxy
         * points to.
         */
        function version()
          external
          view
          override
          returns (uint256)
        {
          return currentPhase.aggregator.version();
        }
      
        /**
         * @notice returns the description of the aggregator the proxy points to.
         */
        function description()
          external
          view
          override
          returns (string memory)
        {
          return currentPhase.aggregator.description();
        }
      
        /**
         * @notice Allows the owner to propose a new address for the aggregator
         * @param _aggregator The new address for the aggregator contract
         */
        function proposeAggregator(address _aggregator)
          external
          onlyOwner()
        {
          proposedAggregator = AggregatorV2V3Interface(_aggregator);
        }
      
        /**
         * @notice Allows the owner to confirm and change the address
         * to the proposed aggregator
         * @dev Reverts if the given address doesn't match what was previously
         * proposed
         * @param _aggregator The new address for the aggregator contract
         */
        function confirmAggregator(address _aggregator)
          external
          onlyOwner()
        {
          require(_aggregator == address(proposedAggregator), "Invalid proposed aggregator");
          delete proposedAggregator;
          setAggregator(_aggregator);
        }
      
      
        /*
         * Internal
         */
      
        function setAggregator(address _aggregator)
          internal
        {
          uint16 id = currentPhase.id + 1;
          currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator));
          phaseAggregators[id] = AggregatorV2V3Interface(_aggregator);
        }
      
        function addPhase(
          uint16 _phase,
          uint64 _originalId
        )
          internal
          view
          returns (uint80)
        {
          return uint80(uint256(_phase) << PHASE_OFFSET | _originalId);
        }
      
        function parseIds(
          uint256 _roundId
        )
          internal
          view
          returns (uint16, uint64)
        {
          uint16 phaseId = uint16(_roundId >> PHASE_OFFSET);
          uint64 aggregatorRoundId = uint64(_roundId);
      
          return (phaseId, aggregatorRoundId);
        }
      
        function addPhaseIds(
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound,
            uint16 phaseId
        )
          internal
          view
          returns (uint80, int256, uint256, uint256, uint80)
        {
          return (
            addPhase(phaseId, uint64(roundId)),
            answer,
            startedAt,
            updatedAt,
            addPhase(phaseId, uint64(answeredInRound))
          );
        }
      
        /*
         * Modifiers
         */
      
        modifier hasProposal() {
          require(address(proposedAggregator) != address(0), "No proposed aggregator present");
          _;
        }
      
      }
      
      interface AccessControllerInterface {
        function hasAccess(address user, bytes calldata data) external view returns (bool);
      }
      
      /**
       * @title External Access Controlled Aggregator Proxy
       * @notice A trusted proxy for updating where current answers are read from
       * @notice This contract provides a consistent address for the
       * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is
       * trusted to update it.
       * @notice Only access enabled addresses are allowed to access getters for
       * aggregated answers and round information.
       */
      contract EACAggregatorProxy is AggregatorProxy {
      
        AccessControllerInterface public accessController;
      
        constructor(
          address _aggregator,
          address _accessController
        )
          public
          AggregatorProxy(_aggregator)
        {
          setController(_accessController);
        }
      
        /**
         * @notice Allows the owner to update the accessController contract address.
         * @param _accessController The new address for the accessController contract
         */
        function setController(address _accessController)
          public
          onlyOwner()
        {
          accessController = AccessControllerInterface(_accessController);
        }
      
        /**
         * @notice Reads the current answer from aggregator delegated to.
         * @dev overridden function to add the checkAccess() modifier
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestAnswer()
          public
          view
          override
          checkAccess()
          returns (int256)
        {
          return super.latestAnswer();
        }
      
        /**
         * @notice get the latest completed round where the answer was updated. This
         * ID includes the proxy's phase, to make sure round IDs increase even when
         * switching to a newly deployed aggregator.
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestTimestamp()
          public
          view
          override
          checkAccess()
          returns (uint256)
        {
          return super.latestTimestamp();
        }
      
        /**
         * @notice get past rounds answers
         * @param _roundId the answer number to retrieve the answer for
         * @dev overridden function to add the checkAccess() modifier
         *
         * @dev #[deprecated] Use getRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended getRoundData
         * instead which includes better verification information.
         */
        function getAnswer(uint256 _roundId)
          public
          view
          override
          checkAccess()
          returns (int256)
        {
          return super.getAnswer(_roundId);
        }
      
        /**
         * @notice get block timestamp when an answer was last updated
         * @param _roundId the answer number to retrieve the updated timestamp for
         * @dev overridden function to add the checkAccess() modifier
         *
         * @dev #[deprecated] Use getRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended getRoundData
         * instead which includes better verification information.
         */
        function getTimestamp(uint256 _roundId)
          public
          view
          override
          checkAccess()
          returns (uint256)
        {
          return super.getTimestamp(_roundId);
        }
      
        /**
         * @notice get the latest completed round where the answer was updated
         * @dev overridden function to add the checkAccess() modifier
         *
         * @dev #[deprecated] Use latestRoundData instead. This does not error if no
         * answer has been reached, it will simply return 0. Either wait to point to
         * an already answered Aggregator or use the recommended latestRoundData
         * instead which includes better verification information.
         */
        function latestRound()
          public
          view
          override
          checkAccess()
          returns (uint256)
        {
          return super.latestRound();
        }
      
        /**
         * @notice get data about a round. Consumers are encouraged to check
         * that they're receiving fresh data by inspecting the updatedAt and
         * answeredInRound return values.
         * Note that different underlying implementations of AggregatorV3Interface
         * have slightly different semantics for some of the return values. Consumers
         * should determine what implementations they expect to receive
         * data from and validate that they can properly handle return data from all
         * of them.
         * @param _roundId the round ID to retrieve the round data for
         * @return roundId is the round ID from the aggregator for which the data was
         * retrieved combined with a phase to ensure that round IDs get larger as
         * time moves forward.
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @dev Note that answer and updatedAt may change between queries.
         */
        function getRoundData(uint80 _roundId)
          public
          view
          checkAccess()
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return super.getRoundData(_roundId);
        }
      
        /**
         * @notice get data about the latest round. Consumers are encouraged to check
         * that they're receiving fresh data by inspecting the updatedAt and
         * answeredInRound return values.
         * Note that different underlying implementations of AggregatorV3Interface
         * have slightly different semantics for some of the return values. Consumers
         * should determine what implementations they expect to receive
         * data from and validate that they can properly handle return data from all
         * of them.
         * @return roundId is the round ID from the aggregator for which the data was
         * retrieved combined with a phase to ensure that round IDs get larger as
         * time moves forward.
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @dev Note that answer and updatedAt may change between queries.
         */
        function latestRoundData()
          public
          view
          checkAccess()
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return super.latestRoundData();
        }
      
        /**
         * @notice Used if an aggregator contract has been proposed.
         * @param _roundId the round ID to retrieve the round data for
         * @return roundId is the round ID for which data was retrieved
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
        */
        function proposedGetRoundData(uint80 _roundId)
          public
          view
          checkAccess()
          hasProposal()
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return super.proposedGetRoundData(_roundId);
        }
      
        /**
         * @notice Used if an aggregator contract has been proposed.
         * @return roundId is the round ID for which data was retrieved
         * @return answer is the answer for the given round
         * @return startedAt is the timestamp when the round was started.
         * (Only some AggregatorV3Interface implementations return meaningful values)
         * @return updatedAt is the timestamp when the round last was updated (i.e.
         * answer was last computed)
         * @return answeredInRound is the round ID of the round in which the answer
         * was computed.
        */
        function proposedLatestRoundData()
          public
          view
          checkAccess()
          hasProposal()
          override
          returns (
            uint80 roundId,
            int256 answer,
            uint256 startedAt,
            uint256 updatedAt,
            uint80 answeredInRound
          )
        {
          return super.proposedLatestRoundData();
        }
      
        /**
         * @dev reverts if the caller does not have access by the accessController
         * contract or is the contract itself.
         */
        modifier checkAccess() {
          AccessControllerInterface ac = accessController;
          require(address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), "No access");
          _;
        }
      }