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
}
}}
Submitted on: 2025-09-27 11:50:32
Comments
Log in to comment.
No comments yet.