Source Code
Overview
CELO Balance
CELO Value
$0.00Multichain Info
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
AkibaDiceGame
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
No with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./MiniPoints.sol"; // IMiniPoints
import "witnet-solidity-bridge/contracts/interfaces/IWitnetRandomness.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
/// @title Akiba Dice Game
/// @notice 6-player pots. Each player picks a unique number 1-6 for a given tier.
/// When the pot fills, randomness is requested and one number wins the full pot.
contract AkibaDiceGame is UUPSUpgradeable, ReentrancyGuardUpgradeable {
/* ────────────────────────────────────────────────────────────── */
/* Types & storage */
/* ────────────────────────────────────────────────────────────── */
struct DiceRound {
uint256 id; // round id
uint256 tier; // entry cost in MiniPoints for this pot (e.g. 10, 20, 30)
uint8 filledSlots; // 0–6
bool winnerSelected; // true once resolved
uint8 winningNumber; // 1–6 when drawn
uint256 randomBlock; // Witnet randomization block (kept as-is for now)
address winner; // winner address
// mapping: chosen number => player
mapping(uint8 => address) playerByNumber;
}
/// @notice Round lifecycle used by getRoundState for FE / bots.
enum RoundState {
None, // 0 – invalid
Open, // has players, not full
FullWaiting, // full, randomness missing or pending
Ready, // full, randomness ready but not resolved
Resolved // winnerSelected
}
/// @notice Per-tier aggregate stats.
struct TierStats {
uint64 roundsCreated;
uint64 roundsResolved;
uint128 totalStaked; // sum of all entry amounts for this tier
uint128 totalPayout; // sum of all payouts for this tier
}
/// @notice Per-player aggregate stats.
struct PlayerStats {
uint64 roundsJoined;
uint64 roundsWon;
uint128 totalStaked;
uint128 totalWon;
}
/// @notice owner (same pattern as AkibaRaffle)
address public owner;
/// @notice Akiba MiniPoints (same token used across the app)
IMiniPoints public miniPoints;
/// @notice Witnet Randomness provider (kept as-is for now)
IWitnetRandomness public constant RNG =
IWitnetRandomness(0xC0FFEE98AD1434aCbDB894BbB752e138c1006fAB);
/// @notice Next round id to use when creating new pots
uint256 public nextRoundId;
/// @notice All dice rounds (id => round)
mapping(uint256 => DiceRound) private _rounds;
/// @notice The currently open round per tier (entry cost)
/// e.g. activeRoundByTier[10] = roundId
mapping(uint256 => uint256) public activeRoundByTier;
/// @notice Allowed tiers (e.g. 10, 20, 30). Only these can be used in joinTier.
mapping(uint256 => bool) public allowedTier;
/// @notice Tracks whether an address has already joined a specific round.
/// Enforces "one entry per address per round".
mapping(uint256 => mapping(address => bool)) public hasJoinedRound;
/// @notice Per-tier aggregate stats.
mapping(uint256 => TierStats) public tierStats;
/// @notice Per-player aggregate stats.
mapping(address => PlayerStats) public playerStats;
/// @notice Global aggregates.
uint64 public totalRoundsCreated;
uint64 public totalRoundsResolved;
uint64 public totalRoundsCancelled;
uint128 public totalStakedGlobal;
uint128 public totalPayoutGlobal;
/* ────────────────────────────────────────────────────────────── */
/* Events */
/* ────────────────────────────────────────────────────────────── */
event RoundOpened(uint256 indexed roundId, uint256 indexed tier);
event Joined(
uint256 indexed roundId,
uint8 indexed number,
address indexed player
);
event RandomnessRequested(uint256 indexed roundId, uint256 randomBlock);
event RoundResolved(
uint256 indexed roundId,
uint8 indexed winningNumber,
address indexed winner,
uint256 payout
);
event RoundCancelled(uint256 indexed roundId);
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event AllowedTierSet(uint256 indexed tier, bool allowed);
/* ────────────────────────────────────────────────────────────── */
/* Modifiers */
/* ────────────────────────────────────────────────────────────── */
modifier onlyOwner() {
require(msg.sender == owner, "Owner: not owner");
_;
}
modifier roundExists(uint256 roundId) {
require(roundId != 0 && roundId < nextRoundId, "Dice: round not found");
_;
}
/* ────────────────────────────────────────────────────────────── */
/* Initializer & UUPS */
/* ────────────────────────────────────────────────────────────── */
/// @notice Initialize upgradeable contract
/// @param _miniPoints address of the MiniPoints token
/// @param _owner owner (admin) address
function initialize(address _miniPoints, address _owner) public initializer {
__UUPSUpgradeable_init();
__ReentrancyGuard_init();
require(_miniPoints != address(0), "Dice: invalid MiniPoints");
require(_owner != address(0), "Dice: invalid owner");
miniPoints = IMiniPoints(_miniPoints);
owner = _owner;
nextRoundId = 1;
// Default tiers used by Akiba UI (10, 20, 30)
allowedTier[10] = true;
allowedTier[20] = true;
allowedTier[30] = true;
emit OwnershipTransferred(address(0), _owner);
emit AllowedTierSet(10, true);
emit AllowedTierSet(20, true);
emit AllowedTierSet(30, true);
}
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
/* ────────────────────────────────────────────────────────────── */
/* Core game logic */
/* ────────────────────────────────────────────────────────────── */
/// @notice Join a pot for a given tier by picking a number 1–6.
/// If there is no active round for this tier, a new one is opened.
/// If the current round is full or already resolved, a new one is opened.
/// @param tier Entry cost in MiniPoints (must be an allowed tier)
/// @param chosenNumber Number between 1 and 6 (inclusive)
function joinTier(uint256 tier, uint8 chosenNumber) external nonReentrant {
require(allowedTier[tier], "Dice: tier not allowed");
require(chosenNumber >= 1 && chosenNumber <= 6, "Dice: bad number");
// Find or open the active round for this tier
uint256 roundId = activeRoundByTier[tier];
DiceRound storage round = _rounds[roundId];
if (
roundId == 0 ||
round.filledSlots == 6 ||
round.winnerSelected
) {
// open new round
roundId = nextRoundId++;
round = _rounds[roundId];
round.id = roundId;
round.tier = tier;
round.filledSlots = 0;
round.winnerSelected = false;
round.winningNumber = 0;
round.randomBlock = 0;
round.winner = address(0);
activeRoundByTier[tier] = roundId;
// stats
totalRoundsCreated += 1;
TierStats storage tsOpen = tierStats[tier];
tsOpen.roundsCreated += 1;
emit RoundOpened(roundId, tier);
}
// Enforce one entry per address per round
require(
!hasJoinedRound[roundId][msg.sender],
"Dice: already joined"
);
// Slot must be free
require(
round.playerByNumber[chosenNumber] == address(0),
"Dice: number taken"
);
// Burn the player's entry cost in MiniPoints
miniPoints.burn(msg.sender, tier);
// Assign the slot
round.playerByNumber[chosenNumber] = msg.sender;
round.filledSlots += 1;
hasJoinedRound[roundId][msg.sender] = true;
// stats: staking & player stats
TierStats storage ts = tierStats[tier];
ts.totalStaked += uint128(tier);
totalStakedGlobal += uint128(tier);
PlayerStats storage ps = playerStats[msg.sender];
ps.roundsJoined += 1;
ps.totalStaked += uint128(tier);
emit Joined(roundId, chosenNumber, msg.sender);
// ── Auto-draw hook: if this join makes pot full, try to auto-resolve
if (round.filledSlots == 6) {
_tryAutoDraw(roundId);
}
}
/// @notice Request randomness for a pot as soon as there is at least 1 player.
/// @dev This should be called "early", e.g. right after the first join, so that
/// randomness is likely ready by the time the 6th player joins.
/// `msg.value` is forwarded to Witnet; any leftover is refunded.
function requestRoundRandomness(
uint256 roundId
) external payable nonReentrant roundExists(roundId) {
DiceRound storage round = _rounds[roundId];
require(round.filledSlots > 0, "Dice: no players yet");
require(!round.winnerSelected, "Dice: already resolved");
require(round.randomBlock == 0, "Dice: randomness requested");
uint256 usedFee = RNG.randomize{value: msg.value}();
round.randomBlock = block.number;
if (usedFee < msg.value) {
payable(msg.sender).transfer(msg.value - usedFee);
}
emit RandomnessRequested(roundId, round.randomBlock);
}
/// @notice Draw the winner for a pot once randomness is available,
/// and pay out the full pot in MiniPoints.
/// @dev Still usable as a manual fallback draw, even with auto-draw enabled.
function drawRound(
uint256 roundId
) external nonReentrant roundExists(roundId) {
DiceRound storage round = _rounds[roundId];
require(round.filledSlots == 6, "Dice: pot not full");
require(!round.winnerSelected, "Dice: already resolved");
require(round.randomBlock != 0, "Dice: randomness not requested");
require(
RNG.isRandomized(round.randomBlock),
"Dice: randomness pending"
);
_finalizeRound(roundId);
}
/// @notice Internal: try to auto-draw the round if all preconditions are met.
/// Used from joinTier when the 6th player joins.
function _tryAutoDraw(uint256 roundId) internal {
DiceRound storage round = _rounds[roundId];
// Must be full
if (round.filledSlots != 6) return;
// Already resolved
if (round.winnerSelected) return;
// Randomness must have been requested earlier
if (round.randomBlock == 0) return;
// Randomness must be ready
if (!RNG.isRandomized(round.randomBlock)) return;
_finalizeRound(roundId);
}
/// @notice Internal: core logic to pick winner, mint payout, update stats and emit event.
function _finalizeRound(uint256 roundId) internal {
DiceRound storage round = _rounds[roundId];
// Draw a number in [0,5], then map to [1,6]
uint256 pick = RNG.random(6, 0, round.randomBlock);
uint8 winningNumber = uint8(pick + 1);
address winner = round.playerByNumber[winningNumber];
require(winner != address(0), "Dice: empty winner slot");
uint256 payout = round.tier * 6;
round.winnerSelected = true;
round.winningNumber = winningNumber;
round.winner = winner;
// Mint the full pot in MiniPoints to winner
miniPoints.mint(winner, payout);
// stats
totalRoundsResolved += 1;
totalPayoutGlobal += uint128(payout);
TierStats storage ts = tierStats[round.tier];
ts.roundsResolved += 1;
ts.totalPayout += uint128(payout);
PlayerStats storage ps = playerStats[winner];
ps.roundsWon += 1;
ps.totalWon += uint128(payout);
emit RoundResolved(roundId, winningNumber, winner, payout);
}
/// @notice Owner can cancel an unresolved *not-full* round and refund players in MiniPoints.
/// @dev Safety valve in case a pot gets stuck / never fills.
/// Cannot cancel a full pot or one where randomness has been requested.
function cancelRound(
uint256 roundId
) external nonReentrant onlyOwner roundExists(roundId) {
DiceRound storage round = _rounds[roundId];
require(!round.winnerSelected, "Dice: already resolved");
require(round.filledSlots < 6, "Dice: full pot");
require(round.randomBlock == 0, "Dice: randomness requested");
// Refund each occupied slot and clear hasJoinedRound
for (uint8 n = 1; n <= 6; n++) {
address player = round.playerByNumber[n];
if (player != address(0)) {
miniPoints.mint(player, round.tier);
round.playerByNumber[n] = address(0);
hasJoinedRound[roundId][player] = false;
}
}
round.filledSlots = 0;
round.winnerSelected = true; // mark as closed to prevent reuse
totalRoundsCancelled += 1;
emit RoundCancelled(roundId);
}
/* ────────────────────────────────────────────────────────────── */
/* View helpers */
/* ────────────────────────────────────────────────────────────── */
/// @notice Returns basic info about a round (no slot mappings).
function getRoundInfo(
uint256 roundId
)
external
view
roundExists(roundId)
returns (
uint256 tier,
uint8 filledSlots,
bool winnerSelected,
uint8 winningNumber,
uint256 randomBlock,
address winner
)
{
DiceRound storage round = _rounds[roundId];
return (
round.tier,
round.filledSlots,
round.winnerSelected,
round.winningNumber,
round.randomBlock,
round.winner
);
}
/// @notice Returns all 6 slots (players + numbers) for a round.
function getRoundSlots(
uint256 roundId
)
external
view
roundExists(roundId)
returns (address[6] memory players, uint8[6] memory numbers)
{
DiceRound storage round = _rounds[roundId];
for (uint8 i = 0; i < 6; i++) {
uint8 num = i + 1;
players[i] = round.playerByNumber[num];
numbers[i] = num;
}
}
/// @notice Returns the player who picked a given number in a round.
function getRoundSlotPlayer(
uint256 roundId,
uint8 number
) external view roundExists(roundId) returns (address) {
require(number >= 1 && number <= 6, "Dice: bad number");
return _rounds[roundId].playerByNumber[number];
}
/// @notice Returns the number this player picked in a given round, if any.
function getMyNumberInRound(
uint256 roundId,
address player
) external view roundExists(roundId) returns (bool joined, uint8 number) {
DiceRound storage round = _rounds[roundId];
for (uint8 n = 1; n <= 6; n++) {
if (round.playerByNumber[n] == player) {
return (true, n);
}
}
return (false, 0);
}
/// @notice Returns the active round id for a given tier (0 if none yet).
function getActiveRoundId(uint256 tier) external view returns (uint256) {
return activeRoundByTier[tier];
}
/// @notice Returns a summarized "state" enum for the given round id.
function getRoundState(uint256 roundId)
external
view
roundExists(roundId)
returns (RoundState)
{
DiceRound storage r = _rounds[roundId];
if (r.winnerSelected) {
return RoundState.Resolved;
}
if (r.filledSlots < 6) {
return RoundState.Open;
}
// full pot here
if (r.randomBlock == 0) {
return RoundState.FullWaiting;
}
if (!RNG.isRandomized(r.randomBlock)) {
return RoundState.FullWaiting;
}
return RoundState.Ready;
}
/// @notice Returns the current active entry (if any) for a player in a given tier.
/// Helps the FE know if the user already joined the current pot.
function getMyActiveEntryForTier(
uint256 tier,
address player
)
external
view
returns (bool joined, uint256 roundId, uint8 number)
{
roundId = activeRoundByTier[tier];
if (roundId == 0) return (false, 0, 0);
DiceRound storage round = _rounds[roundId];
for (uint8 n = 1; n <= 6; n++) {
if (round.playerByNumber[n] == player) {
return (true, roundId, n);
}
}
return (false, roundId, 0);
}
/// @notice Returns aggregate stats for a given tier.
function getTierStats(uint256 tier)
external
view
returns (
uint64 roundsCreated,
uint64 roundsResolved,
uint128 totalStaked,
uint128 totalPayout
)
{
TierStats storage ts = tierStats[tier];
return (
ts.roundsCreated,
ts.roundsResolved,
ts.totalStaked,
ts.totalPayout
);
}
/// @notice Returns aggregate stats for a given player.
function getPlayerStats(address player)
external
view
returns (
uint64 roundsJoined,
uint64 roundsWon,
uint128 totalStaked,
uint128 totalWon
)
{
PlayerStats storage ps = playerStats[player];
return (
ps.roundsJoined,
ps.roundsWon,
ps.totalStaked,
ps.totalWon
);
}
/* ────────────────────────────────────────────────────────────── */
/* Admin */
/* ────────────────────────────────────────────────────────────── */
/// @notice Set whether a tier is allowed for new rounds.
/// E.g. keep 10/20/30, or add/remove others.
function setAllowedTier(uint256 tier, bool allowed) external onlyOwner {
allowedTier[tier] = allowed;
emit AllowedTierSet(tier, allowed);
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "Owner: zero addr");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
// Adjusted gap for new storage vars
uint256[40] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822ProxiableUpgradeable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
*
* _Available since v4.8.3._
*/
interface IERC1967Upgradeable {
/**
* @dev Emitted when the implementation is upgraded.
*/
event Upgraded(address indexed implementation);
/**
* @dev Emitted when the admin account has changed.
*/
event AdminChanged(address previousAdmin, address newAdmin);
/**
* @dev Emitted when the beacon is changed.
*/
event BeaconUpgraded(address indexed beacon);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
pragma solidity ^0.8.0;
/**
* @dev This is the interface that {BeaconProxy} expects of its beacon.
*/
interface IBeaconUpgradeable {
/**
* @dev Must return an address that can be used as a delegate call target.
*
* {BeaconProxy} will check that this address is a contract.
*/
function implementation() external view returns (address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeaconUpgradeable.sol";
import "../../interfaces/IERC1967Upgradeable.sol";
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../../utils/AddressUpgradeable.sol";
import "../../utils/StorageSlotUpgradeable.sol";
import "../utils/Initializable.sol";
/**
* @dev This abstract contract provides getters and event emitting update functions for
* https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
*
* _Available since v4.1._
*/
abstract contract ERC1967UpgradeUpgradeable is Initializable, IERC1967Upgradeable {
function __ERC1967Upgrade_init() internal onlyInitializing {
}
function __ERC1967Upgrade_init_unchained() internal onlyInitializing {
}
// This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
/**
* @dev Storage slot with the address of the current implementation.
* This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
/**
* @dev Returns the current implementation address.
*/
function _getImplementation() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 implementation slot.
*/
function _setImplementation(address newImplementation) private {
require(AddressUpgradeable.isContract(newImplementation), "ERC1967: new implementation is not a contract");
StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
}
/**
* @dev Perform implementation upgrade
*
* Emits an {Upgraded} event.
*/
function _upgradeTo(address newImplementation) internal {
_setImplementation(newImplementation);
emit Upgraded(newImplementation);
}
/**
* @dev Perform implementation upgrade with additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
_upgradeTo(newImplementation);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(newImplementation, data);
}
}
/**
* @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
*
* Emits an {Upgraded} event.
*/
function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlotUpgradeable.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822ProxiableUpgradeable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
* validated in the constructor.
*/
bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
/**
* @dev Returns the current admin.
*/
function _getAdmin() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value;
}
/**
* @dev Stores a new address in the EIP1967 admin slot.
*/
function _setAdmin(address newAdmin) private {
require(newAdmin != address(0), "ERC1967: new admin is the zero address");
StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
}
/**
* @dev Changes the admin of the proxy.
*
* Emits an {AdminChanged} event.
*/
function _changeAdmin(address newAdmin) internal {
emit AdminChanged(_getAdmin(), newAdmin);
_setAdmin(newAdmin);
}
/**
* @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
* This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
*/
bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
/**
* @dev Returns the current beacon.
*/
function _getBeacon() internal view returns (address) {
return StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value;
}
/**
* @dev Stores a new beacon in the EIP1967 beacon slot.
*/
function _setBeacon(address newBeacon) private {
require(AddressUpgradeable.isContract(newBeacon), "ERC1967: new beacon is not a contract");
require(
AddressUpgradeable.isContract(IBeaconUpgradeable(newBeacon).implementation()),
"ERC1967: beacon implementation is not a contract"
);
StorageSlotUpgradeable.getAddressSlot(_BEACON_SLOT).value = newBeacon;
}
/**
* @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
* not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
*
* Emits a {BeaconUpgraded} event.
*/
function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
_setBeacon(newBeacon);
emit BeaconUpgraded(newBeacon);
if (data.length > 0 || forceCall) {
AddressUpgradeable.functionDelegateCall(IBeaconUpgradeable(newBeacon).implementation(), data);
}
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
* constructor.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: setting the version to 255 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized != type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint8) {
return _initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _initializing;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
pragma solidity ^0.8.0;
import "../../interfaces/draft-IERC1822Upgradeable.sol";
import "../ERC1967/ERC1967UpgradeUpgradeable.sol";
import "./Initializable.sol";
/**
* @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
* {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
*
* A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
* reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
* `UUPSUpgradeable` with a custom implementation of upgrades.
*
* The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
*
* _Available since v4.1._
*/
abstract contract UUPSUpgradeable is Initializable, IERC1822ProxiableUpgradeable, ERC1967UpgradeUpgradeable {
function __UUPSUpgradeable_init() internal onlyInitializing {
}
function __UUPSUpgradeable_init_unchained() internal onlyInitializing {
}
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
address private immutable __self = address(this);
/**
* @dev Check that the execution is being performed through a delegatecall call and that the execution context is
* a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
* for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
* function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
* fail.
*/
modifier onlyProxy() {
require(address(this) != __self, "Function must be called through delegatecall");
require(_getImplementation() == __self, "Function must be called through active proxy");
_;
}
/**
* @dev Check that the execution is not being performed through a delegate call. This allows a function to be
* callable on the implementing contract but not through proxies.
*/
modifier notDelegated() {
require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
_;
}
/**
* @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
* implementation. It is used to validate the implementation's compatibility when performing an upgrade.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
*/
function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
return _IMPLEMENTATION_SLOT;
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeTo(address newImplementation) public virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
}
/**
* @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
* encoded in `data`.
*
* Calls {_authorizeUpgrade}.
*
* Emits an {Upgraded} event.
*
* @custom:oz-upgrades-unsafe-allow-reachable delegatecall
*/
function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
_authorizeUpgrade(newImplementation);
_upgradeToAndCallUUPS(newImplementation, data, true);
}
/**
* @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
* {upgradeTo} and {upgradeToAndCall}.
*
* Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
*
* ```solidity
* function _authorizeUpgrade(address) internal override onlyOwner {}
* ```
*/
function _authorizeUpgrade(address newImplementation) internal virtual;
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
*
* Furthermore, `isContract` will also return true if the target contract within
* the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
* which only has an effect at the end of a transaction.
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) 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(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.0;
/**
* @dev Library for reading and writing primitive types to specific storage slots.
*
* Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
*
* Example usage to set ERC1967 implementation slot:
* ```solidity
* contract ERC1967 {
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
* _Available since v4.9 for `string`, `bytes`._
*/
library StorageSlotUpgradeable {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct StringSlot {
string value;
}
struct BytesSlot {
bytes value;
}
/**
* @dev Returns an `AddressSlot` with member `value` located at `slot`.
*/
function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `StringSlot` representation of the string storage pointer `store`.
*/
function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
/**
* @dev Returns an `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
*/
function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @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.
*
* By default, the owner account will be the one that deploys the contract. 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;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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 {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_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);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract AkibaMiles is ERC20, Ownable {
error NullAddress();
error Unauthorized();
mapping(address => bool) public minters;
constructor() ERC20("AkibaMiles", "Miles") {}
modifier onlyAllowed() {
if (msg.sender != owner() && !minters[msg.sender])
revert Unauthorized();
_;
}
function setMinter(address who, bool enabled) external onlyOwner {
require(who != address(0), "Zero addr");
minters[who] = enabled;
}
function mint(address account, uint256 amount) external onlyAllowed {
_mint(account, amount);
}
function burn(address account, uint256 amount) external {
_burn(account, amount);
}
// Make token non-transferrable
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20) {
// Allow minting (from == 0) and burning (to == 0) only
if (from != address(0) && to != address(0)) {
revert("Transfers are not allowed");
}
super._beforeTokenTransfer(from, to, amount);
}
// The following functions are overrides required by Solidity.
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20) {
super._afterTokenTransfer(from, to, amount);
}
function _mint(address to, uint256 amount) internal override(ERC20) {
super._mint(to, amount);
}
function _burn(address account, uint256 amount) internal override(ERC20) {
super._burn(account, amount);
}
}
interface IMiniPoints {
function mint(address account, uint256 amount) external;
function burn(address account, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
import "../libs/WitnetV2.sol";
interface IWitnetOracle {
/// @notice Estimate the minimum reward required for posting a data request.
/// @dev Underestimates if the size of returned data is greater than `resultMaxSize`.
/// @param gasPrice Expected gas price to pay upon posting the data request.
/// @param resultMaxSize Maximum expected size of returned data (in bytes).
function estimateBaseFee(uint256 gasPrice, uint16 resultMaxSize) external view returns (uint256);
/// @notice Estimate the minimum reward required for posting a data request.
/// @dev Fails if the RAD hash was not previously verified on the WitnetRequestBytecodes registry.
/// @param gasPrice Expected gas price to pay upon posting the data request.
/// @param radHash The RAD hash of the data request to be solved by Witnet.
function estimateBaseFee(uint256 gasPrice, bytes32 radHash) external view returns (uint256);
/// @notice Estimate the minimum reward required for posting a data request with a callback.
/// @param gasPrice Expected gas price to pay upon posting the data request.
/// @param callbackGasLimit Maximum gas to be spent when reporting the data request result.
function estimateBaseFeeWithCallback(uint256 gasPrice, uint24 callbackGasLimit) external view returns (uint256);
/// @notice Retrieves a copy of all Witnet-provable data related to a previously posted request,
/// removing the whole query from the WRB storage.
/// @dev Fails if the query was not in 'Reported' status, or called from an address different to
/// @dev the one that actually posted the given request.
/// @param queryId The unique query identifier.
function fetchQueryResponse(uint256 queryId) external returns (WitnetV2.Response memory);
/// @notice Gets the whole Query data contents, if any, no matter its current status.
function getQuery(uint256 queryId) external view returns (WitnetV2.Query memory);
/// @notice Gets the current EVM reward the report can claim, if not done yet.
function getQueryEvmReward(uint256 queryId) external view returns (uint256);
/// @notice Retrieves the RAD hash and SLA parameters of the given query.
/// @param queryId The unique query identifier.
function getQueryRequest(uint256 queryId) external view returns (WitnetV2.Request memory);
/// @notice Retrieves the whole `Witnet.Response` record referred to a previously posted Witnet Data Request.
/// @param queryId The unique query identifier.
function getQueryResponse(uint256 queryId) external view returns (WitnetV2.Response memory);
/// @notice Returns query's result current status from a requester's point of view:
/// @notice - 0 => Void: the query is either non-existent or deleted;
/// @notice - 1 => Awaiting: the query has not yet been reported;
/// @notice - 2 => Ready: the query response was finalized, and contains a result with no erros.
/// @notice - 3 => Error: the query response was finalized, and contains a result with errors.
/// @param queryId The unique query identifier.
function getQueryResponseStatus(uint256 queryId) external view returns (WitnetV2.ResponseStatus);
/// @notice Retrieves the CBOR-encoded buffer containing the Witnet-provided result to the given query.
/// @param queryId The unique query identifier.
function getQueryResultCborBytes(uint256 queryId) external view returns (bytes memory);
/// @notice Gets error code identifying some possible failure on the resolution of the given query.
/// @param queryId The unique query identifier.
function getQueryResultError(uint256 queryId) external view returns (Witnet.ResultError memory);
/// @notice Gets current status of given query.
function getQueryStatus(uint256 queryId) external view returns (WitnetV2.QueryStatus);
/// @notice Get current status of all given query ids.
function getQueryStatusBatch(uint256[] calldata queryIds) external view returns (WitnetV2.QueryStatus[] memory);
/// @notice Returns next query id to be generated by the Witnet Request Board.
function getNextQueryId() external view returns (uint256);
/// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and
/// @notice solved by the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be
/// @notice transferred to the reporter who relays back the Witnet-provable result to this request.
/// @dev Reasons to fail:
/// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry;
/// @dev - invalid SLA parameters were provided;
/// @dev - insufficient value is paid as reward.
/// @param queryRAD The RAD hash of the data request to be solved by Witnet.
/// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
/// @return queryId Unique query identifier.
function postRequest(
bytes32 queryRAD,
WitnetV2.RadonSLA calldata querySLA
) external payable returns (uint256 queryId);
/// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by
/// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the
/// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported
/// @notice directly to the requesting contract. If the report callback fails for any reason, an `WitnetQueryResponseDeliveryFailed`
/// @notice will be triggered, and the Witnet audit trail will be saved in storage, but not so the actual CBOR-encoded result.
/// @dev Reasons to fail:
/// @dev - the caller is not a contract implementing the IWitnetConsumer interface;
/// @dev - the RAD hash was not previously verified by the WitnetRequestBytecodes registry;
/// @dev - invalid SLA parameters were provided;
/// @dev - insufficient value is paid as reward.
/// @param queryRAD The RAD hash of the data request to be solved by Witnet.
/// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
/// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result.
/// @return queryId Unique query identifier.
function postRequestWithCallback(
bytes32 queryRAD,
WitnetV2.RadonSLA calldata querySLA,
uint24 queryCallbackGasLimit
) external payable returns (uint256 queryId);
/// @notice Requests the execution of the given Witnet Data Request, in expectation that it will be relayed and solved by
/// @notice the Witnet blockchain. A reward amount is escrowed by the Witnet Request Board that will be transferred to the
/// @notice reporter who relays back the Witnet-provable result to this request. The Witnet-provable result will be reported
/// @notice directly to the requesting contract. If the report callback fails for any reason, a `WitnetQueryResponseDeliveryFailed`
/// @notice event will be triggered, and the Witnet audit trail will be saved in storage, but not so the CBOR-encoded result.
/// @dev Reasons to fail:
/// @dev - the caller is not a contract implementing the IWitnetConsumer interface;
/// @dev - the provided bytecode is empty;
/// @dev - invalid SLA parameters were provided;
/// @dev - insufficient value is paid as reward.
/// @param queryUnverifiedBytecode The (unverified) bytecode containing the actual data request to be solved by the Witnet blockchain.
/// @param querySLA The data query SLA to be fulfilled on the Witnet blockchain.
/// @param queryCallbackGasLimit Maximum gas to be spent when reporting the data request result.
/// @return queryId Unique query identifier.
function postRequestWithCallback(
bytes calldata queryUnverifiedBytecode,
WitnetV2.RadonSLA calldata querySLA,
uint24 queryCallbackGasLimit
) external payable returns (uint256 queryId);
/// @notice Increments the reward of a previously posted request by adding the transaction value to it.
/// @param queryId The unique query identifier.
function upgradeQueryEvmReward(uint256 queryId) external payable;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
import "../libs/WitnetV2.sol";
interface IWitnetOracleEvents {
/// Emitted every time a new query containing some verified data request is posted to the WRB.
event WitnetQuery(
uint256 id,
uint256 evmReward,
WitnetV2.RadonSLA witnetSLA
);
/// Emitted when a query with no callback gets reported into the WRB.
event WitnetQueryResponse(
uint256 id,
uint256 evmGasPrice
);
/// Emitted when a query with a callback gets successfully reported into the WRB.
event WitnetQueryResponseDelivered(
uint256 id,
uint256 evmGasPrice,
uint256 evmCallbackGas
);
/// Emitted when a query with a callback cannot get reported into the WRB.
event WitnetQueryResponseDeliveryFailed(
uint256 id,
bytes resultCborBytes,
uint256 evmGasPrice,
uint256 evmCallbackActualGas,
string evmCallbackRevertReason
);
/// Emitted when the reward of some not-yet reported query is upgraded.
event WitnetQueryRewardUpgraded(
uint256 id,
uint256 evmReward
);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "../WitnetOracle.sol";
/// @title The Witnet Randomness generator interface.
/// @author Witnet Foundation.
interface IWitnetRandomness {
/// @notice Returns amount of wei required to be paid as a fee when requesting randomization with a
/// transaction gas price as the one given.
function estimateRandomizeFee(uint256 evmGasPrice) external view returns (uint256);
/// @notice Retrieves the result of keccak256-hashing the given block number with the randomness value
/// @notice generated by the Witnet Oracle blockchain in response to the first non-errored randomize request solved
/// @notice after such block number.
/// @dev Reverts if:
/// @dev i. no `randomize()` was requested on neither the given block, nor afterwards.
/// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet.
/// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors.
/// @param blockNumber Block number from which the search will start.
function fetchRandomnessAfter(uint256 blockNumber) external view returns (bytes32);
/// @notice Retrieves the actual random value, unique hash and timestamp of the witnessing commit/reveal act that took
/// @notice place in the Witnet Oracle blockchain in response to the first non-errored randomize request
/// @notice solved after the given block number.
/// @dev Reverts if:
/// @dev i. no `randomize()` was requested on neither the given block, nor afterwards.
/// @dev ii. the first non-errored `randomize()` request found on or after the given block is not solved yet.
/// @dev iii. all `randomize()` requests that took place on or after the given block were solved with errors.
/// @param blockNumber Block number from which the search will start.
/// @return witnetResultRandomness Random value provided by the Witnet blockchain and used for solving randomness after given block.
/// @return witnetResultTimestamp Timestamp at which the randomness value was generated by the Witnet blockchain.
/// @return witnetResultTallyHash Hash of the witnessing commit/reveal act that took place on the Witnet blockchain.
/// @return witnetResultFinalityBlock EVM block number from which the provided randomness can be considered to be final.
function fetchRandomnessAfterProof(uint256 blockNumber) external view returns (
bytes32 witnetResultRandomness,
uint64 witnetResultTimestamp,
bytes32 witnetResultTallyHash,
uint256 witnetResultFinalityBlock
);
/// @notice Returns last block number on which a randomize was requested.
function getLastRandomizeBlock() external view returns (uint256);
/// @notice Retrieves metadata related to the randomize request that got posted to the
/// @notice Witnet Oracle contract on the given block number.
/// @dev Returns zero values if no randomize request was actually posted on the given block.
/// @return witnetQueryId Identifier of the underlying Witnet query created on the given block number.
/// @return prevRandomizeBlock Block number in which a randomize request got posted just before this one. 0 if none.
/// @return nextRandomizeBlock Block number in which a randomize request got posted just after this one, 0 if none.
function getRandomizeData(uint256 blockNumber) external view returns (
uint256 witnetQueryId,
uint256 prevRandomizeBlock,
uint256 nextRandomizeBlock
);
/// @notice Returns the number of the next block in which a randomize request was posted after the given one.
/// @param blockNumber Block number from which the search will start.
/// @return Number of the first block found after the given one, or `0` otherwise.
function getRandomizeNextBlock(uint256 blockNumber) external view returns (uint256);
/// @notice Returns the number of the previous block in which a randomize request was posted before the given one.
/// @param blockNumber Block number from which the search will start.
/// @return First block found before the given one, or `0` otherwise.
function getRandomizePrevBlock(uint256 blockNumber) external view returns (uint256);
/// @notice Gets current status of the first non-errored randomize request posted on or after the given block number.
/// @dev Possible values:
/// @dev - 0 -> Void: no randomize request was actually posted on or after the given block number.
/// @dev - 1 -> Awaiting: a randomize request was found but it's not yet solved by the Witnet blockchain.
/// @dev - 2 -> Ready: a successfull randomize value was reported and ready to be read.
/// @dev - 3 -> Error: all randomize resolutions after the given block were solved with errors.
/// @dev - 4 -> Finalizing: a randomize resolution has been reported from the Witnet blockchain, but it's not yet final.
function getRandomizeStatus(uint256 blockNumber) external view returns (WitnetV2.ResponseStatus);
/// @notice Returns `true` only if a successfull resolution from the Witnet blockchain is found for the first
/// @notice non-errored randomize request posted on or after the given block number.
function isRandomized(uint256 blockNumber) external view returns (bool);
/// @notice Generates a pseudo-random number uniformly distributed within the range [0 .. _range), by using
/// @notice the given `nonce` and the randomness returned by `getRandomnessAfter(blockNumber)`.
/// @dev Fails under same conditions as `getRandomnessAfter(uint256)` does.
/// @param range Range within which the uniformly-distributed random number will be generated.
/// @param nonce Nonce value enabling multiple random numbers from the same randomness value.
/// @param blockNumber Block number from which the search for the first randomize request solved aftewards will start.
function random(uint32 range, uint256 nonce, uint256 blockNumber) external view returns (uint32);
/// @notice Requests the Witnet oracle to generate an EVM-agnostic and trustless source of randomness.
/// @dev Only one randomness request per block will be actually posted to the Witnet Oracle.
/// @dev Unused funds will be transfered back to the `msg.sender`.
/// @return Funds actually paid as randomize fee.
function randomize() external payable returns (uint256);
/// @notice Returns address of the Witnet Oracle bridging contract being used for solving randomness requests.
function witnet() external view returns (WitnetOracle);
/// @notice Returns the SLA parameters required for the Witnet Oracle blockchain to fulfill
/// @notice when solving randomness requests:
/// @notice - number of witnessing nodes contributing to randomness generation
/// @notice - reward in $nanoWIT received per witnessing node in the Witnet blockchain
function witnetQuerySLA() external view returns (WitnetV2.RadonSLA memory);
/// @notice Returns the unique identifier of the Witnet-compliant data request being used for solving randomness.
function witnetRadHash() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
import "../libs/WitnetV2.sol";
interface IWitnetRequestBytecodes {
error UnknownRadonRetrieval(bytes32 hash);
error UnknownRadonReducer(bytes32 hash);
error UnknownRadonRequest(bytes32 hash);
event NewDataProvider(uint256 index);
event NewRadonRetrievalHash(bytes32 hash);
event NewRadonReducerHash(bytes32 hash);
event NewRadHash(bytes32 hash);
function bytecodeOf(bytes32 radHash) external view returns (bytes memory);
function bytecodeOf(bytes32 radHash, WitnetV2.RadonSLA calldata sla) external view returns (bytes memory);
function bytecodeOf(bytes calldata radBytecode, WitnetV2.RadonSLA calldata sla) external view returns (bytes memory);
function hashOf(bytes calldata) external view returns (bytes32);
function lookupDataProvider(uint256 index) external view returns (string memory, uint);
function lookupDataProviderIndex(string calldata authority) external view returns (uint);
function lookupDataProviderSources(uint256 index, uint256 offset, uint256 length) external view returns (bytes32[] memory);
function lookupRadonReducer(bytes32 hash) external view returns (Witnet.RadonReducer memory);
function lookupRadonRetrieval(bytes32 hash) external view returns (Witnet.RadonRetrieval memory);
function lookupRadonRetrievalArgsCount(bytes32 hash) external view returns (uint8);
function lookupRadonRetrievalResultDataType(bytes32 hash) external view returns (Witnet.RadonDataTypes);
function lookupRadonRequestAggregator(bytes32 radHash) external view returns (Witnet.RadonReducer memory);
function lookupRadonRequestResultMaxSize(bytes32 radHash) external view returns (uint16);
function lookupRadonRequestResultDataType(bytes32 radHash) external view returns (Witnet.RadonDataTypes);
function lookupRadonRequestSources(bytes32 radHash) external view returns (bytes32[] memory);
function lookupRadonRequestSourcesCount(bytes32 radHash) external view returns (uint);
function lookupRadonRequestTally(bytes32 radHash) external view returns (Witnet.RadonReducer memory);
function verifyRadonRetrieval(
Witnet.RadonDataRequestMethods requestMethod,
string calldata requestURL,
string calldata requestBody,
string[2][] calldata requestHeaders,
bytes calldata requestRadonScript
) external returns (bytes32 hash);
function verifyRadonReducer(Witnet.RadonReducer calldata reducer)
external returns (bytes32 hash);
function verifyRadonRequest(
bytes32[] calldata sources,
bytes32 aggregator,
bytes32 tally,
uint16 resultMaxSize,
string[][] calldata args
) external returns (bytes32 radHash);
function totalDataProviders() external view returns (uint);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
interface IWitnetRequestFactory {
event WitnetRequestTemplateBuilt(address template, bool parameterized);
function buildRequestTemplate(
bytes32[] memory sourcesIds,
bytes32 aggregatorId,
bytes32 tallyId,
uint16 resultDataMaxSize
) external returns (address template);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "./WitnetCBOR.sol";
library Witnet {
using WitnetBuffer for WitnetBuffer.Buffer;
using WitnetCBOR for WitnetCBOR.CBOR;
using WitnetCBOR for WitnetCBOR.CBOR[];
/// Struct containing both request and response data related to every query posted to the Witnet Request Board
struct Query {
Request request;
Response response;
address from; // Address from which the request was posted.
}
/// Possible status of a Witnet query.
enum QueryStatus {
Unknown,
Posted,
Reported,
Deleted
}
/// Data kept in EVM-storage for every Request posted to the Witnet Request Board.
struct Request {
address addr; // Address of the (deprecated) IWitnetRequest contract containing Witnet data request raw bytecode.
bytes32 slaHash; // Radon SLA hash of the Witnet data request.
bytes32 radHash; // Radon radHash of the Witnet data request.
uint256 gasprice; // Minimum gas price the DR resolver should pay on the solving tx.
uint256 reward; // Escrowed reward to be paid to the DR resolver.
}
/// Data kept in EVM-storage containing the Witnet-provided response metadata and CBOR-encoded result.
struct Response {
address reporter; // Address from which the result was reported.
uint256 timestamp; // Timestamp of the Witnet-provided result.
bytes32 drTxHash; // Hash of the Witnet transaction that solved the queried Data Request.
bytes cborBytes; // Witnet-provided result CBOR-bytes to the queried Data Request.
}
/// Data struct containing the Witnet-provided result to a Data Request.
struct Result {
bool success; // Flag stating whether the request could get solved successfully, or not.
WitnetCBOR.CBOR value; // Resulting value, in CBOR-serialized bytes.
}
/// Final query's result status from a requester's point of view.
enum ResultStatus {
Void,
Awaiting,
Ready,
Error
}
/// Data struct describing an error when trying to fetch a Witnet-provided result to a Data Request.
struct ResultError {
ResultErrorCodes code;
string reason;
}
enum ResultErrorCodes {
/// 0x00: Unknown error. Something went really bad!
Unknown,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Source-specific format error sub-codes ============================================================================
/// 0x01: At least one of the source scripts is not a valid CBOR-encoded value.
SourceScriptNotCBOR,
/// 0x02: The CBOR value decoded from a source script is not an Array.
SourceScriptNotArray,
/// 0x03: The Array value decoded form a source script is not a valid Data Request.
SourceScriptNotRADON,
/// 0x04: The request body of at least one data source was not properly formated.
SourceRequestBody,
/// 0x05: The request headers of at least one data source was not properly formated.
SourceRequestHeaders,
/// 0x06: The request URL of at least one data source was not properly formated.
SourceRequestURL,
/// Unallocated
SourceFormat0x07, SourceFormat0x08, SourceFormat0x09, SourceFormat0x0A, SourceFormat0x0B, SourceFormat0x0C,
SourceFormat0x0D, SourceFormat0x0E, SourceFormat0x0F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Complexity error sub-codes ========================================================================================
/// 0x10: The request contains too many sources.
RequestTooManySources,
/// 0x11: The script contains too many calls.
ScriptTooManyCalls,
/// Unallocated
Complexity0x12, Complexity0x13, Complexity0x14, Complexity0x15, Complexity0x16, Complexity0x17, Complexity0x18,
Complexity0x19, Complexity0x1A, Complexity0x1B, Complexity0x1C, Complexity0x1D, Complexity0x1E, Complexity0x1F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Lack of support error sub-codes ===================================================================================
/// 0x20: Some Radon operator code was found that is not supported (1+ args).
UnsupportedOperator,
/// 0x21: Some Radon filter opcode is not currently supported (1+ args).
UnsupportedFilter,
/// 0x22: Some Radon request type is not currently supported (1+ args).
UnsupportedHashFunction,
/// 0x23: Some Radon reducer opcode is not currently supported (1+ args)
UnsupportedReducer,
/// 0x24: Some Radon hash function is not currently supported (1+ args).
UnsupportedRequestType,
/// 0x25: Some Radon encoding function is not currently supported (1+ args).
UnsupportedEncodingFunction,
/// Unallocated
Operator0x26, Operator0x27,
/// 0x28: Wrong number (or type) of arguments were passed to some Radon operator.
WrongArguments,
/// Unallocated
Operator0x29, Operator0x2A, Operator0x2B, Operator0x2C, Operator0x2D, Operator0x2E, Operator0x2F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Retrieve-specific circumstantial error sub-codes ================================================================================
/// 0x30: A majority of data sources returned an HTTP status code other than 200 (1+ args):
HttpErrors,
/// 0x31: A majority of data sources timed out:
RetrievalsTimeout,
/// Unallocated
RetrieveCircumstance0x32, RetrieveCircumstance0x33, RetrieveCircumstance0x34, RetrieveCircumstance0x35,
RetrieveCircumstance0x36, RetrieveCircumstance0x37, RetrieveCircumstance0x38, RetrieveCircumstance0x39,
RetrieveCircumstance0x3A, RetrieveCircumstance0x3B, RetrieveCircumstance0x3C, RetrieveCircumstance0x3D,
RetrieveCircumstance0x3E, RetrieveCircumstance0x3F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Scripting-specific runtime error sub-code =========================================================================
/// 0x40: Math operator caused an underflow.
MathUnderflow,
/// 0x41: Math operator caused an overflow.
MathOverflow,
/// 0x42: Math operator tried to divide by zero.
MathDivisionByZero,
/// 0x43:Wrong input to subscript call.
WrongSubscriptInput,
/// 0x44: Value cannot be extracted from input binary buffer.
BufferIsNotValue,
/// 0x45: Value cannot be decoded from expected type.
Decode,
/// 0x46: Unexpected empty array.
EmptyArray,
/// 0x47: Value cannot be encoded to expected type.
Encode,
/// 0x48: Failed to filter input values (1+ args).
Filter,
/// 0x49: Failed to hash input value.
Hash,
/// 0x4A: Mismatching array ranks.
MismatchingArrays,
/// 0x4B: Failed to process non-homogenous array.
NonHomegeneousArray,
/// 0x4C: Failed to parse syntax of some input value, or argument.
Parse,
/// 0x4E: Parsing logic limits were exceeded.
ParseOverflow,
/// 0x4F: Unallocated
ScriptError0x4F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Actual first-order result error codes =============================================================================
/// 0x50: Not enough reveals were received in due time:
InsufficientReveals,
/// 0x51: No actual reveal majority was reached on tally stage:
InsufficientMajority,
/// 0x52: Not enough commits were received before tally stage:
InsufficientCommits,
/// 0x53: Generic error during tally execution (to be deprecated after WIP #0028)
TallyExecution,
/// 0x54: A majority of data sources could either be temporarily unresponsive or failing to report the requested data:
CircumstantialFailure,
/// 0x55: At least one data source is inconsistent when queried through multiple transports at once:
InconsistentSources,
/// 0x56: Any one of the (multiple) Retrieve, Aggregate or Tally scripts were badly formated:
MalformedDataRequest,
/// 0x57: Values returned from a majority of data sources don't match the expected schema:
MalformedResponses,
/// Unallocated:
OtherError0x58, OtherError0x59, OtherError0x5A, OtherError0x5B, OtherError0x5C, OtherError0x5D, OtherError0x5E,
/// 0x5F: Size of serialized tally result exceeds allowance:
OversizedTallyResult,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Inter-stage runtime error sub-codes ===============================================================================
/// 0x60: Data aggregation reveals could not get decoded on the tally stage:
MalformedReveals,
/// 0x61: The result to data aggregation could not get encoded:
EncodeReveals,
/// 0x62: A mode tie ocurred when calculating some mode value on the aggregation or the tally stage:
ModeTie,
/// Unallocated:
OtherError0x63, OtherError0x64, OtherError0x65, OtherError0x66, OtherError0x67, OtherError0x68, OtherError0x69,
OtherError0x6A, OtherError0x6B, OtherError0x6C, OtherError0x6D, OtherError0x6E, OtherError0x6F,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Runtime access error sub-codes ====================================================================================
/// 0x70: Tried to access a value from an array using an index that is out of bounds (1+ args):
ArrayIndexOutOfBounds,
/// 0x71: Tried to access a value from a map using a key that does not exist (1+ args):
MapKeyNotFound,
/// 0X72: Tried to extract value from a map using a JSON Path that returns no values (+1 args):
JsonPathNotFound,
/// Unallocated:
OtherError0x73, OtherError0x74, OtherError0x75, OtherError0x76, OtherError0x77, OtherError0x78,
OtherError0x79, OtherError0x7A, OtherError0x7B, OtherError0x7C, OtherError0x7D, OtherError0x7E, OtherError0x7F,
OtherError0x80, OtherError0x81, OtherError0x82, OtherError0x83, OtherError0x84, OtherError0x85, OtherError0x86,
OtherError0x87, OtherError0x88, OtherError0x89, OtherError0x8A, OtherError0x8B, OtherError0x8C, OtherError0x8D,
OtherError0x8E, OtherError0x8F, OtherError0x90, OtherError0x91, OtherError0x92, OtherError0x93, OtherError0x94,
OtherError0x95, OtherError0x96, OtherError0x97, OtherError0x98, OtherError0x99, OtherError0x9A, OtherError0x9B,
OtherError0x9C, OtherError0x9D, OtherError0x9E, OtherError0x9F, OtherError0xA0, OtherError0xA1, OtherError0xA2,
OtherError0xA3, OtherError0xA4, OtherError0xA5, OtherError0xA6, OtherError0xA7, OtherError0xA8, OtherError0xA9,
OtherError0xAA, OtherError0xAB, OtherError0xAC, OtherError0xAD, OtherError0xAE, OtherError0xAF, OtherError0xB0,
OtherError0xB1, OtherError0xB2, OtherError0xB3, OtherError0xB4, OtherError0xB5, OtherError0xB6, OtherError0xB7,
OtherError0xB8, OtherError0xB9, OtherError0xBA, OtherError0xBB, OtherError0xBC, OtherError0xBD, OtherError0xBE,
OtherError0xBF, OtherError0xC0, OtherError0xC1, OtherError0xC2, OtherError0xC3, OtherError0xC4, OtherError0xC5,
OtherError0xC6, OtherError0xC7, OtherError0xC8, OtherError0xC9, OtherError0xCA, OtherError0xCB, OtherError0xCC,
OtherError0xCD, OtherError0xCE, OtherError0xCF, OtherError0xD0, OtherError0xD1, OtherError0xD2, OtherError0xD3,
OtherError0xD4, OtherError0xD5, OtherError0xD6, OtherError0xD7, OtherError0xD8, OtherError0xD9, OtherError0xDA,
OtherError0xDB, OtherError0xDC, OtherError0xDD, OtherError0xDE, OtherError0xDF,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Inter-client generic error codes ==================================================================================
/// Data requests that cannot be relayed into the Witnet blockchain should be reported
/// with one of these errors.
/// 0xE0: Requests that cannot be parsed must always get this error as their result.
BridgeMalformedDataRequest,
/// 0xE1: Witnesses exceeds 100
BridgePoorIncentives,
/// 0xE2: The request is rejected on the grounds that it may cause the submitter to spend or stake an
/// amount of value that is unjustifiably high when compared with the reward they will be getting
BridgeOversizedTallyResult,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Unallocated =======================================================================================================
OtherError0xE3, OtherError0xE4, OtherError0xE5, OtherError0xE6, OtherError0xE7, OtherError0xE8, OtherError0xE9,
OtherError0xEA, OtherError0xEB, OtherError0xEC, OtherError0xED, OtherError0xEE, OtherError0xEF, OtherError0xF0,
OtherError0xF1, OtherError0xF2, OtherError0xF3, OtherError0xF4, OtherError0xF5, OtherError0xF6, OtherError0xF7,
OtherError0xF8, OtherError0xF9, OtherError0xFA, OtherError0xFB, OtherError0xFC, OtherError0xFD, OtherError0xFE,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 0xFF: Some tally error is not intercepted but it should (0+ args)
UnhandledIntercept
}
function isCircumstantial(ResultErrorCodes self) internal pure returns (bool) {
return (self == ResultErrorCodes.CircumstantialFailure);
}
function lackOfConsensus(ResultErrorCodes self) internal pure returns (bool) {
return (
self == ResultErrorCodes.InsufficientCommits
|| self == ResultErrorCodes.InsufficientMajority
|| self == ResultErrorCodes.InsufficientReveals
);
}
function isRetriable(ResultErrorCodes self) internal pure returns (bool) {
return (
lackOfConsensus(self)
|| isCircumstantial(self)
|| poorIncentives(self)
);
}
function poorIncentives(ResultErrorCodes self) internal pure returns (bool) {
return (
self == ResultErrorCodes.OversizedTallyResult
|| self == ResultErrorCodes.InsufficientCommits
|| self == ResultErrorCodes.BridgePoorIncentives
|| self == ResultErrorCodes.BridgeOversizedTallyResult
);
}
/// Possible Radon data request methods that can be used within a Radon Retrieval.
enum RadonDataRequestMethods {
/* 0 */ Unknown,
/* 1 */ HttpGet,
/* 2 */ RNG,
/* 3 */ HttpPost,
/* 4 */ HttpHead
}
/// Possible types either processed by Witnet Radon Scripts or included within results to Witnet Data Requests.
enum RadonDataTypes {
/* 0x00 */ Any,
/* 0x01 */ Array,
/* 0x02 */ Bool,
/* 0x03 */ Bytes,
/* 0x04 */ Integer,
/* 0x05 */ Float,
/* 0x06 */ Map,
/* 0x07 */ String,
Unused0x08, Unused0x09, Unused0x0A, Unused0x0B,
Unused0x0C, Unused0x0D, Unused0x0E, Unused0x0F,
/* 0x10 */ Same,
/* 0x11 */ Inner,
/* 0x12 */ Match,
/* 0x13 */ Subscript
}
/// Structure defining some data filtering that can be applied at the Aggregation or the Tally stages
/// within a Witnet Data Request resolution workflow.
struct RadonFilter {
RadonFilterOpcodes opcode;
bytes args;
}
/// Filtering methods currently supported on the Witnet blockchain.
enum RadonFilterOpcodes {
/* 0x00 */ Reserved0x00, //GreaterThan,
/* 0x01 */ Reserved0x01, //LessThan,
/* 0x02 */ Reserved0x02, //Equals,
/* 0x03 */ Reserved0x03, //AbsoluteDeviation,
/* 0x04 */ Reserved0x04, //RelativeDeviation
/* 0x05 */ StandardDeviation,
/* 0x06 */ Reserved0x06, //Top,
/* 0x07 */ Reserved0x07, //Bottom,
/* 0x08 */ Mode,
/* 0x09 */ Reserved0x09 //LessOrEqualThan
}
/// Structure defining the array of filters and reducting function to be applied at either the Aggregation
/// or the Tally stages within a Witnet Data Request resolution workflow.
struct RadonReducer {
RadonReducerOpcodes opcode;
RadonFilter[] filters;
}
/// Reducting functions currently supported on the Witnet blockchain.
enum RadonReducerOpcodes {
/* 0x00 */ Reserved0x00, //Minimum,
/* 0x01 */ Reserved0x01, //Maximum,
/* 0x02 */ Mode,
/* 0x03 */ AverageMean,
/* 0x04 */ Reserved0x04, //AverageMeanWeighted,
/* 0x05 */ AverageMedian,
/* 0x06 */ Reserved0x06, //AverageMedianWeighted,
/* 0x07 */ StandardDeviation,
/* 0x08 */ Reserved0x08, //AverageDeviation,
/* 0x09 */ Reserved0x09, //MedianDeviation,
/* 0x0A */ Reserved0x10, //MaximumDeviation,
/* 0x0B */ ConcatenateAndHash
}
/// Structure containing all the parameters that fully describe a Witnet Radon Retrieval within a Witnet Data Request.
struct RadonRetrieval {
uint8 argsCount;
RadonDataRequestMethods method;
RadonDataTypes resultDataType;
string url;
string body;
string[2][] headers;
bytes script;
}
/// Structure containing the Retrieve-Attestation-Delivery parts of a Witnet Data Request.
struct RadonRAD {
RadonRetrieval[] retrieve;
RadonReducer aggregate;
RadonReducer tally;
}
/// Structure containing the Service Level Aggreement parameters of a Witnet Data Request.
struct RadonSLA {
uint8 numWitnesses;
uint8 minConsensusPercentage;
uint64 witnessReward;
uint64 witnessCollateral;
uint64 minerCommitRevealFee;
}
/// ===============================================================================================================
/// --- 'uint*' helper methods ------------------------------------------------------------------------------------
/// @notice Convert a `uint8` into a 2 characters long `string` representing its two less significant hexadecimal values.
function toHexString(uint8 _u)
internal pure
returns (string memory)
{
bytes memory b2 = new bytes(2);
uint8 d0 = uint8(_u / 16) + 48;
uint8 d1 = uint8(_u % 16) + 48;
if (d0 > 57)
d0 += 7;
if (d1 > 57)
d1 += 7;
b2[0] = bytes1(d0);
b2[1] = bytes1(d1);
return string(b2);
}
/// @notice Convert a `uint8` into a 1, 2 or 3 characters long `string` representing its.
/// three less significant decimal values.
function toString(uint8 _u)
internal pure
returns (string memory)
{
if (_u < 10) {
bytes memory b1 = new bytes(1);
b1[0] = bytes1(uint8(_u) + 48);
return string(b1);
} else if (_u < 100) {
bytes memory b2 = new bytes(2);
b2[0] = bytes1(uint8(_u / 10) + 48);
b2[1] = bytes1(uint8(_u % 10) + 48);
return string(b2);
} else {
bytes memory b3 = new bytes(3);
b3[0] = bytes1(uint8(_u / 100) + 48);
b3[1] = bytes1(uint8(_u % 100 / 10) + 48);
b3[2] = bytes1(uint8(_u % 10) + 48);
return string(b3);
}
}
/// @notice Convert a `uint` into a string` representing its value.
function toString(uint v)
internal pure
returns (string memory)
{
uint maxlength = 100;
bytes memory reversed = new bytes(maxlength);
uint i = 0;
do {
uint8 remainder = uint8(v % 10);
v = v / 10;
reversed[i ++] = bytes1(48 + remainder);
} while (v != 0);
bytes memory buf = new bytes(i);
for (uint j = 1; j <= i; j ++) {
buf[j - 1] = reversed[i - j];
}
return string(buf);
}
/// ===============================================================================================================
/// --- 'bytes' helper methods ------------------------------------------------------------------------------------
/// @dev Transform given bytes into a Witnet.Result instance.
/// @param cborBytes Raw bytes representing a CBOR-encoded value.
/// @return A `Witnet.Result` instance.
function toWitnetResult(bytes memory cborBytes)
internal pure
returns (Witnet.Result memory)
{
WitnetCBOR.CBOR memory cborValue = WitnetCBOR.fromBytes(cborBytes);
return _resultFromCborValue(cborValue);
}
function toAddress(bytes memory _value) internal pure returns (address) {
return address(toBytes20(_value));
}
function toBytes4(bytes memory _value) internal pure returns (bytes4) {
return bytes4(toFixedBytes(_value, 4));
}
function toBytes20(bytes memory _value) internal pure returns (bytes20) {
return bytes20(toFixedBytes(_value, 20));
}
function toBytes32(bytes memory _value) internal pure returns (bytes32) {
return toFixedBytes(_value, 32);
}
function toFixedBytes(bytes memory _value, uint8 _numBytes)
internal pure
returns (bytes32 _bytes32)
{
assert(_numBytes <= 32);
unchecked {
uint _len = _value.length > _numBytes ? _numBytes : _value.length;
for (uint _i = 0; _i < _len; _i ++) {
_bytes32 |= bytes32(_value[_i] & 0xff) >> (_i * 8);
}
}
}
/// ===============================================================================================================
/// --- 'string' helper methods -----------------------------------------------------------------------------------
function toLowerCase(string memory str)
internal pure
returns (string memory)
{
bytes memory lowered = new bytes(bytes(str).length);
unchecked {
for (uint i = 0; i < lowered.length; i ++) {
uint8 char = uint8(bytes(str)[i]);
if (char >= 65 && char <= 90) {
lowered[i] = bytes1(char + 32);
} else {
lowered[i] = bytes1(char);
}
}
}
return string(lowered);
}
/// @notice Converts bytes32 into string.
function toString(bytes32 _bytes32)
internal pure
returns (string memory)
{
bytes memory _bytes = new bytes(_toStringLength(_bytes32));
for (uint _i = 0; _i < _bytes.length;) {
_bytes[_i] = _bytes32[_i];
unchecked {
_i ++;
}
}
return string(_bytes);
}
function tryUint(string memory str)
internal pure
returns (uint res, bool)
{
unchecked {
for (uint256 i = 0; i < bytes(str).length; i++) {
if (
(uint8(bytes(str)[i]) - 48) < 0
|| (uint8(bytes(str)[i]) - 48) > 9
) {
return (0, false);
}
res += (uint8(bytes(str)[i]) - 48) * 10 ** (bytes(str).length - i - 1);
}
return (res, true);
}
}
/// ===============================================================================================================
/// --- 'Witnet.Result' helper methods ----------------------------------------------------------------------------
modifier _isReady(Result memory result) {
require(result.success, "Witnet: tried to decode value from errored result.");
_;
}
/// @dev Decode an address from the Witnet.Result's CBOR value.
function asAddress(Witnet.Result memory result)
internal pure
_isReady(result)
returns (address)
{
if (result.value.majorType == uint8(WitnetCBOR.MAJOR_TYPE_BYTES)) {
return toAddress(result.value.readBytes());
} else {
// TODO
revert("WitnetLib: reading address from string not yet supported.");
}
}
/// @dev Decode a `bool` value from the Witnet.Result's CBOR value.
function asBool(Witnet.Result memory result)
internal pure
_isReady(result)
returns (bool)
{
return result.value.readBool();
}
/// @dev Decode a `bytes` value from the Witnet.Result's CBOR value.
function asBytes(Witnet.Result memory result)
internal pure
_isReady(result)
returns(bytes memory)
{
return result.value.readBytes();
}
/// @dev Decode a `bytes4` value from the Witnet.Result's CBOR value.
function asBytes4(Witnet.Result memory result)
internal pure
_isReady(result)
returns (bytes4)
{
return toBytes4(asBytes(result));
}
/// @dev Decode a `bytes32` value from the Witnet.Result's CBOR value.
function asBytes32(Witnet.Result memory result)
internal pure
_isReady(result)
returns (bytes32)
{
return toBytes32(asBytes(result));
}
/// @notice Returns the Witnet.Result's unread CBOR value.
function asCborValue(Witnet.Result memory result)
internal pure
_isReady(result)
returns (WitnetCBOR.CBOR memory)
{
return result.value;
}
/// @notice Decode array of CBOR values from the Witnet.Result's CBOR value.
function asCborArray(Witnet.Result memory result)
internal pure
_isReady(result)
returns (WitnetCBOR.CBOR[] memory)
{
return result.value.readArray();
}
/// @dev Decode a fixed16 (half-precision) numeric value from the Witnet.Result's CBOR value.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values.
/// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`.
/// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
function asFixed16(Witnet.Result memory result)
internal pure
_isReady(result)
returns (int32)
{
return result.value.readFloat16();
}
/// @dev Decode an array of fixed16 values from the Witnet.Result's CBOR value.
function asFixed16Array(Witnet.Result memory result)
internal pure
_isReady(result)
returns (int32[] memory)
{
return result.value.readFloat16Array();
}
/// @dev Decode an `int64` value from the Witnet.Result's CBOR value.
function asInt(Witnet.Result memory result)
internal pure
_isReady(result)
returns (int)
{
return result.value.readInt();
}
/// @dev Decode an array of integer numeric values from a Witnet.Result as an `int[]` array.
/// @param result An instance of Witnet.Result.
/// @return The `int[]` decoded from the Witnet.Result.
function asIntArray(Witnet.Result memory result)
internal pure
_isReady(result)
returns (int[] memory)
{
return result.value.readIntArray();
}
/// @dev Decode a `string` value from the Witnet.Result's CBOR value.
/// @param result An instance of Witnet.Result.
/// @return The `string` decoded from the Witnet.Result.
function asText(Witnet.Result memory result)
internal pure
_isReady(result)
returns(string memory)
{
return result.value.readString();
}
/// @dev Decode an array of strings from the Witnet.Result's CBOR value.
/// @param result An instance of Witnet.Result.
/// @return The `string[]` decoded from the Witnet.Result.
function asTextArray(Witnet.Result memory result)
internal pure
_isReady(result)
returns (string[] memory)
{
return result.value.readStringArray();
}
/// @dev Decode a `uint64` value from the Witnet.Result's CBOR value.
/// @param result An instance of Witnet.Result.
/// @return The `uint` decoded from the Witnet.Result.
function asUint(Witnet.Result memory result)
internal pure
_isReady(result)
returns (uint)
{
return result.value.readUint();
}
/// @dev Decode an array of `uint64` values from the Witnet.Result's CBOR value.
/// @param result An instance of Witnet.Result.
/// @return The `uint[]` decoded from the Witnet.Result.
function asUintArray(Witnet.Result memory result)
internal pure
returns (uint[] memory)
{
return result.value.readUintArray();
}
/// ===============================================================================================================
/// --- Witnet library private methods ----------------------------------------------------------------------------
/// @dev Decode a CBOR value into a Witnet.Result instance.
function _resultFromCborValue(WitnetCBOR.CBOR memory cbor)
private pure
returns (Witnet.Result memory)
{
// Witnet uses CBOR tag 39 to represent RADON error code identifiers.
// [CBOR tag 39] Identifiers for CBOR: https://github.com/lucas-clemente/cbor-specs/blob/master/id.md
bool success = cbor.tag != 39;
return Witnet.Result(success, cbor);
}
/// @dev Calculate length of string-equivalent to given bytes32.
function _toStringLength(bytes32 _bytes32)
private pure
returns (uint _length)
{
for (; _length < 32; ) {
if (_bytes32[_length] == 0) {
break;
}
unchecked {
_length ++;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
/// @title A convenient wrapper around the `bytes memory` type that exposes a buffer-like interface
/// @notice The buffer has an inner cursor that tracks the final offset of every read, i.e. any subsequent read will
/// start with the byte that goes right after the last one in the previous read.
/// @dev `uint32` is used here for `cursor` because `uint16` would only enable seeking up to 8KB, which could in some
/// theoretical use cases be exceeded. Conversely, `uint32` supports up to 512MB, which cannot credibly be exceeded.
/// @author The Witnet Foundation.
library WitnetBuffer {
error EmptyBuffer();
error IndexOutOfBounds(uint index, uint range);
error MissingArgs(uint expected, uint given);
/// Iterable bytes buffer.
struct Buffer {
bytes data;
uint cursor;
}
// Ensures we access an existing index in an array
modifier withinRange(uint index, uint _range) {
if (index > _range) {
revert IndexOutOfBounds(index, _range);
}
_;
}
/// @notice Concatenate undefinite number of bytes chunks.
/// @dev Faster than looping on `abi.encodePacked(output, _buffs[ix])`.
function concat(bytes[] memory _buffs)
internal pure
returns (bytes memory output)
{
unchecked {
uint destinationPointer;
uint destinationLength;
assembly {
// get safe scratch location
output := mload(0x40)
// set starting destination pointer
destinationPointer := add(output, 32)
}
for (uint ix = 1; ix <= _buffs.length; ix ++) {
uint source;
uint sourceLength;
uint sourcePointer;
assembly {
// load source length pointer
source := mload(add(_buffs, mul(ix, 32)))
// load source length
sourceLength := mload(source)
// sets source memory pointer
sourcePointer := add(source, 32)
}
memcpy(
destinationPointer,
sourcePointer,
sourceLength
);
assembly {
// increase total destination length
destinationLength := add(destinationLength, sourceLength)
// sets destination memory pointer
destinationPointer := add(destinationPointer, sourceLength)
}
}
assembly {
// protect output bytes
mstore(output, destinationLength)
// set final output length
mstore(0x40, add(mload(0x40), add(destinationLength, 32)))
}
}
}
function fork(WitnetBuffer.Buffer memory buffer)
internal pure
returns (WitnetBuffer.Buffer memory)
{
return Buffer(
buffer.data,
buffer.cursor
);
}
function mutate(
WitnetBuffer.Buffer memory buffer,
uint length,
bytes memory pokes
)
internal pure
withinRange(length, buffer.data.length - buffer.cursor + 1)
{
bytes[] memory parts = new bytes[](3);
parts[0] = peek(
buffer,
0,
buffer.cursor
);
parts[1] = pokes;
parts[2] = peek(
buffer,
buffer.cursor + length,
buffer.data.length - buffer.cursor - length
);
buffer.data = concat(parts);
}
/// @notice Read and consume the next byte from the buffer.
/// @param buffer An instance of `Buffer`.
/// @return The next byte in the buffer counting from the cursor position.
function next(Buffer memory buffer)
internal pure
withinRange(buffer.cursor, buffer.data.length)
returns (bytes1)
{
// Return the byte at the position marked by the cursor and advance the cursor all at once
return buffer.data[buffer.cursor ++];
}
function peek(
WitnetBuffer.Buffer memory buffer,
uint offset,
uint length
)
internal pure
withinRange(offset + length, buffer.data.length)
returns (bytes memory)
{
bytes memory data = buffer.data;
bytes memory peeks = new bytes(length);
uint destinationPointer;
uint sourcePointer;
assembly {
destinationPointer := add(peeks, 32)
sourcePointer := add(add(data, 32), offset)
}
memcpy(
destinationPointer,
sourcePointer,
length
);
return peeks;
}
// @notice Extract bytes array from buffer starting from current cursor.
/// @param buffer An instance of `Buffer`.
/// @param length How many bytes to peek from the Buffer.
// solium-disable-next-line security/no-assign-params
function peek(
WitnetBuffer.Buffer memory buffer,
uint length
)
internal pure
withinRange(length, buffer.data.length - buffer.cursor)
returns (bytes memory)
{
return peek(
buffer,
buffer.cursor,
length
);
}
/// @notice Read and consume a certain amount of bytes from the buffer.
/// @param buffer An instance of `Buffer`.
/// @param length How many bytes to read and consume from the buffer.
/// @return output A `bytes memory` containing the first `length` bytes from the buffer, counting from the cursor position.
function read(Buffer memory buffer, uint length)
internal pure
withinRange(buffer.cursor + length, buffer.data.length)
returns (bytes memory output)
{
// Create a new `bytes memory destination` value
output = new bytes(length);
// Early return in case that bytes length is 0
if (length > 0) {
bytes memory input = buffer.data;
uint offset = buffer.cursor;
// Get raw pointers for source and destination
uint sourcePointer;
uint destinationPointer;
assembly {
sourcePointer := add(add(input, 32), offset)
destinationPointer := add(output, 32)
}
// Copy `length` bytes from source to destination
memcpy(
destinationPointer,
sourcePointer,
length
);
// Move the cursor forward by `length` bytes
seek(
buffer,
length,
true
);
}
}
/// @notice Read and consume the next 2 bytes from the buffer as an IEEE 754-2008 floating point number enclosed in an
/// `int32`.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `float16`
/// use cases. In other words, the integer output of this method is 10,000 times the actual value. The input bytes are
/// expected to follow the 16-bit base-2 format (a.k.a. `binary16`) in the IEEE 754-2008 standard.
/// @param buffer An instance of `Buffer`.
/// @return result The `int32` value of the next 4 bytes in the buffer counting from the cursor position.
function readFloat16(Buffer memory buffer)
internal pure
returns (int32 result)
{
uint32 value = readUint16(buffer);
// Get bit at position 0
uint32 sign = value & 0x8000;
// Get bits 1 to 5, then normalize to the [-15, 16] range so as to counterweight the IEEE 754 exponent bias
int32 exponent = (int32(value & 0x7c00) >> 10) - 15;
// Get bits 6 to 15
int32 fraction = int32(value & 0x03ff);
// Add 2^10 to the fraction if exponent is not -15
if (exponent != -15) {
fraction |= 0x400;
} else if (exponent == 16) {
revert(
string(abi.encodePacked(
"WitnetBuffer.readFloat16: ",
sign != 0 ? "negative" : hex"",
" infinity"
))
);
}
// Compute `2 ^ exponent · (1 + fraction / 1024)`
if (exponent >= 0) {
result = int32(int(
int(1 << uint256(int256(exponent)))
* 10000
* fraction
) >> 10);
} else {
result = int32(int(
int(fraction)
* 10000
/ int(1 << uint(int(- exponent)))
) >> 10);
}
// Make the result negative if the sign bit is not 0
if (sign != 0) {
result *= -1;
}
}
/// @notice Consume the next 4 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `float32`
/// use cases. In other words, the integer output of this method is 10^9 times the actual value. The input bytes are
/// expected to follow the 64-bit base-2 format (a.k.a. `binary32`) in the IEEE 754-2008 standard.
/// @param buffer An instance of `Buffer`.
/// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
function readFloat32(Buffer memory buffer)
internal pure
returns (int result)
{
uint value = readUint32(buffer);
// Get bit at position 0
uint sign = value & 0x80000000;
// Get bits 1 to 8, then normalize to the [-127, 128] range so as to counterweight the IEEE 754 exponent bias
int exponent = (int(value & 0x7f800000) >> 23) - 127;
// Get bits 9 to 31
int fraction = int(value & 0x007fffff);
// Add 2^23 to the fraction if exponent is not -127
if (exponent != -127) {
fraction |= 0x800000;
} else if (exponent == 128) {
revert(
string(abi.encodePacked(
"WitnetBuffer.readFloat32: ",
sign != 0 ? "negative" : hex"",
" infinity"
))
);
}
// Compute `2 ^ exponent · (1 + fraction / 2^23)`
if (exponent >= 0) {
result = (
int(1 << uint(exponent))
* (10 ** 9)
* fraction
) >> 23;
} else {
result = (
fraction
* (10 ** 9)
/ int(1 << uint(-exponent))
) >> 23;
}
// Make the result negative if the sign bit is not 0
if (sign != 0) {
result *= -1;
}
}
/// @notice Consume the next 8 bytes from the buffer as an IEEE 754-2008 floating point number enclosed into an `int`.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `float64`
/// use cases. In other words, the integer output of this method is 10^15 times the actual value. The input bytes are
/// expected to follow the 64-bit base-2 format (a.k.a. `binary64`) in the IEEE 754-2008 standard.
/// @param buffer An instance of `Buffer`.
/// @return result The `int` value of the next 8 bytes in the buffer counting from the cursor position.
function readFloat64(Buffer memory buffer)
internal pure
returns (int result)
{
uint value = readUint64(buffer);
// Get bit at position 0
uint sign = value & 0x8000000000000000;
// Get bits 1 to 12, then normalize to the [-1023, 1024] range so as to counterweight the IEEE 754 exponent bias
int exponent = (int(value & 0x7ff0000000000000) >> 52) - 1023;
// Get bits 6 to 15
int fraction = int(value & 0x000fffffffffffff);
// Add 2^52 to the fraction if exponent is not -1023
if (exponent != -1023) {
fraction |= 0x10000000000000;
} else if (exponent == 1024) {
revert(
string(abi.encodePacked(
"WitnetBuffer.readFloat64: ",
sign != 0 ? "negative" : hex"",
" infinity"
))
);
}
// Compute `2 ^ exponent · (1 + fraction / 1024)`
if (exponent >= 0) {
result = (
int(1 << uint(exponent))
* (10 ** 15)
* fraction
) >> 52;
} else {
result = (
fraction
* (10 ** 15)
/ int(1 << uint(-exponent))
) >> 52;
}
// Make the result negative if the sign bit is not 0
if (sign != 0) {
result *= -1;
}
}
// Read a text string of a given length from a buffer. Returns a `bytes memory` value for the sake of genericness,
/// but it can be easily casted into a string with `string(result)`.
// solium-disable-next-line security/no-assign-params
function readText(
WitnetBuffer.Buffer memory buffer,
uint64 length
)
internal pure
returns (bytes memory text)
{
text = new bytes(length);
unchecked {
for (uint64 index = 0; index < length; index ++) {
uint8 char = readUint8(buffer);
if (char & 0x80 != 0) {
if (char < 0xe0) {
char = (char & 0x1f) << 6
| (readUint8(buffer) & 0x3f);
length -= 1;
} else if (char < 0xf0) {
char = (char & 0x0f) << 12
| (readUint8(buffer) & 0x3f) << 6
| (readUint8(buffer) & 0x3f);
length -= 2;
} else {
char = (char & 0x0f) << 18
| (readUint8(buffer) & 0x3f) << 12
| (readUint8(buffer) & 0x3f) << 6
| (readUint8(buffer) & 0x3f);
length -= 3;
}
}
text[index] = bytes1(char);
}
// Adjust text to actual length:
assembly {
mstore(text, length)
}
}
}
/// @notice Read and consume the next byte from the buffer as an `uint8`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint8` value of the next byte in the buffer counting from the cursor position.
function readUint8(Buffer memory buffer)
internal pure
withinRange(buffer.cursor, buffer.data.length)
returns (uint8 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 1), offset))
}
buffer.cursor ++;
}
/// @notice Read and consume the next 2 bytes from the buffer as an `uint16`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint16` value of the next 2 bytes in the buffer counting from the cursor position.
function readUint16(Buffer memory buffer)
internal pure
withinRange(buffer.cursor + 2, buffer.data.length)
returns (uint16 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 2), offset))
}
buffer.cursor += 2;
}
/// @notice Read and consume the next 4 bytes from the buffer as an `uint32`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint32` value of the next 4 bytes in the buffer counting from the cursor position.
function readUint32(Buffer memory buffer)
internal pure
withinRange(buffer.cursor + 4, buffer.data.length)
returns (uint32 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 4), offset))
}
buffer.cursor += 4;
}
/// @notice Read and consume the next 8 bytes from the buffer as an `uint64`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint64` value of the next 8 bytes in the buffer counting from the cursor position.
function readUint64(Buffer memory buffer)
internal pure
withinRange(buffer.cursor + 8, buffer.data.length)
returns (uint64 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 8), offset))
}
buffer.cursor += 8;
}
/// @notice Read and consume the next 16 bytes from the buffer as an `uint128`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint128` value of the next 16 bytes in the buffer counting from the cursor position.
function readUint128(Buffer memory buffer)
internal pure
withinRange(buffer.cursor + 16, buffer.data.length)
returns (uint128 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 16), offset))
}
buffer.cursor += 16;
}
/// @notice Read and consume the next 32 bytes from the buffer as an `uint256`.
/// @param buffer An instance of `Buffer`.
/// @return value The `uint256` value of the next 32 bytes in the buffer counting from the cursor position.
function readUint256(Buffer memory buffer)
internal pure
withinRange(buffer.cursor + 32, buffer.data.length)
returns (uint256 value)
{
bytes memory data = buffer.data;
uint offset = buffer.cursor;
assembly {
value := mload(add(add(data, 32), offset))
}
buffer.cursor += 32;
}
/// @notice Count number of required parameters for given bytes arrays
/// @dev Wildcard format: "\#\", with # in ["0".."9"].
/// @param input Bytes array containing strings.
/// @param count Highest wildcard index found, plus 1.
function argsCountOf(bytes memory input)
internal pure
returns (uint8 count)
{
if (input.length < 3) {
return 0;
}
unchecked {
uint ix = 0;
uint length = input.length - 2;
for (; ix < length; ) {
if (
input[ix] == bytes1("\\")
&& input[ix + 2] == bytes1("\\")
&& input[ix + 1] >= bytes1("0")
&& input[ix + 1] <= bytes1("9")
) {
uint8 ax = uint8(uint8(input[ix + 1]) - uint8(bytes1("0")) + 1);
if (ax > count) {
count = ax;
}
ix += 3;
} else {
ix ++;
}
}
}
}
/// @notice Replace bytecode indexed wildcards by correspondent substrings.
/// @dev Wildcard format: "\#\", with # in ["0".."9"].
/// @param input Bytes array containing strings.
/// @param args Array of substring values for replacing indexed wildcards.
/// @return output Resulting bytes array after replacing all wildcards.
/// @return hits Total number of replaced wildcards.
function replace(bytes memory input, string[] memory args)
internal pure
returns (bytes memory output, uint hits)
{
uint ix = 0; uint lix = 0;
uint inputLength;
uint inputPointer;
uint outputLength;
uint outputPointer;
uint source;
uint sourceLength;
uint sourcePointer;
if (input.length < 3) {
return (input, 0);
}
assembly {
// set starting input pointer
inputPointer := add(input, 32)
// get safe output location
output := mload(0x40)
// set starting output pointer
outputPointer := add(output, 32)
}
unchecked {
uint length = input.length - 2;
for (; ix < length; ) {
if (
input[ix] == bytes1("\\")
&& input[ix + 2] == bytes1("\\")
&& input[ix + 1] >= bytes1("0")
&& input[ix + 1] <= bytes1("9")
) {
inputLength = (ix - lix);
if (ix > lix) {
memcpy(
outputPointer,
inputPointer,
inputLength
);
inputPointer += inputLength + 3;
outputPointer += inputLength;
} else {
inputPointer += 3;
}
uint ax = uint(uint8(input[ix + 1]) - uint8(bytes1("0")));
if (ax >= args.length) {
revert MissingArgs(ax + 1, args.length);
}
assembly {
source := mload(add(args, mul(32, add(ax, 1))))
sourceLength := mload(source)
sourcePointer := add(source, 32)
}
memcpy(
outputPointer,
sourcePointer,
sourceLength
);
outputLength += inputLength + sourceLength;
outputPointer += sourceLength;
ix += 3;
lix = ix;
hits ++;
} else {
ix ++;
}
}
ix = input.length;
}
if (outputLength > 0) {
if (ix > lix ) {
memcpy(
outputPointer,
inputPointer,
ix - lix
);
outputLength += (ix - lix);
}
assembly {
// set final output length
mstore(output, outputLength)
// protect output bytes
mstore(0x40, add(mload(0x40), add(outputLength, 32)))
}
}
else {
return (input, 0);
}
}
/// @notice Replace string indexed wildcards by correspondent substrings.
/// @dev Wildcard format: "\#\", with # in ["0".."9"].
/// @param input String potentially containing wildcards.
/// @param args Array of substring values for replacing indexed wildcards.
/// @return output Resulting string after replacing all wildcards.
function replace(string memory input, string[] memory args)
internal pure
returns (string memory)
{
(bytes memory _outputBytes, ) = replace(bytes(input), args);
return string(_outputBytes);
}
/// @notice Move the inner cursor of the buffer to a relative or absolute position.
/// @param buffer An instance of `Buffer`.
/// @param offset How many bytes to move the cursor forward.
/// @param relative Whether to count `offset` from the last position of the cursor (`true`) or the beginning of the
/// buffer (`true`).
/// @return The final position of the cursor (will equal `offset` if `relative` is `false`).
// solium-disable-next-line security/no-assign-params
function seek(
Buffer memory buffer,
uint offset,
bool relative
)
internal pure
withinRange(offset, buffer.data.length)
returns (uint)
{
// Deal with relative offsets
if (relative) {
offset += buffer.cursor;
}
buffer.cursor = offset;
return offset;
}
/// @notice Move the inner cursor a number of bytes forward.
/// @dev This is a simple wrapper around the relative offset case of `seek()`.
/// @param buffer An instance of `Buffer`.
/// @param relativeOffset How many bytes to move the cursor forward.
/// @return The final position of the cursor.
function seek(
Buffer memory buffer,
uint relativeOffset
)
internal pure
returns (uint)
{
return seek(
buffer,
relativeOffset,
true
);
}
/// @notice Copy bytes from one memory address into another.
/// @dev This function was borrowed from Nick Johnson's `solidity-stringutils` lib, and reproduced here under the terms
/// of [Apache License 2.0](https://github.com/Arachnid/solidity-stringutils/blob/master/LICENSE).
/// @param dest Address of the destination memory.
/// @param src Address to the source memory.
/// @param len How many bytes to copy.
// solium-disable-next-line security/no-assign-params
function memcpy(
uint dest,
uint src,
uint len
)
private pure
{
unchecked {
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
if (len > 0) {
// Copy remaining bytes
uint _mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(_mask))
let destpart := and(mload(dest), _mask)
mstore(dest, or(destpart, srcpart))
}
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
import "./WitnetBuffer.sol";
/// @title A minimalistic implementation of “RFC 7049 Concise Binary Object Representation”
/// @notice This library leverages a buffer-like structure for step-by-step decoding of bytes so as to minimize
/// the gas cost of decoding them into a useful native type.
/// @dev Most of the logic has been borrowed from Patrick Gansterer’s cbor.js library: https://github.com/paroga/cbor-js
/// @author The Witnet Foundation.
library WitnetCBOR {
using WitnetBuffer for WitnetBuffer.Buffer;
using WitnetCBOR for WitnetCBOR.CBOR;
/// Data struct following the RFC-7049 standard: Concise Binary Object Representation.
struct CBOR {
WitnetBuffer.Buffer buffer;
uint8 initialByte;
uint8 majorType;
uint8 additionalInformation;
uint64 len;
uint64 tag;
}
uint8 internal constant MAJOR_TYPE_INT = 0;
uint8 internal constant MAJOR_TYPE_NEGATIVE_INT = 1;
uint8 internal constant MAJOR_TYPE_BYTES = 2;
uint8 internal constant MAJOR_TYPE_STRING = 3;
uint8 internal constant MAJOR_TYPE_ARRAY = 4;
uint8 internal constant MAJOR_TYPE_MAP = 5;
uint8 internal constant MAJOR_TYPE_TAG = 6;
uint8 internal constant MAJOR_TYPE_CONTENT_FREE = 7;
uint32 internal constant UINT32_MAX = type(uint32).max;
uint64 internal constant UINT64_MAX = type(uint64).max;
error EmptyArray();
error InvalidLengthEncoding(uint length);
error UnexpectedMajorType(uint read, uint expected);
error UnsupportedPrimitive(uint primitive);
error UnsupportedMajorType(uint unexpected);
modifier isMajorType(
WitnetCBOR.CBOR memory cbor,
uint8 expected
) {
if (cbor.majorType != expected) {
revert UnexpectedMajorType(cbor.majorType, expected);
}
_;
}
modifier notEmpty(WitnetBuffer.Buffer memory buffer) {
if (buffer.data.length == 0) {
revert WitnetBuffer.EmptyBuffer();
}
_;
}
function eof(CBOR memory cbor)
internal pure
returns (bool)
{
return cbor.buffer.cursor >= cbor.buffer.data.length;
}
/// @notice Decode a CBOR structure from raw bytes.
/// @dev This is the main factory for CBOR instances, which can be later decoded into native EVM types.
/// @param bytecode Raw bytes representing a CBOR-encoded value.
/// @return A `CBOR` instance containing a partially decoded value.
function fromBytes(bytes memory bytecode)
internal pure
returns (CBOR memory)
{
WitnetBuffer.Buffer memory buffer = WitnetBuffer.Buffer(bytecode, 0);
return fromBuffer(buffer);
}
/// @notice Decode a CBOR structure from raw bytes.
/// @dev This is an alternate factory for CBOR instances, which can be later decoded into native EVM types.
/// @param buffer A Buffer structure representing a CBOR-encoded value.
/// @return A `CBOR` instance containing a partially decoded value.
function fromBuffer(WitnetBuffer.Buffer memory buffer)
internal pure
notEmpty(buffer)
returns (CBOR memory)
{
uint8 initialByte;
uint8 majorType = 255;
uint8 additionalInformation;
uint64 tag = UINT64_MAX;
uint256 len;
bool isTagged = true;
while (isTagged) {
// Extract basic CBOR properties from input bytes
initialByte = buffer.readUint8();
len ++;
majorType = initialByte >> 5;
additionalInformation = initialByte & 0x1f;
// Early CBOR tag parsing.
if (majorType == MAJOR_TYPE_TAG) {
uint _cursor = buffer.cursor;
tag = readLength(buffer, additionalInformation);
len += buffer.cursor - _cursor;
} else {
isTagged = false;
}
}
if (majorType > MAJOR_TYPE_CONTENT_FREE) {
revert UnsupportedMajorType(majorType);
}
return CBOR(
buffer,
initialByte,
majorType,
additionalInformation,
uint64(len),
tag
);
}
function fork(WitnetCBOR.CBOR memory self)
internal pure
returns (WitnetCBOR.CBOR memory)
{
return CBOR({
buffer: self.buffer.fork(),
initialByte: self.initialByte,
majorType: self.majorType,
additionalInformation: self.additionalInformation,
len: self.len,
tag: self.tag
});
}
function settle(CBOR memory self)
internal pure
returns (WitnetCBOR.CBOR memory)
{
if (!self.eof()) {
return fromBuffer(self.buffer);
} else {
return self;
}
}
function skip(CBOR memory self)
internal pure
returns (WitnetCBOR.CBOR memory)
{
if (
self.majorType == MAJOR_TYPE_INT
|| self.majorType == MAJOR_TYPE_NEGATIVE_INT
|| (
self.majorType == MAJOR_TYPE_CONTENT_FREE
&& self.additionalInformation >= 25
&& self.additionalInformation <= 27
)
) {
self.buffer.cursor += self.peekLength();
} else if (
self.majorType == MAJOR_TYPE_STRING
|| self.majorType == MAJOR_TYPE_BYTES
) {
uint64 len = readLength(self.buffer, self.additionalInformation);
self.buffer.cursor += len;
} else if (
self.majorType == MAJOR_TYPE_ARRAY
|| self.majorType == MAJOR_TYPE_MAP
) {
self.len = readLength(self.buffer, self.additionalInformation);
} else if (
self.majorType != MAJOR_TYPE_CONTENT_FREE
|| (
self.additionalInformation != 20
&& self.additionalInformation != 21
)
) {
revert("WitnetCBOR.skip: unsupported major type");
}
return self;
}
function peekLength(CBOR memory self)
internal pure
returns (uint64)
{
if (self.additionalInformation < 24) {
return 0;
} else if (self.additionalInformation < 28) {
return uint64(1 << (self.additionalInformation - 24));
} else {
revert InvalidLengthEncoding(self.additionalInformation);
}
}
function readArray(CBOR memory self)
internal pure
isMajorType(self, MAJOR_TYPE_ARRAY)
returns (CBOR[] memory items)
{
// read array's length and move self cursor forward to the first array element:
uint64 len = readLength(self.buffer, self.additionalInformation);
items = new CBOR[](len + 1);
for (uint ix = 0; ix < len; ix ++) {
// settle next element in the array:
self = self.settle();
// fork it and added to the list of items to be returned:
items[ix] = self.fork();
if (self.majorType == MAJOR_TYPE_ARRAY) {
CBOR[] memory _subitems = self.readArray();
// move forward to the first element after inner array:
self = _subitems[_subitems.length - 1];
} else if (self.majorType == MAJOR_TYPE_MAP) {
CBOR[] memory _subitems = self.readMap();
// move forward to the first element after inner map:
self = _subitems[_subitems.length - 1];
} else {
// move forward to the next element:
self.skip();
}
}
// return self cursor as extra item at the end of the list,
// as to optimize recursion when jumping over nested arrays:
items[len] = self;
}
function readMap(CBOR memory self)
internal pure
isMajorType(self, MAJOR_TYPE_MAP)
returns (CBOR[] memory items)
{
// read number of items within the map and move self cursor forward to the first inner element:
uint64 len = readLength(self.buffer, self.additionalInformation) * 2;
items = new CBOR[](len + 1);
for (uint ix = 0; ix < len; ix ++) {
// settle next element in the array:
self = self.settle();
// fork it and added to the list of items to be returned:
items[ix] = self.fork();
if (ix % 2 == 0 && self.majorType != MAJOR_TYPE_STRING) {
revert UnexpectedMajorType(self.majorType, MAJOR_TYPE_STRING);
} else if (self.majorType == MAJOR_TYPE_ARRAY || self.majorType == MAJOR_TYPE_MAP) {
CBOR[] memory _subitems = (self.majorType == MAJOR_TYPE_ARRAY
? self.readArray()
: self.readMap()
);
// move forward to the first element after inner array or map:
self = _subitems[_subitems.length - 1];
} else {
// move forward to the next element:
self.skip();
}
}
// return self cursor as extra item at the end of the list,
// as to optimize recursion when jumping over nested arrays:
items[len] = self;
}
/// Reads the length of the settle CBOR item from a buffer, consuming a different number of bytes depending on the
/// value of the `additionalInformation` argument.
function readLength(
WitnetBuffer.Buffer memory buffer,
uint8 additionalInformation
)
internal pure
returns (uint64)
{
if (additionalInformation < 24) {
return additionalInformation;
}
if (additionalInformation == 24) {
return buffer.readUint8();
}
if (additionalInformation == 25) {
return buffer.readUint16();
}
if (additionalInformation == 26) {
return buffer.readUint32();
}
if (additionalInformation == 27) {
return buffer.readUint64();
}
if (additionalInformation == 31) {
return UINT64_MAX;
}
revert InvalidLengthEncoding(additionalInformation);
}
/// @notice Read a `CBOR` structure into a native `bool` value.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as a `bool` value.
function readBool(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
returns (bool)
{
if (cbor.additionalInformation == 20) {
return false;
} else if (cbor.additionalInformation == 21) {
return true;
} else {
revert UnsupportedPrimitive(cbor.additionalInformation);
}
}
/// @notice Decode a `CBOR` structure into a native `bytes` value.
/// @param cbor An instance of `CBOR`.
/// @return output The value represented by the input, as a `bytes` value.
function readBytes(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_BYTES)
returns (bytes memory output)
{
cbor.len = readLength(
cbor.buffer,
cbor.additionalInformation
);
if (cbor.len == UINT32_MAX) {
// These checks look repetitive but the equivalent loop would be more expensive.
uint32 length = uint32(_readIndefiniteStringLength(
cbor.buffer,
cbor.majorType
));
if (length < UINT32_MAX) {
output = abi.encodePacked(cbor.buffer.read(length));
length = uint32(_readIndefiniteStringLength(
cbor.buffer,
cbor.majorType
));
if (length < UINT32_MAX) {
output = abi.encodePacked(
output,
cbor.buffer.read(length)
);
}
}
} else {
return cbor.buffer.read(uint32(cbor.len));
}
}
/// @notice Decode a `CBOR` structure into a `fixed16` value.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 5 decimal orders so as to get a fixed precision of 5 decimal positions, which should be OK for most `fixed16`
/// use cases. In other words, the output of this method is 10,000 times the actual value, encoded into an `int32`.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as an `int128` value.
function readFloat16(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
returns (int32)
{
if (cbor.additionalInformation == 25) {
return cbor.buffer.readFloat16();
} else {
revert UnsupportedPrimitive(cbor.additionalInformation);
}
}
/// @notice Decode a `CBOR` structure into a `fixed32` value.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 9 decimal orders so as to get a fixed precision of 9 decimal positions, which should be OK for most `fixed64`
/// use cases. In other words, the output of this method is 10^9 times the actual value, encoded into an `int`.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as an `int` value.
function readFloat32(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
returns (int)
{
if (cbor.additionalInformation == 26) {
return cbor.buffer.readFloat32();
} else {
revert UnsupportedPrimitive(cbor.additionalInformation);
}
}
/// @notice Decode a `CBOR` structure into a `fixed64` value.
/// @dev Due to the lack of support for floating or fixed point arithmetic in the EVM, this method offsets all values
/// by 15 decimal orders so as to get a fixed precision of 15 decimal positions, which should be OK for most `fixed64`
/// use cases. In other words, the output of this method is 10^15 times the actual value, encoded into an `int`.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as an `int` value.
function readFloat64(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_CONTENT_FREE)
returns (int)
{
if (cbor.additionalInformation == 27) {
return cbor.buffer.readFloat64();
} else {
revert UnsupportedPrimitive(cbor.additionalInformation);
}
}
/// @notice Decode a `CBOR` structure into a native `int128[]` value whose inner values follow the same convention
/// @notice as explained in `decodeFixed16`.
/// @param cbor An instance of `CBOR`.
function readFloat16Array(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_ARRAY)
returns (int32[] memory values)
{
uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
if (length < UINT64_MAX) {
values = new int32[](length);
for (uint64 i = 0; i < length; ) {
CBOR memory item = fromBuffer(cbor.buffer);
values[i] = readFloat16(item);
unchecked {
i ++;
}
}
} else {
revert InvalidLengthEncoding(length);
}
}
/// @notice Decode a `CBOR` structure into a native `int128` value.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as an `int128` value.
function readInt(CBOR memory cbor)
internal pure
returns (int)
{
if (cbor.majorType == 1) {
uint64 _value = readLength(
cbor.buffer,
cbor.additionalInformation
);
return int(-1) - int(uint(_value));
} else if (cbor.majorType == 0) {
// Any `uint64` can be safely casted to `int128`, so this method supports majorType 1 as well so as to have offer
// a uniform API for positive and negative numbers
return int(readUint(cbor));
}
else {
revert UnexpectedMajorType(cbor.majorType, 1);
}
}
/// @notice Decode a `CBOR` structure into a native `int[]` value.
/// @param cbor instance of `CBOR`.
/// @return array The value represented by the input, as an `int[]` value.
function readIntArray(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_ARRAY)
returns (int[] memory array)
{
uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
if (length < UINT64_MAX) {
array = new int[](length);
for (uint i = 0; i < length; ) {
CBOR memory item = fromBuffer(cbor.buffer);
array[i] = readInt(item);
unchecked {
i ++;
}
}
} else {
revert InvalidLengthEncoding(length);
}
}
/// @notice Decode a `CBOR` structure into a native `string` value.
/// @param cbor An instance of `CBOR`.
/// @return text The value represented by the input, as a `string` value.
function readString(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_STRING)
returns (string memory text)
{
cbor.len = readLength(cbor.buffer, cbor.additionalInformation);
if (cbor.len == UINT64_MAX) {
bool _done;
while (!_done) {
uint64 length = _readIndefiniteStringLength(
cbor.buffer,
cbor.majorType
);
if (length < UINT64_MAX) {
text = string(abi.encodePacked(
text,
cbor.buffer.readText(length / 4)
));
} else {
_done = true;
}
}
} else {
return string(cbor.buffer.readText(cbor.len));
}
}
/// @notice Decode a `CBOR` structure into a native `string[]` value.
/// @param cbor An instance of `CBOR`.
/// @return strings The value represented by the input, as an `string[]` value.
function readStringArray(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_ARRAY)
returns (string[] memory strings)
{
uint length = readLength(cbor.buffer, cbor.additionalInformation);
if (length < UINT64_MAX) {
strings = new string[](length);
for (uint i = 0; i < length; ) {
CBOR memory item = fromBuffer(cbor.buffer);
strings[i] = readString(item);
unchecked {
i ++;
}
}
} else {
revert InvalidLengthEncoding(length);
}
}
/// @notice Decode a `CBOR` structure into a native `uint64` value.
/// @param cbor An instance of `CBOR`.
/// @return The value represented by the input, as an `uint64` value.
function readUint(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_INT)
returns (uint)
{
return readLength(
cbor.buffer,
cbor.additionalInformation
);
}
/// @notice Decode a `CBOR` structure into a native `uint64[]` value.
/// @param cbor An instance of `CBOR`.
/// @return values The value represented by the input, as an `uint64[]` value.
function readUintArray(CBOR memory cbor)
internal pure
isMajorType(cbor, MAJOR_TYPE_ARRAY)
returns (uint[] memory values)
{
uint64 length = readLength(cbor.buffer, cbor.additionalInformation);
if (length < UINT64_MAX) {
values = new uint[](length);
for (uint ix = 0; ix < length; ) {
CBOR memory item = fromBuffer(cbor.buffer);
values[ix] = readUint(item);
unchecked {
ix ++;
}
}
} else {
revert InvalidLengthEncoding(length);
}
}
/// Read the length of a CBOR indifinite-length item (arrays, maps, byte strings and text) from a buffer, consuming
/// as many bytes as specified by the first byte.
function _readIndefiniteStringLength(
WitnetBuffer.Buffer memory buffer,
uint8 majorType
)
private pure
returns (uint64 len)
{
uint8 initialByte = buffer.readUint8();
if (initialByte == 0xff) {
return UINT64_MAX;
}
len = readLength(
buffer,
initialByte & 0x1f
);
if (len >= UINT64_MAX) {
revert InvalidLengthEncoding(len);
} else if (majorType != (initialByte >> 5)) {
revert UnexpectedMajorType((initialByte >> 5), majorType);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
import "./Witnet.sol";
library WitnetV2 {
/// Struct containing both request and response data related to every query posted to the Witnet Request Board
struct Query {
Request request;
Response response;
}
/// Possible status of a Witnet query.
enum QueryStatus {
Unknown,
Posted,
Reported,
Finalized
}
/// Data kept in EVM-storage for every Request posted to the Witnet Request Board.
struct Request {
address requester; // EVM address from which the request was posted.
uint24 gasCallback; // Max callback gas limit upon response, if a callback is required.
uint72 evmReward; // EVM amount in wei eventually to be paid to the legit result reporter.
bytes witnetBytecode; // Optional: Witnet Data Request bytecode to be solved by the Witnet blockchain.
bytes32 witnetRAD; // Optional: Previously verified hash of the Witnet Data Request to be solved.
WitnetV2.RadonSLA witnetSLA; // Minimum Service-Level parameters to be committed by the Witnet blockchain.
}
/// Response metadata and result as resolved by the Witnet blockchain.
struct Response {
address reporter; // EVM address from which the Data Request result was reported.
uint64 finality; // EVM block number at which the reported data will be considered to be finalized.
uint32 resultTimestamp; // Unix timestamp (seconds) at which the data request was resolved in the Witnet blockchain.
bytes32 resultTallyHash; // Unique hash of the commit/reveal act in the Witnet blockchain that resolved the data request.
bytes resultCborBytes; // CBOR-encode result to the request, as resolved in the Witnet blockchain.
}
/// Response status from a requester's point of view.
enum ResponseStatus {
Void,
Awaiting,
Ready,
Error,
Finalizing,
Delivered
}
struct RadonSLA {
/// @notice Number of nodes in the Witnet blockchain that will take part in solving the data request.
uint8 committeeSize;
/// @notice Fee in $nanoWIT paid to every node in the Witnet blockchain involved in solving the data request.
/// @dev Witnet nodes participating as witnesses will have to stake as collateral 100x this amount.
uint64 witnessingFeeNanoWit;
}
/// ===============================================================================================================
/// --- 'WitnetV2.RadonSLA' helper methods ------------------------------------------------------------------------
function equalOrGreaterThan(RadonSLA memory a, RadonSLA memory b)
internal pure returns (bool)
{
return (a.committeeSize >= b.committeeSize);
}
function isValid(RadonSLA calldata sla) internal pure returns (bool) {
return (
sla.witnessingFeeNanoWit > 0
&& sla.committeeSize > 0 && sla.committeeSize <= 127
);
}
function toV1(RadonSLA memory self) internal pure returns (Witnet.RadonSLA memory) {
return Witnet.RadonSLA({
numWitnesses: self.committeeSize,
minConsensusPercentage: 51,
witnessReward: self.witnessingFeeNanoWit,
witnessCollateral: self.witnessingFeeNanoWit * 100,
minerCommitRevealFee: self.witnessingFeeNanoWit / self.committeeSize
});
}
function nanoWitTotalFee(RadonSLA storage self) internal view returns (uint64) {
return self.witnessingFeeNanoWit * (self.committeeSize + 3);
}
/// ===============================================================================================================
/// --- P-RNG generators ------------------------------------------------------------------------------------------
/// Generates a pseudo-random uint32 number uniformly distributed within the range `[0 .. range)`, based on
/// the given `nonce` and `seed` values.
function randomUniformUint32(uint32 range, uint256 nonce, bytes32 seed)
internal pure
returns (uint32)
{
uint256 _number = uint256(
keccak256(
abi.encode(seed, nonce)
)
) & uint256(2 ** 224 - 1);
return uint32((_number * range) >> 224);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
import "./WitnetRequestBytecodes.sol";
import "./WitnetRequestFactory.sol";
import "./interfaces/IWitnetOracle.sol";
import "./interfaces/IWitnetOracleEvents.sol";
/// @title Witnet Request Board functionality base contract.
/// @author The Witnet Foundation.
abstract contract WitnetOracle
is
IWitnetOracle,
IWitnetOracleEvents
{
function class() virtual external view returns (string memory) {
return type(WitnetOracle).name;
}
function channel() virtual external view returns (bytes4);
function factory() virtual external view returns (WitnetRequestFactory);
function registry() virtual external view returns (WitnetRequestBytecodes);
function specs() virtual external view returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "./interfaces/IWitnetRequestBytecodes.sol";
abstract contract WitnetRequestBytecodes
is
IWitnetRequestBytecodes
{
function class() virtual external view returns (string memory) {
return type(WitnetRequestBytecodes).name;
}
function specs() virtual external view returns (bytes4);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
pragma experimental ABIEncoderV2;
import "./WitnetRequestBytecodes.sol";
import "./WitnetOracle.sol";
import "./interfaces/IWitnetRequestFactory.sol";
abstract contract WitnetRequestFactory
is
IWitnetRequestFactory
{
function class() virtual external view returns (string memory);
function registry() virtual external view returns (WitnetRequestBytecodes);
function specs() virtual external view returns (bytes4);
function witnet() virtual external view returns (WitnetOracle);
}{
"evmVersion": "paris",
"optimizer": {
"enabled": false,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tier","type":"uint256"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"AllowedTierSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"number","type":"uint8"},{"indexed":true,"internalType":"address","name":"player","type":"address"}],"name":"Joined","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"randomBlock","type":"uint256"}],"name":"RandomnessRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"RoundCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"tier","type":"uint256"}],"name":"RoundOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"roundId","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"winningNumber","type":"uint8"},{"indexed":true,"internalType":"address","name":"winner","type":"address"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"}],"name":"RoundResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"RNG","outputs":[{"internalType":"contract IWitnetRandomness","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"activeRoundByTier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"allowedTier","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"cancelRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"drawRound","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"}],"name":"getActiveRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"name":"getMyActiveEntryForTier","outputs":[{"internalType":"bool","name":"joined","type":"bool"},{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint8","name":"number","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"address","name":"player","type":"address"}],"name":"getMyNumberInRound","outputs":[{"internalType":"bool","name":"joined","type":"bool"},{"internalType":"uint8","name":"number","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"player","type":"address"}],"name":"getPlayerStats","outputs":[{"internalType":"uint64","name":"roundsJoined","type":"uint64"},{"internalType":"uint64","name":"roundsWon","type":"uint64"},{"internalType":"uint128","name":"totalStaked","type":"uint128"},{"internalType":"uint128","name":"totalWon","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRoundInfo","outputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"uint8","name":"filledSlots","type":"uint8"},{"internalType":"bool","name":"winnerSelected","type":"bool"},{"internalType":"uint8","name":"winningNumber","type":"uint8"},{"internalType":"uint256","name":"randomBlock","type":"uint256"},{"internalType":"address","name":"winner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"},{"internalType":"uint8","name":"number","type":"uint8"}],"name":"getRoundSlotPlayer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRoundSlots","outputs":[{"internalType":"address[6]","name":"players","type":"address[6]"},{"internalType":"uint8[6]","name":"numbers","type":"uint8[6]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"getRoundState","outputs":[{"internalType":"enum AkibaDiceGame.RoundState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"}],"name":"getTierStats","outputs":[{"internalType":"uint64","name":"roundsCreated","type":"uint64"},{"internalType":"uint64","name":"roundsResolved","type":"uint64"},{"internalType":"uint128","name":"totalStaked","type":"uint128"},{"internalType":"uint128","name":"totalPayout","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"hasJoinedRound","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_miniPoints","type":"address"},{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"uint8","name":"chosenNumber","type":"uint8"}],"name":"joinTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"miniPoints","outputs":[{"internalType":"contract IMiniPoints","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRoundId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"playerStats","outputs":[{"internalType":"uint64","name":"roundsJoined","type":"uint64"},{"internalType":"uint64","name":"roundsWon","type":"uint64"},{"internalType":"uint128","name":"totalStaked","type":"uint128"},{"internalType":"uint128","name":"totalWon","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roundId","type":"uint256"}],"name":"requestRoundRandomness","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tier","type":"uint256"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"setAllowedTier","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tierStats","outputs":[{"internalType":"uint64","name":"roundsCreated","type":"uint64"},{"internalType":"uint64","name":"roundsResolved","type":"uint64"},{"internalType":"uint128","name":"totalStaked","type":"uint128"},{"internalType":"uint128","name":"totalPayout","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPayoutGlobal","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRoundsCancelled","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRoundsCreated","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRoundsResolved","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStakedGlobal","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"}]Contract Creation Code
60a06040523073ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff1681525034801561004357600080fd5b506080516158956200007c60003960008181610adf01528181610b6d0152818161191e015281816119ac0152611b2901526158956000f3fe6080604052600436106101ee5760003560e01c806388c3ffb01161010d578063cbff9718116100a0578063e9a945401161006f578063e9a9454014610755578063ed5299eb14610795578063f2fde38b146107d2578063f7149220146107fb578063ffa2b81d14610826576101ee565b8063cbff97181461066d578063cdafbbb6146106ad578063e84daf0a146106ed578063e8fdd49414610718576101ee565b8063a8c30043116100dc578063a8c3004314610577578063c642e7bf146105b5578063c678be40146105f2578063cb99bd3b1461062f576101ee565b806388c3ffb0146104b45780638c1ea85b146104f65780638da5cb5b14610521578063a8513ffa1461054c576101ee565b80634af74b58116101855780635ee49b8f116101545780635ee49b8f1461040757806369e83a55146104235780637e07ab0914610462578063831cdf871461048b576101ee565b80634af74b58146103575780634f1ef286146103805780634fd66eae1461039c57806352d1902d146103dc576101ee565b80633ffe0648116101c15780633ffe0648146102ad5780634002eda6146102d857806343fae74414610303578063485cc9551461032e576101ee565b806302516374146101f35780631898049d1461021c57806330814b1b146102595780633659cfe614610284575b600080fd5b3480156101ff57600080fd5b5061021a60048036038101906102159190613d27565b610863565b005b34801561022857600080fd5b50610243600480360381019061023e9190613d27565b610aab565b6040516102509190613d63565b60405180910390f35b34801561026557600080fd5b5061026e610ac3565b60405161027b9190613da1565b60405180910390f35b34801561029057600080fd5b506102ab60048036038101906102a69190613e1a565b610add565b005b3480156102b957600080fd5b506102c2610c65565b6040516102cf9190613da1565b60405180910390f35b3480156102e457600080fd5b506102ed610c7f565b6040516102fa9190613d63565b60405180910390f35b34801561030f57600080fd5b50610318610c85565b6040516103259190613e72565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613e8d565b610ca7565b005b34801561036357600080fd5b5061037e60048036038101906103799190613f06565b6110e7565b005b61039a6004803603810190610395919061408c565b61191c565b005b3480156103a857600080fd5b506103c360048036038101906103be9190613e1a565b611a58565b6040516103d394939291906140e8565b60405180910390f35b3480156103e857600080fd5b506103f1611b25565b6040516103fe9190614146565b60405180910390f35b610421600480360381019061041c9190613d27565b611bde565b005b34801561042f57600080fd5b5061044a60048036038101906104459190614161565b611e77565b604051610459939291906141cb565b60405180910390f35b34801561046e57600080fd5b5061048960048036038101906104849190613d27565b611f7a565b005b34801561049757600080fd5b506104b260048036038101906104ad919061422e565b61241f565b005b3480156104c057600080fd5b506104db60048036038101906104d69190613d27565b612516565b6040516104ed9695949392919061427d565b60405180910390f35b34801561050257600080fd5b5061050b612604565b6040516105189190613da1565b60405180910390f35b34801561052d57600080fd5b5061053661261e565b60405161054391906142de565b60405180910390f35b34801561055857600080fd5b50610561612644565b60405161056e9190613e72565b60405180910390f35b34801561058357600080fd5b5061059e60048036038101906105999190613d27565b612666565b6040516105ac92919061444f565b60405180910390f35b3480156105c157600080fd5b506105dc60048036038101906105d79190613d27565b6127c6565b6040516105e991906144f0565b60405180910390f35b3480156105fe57600080fd5b5061061960048036038101906106149190614161565b61293b565b604051610626919061450b565b60405180910390f35b34801561063b57600080fd5b5061065660048036038101906106519190614161565b61296a565b604051610664929190614526565b60405180910390f35b34801561067957600080fd5b50610694600480360381019061068f9190613d27565b612a89565b6040516106a494939291906140e8565b60405180910390f35b3480156106b957600080fd5b506106d460048036038101906106cf9190613e1a565b612b2a565b6040516106e494939291906140e8565b60405180910390f35b3480156106f957600080fd5b50610702612bba565b60405161070f91906145ae565b60405180910390f35b34801561072457600080fd5b5061073f600480360381019061073a9190613f06565b612be0565b60405161074c91906142de565b60405180910390f35b34801561076157600080fd5b5061077c60048036038101906107779190613d27565b612ce2565b60405161078c94939291906140e8565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190613d27565b612d72565b6040516107c9919061450b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190613e1a565b612d92565b005b34801561080757600080fd5b50610810612f51565b60405161081d91906145ea565b60405180910390f35b34801561083257600080fd5b5061084d60048036038101906108489190613d27565b612f69565b60405161085a9190613d63565b60405180910390f35b61086b612f86565b806000811415801561087e575060995481105b6108bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b490614662565b60405180910390fd5b6000609a6000848152602001908152602001600020905060068160020160009054906101000a900460ff1660ff161461092b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610922906146ce565b60405180910390fd5b8060020160019054906101000a900460ff161561097d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109749061473a565b60405180910390fd5b60008160030154036109c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109bb906147a6565b60405180910390fd5b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b8152600401610a159190613d63565b602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5691906147db565b610a95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8c90614854565b60405180910390fd5b610a9e83612fd5565b5050610aa861353f565b50565b609b6020528060005260406000206000915090505481565b60a060009054906101000a900467ffffffffffffffff1681565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b62906148e6565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16610baa613549565b73ffffffffffffffffffffffffffffffffffffffff1614610c00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf790614978565b60405180910390fd5b610c09816135a0565b610c6281600067ffffffffffffffff811115610c2857610c27613f61565b5b6040519080825280601f01601f191660200182016040528015610c5a5781602001600182028036833780820191505090505b506000613633565b50565b60a060089054906101000a900467ffffffffffffffff1681565b60995481565b60a160109054906101000a90046fffffffffffffffffffffffffffffffff1681565b60008060019054906101000a900460ff16159050808015610cd85750600160008054906101000a900460ff1660ff16105b80610d055750610ce7306137a1565b158015610d045750600160008054906101000a900460ff1660ff16145b5b610d44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d3b90614a0a565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610d81576001600060016101000a81548160ff0219169083151502179055505b610d896137c4565b610d91613815565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df790614a76565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6690614ae2565b60405180910390fd5b82609860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016099819055506001609c6000600a815260200190815260200160002060006101000a81548160ff0219169083151502179055506001609c60006014815260200190815260200160002060006101000a81548160ff0219169083151502179055506001609c6000601e815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600a7f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f5600160405161100d919061450b565b60405180910390a260147f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f56001604051611047919061450b565b60405180910390a2601e7f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f56001604051611081919061450b565b60405180910390a280156110e25760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516110d99190614b3d565b60405180910390a15b505050565b6110ef612f86565b609c600083815260200190815260200160002060009054906101000a900460ff1661114f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114690614ba4565b60405180910390fd5b60018160ff1610158015611167575060068160ff1611155b6111a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119d90614c10565b60405180910390fd5b6000609b60008481526020019081526020016000205490506000609a6000838152602001908152602001600020905060008214806111f8575060068160020160009054906101000a900460ff1660ff16145b8061121157508060020160019054906101000a900460ff165b156113f6576099600081548092919061122990614c5f565b919050559150609a6000838152602001908152602001600020905081816000018190555083816001018190555060008160020160006101000a81548160ff021916908360ff16021790555060008160020160016101000a81548160ff02191690831515021790555060008160020160026101000a81548160ff021916908360ff1602179055506000816003018190555060008160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609b600086815260200190815260200160002081905550600160a060008282829054906101000a900467ffffffffffffffff1661133b9190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000609e6000868152602001908152602001600020905060018160000160008282829054906101000a900467ffffffffffffffff166113a09190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555084837fd5a850d069d7216a3c3e54842d8e62fae0a8a37d00b6871658002d817f02c82360405160405180910390a3505b609d600083815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148b90614d2f565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168160050160008560ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161153590614d9b565b60405180910390fd5b609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33866040518363ffffffff1660e01b815260040161159b929190614dbb565b600060405180830381600087803b1580156115b557600080fd5b505af11580156115c9573d6000803e3d6000fd5b50505050338160050160008560ff1660ff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018160020160008282829054906101000a900460ff166116489190614de4565b92506101000a81548160ff021916908360ff1602179055506001609d600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000609e60008681526020019081526020016000209050848160000160108282829054906101000a90046fffffffffffffffffffffffffffffffff1661170f9190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508460a160008282829054906101000a90046fffffffffffffffffffffffffffffffff166117729190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609f60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160008282829054906101000a900467ffffffffffffffff166118139190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550858160000160108282829054906101000a90046fffffffffffffffffffffffffffffffff166118689190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff168560ff16857fd7012949087694262b79936dc8bd8cd0631709e0eb2ec840460c3fe1f5de7d2460405160405180910390a460068360020160009054906101000a900460ff1660ff160361190c5761190b8461386e565b5b5050505061191861353f565b5050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036119aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119a1906148e6565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166119e9613549565b73ffffffffffffffffffffffffffffffffffffffff1614611a3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a3690614978565b60405180910390fd5b611a48826135a0565b611a5482826001613633565b5050565b6000806000806000609f60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000160009054906101000a900467ffffffffffffffff168160000160089054906101000a900467ffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff168360010160009054906101000a90046fffffffffffffffffffffffffffffffff169450945094509450509193509193565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614611bb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bac90614ecf565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b905090565b611be6612f86565b8060008114158015611bf9575060995481105b611c38576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2f90614662565b60405180910390fd5b6000609a6000848152602001908152602001600020905060008160020160009054906101000a900460ff1660ff1611611ca6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c9d90614f3b565b60405180910390fd5b8060020160019054906101000a900460ff1615611cf8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cef9061473a565b60405180910390fd5b6000816003015414611d3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3690614fa7565b60405180910390fd5b600073c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff1663699b328a346040518263ffffffff1660e01b815260040160206040518083038185885af1158015611da2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611dc79190614fdc565b905043826003018190555034811015611e2d573373ffffffffffffffffffffffffffffffffffffffff166108fc8234611e009190615009565b9081150290604051600060405180830381858888f19350505050158015611e2b573d6000803e3d6000fd5b505b837f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a18360030154604051611e619190613d63565b60405180910390a2505050611e7461353f565b50565b6000806000609b600086815260200190815260200160002054915060008203611eaa576000806000925092509250611f73565b6000609a600084815260200190815260200160002090506000600190505b60068160ff1611611f65578573ffffffffffffffffffffffffffffffffffffffff168260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603611f5257600184829450945094505050611f73565b8080611f5d9061503d565b915050611ec8565b506000836000935093509350505b9250925092565b611f82612f86565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612012576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612009906150b2565b60405180910390fd5b8060008114158015612025575060995481105b612064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161205b90614662565b60405180910390fd5b6000609a600084815260200190815260200160002090508060020160019054906101000a900460ff16156120cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c49061473a565b60405180910390fd5b60068160020160009054906101000a900460ff1660ff1610612124576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161211b9061511e565b60405180910390fd5b600081600301541461216b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216290614fa7565b60405180910390fd5b6000600190505b60068160ff161161235d5760008260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461234957609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f198285600101546040518363ffffffff1660e01b8152600401612252929190614dbb565b600060405180830381600087803b15801561226c57600080fd5b505af1158015612280573d6000803e3d6000fd5b5050505060008360050160008460ff1660ff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000609d600087815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5080806123559061503d565b915050612172565b5060008160020160006101000a81548160ff021916908360ff16021790555060018160020160016101000a81548160ff021916908315150217905550600160a060108282829054906101000a900467ffffffffffffffff166123bf9190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550827fbf7aeff89cf7a4c3d0145879e39aa6a19e8e64ed585090ef86bf31f4d2ae57bf60405160405180910390a2505061241c61353f565b50565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146124af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124a6906150b2565b60405180910390fd5b80609c600084815260200190815260200160002060006101000a81548160ff021916908315150217905550817f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f58260405161250a919061450b565b60405180910390a25050565b6000806000806000808660008114158015612532575060995481105b612571576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256890614662565b60405180910390fd5b6000609a60008a8152602001908152602001600020905080600101548160020160009054906101000a900460ff168260020160019054906101000a900460ff168360020160029054906101000a900460ff1684600301548560040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16975097509750975097509750505091939550919395565b60a060109054906101000a900467ffffffffffffffff1681565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60a160009054906101000a90046fffffffffffffffffffffffffffffffff1681565b61266e613c99565b612676613cbb565b8260008114158015612689575060995481105b6126c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126bf90614662565b60405180910390fd5b6000609a6000868152602001908152602001600020905060005b60068160ff1610156127be5760006001826126fd9190614de4565b90508260050160008260ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868360ff16600681106127515761275061513e565b5b602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080858360ff166006811061279f5761279e61513e565b5b602002019060ff16908160ff16815250505080806001019150506126e2565b505050915091565b600081600081141580156127db575060995481105b61281a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161281190614662565b60405180910390fd5b6000609a600085815260200190815260200160002090508060020160019054906101000a900460ff1615612852576004925050612935565b60068160020160009054906101000a900460ff1660ff161015612879576001925050612935565b600081600301540361288f576002925050612935565b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b81526004016128e09190613d63565b602060405180830381865afa1580156128fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292191906147db565b61292f576002925050612935565b60039250505b50919050565b609d6020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b6000808360008114158015612980575060995481105b6129bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b690614662565b60405180910390fd5b6000609a600087815260200190815260200160002090506000600190505b60068160ff1611612a77578573ffffffffffffffffffffffffffffffffffffffff168260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603612a6457600181945094505050612a81565b8080612a6f9061503d565b9150506129dd565b5060008093509350505b509250929050565b6000806000806000609e600087815260200190815260200160002090508060000160009054906101000a900467ffffffffffffffff168160000160089054906101000a900467ffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff168360010160009054906101000a90046fffffffffffffffffffffffffffffffff169450945094509450509193509193565b609f6020528060005260406000206000915090508060000160009054906101000a900467ffffffffffffffff16908060000160089054906101000a900467ffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010160009054906101000a90046fffffffffffffffffffffffffffffffff16905084565b609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008260008114158015612bf5575060995481105b612c34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c2b90614662565b60405180910390fd5b60018360ff1610158015612c4c575060068360ff1611155b612c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c8290614c10565b60405180910390fd5b609a600085815260200190815260200160002060050160008460ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505092915050565b609e6020528060005260406000206000915090508060000160009054906101000a900467ffffffffffffffff16908060000160089054906101000a900467ffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010160009054906101000a90046fffffffffffffffffffffffffffffffff16905084565b609c6020528060005260406000206000915054906101000a900460ff1681565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e19906150b2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e88906151b9565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b73c0ffee98ad1434acbdb894bbb752e138c1006fab81565b6000609b6000838152602001908152602001600020549050919050565b600260655403612fcb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fc290615225565b60405180910390fd5b6002606581905550565b6000609a60008381526020019081526020016000209050600073c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff166324cbbfc16006600085600301546040518463ffffffff1660e01b8152600401613045939291906152cb565b602060405180830381865afa158015613062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613086919061532e565b63ffffffff169050600060018261309d919061535b565b905060008360050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361314e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613145906153db565b60405180910390fd5b60006006856001015461316191906153fb565b905060018560020160016101000a81548160ff021916908315150217905550828560020160026101000a81548160ff021916908360ff160217905550818560040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1983836040518363ffffffff1660e01b815260040161323d929190614dbb565b600060405180830381600087803b15801561325757600080fd5b505af115801561326b573d6000803e3d6000fd5b50505050600160a060088282829054906101000a900467ffffffffffffffff166132959190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508060a160108282829054906101000a90046fffffffffffffffffffffffffffffffff166132e89190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609e600087600101548152602001908152602001600020905060018160000160088282829054906101000a900467ffffffffffffffff166133619190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550818160010160008282829054906101000a90046fffffffffffffffffffffffffffffffff166133b69190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609f60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160088282829054906101000a900467ffffffffffffffff166134579190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550828160010160008282829054906101000a90046fffffffffffffffffffffffffffffffff166134ac9190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168560ff16897f782c97b3b6b457b2689076d96212fce94b4b3d639de6f37f7aba2c43886a661b8660405161352d9190613d63565b60405180910390a45050505050505050565b6001606581905550565b60006135777f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b613980565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613630576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613627906150b2565b60405180910390fd5b50565b61365f7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914360001b61398a565b60000160009054906101000a900460ff16156136835761367e83613994565b61379c565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156136eb57506040513d601f19601f820116820180604052508101906136e89190615469565b60015b61372a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161372190615508565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b811461378f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137869061559a565b60405180910390fd5b5061379b838383613a4d565b5b505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600060019054906101000a900460ff16613813576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161380a9061562c565b60405180910390fd5b565b600060019054906101000a900460ff16613864576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161385b9061562c565b60405180910390fd5b61386c613a79565b565b6000609a6000838152602001908152602001600020905060068160020160009054906101000a900460ff1660ff16146138a7575061397d565b8060020160019054906101000a900460ff16156138c4575061397d565b60008160030154036138d6575061397d565b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b81526004016139279190613d63565b602060405180830381865afa158015613944573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396891906147db565b613972575061397d565b61397b82612fd5565b505b50565b6000819050919050565b6000819050919050565b61399d816137a1565b6139dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016139d3906156be565b60405180910390fd5b80613a097f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b613980565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b613a5683613ad2565b600082511180613a635750805b15613a7457613a728383613b21565b505b505050565b600060019054906101000a900460ff16613ac8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613abf9061562c565b60405180910390fd5b6001606581905550565b613adb81613994565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b6060613b46838360405180606001604052806027815260200161583960279139613b4e565b905092915050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051613b78919061574f565b600060405180830381855af49150503d8060008114613bb3576040519150601f19603f3d011682016040523d82523d6000602084013e613bb8565b606091505b5091509150613bc986838387613bd4565b925050509392505050565b60608315613c36576000835103613c2e57613bee856137a1565b613c2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c24906157b2565b60405180910390fd5b5b829050613c41565b613c408383613c49565b5b949350505050565b600082511115613c5c5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c909190615816565b60405180910390fd5b6040518060c00160405280600690602082028036833780820191505090505090565b6040518060c00160405280600690602082028036833780820191505090505090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b613d0481613cf1565b8114613d0f57600080fd5b50565b600081359050613d2181613cfb565b92915050565b600060208284031215613d3d57613d3c613ce7565b5b6000613d4b84828501613d12565b91505092915050565b613d5d81613cf1565b82525050565b6000602082019050613d786000830184613d54565b92915050565b600067ffffffffffffffff82169050919050565b613d9b81613d7e565b82525050565b6000602082019050613db66000830184613d92565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613de782613dbc565b9050919050565b613df781613ddc565b8114613e0257600080fd5b50565b600081359050613e1481613dee565b92915050565b600060208284031215613e3057613e2f613ce7565b5b6000613e3e84828501613e05565b91505092915050565b60006fffffffffffffffffffffffffffffffff82169050919050565b613e6c81613e47565b82525050565b6000602082019050613e876000830184613e63565b92915050565b60008060408385031215613ea457613ea3613ce7565b5b6000613eb285828601613e05565b9250506020613ec385828601613e05565b9150509250929050565b600060ff82169050919050565b613ee381613ecd565b8114613eee57600080fd5b50565b600081359050613f0081613eda565b92915050565b60008060408385031215613f1d57613f1c613ce7565b5b6000613f2b85828601613d12565b9250506020613f3c85828601613ef1565b9150509250929050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613f9982613f50565b810181811067ffffffffffffffff82111715613fb857613fb7613f61565b5b80604052505050565b6000613fcb613cdd565b9050613fd78282613f90565b919050565b600067ffffffffffffffff821115613ff757613ff6613f61565b5b61400082613f50565b9050602081019050919050565b82818337600083830152505050565b600061402f61402a84613fdc565b613fc1565b90508281526020810184848401111561404b5761404a613f4b565b5b61405684828561400d565b509392505050565b600082601f83011261407357614072613f46565b5b813561408384826020860161401c565b91505092915050565b600080604083850312156140a3576140a2613ce7565b5b60006140b185828601613e05565b925050602083013567ffffffffffffffff8111156140d2576140d1613cec565b5b6140de8582860161405e565b9150509250929050565b60006080820190506140fd6000830187613d92565b61410a6020830186613d92565b6141176040830185613e63565b6141246060830184613e63565b95945050505050565b6000819050919050565b6141408161412d565b82525050565b600060208201905061415b6000830184614137565b92915050565b6000806040838503121561417857614177613ce7565b5b600061418685828601613d12565b925050602061419785828601613e05565b9150509250929050565b60008115159050919050565b6141b6816141a1565b82525050565b6141c581613ecd565b82525050565b60006060820190506141e060008301866141ad565b6141ed6020830185613d54565b6141fa60408301846141bc565b949350505050565b61420b816141a1565b811461421657600080fd5b50565b60008135905061422881614202565b92915050565b6000806040838503121561424557614244613ce7565b5b600061425385828601613d12565b925050602061426485828601614219565b9150509250929050565b61427781613ddc565b82525050565b600060c0820190506142926000830189613d54565b61429f60208301886141bc565b6142ac60408301876141ad565b6142b960608301866141bc565b6142c66080830185613d54565b6142d360a083018461426e565b979650505050505050565b60006020820190506142f3600083018461426e565b92915050565b600060069050919050565b600081905092915050565b6000819050919050565b61432281613ddc565b82525050565b60006143348383614319565b60208301905092915050565b6000602082019050919050565b614356816142f9565b6143608184614304565b925061436b8261430f565b8060005b8381101561439c5781516143838782614328565b965061438e83614340565b92505060018101905061436f565b505050505050565b600060069050919050565b600081905092915050565b6000819050919050565b6143cd81613ecd565b82525050565b60006143df83836143c4565b60208301905092915050565b6000602082019050919050565b614401816143a4565b61440b81846143af565b9250614416826143ba565b8060005b8381101561444757815161442e87826143d3565b9650614439836143eb565b92505060018101905061441a565b505050505050565b600061018082019050614465600083018561434d565b61447260c08301846143f8565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106144b9576144b8614479565b5b50565b60008190506144ca826144a8565b919050565b60006144da826144bc565b9050919050565b6144ea816144cf565b82525050565b600060208201905061450560008301846144e1565b92915050565b600060208201905061452060008301846141ad565b92915050565b600060408201905061453b60008301856141ad565b61454860208301846141bc565b9392505050565b6000819050919050565b600061457461456f61456a84613dbc565b61454f565b613dbc565b9050919050565b600061458682614559565b9050919050565b60006145988261457b565b9050919050565b6145a88161458d565b82525050565b60006020820190506145c3600083018461459f565b92915050565b60006145d48261457b565b9050919050565b6145e4816145c9565b82525050565b60006020820190506145ff60008301846145db565b92915050565b600082825260208201905092915050565b7f446963653a20726f756e64206e6f7420666f756e640000000000000000000000600082015250565b600061464c601583614605565b915061465782614616565b602082019050919050565b6000602082019050818103600083015261467b8161463f565b9050919050565b7f446963653a20706f74206e6f742066756c6c0000000000000000000000000000600082015250565b60006146b8601283614605565b91506146c382614682565b602082019050919050565b600060208201905081810360008301526146e7816146ab565b9050919050565b7f446963653a20616c7265616479207265736f6c76656400000000000000000000600082015250565b6000614724601683614605565b915061472f826146ee565b602082019050919050565b6000602082019050818103600083015261475381614717565b9050919050565b7f446963653a2072616e646f6d6e657373206e6f74207265717565737465640000600082015250565b6000614790601e83614605565b915061479b8261475a565b602082019050919050565b600060208201905081810360008301526147bf81614783565b9050919050565b6000815190506147d581614202565b92915050565b6000602082840312156147f1576147f0613ce7565b5b60006147ff848285016147c6565b91505092915050565b7f446963653a2072616e646f6d6e6573732070656e64696e670000000000000000600082015250565b600061483e601883614605565b915061484982614808565b602082019050919050565b6000602082019050818103600083015261486d81614831565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f64656c656761746563616c6c0000000000000000000000000000000000000000602082015250565b60006148d0602c83614605565b91506148db82614874565b604082019050919050565b600060208201905081810360008301526148ff816148c3565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f6163746976652070726f78790000000000000000000000000000000000000000602082015250565b6000614962602c83614605565b915061496d82614906565b604082019050919050565b6000602082019050818103600083015261499181614955565b9050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006149f4602e83614605565b91506149ff82614998565b604082019050919050565b60006020820190508181036000830152614a23816149e7565b9050919050565b7f446963653a20696e76616c6964204d696e69506f696e74730000000000000000600082015250565b6000614a60601883614605565b9150614a6b82614a2a565b602082019050919050565b60006020820190508181036000830152614a8f81614a53565b9050919050565b7f446963653a20696e76616c6964206f776e657200000000000000000000000000600082015250565b6000614acc601383614605565b9150614ad782614a96565b602082019050919050565b60006020820190508181036000830152614afb81614abf565b9050919050565b6000819050919050565b6000614b27614b22614b1d84614b02565b61454f565b613ecd565b9050919050565b614b3781614b0c565b82525050565b6000602082019050614b526000830184614b2e565b92915050565b7f446963653a2074696572206e6f7420616c6c6f77656400000000000000000000600082015250565b6000614b8e601683614605565b9150614b9982614b58565b602082019050919050565b60006020820190508181036000830152614bbd81614b81565b9050919050565b7f446963653a20626164206e756d62657200000000000000000000000000000000600082015250565b6000614bfa601083614605565b9150614c0582614bc4565b602082019050919050565b60006020820190508181036000830152614c2981614bed565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614c6a82613cf1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c9c57614c9b614c30565b5b600182019050919050565b6000614cb282613d7e565b9150614cbd83613d7e565b9250828201905067ffffffffffffffff811115614cdd57614cdc614c30565b5b92915050565b7f446963653a20616c7265616479206a6f696e6564000000000000000000000000600082015250565b6000614d19601483614605565b9150614d2482614ce3565b602082019050919050565b60006020820190508181036000830152614d4881614d0c565b9050919050565b7f446963653a206e756d6265722074616b656e0000000000000000000000000000600082015250565b6000614d85601283614605565b9150614d9082614d4f565b602082019050919050565b60006020820190508181036000830152614db481614d78565b9050919050565b6000604082019050614dd0600083018561426e565b614ddd6020830184613d54565b9392505050565b6000614def82613ecd565b9150614dfa83613ecd565b9250828201905060ff811115614e1357614e12614c30565b5b92915050565b6000614e2482613e47565b9150614e2f83613e47565b925082820190506fffffffffffffffffffffffffffffffff811115614e5757614e56614c30565b5b92915050565b7f555550535570677261646561626c653a206d757374206e6f742062652063616c60008201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000602082015250565b6000614eb9603883614605565b9150614ec482614e5d565b604082019050919050565b60006020820190508181036000830152614ee881614eac565b9050919050565b7f446963653a206e6f20706c617965727320796574000000000000000000000000600082015250565b6000614f25601483614605565b9150614f3082614eef565b602082019050919050565b60006020820190508181036000830152614f5481614f18565b9050919050565b7f446963653a2072616e646f6d6e65737320726571756573746564000000000000600082015250565b6000614f91601a83614605565b9150614f9c82614f5b565b602082019050919050565b60006020820190508181036000830152614fc081614f84565b9050919050565b600081519050614fd681613cfb565b92915050565b600060208284031215614ff257614ff1613ce7565b5b600061500084828501614fc7565b91505092915050565b600061501482613cf1565b915061501f83613cf1565b925082820390508181111561503757615036614c30565b5b92915050565b600061504882613ecd565b915060ff820361505b5761505a614c30565b5b600182019050919050565b7f4f776e65723a206e6f74206f776e657200000000000000000000000000000000600082015250565b600061509c601083614605565b91506150a782615066565b602082019050919050565b600060208201905081810360008301526150cb8161508f565b9050919050565b7f446963653a2066756c6c20706f74000000000000000000000000000000000000600082015250565b6000615108600e83614605565b9150615113826150d2565b602082019050919050565b60006020820190508181036000830152615137816150fb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4f776e65723a207a65726f206164647200000000000000000000000000000000600082015250565b60006151a3601083614605565b91506151ae8261516d565b602082019050919050565b600060208201905081810360008301526151d281615196565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b600061520f601f83614605565b915061521a826151d9565b602082019050919050565b6000602082019050818103600083015261523e81615202565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b600061527a61527561527084615245565b61454f565b61524f565b9050919050565b61528a8161525f565b82525050565b6000819050919050565b60006152b56152b06152ab84615290565b61454f565b613cf1565b9050919050565b6152c58161529a565b82525050565b60006060820190506152e06000830186615281565b6152ed60208301856152bc565b6152fa6040830184613d54565b949350505050565b61530b8161524f565b811461531657600080fd5b50565b60008151905061532881615302565b92915050565b60006020828403121561534457615343613ce7565b5b600061535284828501615319565b91505092915050565b600061536682613cf1565b915061537183613cf1565b925082820190508082111561538957615388614c30565b5b92915050565b7f446963653a20656d7074792077696e6e657220736c6f74000000000000000000600082015250565b60006153c5601783614605565b91506153d08261538f565b602082019050919050565b600060208201905081810360008301526153f4816153b8565b9050919050565b600061540682613cf1565b915061541183613cf1565b925082820261541f81613cf1565b9150828204841483151761543657615435614c30565b5b5092915050565b6154468161412d565b811461545157600080fd5b50565b6000815190506154638161543d565b92915050565b60006020828403121561547f5761547e613ce7565b5b600061548d84828501615454565b91505092915050565b7f45524331393637557067726164653a206e657720696d706c656d656e7461746960008201527f6f6e206973206e6f742055555053000000000000000000000000000000000000602082015250565b60006154f2602e83614605565b91506154fd82615496565b604082019050919050565b60006020820190508181036000830152615521816154e5565b9050919050565b7f45524331393637557067726164653a20756e737570706f727465642070726f7860008201527f6961626c65555549440000000000000000000000000000000000000000000000602082015250565b6000615584602983614605565b915061558f82615528565b604082019050919050565b600060208201905081810360008301526155b381615577565b9050919050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000615616602b83614605565b9150615621826155ba565b604082019050919050565b6000602082019050818103600083015261564581615609565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006156a8602d83614605565b91506156b38261564c565b604082019050919050565b600060208201905081810360008301526156d78161569b565b9050919050565b600081519050919050565b600081905092915050565b60005b838110156157125780820151818401526020810190506156f7565b60008484015250505050565b6000615729826156de565b61573381856156e9565b93506157438185602086016156f4565b80840191505092915050565b600061575b828461571e565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600061579c601d83614605565b91506157a782615766565b602082019050919050565b600060208201905081810360008301526157cb8161578f565b9050919050565b600081519050919050565b60006157e8826157d2565b6157f28185614605565b93506158028185602086016156f4565b61580b81613f50565b840191505092915050565b6000602082019050818103600083015261583081846157dd565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200028c5cb9072a64b78023bc05d6fc78449690c601fe1356a7daac8699a1f12f064736f6c63430008180033
Deployed Bytecode
0x6080604052600436106101ee5760003560e01c806388c3ffb01161010d578063cbff9718116100a0578063e9a945401161006f578063e9a9454014610755578063ed5299eb14610795578063f2fde38b146107d2578063f7149220146107fb578063ffa2b81d14610826576101ee565b8063cbff97181461066d578063cdafbbb6146106ad578063e84daf0a146106ed578063e8fdd49414610718576101ee565b8063a8c30043116100dc578063a8c3004314610577578063c642e7bf146105b5578063c678be40146105f2578063cb99bd3b1461062f576101ee565b806388c3ffb0146104b45780638c1ea85b146104f65780638da5cb5b14610521578063a8513ffa1461054c576101ee565b80634af74b58116101855780635ee49b8f116101545780635ee49b8f1461040757806369e83a55146104235780637e07ab0914610462578063831cdf871461048b576101ee565b80634af74b58146103575780634f1ef286146103805780634fd66eae1461039c57806352d1902d146103dc576101ee565b80633ffe0648116101c15780633ffe0648146102ad5780634002eda6146102d857806343fae74414610303578063485cc9551461032e576101ee565b806302516374146101f35780631898049d1461021c57806330814b1b146102595780633659cfe614610284575b600080fd5b3480156101ff57600080fd5b5061021a60048036038101906102159190613d27565b610863565b005b34801561022857600080fd5b50610243600480360381019061023e9190613d27565b610aab565b6040516102509190613d63565b60405180910390f35b34801561026557600080fd5b5061026e610ac3565b60405161027b9190613da1565b60405180910390f35b34801561029057600080fd5b506102ab60048036038101906102a69190613e1a565b610add565b005b3480156102b957600080fd5b506102c2610c65565b6040516102cf9190613da1565b60405180910390f35b3480156102e457600080fd5b506102ed610c7f565b6040516102fa9190613d63565b60405180910390f35b34801561030f57600080fd5b50610318610c85565b6040516103259190613e72565b60405180910390f35b34801561033a57600080fd5b5061035560048036038101906103509190613e8d565b610ca7565b005b34801561036357600080fd5b5061037e60048036038101906103799190613f06565b6110e7565b005b61039a6004803603810190610395919061408c565b61191c565b005b3480156103a857600080fd5b506103c360048036038101906103be9190613e1a565b611a58565b6040516103d394939291906140e8565b60405180910390f35b3480156103e857600080fd5b506103f1611b25565b6040516103fe9190614146565b60405180910390f35b610421600480360381019061041c9190613d27565b611bde565b005b34801561042f57600080fd5b5061044a60048036038101906104459190614161565b611e77565b604051610459939291906141cb565b60405180910390f35b34801561046e57600080fd5b5061048960048036038101906104849190613d27565b611f7a565b005b34801561049757600080fd5b506104b260048036038101906104ad919061422e565b61241f565b005b3480156104c057600080fd5b506104db60048036038101906104d69190613d27565b612516565b6040516104ed9695949392919061427d565b60405180910390f35b34801561050257600080fd5b5061050b612604565b6040516105189190613da1565b60405180910390f35b34801561052d57600080fd5b5061053661261e565b60405161054391906142de565b60405180910390f35b34801561055857600080fd5b50610561612644565b60405161056e9190613e72565b60405180910390f35b34801561058357600080fd5b5061059e60048036038101906105999190613d27565b612666565b6040516105ac92919061444f565b60405180910390f35b3480156105c157600080fd5b506105dc60048036038101906105d79190613d27565b6127c6565b6040516105e991906144f0565b60405180910390f35b3480156105fe57600080fd5b5061061960048036038101906106149190614161565b61293b565b604051610626919061450b565b60405180910390f35b34801561063b57600080fd5b5061065660048036038101906106519190614161565b61296a565b604051610664929190614526565b60405180910390f35b34801561067957600080fd5b50610694600480360381019061068f9190613d27565b612a89565b6040516106a494939291906140e8565b60405180910390f35b3480156106b957600080fd5b506106d460048036038101906106cf9190613e1a565b612b2a565b6040516106e494939291906140e8565b60405180910390f35b3480156106f957600080fd5b50610702612bba565b60405161070f91906145ae565b60405180910390f35b34801561072457600080fd5b5061073f600480360381019061073a9190613f06565b612be0565b60405161074c91906142de565b60405180910390f35b34801561076157600080fd5b5061077c60048036038101906107779190613d27565b612ce2565b60405161078c94939291906140e8565b60405180910390f35b3480156107a157600080fd5b506107bc60048036038101906107b79190613d27565b612d72565b6040516107c9919061450b565b60405180910390f35b3480156107de57600080fd5b506107f960048036038101906107f49190613e1a565b612d92565b005b34801561080757600080fd5b50610810612f51565b60405161081d91906145ea565b60405180910390f35b34801561083257600080fd5b5061084d60048036038101906108489190613d27565b612f69565b60405161085a9190613d63565b60405180910390f35b61086b612f86565b806000811415801561087e575060995481105b6108bd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108b490614662565b60405180910390fd5b6000609a6000848152602001908152602001600020905060068160020160009054906101000a900460ff1660ff161461092b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610922906146ce565b60405180910390fd5b8060020160019054906101000a900460ff161561097d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109749061473a565b60405180910390fd5b60008160030154036109c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016109bb906147a6565b60405180910390fd5b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b8152600401610a159190613d63565b602060405180830381865afa158015610a32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a5691906147db565b610a95576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a8c90614854565b60405180910390fd5b610a9e83612fd5565b5050610aa861353f565b50565b609b6020528060005260406000206000915090505481565b60a060009054906101000a900467ffffffffffffffff1681565b7f000000000000000000000000b4783f59efa33ed8270b890709c09afa6ee7e36873ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603610b6b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b62906148e6565b60405180910390fd5b7f000000000000000000000000b4783f59efa33ed8270b890709c09afa6ee7e36873ffffffffffffffffffffffffffffffffffffffff16610baa613549565b73ffffffffffffffffffffffffffffffffffffffff1614610c00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf790614978565b60405180910390fd5b610c09816135a0565b610c6281600067ffffffffffffffff811115610c2857610c27613f61565b5b6040519080825280601f01601f191660200182016040528015610c5a5781602001600182028036833780820191505090505b506000613633565b50565b60a060089054906101000a900467ffffffffffffffff1681565b60995481565b60a160109054906101000a90046fffffffffffffffffffffffffffffffff1681565b60008060019054906101000a900460ff16159050808015610cd85750600160008054906101000a900460ff1660ff16105b80610d055750610ce7306137a1565b158015610d045750600160008054906101000a900460ff1660ff16145b5b610d44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d3b90614a0a565b60405180910390fd5b60016000806101000a81548160ff021916908360ff1602179055508015610d81576001600060016101000a81548160ff0219169083151502179055505b610d896137c4565b610d91613815565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603610e00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610df790614a76565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603610e6f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e6690614ae2565b60405180910390fd5b82609860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060016099819055506001609c6000600a815260200190815260200160002060006101000a81548160ff0219169083151502179055506001609c60006014815260200190815260200160002060006101000a81548160ff0219169083151502179055506001609c6000601e815260200190815260200160002060006101000a81548160ff0219169083151502179055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a3600a7f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f5600160405161100d919061450b565b60405180910390a260147f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f56001604051611047919061450b565b60405180910390a2601e7f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f56001604051611081919061450b565b60405180910390a280156110e25760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb384740249860016040516110d99190614b3d565b60405180910390a15b505050565b6110ef612f86565b609c600083815260200190815260200160002060009054906101000a900460ff1661114f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161114690614ba4565b60405180910390fd5b60018160ff1610158015611167575060068160ff1611155b6111a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161119d90614c10565b60405180910390fd5b6000609b60008481526020019081526020016000205490506000609a6000838152602001908152602001600020905060008214806111f8575060068160020160009054906101000a900460ff1660ff16145b8061121157508060020160019054906101000a900460ff165b156113f6576099600081548092919061122990614c5f565b919050559150609a6000838152602001908152602001600020905081816000018190555083816001018190555060008160020160006101000a81548160ff021916908360ff16021790555060008160020160016101000a81548160ff02191690831515021790555060008160020160026101000a81548160ff021916908360ff1602179055506000816003018190555060008160040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081609b600086815260200190815260200160002081905550600160a060008282829054906101000a900467ffffffffffffffff1661133b9190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506000609e6000868152602001908152602001600020905060018160000160008282829054906101000a900467ffffffffffffffff166113a09190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555084837fd5a850d069d7216a3c3e54842d8e62fae0a8a37d00b6871658002d817f02c82360405160405180910390a3505b609d600083815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff1615611494576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161148b90614d2f565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168160050160008560ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461153e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161153590614d9b565b60405180910390fd5b609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16639dc29fac33866040518363ffffffff1660e01b815260040161159b929190614dbb565b600060405180830381600087803b1580156115b557600080fd5b505af11580156115c9573d6000803e3d6000fd5b50505050338160050160008560ff1660ff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018160020160008282829054906101000a900460ff166116489190614de4565b92506101000a81548160ff021916908360ff1602179055506001609d600084815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055506000609e60008681526020019081526020016000209050848160000160108282829054906101000a90046fffffffffffffffffffffffffffffffff1661170f9190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508460a160008282829054906101000a90046fffffffffffffffffffffffffffffffff166117729190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609f60003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160008282829054906101000a900467ffffffffffffffff166118139190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550858160000160108282829054906101000a90046fffffffffffffffffffffffffffffffff166118689190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff168560ff16857fd7012949087694262b79936dc8bd8cd0631709e0eb2ec840460c3fe1f5de7d2460405160405180910390a460068360020160009054906101000a900460ff1660ff160361190c5761190b8461386e565b5b5050505061191861353f565b5050565b7f000000000000000000000000b4783f59efa33ed8270b890709c09afa6ee7e36873ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16036119aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016119a1906148e6565b60405180910390fd5b7f000000000000000000000000b4783f59efa33ed8270b890709c09afa6ee7e36873ffffffffffffffffffffffffffffffffffffffff166119e9613549565b73ffffffffffffffffffffffffffffffffffffffff1614611a3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611a3690614978565b60405180910390fd5b611a48826135a0565b611a5482826001613633565b5050565b6000806000806000609f60008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060000160009054906101000a900467ffffffffffffffff168160000160089054906101000a900467ffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff168360010160009054906101000a90046fffffffffffffffffffffffffffffffff169450945094509450509193509193565b60007f000000000000000000000000b4783f59efa33ed8270b890709c09afa6ee7e36873ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1614611bb5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611bac90614ecf565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b905090565b611be6612f86565b8060008114158015611bf9575060995481105b611c38576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c2f90614662565b60405180910390fd5b6000609a6000848152602001908152602001600020905060008160020160009054906101000a900460ff1660ff1611611ca6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c9d90614f3b565b60405180910390fd5b8060020160019054906101000a900460ff1615611cf8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611cef9061473a565b60405180910390fd5b6000816003015414611d3f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611d3690614fa7565b60405180910390fd5b600073c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff1663699b328a346040518263ffffffff1660e01b815260040160206040518083038185885af1158015611da2573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190611dc79190614fdc565b905043826003018190555034811015611e2d573373ffffffffffffffffffffffffffffffffffffffff166108fc8234611e009190615009565b9081150290604051600060405180830381858888f19350505050158015611e2b573d6000803e3d6000fd5b505b837f3d94fecedaa4f90b8bd459797adb95f5bb11426025c5541390d9ccc1ad1b60a18360030154604051611e619190613d63565b60405180910390a2505050611e7461353f565b50565b6000806000609b600086815260200190815260200160002054915060008203611eaa576000806000925092509250611f73565b6000609a600084815260200190815260200160002090506000600190505b60068160ff1611611f65578573ffffffffffffffffffffffffffffffffffffffff168260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603611f5257600184829450945094505050611f73565b8080611f5d9061503d565b915050611ec8565b506000836000935093509350505b9250925092565b611f82612f86565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612012576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612009906150b2565b60405180910390fd5b8060008114158015612025575060995481105b612064576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161205b90614662565b60405180910390fd5b6000609a600084815260200190815260200160002090508060020160019054906101000a900460ff16156120cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120c49061473a565b60405180910390fd5b60068160020160009054906101000a900460ff1660ff1610612124576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161211b9061511e565b60405180910390fd5b600081600301541461216b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161216290614fa7565b60405180910390fd5b6000600190505b60068160ff161161235d5760008260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161461234957609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f198285600101546040518363ffffffff1660e01b8152600401612252929190614dbb565b600060405180830381600087803b15801561226c57600080fd5b505af1158015612280573d6000803e3d6000fd5b5050505060008360050160008460ff1660ff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000609d600087815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505b5080806123559061503d565b915050612172565b5060008160020160006101000a81548160ff021916908360ff16021790555060018160020160016101000a81548160ff021916908315150217905550600160a060108282829054906101000a900467ffffffffffffffff166123bf9190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550827fbf7aeff89cf7a4c3d0145879e39aa6a19e8e64ed585090ef86bf31f4d2ae57bf60405160405180910390a2505061241c61353f565b50565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146124af576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016124a6906150b2565b60405180910390fd5b80609c600084815260200190815260200160002060006101000a81548160ff021916908315150217905550817f88ef30a280dd2eec5269815ff74f7f1c354fdace8d07a65295ca5d2431d622f58260405161250a919061450b565b60405180910390a25050565b6000806000806000808660008114158015612532575060995481105b612571576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161256890614662565b60405180910390fd5b6000609a60008a8152602001908152602001600020905080600101548160020160009054906101000a900460ff168260020160019054906101000a900460ff168360020160029054906101000a900460ff1684600301548560040160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16975097509750975097509750505091939550919395565b60a060109054906101000a900467ffffffffffffffff1681565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60a160009054906101000a90046fffffffffffffffffffffffffffffffff1681565b61266e613c99565b612676613cbb565b8260008114158015612689575060995481105b6126c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126bf90614662565b60405180910390fd5b6000609a6000868152602001908152602001600020905060005b60068160ff1610156127be5760006001826126fd9190614de4565b90508260050160008260ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16868360ff16600681106127515761275061513e565b5b602002019073ffffffffffffffffffffffffffffffffffffffff16908173ffffffffffffffffffffffffffffffffffffffff168152505080858360ff166006811061279f5761279e61513e565b5b602002019060ff16908160ff16815250505080806001019150506126e2565b505050915091565b600081600081141580156127db575060995481105b61281a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161281190614662565b60405180910390fd5b6000609a600085815260200190815260200160002090508060020160019054906101000a900460ff1615612852576004925050612935565b60068160020160009054906101000a900460ff1660ff161015612879576001925050612935565b600081600301540361288f576002925050612935565b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b81526004016128e09190613d63565b602060405180830381865afa1580156128fd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061292191906147db565b61292f576002925050612935565b60039250505b50919050565b609d6020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b6000808360008114158015612980575060995481105b6129bf576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016129b690614662565b60405180910390fd5b6000609a600087815260200190815260200160002090506000600190505b60068160ff1611612a77578573ffffffffffffffffffffffffffffffffffffffff168260050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603612a6457600181945094505050612a81565b8080612a6f9061503d565b9150506129dd565b5060008093509350505b509250929050565b6000806000806000609e600087815260200190815260200160002090508060000160009054906101000a900467ffffffffffffffff168160000160089054906101000a900467ffffffffffffffff168260000160109054906101000a90046fffffffffffffffffffffffffffffffff168360010160009054906101000a90046fffffffffffffffffffffffffffffffff169450945094509450509193509193565b609f6020528060005260406000206000915090508060000160009054906101000a900467ffffffffffffffff16908060000160089054906101000a900467ffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010160009054906101000a90046fffffffffffffffffffffffffffffffff16905084565b609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008260008114158015612bf5575060995481105b612c34576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c2b90614662565b60405180910390fd5b60018360ff1610158015612c4c575060068360ff1611155b612c8b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612c8290614c10565b60405180910390fd5b609a600085815260200190815260200160002060050160008460ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1691505092915050565b609e6020528060005260406000206000915090508060000160009054906101000a900467ffffffffffffffff16908060000160089054906101000a900467ffffffffffffffff16908060000160109054906101000a90046fffffffffffffffffffffffffffffffff16908060010160009054906101000a90046fffffffffffffffffffffffffffffffff16905084565b609c6020528060005260406000206000915054906101000a900460ff1681565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612e22576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e19906150b2565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603612e91576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612e88906151b9565b60405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff16609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a380609760006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b73c0ffee98ad1434acbdb894bbb752e138c1006fab81565b6000609b6000838152602001908152602001600020549050919050565b600260655403612fcb576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401612fc290615225565b60405180910390fd5b6002606581905550565b6000609a60008381526020019081526020016000209050600073c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff166324cbbfc16006600085600301546040518463ffffffff1660e01b8152600401613045939291906152cb565b602060405180830381865afa158015613062573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613086919061532e565b63ffffffff169050600060018261309d919061535b565b905060008360050160008360ff1660ff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160361314e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613145906153db565b60405180910390fd5b60006006856001015461316191906153fb565b905060018560020160016101000a81548160ff021916908315150217905550828560020160026101000a81548160ff021916908360ff160217905550818560040160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550609860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166340c10f1983836040518363ffffffff1660e01b815260040161323d929190614dbb565b600060405180830381600087803b15801561325757600080fd5b505af115801561326b573d6000803e3d6000fd5b50505050600160a060088282829054906101000a900467ffffffffffffffff166132959190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055508060a160108282829054906101000a90046fffffffffffffffffffffffffffffffff166132e89190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609e600087600101548152602001908152602001600020905060018160000160088282829054906101000a900467ffffffffffffffff166133619190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550818160010160008282829054906101000a90046fffffffffffffffffffffffffffffffff166133b69190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506000609f60008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060018160000160088282829054906101000a900467ffffffffffffffff166134579190614ca7565b92506101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550828160010160008282829054906101000a90046fffffffffffffffffffffffffffffffff166134ac9190614e19565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff168560ff16897f782c97b3b6b457b2689076d96212fce94b4b3d639de6f37f7aba2c43886a661b8660405161352d9190613d63565b60405180910390a45050505050505050565b6001606581905550565b60006135777f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b613980565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b609760009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614613630576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613627906150b2565b60405180910390fd5b50565b61365f7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914360001b61398a565b60000160009054906101000a900460ff16156136835761367e83613994565b61379c565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa9250505080156136eb57506040513d601f19601f820116820180604052508101906136e89190615469565b60015b61372a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161372190615508565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b811461378f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016137869061559a565b60405180910390fd5b5061379b838383613a4d565b5b505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600060019054906101000a900460ff16613813576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161380a9061562c565b60405180910390fd5b565b600060019054906101000a900460ff16613864576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161385b9061562c565b60405180910390fd5b61386c613a79565b565b6000609a6000838152602001908152602001600020905060068160020160009054906101000a900460ff1660ff16146138a7575061397d565b8060020160019054906101000a900460ff16156138c4575061397d565b60008160030154036138d6575061397d565b73c0ffee98ad1434acbdb894bbb752e138c1006fab73ffffffffffffffffffffffffffffffffffffffff16639bc86fec82600301546040518263ffffffff1660e01b81526004016139279190613d63565b602060405180830381865afa158015613944573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061396891906147db565b613972575061397d565b61397b82612fd5565b505b50565b6000819050919050565b6000819050919050565b61399d816137a1565b6139dc576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016139d3906156be565b60405180910390fd5b80613a097f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b613980565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b613a5683613ad2565b600082511180613a635750805b15613a7457613a728383613b21565b505b505050565b600060019054906101000a900460ff16613ac8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613abf9061562c565b60405180910390fd5b6001606581905550565b613adb81613994565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b6060613b46838360405180606001604052806027815260200161583960279139613b4e565b905092915050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051613b78919061574f565b600060405180830381855af49150503d8060008114613bb3576040519150601f19603f3d011682016040523d82523d6000602084013e613bb8565b606091505b5091509150613bc986838387613bd4565b925050509392505050565b60608315613c36576000835103613c2e57613bee856137a1565b613c2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c24906157b2565b60405180910390fd5b5b829050613c41565b613c408383613c49565b5b949350505050565b600082511115613c5c5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401613c909190615816565b60405180910390fd5b6040518060c00160405280600690602082028036833780820191505090505090565b6040518060c00160405280600690602082028036833780820191505090505090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b613d0481613cf1565b8114613d0f57600080fd5b50565b600081359050613d2181613cfb565b92915050565b600060208284031215613d3d57613d3c613ce7565b5b6000613d4b84828501613d12565b91505092915050565b613d5d81613cf1565b82525050565b6000602082019050613d786000830184613d54565b92915050565b600067ffffffffffffffff82169050919050565b613d9b81613d7e565b82525050565b6000602082019050613db66000830184613d92565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000613de782613dbc565b9050919050565b613df781613ddc565b8114613e0257600080fd5b50565b600081359050613e1481613dee565b92915050565b600060208284031215613e3057613e2f613ce7565b5b6000613e3e84828501613e05565b91505092915050565b60006fffffffffffffffffffffffffffffffff82169050919050565b613e6c81613e47565b82525050565b6000602082019050613e876000830184613e63565b92915050565b60008060408385031215613ea457613ea3613ce7565b5b6000613eb285828601613e05565b9250506020613ec385828601613e05565b9150509250929050565b600060ff82169050919050565b613ee381613ecd565b8114613eee57600080fd5b50565b600081359050613f0081613eda565b92915050565b60008060408385031215613f1d57613f1c613ce7565b5b6000613f2b85828601613d12565b9250506020613f3c85828601613ef1565b9150509250929050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b613f9982613f50565b810181811067ffffffffffffffff82111715613fb857613fb7613f61565b5b80604052505050565b6000613fcb613cdd565b9050613fd78282613f90565b919050565b600067ffffffffffffffff821115613ff757613ff6613f61565b5b61400082613f50565b9050602081019050919050565b82818337600083830152505050565b600061402f61402a84613fdc565b613fc1565b90508281526020810184848401111561404b5761404a613f4b565b5b61405684828561400d565b509392505050565b600082601f83011261407357614072613f46565b5b813561408384826020860161401c565b91505092915050565b600080604083850312156140a3576140a2613ce7565b5b60006140b185828601613e05565b925050602083013567ffffffffffffffff8111156140d2576140d1613cec565b5b6140de8582860161405e565b9150509250929050565b60006080820190506140fd6000830187613d92565b61410a6020830186613d92565b6141176040830185613e63565b6141246060830184613e63565b95945050505050565b6000819050919050565b6141408161412d565b82525050565b600060208201905061415b6000830184614137565b92915050565b6000806040838503121561417857614177613ce7565b5b600061418685828601613d12565b925050602061419785828601613e05565b9150509250929050565b60008115159050919050565b6141b6816141a1565b82525050565b6141c581613ecd565b82525050565b60006060820190506141e060008301866141ad565b6141ed6020830185613d54565b6141fa60408301846141bc565b949350505050565b61420b816141a1565b811461421657600080fd5b50565b60008135905061422881614202565b92915050565b6000806040838503121561424557614244613ce7565b5b600061425385828601613d12565b925050602061426485828601614219565b9150509250929050565b61427781613ddc565b82525050565b600060c0820190506142926000830189613d54565b61429f60208301886141bc565b6142ac60408301876141ad565b6142b960608301866141bc565b6142c66080830185613d54565b6142d360a083018461426e565b979650505050505050565b60006020820190506142f3600083018461426e565b92915050565b600060069050919050565b600081905092915050565b6000819050919050565b61432281613ddc565b82525050565b60006143348383614319565b60208301905092915050565b6000602082019050919050565b614356816142f9565b6143608184614304565b925061436b8261430f565b8060005b8381101561439c5781516143838782614328565b965061438e83614340565b92505060018101905061436f565b505050505050565b600060069050919050565b600081905092915050565b6000819050919050565b6143cd81613ecd565b82525050565b60006143df83836143c4565b60208301905092915050565b6000602082019050919050565b614401816143a4565b61440b81846143af565b9250614416826143ba565b8060005b8381101561444757815161442e87826143d3565b9650614439836143eb565b92505060018101905061441a565b505050505050565b600061018082019050614465600083018561434d565b61447260c08301846143f8565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600581106144b9576144b8614479565b5b50565b60008190506144ca826144a8565b919050565b60006144da826144bc565b9050919050565b6144ea816144cf565b82525050565b600060208201905061450560008301846144e1565b92915050565b600060208201905061452060008301846141ad565b92915050565b600060408201905061453b60008301856141ad565b61454860208301846141bc565b9392505050565b6000819050919050565b600061457461456f61456a84613dbc565b61454f565b613dbc565b9050919050565b600061458682614559565b9050919050565b60006145988261457b565b9050919050565b6145a88161458d565b82525050565b60006020820190506145c3600083018461459f565b92915050565b60006145d48261457b565b9050919050565b6145e4816145c9565b82525050565b60006020820190506145ff60008301846145db565b92915050565b600082825260208201905092915050565b7f446963653a20726f756e64206e6f7420666f756e640000000000000000000000600082015250565b600061464c601583614605565b915061465782614616565b602082019050919050565b6000602082019050818103600083015261467b8161463f565b9050919050565b7f446963653a20706f74206e6f742066756c6c0000000000000000000000000000600082015250565b60006146b8601283614605565b91506146c382614682565b602082019050919050565b600060208201905081810360008301526146e7816146ab565b9050919050565b7f446963653a20616c7265616479207265736f6c76656400000000000000000000600082015250565b6000614724601683614605565b915061472f826146ee565b602082019050919050565b6000602082019050818103600083015261475381614717565b9050919050565b7f446963653a2072616e646f6d6e657373206e6f74207265717565737465640000600082015250565b6000614790601e83614605565b915061479b8261475a565b602082019050919050565b600060208201905081810360008301526147bf81614783565b9050919050565b6000815190506147d581614202565b92915050565b6000602082840312156147f1576147f0613ce7565b5b60006147ff848285016147c6565b91505092915050565b7f446963653a2072616e646f6d6e6573732070656e64696e670000000000000000600082015250565b600061483e601883614605565b915061484982614808565b602082019050919050565b6000602082019050818103600083015261486d81614831565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f64656c656761746563616c6c0000000000000000000000000000000000000000602082015250565b60006148d0602c83614605565b91506148db82614874565b604082019050919050565b600060208201905081810360008301526148ff816148c3565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f6163746976652070726f78790000000000000000000000000000000000000000602082015250565b6000614962602c83614605565b915061496d82614906565b604082019050919050565b6000602082019050818103600083015261499181614955565b9050919050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b60006149f4602e83614605565b91506149ff82614998565b604082019050919050565b60006020820190508181036000830152614a23816149e7565b9050919050565b7f446963653a20696e76616c6964204d696e69506f696e74730000000000000000600082015250565b6000614a60601883614605565b9150614a6b82614a2a565b602082019050919050565b60006020820190508181036000830152614a8f81614a53565b9050919050565b7f446963653a20696e76616c6964206f776e657200000000000000000000000000600082015250565b6000614acc601383614605565b9150614ad782614a96565b602082019050919050565b60006020820190508181036000830152614afb81614abf565b9050919050565b6000819050919050565b6000614b27614b22614b1d84614b02565b61454f565b613ecd565b9050919050565b614b3781614b0c565b82525050565b6000602082019050614b526000830184614b2e565b92915050565b7f446963653a2074696572206e6f7420616c6c6f77656400000000000000000000600082015250565b6000614b8e601683614605565b9150614b9982614b58565b602082019050919050565b60006020820190508181036000830152614bbd81614b81565b9050919050565b7f446963653a20626164206e756d62657200000000000000000000000000000000600082015250565b6000614bfa601083614605565b9150614c0582614bc4565b602082019050919050565b60006020820190508181036000830152614c2981614bed565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000614c6a82613cf1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203614c9c57614c9b614c30565b5b600182019050919050565b6000614cb282613d7e565b9150614cbd83613d7e565b9250828201905067ffffffffffffffff811115614cdd57614cdc614c30565b5b92915050565b7f446963653a20616c7265616479206a6f696e6564000000000000000000000000600082015250565b6000614d19601483614605565b9150614d2482614ce3565b602082019050919050565b60006020820190508181036000830152614d4881614d0c565b9050919050565b7f446963653a206e756d6265722074616b656e0000000000000000000000000000600082015250565b6000614d85601283614605565b9150614d9082614d4f565b602082019050919050565b60006020820190508181036000830152614db481614d78565b9050919050565b6000604082019050614dd0600083018561426e565b614ddd6020830184613d54565b9392505050565b6000614def82613ecd565b9150614dfa83613ecd565b9250828201905060ff811115614e1357614e12614c30565b5b92915050565b6000614e2482613e47565b9150614e2f83613e47565b925082820190506fffffffffffffffffffffffffffffffff811115614e5757614e56614c30565b5b92915050565b7f555550535570677261646561626c653a206d757374206e6f742062652063616c60008201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000602082015250565b6000614eb9603883614605565b9150614ec482614e5d565b604082019050919050565b60006020820190508181036000830152614ee881614eac565b9050919050565b7f446963653a206e6f20706c617965727320796574000000000000000000000000600082015250565b6000614f25601483614605565b9150614f3082614eef565b602082019050919050565b60006020820190508181036000830152614f5481614f18565b9050919050565b7f446963653a2072616e646f6d6e65737320726571756573746564000000000000600082015250565b6000614f91601a83614605565b9150614f9c82614f5b565b602082019050919050565b60006020820190508181036000830152614fc081614f84565b9050919050565b600081519050614fd681613cfb565b92915050565b600060208284031215614ff257614ff1613ce7565b5b600061500084828501614fc7565b91505092915050565b600061501482613cf1565b915061501f83613cf1565b925082820390508181111561503757615036614c30565b5b92915050565b600061504882613ecd565b915060ff820361505b5761505a614c30565b5b600182019050919050565b7f4f776e65723a206e6f74206f776e657200000000000000000000000000000000600082015250565b600061509c601083614605565b91506150a782615066565b602082019050919050565b600060208201905081810360008301526150cb8161508f565b9050919050565b7f446963653a2066756c6c20706f74000000000000000000000000000000000000600082015250565b6000615108600e83614605565b9150615113826150d2565b602082019050919050565b60006020820190508181036000830152615137816150fb565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4f776e65723a207a65726f206164647200000000000000000000000000000000600082015250565b60006151a3601083614605565b91506151ae8261516d565b602082019050919050565b600060208201905081810360008301526151d281615196565b9050919050565b7f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00600082015250565b600061520f601f83614605565b915061521a826151d9565b602082019050919050565b6000602082019050818103600083015261523e81615202565b9050919050565b6000819050919050565b600063ffffffff82169050919050565b600061527a61527561527084615245565b61454f565b61524f565b9050919050565b61528a8161525f565b82525050565b6000819050919050565b60006152b56152b06152ab84615290565b61454f565b613cf1565b9050919050565b6152c58161529a565b82525050565b60006060820190506152e06000830186615281565b6152ed60208301856152bc565b6152fa6040830184613d54565b949350505050565b61530b8161524f565b811461531657600080fd5b50565b60008151905061532881615302565b92915050565b60006020828403121561534457615343613ce7565b5b600061535284828501615319565b91505092915050565b600061536682613cf1565b915061537183613cf1565b925082820190508082111561538957615388614c30565b5b92915050565b7f446963653a20656d7074792077696e6e657220736c6f74000000000000000000600082015250565b60006153c5601783614605565b91506153d08261538f565b602082019050919050565b600060208201905081810360008301526153f4816153b8565b9050919050565b600061540682613cf1565b915061541183613cf1565b925082820261541f81613cf1565b9150828204841483151761543657615435614c30565b5b5092915050565b6154468161412d565b811461545157600080fd5b50565b6000815190506154638161543d565b92915050565b60006020828403121561547f5761547e613ce7565b5b600061548d84828501615454565b91505092915050565b7f45524331393637557067726164653a206e657720696d706c656d656e7461746960008201527f6f6e206973206e6f742055555053000000000000000000000000000000000000602082015250565b60006154f2602e83614605565b91506154fd82615496565b604082019050919050565b60006020820190508181036000830152615521816154e5565b9050919050565b7f45524331393637557067726164653a20756e737570706f727465642070726f7860008201527f6961626c65555549440000000000000000000000000000000000000000000000602082015250565b6000615584602983614605565b915061558f82615528565b604082019050919050565b600060208201905081810360008301526155b381615577565b9050919050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000615616602b83614605565b9150615621826155ba565b604082019050919050565b6000602082019050818103600083015261564581615609565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006156a8602d83614605565b91506156b38261564c565b604082019050919050565b600060208201905081810360008301526156d78161569b565b9050919050565b600081519050919050565b600081905092915050565b60005b838110156157125780820151818401526020810190506156f7565b60008484015250505050565b6000615729826156de565b61573381856156e9565b93506157438185602086016156f4565b80840191505092915050565b600061575b828461571e565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600061579c601d83614605565b91506157a782615766565b602082019050919050565b600060208201905081810360008301526157cb8161578f565b9050919050565b600081519050919050565b60006157e8826157d2565b6157f28185614605565b93506158028185602086016156f4565b61580b81613f50565b840191505092915050565b6000602082019050818103600083015261583081846157dd565b90509291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212200028c5cb9072a64b78023bc05d6fc78449690c601fe1356a7daac8699a1f12f064736f6c63430008180033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.