编译器
0.8.19+commit.7dd6d404
文件 1 的 23:AccessControl.sol
文件 2 的 23:AccessControlEnumerable.sol
文件 3 的 23:CallbackerWithAccessControl.sol
文件 6 的 23:EnumerableSet.sol
文件 7 的 23:IAccessControl.sol
文件 8 的 23:IAccessControlEnumerable.sol
文件 11 的 23:IEntropyOracle.sol
文件 14 的 23:MythicEggSampler.sol
pragma solidity ^0.8.15;
import {IEntropyOracle} from "proof/entropy/IEntropyOracle.sol";
import {MythicsEggErrors} from "./MythicsEggErrors.sol";
import {
StochasticSampler, StochasticSamplerWithCDFStorage, StochasticSamplerWithOracle
} from "./StochasticSampling.sol";
abstract contract MythicEggSampler is StochasticSamplerWithCDFStorage, StochasticSamplerWithOracle, MythicsEggErrors {
enum EggType {
Stone,
Runic,
Legendary
}
uint8 public constant NUM_EGG_TYPES = 3;
uint8 private constant _EGG_TYPE_TRAIT_ID = 0;
struct SamplingParams {
uint64 revealBlockNumber;
uint16 distributionVersion;
uint128 mixHash;
}
mapping(uint256 => SamplingParams) private _samplingParams;
function _numPerTrait() private pure returns (uint256[] memory) {
uint256[] memory numPerTrait = new uint256[](1);
numPerTrait[_EGG_TYPE_TRAIT_ID] = NUM_EGG_TYPES;
return numPerTrait;
}
constructor(IEntropyOracle oracle)
StochasticSamplerWithCDFStorage(_numPerTrait())
StochasticSamplerWithOracle(oracle)
{}
function samplingParams(uint256 tokenId) public view returns (SamplingParams memory) {
if (!_exists(tokenId)) {
revert NonexistentEgg(tokenId);
}
return _samplingParams[tokenId];
}
function _distributionVersion(uint256 tokenId, uint256 traitId) internal view virtual override returns (uint256) {
assert(traitId == _EGG_TYPE_TRAIT_ID);
return _samplingParams[tokenId].distributionVersion;
}
function _revealBlockNumber(uint256 tokenId) internal view virtual override returns (uint256) {
return _samplingParams[tokenId].revealBlockNumber;
}
function _registerForSampling(uint256 tokenId) internal {
uint256 revealBlockNumber = block.number;
_samplingParams[tokenId] = SamplingParams({
revealBlockNumber: uint64(revealBlockNumber),
distributionVersion: uint16(_latestDistributionVersion(_EGG_TYPE_TRAIT_ID)),
mixHash: uint128(uint256(keccak256(abi.encode(block.prevrandao))))
});
entropyOracle.requestEntropy(revealBlockNumber);
}
function _setEggProbabilities(uint64[NUM_EGG_TYPES] memory pdf) internal {
uint64[] memory p = new uint64[](NUM_EGG_TYPES);
for (uint256 i = 0; i < NUM_EGG_TYPES; i++) {
p[i] = pdf[i];
}
_pushProbabilities(_EGG_TYPE_TRAIT_ID, p);
}
function _seed(uint256 tokenId)
internal
view
virtual
override(StochasticSampler, StochasticSamplerWithOracle)
returns (bytes32, bool)
{
(bytes32 seed, bool revealed) = StochasticSamplerWithOracle._seed(tokenId);
return (keccak256(abi.encode(seed, samplingParams(tokenId))), revealed);
}
function eggType(uint256 tokenId) public view returns (EggType, bool) {
(uint256 sample, bool revealed) = _sampleTrait(tokenId, _EGG_TYPE_TRAIT_ID);
return (EggType(sample), revealed);
}
function _exists(uint256 tokenId) internal view virtual returns (bool);
}
文件 15 的 23:MythicsEggErrors.sol
pragma solidity ^0.8.15;
interface MythicsEggErrors {
error NonexistentEgg(uint256 tokenId);
}
文件 16 的 23:NonRollingRateLimited.sol
pragma solidity ^0.8.15;
contract NonRollingRateLimited {
error ExceedingRateLimit(uint256 requested, uint256 numLeft);
uint64 private immutable _periodLength;
uint64 private _lastPeriod;
uint64 private __maxActionsPerPeriod;
uint64 private __performedCurrentPeriod;
constructor(uint64 maxActionsPerPeriod, uint64 periodLength) {
_periodLength = periodLength;
_setMaxActionsPerPeriod(maxActionsPerPeriod);
}
function _currentPeriod() private view returns (uint64) {
return uint64(block.timestamp / _periodLength);
}
function _setMaxActionsPerPeriod(uint64 maxActionsPerPeriod) internal {
__maxActionsPerPeriod = maxActionsPerPeriod;
}
function _maxActionsPerPeriod() internal view returns (uint64) {
return __maxActionsPerPeriod;
}
function _checkAndTrackRateLimit(uint64 requested) internal {
uint64 performed = _performedCurrentPeriod();
uint64 left = __maxActionsPerPeriod - performed;
if (requested > left) {
revert ExceedingRateLimit(requested, left);
}
__performedCurrentPeriod = performed + requested;
_lastPeriod = _currentPeriod();
}
function _performedCurrentPeriod() internal view returns (uint64) {
if (_currentPeriod() > _lastPeriod) {
return 0;
}
return __performedCurrentPeriod;
}
}
文件 17 的 23:Oddsoleum.sol
pragma solidity ^0.8.15;
import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {SettableCallbackerWithAccessControl} from "proof/sellers/presets/CallbackerWithAccessControl.sol";
import {Seller} from "proof/sellers/base/Seller.sol";
import {MythicEggSampler} from "../Egg/MythicEggSampler.sol";
import {NonRollingRateLimited} from "./NonRollingRateLimited.sol";
interface OddsoleumEvents {
event OdditySacrificed(address indexed owner, uint256 tokenId);
event CannotBurnIneligibleOddity(uint256 indexed tokenId, bool queued, bool approved);
}
contract Oddsoleum is Seller, SettableCallbackerWithAccessControl, OddsoleumEvents, NonRollingRateLimited {
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");
address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
IERC721 public immutable oddities;
mapping(address owner => mapping(uint256 tokenId => bool)) private _queued;
constructor(address admin, address steerer, IERC721 oddities_)
SettableCallbackerWithAccessControl(admin, steerer)
NonRollingRateLimited(50, 1 days)
{
_setRoleAdmin(BURNER_ROLE, DEFAULT_STEERING_ROLE);
oddities = oddities_;
}
function addToQueue(uint256[] calldata tokenIds) external {
for (uint256 i = 0; i < tokenIds.length; ++i) {
_queued[msg.sender][tokenIds[i]] = true;
}
}
function removeFromQueue(uint256[] calldata tokenIds) external {
for (uint256 i = 0; i < tokenIds.length; ++i) {
_queued[msg.sender][tokenIds[i]] = false;
}
}
function queued(uint256[] calldata tokenIds) public view returns (bool[] memory) {
bool[] memory queued_ = new bool[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; ++i) {
address owner = oddities.ownerOf(tokenIds[i]);
queued_[i] = _queued[owner][tokenIds[i]];
}
return queued_;
}
function burnable(uint256[] calldata tokenIds) external view returns (bool[] memory) {
bool[] memory burnable_ = new bool[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; ++i) {
address owner = oddities.ownerOf(tokenIds[i]);
burnable_[i] = _burnable(owner, tokenIds[i]);
}
return burnable_;
}
function _burnable(address owner, uint256 tokenId) internal view returns (bool) {
return _queued[owner][tokenId] && _approved(owner, tokenId);
}
function _approved(address owner, uint256 tokenId) internal view returns (bool) {
return (oddities.isApprovedForAll(owner, address(this)) || oddities.getApproved(tokenId) == address(this));
}
function _burn(address owner, uint256 tokenId) internal returns (bool) {
bool queued_ = _queued[owner][tokenId];
bool approved = _approved(owner, tokenId);
if (!(queued_ && approved)) {
emit CannotBurnIneligibleOddity(tokenId, queued_, approved);
return false;
}
oddities.transferFrom(owner, BURN_ADDRESS, tokenId);
emit OdditySacrificed(owner, tokenId);
return true;
}
function _sacrifice(uint256 tokenId) internal returns (bool) {
address owner = oddities.ownerOf(tokenId);
bool burned = _burn(owner, tokenId);
if (!burned) {
return false;
}
_purchase(owner, 1, 0, "");
return true;
}
function sacrifice(uint256[] calldata tokenIds) external onlyRole(BURNER_ROLE) {
uint64 numSacrificed;
for (uint256 i = 0; i < tokenIds.length; ++i) {
bool sacrificed = _sacrifice(tokenIds[i]);
unchecked {
if (sacrificed) {
++numSacrificed;
}
}
}
_checkAndTrackRateLimit(numSacrificed);
}
function setMaxSacrificesPerPeriod(uint32 maxSacrificesPerPeriod) external onlyRole(DEFAULT_STEERING_ROLE) {
_setMaxActionsPerPeriod(maxSacrificesPerPeriod);
}
}
文件 18 的 23:PurchaseExecuter.sol
文件 19 的 23:ReentrancyGuard.sol
文件 20 的 23:SellableCallbacker.sol
文件 22 的 23:StochasticSampling.sol
pragma solidity ^0.8.15;
import {IEntropyOracle} from "proof/entropy/IEntropyOracle.sol";
library StochasticSamplingLib {
function computeCDF(uint64[] memory pdf) internal pure returns (uint64[] memory) {
uint64[] memory cdf = new uint64[](pdf.length);
cdf[0] = pdf[0];
for (uint256 i = 1; i < pdf.length; ++i) {
cdf[i] = cdf[i - 1] + pdf[i];
}
return cdf;
}
function sampleWithCDF(uint256 rand, uint64[] memory cdf) internal pure returns (uint256) {
rand = rand % cdf[cdf.length - 1];
for (uint256 i; i < cdf.length; ++i) {
if (rand < cdf[i]) {
return i;
}
}
assert(false);
return 0;
}
}
abstract contract StochasticSampler {
function _seed(uint256 tokenId) internal view virtual returns (bytes32, bool);
function _cdf(uint256 tokenId, uint256 traitId) internal view virtual returns (uint64[] memory);
function _sampleTrait(uint256 tokenId, uint256 traitId) internal view returns (uint256, bool) {
(bytes32 seed, bool revealed) = _seed(tokenId);
seed = keccak256(abi.encodePacked(seed, traitId));
return (StochasticSamplingLib.sampleWithCDF(uint256(seed), _cdf(tokenId, traitId)), revealed);
}
}
abstract contract StochasticSamplerWithCDFStorage is StochasticSampler {
using StochasticSamplingLib for uint64[];
error InvalidTraitId(uint256 traitId);
error IncorrectPDFLength(uint256 gotLength, uint256 traitId, uint256 wantLength);
error ConstantZeroPDF();
uint256[] private _numPerTrait;
uint64[][][] private _cdfs;
constructor(uint256[] memory numPerTrait) {
_numPerTrait = numPerTrait;
for (uint256 i; i < numPerTrait.length; ++i) {
_cdfs.push(new uint64[][](0));
}
assert(_cdfs.length == numPerTrait.length);
}
function _pushProbabilities(uint256 traitId, uint64[] memory pdf) internal {
if (traitId >= _numPerTrait.length) {
revert InvalidTraitId(traitId);
}
if (pdf.length != _numPerTrait[traitId]) {
revert IncorrectPDFLength(pdf.length, traitId, _numPerTrait[traitId]);
}
uint64[] memory cdf = pdf.computeCDF();
if (cdf[cdf.length - 1] == 0) {
revert ConstantZeroPDF();
}
_cdfs[traitId].push(cdf);
}
function _latestDistributionVersion(uint256 traitId) internal view returns (uint256) {
return _cdfs[traitId].length - 1;
}
function _distributionVersion(uint256 tokenId, uint256 traitId) internal view virtual returns (uint256);
function _cdf(uint256 tokenId, uint256 traitId) internal view virtual override returns (uint64[] memory) {
if (traitId >= _numPerTrait.length) {
revert InvalidTraitId(traitId);
}
return _cdfs[traitId][_distributionVersion(tokenId, traitId)];
}
}
abstract contract StochasticSamplerWithOracle is StochasticSampler {
IEntropyOracle public entropyOracle;
constructor(IEntropyOracle entropyOracle_) {
entropyOracle = entropyOracle_;
}
function _seed(uint256 tokenId) internal view virtual override returns (bytes32, bool) {
bytes32 entropy = entropyOracle.blockEntropy(_revealBlockNumber(tokenId));
return (keccak256(abi.encode(entropy, tokenId)), entropy != 0);
}
function _revealBlockNumber(uint256 tokenId) internal view virtual returns (uint256);
}
{
"compilationTarget": {
"src/Oddsoleum/Oddsoleum.sol": "Oddsoleum"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": false,
"bytecodeHash": "none"
},
"optimizer": {
"enabled": true,
"runs": 9999
},
"remappings": [
":@divergencetech/ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/",
":@openzeppelin/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts_4-8-1/",
":@openzeppelin/contracts-upgradeable/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts-upgradeable_4-9-0/",
":ERC721A/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/contracts/",
":ERC721A_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/",
":delegation-registry/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/delegation-registry_2d1a158b/src/",
":delegation-registry_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/delegation-registry_2d1a158b/",
":ds-test/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ds-test_013e6c64/src/",
":erc721a/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ERC721A_4-2-3/",
":ethier/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/contracts/",
":ethier_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/ethier_0-55-0/",
":forge-std/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/forge-std_1-5-6/src/",
":forge-std_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/forge-std_1-5-6/",
":openzeppelin-contracts-upgradeable/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts-upgradeable_4-9-0/contracts/",
":openzeppelin-contracts-upgradeable/contracts/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts-upgradeable_4-9-0/contracts/",
":openzeppelin-contracts-upgradeable_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/openzeppelin-contracts-upgradeable_4-9-0/",
":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/",
":operator-filter-registry/src/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/operator-filter-registry_1-4-1/src/",
":operator-filter-registry_root/=/home/dave/.cache/bazel/_bazel_dave/b9a57168317213f9241a484d2ee2d038/external/operator-filter-registry_1-4-1/",
":proof/constants/=/home/dave/proof/proof-seller/contracts/constants/src/",
":proof/entropy/=/home/dave/proof/proof-seller/contracts/entropy/",
":proof/redemption/=/home/dave/proof/proof-seller/contracts/redemption/src/",
":proof/sellers/=/home/dave/proof/proof-seller/contracts/sellers/src/"
]
}
[{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"steerer","type":"address"},{"internalType":"contract IERC721","name":"oddities_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes","name":"reason","type":"bytes"}],"name":"CallbackFailed","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"numLeft","type":"uint256"}],"name":"ExceedingRateLimit","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"queued","type":"bool"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"CannotBurnIneligibleOddity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"OdditySacrificed","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":"BURNER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"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":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"addToQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"burnable","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"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":[],"name":"oddities","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"queued","outputs":[{"internalType":"bool[]","name":"","type":"bool[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"removeFromQueue","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":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"sacrifice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sellable","outputs":[{"internalType":"contract ISellable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"maxSacrificesPerPeriod","type":"uint32"}],"name":"setMaxSacrificesPerPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISellable","name":"sellable_","type":"address"}],"name":"setSellable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]