Source Code
Latest 5 from a total of 5 transactions
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Predicter
Compiler Version
v0.8.30+commit.73712a01
Optimization Enabled:
Yes with 200 runs
Other Settings:
prague EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
// Envelop V2 — Simple Price Prediction (Voting) Implementation
pragma solidity ^0.8.24;
import {ERC6909TokenSupply} from "@openzeppelin/contracts/token/ERC6909/extensions/ERC6909TokenSupply.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
/// forge-lint: disable-next-line(unaliased-plain-import)
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
/// forge-lint: disable-next-line(unaliased-plain-import)
import "../interfaces/IEnvelopOracle.sol";
/// forge-lint: disable-next-line(unaliased-plain-import)
//import "../interfaces/IPermit2Minimal.sol";
import "../interfaces/IPermit2Minimal.sol";
/**
* @title Predicter
* @notice A decentralized binary prediction market based on ERC-6909 share tokens.
* Each prediction is created by an initiator (“creator”) and users may vote
* “agree” or “disagree” by staking ERC20 tokens. After expiration, the prediction
* resolves via an on-chain oracle, and winners claim rewards proportional to their share.
*
* @dev Uses ERC6909 token IDs encoded as:
* [20 bytes: creator address][11 bytes: padding][1 byte: vote flag (1 = yes, 0 = no)]
*
* @custom:security-contact Envelop V2
*/
contract Predicter is ERC6909TokenSupply, ReentrancyGuard {
using SafeERC20 for IERC20;
/**
* @dev Single prediction entity created by an address.
* A creator may have only one active prediction at a time.
*
* - strike: token/amount encoded pair representing the stake size for each vote.
* - predictedPrice: prediction target value (amount field) with token as “unit” asset.
* - expirationTime: UNIX timestamp after which new votes are not accepted.
* - resolvedPrice: oracle result after expiration, stored once and used for outcome.
* - portfolio: array of underlying assets used by the oracle for pricing.
*/
struct Prediction {
CompactAsset strike;
/// @dev predictedPrice.amount is a threshold value.
/// Outcome is YES if predictedPrice.amount <= resolvedPrice, otherwise NO.
/// resolvedPrice must be in the same units/decimals as predictedPrice.amount.
OracleData predictedPrice;
uint40 expirationTime;
uint96 resolvedPrice;
CompactAsset[] portfolio;
}
// ==================================
// CONSTANTS
// ==================================
/// @dev Reserved constant for potential “stop voting before expiration” logic.
uint40 public constant STOP_BEFORE_EXPIRED = 0;
/// @dev Creator fee in bps. 200 = 2%
uint96 public constant FEE_CREATOR_PERCENT = 100;
/// @dev Protocol fee in bps. 100 = 1%.
uint96 public constant FEE_PROTOCOL_PERCENT = 0;
/// @dev Percentage denominator (basis points = 10_000).
uint96 public constant PERCENT_DENOMINATOR = 10_000;
/// @dev Fixed-point scale used to reduce rounding loss in share calculations.
/// Shares are computed as: userShares = (userBalance * SCALE) / totalWin.
uint96 public constant SCALE = 1e18;
/// @dev Hard cap for number of portfolio items, to avoid gas blow-ups.
uint256 public constant MAX_PORTFOLIO_LEN = 100;
/// @dev Hard cap for number of portfolio items, to avoid gas blow-ups.
uint40 public constant MAX_PREDICTION_PERIOD = uint40(1000 days);
/// @dev Uniswap Permit2 constant (reserved for future integrations, currently unused).
address public constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
/// @dev for use with Uniswap Permit2, seconds
uint256 public constant PERMIT2_TTL = 600;
/// @notice Protocol-level fee receiver.
address public immutable FEE_PROTOCOL_BENEFICIARY;
/// @notice Oracle used for resolving predictions.
//address public immutable ORACLE;
/// @notice Mapping of prediction creator → prediction data.
mapping(address creator => Prediction) public predictions;
// ==================================
// ERRORS
// ==================================
/// @dev Thrown when a creator attempts to create a second active prediction.
error ActivePredictionExist(address sender);
/// @dev Thrown when voting happens after expiration.
error PredictionExpired(address prediction, uint40 expirationTime);
/// @dev Thrown if the prediction is referenced but does not exist.
error PredictionNotExist(address prediction);
/// @dev Thrown if oracle price does not fit into uint96.
error OraclePriceTooHigh(uint256 oraclePrice);
/// @dev Thrown if portfolio length exceeds MAX_PORTFOLIO_LEN.
error TooManyPortfolioItems(uint256 actualLength);
/// @dev Thrown if prediction too long
error TooLongPrediction(uint256 actualTimestamp);
// ==================================
// EVENTS
// ==================================
/// @notice Emitted when a new prediction is created.
event PredictionCreated(address indexed creator, uint40 expirationTime);
/// @notice Emitted on each user vote.
event Voted(address indexed voter, address indexed prediction, bool agree);
/// @notice Emitted once prediction is resolved with oracle price.
event PredictionResolved(address indexed prediction, uint256 resolvedPrice);
/// @notice Emitted when a user successfully claims their reward.
event Claimed(address indexed user, address indexed prediction, uint256 reward);
// ==================================
// CONSTRUCTOR
// ==================================
/**
* @param _feeBeneficiary Address receiving protocol-level fees.
*/
constructor(address _feeBeneficiary) {
FEE_PROTOCOL_BENEFICIARY = _feeBeneficiary;
}
// ==================================
// USER FUNCTIONS
// ==================================
/**
* @notice Create a new prediction owned by msg.sender.
* A creator may only have one active prediction at a time.
* @param _pred The prediction parameters.
*
* Requirements:
* - `_pred.portfolio.length` MUST be ≤ MAX_PORTFOLIO_LEN.
* - Creator MUST NOT have an existing prediction (`expirationTime == 0`).
*/
function createPrediction(Prediction calldata _pred) external {
if (_pred.portfolio.length > MAX_PORTFOLIO_LEN) {
revert TooManyPortfolioItems(_pred.portfolio.length);
}
if (_pred.expirationTime > MAX_PREDICTION_PERIOD + uint40(block.timestamp)) {
revert TooLongPrediction(_pred.expirationTime);
}
_checkPrediction(msg.sender, _pred);
_createPrediction(msg.sender, _pred);
emit PredictionCreated(msg.sender, _pred.expirationTime);
}
/**
* @notice Cast a vote on a prediction by staking tokens.
* @param _prediction Address of the prediction creator.
* @param _agree Whether the user votes “yes” (true) or “no” (false).
*
* Emits:
* - {Voted}
*
* Requirements:
* - Prediction MUST exist.
* - Current time MUST be strictly less than `expirationTime`.
* - Caller MUST have approved enough ERC20 to `this` for the strike amount.
*/
function vote(address _prediction, bool _agree) external nonReentrant {
(address token, uint96 amount) = _vote(msg.sender, _prediction, _agree);
IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
}
/**
* @notice Cast a vote using Uniswap Permit2 signature-based transfer.
* @dev Flow:
* 1) User gives standard ERC20 approval to Permit2 once (off-chain setup).
* 2) Prerpare and sign digest for Permit2.
* 3) In this method we call Permit2.permitTransferFrom, wich
* transfer stake from user to this contract, then mint 6909-shares.
*
* @param _prediction Address of the prediction creator.
* @param _agree Whether the user votes “yes” (true) or “no” (false).
* @param permit Permit2 permit struct (token, max amount, nonce, deadline).
* @param transfer Permit2 transfer details (recipient, requestedAmount).
* @param signature User EIP-712 signature for Permit2.
*
* Requirements:
* - Prediction MUST exist.
* - Now MUST be < expirationTime.
* - permit.permitted.token MUST match prediction strike token.
* - transfer.to MUST be this contract.
* - transfer.requestedAmount MUST be >= strike amount.
* - owner (msg.sender) MUST have given ERC20 approve to Permit2 beforehand.
*/
function voteWithPermit2(
address _prediction,
bool _agree,
IPermit2Minimal.PermitTransferFrom calldata permit,
IPermit2Minimal.SignatureTransferDetails calldata transfer,
bytes calldata signature
) external nonReentrant {
Prediction storage p = predictions[_prediction];
// Basic sanity checks to bind Permit2 params to this prediction
if (permit.permitted.token != p.strike.token) {
revert("Permit2: wrong token");
}
if (transfer.to != address(this)) {
revert("Permit2: wrong recipient");
}
if (transfer.requestedAmount != p.strike.amount) {
revert("Permit2: insufficient amount");
}
_vote(msg.sender, _prediction, _agree);
// 1) Move tokens from user to this contract via Permit2
IPermit2Minimal(PERMIT2).permitTransferFrom(permit, transfer, msg.sender, signature);
}
/**
* @notice Cast a vote using Uniswap Permit2 signature-based transfer.
* @dev Flow:
* 1) User gives standard ERC20 approval to Permit2 once (off-chain setup).
* 2) Prerpare and sign digest for Permit2.
* 3) In this method we call Permit2.permitTransferFrom, wich
* transfer stake from user to this contract, then mint 6909-shares.
*
* @param _prediction Address of the prediction creator.
* @param _agree Whether the user votes “yes” (true) or “no” (false).
* @param permit Permit2 permit struct (token, max amount, nonce, deadline).
* @param signature User EIP-712 signature for Permit2.
*
* Requirements:
* - Prediction MUST exist.
* - owner (msg.sender) MUST have given ERC20 approve to Permit2 beforehand.
*/
function voteWithPermit2(
address _prediction,
bool _agree,
IPermit2Minimal.PermitTransferFrom calldata permit,
bytes calldata signature
) external virtual nonReentrant {
Prediction storage p = predictions[_prediction];
// Basic sanity checks to bind Permit2 params to this prediction
if (permit.permitted.token != p.strike.token) {
revert("Permit2: wrong token");
}
IPermit2Minimal.SignatureTransferDetails memory transfer = IPermit2Minimal.SignatureTransferDetails(
address(this),
p.strike.amount //TODO check implicit uint256() ?
);
_vote(msg.sender, _prediction, _agree);
// 1) Move tokens from user to this contract via Permit2
IPermit2Minimal(PERMIT2).permitTransferFrom(permit, transfer, msg.sender, signature);
}
/**
* @dev If only one side has any votes (no-contest), voters can refund their stake instead of rewards.
* @notice Claim rewards based on resolved prediction outcome.
* @param _prediction Address of prediction creator.
*
* Emits:
* - {PredictionResolved} (if first-time resolve)
* - {Claimed} (if caller has a positive winner’s prize)
*
* Requirements:
* - Prediction MUST exist and be resolvable (expired).
* - Caller MUST hold a positive amount of winning share tokens (ERC6909),
* otherwise the call is a no-op.
*/
function claim(address _prediction) external nonReentrant {
if (_resolvePrediction(_prediction)) {
if (_checkIsGameValidAndReturnStakesIfNot(msg.sender, _prediction)) {
_claim(msg.sender, _prediction);
}
}
}
/**
* @notice Helper to estimate user positions and raw rewards without executing a claim.
* @param _user Address of the user.
* @param _prediction Address of the prediction creator.
*
* @return yesBalance User balance of “yes” 6909 tokens.
* @return noBalance User balance of “no” 6909 tokens.
* @return yesTotal Total supply of “yes” tokens.
* @return noTotal Total supply of “no” tokens.
* @return yesReward Raw share of loser pool if “yes” wins (before fees).
* @return noReward Raw share of loser pool if “no” wins (before fees).
*/
function getUserEstimates(address _user, address _prediction)
external
view
returns (
uint256 yesBalance,
uint256 noBalance,
uint256 yesTotal,
uint256 noTotal,
uint256 yesReward,
uint256 noReward,
uint256 currentPrice
)
{
Prediction storage p = predictions[_prediction];
(uint256 yesToken, uint256 noToken) = hlpGet6909Ids(_prediction);
yesBalance = balanceOf(_user, yesToken);
noBalance = balanceOf(_user, noToken);
yesTotal = totalSupply(yesToken);
noTotal = totalSupply(noToken);
uint256 estimateFee;
currentPrice = p.resolvedPrice;
if (currentPrice > 0) {
// if we here then prediction already resolved and we can
// show reward to user
if (yesTotal > 0) {
yesReward = noTotal * (yesBalance * SCALE / yesTotal) / SCALE;
estimateFee = (yesReward * (FEE_CREATOR_PERCENT + FEE_PROTOCOL_PERCENT) * SCALE)
/ PERCENT_DENOMINATOR / SCALE;
yesReward -= estimateFee;
}
if (noTotal > 0) {
noReward = yesTotal * (noBalance * SCALE / noTotal) / SCALE;
estimateFee = (noReward * (FEE_CREATOR_PERCENT + FEE_PROTOCOL_PERCENT) * SCALE)
/ PERCENT_DENOMINATOR / SCALE;
noReward -= estimateFee;
}
} else {
currentPrice = _getCurrentOraclePrice(_prediction, p);
}
}
/**
* @notice Helper to compute ERC6909 token IDs for given prediction.
* @param _prediction Address of prediction creator.
* @return yesId Token ID for “yes” shares.
* @return noId Token ID for “no” shares.
*
* @dev Encoding:
* yesId = (uint160(creator) << 96) | 1
* noId = (uint160(creator) << 96)
*/
function hlpGet6909Ids(address _prediction) public pure returns (uint256 yesId, uint256 noId) {
yesId = (uint256(uint160(_prediction)) << 96) | 1;
noId = (uint256(uint160(_prediction)) << 96);
}
/**
* @notice Builds a Permit2 `PermitTransferFrom` struct and the corresponding EIP-712 digest
* for signing an off-chain approval that allows staking via Permit2.
*
* @dev This helper is intended for frontend / off-chain usage.
* It prepares:
* - a Permit2-compatible permit allowing this contract to pull exactly
* `strike.amount` of `strike.token` from the signer
* - the EIP-712 digest that must be signed by the user
*
* The resulting signature can later be passed to {voteWithPermit2}.
*
* @param _prediction Address of the prediction creator (prediction identifier).
* @param _deadline Unix timestamp after which the permit becomes invalid.
*
* @return permit Permit2 `PermitTransferFrom` struct containing:
* - token permissions (token + exact amount)
* - nonce
* - deadline
*
* @return digest EIP-712 digest to be signed by the user for Permit2 execution.
*
* @custom:security
* - The nonce is derived from `(prediction, block.timestamp)` and is intended
* for short-lived, UI-generated permits.
* - Frontends MUST ensure the signature is used promptly to avoid nonce reuse.
* - This function does NOT store any state and does NOT guarantee nonce uniqueness
* across blocks or chains.
*
* @custom:integration
* - The returned `digest` must be signed using `eth_signTypedData_v4`.
* - The signed permit must be submitted via `voteWithPermit2`.
*
* @custom:warning
* - This helper assumes Permit2 DOMAIN_SEPARATOR is stable for the target chain.
* - Contracts relying on deterministic nonces should override this logic.
*/
function hlpGetPermitAndDigest(address _prediction, uint256 _deadline)
public
view
returns (IPermit2Minimal.PermitTransferFrom memory permit, bytes32 digest, bytes32 hashedDigest)
{
Prediction storage p = predictions[_prediction];
bytes32 DOMAIN_SEPARATOR = IPermit2Minimal(PERMIT2).DOMAIN_SEPARATOR();
IPermit2Minimal.TokenPermissions memory tp = IPermit2Minimal.TokenPermissions(p.strike.token, p.strike.amount);
// (uint256 yesToken, uint256 noToken) = hlpGet6909Ids(_prediction);
uint256 nonce = uint256(keccak256(abi.encodePacked(_prediction, block.timestamp, block.chainid)));
permit = IPermit2Minimal.PermitTransferFrom(tp, nonce, _deadline);
bytes32 tokenPermissions = keccak256(abi.encode(_TOKEN_PERMISSIONS_TYPEHASH, tp));
digest = keccak256(abi.encode(_PERMIT_TRANSFER_FROM_TYPEHASH, tokenPermissions, address(this), nonce, _deadline));
hashedDigest = keccak256(
abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, digest)
);
}
// ==================================
// INTERNAL LOGIC
// ==================================
function _checkPrediction(address _creator, Prediction calldata _pred) internal virtual {}
/**
* @dev Internal implementation of prediction creation.
* Reverts if creator already has an active prediction.
*/
function _createPrediction(address _creator, Prediction calldata _pred) internal virtual {
Prediction storage p = predictions[_creator];
if (p.expirationTime != 0) {
revert ActivePredictionExist(_creator);
}
predictions[_creator] = _pred;
}
/**
* @dev Internal voting logic.
* Mints ERC6909 vote-shares and pulls the user's ERC20 stake.
* @param _user Voting user.
* @param _prediction Prediction creator address.
* @param _agree Vote type (true = yes, false = no).
*/
function _vote(address _user, address _prediction, bool _agree) internal returns (address, uint96) {
Prediction storage p = predictions[_prediction];
if (p.expirationTime == 0) revert PredictionNotExist(_prediction);
// Only allow voting before expiration
if (p.expirationTime > block.timestamp + STOP_BEFORE_EXPIRED) {
//CompactAsset storage s = p.strike;
// Construct 6909 tokenId
uint256 tokenId = (uint256(uint160(_prediction)) << 96) | (_agree ? 1 : 0);
// Mint share tokens equal to strike amount
_mint(_user, tokenId, p.strike.amount);
} else {
revert PredictionExpired(_prediction, p.expirationTime);
}
emit Voted(_user, _prediction, _agree);
return (p.strike.token, p.strike.amount);
}
/**
* @dev Resolve a prediction by fetching its actual price from oracle.
* Only executes once per prediction (idempotent).
*
* @return isResolved True if prediction has a non-zero resolvedPrice after the call.
*
* Requirements:
* - Prediction MUST exist.
* - Current time MUST be >= expirationTime.
* - Oracle price MUST fit into uint96.
*/
function _resolvePrediction(address _prediction) internal virtual returns (bool isResolved) {
Prediction storage p = predictions[_prediction];
if (
p.expirationTime <= block.timestamp // time to resolve came
&& p.resolvedPrice == 0 // implicit resolved flag
) {
uint256 oraclePrice = _getCurrentOraclePrice(_prediction, p);
if (oraclePrice > type(uint96).max) {
revert OraclePriceTooHigh(oraclePrice);
}
p.resolvedPrice = uint96(oraclePrice);
emit PredictionResolved(_prediction, oraclePrice);
}
isResolved = p.resolvedPrice > 0;
}
/// @dev Handles the "no-contest" case: if either YES or NO totalSupply is zero,
/// user gets their stake refunded for both sides they hold, and their 6909 shares are pulled back.
/// @return isValidGame True if both sides have non-zero totalSupply.
function _checkIsGameValidAndReturnStakesIfNot(address _user, address _prediction)
internal
returns (bool isValidGame)
{
(uint256 yesToken, uint256 noToken) = hlpGet6909Ids(_prediction);
isValidGame = totalSupply(yesToken) > 0 && totalSupply(noToken) > 0;
CompactAsset storage s = predictions[_prediction].strike;
//if we have bets only one side then no game situation
//and users can get back their bets
if (!isValidGame) {
uint256 y = balanceOf(_user, yesToken);
uint256 n = balanceOf(_user, noToken);
// 1. Pull back ERC6909 share tokens (not burned in this version)
_transfer(_user, address(this), yesToken, y);
// 1. Pull back ERC6909 share tokens (not burned in this version)
_transfer(_user, address(this), noToken, n);
// 2. Return original stake
IERC20(s.token).safeTransfer(_user, y);
IERC20(s.token).safeTransfer(_user, n);
}
}
/**
* @dev Claim the reward for a winning voter.
* Handles:
* - returning the original stake
* - pulling back 6909 share tokens
* - distributing fee to creator + protocol
* - paying remaining reward to user
*
* @param _user Address of the claimant.
* @param _prediction Address of the prediction creator.
*/
function _claim(address _user, address _prediction) internal {
(uint256 winTokenId, uint256 winTokenBalance,, uint256 winnerPrize) =
_getWinnerShareAndAmount(_user, _prediction);
CompactAsset storage s = predictions[_prediction].strike;
if (winnerPrize > 0) {
uint256 paid;
uint256 fee;
// 1. Pull back ERC6909 share tokens (not burned in this version)
_transfer(_user, address(this), winTokenId, winTokenBalance);
// 2. Return original stake
IERC20(s.token).safeTransfer(_user, winTokenBalance);
// 3. Creator fee
fee = (winnerPrize * FEE_CREATOR_PERCENT * SCALE) / PERCENT_DENOMINATOR / SCALE;
paid += fee;
IERC20(s.token).safeTransfer(_prediction, fee);
// 4. Protocol fee
fee = (winnerPrize * FEE_PROTOCOL_PERCENT * SCALE) / PERCENT_DENOMINATOR / SCALE;
paid += fee;
IERC20(s.token).safeTransfer(FEE_PROTOCOL_BENEFICIARY, fee);
// 5. User reward (winnerPrize minus all fees)
uint256 userReward = winnerPrize - paid;
IERC20(s.token).safeTransfer(_user, userReward);
emit Claimed(_user, _prediction, userReward);
}
}
/**
* @dev Calculates:
* - tokenId of winning vote
* - user balance of winning tokens
* - user's share percentage (non-denominated)
* - total reward owed, proportional to losing pool
*
* @return winTokenId ID of the winning ERC6909 token.
* @return winTokenBalance User balance of winning token.
* @return sharesNonDenominated Fraction in PERCENT_DENOMINATOR units.
* @return prizeAmount Raw prize before fee splits.
*/
function _getWinnerShareAndAmount(address _user, address _prediction)
internal
view
returns (uint256 winTokenId, uint256 winTokenBalance, uint256 sharesNonDenominated, uint256 prizeAmount)
{
Prediction storage p = predictions[_prediction];
// True if predictedPrice <= actual oracle result
bool predictedTrue = p.predictedPrice.amount <= p.resolvedPrice;
// Determine winning and losing token IDs
winTokenId = (uint256(uint160(_prediction)) << 96) | (predictedTrue ? 1 : 0);
uint256 loserTokenId = (uint256(uint160(_prediction)) << 96) | (!predictedTrue ? 1 : 0);
winTokenBalance = balanceOf(_user, winTokenId);
if (winTokenBalance == 0) {
return (winTokenId, 0, 0, 0);
}
// User share = userVotes / totalVotes
uint256 totalWin = totalSupply(winTokenId);
sharesNonDenominated = (winTokenBalance * SCALE) / totalWin;
// Prize = share * totalLosingPool
uint256 totalLose = totalSupply(loserTokenId);
prizeAmount = (totalLose * sharesNonDenominated) / SCALE;
}
function _getCurrentOraclePrice(address _prediction, Prediction storage p)
internal
view
returns (uint256 oraclePrice)
{
address oracleAddress = p.predictedPrice.oracle;
oraclePrice = IEnvelopOracle(oracleAddress).getIndexPrice(_prediction);
if (oraclePrice == 0) {
oraclePrice = IEnvelopOracle(oracleAddress).getIndexPrice(p.portfolio);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC6909/extensions/ERC6909TokenSupply.sol)
pragma solidity ^0.8.20;
import {ERC6909} from "../ERC6909.sol";
import {IERC6909TokenSupply} from "../../../interfaces/IERC6909.sol";
/**
* @dev Implementation of the Token Supply extension defined in ERC6909.
* Tracks the total supply of each token id individually.
*/
contract ERC6909TokenSupply is ERC6909, IERC6909TokenSupply {
mapping(uint256 id => uint256) private _totalSupplies;
/// @inheritdoc IERC6909TokenSupply
function totalSupply(uint256 id) public view virtual override returns (uint256) {
return _totalSupplies[id];
}
/// @dev Override the `_update` function to update the total supply of each token id as necessary.
function _update(address from, address to, uint256 id, uint256 amount) internal virtual override {
super._update(from, to, id, amount);
if (from == address(0)) {
_totalSupplies[id] += amount;
}
if (to == address(0)) {
unchecked {
// amount <= _balances[from][id] <= _totalSupplies[id]
_totalSupplies[id] -= amount;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {StorageSlot} from "./StorageSlot.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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* 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].
*
* IMPORTANT: Deprecated. This storage-based reentrancy guard will be removed and replaced
* by the {ReentrancyGuardTransient} variant in v6.0.
*
* @custom:stateless
*/
abstract contract ReentrancyGuard {
using StorageSlot for bytes32;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
// 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;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_reentrancyGuardStorageSlot().getUint256Slot().value = 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();
}
/**
* @dev A `view` only version of {nonReentrant}. Use to block view functions
* from being called, preventing reading from inconsistent contract state.
*
* CAUTION: This is a "view" modifier and does not change the reentrancy
* status. Use it only on view functions. For payable or non-payable functions,
* use the standard {nonReentrant} modifier instead.
*/
modifier nonReentrantView() {
_nonReentrantBeforeView();
_;
}
function _nonReentrantBeforeView() private view {
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
_nonReentrantBeforeView();
// Any calls to nonReentrant after this point will fail
_reentrancyGuardStorageSlot().getUint256Slot().value = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_reentrancyGuardStorageSlot().getUint256Slot().value = 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 _reentrancyGuardStorageSlot().getUint256Slot().value == ENTERED;
}
function _reentrancyGuardStorageSlot() internal pure virtual returns (bytes32) {
return REENTRANCY_GUARD_STORAGE;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
if (!_safeTransfer(token, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
if (!_safeTransferFrom(token, from, to, value, true)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _safeTransfer(token, to, value, false);
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _safeTransferFrom(token, from, to, value, false);
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
if (!_safeApprove(token, spender, value, false)) {
if (!_safeApprove(token, spender, 0, true)) revert SafeERC20FailedOperation(address(token));
if (!_safeApprove(token, spender, value, true)) revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that relies on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Oppositely, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity `token.transfer(to, value)` call, relaxing the requirement on the return value: the
* return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransfer(IERC20 token, address to, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.transfer.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(to, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
/**
* @dev Imitates a Solidity `token.transferFrom(from, to, value)` call, relaxing the requirement on the return
* value: the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param from The sender of the tokens
* @param to The recipient of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value,
bool bubble
) private returns (bool success) {
bytes4 selector = IERC20.transferFrom.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(from, shr(96, not(0))))
mstore(0x24, and(to, shr(96, not(0))))
mstore(0x44, value)
success := call(gas(), token, 0, 0x00, 0x64, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
mstore(0x60, 0)
}
}
/**
* @dev Imitates a Solidity `token.approve(spender, value)` call, relaxing the requirement on the return value:
* the return value is optional (but if data is returned, it must not be false).
*
* @param token The token targeted by the call.
* @param spender The spender of the tokens
* @param value The amount of token to transfer
* @param bubble Behavior switch if the transfer call reverts: bubble the revert reason or return a false boolean.
*/
function _safeApprove(IERC20 token, address spender, uint256 value, bool bubble) private returns (bool success) {
bytes4 selector = IERC20.approve.selector;
assembly ("memory-safe") {
let fmp := mload(0x40)
mstore(0x00, selector)
mstore(0x04, and(spender, shr(96, not(0))))
mstore(0x24, value)
success := call(gas(), token, 0, 0x00, 0x44, 0x00, 0x20)
// if call success and return is true, all is good.
// otherwise (not success or return is not true), we need to perform further checks
if iszero(and(success, eq(mload(0x00), 1))) {
// if the call was a failure and bubble is enabled, bubble the error
if and(iszero(success), bubble) {
returndatacopy(fmp, 0x00, returndatasize())
revert(fmp, returndatasize())
}
// if the return value is not true, then the call is only successful if:
// - the token address has code
// - the returndata is empty
success := and(success, and(iszero(returndatasize()), gt(extcodesize(token), 0)))
}
mstore(0x40, fmp)
}
}
}// SPDX-License-Identifier: MIT
// ENVELOP(NIFTSY) protocol V2 for NFT. Onchain Oracle
pragma solidity ^0.8.28;
/// @dev Compact representation of an ERC20 asset + amount.
/// Used both for strike configuration and as portfolio items for the oracle.
struct CompactAsset {
address token; // ERC20 token address (20 bytes)
uint96 amount; // Amount with token decimals (12 bytes)
}
struct OracleData {
address oracle; //Data Provider address
uint96 amount; // Amount with token decimals (12 bytes)
}
/// @dev Oracle interface for retrieving index prices.
/// Supports:
/// - price by index address
/// - price by custom portfolio composition
interface IEnvelopOracle {
function getIndexPrice(address _v2Index) external view returns (uint256);
function getIndexPrice(CompactAsset[] calldata _assets) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// ENVELOP(NIFTSY) protocol V2 for NFT. Permit2 minimal
pragma solidity ^0.8.28;
bytes32 constant _TOKEN_PERMISSIONS_TYPEHASH = keccak256("TokenPermissions(address token,uint256 amount)");
bytes32 constant _PERMIT_TRANSFER_FROM_TYPEHASH = keccak256(
"PermitTransferFrom(TokenPermissions permitted,address spender,uint256 nonce,uint256 deadline)TokenPermissions(address token,uint256 amount)"
);
/// @dev Compact representation of an ERC20 asset + amount.
/// @dev Minimal Permit2 interface for signature-based transfers
interface IPermit2Minimal {
/// @notice The token and amount details for a transfer signed in the permit transfer signature
struct TokenPermissions {
// ERC20 token address
address token;
// the maximum amount that can be spent
uint256 amount;
}
/// @notice The signed permit message for a single token transfer
struct PermitTransferFrom {
TokenPermissions permitted;
// a unique value for every token owner's signature to prevent signature replays
uint256 nonce;
// deadline on the permit signature
uint256 deadline;
}
/// @notice Specifies the recipient address and amount for batched transfers.
/// @dev Recipients and amounts correspond to the index of the signed token permissions array.
/// @dev Reverts if the requested amount is greater than the permitted signed amount.
struct SignatureTransferDetails {
// recipient address
address to;
// spender requested amount
uint256 requestedAmount;
}
/// @notice Transfers a token using a signed permit message
/// @dev Reverts if the requested amount is greater than the permitted signed amount
/// @param permit The permit data signed over by the owner
/// @param owner The owner of the tokens to transfer
/// @param transferDetails The spender's requested transfer details for the permitted token
/// @param signature The signature to verify
function permitTransferFrom(
PermitTransferFrom memory permit,
SignatureTransferDetails calldata transferDetails,
address owner,
bytes calldata signature
) external;
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice A map from token owner address and a caller specified word index to a bitmap. Used to set bits in the bitmap to prevent against signature replay protection
/// @dev Uses unordered nonces so that permit messages do not need to be spent in a certain order
/// @dev The mapping is indexed first by the token owner, then by an index specified in the nonce
/// @dev It returns a uint256 bitmap
/// @dev The index, or wordPosition is capped at type(uint248).max
function nonceBitmap(address, uint256) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (token/ERC6909/ERC6909.sol)
pragma solidity ^0.8.20;
import {IERC6909} from "../../interfaces/IERC6909.sol";
import {Context} from "../../utils/Context.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of ERC-6909.
* See https://eips.ethereum.org/EIPS/eip-6909
*/
contract ERC6909 is Context, ERC165, IERC6909 {
mapping(address owner => mapping(uint256 id => uint256)) private _balances;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
mapping(address owner => mapping(address spender => mapping(uint256 id => uint256))) private _allowances;
error ERC6909InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 id);
error ERC6909InsufficientAllowance(address spender, uint256 allowance, uint256 needed, uint256 id);
error ERC6909InvalidApprover(address approver);
error ERC6909InvalidReceiver(address receiver);
error ERC6909InvalidSender(address sender);
error ERC6909InvalidSpender(address spender);
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return interfaceId == type(IERC6909).interfaceId || super.supportsInterface(interfaceId);
}
/// @inheritdoc IERC6909
function balanceOf(address owner, uint256 id) public view virtual override returns (uint256) {
return _balances[owner][id];
}
/// @inheritdoc IERC6909
function allowance(address owner, address spender, uint256 id) public view virtual override returns (uint256) {
return _allowances[owner][spender][id];
}
/// @inheritdoc IERC6909
function isOperator(address owner, address spender) public view virtual override returns (bool) {
return _operatorApprovals[owner][spender];
}
/// @inheritdoc IERC6909
function approve(address spender, uint256 id, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, id, amount);
return true;
}
/// @inheritdoc IERC6909
function setOperator(address spender, bool approved) public virtual override returns (bool) {
_setOperator(_msgSender(), spender, approved);
return true;
}
/// @inheritdoc IERC6909
function transfer(address receiver, uint256 id, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), receiver, id, amount);
return true;
}
/// @inheritdoc IERC6909
function transferFrom(
address sender,
address receiver,
uint256 id,
uint256 amount
) public virtual override returns (bool) {
address caller = _msgSender();
if (sender != caller && !isOperator(sender, caller)) {
_spendAllowance(sender, caller, id, amount);
}
_transfer(sender, receiver, id, amount);
return true;
}
/**
* @dev Creates `amount` of token `id` and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address to, uint256 id, uint256 amount) internal {
if (to == address(0)) {
revert ERC6909InvalidReceiver(address(0));
}
_update(address(0), to, id, amount);
}
/**
* @dev Moves `amount` of token `id` from `from` to `to` without checking for approvals. This function verifies
* that neither the sender nor the receiver are address(0), which means it cannot mint or burn tokens.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 id, uint256 amount) internal {
if (from == address(0)) {
revert ERC6909InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC6909InvalidReceiver(address(0));
}
_update(from, to, id, amount);
}
/**
* @dev Destroys a `amount` of token `id` from `account`.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address from, uint256 id, uint256 amount) internal {
if (from == address(0)) {
revert ERC6909InvalidSender(address(0));
}
_update(from, address(0), id, amount);
}
/**
* @dev Transfers `amount` of token `id` from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 id, uint256 amount) internal virtual {
address caller = _msgSender();
if (from != address(0)) {
uint256 fromBalance = _balances[from][id];
if (fromBalance < amount) {
revert ERC6909InsufficientBalance(from, fromBalance, amount, id);
}
unchecked {
// Overflow not possible: amount <= fromBalance.
_balances[from][id] = fromBalance - amount;
}
}
if (to != address(0)) {
_balances[to][id] += amount;
}
emit Transfer(caller, from, to, id, amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner`'s `id` 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 id, uint256 amount) internal virtual {
if (owner == address(0)) {
revert ERC6909InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC6909InvalidSpender(address(0));
}
_allowances[owner][spender][id] = amount;
emit Approval(owner, spender, id, amount);
}
/**
* @dev Approve `spender` to operate on all of `owner`'s tokens
*
* This internal function is equivalent to `setOperator`, and can be used to e.g. set automatic allowances for
* certain subsystems, etc.
*
* Emits an {OperatorSet} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _setOperator(address owner, address spender, bool approved) internal virtual {
if (owner == address(0)) {
revert ERC6909InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC6909InvalidSpender(address(0));
}
_operatorApprovals[owner][spender] = approved;
emit OperatorSet(owner, spender, approved);
}
/**
* @dev Updates `owner`'s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 id, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender, id);
if (currentAllowance < type(uint256).max) {
if (currentAllowance < amount) {
revert ERC6909InsufficientAllowance(spender, currentAllowance, amount, id);
}
unchecked {
_allowances[owner][spender][id] = currentAllowance - amount;
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.5.0) (interfaces/IERC6909.sol)
pragma solidity >=0.6.2;
import {IERC165} from "../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC-6909 compliant contract, as defined in the
* https://eips.ethereum.org/EIPS/eip-6909[ERC].
*/
interface IERC6909 is IERC165 {
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set for a token of type `id`.
* The new allowance is `amount`.
*/
event Approval(address indexed owner, address indexed spender, uint256 indexed id, uint256 amount);
/**
* @dev Emitted when `owner` grants or revokes operator status for a `spender`.
*/
event OperatorSet(address indexed owner, address indexed spender, bool approved);
/**
* @dev Emitted when `amount` tokens of type `id` are moved from `sender` to `receiver` initiated by `caller`.
*/
event Transfer(
address caller,
address indexed sender,
address indexed receiver,
uint256 indexed id,
uint256 amount
);
/**
* @dev Returns the amount of tokens of type `id` owned by `owner`.
*/
function balanceOf(address owner, uint256 id) external view returns (uint256);
/**
* @dev Returns the amount of tokens of type `id` that `spender` is allowed to spend on behalf of `owner`.
*
* NOTE: Does not include operator allowances.
*/
function allowance(address owner, address spender, uint256 id) external view returns (uint256);
/**
* @dev Returns true if `spender` is set as an operator for `owner`.
*/
function isOperator(address owner, address spender) external view returns (bool);
/**
* @dev Sets an approval to `spender` for `amount` of tokens of type `id` from the caller's tokens. An `amount` of
* `type(uint256).max` signifies an unlimited approval.
*
* Must return true.
*/
function approve(address spender, uint256 id, uint256 amount) external returns (bool);
/**
* @dev Grants or revokes unlimited transfer permission of any token id to `spender` for the caller's tokens.
*
* Must return true.
*/
function setOperator(address spender, bool approved) external returns (bool);
/**
* @dev Transfers `amount` of token type `id` from the caller's account to `receiver`.
*
* Must return true.
*/
function transfer(address receiver, uint256 id, uint256 amount) external returns (bool);
/**
* @dev Transfers `amount` of token type `id` from `sender` to `receiver`.
*
* Must return true.
*/
function transferFrom(address sender, address receiver, uint256 id, uint256 amount) external returns (bool);
}
/**
* @dev Optional extension of {IERC6909} that adds metadata functions.
*/
interface IERC6909Metadata is IERC6909 {
/**
* @dev Returns the name of the token of type `id`.
*/
function name(uint256 id) external view returns (string memory);
/**
* @dev Returns the ticker symbol of the token of type `id`.
*/
function symbol(uint256 id) external view returns (string memory);
/**
* @dev Returns the number of decimals for the token of type `id`.
*/
function decimals(uint256 id) external view returns (uint8);
}
/**
* @dev Optional extension of {IERC6909} that adds content URI functions.
*/
interface IERC6909ContentURI is IERC6909 {
/**
* @dev Returns URI for the contract.
*/
function contractURI() external view returns (string memory);
/**
* @dev Returns the URI for the token of type `id`.
*/
function tokenURI(uint256 id) external view returns (string memory);
}
/**
* @dev Optional extension of {IERC6909} that adds a token supply function.
*/
interface IERC6909TokenSupply is IERC6909 {
/**
* @dev Returns the total supply of the token of type `id`.
*/
function totalSupply(uint256 id) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
pragma solidity ^0.8.20;
/**
* @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 ERC-1967 implementation slot:
* ```solidity
* contract ERC1967 {
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
*
* function _getImplementation() internal view returns (address) {
* return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
* }
*
* function _setImplementation(address newImplementation) internal {
* require(newImplementation.code.length > 0);
* StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library StorageSlot {
struct AddressSlot {
address value;
}
struct BooleanSlot {
bool value;
}
struct Bytes32Slot {
bytes32 value;
}
struct Uint256Slot {
uint256 value;
}
struct Int256Slot {
int256 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) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `Int256Slot` with member `value` located at `slot`.
*/
function getInt256Slot(bytes32 slot) internal pure returns (Int256Slot storage r) {
assembly ("memory-safe") {
r.slot := slot
}
}
/**
* @dev Returns a `StringSlot` with member `value` located at `slot`.
*/
function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
assembly ("memory-safe") {
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) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
/**
* @dev Returns a `BytesSlot` with member `value` located at `slot`.
*/
function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
assembly ("memory-safe") {
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) {
assembly ("memory-safe") {
r.slot := store.slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
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 value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` 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 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";{
"remappings": [
"@openzeppelin/=lib/openzeppelin-contracts/",
"@Uopenzeppelin/=lib/openzeppelin-contracts-upgradeable/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "prague",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_feeBeneficiary","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ActivePredictionExist","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC6909InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ERC6909InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC6909InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC6909InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC6909InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC6909InvalidSpender","type":"error"},{"inputs":[{"internalType":"uint256","name":"oraclePrice","type":"uint256"}],"name":"OraclePriceTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"prediction","type":"address"},{"internalType":"uint40","name":"expirationTime","type":"uint40"}],"name":"PredictionExpired","type":"error"},{"inputs":[{"internalType":"address","name":"prediction","type":"address"}],"name":"PredictionNotExist","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualTimestamp","type":"uint256"}],"name":"TooLongPrediction","type":"error"},{"inputs":[{"internalType":"uint256","name":"actualLength","type":"uint256"}],"name":"TooManyPortfolioItems","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"prediction","type":"address"},{"indexed":false,"internalType":"uint256","name":"reward","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"OperatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"creator","type":"address"},{"indexed":false,"internalType":"uint40","name":"expirationTime","type":"uint40"}],"name":"PredictionCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"prediction","type":"address"},{"indexed":false,"internalType":"uint256","name":"resolvedPrice","type":"uint256"}],"name":"PredictionResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":true,"internalType":"address","name":"prediction","type":"address"},{"indexed":false,"internalType":"bool","name":"agree","type":"bool"}],"name":"Voted","type":"event"},{"inputs":[],"name":"FEE_CREATOR_PERCENT","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PROTOCOL_BENEFICIARY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_PROTOCOL_PERCENT","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PORTFOLIO_LEN","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_PREDICTION_PERIOD","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERCENT_DENOMINATOR","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT2_TTL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SCALE","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STOP_BEFORE_EXPIRED","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"internalType":"struct CompactAsset","name":"strike","type":"tuple"},{"components":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"internalType":"struct OracleData","name":"predictedPrice","type":"tuple"},{"internalType":"uint40","name":"expirationTime","type":"uint40"},{"internalType":"uint96","name":"resolvedPrice","type":"uint96"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"internalType":"struct CompactAsset[]","name":"portfolio","type":"tuple[]"}],"internalType":"struct Predicter.Prediction","name":"_pred","type":"tuple"}],"name":"createPrediction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_prediction","type":"address"}],"name":"getUserEstimates","outputs":[{"internalType":"uint256","name":"yesBalance","type":"uint256"},{"internalType":"uint256","name":"noBalance","type":"uint256"},{"internalType":"uint256","name":"yesTotal","type":"uint256"},{"internalType":"uint256","name":"noTotal","type":"uint256"},{"internalType":"uint256","name":"yesReward","type":"uint256"},{"internalType":"uint256","name":"noReward","type":"uint256"},{"internalType":"uint256","name":"currentPrice","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"}],"name":"hlpGet6909Ids","outputs":[{"internalType":"uint256","name":"yesId","type":"uint256"},{"internalType":"uint256","name":"noId","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"},{"internalType":"uint256","name":"_deadline","type":"uint256"}],"name":"hlpGetPermitAndDigest","outputs":[{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2Minimal.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2Minimal.PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"bytes32","name":"hashedDigest","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"isOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"creator","type":"address"}],"name":"predictions","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"internalType":"struct CompactAsset","name":"strike","type":"tuple"},{"components":[{"internalType":"address","name":"oracle","type":"address"},{"internalType":"uint96","name":"amount","type":"uint96"}],"internalType":"struct OracleData","name":"predictedPrice","type":"tuple"},{"internalType":"uint40","name":"expirationTime","type":"uint40"},{"internalType":"uint96","name":"resolvedPrice","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setOperator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"},{"internalType":"bool","name":"_agree","type":"bool"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"},{"internalType":"bool","name":"_agree","type":"bool"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2Minimal.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2Minimal.PermitTransferFrom","name":"permit","type":"tuple"},{"components":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"requestedAmount","type":"uint256"}],"internalType":"struct IPermit2Minimal.SignatureTransferDetails","name":"transfer","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"voteWithPermit2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_prediction","type":"address"},{"internalType":"bool","name":"_agree","type":"bool"},{"components":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct IPermit2Minimal.TokenPermissions","name":"permitted","type":"tuple"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"internalType":"struct IPermit2Minimal.PermitTransferFrom","name":"permit","type":"tuple"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"voteWithPermit2","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a0604052348015600e575f5ffd5b5060405161257c38038061257c833981016040819052602b91605f565b60017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00556001600160a01b0316608052608a565b5f60208284031215606e575f5ffd5b81516001600160a01b03811681146083575f5ffd5b9392505050565b6080516124d36100a95f395f818161028801526112f201526124d35ff3fe608060405234801561000f575f5ffd5b50600436106101ba575f3560e01c80639e6c2959116100f3578063c19b13aa11610093578063eced55261161006e578063eced55261461059b578063f8ea7eb6146105aa578063fd8caf15146105b2578063fe99049a146105bd575f5ffd5b8063c19b13aa14610578578063c6176ae81461058b578063d0c4f4c914610594575f5ffd5b8063b6363cf2116100ce578063b6363cf2146104ee578063bc74500e14610529578063bd041c4d14610546578063bd85b03914610559575f5ffd5b80639e6c2959146104b2578063a1735138146104d3578063aa84aaee146104e6575f5ffd5b8063426a84931161015e578063558a729711610139578063558a729714610437578063598af9e71461044a5780636afdd850146104895780638debc55d1461049f575f5ffd5b8063426a8493146103a5578063503815cc146103b857806350497b42146103ef575f5ffd5b80631906476d116101995780631906476d1461021a5780631e83409a1461026e5780632d3e82e61461028357806335fa61fa146102c2575f5ffd5b8062fdd58e146101be57806301ffc9a7146101e4578063095bcdb614610207575b5f5ffd5b6101d16101cc366004611cf6565b6105d0565b6040519081526020015b60405180910390f35b6101f76101f2366004611d20565b6105f8565b60405190151581526020016101db565b6101f7610215366004611d47565b61062c565b61022d610228366004611cf6565b610644565b60408051845180516001600160a01b0316825260209081015181830152850151818301529301516060840152608083019190915260a082015260c0016101db565b61028161027c366004611d79565b61086f565b005b6102aa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101db565b6103496102d0366004611d79565b600460209081525f9182526040918290208251808401845281546001600160a01b0380821683526001600160601b03600160a01b9283900481168487015286518088019097526001850154918216875291900481169385019390935260029091015490929164ffffffffff821691600160281b90041684565b6040805185516001600160a01b0390811682526020968701516001600160601b039081168884015286519091169282019290925294909301518316606085015264ffffffffff90911660808401521660a082015260c0016101db565b6101f76103b3366004611d47565b6108b7565b6103da6103c6366004611d79565b60601b6001600160601b0319166001811791565b604080519283526020830191909152016101db565b6104026103fd366004611d94565b6108c4565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016101db565b6101f7610445366004611ddf565b610a9d565b6101d1610458366004611e12565b6001600160a01b039283165f9081526002602090815260408083209490951682529283528381209181529152205490565b6102aa6e22d473030f116ddee9f6b43ac78ba381565b6102816104ad366004611eab565b610ab2565b6104bb61271081565b6040516001600160601b0390911681526020016101db565b6102816104e1366004611f3c565b610c94565b6101d1606481565b6101f76104fc366004611d94565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205460ff1690565b6105305f81565b60405164ffffffffff90911681526020016101db565b610281610554366004611ddf565b610dcd565b6101d1610567366004611fb0565b5f9081526003602052604090205490565b610281610586366004611fc7565b610e21565b6101d161025881565b6104bb5f81565b6104bb670de0b6b3a764000081565b6104bb606481565b6105306305265c0081565b6101f76105cb366004611ffe565b610f20565b6001600160a01b0382165f908152602081815260408083208484529091529020545b92915050565b5f6001600160e01b03198216630f632fb360e01b14806105f257506301ffc9a760e01b6001600160e01b03198316146105f2565b5f61063933858585610f89565b5060015b9392505050565b6040805160a0810182525f6060820181815260808301829052825260208083018290528284018290526001600160a01b038616825260048082528483208551633644e51560e01b81529551949593948594919385936e22d473030f116ddee9f6b43ac78ba393633644e51593818301939290918290030181865afa1580156106ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106f29190612041565b60408051808201825284546001600160a01b0381168252600160a01b90046001600160601b031660208083019190915291516001600160601b031960608c901b16928101929092524260348301524660548301529192505f90607401604051602081830303815290604052805190602001205f1c905060405180606001604052808381526020018281526020018981525096505f7f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1836040516020016107b9929190612058565b60408051808303601f1901815282825280516020918201207f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068285015283830152306060840152608083019490945260a08083019b909b528051808303909b018b5260c0820181528a519a84019a909a2061190160f01b60e083015260e28201959095526101028082018690528a5180830390910181526101229091019099525087519701969096209497909650939450505050565b610877610fed565b61088081611008565b1561089e5761088f3382611114565b1561089e5761089e33826111ea565b6108b460015f51602061247e5f395f51905f5255565b50565b5f61063933858585611393565b6001600160a01b0381165f90815260046020526040812081908190819081908190819081806109018b60601b6001600160601b0319166001811791565b9150915061090f8c836105d0565b995061091b8c826105d0565b5f8381526003602052604080822054848352908220546002870154939c50909a509850600160281b9091046001600160601b031694508415610a805788156109e957670de0b6b3a764000089610971828e612093565b61097b91906120aa565b610985908a612093565b61098f91906120aa565b9650670de0b6b3a7640000612710816109a95f60646120c9565b6109bc906001600160601b03168b612093565b6109c69190612093565b6109d091906120aa565b6109da91906120aa565b90506109e681886120e8565b96505b8715610a7b57670de0b6b3a764000088610a03828d612093565b610a0d91906120aa565b610a17908b612093565b610a2191906120aa565b9550670de0b6b3a764000061271081610a3b5f60646120c9565b610a4e906001600160601b03168a612093565b610a589190612093565b610a6291906120aa565b610a6c91906120aa565b9050610a7881876120e8565b95505b610a8d565b610a8a8c85611452565b94505b5050505092959891949750929550565b5f610aa9338484611543565b50600192915050565b610aba610fed565b6001600160a01b038087165f908152600460209081526040909120805490921690610ae790870187611d79565b6001600160a01b031614610b395760405162461bcd60e51b81526020600482015260146024820152732832b936b4ba191d103bb937b733903a37b5b2b760611b60448201526064015b60405180910390fd5b30610b476020860186611d79565b6001600160a01b031614610b9d5760405162461bcd60e51b815260206004820152601860248201527f5065726d6974323a2077726f6e6720726563697069656e7400000000000000006044820152606401610b30565b8054600160a01b90046001600160601b0316602085013514610c015760405162461bcd60e51b815260206004820152601c60248201527f5065726d6974323a20696e73756666696369656e7420616d6f756e74000000006044820152606401610b30565b610c0c338888611601565b505060405163187945bd60e11b81526e22d473030f116ddee9f6b43ac78ba3906330f28b7a90610c489088908890339089908990600401612163565b5f604051808303815f87803b158015610c5f575f5ffd5b505af1158015610c71573d5f5f3e3d5ffd5b5050505050610c8c60015f51602061247e5f395f51905f5255565b505050505050565b610c9c610fed565b6001600160a01b038086165f908152600460209081526040909120805490921690610cc990860186611d79565b6001600160a01b031614610d165760405162461bcd60e51b81526020600482015260146024820152732832b936b4ba191d103bb937b733903a37b5b2b760611b6044820152606401610b30565b604080518082019091523081528154600160a01b90046001600160601b03166020820152610d45338888611601565b505060405163187945bd60e11b81526e22d473030f116ddee9f6b43ac78ba3906330f28b7a90610d81908890859033908a908a906004016121ad565b5f604051808303815f87803b158015610d98575f5ffd5b505af1158015610daa573d5f5f3e3d5ffd5b505050505050610dc660015f51602061247e5f395f51905f5255565b5050505050565b610dd5610fed565b5f5f610de2338585611601565b9092509050610e056001600160a01b03831633306001600160601b03851661176e565b5050610e1d60015f51602061247e5f395f51905f5255565b5050565b6064610e3060c08301836121d6565b90501115610e6357610e4560c08201826121d6565b60405163334e120b60e01b8152610b30925060040190815260200190565b610e71426305265c0061221c565b64ffffffffff16610e8860a083016080840161224b565b64ffffffffff161115610ec857610ea560a082016080830161224b565b604051630f355a4b60e01b815264ffffffffff9091166004820152602401610b30565b610ed233826117a4565b337f49590a953e4f7ed634e3098ee5653ebc3623584f3677075fd182a1cdf75b1160610f0460a084016080850161224b565b60405164ffffffffff909116815260200160405180910390a250565b5f336001600160a01b0386168114801590610f6057506001600160a01b038087165f9081526001602090815260408083209385168352929052205460ff16155b15610f7157610f7186828686611813565b610f7d86868686610f89565b50600195945050505050565b6001600160a01b038416610fb2576040516301486a4160e71b81525f6004820152602401610b30565b6001600160a01b038316610fdb57604051630b8bbd6160e41b81525f6004820152602401610b30565b610fe7848484846118c2565b50505050565b610ff5611927565b60025f51602061247e5f395f51905f5255565b6001600160a01b0381165f90815260046020526040812060028101544264ffffffffff9091161180159061104e57506002810154600160281b90046001600160601b0316155b156110f8575f61105e8483611452565b90506001600160601b0381111561108b5760405163117fa68b60e31b815260048101829052602401610b30565b60028201805470ffffffffffffffffffffffff00000000001916600160281b6001600160601b038416021790556040518181526001600160a01b038516907f2b3604031e8bef4a9d91a0ac0e5b51a703c8a979bf952a1bf12725215ad307319060200160405180910390a2505b60020154600160281b90046001600160601b0316151592915050565b5f5f5f61112f8460601b6001600160601b0319166001811791565b915091505f611149835f9081526003602052604090205490565b11801561116157505f81815260036020526040812054115b6001600160a01b0385165f908152600460205260409020909350836111e1575f61118b87856105d0565b90505f61119888856105d0565b90506111a688308785610f89565b6111b288308684610f89565b82546111c8906001600160a01b03168984611958565b82546111de906001600160a01b03168983611958565b50505b50505092915050565b5f5f5f6111f78585611992565b6001600160a01b0388165f908152600460205260409020939650919450909250508115610c8c575f5f61122c88308888610f89565b8254611242906001600160a01b03168987611958565b670de0b6b3a76400006127108161125a606488612093565b6112649190612093565b61126e91906120aa565b61127891906120aa565b90506112848183612266565b835490925061129d906001600160a01b03168883611958565b670de0b6b3a7640000612710816112b45f88612093565b6112be9190612093565b6112c891906120aa565b6112d291906120aa565b90506112de8183612266565b8354909250611317906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000083611958565b5f61132283866120e8565b845490915061133b906001600160a01b03168a83611958565b876001600160a01b0316896001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd39926838360405161138091815260200190565b60405180910390a3505050505050505050565b6001600160a01b0384166113bc5760405163198ecd5360e31b81525f6004820152602401610b30565b6001600160a01b0383166113e557604051636f65f46560e01b81525f6004820152602401610b30565b6001600160a01b038481165f8181526002602090815260408083209488168084529482528083208784528252918290208590559051848152859392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a450505050565b6001810154604051630b263e0160e41b81526001600160a01b0384811660048301525f921690819063b263e01090602401602060405180830381865afa15801561149e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c29190612041565b9150815f0361153c57604051630fcd356960e11b81526001600160a01b03821690631f9a6ad2906114fa906003870190600401612279565b602060405180830381865afa158015611515573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115399190612041565b91505b5092915050565b6001600160a01b03831661156c5760405163198ecd5360e31b81525f6004820152602401610b30565b6001600160a01b03821661159557604051636f65f46560e01b81525f6004820152602401610b30565b6001600160a01b038381165f81815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a3505050565b6001600160a01b0382165f908152600460205260408120600281015482919064ffffffffff16820361165157604051636db31fe360e11b81526001600160a01b0386166004820152602401610b30565b61165b5f42612266565b600282015464ffffffffff1611156116c2575f84611679575f61167c565b60015b60ff166060876001600160a01b0316901b1790506116bc8782845f015f0160149054906101000a90046001600160601b03166001600160601b0316611aac565b506116f9565b600281015460405163051a59dd60e21b81526001600160a01b038716600482015264ffffffffff9091166024820152604401610b30565b846001600160a01b0316866001600160a01b03167ff01e0648b75d055c003bb115baaa99af91e34a86a5405eb8b96e451bcb1c79f086604051611740911515815260200190565b60405180910390a3546001600160a01b03811696600160a01b9091046001600160601b031695509350505050565b61177c848484846001611ae1565b610fe757604051635274afe760e01b81526001600160a01b0385166004820152602401610b30565b6001600160a01b0382165f908152600460205260409020600281015464ffffffffff16156117f0576040516306cd244760e41b81526001600160a01b0384166004820152602401610b30565b6001600160a01b0383165f9081526004602052604090208290610dc682826123b2565b6001600160a01b038481165f9081526002602090815260408083209387168352928152828220858352905220545f19811015610dc6578181101561188a57604051632c51fead60e11b81526001600160a01b0385166004820152602481018290526044810183905260648101849052608401610b30565b6001600160a01b038086165f908152600260209081526040808320938816835292815282822086835290522082820390555050505050565b6118ce84848484611b4e565b6001600160a01b0384166118ff575f82815260036020526040812080548392906118f9908490612266565b90915550505b6001600160a01b038316610fe7575f8281526003602052604090208054829003905550505050565b5f51602061247e5f395f51905f525460020361195657604051633ee5aeb560e01b815260040160405180910390fd5b565b6119658383836001611c80565b61198d57604051635274afe760e01b81526001600160a01b0384166004820152602401610b30565b505050565b6001600160a01b0381165f90815260046020526040812060028101546001820154839283928392600160281b9091046001600160601b03908116600160a01b909204161115806119e2575f6119e5565b60015b60ff166060886001600160a01b0316901b1795505f8115611a06575f611a09565b60015b60ff166060896001600160a01b0316901b179050611a2789886105d0565b9550855f03611a4257505f9450849350839250611aa3915050565b5f8781526003602052604090205480611a63670de0b6b3a764000089612093565b611a6d91906120aa565b5f83815260036020526040902054909650670de0b6b3a7640000611a918883612093565b611a9b91906120aa565b955050505050505b92959194509250565b6001600160a01b038316611ad557604051630b8bbd6160e41b81525f6004820152602401610b30565b61198d5f8484846118c2565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316611b3d578383151615611b31573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b336001600160a01b03851615611be7576001600160a01b0385165f9081526020818152604080832086845290915290205482811015611bc0576040516302c6d3fb60e61b81526001600160a01b0387166004820152602481018290526044810184905260648101859052608401610b30565b6001600160a01b0386165f9081526020818152604080832087845290915290209083900390555b6001600160a01b03841615611c2c576001600160a01b0384165f9081526020818152604080832086845290915281208054849290611c26908490612266565b90915550505b604080516001600160a01b03838116825260208201859052859281881692918916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a45050505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316611cd6578383151615611cca573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6001600160a01b03811681146108b4575f5ffd5b5f5f60408385031215611d07575f5ffd5b8235611d1281611ce2565b946020939093013593505050565b5f60208284031215611d30575f5ffd5b81356001600160e01b03198116811461063d575f5ffd5b5f5f5f60608486031215611d59575f5ffd5b8335611d6481611ce2565b95602085013595506040909401359392505050565b5f60208284031215611d89575f5ffd5b813561063d81611ce2565b5f5f60408385031215611da5575f5ffd5b8235611db081611ce2565b91506020830135611dc081611ce2565b809150509250929050565b80358015158114611dda575f5ffd5b919050565b5f5f60408385031215611df0575f5ffd5b8235611dfb81611ce2565b9150611e0960208401611dcb565b90509250929050565b5f5f5f60608486031215611e24575f5ffd5b8335611e2f81611ce2565b92506020840135611e3f81611ce2565b929592945050506040919091013590565b5f60808284031215611e60575f5ffd5b50919050565b5f5f83601f840112611e76575f5ffd5b50813567ffffffffffffffff811115611e8d575f5ffd5b602083019150836020828501011115611ea4575f5ffd5b9250929050565b5f5f5f5f5f5f868803610120811215611ec2575f5ffd5b8735611ecd81611ce2565b9650611edb60208901611dcb565b9550611eea8960408a01611e50565b9450604060bf1982011215611efd575f5ffd5b5060c08701925061010087013567ffffffffffffffff811115611f1e575f5ffd5b611f2a89828a01611e66565b979a9699509497509295939492505050565b5f5f5f5f5f60e08688031215611f50575f5ffd5b8535611f5b81611ce2565b9450611f6960208701611dcb565b9350611f788760408801611e50565b925060c086013567ffffffffffffffff811115611f93575f5ffd5b611f9f88828901611e66565b969995985093965092949392505050565b5f60208284031215611fc0575f5ffd5b5035919050565b5f60208284031215611fd7575f5ffd5b813567ffffffffffffffff811115611fed575f5ffd5b820160e0818503121561063d575f5ffd5b5f5f5f5f60808587031215612011575f5ffd5b843561201c81611ce2565b9350602085013561202c81611ce2565b93969395505050506040820135916060013590565b5f60208284031215612051575f5ffd5b5051919050565b8281526060810161063d602083018480516001600160a01b03168252602090810151910152565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176105f2576105f261207f565b5f826120c457634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160601b0381811683821601908111156105f2576105f261207f565b818103818111156105f2576105f261207f565b803561210681611ce2565b6001600160a01b03168252602090810135910152565b61212682826120fb565b60408181013590830152606090810135910152565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61216d818761211c565b61217a60808201866120fb565b6001600160a01b03841660c082015261010060e082018190525f906121a2908301848661213b565b979650505050505050565b6121b7818761211c565b84516001600160a01b03166080820152602085015160a082015261217a565b5f5f8335601e198436030181126121eb575f5ffd5b83018035915067ffffffffffffffff821115612205575f5ffd5b6020019150600681901b3603821315611ea4575f5ffd5b64ffffffffff81811683821601908111156105f2576105f261207f565b64ffffffffff811681146108b4575f5ffd5b5f6020828403121561225b575f5ffd5b813561063d81612239565b808201808211156105f2576105f261207f565b602080825282548282018190525f848152918220906040840190835b818110156122c55783546001600160a01b038116845260a01c602084015260019384019360409093019201612295565b509095945050505050565b5f81356001600160601b03811681146105f2575f5ffd5b81356122f281611ce2565b81546001600160a01b03199081166001600160a01b0392909216918217835561231d602085016122d0565b60a01b1617905550565b6801000000000000000083111561234c57634e487b7160e01b5f52604160045260245ffd5b805483825580841015612381575f828152602090208481019082015b8082101561237e575f8255600182019150612368565b50505b505f8181526020812083915b85811015610c8c5761239f83836122e7565b604092909201916001918201910161238d565b6123bc82826122e7565b6123cc60408301600183016122e7565b6002810160808301356123de81612239565b815470ffffffffffffffffffffffff00000000006123fe60a087016122d0565b60281b1664ffffffffff831670ffffffffffffffffffffffffffffffffff198316171783555050505f5f60c0840135601e1985360301811261243e575f5ffd5b84018035915067ffffffffffffffff821115612458575f5ffd5b6020019150600681901b360382131561246f575f5ffd5b610fe781836003860161232756fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a264697066735822122046427da9da2d5a5b85f1aac3d4dfd4c80900329ca297ce3fa9eff53841e85a5064736f6c634300081e003300000000000000000000000013b9cbcb46ad79878af8c9faa835bee19b977d3d
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106101ba575f3560e01c80639e6c2959116100f3578063c19b13aa11610093578063eced55261161006e578063eced55261461059b578063f8ea7eb6146105aa578063fd8caf15146105b2578063fe99049a146105bd575f5ffd5b8063c19b13aa14610578578063c6176ae81461058b578063d0c4f4c914610594575f5ffd5b8063b6363cf2116100ce578063b6363cf2146104ee578063bc74500e14610529578063bd041c4d14610546578063bd85b03914610559575f5ffd5b80639e6c2959146104b2578063a1735138146104d3578063aa84aaee146104e6575f5ffd5b8063426a84931161015e578063558a729711610139578063558a729714610437578063598af9e71461044a5780636afdd850146104895780638debc55d1461049f575f5ffd5b8063426a8493146103a5578063503815cc146103b857806350497b42146103ef575f5ffd5b80631906476d116101995780631906476d1461021a5780631e83409a1461026e5780632d3e82e61461028357806335fa61fa146102c2575f5ffd5b8062fdd58e146101be57806301ffc9a7146101e4578063095bcdb614610207575b5f5ffd5b6101d16101cc366004611cf6565b6105d0565b6040519081526020015b60405180910390f35b6101f76101f2366004611d20565b6105f8565b60405190151581526020016101db565b6101f7610215366004611d47565b61062c565b61022d610228366004611cf6565b610644565b60408051845180516001600160a01b0316825260209081015181830152850151818301529301516060840152608083019190915260a082015260c0016101db565b61028161027c366004611d79565b61086f565b005b6102aa7f00000000000000000000000013b9cbcb46ad79878af8c9faa835bee19b977d3d81565b6040516001600160a01b0390911681526020016101db565b6103496102d0366004611d79565b600460209081525f9182526040918290208251808401845281546001600160a01b0380821683526001600160601b03600160a01b9283900481168487015286518088019097526001850154918216875291900481169385019390935260029091015490929164ffffffffff821691600160281b90041684565b6040805185516001600160a01b0390811682526020968701516001600160601b039081168884015286519091169282019290925294909301518316606085015264ffffffffff90911660808401521660a082015260c0016101db565b6101f76103b3366004611d47565b6108b7565b6103da6103c6366004611d79565b60601b6001600160601b0319166001811791565b604080519283526020830191909152016101db565b6104026103fd366004611d94565b6108c4565b604080519788526020880196909652948601939093526060850191909152608084015260a083015260c082015260e0016101db565b6101f7610445366004611ddf565b610a9d565b6101d1610458366004611e12565b6001600160a01b039283165f9081526002602090815260408083209490951682529283528381209181529152205490565b6102aa6e22d473030f116ddee9f6b43ac78ba381565b6102816104ad366004611eab565b610ab2565b6104bb61271081565b6040516001600160601b0390911681526020016101db565b6102816104e1366004611f3c565b610c94565b6101d1606481565b6101f76104fc366004611d94565b6001600160a01b039182165f90815260016020908152604080832093909416825291909152205460ff1690565b6105305f81565b60405164ffffffffff90911681526020016101db565b610281610554366004611ddf565b610dcd565b6101d1610567366004611fb0565b5f9081526003602052604090205490565b610281610586366004611fc7565b610e21565b6101d161025881565b6104bb5f81565b6104bb670de0b6b3a764000081565b6104bb606481565b6105306305265c0081565b6101f76105cb366004611ffe565b610f20565b6001600160a01b0382165f908152602081815260408083208484529091529020545b92915050565b5f6001600160e01b03198216630f632fb360e01b14806105f257506301ffc9a760e01b6001600160e01b03198316146105f2565b5f61063933858585610f89565b5060015b9392505050565b6040805160a0810182525f6060820181815260808301829052825260208083018290528284018290526001600160a01b038616825260048082528483208551633644e51560e01b81529551949593948594919385936e22d473030f116ddee9f6b43ac78ba393633644e51593818301939290918290030181865afa1580156106ce573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106f29190612041565b60408051808201825284546001600160a01b0381168252600160a01b90046001600160601b031660208083019190915291516001600160601b031960608c901b16928101929092524260348301524660548301529192505f90607401604051602081830303815290604052805190602001205f1c905060405180606001604052808381526020018281526020018981525096505f7f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1836040516020016107b9929190612058565b60408051808303601f1901815282825280516020918201207f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068285015283830152306060840152608083019490945260a08083019b909b528051808303909b018b5260c0820181528a519a84019a909a2061190160f01b60e083015260e28201959095526101028082018690528a5180830390910181526101229091019099525087519701969096209497909650939450505050565b610877610fed565b61088081611008565b1561089e5761088f3382611114565b1561089e5761089e33826111ea565b6108b460015f51602061247e5f395f51905f5255565b50565b5f61063933858585611393565b6001600160a01b0381165f90815260046020526040812081908190819081908190819081806109018b60601b6001600160601b0319166001811791565b9150915061090f8c836105d0565b995061091b8c826105d0565b5f8381526003602052604080822054848352908220546002870154939c50909a509850600160281b9091046001600160601b031694508415610a805788156109e957670de0b6b3a764000089610971828e612093565b61097b91906120aa565b610985908a612093565b61098f91906120aa565b9650670de0b6b3a7640000612710816109a95f60646120c9565b6109bc906001600160601b03168b612093565b6109c69190612093565b6109d091906120aa565b6109da91906120aa565b90506109e681886120e8565b96505b8715610a7b57670de0b6b3a764000088610a03828d612093565b610a0d91906120aa565b610a17908b612093565b610a2191906120aa565b9550670de0b6b3a764000061271081610a3b5f60646120c9565b610a4e906001600160601b03168a612093565b610a589190612093565b610a6291906120aa565b610a6c91906120aa565b9050610a7881876120e8565b95505b610a8d565b610a8a8c85611452565b94505b5050505092959891949750929550565b5f610aa9338484611543565b50600192915050565b610aba610fed565b6001600160a01b038087165f908152600460209081526040909120805490921690610ae790870187611d79565b6001600160a01b031614610b395760405162461bcd60e51b81526020600482015260146024820152732832b936b4ba191d103bb937b733903a37b5b2b760611b60448201526064015b60405180910390fd5b30610b476020860186611d79565b6001600160a01b031614610b9d5760405162461bcd60e51b815260206004820152601860248201527f5065726d6974323a2077726f6e6720726563697069656e7400000000000000006044820152606401610b30565b8054600160a01b90046001600160601b0316602085013514610c015760405162461bcd60e51b815260206004820152601c60248201527f5065726d6974323a20696e73756666696369656e7420616d6f756e74000000006044820152606401610b30565b610c0c338888611601565b505060405163187945bd60e11b81526e22d473030f116ddee9f6b43ac78ba3906330f28b7a90610c489088908890339089908990600401612163565b5f604051808303815f87803b158015610c5f575f5ffd5b505af1158015610c71573d5f5f3e3d5ffd5b5050505050610c8c60015f51602061247e5f395f51905f5255565b505050505050565b610c9c610fed565b6001600160a01b038086165f908152600460209081526040909120805490921690610cc990860186611d79565b6001600160a01b031614610d165760405162461bcd60e51b81526020600482015260146024820152732832b936b4ba191d103bb937b733903a37b5b2b760611b6044820152606401610b30565b604080518082019091523081528154600160a01b90046001600160601b03166020820152610d45338888611601565b505060405163187945bd60e11b81526e22d473030f116ddee9f6b43ac78ba3906330f28b7a90610d81908890859033908a908a906004016121ad565b5f604051808303815f87803b158015610d98575f5ffd5b505af1158015610daa573d5f5f3e3d5ffd5b505050505050610dc660015f51602061247e5f395f51905f5255565b5050505050565b610dd5610fed565b5f5f610de2338585611601565b9092509050610e056001600160a01b03831633306001600160601b03851661176e565b5050610e1d60015f51602061247e5f395f51905f5255565b5050565b6064610e3060c08301836121d6565b90501115610e6357610e4560c08201826121d6565b60405163334e120b60e01b8152610b30925060040190815260200190565b610e71426305265c0061221c565b64ffffffffff16610e8860a083016080840161224b565b64ffffffffff161115610ec857610ea560a082016080830161224b565b604051630f355a4b60e01b815264ffffffffff9091166004820152602401610b30565b610ed233826117a4565b337f49590a953e4f7ed634e3098ee5653ebc3623584f3677075fd182a1cdf75b1160610f0460a084016080850161224b565b60405164ffffffffff909116815260200160405180910390a250565b5f336001600160a01b0386168114801590610f6057506001600160a01b038087165f9081526001602090815260408083209385168352929052205460ff16155b15610f7157610f7186828686611813565b610f7d86868686610f89565b50600195945050505050565b6001600160a01b038416610fb2576040516301486a4160e71b81525f6004820152602401610b30565b6001600160a01b038316610fdb57604051630b8bbd6160e41b81525f6004820152602401610b30565b610fe7848484846118c2565b50505050565b610ff5611927565b60025f51602061247e5f395f51905f5255565b6001600160a01b0381165f90815260046020526040812060028101544264ffffffffff9091161180159061104e57506002810154600160281b90046001600160601b0316155b156110f8575f61105e8483611452565b90506001600160601b0381111561108b5760405163117fa68b60e31b815260048101829052602401610b30565b60028201805470ffffffffffffffffffffffff00000000001916600160281b6001600160601b038416021790556040518181526001600160a01b038516907f2b3604031e8bef4a9d91a0ac0e5b51a703c8a979bf952a1bf12725215ad307319060200160405180910390a2505b60020154600160281b90046001600160601b0316151592915050565b5f5f5f61112f8460601b6001600160601b0319166001811791565b915091505f611149835f9081526003602052604090205490565b11801561116157505f81815260036020526040812054115b6001600160a01b0385165f908152600460205260409020909350836111e1575f61118b87856105d0565b90505f61119888856105d0565b90506111a688308785610f89565b6111b288308684610f89565b82546111c8906001600160a01b03168984611958565b82546111de906001600160a01b03168983611958565b50505b50505092915050565b5f5f5f6111f78585611992565b6001600160a01b0388165f908152600460205260409020939650919450909250508115610c8c575f5f61122c88308888610f89565b8254611242906001600160a01b03168987611958565b670de0b6b3a76400006127108161125a606488612093565b6112649190612093565b61126e91906120aa565b61127891906120aa565b90506112848183612266565b835490925061129d906001600160a01b03168883611958565b670de0b6b3a7640000612710816112b45f88612093565b6112be9190612093565b6112c891906120aa565b6112d291906120aa565b90506112de8183612266565b8354909250611317906001600160a01b03167f00000000000000000000000013b9cbcb46ad79878af8c9faa835bee19b977d3d83611958565b5f61132283866120e8565b845490915061133b906001600160a01b03168a83611958565b876001600160a01b0316896001600160a01b03167ff7a40077ff7a04c7e61f6f26fb13774259ddf1b6bce9ecf26a8276cdd39926838360405161138091815260200190565b60405180910390a3505050505050505050565b6001600160a01b0384166113bc5760405163198ecd5360e31b81525f6004820152602401610b30565b6001600160a01b0383166113e557604051636f65f46560e01b81525f6004820152602401610b30565b6001600160a01b038481165f8181526002602090815260408083209488168084529482528083208784528252918290208590559051848152859392917fb3fd5071835887567a0671151121894ddccc2842f1d10bedad13e0d17cace9a7910160405180910390a450505050565b6001810154604051630b263e0160e41b81526001600160a01b0384811660048301525f921690819063b263e01090602401602060405180830381865afa15801561149e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114c29190612041565b9150815f0361153c57604051630fcd356960e11b81526001600160a01b03821690631f9a6ad2906114fa906003870190600401612279565b602060405180830381865afa158015611515573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906115399190612041565b91505b5092915050565b6001600160a01b03831661156c5760405163198ecd5360e31b81525f6004820152602401610b30565b6001600160a01b03821661159557604051636f65f46560e01b81525f6004820152602401610b30565b6001600160a01b038381165f81815260016020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527fceb576d9f15e4e200fdb5096d64d5dfd667e16def20c1eefd14256d8e3faa267910160405180910390a3505050565b6001600160a01b0382165f908152600460205260408120600281015482919064ffffffffff16820361165157604051636db31fe360e11b81526001600160a01b0386166004820152602401610b30565b61165b5f42612266565b600282015464ffffffffff1611156116c2575f84611679575f61167c565b60015b60ff166060876001600160a01b0316901b1790506116bc8782845f015f0160149054906101000a90046001600160601b03166001600160601b0316611aac565b506116f9565b600281015460405163051a59dd60e21b81526001600160a01b038716600482015264ffffffffff9091166024820152604401610b30565b846001600160a01b0316866001600160a01b03167ff01e0648b75d055c003bb115baaa99af91e34a86a5405eb8b96e451bcb1c79f086604051611740911515815260200190565b60405180910390a3546001600160a01b03811696600160a01b9091046001600160601b031695509350505050565b61177c848484846001611ae1565b610fe757604051635274afe760e01b81526001600160a01b0385166004820152602401610b30565b6001600160a01b0382165f908152600460205260409020600281015464ffffffffff16156117f0576040516306cd244760e41b81526001600160a01b0384166004820152602401610b30565b6001600160a01b0383165f9081526004602052604090208290610dc682826123b2565b6001600160a01b038481165f9081526002602090815260408083209387168352928152828220858352905220545f19811015610dc6578181101561188a57604051632c51fead60e11b81526001600160a01b0385166004820152602481018290526044810183905260648101849052608401610b30565b6001600160a01b038086165f908152600260209081526040808320938816835292815282822086835290522082820390555050505050565b6118ce84848484611b4e565b6001600160a01b0384166118ff575f82815260036020526040812080548392906118f9908490612266565b90915550505b6001600160a01b038316610fe7575f8281526003602052604090208054829003905550505050565b5f51602061247e5f395f51905f525460020361195657604051633ee5aeb560e01b815260040160405180910390fd5b565b6119658383836001611c80565b61198d57604051635274afe760e01b81526001600160a01b0384166004820152602401610b30565b505050565b6001600160a01b0381165f90815260046020526040812060028101546001820154839283928392600160281b9091046001600160601b03908116600160a01b909204161115806119e2575f6119e5565b60015b60ff166060886001600160a01b0316901b1795505f8115611a06575f611a09565b60015b60ff166060896001600160a01b0316901b179050611a2789886105d0565b9550855f03611a4257505f9450849350839250611aa3915050565b5f8781526003602052604090205480611a63670de0b6b3a764000089612093565b611a6d91906120aa565b5f83815260036020526040902054909650670de0b6b3a7640000611a918883612093565b611a9b91906120aa565b955050505050505b92959194509250565b6001600160a01b038316611ad557604051630b8bbd6160e41b81525f6004820152602401610b30565b61198d5f8484846118c2565b6040516323b872dd60e01b5f8181526001600160a01b038781166004528616602452604485905291602083606481808c5af1925060015f51148316611b3d578383151615611b31573d5f823e3d81fd5b5f883b113d1516831692505b604052505f60605295945050505050565b336001600160a01b03851615611be7576001600160a01b0385165f9081526020818152604080832086845290915290205482811015611bc0576040516302c6d3fb60e61b81526001600160a01b0387166004820152602481018290526044810184905260648101859052608401610b30565b6001600160a01b0386165f9081526020818152604080832087845290915290209083900390555b6001600160a01b03841615611c2c576001600160a01b0384165f9081526020818152604080832086845290915281208054849290611c26908490612266565b90915550505b604080516001600160a01b03838116825260208201859052859281881692918916917f1b3d7edb2e9c0b0e7c525b20aaaef0f5940d2ed71663c7d39266ecafac728859910160405180910390a45050505050565b60405163a9059cbb60e01b5f8181526001600160a01b038616600452602485905291602083604481808b5af1925060015f51148316611cd6578383151615611cca573d5f823e3d81fd5b5f873b113d1516831692505b60405250949350505050565b6001600160a01b03811681146108b4575f5ffd5b5f5f60408385031215611d07575f5ffd5b8235611d1281611ce2565b946020939093013593505050565b5f60208284031215611d30575f5ffd5b81356001600160e01b03198116811461063d575f5ffd5b5f5f5f60608486031215611d59575f5ffd5b8335611d6481611ce2565b95602085013595506040909401359392505050565b5f60208284031215611d89575f5ffd5b813561063d81611ce2565b5f5f60408385031215611da5575f5ffd5b8235611db081611ce2565b91506020830135611dc081611ce2565b809150509250929050565b80358015158114611dda575f5ffd5b919050565b5f5f60408385031215611df0575f5ffd5b8235611dfb81611ce2565b9150611e0960208401611dcb565b90509250929050565b5f5f5f60608486031215611e24575f5ffd5b8335611e2f81611ce2565b92506020840135611e3f81611ce2565b929592945050506040919091013590565b5f60808284031215611e60575f5ffd5b50919050565b5f5f83601f840112611e76575f5ffd5b50813567ffffffffffffffff811115611e8d575f5ffd5b602083019150836020828501011115611ea4575f5ffd5b9250929050565b5f5f5f5f5f5f868803610120811215611ec2575f5ffd5b8735611ecd81611ce2565b9650611edb60208901611dcb565b9550611eea8960408a01611e50565b9450604060bf1982011215611efd575f5ffd5b5060c08701925061010087013567ffffffffffffffff811115611f1e575f5ffd5b611f2a89828a01611e66565b979a9699509497509295939492505050565b5f5f5f5f5f60e08688031215611f50575f5ffd5b8535611f5b81611ce2565b9450611f6960208701611dcb565b9350611f788760408801611e50565b925060c086013567ffffffffffffffff811115611f93575f5ffd5b611f9f88828901611e66565b969995985093965092949392505050565b5f60208284031215611fc0575f5ffd5b5035919050565b5f60208284031215611fd7575f5ffd5b813567ffffffffffffffff811115611fed575f5ffd5b820160e0818503121561063d575f5ffd5b5f5f5f5f60808587031215612011575f5ffd5b843561201c81611ce2565b9350602085013561202c81611ce2565b93969395505050506040820135916060013590565b5f60208284031215612051575f5ffd5b5051919050565b8281526060810161063d602083018480516001600160a01b03168252602090810151910152565b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176105f2576105f261207f565b5f826120c457634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160601b0381811683821601908111156105f2576105f261207f565b818103818111156105f2576105f261207f565b803561210681611ce2565b6001600160a01b03168252602090810135910152565b61212682826120fb565b60408181013590830152606090810135910152565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b61216d818761211c565b61217a60808201866120fb565b6001600160a01b03841660c082015261010060e082018190525f906121a2908301848661213b565b979650505050505050565b6121b7818761211c565b84516001600160a01b03166080820152602085015160a082015261217a565b5f5f8335601e198436030181126121eb575f5ffd5b83018035915067ffffffffffffffff821115612205575f5ffd5b6020019150600681901b3603821315611ea4575f5ffd5b64ffffffffff81811683821601908111156105f2576105f261207f565b64ffffffffff811681146108b4575f5ffd5b5f6020828403121561225b575f5ffd5b813561063d81612239565b808201808211156105f2576105f261207f565b602080825282548282018190525f848152918220906040840190835b818110156122c55783546001600160a01b038116845260a01c602084015260019384019360409093019201612295565b509095945050505050565b5f81356001600160601b03811681146105f2575f5ffd5b81356122f281611ce2565b81546001600160a01b03199081166001600160a01b0392909216918217835561231d602085016122d0565b60a01b1617905550565b6801000000000000000083111561234c57634e487b7160e01b5f52604160045260245ffd5b805483825580841015612381575f828152602090208481019082015b8082101561237e575f8255600182019150612368565b50505b505f8181526020812083915b85811015610c8c5761239f83836122e7565b604092909201916001918201910161238d565b6123bc82826122e7565b6123cc60408301600183016122e7565b6002810160808301356123de81612239565b815470ffffffffffffffffffffffff00000000006123fe60a087016122d0565b60281b1664ffffffffff831670ffffffffffffffffffffffffffffffffff198316171783555050505f5f60c0840135601e1985360301811261243e575f5ffd5b84018035915067ffffffffffffffff821115612458575f5ffd5b6020019150600681901b360382131561246f575f5ffd5b610fe781836003860161232756fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00a264697066735822122046427da9da2d5a5b85f1aac3d4dfd4c80900329ca297ce3fa9eff53841e85a5064736f6c634300081e0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000013b9cbcb46ad79878af8c9faa835bee19b977d3d
-----Decoded View---------------
Arg [0] : _feeBeneficiary (address): 0x13B9cBcB46aD79878af8c9faa835Bee19B977D3D
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000013b9cbcb46ad79878af8c9faa835bee19b977d3d
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
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.