编译器
0.8.19+commit.7dd6d404
文件 1 的 16:AccessControl.sol
文件 2 的 16:AccessControlEnumerable.sol
文件 7 的 16:EntropyOracle.sol
pragma solidity >=0.8.19;
import {IEntropyOracle, IEntropyOracleEvents} from "./IEntropyOracle.sol";
import {AccessControlEnumerable} from "ethier/utils/AccessControlEnumerable.sol";
import {ECDSA} from "openzeppelin-contracts/utils/cryptography/ECDSA.sol";
function blockDigest(uint256 blockNumber) view returns (bytes32) {
return ECDSA.toEthSignedMessageHash(abi.encode(blockNumber, block.chainid));
}
contract EntropyOracle is IEntropyOracle, AccessControlEnumerable {
error NonHistoricalBlock(uint256 blockNumber);
error InvalidEntropySignature();
error EntropyAlreadyProvided(uint256 blockNumber);
bytes32 public constant ENTROPY_REQUESTER_ROLE = keccak256("ENTROPY_REQUESTER_ROLE");
address public signer;
mapping(uint256 => bytes32) private _blockEntropy;
constructor(address admin, address steerer) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(DEFAULT_STEERING_ROLE, steerer);
_setRoleAdmin(ENTROPY_REQUESTER_ROLE, DEFAULT_STEERING_ROLE);
}
function requestEntropy() public {
requestEntropy(block.number);
}
function requestEntropy(uint256 blockNumber) public onlyRole(ENTROPY_REQUESTER_ROLE) {
if (_blockEntropy[blockNumber] == 0) {
emit EntropyRequested(blockNumber);
_blockEntropy[blockNumber] = bytes32(uint256(1));
}
}
struct EntropyFulfilment {
uint256 blockNumber;
bytes signature;
}
function provideEntropy(EntropyFulfilment calldata entropy) external virtual {
_provideEntropy(entropy);
}
function _provideEntropy(EntropyFulfilment calldata entropy) internal returns (bytes32) {
uint256 blockNumber = entropy.blockNumber;
if (blockNumber >= block.number) {
revert NonHistoricalBlock(blockNumber);
}
if (ECDSA.recover(blockDigest(blockNumber), entropy.signature) != signer) {
revert InvalidEntropySignature();
}
if (blockEntropy(blockNumber) != 0) {
revert EntropyAlreadyProvided(blockNumber);
}
bytes32 hashed = keccak256(entropy.signature);
_blockEntropy[blockNumber] = hashed;
emit EntropyProvided(blockNumber, hashed);
return hashed;
}
function provideEntropy(EntropyFulfilment[] calldata entropy) external virtual {
for (uint256 i = 0; i < entropy.length; ++i) {
_provideEntropy(entropy[i]);
}
}
function blockEntropy(uint256 blockNumber) public view virtual returns (bytes32) {
bytes32 entropy = _blockEntropy[blockNumber];
if (uint256(entropy) > 1) {
return entropy;
}
return 0;
}
function setSigner(address signer_) external onlyRole(DEFAULT_STEERING_ROLE) {
signer = signer_;
}
}
文件 8 的 16:EntropyOracleV2.sol
pragma solidity >=0.8.19;
import {EntropyOracle} from "./EntropyOracle.sol";
import {IEntropyOracle} from "./IEntropyOracle.sol";
import {IEntropyOracleV2, IEntropyOracleV2Events, IEntropyConsumer} from "./IEntropyOracleV2.sol";
import {Address} from "openzeppelin-contracts/utils/Address.sol";
import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
contract EntropyOracleV2 is EntropyOracle, IEntropyOracleV2, IEntropyOracleV2Events {
using Address for address;
using EnumerableSet for EnumerableSet.Bytes32Set;
error EntropyNotAvailable(uint256 blockNumber);
error CallbackNotRegistered(address consumer, uint96 callbackId, uint256 blockNumber);
mapping(uint256 => EnumerableSet.Bytes32Set) private _callbacks;
IEntropyOracle public v1Override;
constructor(address admin, address steerer) EntropyOracle(admin, steerer) {}
function requestEntropyWithCallback() external {
requestEntropyWithCallback(block.number, 0);
}
function requestEntropyWithCallback(uint256 blockNumber, uint96 callbackId) public {
bytes32 entropy = blockEntropy(blockNumber);
if (uint256(entropy) != 0) {
IEntropyConsumer(msg.sender).consumeEntropy(blockNumber, callbackId, entropy);
} else {
EntropyOracle.requestEntropy(blockNumber);
_callbacks[blockNumber].add(_packCallback(msg.sender, callbackId));
}
}
function numCallbacks(uint256 blockNumber) external view returns (uint256) {
return _callbacks[blockNumber].length();
}
function callback(uint256 blockNumber, uint256 i) external view returns (address, uint96) {
return _unpackCallback(_callbacks[blockNumber].at(i));
}
function isCallbackRegistered(address consumer, uint96 callbackId, uint256 blockNumber)
external
view
returns (bool)
{
return _callbacks[blockNumber].contains(_packCallback(consumer, callbackId));
}
function _packCallback(address addr, uint96 id) internal pure returns (bytes32) {
return bytes32(uint256(uint160(addr)) << 96 | (id & type(uint96).max));
}
function _unpackCallback(bytes32 packed) internal pure returns (address consumer, uint96 id) {
consumer = address(uint160(uint256(packed) >> 96));
id = uint96(uint256(packed));
}
function provideEntropy(EntropyFulfilment calldata entropy, uint256 maxCallbacks) public virtual {
bytes32 hashed = EntropyOracle._provideEntropy(entropy);
_triggerCallbacks(entropy.blockNumber, hashed, maxCallbacks);
}
function provideEntropy(EntropyFulfilment calldata entropy) external virtual override {
provideEntropy(entropy, type(uint256).max);
}
function provideEntropy(EntropyFulfilment[] calldata entropy) external virtual override {
for (uint256 i = 0; i < entropy.length; ++i) {
provideEntropy(entropy[i], type(uint256).max);
}
}
function removeCallback(address consumer, uint96 callbackId, uint256 blockNumber)
external
onlyRole(DEFAULT_STEERING_ROLE)
{
EnumerableSet.Bytes32Set storage callbacks = _callbacks[blockNumber];
bytes32 packed = _packCallback(consumer, callbackId);
if (!callbacks.contains(packed)) {
revert CallbackNotRegistered(consumer, callbackId, blockNumber);
}
_callbacks[blockNumber].remove(packed);
}
function triggerCallbacks(uint256 blockNumber, uint256 max) external {
bytes32 entropy = blockEntropy(blockNumber);
if (uint256(entropy) == 0) revert EntropyNotAvailable(blockNumber);
_triggerCallbacks(blockNumber, entropy, max);
}
function _triggerCallbacks(uint256 blockNumber, bytes32 entropy, uint256 max) internal {
EnumerableSet.Bytes32Set storage callbacks = _callbacks[blockNumber];
uint256 n = callbacks.length();
if (n > max) {
n = max;
}
bytes32[] memory successful = new bytes32[](n);
uint256 cursor;
for (uint256 i = 0; i < n; ++i) {
bytes32 packed = callbacks.at(i);
(address consumer, uint96 id) = _unpackCallback(packed);
bytes memory data =
abi.encodeWithSelector(IEntropyConsumer.consumeEntropy.selector, blockNumber, id, entropy);
(bool ok, bytes memory reason) = consumer.call(data);
if (ok) {
successful[cursor++] = packed;
} else {
emit CallbackFailed(blockNumber, consumer, reason);
}
}
while (cursor > 0) {
callbacks.remove(successful[--cursor]);
}
}
function blockEntropy(uint256 blockNumber)
public
view
virtual
override(EntropyOracle, IEntropyOracle)
returns (bytes32)
{
if (address(v1Override) != address(0)) {
bytes32 entropy = v1Override.blockEntropy(blockNumber);
if (uint256(entropy) != 0) {
return entropy;
}
}
return EntropyOracle.blockEntropy(blockNumber);
}
function setOverride(IEntropyOracle v1) external onlyRole(DEFAULT_STEERING_ROLE) {
v1Override = v1;
}
}
文件 9 的 16:EnumerableSet.sol
文件 10 的 16:IAccessControl.sol
文件 11 的 16:IAccessControlEnumerable.sol
文件 13 的 16:IEntropyOracle.sol
pragma solidity ^0.8.0;
interface IEntropyOracleEvents {
event EntropyRequested(uint256 indexed blockNumber);
event EntropyProvided(uint256 indexed blockNumber, bytes32 entropy);
}
interface IEntropyOracle is IEntropyOracleEvents {
function requestEntropy() external;
function requestEntropy(uint256 blockNumber) external;
function blockEntropy(uint256) external view returns (bytes32);
}
文件 14 的 16:IEntropyOracleV2.sol
pragma solidity ^0.8.0;
import {IEntropyOracle} from "./IEntropyOracle.sol";
interface IEntropyConsumer {
function consumeEntropy(uint256 blockNumber, uint96 callbackId, bytes32 entropy) external;
}
interface IEntropyOracleV2Events {
event CallbackFailed(uint256 indexed blockNumber, address indexed consumer, bytes reason);
}
interface IEntropyOracleV2 is IEntropyOracle {
function requestEntropyWithCallback() external;
function requestEntropyWithCallback(uint256 blockNumber, uint96 callbackId) external;
}
{
"compilationTarget": {
"EntropyOracleV2.sol": "EntropyOracleV2"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 99999
},
"remappings": [
":@divergencetech/ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-54-0/",
":@openzeppelin/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/",
":ds-test/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ds-test_013e6c64/src/",
":ds-test_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ds-test_013e6c64/",
":ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-54-0/contracts/",
":ethier_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-54-0/",
":forge-std/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/forge-std_1-4-0/src/",
":openzeppelin-contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/contracts/",
":openzeppelin-contracts/contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/contracts/",
":openzeppelin-contracts_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/",
":proof/constants/=/home/dave/proof/proof-seller/contracts/constants/src/"
]
}
[{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"steerer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"consumer","type":"address"},{"internalType":"uint96","name":"callbackId","type":"uint96"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"CallbackNotRegistered","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"EntropyAlreadyProvided","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"EntropyNotAvailable","type":"error"},{"inputs":[],"name":"InvalidEntropySignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"NonHistoricalBlock","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockNumber","type":"uint256"},{"indexed":true,"internalType":"address","name":"consumer","type":"address"},{"indexed":false,"internalType":"bytes","name":"reason","type":"bytes"}],"name":"CallbackFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockNumber","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"entropy","type":"bytes32"}],"name":"EntropyProvided","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"EntropyRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_STEERING_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ENTROPY_REQUESTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"blockEntropy","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"i","type":"uint256"}],"name":"callback","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"consumer","type":"address"},{"internalType":"uint96","name":"callbackId","type":"uint96"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"isCallbackRegistered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"numCallbacks","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct EntropyOracle.EntropyFulfilment","name":"entropy","type":"tuple"},{"internalType":"uint256","name":"maxCallbacks","type":"uint256"}],"name":"provideEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct EntropyOracle.EntropyFulfilment[]","name":"entropy","type":"tuple[]"}],"name":"provideEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct EntropyOracle.EntropyFulfilment","name":"entropy","type":"tuple"}],"name":"provideEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"consumer","type":"address"},{"internalType":"uint96","name":"callbackId","type":"uint96"},{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"removeCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"requestEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestEntropy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint96","name":"callbackId","type":"uint96"}],"name":"requestEntropyWithCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"requestEntropyWithCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IEntropyOracle","name":"v1","type":"address"}],"name":"setOverride","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"uint256","name":"max","type":"uint256"}],"name":"triggerCallbacks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"v1Override","outputs":[{"internalType":"contract IEntropyOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"}]