Easyntropy

Description:

Smart contract deployed on Ethereum with Factory, Oracle features.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/contracts/Easyntropy/Easyntropy.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "./IEasyntropy.sol";
import "./IEasyntropyConsumer.sol";

contract Easyntropy is IEasyntropy {
  uint256 public constant RELEASE_FUNDS_AFTER_BLOCKS = 50000; // ~1 week

  address public owner;
  mapping(address executor => bool allowed) public executors;
  uint64 public lastRequestId = 0;

  uint256 public baseFee;
  mapping(address requester => uint256 customFee) public customFees;
  mapping(address requester => uint256 balance) public balances;
  mapping(address requester => uint256 reservedFund) public reservedFunds;
  mapping(address requester => uint256 lastResponseBlockNumber) public lastResponses;
  mapping(uint64 requestId => uint256 fee) public requestFees;

  event RequestSubmitted(uint64 indexed requestId, address indexed requester, bytes4 callbackSelector);
  event DepositReceived(address indexed account, uint256 indexed value);
  event FundsWithdrawn(address indexed account, uint256 indexed value);
  event OwnerSet(address indexed account);
  event ExecutorAdded(address indexed account);
  event ExecutorRemoved(address indexed account);
  event BaseFeeSet(uint256 indexed value);
  event CustomFeeSet(address indexed account, uint256 indexed value);
  event CustomFeeRemoved(address indexed account);
  error PermissionDenied();
  error NotEnoughEth();

  modifier onlyOwner() {
    if (msg.sender != owner) revert PermissionDenied();
    _;
  }

  modifier onlyExecutor() {
    if (!executors[msg.sender]) revert PermissionDenied();
    _;
  }

  constructor(address executor, uint256 _baseFee) {
    executors[executor] = true;
    baseFee = _baseFee;
    owner = msg.sender;
  }

  // solhint-disable-next-line gas-named-return-values
  function fee() public view returns (uint256) {
    if (customFees[msg.sender] == 0) return baseFee;
    if (customFees[msg.sender] == type(uint256).max) return 0;
    return customFees[msg.sender];
  }

  //
  // RNG requests
  function requestWithCallback() public payable returns (uint64 requestId) {
    requestId = requestWithCallback(
      0x774358d3 // bytes4(keccak256("easyntropyFulfill(uint64,bytes32)"));
    );
  }

  function requestWithCallback(bytes4 callbackSelector) public payable returns (uint64 requestId) {
    balances[msg.sender] += msg.value;
    uint256 requestFee = fee();
    if (balances[msg.sender] < requestFee) revert NotEnoughEth();

    requestId = ++lastRequestId;
    reservedFunds[msg.sender] += requestFee;
    requestFees[requestId] = requestFee;

    //
    // To allow withdrawal of reserved funds (after the RELEASE_FUNDS_AFTER_BLOCKS period)
    // in case of a response failure on a first request for a given address. We artificially
    // set lastResponses to current block number. For details, examine reservedFundsWaitingPeriod()
    if (lastResponses[msg.sender] == 0) {
      lastResponses[msg.sender] = block.number;
    }

    emit RequestSubmitted(requestId, msg.sender, callbackSelector);
  }

  //
  // rng responses
  function responseWithCallback(uint64 requestId, address requester, bytes4 callbackSelector, bytes32 seed) public onlyExecutor {
    uint256 requestFee = requestFees[requestId];
    if (balances[requester] < requestFee) revert NotEnoughEth();

    balances[requester] -= requestFee;
    reservedFunds[requester] -= requestFee;
    lastResponses[requester] = block.number;
    delete requestFees[requestId];

    payable(msg.sender).transfer(requestFee);

    IEasyntropyConsumer(requester)._easyntropyFulfill(requestId, callbackSelector, seed);
  }

  //
  // contract management
  function setOwner(address _owner) public onlyOwner {
    owner = _owner;
    emit OwnerSet(_owner);
  }

  function addExecutor(address executor) public onlyOwner {
    executors[executor] = true;
    emit ExecutorAdded(executor);
  }

  function removeExecutor(address executor) public onlyOwner {
    delete executors[executor];
    emit ExecutorRemoved(executor);
  }

  function setBaseFee(uint256 _baseFee) public onlyOwner {
    baseFee = _baseFee;
    emit BaseFeeSet(_baseFee);
  }

  function setCustomFee(address addr, uint256 _customFee) public onlyOwner {
    customFees[addr] = _customFee;
    emit CustomFeeSet(addr, _customFee);
  }

  function removeCustomFee(address addr) public onlyOwner {
    delete customFees[addr];
    emit CustomFeeRemoved(addr);
  }

  //
  // users money management
  function reservedFundsWaitingPeriod(address addr) public view returns (uint256 result) {
    uint256 releaseBlock = lastResponses[addr] + RELEASE_FUNDS_AFTER_BLOCKS;
    return block.number > releaseBlock ? 0 : (releaseBlock - block.number);
  }

  function withdraw(uint256 amount) public {
    // Release reserved funds after RELEASE_FUNDS_AFTER_BLOCKS of oracle inactivity
    // to allow contracts to withdraw all funds in case of a major oracle failure.
    if (reservedFundsWaitingPeriod(msg.sender) == 0) {
      reservedFunds[msg.sender] = 0;
    }

    if (amount > balances[msg.sender] - reservedFunds[msg.sender]) revert NotEnoughEth();

    balances[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
    emit FundsWithdrawn(msg.sender, amount);
  }

  function deposit() public payable {
    balances[msg.sender] += msg.value;
    emit DepositReceived(msg.sender, msg.value);
  }

  receive() external payable {
    deposit();
  }
}
"
    },
    "src/contracts/Easyntropy/IEasyntropy.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

interface IEasyntropy {
  function fee() external view returns (uint256 fee);
  function balances(address addr) external view returns (uint256 balance);
  function deposit() external payable;
  function withdraw(uint256 amount) external;
  function requestWithCallback() external payable returns (uint64 requestId);
  function requestWithCallback(bytes4 callbackSelector) external payable returns (uint64 requestId);
}
"
    },
    "src/contracts/Easyntropy/IEasyntropyConsumer.sol": {
      "content": "// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import "./IEasyntropy.sol";

interface IEasyntropyConsumer {
  function easyntropy() external view returns (IEasyntropy entropy);
  function easyntropyFee() external view returns (uint256 fee);
  function easyntropyCurrentBalance() external view returns (uint256 balance);
  function easyntropyDeposit() external payable;
  function _easyntropyFulfill(uint64 requestId, bytes4 callbackSelector, bytes32 seed) external;
}
"
    }
  },
  "settings": {
    "remappings": [
      "forge-std/=src/libs/forge-std/src/",
      "pyth/=src/libs/pyth-crosschain/target_chains/ethereum/entropy_sdk/solidity/",
      "createx/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/createx/src/",
      "ds-test/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/createx/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/openzeppelin-contracts/lib/erc4626-tests/",
      "halmos-cheatcodes/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
      "openzeppelin-contracts-upgradeable/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/openzeppelin-contracts/",
      "openzeppelin-foundry-upgrades/=src/libs/pyth-crosschain/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades/src/",
      "pyth-crosschain/=src/libs/pyth-crosschain/",
      "solady/=src/libs/pyth-crosschain/lazer/contracts/evm/lib/createx/lib/solady/",
      "solidity-stringutils/=src/libs/pyth-crosschain/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
    ],
    "optimizer": {
      "enabled": false,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "prague",
    "viaIR": false
  }
}}

Tags:
Factory, Oracle|addr:0x2a9adbbad92f37670e8e98fe86a8b2fb07681690|verified:true|block:23452049|tx:0xebd4594ca02831325f1868ed7bde81e04d253b31d76f85da26e4166ad2124dac|first_check:1758966631

Submitted on: 2025-09-27 11:50:32

Comments

Log in to comment.

No comments yet.