Latest 25 from a total of 352,293 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Merge Positions | 82877646 | 27 secs ago | IN | 0 POL | 0.03440305 | ||||
| Merge Positions | 82877620 | 1 min ago | IN | 0 POL | 0.0343902 | ||||
| Merge Positions | 82877595 | 2 mins ago | IN | 0 POL | 0.03455222 | ||||
| Merge Positions | 82877570 | 2 mins ago | IN | 0 POL | 0.03496709 | ||||
| Merge Positions | 82877546 | 3 mins ago | IN | 0 POL | 0.03095954 | ||||
| Merge Positions | 82877522 | 4 mins ago | IN | 0 POL | 0.03180001 | ||||
| Convert Position... | 82877507 | 5 mins ago | IN | 0 POL | 2.45069517 | ||||
| Convert Position... | 82877507 | 5 mins ago | IN | 0 POL | 1.54389105 | ||||
| Convert Position... | 82877507 | 5 mins ago | IN | 0 POL | 1.50551328 | ||||
| Merge Positions | 82877497 | 5 mins ago | IN | 0 POL | 0.03476264 | ||||
| Merge Positions | 82877472 | 6 mins ago | IN | 0 POL | 0.03691805 | ||||
| Convert Position... | 82877453 | 6 mins ago | IN | 0 POL | 0.45172092 | ||||
| Convert Position... | 82877451 | 6 mins ago | IN | 0 POL | 0.13287862 | ||||
| Convert Position... | 82877451 | 6 mins ago | IN | 0 POL | 0.44924851 | ||||
| Convert Position... | 82877450 | 6 mins ago | IN | 0 POL | 0.14265145 | ||||
| Merge Positions | 82877400 | 8 mins ago | IN | 0 POL | 0.03995969 | ||||
| Merge Positions | 82877375 | 9 mins ago | IN | 0 POL | 0.03934877 | ||||
| Merge Positions | 82877350 | 10 mins ago | IN | 0 POL | 0.03801089 | ||||
| Merge Positions | 82877325 | 11 mins ago | IN | 0 POL | 0.0379612 | ||||
| Convert Position... | 82877304 | 11 mins ago | IN | 0 POL | 0.12826999 | ||||
| Merge Positions | 82877300 | 11 mins ago | IN | 0 POL | 0.03537514 | ||||
| Merge Positions | 82877275 | 12 mins ago | IN | 0 POL | 0.03579772 | ||||
| Merge Positions | 82877251 | 13 mins ago | IN | 0 POL | 0.03663272 | ||||
| Merge Positions | 82877226 | 14 mins ago | IN | 0 POL | 0.03741424 | ||||
| Redeem Positions | 82877207 | 15 mins ago | IN | 0 POL | 0.04989792 |
Latest 10 internal transactions
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 70965288 | 287 days ago | 10 wei | ||||
| 70965175 | 287 days ago | 10 wei | ||||
| 70965159 | 287 days ago | 10 wei | ||||
| 70965068 | 287 days ago | 10 wei | ||||
| 70964677 | 287 days ago | 10 wei | ||||
| 70935448 | 287 days ago | 100 wei | ||||
| 63686385 | 469 days ago | 1 wei | ||||
| 63686305 | 469 days ago | 1 wei | ||||
| 63642257 | 470 days ago | 1 wei | ||||
| 50505403 | 806 days ago | Contract Creation | 0 POL |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
NegRiskAdapter
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ERC1155TokenReceiver} from "lib/solmate/src/tokens/ERC1155.sol";
import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "lib/solmate/src/utils/SafeTransferLib.sol";
import {WrappedCollateral} from "src/WrappedCollateral.sol";
import {MarketData, MarketStateManager, IMarketStateManagerEE} from "src/modules/MarketDataManager.sol";
import {CTHelpers} from "src/libraries/CTHelpers.sol";
import {Helpers} from "src/libraries/Helpers.sol";
import {NegRiskIdLib} from "src/libraries/NegRiskIdLib.sol";
import {IConditionalTokens} from "src/interfaces/IConditionalTokens.sol";
import {Auth} from "src/modules/Auth.sol";
import {IAuthEE} from "src/modules/interfaces/IAuth.sol";
/// @title INegRiskAdapterEE
/// @notice NegRiskAdapter Errors and Events
interface INegRiskAdapterEE is IMarketStateManagerEE, IAuthEE {
error InvalidIndexSet();
error LengthMismatch();
error UnexpectedCollateralToken();
error NoConvertiblePositions();
error NotApprovedForAll();
event MarketPrepared(bytes32 indexed marketId, address indexed oracle, uint256 feeBips, bytes data);
event QuestionPrepared(bytes32 indexed marketId, bytes32 indexed questionId, uint256 index, bytes data);
event OutcomeReported(bytes32 indexed marketId, bytes32 indexed questionId, bool outcome);
event PositionSplit(address indexed stakeholder, bytes32 indexed conditionId, uint256 amount);
event PositionsMerge(address indexed stakeholder, bytes32 indexed conditionId, uint256 amount);
event PositionsConverted(
address indexed stakeholder, bytes32 indexed marketId, uint256 indexed indexSet, uint256 amount
);
event PayoutRedemption(address indexed redeemer, bytes32 indexed conditionId, uint256[] amounts, uint256 payout);
}
/// @title NegRiskAdapter
/// @notice Adapter for the CTF enabling the linking of a set binary markets where only one can resolve true
/// @notice The adapter prevents more than one question in the same multi-outcome market from resolving true
/// @notice And the adapter allows for the conversion of a set of no positions, to collateral plus the set of
/// complementary yes positions
/// @author Mike Shrieve ([email protected])
contract NegRiskAdapter is ERC1155TokenReceiver, MarketStateManager, INegRiskAdapterEE, Auth {
using SafeTransferLib for ERC20;
/*//////////////////////////////////////////////////////////////
STATE
//////////////////////////////////////////////////////////////*/
IConditionalTokens public immutable ctf;
ERC20 public immutable col;
WrappedCollateral public immutable wcol;
address public immutable vault;
address public constant NO_TOKEN_BURN_ADDRESS = address(bytes20(bytes32(keccak256("NO_TOKEN_BURN_ADDRESS"))));
uint256 public constant FEE_DENOMINATOR = 10_000;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/// @param _ctf - ConditionalTokens address
/// @param _collateral - collateral address
constructor(address _ctf, address _collateral, address _vault) {
ctf = IConditionalTokens(_ctf);
col = ERC20(_collateral);
vault = _vault;
wcol = new WrappedCollateral(_collateral, col.decimals());
// approve the ctf to transfer wcol on our behalf
wcol.approve(_ctf, type(uint256).max);
// approve wcol to transfer collateral on our behalf
col.approve(address(wcol), type(uint256).max);
}
/*//////////////////////////////////////////////////////////////
IDS
//////////////////////////////////////////////////////////////*/
/// @notice Returns the conditionId for a given questionId
/// @param _questionId - the questionId
/// @return conditionId - the corresponding conditionId
function getConditionId(bytes32 _questionId) public view returns (bytes32) {
return CTHelpers.getConditionId(
address(this), // oracle
_questionId,
2 // outcomeCount
);
}
/// @notice Returns the positionId for a given questionId and outcome
/// @param _questionId - the questionId
/// @param _outcome - the boolean outcome
/// @return positionId - the corresponding positionId
function getPositionId(bytes32 _questionId, bool _outcome) public view returns (uint256) {
bytes32 collectionId = CTHelpers.getCollectionId(
bytes32(0),
getConditionId(_questionId),
_outcome ? 1 : 2 // 1 (0b01) is yes, 2 (0b10) is no
);
uint256 positionId = CTHelpers.getPositionId(address(wcol), collectionId);
return positionId;
}
/*//////////////////////////////////////////////////////////////
SPLIT POSITION
//////////////////////////////////////////////////////////////*/
/// @notice Splits collateral to a complete set of conditional tokens for a single question
/// @notice This function signature is the same as the CTF's splitPosition
/// @param _collateralToken - the collateral token, must be the same as the adapter's collateral token
/// @param _conditionId - the conditionId for the question
/// @param _amount - the amount of collateral to split
function splitPosition(address _collateralToken, bytes32, bytes32 _conditionId, uint256[] calldata, uint256 _amount)
external
{
if (_collateralToken != address(col)) revert UnexpectedCollateralToken();
splitPosition(_conditionId, _amount);
}
/// @notice Splits collateral to a complete set of conditional tokens for a single question
/// @param _conditionId - the conditionId for the question
/// @param _amount - the amount of collateral to split
function splitPosition(bytes32 _conditionId, uint256 _amount) public {
col.safeTransferFrom(msg.sender, address(this), _amount);
wcol.wrap(address(this), _amount);
ctf.splitPosition(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
ctf.safeBatchTransferFrom(
address(this), msg.sender, Helpers.positionIds(address(wcol), _conditionId), Helpers.values(2, _amount), ""
);
emit PositionSplit(msg.sender, _conditionId, _amount);
}
/*//////////////////////////////////////////////////////////////
MERGE POSITIONS
//////////////////////////////////////////////////////////////*/
/// @notice Merges a complete set of conditional tokens for a single question to collateral
/// @notice This function signature is the same as the CTF's mergePositions
/// @param _collateralToken - the collateral token, must be the same as the adapter's collateral token
/// @param _conditionId - the conditionId for the question
/// @param _amount - the amount of collateral to merge
function mergePositions(
address _collateralToken,
bytes32,
bytes32 _conditionId,
uint256[] calldata,
uint256 _amount
) external {
if (_collateralToken != address(col)) revert UnexpectedCollateralToken();
mergePositions(_conditionId, _amount);
}
/// @notice Merges a complete set of conditional tokens for a single question to collateral
/// @param _conditionId - the conditionId for the question
/// @param _amount - the amount of collateral to merge
function mergePositions(bytes32 _conditionId, uint256 _amount) public {
uint256[] memory positionIds = Helpers.positionIds(address(wcol), _conditionId);
// get conditional tokens from sender
ctf.safeBatchTransferFrom(msg.sender, address(this), positionIds, Helpers.values(2, _amount), "");
ctf.mergePositions(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
wcol.unwrap(msg.sender, _amount);
emit PositionsMerge(msg.sender, _conditionId, _amount);
}
/*//////////////////////////////////////////////////////////////
ERC1155 OPERATIONS
//////////////////////////////////////////////////////////////*/
/// @notice Proxies ERC1155 balanceOf to the CTF
/// @param _owner - the owner of the tokens
/// @param _id - the positionId
/// @return balance - the owner's balance
function balanceOf(address _owner, uint256 _id) external view returns (uint256) {
return ctf.balanceOf(_owner, _id);
}
/// @notice Proxies ERC1155 balanceOfBatch to the CTF
/// @param _owners - the owners of the tokens
/// @param _ids - the positionIds
/// @return balances - the owners' balances
function balanceOfBatch(address[] memory _owners, uint256[] memory _ids) external view returns (uint256[] memory) {
return ctf.balanceOfBatch(_owners, _ids);
}
/// @notice Proxies ERC1155 safeTransferFrom to the CTF
/// @notice Can only be called by an admin
/// @notice Requires this contract to be approved for all
/// @notice Requires the sender to be approved for all
/// @param _from - the owner of the tokens
/// @param _to - the recipient of the tokens
/// @param _id - the positionId
/// @param _value - the amount of tokens to transfer
/// @param _data - the data to pass to the recipient
function safeTransferFrom(address _from, address _to, uint256 _id, uint256 _value, bytes calldata _data)
external
onlyAdmin
{
if (!ctf.isApprovedForAll(_from, msg.sender)) {
revert NotApprovedForAll();
}
return ctf.safeTransferFrom(_from, _to, _id, _value, _data);
}
/*//////////////////////////////////////////////////////////////
REDEEM POSITION
//////////////////////////////////////////////////////////////*/
/// @notice Redeem a set of conditional tokens for collateral
/// @param _conditionId - conditionId of the conditional tokens to redeem
/// @param _amounts - amounts of conditional tokens to redeem
/// _amounts should always have length 2, with the first element being the amount of yes tokens to redeem and the
/// second element being the amount of no tokens to redeem
function redeemPositions(bytes32 _conditionId, uint256[] calldata _amounts) public {
uint256[] memory positionIds = Helpers.positionIds(address(wcol), _conditionId);
// get conditional tokens from sender
ctf.safeBatchTransferFrom(msg.sender, address(this), positionIds, _amounts, "");
ctf.redeemPositions(address(wcol), bytes32(0), _conditionId, Helpers.partition());
uint256 payout = wcol.balanceOf(address(this));
if (payout > 0) {
wcol.unwrap(msg.sender, payout);
}
emit PayoutRedemption(msg.sender, _conditionId, _amounts, payout);
}
/*//////////////////////////////////////////////////////////////
CONVERT POSITIONS
//////////////////////////////////////////////////////////////*/
/// @notice Convert a set of no positions to the complementary set of yes positions plus collateral proportional to
/// (# of no positions - 1)
/// @notice If the market has a fee, the fee is taken from both collateral and the yes positions
/// @param _marketId - the marketId
/// @param _indexSet - the set of positions to convert, expressed as an index set where the least significant bit is
/// the first question (index zero)
/// @param _amount - the amount of tokens to convert
function convertPositions(bytes32 _marketId, uint256 _indexSet, uint256 _amount) external {
MarketData md = getMarketData(_marketId);
uint256 questionCount = md.questionCount();
if (md.oracle() == address(0)) revert MarketNotPrepared();
if (questionCount <= 1) revert NoConvertiblePositions();
if (_indexSet == 0) revert InvalidIndexSet();
if ((_indexSet >> questionCount) > 0) revert InvalidIndexSet();
// if _amount is 0, return early
if (_amount == 0) {
return;
}
uint256 index = 0;
uint256 noPositionCount;
// count number of no positions
while (index < questionCount) {
unchecked {
if ((_indexSet & (1 << index)) > 0) {
++noPositionCount;
}
++index;
}
}
uint256 yesPositionCount = questionCount - noPositionCount;
uint256[] memory noPositionIds = new uint256[](noPositionCount);
uint256[] memory yesPositionIds = new uint256[](yesPositionCount);
uint256[] memory accumulatedNoPositionIds = new uint256[](yesPositionCount);
// mint the amount of wcol required
wcol.mint(yesPositionCount * _amount);
// populate noPositionIds and yesPositionIds
// split yes positions
{
uint256 noIndex;
uint256 yesIndex;
index = 0;
while (index < questionCount) {
bytes32 questionId = NegRiskIdLib.getQuestionId(_marketId, uint8(index));
if ((_indexSet & (1 << index)) > 0) {
// NO
noPositionIds[noIndex] = getPositionId(questionId, false);
unchecked {
++noIndex;
}
} else {
// YES
yesPositionIds[yesIndex] = getPositionId(questionId, true);
accumulatedNoPositionIds[yesIndex] = getPositionId(questionId, false);
// split position to get yes and no tokens
// the no tokens will be discarded
_splitPosition(getConditionId(questionId), _amount);
unchecked {
++yesIndex;
}
}
unchecked {
++index;
}
}
}
// transfer the caller's no tokens _and_ accumulated no tokens to the burn address
// these must never be redeemed
{
ctf.safeBatchTransferFrom(
msg.sender, NO_TOKEN_BURN_ADDRESS, noPositionIds, Helpers.values(noPositionIds.length, _amount), ""
);
ctf.safeBatchTransferFrom(
address(this),
NO_TOKEN_BURN_ADDRESS,
accumulatedNoPositionIds,
Helpers.values(yesPositionCount, _amount),
""
);
}
uint256 feeAmount = (_amount * md.feeBips()) / FEE_DENOMINATOR;
uint256 amountOut = _amount - feeAmount;
if (noPositionIds.length > 1) {
// collateral out is always proportional to the number of no positions minus 1
uint256 multiplier = noPositionIds.length - 1;
// transfer collateral fees to vault
if (feeAmount > 0) {
wcol.release(vault, multiplier * feeAmount);
}
// transfer collateral to sender
wcol.release(msg.sender, multiplier * amountOut);
}
if (yesPositionIds.length > 0) {
if (feeAmount > 0) {
// transfer yes token fees to vault
ctf.safeBatchTransferFrom(
address(this), vault, yesPositionIds, Helpers.values(yesPositionIds.length, feeAmount), ""
);
}
// transfer yes tokens to sender
ctf.safeBatchTransferFrom(
address(this), msg.sender, yesPositionIds, Helpers.values(yesPositionIds.length, amountOut), ""
);
}
emit PositionsConverted(msg.sender, _marketId, _indexSet, _amount);
}
/*//////////////////////////////////////////////////////////////
PREPARE MARKET
//////////////////////////////////////////////////////////////*/
/// @notice Prepare a multi-outcome market
/// @param _feeBips - the fee for the market, out of 10_000
/// @param _metadata - metadata for the market
/// @return marketId - the marketId
function prepareMarket(uint256 _feeBips, bytes calldata _metadata) external returns (bytes32) {
bytes32 marketId = _prepareMarket(_feeBips, _metadata);
emit MarketPrepared(marketId, msg.sender, _feeBips, _metadata);
return marketId;
}
/*//////////////////////////////////////////////////////////////
PREPARE QUESTION
//////////////////////////////////////////////////////////////*/
/// @notice Prepare a question for a given market
/// @param _marketId - the id of the market for which to prepare the question
/// @param _metadata - the question metadata
/// @return questionId - the id of the resulting question
function prepareQuestion(bytes32 _marketId, bytes calldata _metadata) external returns (bytes32) {
(bytes32 questionId, uint256 questionIndex) = _prepareQuestion(_marketId);
bytes32 conditionId = getConditionId(questionId);
// check to see if the condition has already been prepared on the ctf
if (ctf.getOutcomeSlotCount(conditionId) == 0) {
ctf.prepareCondition(address(this), questionId, 2);
}
emit QuestionPrepared(_marketId, questionId, questionIndex, _metadata);
return questionId;
}
/*//////////////////////////////////////////////////////////////
REPORT OUTCOME
//////////////////////////////////////////////////////////////*/
/// @notice Report the outcome of a question
/// @param _questionId - the questionId to report
/// @param _outcome - the outcome of the question
function reportOutcome(bytes32 _questionId, bool _outcome) external {
_reportOutcome(_questionId, _outcome);
ctf.reportPayouts(_questionId, Helpers.payouts(_outcome));
emit OutcomeReported(NegRiskIdLib.getMarketId(_questionId), _questionId, _outcome);
}
/*//////////////////////////////////////////////////////////////
INTERNAL
//////////////////////////////////////////////////////////////*/
/// @dev internal function to avoid stack too deep in convertPositions
function _splitPosition(bytes32 _conditionId, uint256 _amount) internal {
ctf.splitPosition(address(wcol), bytes32(0), _conditionId, Helpers.partition(), _amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Minimalist and gas efficient standard ERC1155 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 amount
);
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] amounts
);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
/*//////////////////////////////////////////////////////////////
ERC1155 STORAGE
//////////////////////////////////////////////////////////////*/
mapping(address => mapping(uint256 => uint256)) public balanceOf;
mapping(address => mapping(address => bool)) public isApprovedForAll;
/*//////////////////////////////////////////////////////////////
METADATA LOGIC
//////////////////////////////////////////////////////////////*/
function uri(uint256 id) public view virtual returns (string memory);
/*//////////////////////////////////////////////////////////////
ERC1155 LOGIC
//////////////////////////////////////////////////////////////*/
function setApprovalForAll(address operator, bool approved) public virtual {
isApprovedForAll[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) public virtual {
require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;
emit TransferSingle(msg.sender, from, to, id, amount);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, from, id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public virtual {
require(ids.length == amounts.length, "LENGTH_MISMATCH");
require(msg.sender == from || isApprovedForAll[from][msg.sender], "NOT_AUTHORIZED");
// Storing these outside the loop saves ~15 gas per iteration.
uint256 id;
uint256 amount;
for (uint256 i = 0; i < ids.length; ) {
id = ids[i];
amount = amounts[i];
balanceOf[from][id] -= amount;
balanceOf[to][id] += amount;
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, from, to, ids, amounts);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, from, ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
public
view
virtual
returns (uint256[] memory balances)
{
require(owners.length == ids.length, "LENGTH_MISMATCH");
balances = new uint256[](owners.length);
// Unchecked because the only math done is incrementing
// the array index counter which cannot possibly overflow.
unchecked {
for (uint256 i = 0; i < owners.length; ++i) {
balances[i] = balanceOf[owners[i]][ids[i]];
}
}
}
/*//////////////////////////////////////////////////////////////
ERC165 LOGIC
//////////////////////////////////////////////////////////////*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return
interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
interfaceId == 0xd9b67a26 || // ERC165 Interface ID for ERC1155
interfaceId == 0x0e89341c; // ERC165 Interface ID for ERC1155MetadataURI
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
balanceOf[to][id] += amount;
emit TransferSingle(msg.sender, address(0), to, id, amount);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155Received(msg.sender, address(0), id, amount, data) ==
ERC1155TokenReceiver.onERC1155Received.selector,
"UNSAFE_RECIPIENT"
);
}
function _batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
uint256 idsLength = ids.length; // Saves MLOADs.
require(idsLength == amounts.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < idsLength; ) {
balanceOf[to][ids[i]] += amounts[i];
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, address(0), to, ids, amounts);
require(
to.code.length == 0
? to != address(0)
: ERC1155TokenReceiver(to).onERC1155BatchReceived(msg.sender, address(0), ids, amounts, data) ==
ERC1155TokenReceiver.onERC1155BatchReceived.selector,
"UNSAFE_RECIPIENT"
);
}
function _batchBurn(
address from,
uint256[] memory ids,
uint256[] memory amounts
) internal virtual {
uint256 idsLength = ids.length; // Saves MLOADs.
require(idsLength == amounts.length, "LENGTH_MISMATCH");
for (uint256 i = 0; i < idsLength; ) {
balanceOf[from][ids[i]] -= amounts[i];
// An array can't have a total length
// larger than the max uint256 value.
unchecked {
++i;
}
}
emit TransferBatch(msg.sender, from, address(0), ids, amounts);
}
function _burn(
address from,
uint256 id,
uint256 amount
) internal virtual {
balanceOf[from][id] -= amount;
emit TransferSingle(msg.sender, from, address(0), id, amount);
}
}
/// @notice A generic interface for a contract which properly accepts ERC1155 tokens.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
abstract contract ERC1155TokenReceiver {
function onERC1155Received(
address,
address,
uint256,
uint256,
bytes calldata
) external virtual returns (bytes4) {
return ERC1155TokenReceiver.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address,
address,
uint256[] calldata,
uint256[] calldata,
bytes calldata
) external virtual returns (bytes4) {
return ERC1155TokenReceiver.onERC1155BatchReceived.selector;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Append and mask the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. Masking not required as it's a full 32 byte type.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {ERC20} from "lib/solmate/src/tokens/ERC20.sol";
import {SafeTransferLib} from "lib/solmate/src/utils/SafeTransferLib.sol";
/// @title IWrappedCollateralEE
/// @notice WrappedCollateral Errors and Events
interface IWrappedCollateralEE {
error OnlyOwner();
}
string constant NAME = "Wrapped Collateral";
string constant SYMBOL = "WCOL";
/// @title WrappedCollateral
/// @author Mike Shrieve ([email protected])
/// @notice Wraps an ERC20 token to be used as collateral in the CTF
contract WrappedCollateral is IWrappedCollateralEE, ERC20 {
using SafeTransferLib for ERC20;
/*//////////////////////////////////////////////////////////////
STATE
//////////////////////////////////////////////////////////////*/
address public immutable owner;
address public immutable underlying;
/*//////////////////////////////////////////////////////////////
MODIFIERS
//////////////////////////////////////////////////////////////*/
modifier onlyOwner() {
if (msg.sender != owner) revert OnlyOwner();
_;
}
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
/// @param _underlying The address of the underlying ERC20 token
/// @param _decimals The number of decimals of the underlying ERC20 token
constructor(address _underlying, uint8 _decimals) ERC20(NAME, SYMBOL, _decimals) {
owner = msg.sender;
underlying = _underlying;
}
/*//////////////////////////////////////////////////////////////
UNWRAP
//////////////////////////////////////////////////////////////*/
/// @notice Unwraps the specified amount of tokens
/// @param _to The address to send the unwrapped tokens to
/// @param _amount The amount of tokens to unwrap
function unwrap(address _to, uint256 _amount) external {
_burn(msg.sender, _amount);
ERC20(underlying).safeTransfer(_to, _amount);
}
/*//////////////////////////////////////////////////////////////
ADMIN
//////////////////////////////////////////////////////////////*/
/// @notice Wraps the specified amount of tokens
/// @notice Can only be called by the owner
/// @param _to - the address to send the wrapped tokens to
/// @param _amount - the amount of tokens to wrap
function wrap(address _to, uint256 _amount) external onlyOwner {
ERC20(underlying).safeTransferFrom(msg.sender, address(this), _amount);
_mint(_to, _amount);
}
/// @notice Burns the specified amount of tokens
/// @notice Can only be called by the owner
/// @param _amount - the amount of tokens to burn
function burn(uint256 _amount) external onlyOwner {
_burn(msg.sender, _amount);
}
/// @notice Mints the specified amount of tokens
/// @notice Can only be called by the owner
/// @param _amount - the amount of tokens to mint
function mint(uint256 _amount) external onlyOwner {
_mint(msg.sender, _amount);
}
/// @notice Releases the specified amount of the underlying token
/// @notice Can only be called by the owner
/// @param _to - the address to send the released tokens to
/// @param _amount - the amount of tokens to release
function release(address _to, uint256 _amount) external onlyOwner {
ERC20(underlying).safeTransfer(_to, _amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import {MarketData, MarketDataLib} from "src/types/MarketData.sol";
import {NegRiskIdLib} from "src/libraries/NegRiskIdLib.sol";
interface IMarketStateManagerEE {
error IndexOutOfBounds();
error OnlyOracle();
error MarketNotPrepared();
error MarketAlreadyPrepared();
error MarketAlreadyDetermined();
error FeeBipsOutOfBounds();
}
/// @title MarketStateManager
/// @notice Manages market state on behalf of the NegRiskAdapter
/// @author Mike Shrieve([email protected])
abstract contract MarketStateManager is IMarketStateManagerEE {
mapping(bytes32 _marketId => MarketData) internal marketData;
/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/
function getMarketData(bytes32 _marketId) public view returns (MarketData) {
return marketData[_marketId];
}
function getOracle(bytes32 _marketId) external view returns (address) {
return marketData[_marketId].oracle();
}
function getQuestionCount(bytes32 _marketId) external view returns (uint256) {
return marketData[_marketId].questionCount();
}
function getDetermined(bytes32 _marketId) external view returns (bool) {
return marketData[_marketId].determined();
}
function getResult(bytes32 _marketId) external view returns (uint256) {
return marketData[_marketId].result();
}
function getFeeBips(bytes32 _marketId) external view returns (uint256) {
return marketData[_marketId].feeBips();
}
/*//////////////////////////////////////////////////////////////
INTERNAL
//////////////////////////////////////////////////////////////*/
/// @notice Prepares market data
/// @notice The market id depends on the oracle address, feeBips, and market metadata
/// @param _feeBips - feeBips out of 10_000
/// @param _metadata - market metadata
/// @return marketId - the market id
function _prepareMarket(uint256 _feeBips, bytes memory _metadata) internal returns (bytes32 marketId) {
address oracle = msg.sender;
marketId = NegRiskIdLib.getMarketId(oracle, _feeBips, _metadata);
MarketData md = marketData[marketId];
if (md.oracle() != address(0)) revert MarketAlreadyPrepared();
if (_feeBips > 10_000) revert FeeBipsOutOfBounds();
marketData[marketId] = MarketDataLib.initialize(oracle, _feeBips);
}
/// @notice Prepares a new question for the given market
/// @param _marketId - the market for which to prepare a new question
/// @return questionId - the resulting question id
/// @return index - the resulting question index
function _prepareQuestion(bytes32 _marketId) internal returns (bytes32 questionId, uint256 index) {
MarketData md = marketData[_marketId];
address oracle = marketData[_marketId].oracle();
if (oracle == address(0)) revert MarketNotPrepared();
if (oracle != msg.sender) revert OnlyOracle();
index = md.questionCount();
questionId = NegRiskIdLib.getQuestionId(_marketId, uint8(index));
marketData[_marketId] = md.incrementQuestionCount();
}
/// @notice Reports the outcome of a question
/// @notice State is only modified if the outcome is true
/// @notice Reverts if the market is not prepared
/// @notice Reverts if msg.sender is not the market's oracle
/// @notice Reverts if the question index is out of bounds
/// @notice Reverts if the outcome is true, and the market has already been determined
function _reportOutcome(bytes32 _questionId, bool _outcome) internal {
bytes32 marketId = NegRiskIdLib.getMarketId(_questionId);
uint256 questionIndex = NegRiskIdLib.getQuestionIndex(_questionId);
MarketData data = marketData[marketId];
address oracle = data.oracle();
if (oracle == address(0)) revert MarketNotPrepared();
if (oracle != msg.sender) revert OnlyOracle();
if (questionIndex >= data.questionCount()) revert IndexOutOfBounds();
if (_outcome == true) {
if (data.determined()) revert MarketAlreadyDetermined();
marketData[marketId] = data.determine(questionIndex);
}
}
}// SPDX-License-Identifier: LGPL-3.0-or-later
pragma solidity >=0.5.1;
// forked from Gnosis Condtional Tokens
library CTHelpers {
/// @dev Constructs a condition ID from an oracle, a question ID, and the outcome slot count for
/// the question.
/// @param oracle The account assigned to report the result for the prepared condition.
/// @param questionId An identifier for the question to be answered by the oracle.
/// @param outcomeSlotCount The number of outcome slots which should be used for this condition.
/// Must not exceed 256.
function getConditionId(address oracle, bytes32 questionId, uint256 outcomeSlotCount)
internal
pure
returns (bytes32)
{
return keccak256(abi.encodePacked(oracle, questionId, outcomeSlotCount));
}
uint256 constant P =
21888242871839275222246405745257275088696311157297823662689037894645226208583;
uint256 constant B = 3;
function sqrt(uint256 x) private pure returns (uint256 y) {
uint256 p = P;
// solium-disable-next-line security/no-inline-assembly
assembly {
// add chain generated via https://crypto.stackexchange.com/q/27179/71252
// and transformed to the following program:
// x=1; y=x+x; z=y+y; z=z+z; y=y+z; x=x+y; y=y+x; z=y+y; t=z+z; t=z+t; t=t+t;
// t=t+t; z=z+t; x=x+z; z=x+x; z=z+z; y=y+z; z=y+y; z=z+z; z=z+z; z=y+z; x=x+z;
// z=x+x; z=z+z; z=z+z; z=x+z; y=y+z; x=x+y; z=x+x; z=z+z; y=y+z; z=y+y; t=z+z;
// t=t+t; t=t+t; z=z+t; x=x+z; y=y+x; z=y+y; z=z+z; z=z+z; x=x+z; z=x+x; z=z+z;
// z=x+z; z=z+z; z=z+z; z=x+z; y=y+z; z=y+y; t=z+z; t=t+t; t=z+t; t=y+t; t=t+t;
// t=t+t; t=t+t; t=t+t; z=z+t; x=x+z; z=x+x; z=x+z; y=y+z; z=y+y; z=y+z; z=z+z;
// t=z+z; t=z+t; w=t+t; w=w+w; w=w+w; w=w+w; w=w+w; t=t+w; z=z+t; x=x+z; y=y+x;
// z=y+y; x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; z=x+x; z=x+z; z=z+z; y=y+z; z=y+y;
// z=z+z; x=x+z; y=y+x; z=y+y; z=y+z; x=x+z; y=y+x; x=x+y; y=y+x; z=y+y; z=z+z;
// z=y+z; x=x+z; z=x+x; z=x+z; y=y+z; x=x+y; y=y+x; x=x+y; y=y+x; z=y+y; z=y+z;
// z=z+z; x=x+z; y=y+x; z=y+y; z=y+z; z=z+z; x=x+z; z=x+x; t=z+z; t=t+t; t=z+t;
// t=x+t; t=t+t; t=t+t; t=t+t; t=t+t; z=z+t; y=y+z; x=x+y; y=y+x; x=x+y; z=x+x;
// z=x+z; z=z+z; z=z+z; z=z+z; z=x+z; y=y+z; z=y+y; z=y+z; z=z+z; x=x+z; z=x+x;
// z=x+z; y=y+z; x=x+y; z=x+x; z=z+z; y=y+z; x=x+y; z=x+x; y=y+z; x=x+y; y=y+x;
// z=y+y; z=y+z; x=x+z; y=y+x; z=y+y; z=y+z; z=z+z; z=z+z; x=x+z; z=x+x; z=z+z;
// z=z+z; z=x+z; y=y+z; x=x+y; z=x+x; t=x+z; t=t+t; t=t+t; z=z+t; y=y+z; z=y+y;
// x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; y=y+x; z=y+y; t=y+z; z=y+t; z=z+z; z=z+z;
// z=t+z; x=x+z; y=y+x; x=x+y; y=y+x; x=x+y; z=x+x; z=x+z; y=y+z; x=x+y; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x; x=x+x;
// x=x+x; x=x+x; x=x+x; x=x+x; res=y+x
// res == (P + 1) // 4
y := mulmod(x, x, p)
{
let z := mulmod(y, y, p)
z := mulmod(z, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
{
let t := mulmod(z, z, p)
t := mulmod(z, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
z := mulmod(z, t, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(y, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
t := mulmod(z, z, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
z := mulmod(z, t, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
z := mulmod(x, z, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
t := mulmod(z, z, p)
t := mulmod(t, t, p)
t := mulmod(z, t, p)
t := mulmod(y, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
z := mulmod(z, t, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
z := mulmod(z, z, p)
t := mulmod(z, z, p)
t := mulmod(z, t, p)
{
let w := mulmod(t, t, p)
w := mulmod(w, w, p)
w := mulmod(w, w, p)
w := mulmod(w, w, p)
w := mulmod(w, w, p)
t := mulmod(t, w, p)
}
z := mulmod(z, t, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
z := mulmod(z, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(z, z, p)
z := mulmod(y, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
t := mulmod(z, z, p)
t := mulmod(t, t, p)
t := mulmod(z, t, p)
t := mulmod(x, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
z := mulmod(z, t, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
z := mulmod(y, z, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
x := mulmod(x, z, p)
z := mulmod(x, x, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
t := mulmod(x, z, p)
t := mulmod(t, t, p)
t := mulmod(t, t, p)
z := mulmod(z, t, p)
y := mulmod(y, z, p)
z := mulmod(y, y, p)
x := mulmod(x, z, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
z := mulmod(y, y, p)
t := mulmod(y, z, p)
z := mulmod(y, t, p)
z := mulmod(z, z, p)
z := mulmod(z, z, p)
z := mulmod(t, z, p)
}
x := mulmod(x, z, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
y := mulmod(y, x, p)
x := mulmod(x, y, p)
z := mulmod(x, x, p)
z := mulmod(x, z, p)
y := mulmod(y, z, p)
}
x := mulmod(x, y, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
x := mulmod(x, x, p)
y := mulmod(y, x, p)
}
}
/// @dev Constructs an outcome collection ID from a parent collection and an outcome collection.
/// @param parentCollectionId Collection ID of the parent outcome collection, or bytes32(0) if
/// there's no parent.
/// @param conditionId Condition ID of the outcome collection to combine with the parent outcome
/// collection.
/// @param indexSet Index set of the outcome collection to combine with the parent outcome
/// collection.
function getCollectionId(bytes32 parentCollectionId, bytes32 conditionId, uint256 indexSet)
internal
view
returns (bytes32)
{
uint256 x1 = uint256(keccak256(abi.encodePacked(conditionId, indexSet)));
bool odd = x1 >> 255 != 0;
uint256 y1;
uint256 yy;
do {
x1 = addmod(x1, 1, P);
yy = addmod(mulmod(x1, mulmod(x1, x1, P), P), B, P);
y1 = sqrt(yy);
} while (mulmod(y1, y1, P) != yy);
if ((odd && y1 % 2 == 0) || (!odd && y1 % 2 == 1)) y1 = P - y1;
uint256 x2 = uint256(parentCollectionId);
if (x2 != 0) {
odd = x2 >> 254 != 0;
x2 = (x2 << 2) >> 2;
yy = addmod(mulmod(x2, mulmod(x2, x2, P), P), B, P);
uint256 y2 = sqrt(yy);
if ((odd && y2 % 2 == 0) || (!odd && y2 % 2 == 1)) y2 = P - y2;
require(mulmod(y2, y2, P) == yy, "invalid parent collection ID");
(bool success, bytes memory ret) = address(6).staticcall(abi.encode(x1, y1, x2, y2));
require(success, "ecadd failed");
(x1, y1) = abi.decode(ret, (uint256, uint256));
}
if (y1 % 2 == 1) x1 ^= 1 << 254;
return bytes32(x1);
}
/// @dev Constructs a position ID from a collateral token and an outcome collection. These IDs
/// are used as the ERC-1155 ID for this contract.
/// @param collateralToken Collateral token which backs the position.
/// @param collectionId ID of the outcome collection associated with this position.
function getPositionId(address collateralToken, bytes32 collectionId)
internal
pure
returns (uint256)
{
return uint256(keccak256(abi.encodePacked(collateralToken, collectionId)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import {CTHelpers} from "./CTHelpers.sol";
/// @title Helpers
/// @notice Helper functions for the NegRiskAdapter
/// @author Mike Shrieve ([email protected])
library Helpers {
/// @notice Returns the positionIds corresponding to _conditionId
/// @param _collateral - the collateral address
/// @param _conditionId - the conditionId
/// @return positionIds - length 2 array of position ids
function positionIds(address _collateral, bytes32 _conditionId) internal view returns (uint256[] memory) {
uint256[] memory positionIds_ = new uint256[](2);
// YES
positionIds_[0] = CTHelpers.getPositionId(_collateral, CTHelpers.getCollectionId(bytes32(0), _conditionId, 1));
// NO
positionIds_[1] = CTHelpers.getPositionId(_collateral, CTHelpers.getCollectionId(bytes32(0), _conditionId, 2));
return positionIds_;
}
/// @notice Returns an array with each element set to the same value
/// @param _length - the length of the array
/// @param _value - the value of each element
/// @return values_ - the array of values
function values(uint256 _length, uint256 _value) internal pure returns (uint256[] memory) {
uint256[] memory values_ = new uint256[](_length);
uint256 i;
while (i < _length) {
values_[i] = _value;
unchecked {
++i;
}
}
return values_;
}
/// @notice returns the partition for a binary conditional token
/// @return partition - the partition [1,2] = [0b01, 0b10]
function partition() internal pure returns (uint256[] memory) {
uint256[] memory partition_ = new uint256[](2);
// YES
partition_[0] = 1;
// NO
partition_[1] = 2;
return partition_;
}
/// @notice returns the payouts for a binary conditional token
/// @notice payouts are [1,0] if _outcome is true and [0,1] otherwise
/// @param _outcome - the boolean outcome
/// @return payouts - the payouts
function payouts(bool _outcome) internal pure returns (uint256[] memory) {
uint256[] memory payouts_ = new uint256[](2);
// YES
payouts_[0] = _outcome ? 1 : 0;
// NO
payouts_[1] = _outcome ? 0 : 1;
return payouts_;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; /// @title NegRiskIdLib /// @notice Functions for the NegRiskAdapter Market and QuestionIds /// @notice MarketIds are the keccak256 hash of the oracle, feeBips, and metadata, with the final 8 bits set to 0 /// @notice QuestionIds share the first 31 bytes with their corresponding MarketId, and the final byte consists of the /// questionIndex /// @author Mike Shrieve ([email protected]) library NegRiskIdLib { bytes32 private constant MASK = bytes32(type(uint256).max) << 8; /// @notice Returns the MarketId for a given oracle, feeBips, and metadata /// @param _oracle - the oracle address /// @param _feeBips - the feeBips, out of 10_000 /// @param _metadata - the market metadata /// @return marketId - the marketId function getMarketId(address _oracle, uint256 _feeBips, bytes memory _metadata) internal pure returns (bytes32) { return keccak256(abi.encode(_oracle, _feeBips, _metadata)) & MASK; } /// @notice Returns the MarketId for a given QuestionId /// @param _questionId - the questionId /// @return marketId - the marketId function getMarketId(bytes32 _questionId) internal pure returns (bytes32) { return _questionId & MASK; } /// @notice Returns the QuestionId for a given MarketId and questionIndex /// @param _marketId - the marketId /// @param _questionIndex - the questionIndex /// @return questionId - the questionId function getQuestionId(bytes32 _marketId, uint8 _questionIndex) internal pure returns (bytes32) { unchecked { return bytes32(uint256(_marketId) + _questionIndex); } } /// @notice Returns the questionIndex for a given QuestionId /// @param _questionId - the questionId /// @return questionIndex - the questionIndex function getQuestionIndex(bytes32 _questionId) internal pure returns (uint8) { return uint8(uint256(_questionId)); } }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
/// @notice references to IERC20 are replaced by address
/// @notice Interface for Gnosis Conditional Tokens
interface IERC1155 {
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
event TransferBatch(
address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values
);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
event URI(string value, uint256 indexed id);
function balanceOf(address owner, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] memory owners, uint256[] memory ids) external view returns (uint256[] memory);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external;
}
interface IConditionalTokensEE {
event ConditionPreparation(
bytes32 indexed conditionId, address indexed oracle, bytes32 indexed questionId, uint256 outcomeSlotCount
);
event ConditionResolution(
bytes32 indexed conditionId,
address indexed oracle,
bytes32 indexed questionId,
uint256 outcomeSlotCount,
uint256[] payoutNumerators
);
/// @dev Emitted when a position is successfully split.
event PositionSplit(
address indexed stakeholder,
address collateralToken,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint256[] partition,
uint256 amount
);
/// @dev Emitted when positions are successfully merged.
event PositionsMerge(
address indexed stakeholder,
address collateralToken,
bytes32 indexed parentCollectionId,
bytes32 indexed conditionId,
uint256[] partition,
uint256 amount
);
event PayoutRedemption(
address indexed redeemer,
address indexed collateralToken,
bytes32 indexed parentCollectionId,
bytes32 conditionId,
uint256[] indexSets,
uint256 payout
);
}
interface IConditionalTokens is IConditionalTokensEE, IERC1155 {
function payoutNumerators(bytes32 conditionId, uint256 index) external view returns (uint256);
function payoutDenominator(bytes32 conditionId) external view returns (uint256);
/// @dev This function prepares a condition by initializing a payout vector associated with the
/// condition.
/// @param oracle The account assigned to report the result for the prepared condition.
/// @param questionId An identifier for the question to be answered by the oracle.
/// @param outcomeSlotCount The number of outcome slots which should be used for this condition.
/// Must not exceed 256.
function prepareCondition(address oracle, bytes32 questionId, uint256 outcomeSlotCount) external;
/// @dev Called by the oracle for reporting results of conditions. Will set the payout vector
/// for the condition with the ID ``keccak256(abi.encodePacked(oracle, questionId,
/// outcomeSlotCount))``, where oracle is the message sender, questionId is one of the
/// parameters of this function, and outcomeSlotCount is the length of the payouts parameter,
/// which contains the payoutNumerators for each outcome slot of the condition.
/// @param questionId The question ID the oracle is answering for
/// @param payouts The oracle's answer
function reportPayouts(bytes32 questionId, uint256[] calldata payouts) external;
/// @dev This function splits a position. If splitting from the collateral, this contract will
/// attempt to transfer `amount` collateral from the message sender to itself. Otherwise, this
/// contract will burn `amount` stake held by the message sender in the position being split
/// worth of EIP 1155 tokens. Regardless, if successful, `amount` stake will be minted in the
/// split target positions. If any of the transfers, mints, or burns fail, the transaction will
/// revert. The transaction will also revert if the given partition is trivial, invalid, or
/// refers to more slots than the condition is prepared with.
/// @param collateralToken The address of the positions' backing collateral token.
/// @param parentCollectionId The ID of the outcome collections common to the position being
/// split and the split target positions. May be null, in which only the collateral is shared.
/// @param conditionId The ID of the condition to split on.
/// @param partition An array of disjoint index sets representing a nontrivial partition of the
/// outcome slots of the given condition. E.g. A|B and C but not A|B and B|C (is not disjoint).
/// Each element's a number which, together with the condition, represents the outcome
/// collection. E.g. 0b110 is A|B, 0b010 is B, etc.
/// @param amount The amount of collateral or stake to split.
function splitPosition(
address collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint256[] calldata partition,
uint256 amount
) external;
function mergePositions(
address collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint256[] calldata partition,
uint256 amount
) external;
function redeemPositions(
address collateralToken,
bytes32 parentCollectionId,
bytes32 conditionId,
uint256[] calldata indexSets
) external;
/// @dev Gets the outcome slot count of a condition.
/// @param conditionId ID of the condition.
/// @return Number of outcome slots associated with a condition, or zero if condition has not
/// been prepared yet.
function getOutcomeSlotCount(bytes32 conditionId) external view returns (uint256);
/// @dev Constructs a condition ID from an oracle, a question ID, and the outcome slot count for
/// the question.
/// @param oracle The account assigned to report the result for the prepared condition.
/// @param questionId An identifier for the question to be answered by the oracle.
/// @param outcomeSlotCount The number of outcome slots which should be used for this condition.
/// Must not exceed 256.
function getConditionId(address oracle, bytes32 questionId, uint256 outcomeSlotCount)
external
pure
returns (bytes32);
/// @dev Constructs an outcome collection ID from a parent collection and an outcome collection.
/// @param parentCollectionId Collection ID of the parent outcome collection, or bytes32(0) if
/// there's no parent.
/// @param conditionId Condition ID of the outcome collection to combine with the parent outcome
/// collection.
/// @param indexSet Index set of the outcome collection to combine with the parent outcome
/// collection.
function getCollectionId(bytes32 parentCollectionId, bytes32 conditionId, uint256 indexSet)
external
view
returns (bytes32);
/// @dev Constructs a position ID from a collateral token and an outcome collection. These IDs
/// are used as the ERC-1155 ID for this contract.
/// @param collateralToken Collateral token which backs the position.
/// @param collectionId ID of the outcome collection associated with this position.
function getPositionId(address collateralToken, bytes32 collectionId) external pure returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import {IAuth} from "./interfaces/IAuth.sol";
/// @title Auth
/// @author Jon Amenechi ([email protected])
/// @notice Provides access control modifiers
abstract contract Auth is IAuth {
/// @notice Auth
mapping(address => uint256) public admins;
modifier onlyAdmin() {
if (admins[msg.sender] != 1) revert NotAdmin();
_;
}
constructor() {
admins[msg.sender] = 1;
}
/// @notice Adds an Admin
/// @param admin - The address of the admin
function addAdmin(address admin) external onlyAdmin {
admins[admin] = 1;
emit NewAdmin(msg.sender, admin);
}
/// @notice Removes an admin
/// @param admin - The address of the admin to be removed
function removeAdmin(address admin) external onlyAdmin {
admins[admin] = 0;
emit RemovedAdmin(msg.sender, admin);
}
/// @notice Renounces Admin privileges from the caller
function renounceAdmin() external onlyAdmin {
admins[msg.sender] = 0;
emit RemovedAdmin(msg.sender, msg.sender);
}
/// @notice Checks if an address is an admin
/// @param addr - The address to be checked
function isAdmin(address addr) external view returns (bool) {
return admins[addr] == 1;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
interface IAuthEE {
error NotAdmin();
/// @notice Emitted when a new admin is added
event NewAdmin(address indexed admin, address indexed newAdminAddress);
/// @notice Emitted when an admin is removed
event RemovedAdmin(address indexed admin, address indexed removedAdmin);
}
interface IAuth is IAuthEE {
function isAdmin(address) external view returns (bool);
function addAdmin(address) external;
function removeAdmin(address) external;
function renounceAdmin() external;
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.15; /// @notice the MarketData user-defined type, a zero-cost abstraction over bytes32 type MarketData is bytes32; // md[0] = questionCount // md[1] = determined // md[2] = result // md[3:4] = feeBips // md[12:32] = oracle using MarketDataLib for MarketData global; /// @title MarketDataLib /// @notice Library for dealing with the MarketData user-defined bytes32 type /// @author Mike Shrieve ([email protected]) library MarketDataLib { error DeterminedFlagAlreadySet(); /// @notice used to increment the questionCount uint256 constant INCREMENT = uint256(bytes32(bytes1(0x01))); /// @notice extracts the oracle address from MarketData /// @return oracle - the address of the oracle function oracle(MarketData _data) internal pure returns (address) { return address(uint160(uint256(MarketData.unwrap(_data)))); } /// @notice extracts the questionCount from MarketData /// @return questionCount - the number of questions in the market function questionCount(MarketData _data) internal pure returns (uint256) { return uint256(uint8(MarketData.unwrap(_data)[0])); } /// @notice increments the questionCount /// @notice does _not_ check to see if the questionCount is already at the maximum value /// @return marketData - the modified MarketData function incrementQuestionCount(MarketData _data) internal pure returns (MarketData) { bytes32 data = MarketData.unwrap(_data); data = bytes32(uint256(data) + INCREMENT); return MarketData.wrap(data); } /// @notice extracts the determined flag from MarketData /// @return determined - true if the market has been determined, i.e. if one of the questions was resolved true function determined(MarketData _data) internal pure returns (bool) { return MarketData.unwrap(_data)[1] == 0x00 ? false : true; } /// @notice marks the market as determined /// @param _result - the result of the market, i.e., the index of the question that was resolved true /// @return marketData - the modified MarketData function determine(MarketData _data, uint256 _result) internal pure returns (MarketData) { bytes32 data = MarketData.unwrap(_data); if (data[1] != 0x00) revert DeterminedFlagAlreadySet(); data |= bytes32(bytes1(0x01)) >> 8; data |= bytes32(bytes1(uint8(_result))) >> 16; return MarketData.wrap(data); } /// @notice initializes the MarketData type /// @param _oracle - the address of the oracle /// @param _feeBips - the feeBips, out of 10_000 /// @return marketData - the initialized MarketData function initialize(address _oracle, uint256 _feeBips) internal pure returns (MarketData) { bytes32 data; data |= bytes32(bytes2(uint16(_feeBips))) >> 24; data |= bytes32(uint256(uint160(_oracle))); return MarketData.wrap(data); } /// @notice extracts the result from MarketData, i.e., the index of the question that was resolved true /// @notice if the market has not been determined, returns zero /// @return result - the index of the question that was resolved true, or zero function result(MarketData _data) internal pure returns (uint256) { return uint256(uint8(MarketData.unwrap(_data)[2])); } /// @notice extracts the feeBips from MarketData, out of 10_000 /// @return feeBips - the feeBips function feeBips(MarketData _data) internal pure returns (uint256) { return uint256(uint16(bytes2(MarketData.unwrap(_data) << 24))); } }
{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"solmate/=lib/solmate/src/",
"forge-gas-snapshot/=lib/forge-gas-snapshot/src/",
"openzeppelin-contracts/=lib/ctf-exchange/lib/openzeppelin-contracts/contracts/",
"common/=lib/ctf-exchange/src/common/",
"creator/=lib/ctf-exchange/src/creator/",
"ctf-exchange/=lib/ctf-exchange/src/",
"dev/=lib/ctf-exchange/src/dev/",
"exchange-fee-module/=lib/exchange-fee-module/src/",
"exchange/=lib/ctf-exchange/src/exchange/",
"openzeppelin/=lib/ctf-exchange/lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 1000000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_ctf","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"address","name":"_vault","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"DeterminedFlagAlreadySet","type":"error"},{"inputs":[],"name":"FeeBipsOutOfBounds","type":"error"},{"inputs":[],"name":"IndexOutOfBounds","type":"error"},{"inputs":[],"name":"InvalidIndexSet","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"MarketAlreadyDetermined","type":"error"},{"inputs":[],"name":"MarketAlreadyPrepared","type":"error"},{"inputs":[],"name":"MarketNotPrepared","type":"error"},{"inputs":[],"name":"NoConvertiblePositions","type":"error"},{"inputs":[],"name":"NotAdmin","type":"error"},{"inputs":[],"name":"NotApprovedForAll","type":"error"},{"inputs":[],"name":"OnlyOracle","type":"error"},{"inputs":[],"name":"UnexpectedCollateralToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"oracle","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeBips","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"MarketPrepared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":true,"internalType":"address","name":"newAdminAddress","type":"address"}],"name":"NewAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"questionId","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"outcome","type":"bool"}],"name":"OutcomeReported","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"redeemer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"}],"name":"PayoutRedemption","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"indexSet","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionsConverted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stakeholder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"conditionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PositionsMerge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"marketId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"questionId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"QuestionPrepared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":true,"internalType":"address","name":"removedAdmin","type":"address"}],"name":"RemovedAdmin","type":"event"},{"inputs":[],"name":"FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_TOKEN_BURN_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"admins","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"_owners","type":"address[]"},{"internalType":"uint256[]","name":"_ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"col","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"},{"internalType":"uint256","name":"_indexSet","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"convertPositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"ctf","outputs":[{"internalType":"contract IConditionalTokens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_questionId","type":"bytes32"}],"name":"getConditionId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getDetermined","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getFeeBips","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getMarketData","outputs":[{"internalType":"MarketData","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_questionId","type":"bytes32"},{"internalType":"bool","name":"_outcome","type":"bool"}],"name":"getPositionId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getQuestionCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"}],"name":"getResult","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mergePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mergePositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_feeBips","type":"uint256"},{"internalType":"bytes","name":"_metadata","type":"bytes"}],"name":"prepareMarket","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_marketId","type":"bytes32"},{"internalType":"bytes","name":"_metadata","type":"bytes"}],"name":"prepareQuestion","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"}],"name":"redeemPositions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_questionId","type":"bytes32"},{"internalType":"bool","name":"_outcome","type":"bool"}],"name":"reportOutcome","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collateralToken","type":"address"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"splitPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_conditionId","type":"bytes32"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"splitPosition","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wcol","outputs":[{"internalType":"contract WrappedCollateral","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6101006040523480156200001257600080fd5b5060405162005ed038038062005ed083398101604081905262000035916200023b565b33600090815260016020818152604092839020919091556001600160a01b0385811660805284811660a081905290841660e052825163313ce56760e01b815292518593919263313ce56792600480820193918290030181865afa158015620000a1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000c7919062000285565b604051620000d59062000210565b6001600160a01b03909216825260ff166020820152604001604051809103906000f0801580156200010a573d6000803e3d6000fd5b506001600160a01b0390811660c081905260405163095ea7b360e01b8152918516600483015260001960248301529063095ea7b3906044016020604051808303816000875af115801562000162573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001889190620002b1565b5060a05160c05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291169063095ea7b3906044016020604051808303816000875af1158015620001e0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002069190620002b1565b50505050620002d5565b61174d806200478383390190565b80516001600160a01b03811681146200023657600080fd5b919050565b6000806000606084860312156200025157600080fd5b6200025c846200021e565b92506200026c602085016200021e565b91506200027c604085016200021e565b90509250925092565b6000602082840312156200029857600080fd5b815160ff81168114620002aa57600080fd5b9392505050565b600060208284031215620002c457600080fd5b81518015158114620002aa57600080fd5b60805160a05160c05160e05161436a62000419600039600081816105ba015281816118e90152611aae0152600081816103e501528181610bc301528181610e8201528181610f3101528181610ff3015281816110cf015281816111cf015281816112810152818161158d015281816118c2015281816119ad01528181611c4301528181611d5501528181611e0201528181611ec00152612c2d01526000818161044d01528181610b0101528181610d7e0152610e250152600081816102750152818161062a015281816107ee015281816108b1015281816109c601528181610ef501528181610fb2015281816110f801528181611193015281816116dc0152818161179a01528181611a7101528181611b2d01528181611ca801528181611d1901528181611f980152818161211c015281816121fa0152612c06015261436a6000f3fe608060405234801561001057600080fd5b506004361061020a5760003560e01c80638a0db6151161012a578063bc197c81116100bd578063dbeccb231161008c578063f23a6e6111610071578063f23a6e6114610569578063f242432a146105a2578063fbfa77cf146105b557600080fd5b8063dbeccb2314610543578063e200affd1461055657600080fd5b8063bc197c81146104a8578063c64748c414610514578063d73792a914610527578063dafaf94a1461053057600080fd5b8063a78695b0116100f9578063a78695b014610448578063add4c7841461046f578063b10c5c1714610482578063b7f75d2c1461049557600080fd5b80638a0db615146104075780638bad0c0a1461041a5780639e7212ad14610422578063a3d7da1d1461043557600080fd5b8063429b62e5116101a2578063752b5ba511610171578063752b5ba51461039f5780637ad7fe36146103b25780637ae2e67b146103cd5780637e3b74c3146103e057600080fd5b8063429b62e5146103395780634e1273f414610359578063704802751461037957806372ce42751461038c57600080fd5b806322a9339f116101de57806322a9339f1461027057806324d7806c146102bc5780632582cb5e1461030657806330f4f4bb1461031957600080fd5b8062fdd58e1461020f57806304329c03146102355780631785f53c146102485780631d69b48d1461025d575b600080fd5b61022261021d3660046137d2565b6105dc565b6040519081526020015b60405180910390f35b6102226102433660046137fc565b61069f565b61025b610256366004613815565b610703565b005b61022261026b366004613879565b61079f565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022c565b6102f66102ca366004613815565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120541490565b604051901515815260200161022c565b6102226103143660046137fc565b61096b565b6102226103273660046137fc565b60009081526020819052604090205490565b610222610347366004613815565b60016020526000908152604090205481565b61036c6103673660046139d2565b610986565b60405161022c9190613acd565b61025b610387366004613815565b610a60565b61025b61039a366004613b25565b610aff565b6102226103ad366004613ba6565b610b96565b61029773a5ef39c3d3e10d0b270233af41cac69796b1296681565b6102f66103db3660046137fc565b610c3f565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b610222610415366004613879565b610c57565b61025b610cf7565b61025b610430366004613b25565b610d7c565b61025b610443366004613bd6565b610e0b565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b61022261047d3660046137fc565b6110b0565b61025b610490366004613bd6565b6110c8565b6102226104a33660046137fc565b611330565b6104e36104b6366004613bf8565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161022c565b61025b610522366004613cb3565b611348565b61022261271081565b61029761053e3660046137fc565b611c28565b61025b610551366004613cdf565b611c3c565b61025b610564366004613ba6565b611f8c565b6104e3610577366004613d1e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61025b6105b0366004613d1e565b612087565b6102977f000000000000000000000000000000000000000000000000000000000000000081565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390526000917f00000000000000000000000000000000000000000000000000000000000000009091169062fdd58e90604401602060405180830381865afa158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190613d96565b90505b92915050565b604080513060601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020808301919091526034820184905260026054808401919091528351808403909101815260749092019092528051910120600090610699565b336000908152600160208190526040909120541461074d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160205260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b60008060006107ad86612273565b9150915060006107bc8361069f565b6040517fd42dc0c2000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d42dc0c290602401602060405180830381865afa15801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086e9190613d96565b600003610923576040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050505b82877faac410f87d423a922a7b226ac68f0c2eaf5bf6d15e644ac0758c7f96e2c253f784898960405161095893929190613df8565b60405180910390a3509095945050505050565b60008181526020819052604081205460d81c61ffff16610699565b6040517f4e1273f400000000000000000000000000000000000000000000000000000000815260609073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690634e1273f4906109fd9086908690600401613e12565b600060405180830381865afa158015610a1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106969190810190613e7f565b3360009081526001602081905260409091205414610aaa576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160208190526040808320919091555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610b84576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e8482610e0b565b505050505050565b600080610bbd81610ba68661069f565b85610bb2576002610bb5565b60015b60ff16612358565b604080517f000000000000000000000000000000000000000000000000000000000000000060601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602080830191909152603480830185905283518084039091018152605490920190925280519101209091506000905b95945050505050565b600081815260208190526040812054610699906127ba565b600080610c9a8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127f992505050565b90503373ffffffffffffffffffffffffffffffffffffffff16817ff059ab16d1ca60e123eab60e3c02b68faf060347c701a5d14885a8e1def7b3a8878787604051610ce793929190613df8565b60405180910390a3949350505050565b3360009081526001602081905260409091205414610d41576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600160205260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610e01576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e84826110c8565b610e4d73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163330846128f7565b6040517fbf376c7a000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063bf376c7a90604401600060405180830381600087803b158015610edb57600080fd5b505af1158015610eef573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166372ce42757f00000000000000000000000000000000000000000000000000000000000000006000801b85610f5d6129e9565b866040518663ffffffff1660e01b8152600401610f7e959493929190613f10565b600060405180830381600087803b158015610f9857600080fd5b505af1158015610fac573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d630336110187f000000000000000000000000000000000000000000000000000000000000000087612a54565b611023600287612b57565b6040518563ffffffff1660e01b81526004016110429493929190613f5d565b600060405180830381600087803b15801561105c57600080fd5b505af1158015611070573d6000803e3d6000fd5b50506040518381528492503391507fbbed930dbfb7907ae2d60ddf78345610214f26419a0128df39b6cc3d9e5df9b0906020015b60405180910390a35050565b60008181526020819052604081205461069990612bd9565b60006110f47f000000000000000000000000000000000000000000000000000000000000000084612a54565b90507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6333084611140600288612b57565b6040518563ffffffff1660e01b815260040161115f9493929190613f5d565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16639e7212ad7f00000000000000000000000000000000000000000000000000000000000000006000801b866111fb6129e9565b876040518663ffffffff1660e01b815260040161121c959493929190613f10565b600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50506040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1692506339f476939150604401600060405180830381600087803b1580156112dc57600080fd5b505af11580156112f0573d6000803e3d6000fd5b50506040518481528592503391507fba33ac50d8894676597e6e35dc09cff59854708b642cd069d21eb9c7ca072a049060200160405180910390a3505050565b60008181526020819052604081205461069990612be6565b6000838152602081905260408120549061136182612be6565b905073ffffffffffffffffffffffffffffffffffffffff82166113b0576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181116113ea576040517f24f2dfe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611424576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83811c1561145e576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361146d575050505050565b6000805b82821015611493576001821b861615611488576001015b816001019150611471565b600061149f8285613ff4565b905060008267ffffffffffffffff8111156114bc576114bc6138c5565b6040519080825280602002602001820160405280156114e5578160200160208202803683370190505b50905060008267ffffffffffffffff811115611503576115036138c5565b60405190808252806020026020018201604052801561152c578160200160208202803683370190505b50905060008367ffffffffffffffff81111561154a5761154a6138c5565b604051908082528060200260200182016040528015611573578160200160208202803683370190505b50905073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001663a0712d686115bc8b87614007565b6040518263ffffffff1660e01b81526004016115da91815260200190565b600060405180830381600087803b1580156115f457600080fd5b505af1158015611608573d6000803e3d6000fd5b50505050600080600097505b888810156116d85760ff88168d016001891b8d161561166157611638816000610b96565b86848151811061164a5761164a61401e565b6020026020010181815250508260010192506116cc565b61166c816001610b96565b85838151811061167e5761167e61401e565b602002602001018181525050611695816000610b96565b8483815181106116a7576116a761401e565b6020026020010181815250506116c56116bf8261069f565b8d612bef565b8160010191505b88600101985050611614565b50507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6337fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c8661174788518f612b57565b6040518563ffffffff1660e01b81526004016117669493929190613f5d565b600060405180830381600087803b15801561178057600080fd5b505af1158015611794573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c84611804898f612b57565b6040518563ffffffff1660e01b81526004016118239493929190613f5d565b600060405180830381600087803b15801561183d57600080fd5b505af1158015611851573d6000803e3d6000fd5b506000925061271091505060d88a901c61ffff1661186f908c614007565b611879919061407c565b90506000611887828c613ff4565b9050600185511115611a62576000600186516118a39190613ff4565b905082156119965773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016630357371d7f00000000000000000000000000000000000000000000000000000000000000006119128685614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561197d57600080fd5b505af1158015611991573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016630357371d336119dd8585614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015611a4857600080fd5b505af1158015611a5c573d6000803e3d6000fd5b50505050505b835115611bc7578115611b2b577f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307f000000000000000000000000000000000000000000000000000000000000000087611ad9895188612b57565b6040518563ffffffff1660e01b8152600401611af89493929190613f5d565b600060405180830381600087803b158015611b1257600080fd5b505af1158015611b26573d6000803e3d6000fd5b505050505b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6303387611b75895187612b57565b6040518563ffffffff1660e01b8152600401611b949493929190613f5d565b600060405180830381600087803b158015611bae57600080fd5b505af1158015611bc2573d6000803e3d6000fd5b505050505b8b8d3373ffffffffffffffffffffffffffffffffffffffff167fb03d19dddbc72a87e735ff0ea3b57bef133ebe44e1894284916a84044deb367e8e604051611c1191815260200190565b60405180910390a450505050505050505050505050565b600081815260208190526040812054610699565b6000611c687f000000000000000000000000000000000000000000000000000000000000000085612a54565b6040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001690632eb2c2d690611ce590339030908690899089906004016140db565b600060405180830381600087803b158015611cff57600080fd5b505af1158015611d13573d6000803e3d6000fd5b505050507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166301b7037c7f00000000000000000000000000000000000000000000000000000000000000006000801b87611d816129e9565b6040518563ffffffff1660e01b8152600401611da09493929190614145565b600060405180830381600087803b158015611dba57600080fd5b505af1158015611dce573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1691506370a0823190602401602060405180830381865afa158015611e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e839190613d96565b90508015611f32576040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906339f4769390604401600060405180830381600087803b158015611f1957600080fd5b505af1158015611f2d573d6000803e3d6000fd5b505050505b843373ffffffffffffffffffffffffffffffffffffffff167f9140a6a270ef945260c03894b3c6b3b2695e9d5101feef0ff24fec960cfd3224868685604051611f7d93929190614180565b60405180910390a35050505050565b611f968282612ca6565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663c49298ac83611fdc84612e26565b6040518363ffffffff1660e01b8152600401611ff99291906141a4565b600060405180830381600087803b15801561201357600080fd5b505af1158015612027573d6000803e3d6000fd5b5050505081612055837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60405183151581527f9e9fa7fd355160bd4cd3f22d4333519354beff1f5689bde87f2c5e63d8d484b2906020016110a4565b33600090815260016020819052604090912054146120d1576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301523360248301527f0000000000000000000000000000000000000000000000000000000000000000169063e985e9c590604401602060405180830381865afa158015612163573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218791906141c5565b6121bd576040517fcd7769ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f242432a90612239908990899089908990899089906004016141e2565b600060405180830381600087803b15801561225357600080fd5b505af1158015612267573d6000803e3d6000fd5b50505050505050505050565b60008181526020819052604081205481908073ffffffffffffffffffffffffffffffffffffffff81166122d2576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612321576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232a82612be6565b925060ff83168501935061233d82612eb2565b60009586526020869052604090952094909455509092909150565b6000808383604051602001612377929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120905060ff81901c15156000805b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476001850893507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780878809870908905061243781612ee6565b9150807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47838409036123ba578280156124785750612476600283614234565b155b806124965750821580156124965750612492600283614234565b6001145b156124c8576124c5827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b91505b8780156127755760fe81901c151593507f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808485098409089150600061255283612ee6565b90508480156125695750612567600282614234565b155b806125875750841580156125875750612583600282614234565b6001145b156125b9576125b6817f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b90505b827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478283091461264a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420706172656e7420636f6c6c656374696f6e2049440000000060448201526064015b60405180910390fd5b60408051602081018890529081018590526060810183905260808101829052600090819060069060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526126ac9161426c565b600060405180830381855afa9150503d80600081146126e7576040519150601f19603f3d011682016040523d82523d6000602084013e6126ec565b606091505b509150915081612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f6563616464206661696c656400000000000000000000000000000000000000006044820152606401612641565b8080602001905181019061276c9190614288565b90985095505050505b612780600284614234565b6001036127ad577f4000000000000000000000000000000000000000000000000000000000000000851894505b5092979650505050505050565b60008160011a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016156127f1576001610699565b600092915050565b60003361280781858561369d565b6000818152602081905260408120549193508173ffffffffffffffffffffffffffffffffffffffff1614612867576040517fd2b4c0c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108511156128a3576040517ffc520af500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82167cffff00000000000000000000000000000000000000000000000000000060d887901b161760008481526020819052604090205550909392505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612641565b5050505050565b60408051600280825260608083018452926000929190602083019080368337019050509050600181600081518110612a2357612a2361401e565b602002602001018181525050600281600181518110612a4457612a4461401e565b6020908102919091010152919050565b60408051600280825260608083018452926000929190602083019080368337019050509050612b0384612a8a6000866001612358565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b16602082015260348101829052600090605401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b81600081518110612b1657612b1661401e565b6020908102919091010152612b3284612a8a6000866002612358565b81600181518110612b4557612b4561401e565b60209081029190910101529392505050565b606060008367ffffffffffffffff811115612b7457612b746138c5565b604051908082528060200260200182016040528015612b9d578160200160208202803683370190505b50905060005b84811015612bd15783828281518110612bbe57612bbe61401e565b6020908102919091010152600101612ba3565b509392505050565b60008160025b1a92915050565b60008181612bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000166372ce42757f0000000000000000000000000000000000000000000000000000000000000000600085612c576129e9565b866040518663ffffffff1660e01b8152600401612c78959493929190613f10565b600060405180830381600087803b158015612c9257600080fd5b505af1158015610b8e573d6000803e3d6000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00821660008181526020819052604090205460ff8416908073ffffffffffffffffffffffffffffffffffffffff8116612d2b576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612d7a576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d8382612be6565b8310612dbb576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841515600103610b8e57612dce826127ba565b15612e05576040517fe3b0238900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e0f82846136f7565b600085815260208190526040902055505050505050565b6040805160028082526060808301845292600092919060208301908036833701905050905082612e57576000612e5a565b60015b60ff1681600081518110612e7057612e7061401e565b60200260200101818152505082612e88576001612e8b565b60005b60ff1681600181518110612ea157612ea161401e565b602090810291909101015292915050565b600081612edf7f0100000000000000000000000000000000000000000000000000000000000000826142ac565b9392505050565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808380099150808283098181820990508181840992508183850993508184840992508183840990508181820982818309905082818209905082818209905082818309915082828609945082858609915082828309915082828509935082848509915082828309915082828309915082828509915082828609945082858609915082828309915082828309915082828609915082828509935082848609945082858609915082828309915082828509935082848509915082828309905082818209905082818209905082818309915082828609945082858509935082848509915082828309915082828309915082828609945082858609915082828309915082828609915082828309915082828309915082828609915082828509935082848509915082828309905082818209905082818309905082818509905082818209905082818209905082818209905082818209905082818309915082828609945082858609915082828609915082828509935082848509915082828509915082828309915082828309905082818309905082818209838182099050838182099050838182099050838182099050838183099150508281830991508282860994508285850993508284850991508282860994508285850993508284860994508285850993508284860994508285860991508282860991508282830991508282850993508284850991508282830991508282860994508285850993508284850991508282850991508282860994508285850993508284860994508285850993508284850991508282830991508282850991508282860994508285860991508282860991508282850993508284860994508285850993508284860994508285850993508284850991508282850991508282830991508282860994508285850993508284850991508282850991508282830991508282860994508285860991508282830990508281820990508281830990508281860990508281820990508281820990508281820990508281820990508281830991508282850993508284860994508285850993508284860994508285860991508282860991508282830991508282830991508282830991508282860991508282850993508284850991508282850991508282830991508282860994508285860991508282860991508282850993508284860994508285860991508282830991508282850993508284860994508285860991508282850993508284860994508285850993508284850991508282850991508282860994508285850993508284850991508282850991508282830991508282830991508282860994508285860991508282830991508282830991508282860991508282850993508284860994508285860991508282860990508281820990508281820990508281830991508282850993508284850991508282860994508285850993508284860994508285850993508284860994508285850993508284850991508282850990508281850991508282830991508282830991508282820991505081818509935081848409925081838509935081848409925081838509935081848509905081818509905081818409925050808284099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808383099392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00906136d7908690869086906020016142bf565b604051602081830303815290604052805190602001201690509392505050565b6000828060011a60f81b7fff00000000000000000000000000000000000000000000000000000000000000161561375a576040517fb36eb03600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7dff000000000000000000000000000000000000000000000000000000000060e884901b16177e0100000000000000000000000000000000000000000000000000000000000017905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146137cd57600080fd5b919050565b600080604083850312156137e557600080fd5b6137ee836137a9565b946020939093013593505050565b60006020828403121561380e57600080fd5b5035919050565b60006020828403121561382757600080fd5b610696826137a9565b60008083601f84011261384257600080fd5b50813567ffffffffffffffff81111561385a57600080fd5b60208301915083602082850101111561387257600080fd5b9250929050565b60008060006040848603121561388e57600080fd5b83359250602084013567ffffffffffffffff8111156138ac57600080fd5b6138b886828701613830565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561393b5761393b6138c5565b604052919050565b600067ffffffffffffffff82111561395d5761395d6138c5565b5060051b60200190565b600082601f83011261397857600080fd5b8135602061398d61398883613943565b6138f4565b82815260059290921b840181019181810190868411156139ac57600080fd5b8286015b848110156139c757803583529183019183016139b0565b509695505050505050565b600080604083850312156139e557600080fd5b823567ffffffffffffffff808211156139fd57600080fd5b818501915085601f830112613a1157600080fd5b81356020613a2161398883613943565b82815260059290921b84018101918181019089841115613a4057600080fd5b948201945b83861015613a6557613a56866137a9565b82529482019490820190613a45565b96505086013592505080821115613a7b57600080fd5b50613a8885828601613967565b9150509250929050565b600081518084526020808501945080840160005b83811015613ac257815187529582019590820190600101613aa6565b509495945050505050565b6020815260006106966020830184613a92565b60008083601f840112613af257600080fd5b50813567ffffffffffffffff811115613b0a57600080fd5b6020830191508360208260051b850101111561387257600080fd5b60008060008060008060a08789031215613b3e57600080fd5b613b47876137a9565b95506020870135945060408701359350606087013567ffffffffffffffff811115613b7157600080fd5b613b7d89828a01613ae0565b979a9699509497949695608090950135949350505050565b8015158114613ba357600080fd5b50565b60008060408385031215613bb957600080fd5b823591506020830135613bcb81613b95565b809150509250929050565b60008060408385031215613be957600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b031215613c1457600080fd5b613c1d896137a9565b9750613c2b60208a016137a9565b9650604089013567ffffffffffffffff80821115613c4857600080fd5b613c548c838d01613ae0565b909850965060608b0135915080821115613c6d57600080fd5b613c798c838d01613ae0565b909650945060808b0135915080821115613c9257600080fd5b50613c9f8b828c01613830565b999c989b5096995094979396929594505050565b600080600060608486031215613cc857600080fd5b505081359360208301359350604090920135919050565b600080600060408486031215613cf457600080fd5b83359250602084013567ffffffffffffffff811115613d1257600080fd5b6138b886828701613ae0565b60008060008060008060a08789031215613d3757600080fd5b613d40876137a9565b9550613d4e602088016137a9565b94506040870135935060608701359250608087013567ffffffffffffffff811115613d7857600080fd5b613d8489828a01613830565b979a9699509497509295939492505050565b600060208284031215613da857600080fd5b5051919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b838152604060208201526000610c36604083018486613daf565b604080825283519082018190526000906020906060840190828701845b82811015613e6157815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101613e2f565b50505083810382850152613e758186613a92565b9695505050505050565b60006020808385031215613e9257600080fd5b825167ffffffffffffffff811115613ea957600080fd5b8301601f81018513613eba57600080fd5b8051613ec861398882613943565b81815260059190911b82018301908381019087831115613ee757600080fd5b928401925b82841015613f0557835182529284019290840190613eec565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015260a060608201526000613f4b60a0830185613a92565b90508260808301529695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525060a06040830152613f9660a0830185613a92565b8281036060840152613fa88185613a92565b838103608090940193909352505060008152602001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561069957610699613fc5565b808202811582820484141761069957610699613fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261408b5761408b61404d565b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156140c257600080fd5b8260051b80836020870137939093016020019392505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261411460a0830186613a92565b8281036060840152614127818587614090565b83810360809094019390935250506000815260200195945050505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613e756080830184613a92565b604081526000614194604083018587614090565b9050826020830152949350505050565b8281526040602082015260006141bd6040830184613a92565b949350505050565b6000602082840312156141d757600080fd5b8151612edf81613b95565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261422860a083018486613daf565b98975050505050505050565b6000826142435761424361404d565b500690565b60005b8381101561426357818101518382015260200161424b565b50506000910152565b6000825161427e818460208701614248565b9190910192915050565b6000806040838503121561429b57600080fd5b505080516020909101519092909150565b8082018082111561069957610699613fc5565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260008251806060840152614300816080850160208701614248565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160800194935050505056fea2646970667358221220cb002f701e1383f3770988bb92900d67a44a83a2d126941d16180c38af3bdf6664736f6c634300081300336101206040523480156200001257600080fd5b506040516200174d3803806200174d83398101604081905262000035916200016e565b6040518060400160405280601281526020017115dc985c1c19590810dbdb1b185d195c985b60721b8152506040518060400160405280600481526020016315d0d3d360e21b8152508282600090816200008f919062000262565b5060016200009e838262000262565b5060ff81166080524660a052620000b4620000d2565b60c05250503360e05250506001600160a01b031661010052620003ac565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516200010691906200032e565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600080604083850312156200018257600080fd5b82516001600160a01b03811681146200019a57600080fd5b602084015190925060ff81168114620001b257600080fd5b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620001e857607f821691505b6020821081036200020957634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200025d57600081815260208120601f850160051c81016020861015620002385750805b601f850160051c820191505b81811015620002595782815560010162000244565b5050505b505050565b81516001600160401b038111156200027e576200027e620001bd565b62000296816200028f8454620001d3565b846200020f565b602080601f831160018114620002ce5760008415620002b55750858301515b600019600386901b1c1916600185901b17855562000259565b600085815260208120601f198616915b82811015620002ff57888601518255948401946001909101908401620002de565b50858210156200031e5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60008083546200033e81620001d3565b600182811680156200035957600181146200036f57620003a0565b60ff1984168752821515830287019450620003a0565b8760005260208060002060005b85811015620003975781548a8201529084019082016200037c565b50505082870194505b50929695505050505050565b60805160a05160c05160e051610100516113326200041b60003960008181610242015281816103f801526108e40152600081816102ce01528181610387015281816106ec015281816107750152610873015260006106a801526000610673015260006101db01526113326000f3fe608060405234801561001057600080fd5b50600436106101515760003560e01c80636f307dc3116100cd578063a0712d6811610081578063bf376c7a11610066578063bf376c7a1461031e578063d505accf14610331578063dd62ed3e1461034457600080fd5b8063a0712d68146102f8578063a9059cbb1461030b57600080fd5b80637ecebe00116100b25780637ecebe00146102a95780638da5cb5b146102c957806395d89b41146102f057600080fd5b80636f307dc31461023d57806370a082311461028957600080fd5b806323b872dd116101245780633644e515116101095780633644e5151461020f57806339f476931461021757806342966c681461022a57600080fd5b806323b872dd146101c3578063313ce567146101d657600080fd5b80630357371d1461015657806306fdde031461016b578063095ea7b31461018957806318160ddd146101ac575b600080fd5b610169610164366004610fcb565b61036f565b005b610173610423565b6040516101809190610ff5565b60405180910390f35b61019c610197366004610fcb565b6104b1565b6040519015158152602001610180565b6101b560025481565b604051908152602001610180565b61019c6101d1366004611061565b61052b565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff9091168152602001610180565b6101b561066f565b610169610225366004610fcb565b6106ca565b61016961023836600461109d565b6106d4565b6102647f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610180565b6101b56102973660046110b6565b60036020526000908152604090205481565b6101b56102b73660046110b6565b60056020526000908152604090205481565b6102647f000000000000000000000000000000000000000000000000000000000000000081565b610173610750565b61016961030636600461109d565b61075d565b61019c610319366004610fcb565b6107d6565b61016961032c366004610fcb565b61085b565b61016961033f3660046110d8565b610916565b6101b561035236600461114b565b600460209081526000928352604080842090915290825290205481565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146103de576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61041f73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168383610c3a565b5050565b600080546104309061117e565b80601f016020809104026020016040519081016040528092919081815260200182805461045c9061117e565b80156104a95780601f1061047e576101008083540402835291602001916104a9565b820191906000526020600020905b81548152906001019060200180831161048c57829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906105199086815260200190565b60405180910390a35060015b92915050565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146105bf5761058d8382611200565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff8516600090815260036020526040812080548592906105f4908490611200565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061065c9087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146106a5576106a0610d0f565b905090565b507f000000000000000000000000000000000000000000000000000000000000000090565b6103de3382610da9565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610743576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61074d3382610da9565b50565b600180546104309061117e565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146107cc576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61074d3382610e3f565b336000908152600360205260408120805483919083906107f7908490611200565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906105199086815260200190565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146108ca576040517f5fc483c500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61090c73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016333084610eb0565b61041f8282610e3f565b42841015610985576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f4558504952454400000000000000000060448201526064015b60405180910390fd5b6000600161099161066f565b73ffffffffffffffffffffffffffffffffffffffff8a811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938d166060840152608083018c905260a083019390935260c08083018b90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff871690820152606081018590526080810184905260a0016020604051602081039080840390855afa158015610ae3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615801590610b5e57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610bc4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e4552000000000000000000000000000000000000604482015260640161097c565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208a8516808552908352928190208990555188815291928a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b60006040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84166004820152826024820152602060006044836000895af13d15601f3d1160016000511416171691505080610d09576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c45440000000000000000000000000000000000604482015260640161097c565b50505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051610d419190611213565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604081208054839290610dde908490611200565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906020015b60405180910390a35050565b8060026000828254610e5191906112e9565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9101610e33565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d1160016000511416171691505080610f9b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c4544000000000000000000000000604482015260640161097c565b5050505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610fc657600080fd5b919050565b60008060408385031215610fde57600080fd5b610fe783610fa2565b946020939093013593505050565b600060208083528351808285015260005b8181101561102257858101830151858201604001528201611006565b5060006040828601015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8301168501019250505092915050565b60008060006060848603121561107657600080fd5b61107f84610fa2565b925061108d60208501610fa2565b9150604084013590509250925092565b6000602082840312156110af57600080fd5b5035919050565b6000602082840312156110c857600080fd5b6110d182610fa2565b9392505050565b600080600080600080600060e0888a0312156110f357600080fd5b6110fc88610fa2565b965061110a60208901610fa2565b95506040880135945060608801359350608088013560ff8116811461112e57600080fd5b9699959850939692959460a0840135945060c09093013592915050565b6000806040838503121561115e57600080fd5b61116783610fa2565b915061117560208401610fa2565b90509250929050565b600181811c9082168061119257607f821691505b6020821081036111cb577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b81810381811115610525576105256111d1565b600080835481600182811c91508083168061122f57607f831692505b60208084108203611267577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b81801561127b57600181146112ae576112db565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528415158502890196506112db565b60008a81526020902060005b868110156112d35781548b8201529085019083016112ba565b505084890196505b509498975050505050505050565b80820180821115610525576105256111d156fea2646970667358221220ad3d29a4463d14a148a3849050be8e5252fd8bc37be24d48ae47ffef67fa5b4664736f6c634300081300330000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760450000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061020a5760003560e01c80638a0db6151161012a578063bc197c81116100bd578063dbeccb231161008c578063f23a6e6111610071578063f23a6e6114610569578063f242432a146105a2578063fbfa77cf146105b557600080fd5b8063dbeccb2314610543578063e200affd1461055657600080fd5b8063bc197c81146104a8578063c64748c414610514578063d73792a914610527578063dafaf94a1461053057600080fd5b8063a78695b0116100f9578063a78695b014610448578063add4c7841461046f578063b10c5c1714610482578063b7f75d2c1461049557600080fd5b80638a0db615146104075780638bad0c0a1461041a5780639e7212ad14610422578063a3d7da1d1461043557600080fd5b8063429b62e5116101a2578063752b5ba511610171578063752b5ba51461039f5780637ad7fe36146103b25780637ae2e67b146103cd5780637e3b74c3146103e057600080fd5b8063429b62e5146103395780634e1273f414610359578063704802751461037957806372ce42751461038c57600080fd5b806322a9339f116101de57806322a9339f1461027057806324d7806c146102bc5780632582cb5e1461030657806330f4f4bb1461031957600080fd5b8062fdd58e1461020f57806304329c03146102355780631785f53c146102485780631d69b48d1461025d575b600080fd5b61022261021d3660046137d2565b6105dc565b6040519081526020015b60405180910390f35b6102226102433660046137fc565b61069f565b61025b610256366004613815565b610703565b005b61022261026b366004613879565b61079f565b6102977f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604581565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161022c565b6102f66102ca366004613815565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160208190526040909120541490565b604051901515815260200161022c565b6102226103143660046137fc565b61096b565b6102226103273660046137fc565b60009081526020819052604090205490565b610222610347366004613815565b60016020526000908152604090205481565b61036c6103673660046139d2565b610986565b60405161022c9190613acd565b61025b610387366004613815565b610a60565b61025b61039a366004613b25565b610aff565b6102226103ad366004613ba6565b610b96565b61029773a5ef39c3d3e10d0b270233af41cac69796b1296681565b6102f66103db3660046137fc565b610c3f565b6102977f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e281565b610222610415366004613879565b610c57565b61025b610cf7565b61025b610430366004613b25565b610d7c565b61025b610443366004613bd6565b610e0b565b6102977f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417481565b61022261047d3660046137fc565b6110b0565b61025b610490366004613bd6565b6110c8565b6102226104a33660046137fc565b611330565b6104e36104b6366004613bf8565b7fbc197c810000000000000000000000000000000000000000000000000000000098975050505050505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200161022c565b61025b610522366004613cb3565b611348565b61022261271081565b61029761053e3660046137fc565b611c28565b61025b610551366004613cdf565b611c3c565b61025b610564366004613ba6565b611f8c565b6104e3610577366004613d1e565b7ff23a6e61000000000000000000000000000000000000000000000000000000009695505050505050565b61025b6105b0366004613d1e565b612087565b6102977f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d81565b6040517efdd58e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390526000917f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760459091169062fdd58e90604401602060405180830381865afa158015610672573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106969190613d96565b90505b92915050565b604080513060601b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000166020808301919091526034820184905260026054808401919091528351808403909101815260749092019092528051910120600090610699565b336000908152600160208190526040909120541461074d576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160205260408082208290555133917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a350565b60008060006107ad86612273565b9150915060006107bc8361069f565b6040517fd42dc0c2000000000000000000000000000000000000000000000000000000008152600481018290529091507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff169063d42dc0c290602401602060405180830381865afa15801561084a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061086e9190613d96565b600003610923576040517fd96ee75400000000000000000000000000000000000000000000000000000000815230600482015260248101849052600260448201527f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff169063d96ee75490606401600060405180830381600087803b15801561090a57600080fd5b505af115801561091e573d6000803e3d6000fd5b505050505b82877faac410f87d423a922a7b226ac68f0c2eaf5bf6d15e644ac0758c7f96e2c253f784898960405161095893929190613df8565b60405180910390a3509095945050505050565b60008181526020819052604081205460d81c61ffff16610699565b6040517f4e1273f400000000000000000000000000000000000000000000000000000000815260609073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760451690634e1273f4906109fd9086908690600401613e12565b600060405180830381865afa158015610a1a573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526106969190810190613e7f565b3360009081526001602081905260409091205414610aaa576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81166000818152600160208190526040808320919091555133917ff9ffabca9c8276e99321725bcb43fb076a6c66a54b7f21c4e8146d8519b417dc91a350565b7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610b84576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e8482610e0b565b505050505050565b600080610bbd81610ba68661069f565b85610bb2576002610bb5565b60015b60ff16612358565b604080517f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e260601b7fffffffffffffffffffffffffffffffffffffffff00000000000000000000000016602080830191909152603480830185905283518084039091018152605490920190925280519101209091506000905b95945050505050565b600081815260208190526040812054610699906127ba565b600080610c9a8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506127f992505050565b90503373ffffffffffffffffffffffffffffffffffffffff16817ff059ab16d1ca60e123eab60e3c02b68faf060347c701a5d14885a8e1def7b3a8878787604051610ce793929190613df8565b60405180910390a3949350505050565b3360009081526001602081905260409091205414610d41576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b336000818152600160205260408082208290555182917f787a2e12f4a55b658b8f573c32432ee11a5e8b51677d1e1e937aaf6a0bb5776e91a3565b7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa8417473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614610e01576040517f155a4b5c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610b8e84826110c8565b610e4d73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174163330846128f7565b6040517fbf376c7a000000000000000000000000000000000000000000000000000000008152306004820152602481018290527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff169063bf376c7a90604401600060405180830381600087803b158015610edb57600080fd5b505af1158015610eef573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff166372ce42757f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b85610f5d6129e9565b866040518663ffffffff1660e01b8152600401610f7e959493929190613f10565b600060405180830381600087803b158015610f9857600080fd5b505af1158015610fac573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d630336110187f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e287612a54565b611023600287612b57565b6040518563ffffffff1660e01b81526004016110429493929190613f5d565b600060405180830381600087803b15801561105c57600080fd5b505af1158015611070573d6000803e3d6000fd5b50506040518381528492503391507fbbed930dbfb7907ae2d60ddf78345610214f26419a0128df39b6cc3d9e5df9b0906020015b60405180910390a35050565b60008181526020819052604081205461069990612bd9565b60006110f47f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e284612a54565b90507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6333084611140600288612b57565b6040518563ffffffff1660e01b815260040161115f9493929190613f5d565b600060405180830381600087803b15801561117957600080fd5b505af115801561118d573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16639e7212ad7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b866111fb6129e9565b876040518663ffffffff1660e01b815260040161121c959493929190613f10565b600060405180830381600087803b15801561123657600080fd5b505af115801561124a573d6000803e3d6000fd5b50506040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018590527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff1692506339f476939150604401600060405180830381600087803b1580156112dc57600080fd5b505af11580156112f0573d6000803e3d6000fd5b50506040518481528592503391507fba33ac50d8894676597e6e35dc09cff59854708b642cd069d21eb9c7ca072a049060200160405180910390a3505050565b60008181526020819052604081205461069990612be6565b6000838152602081905260408120549061136182612be6565b905073ffffffffffffffffffffffffffffffffffffffff82166113b0576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600181116113ea576040517f24f2dfe700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600003611424576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83811c1561145e576040517f9667d38100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8260000361146d575050505050565b6000805b82821015611493576001821b861615611488576001015b816001019150611471565b600061149f8285613ff4565b905060008267ffffffffffffffff8111156114bc576114bc6138c5565b6040519080825280602002602001820160405280156114e5578160200160208202803683370190505b50905060008267ffffffffffffffff811115611503576115036138c5565b60405190808252806020026020018201604052801561152c578160200160208202803683370190505b50905060008367ffffffffffffffff81111561154a5761154a6138c5565b604051908082528060200260200182016040528015611573578160200160208202803683370190505b50905073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e21663a0712d686115bc8b87614007565b6040518263ffffffff1660e01b81526004016115da91815260200190565b600060405180830381600087803b1580156115f457600080fd5b505af1158015611608573d6000803e3d6000fd5b50505050600080600097505b888810156116d85760ff88168d016001891b8d161561166157611638816000610b96565b86848151811061164a5761164a61401e565b6020026020010181815250508260010192506116cc565b61166c816001610b96565b85838151811061167e5761167e61401e565b602002602001018181525050611695816000610b96565b8483815181106116a7576116a761401e565b6020026020010181815250506116c56116bf8261069f565b8d612bef565b8160010191505b88600101985050611614565b50507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6337fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c8661174788518f612b57565b6040518563ffffffff1660e01b81526004016117669493929190613f5d565b600060405180830381600087803b15801561178057600080fd5b505af1158015611794573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307fa5ef39c3d3e10d0b270233af41cac69796b12966b80367e2fe6c6f7041543fbf60601c84611804898f612b57565b6040518563ffffffff1660e01b81526004016118239493929190613f5d565b600060405180830381600087803b15801561183d57600080fd5b505af1158015611851573d6000803e3d6000fd5b506000925061271091505060d88a901c61ffff1661186f908c614007565b611879919061407c565b90506000611887828c613ff4565b9050600185511115611a62576000600186516118a39190613ff4565b905082156119965773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e216630357371d7f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d6119128685614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b15801561197d57600080fd5b505af1158015611991573d6000803e3d6000fd5b505050505b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e216630357371d336119dd8585614007565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401600060405180830381600087803b158015611a4857600080fd5b505af1158015611a5c573d6000803e3d6000fd5b50505050505b835115611bc7578115611b2b577f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6307f0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d87611ad9895188612b57565b6040518563ffffffff1660e01b8152600401611af89493929190613f5d565b600060405180830381600087803b158015611b1257600080fd5b505af1158015611b26573d6000803e3d6000fd5b505050505b7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff16632eb2c2d6303387611b75895187612b57565b6040518563ffffffff1660e01b8152600401611b949493929190613f5d565b600060405180830381600087803b158015611bae57600080fd5b505af1158015611bc2573d6000803e3d6000fd5b505050505b8b8d3373ffffffffffffffffffffffffffffffffffffffff167fb03d19dddbc72a87e735ff0ea3b57bef133ebe44e1894284916a84044deb367e8e604051611c1191815260200190565b60405180910390a450505050505050505050505050565b600081815260208190526040812054610699565b6000611c687f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e285612a54565b6040517f2eb2c2d600000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760451690632eb2c2d690611ce590339030908690899089906004016140db565b600060405180830381600087803b158015611cff57600080fd5b505af1158015611d13573d6000803e3d6000fd5b505050507f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff166301b7037c7f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e26000801b87611d816129e9565b6040518563ffffffff1660e01b8152600401611da09493929190614145565b600060405180830381600087803b158015611dba57600080fd5b505af1158015611dce573d6000803e3d6000fd5b50506040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152600092507f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff1691506370a0823190602401602060405180830381865afa158015611e5f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e839190613d96565b90508015611f32576040517f39f47693000000000000000000000000000000000000000000000000000000008152336004820152602481018290527f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e273ffffffffffffffffffffffffffffffffffffffff16906339f4769390604401600060405180830381600087803b158015611f1957600080fd5b505af1158015611f2d573d6000803e3d6000fd5b505050505b843373ffffffffffffffffffffffffffffffffffffffff167f9140a6a270ef945260c03894b3c6b3b2695e9d5101feef0ff24fec960cfd3224868685604051611f7d93929190614180565b60405180910390a35050505050565b611f968282612ca6565b7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea047604573ffffffffffffffffffffffffffffffffffffffff1663c49298ac83611fdc84612e26565b6040518363ffffffff1660e01b8152600401611ff99291906141a4565b600060405180830381600087803b15801561201357600080fd5b505af1158015612027573d6000803e3d6000fd5b5050505081612055837fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001690565b60405183151581527f9e9fa7fd355160bd4cd3f22d4333519354beff1f5689bde87f2c5e63d8d484b2906020016110a4565b33600090815260016020819052604090912054146120d1576040517f7bfa4b9f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fe985e9c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff87811660048301523360248301527f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063e985e9c590604401602060405180830381865afa158015612163573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061218791906141c5565b6121bd576040517fcd7769ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff242432a00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045169063f242432a90612239908990899089908990899089906004016141e2565b600060405180830381600087803b15801561225357600080fd5b505af1158015612267573d6000803e3d6000fd5b50505050505050505050565b60008181526020819052604081205481908073ffffffffffffffffffffffffffffffffffffffff81166122d2576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612321576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61232a82612be6565b925060ff83168501935061233d82612eb2565b60009586526020869052604090952094909455509092909150565b6000808383604051602001612377929190918252602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190528051602090910120905060ff81901c15156000805b7f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd476001850893507f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4780878809870908905061243781612ee6565b9150807f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47838409036123ba578280156124785750612476600283614234565b155b806124965750821580156124965750612492600283614234565b6001145b156124c8576124c5827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b91505b8780156127755760fe81901c151593507f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4760037f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808485098409089150600061255283612ee6565b90508480156125695750612567600282614234565b155b806125875750841580156125875750612583600282614234565b6001145b156125b9576125b6817f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47613ff4565b90505b827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd478283091461264a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601c60248201527f696e76616c696420706172656e7420636f6c6c656374696f6e2049440000000060448201526064015b60405180910390fd5b60408051602081018890529081018590526060810183905260808101829052600090819060069060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526126ac9161426c565b600060405180830381855afa9150503d80600081146126e7576040519150601f19603f3d011682016040523d82523d6000602084013e6126ec565b606091505b509150915081612758576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f6563616464206661696c656400000000000000000000000000000000000000006044820152606401612641565b8080602001905181019061276c9190614288565b90985095505050505b612780600284614234565b6001036127ad577f4000000000000000000000000000000000000000000000000000000000000000851894505b5092979650505050505050565b60008160011a60f81b7fff0000000000000000000000000000000000000000000000000000000000000016156127f1576001610699565b600092915050565b60003361280781858561369d565b6000818152602081905260408120549193508173ffffffffffffffffffffffffffffffffffffffff1614612867576040517fd2b4c0c600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6127108511156128a3576040517ffc520af500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff82167cffff00000000000000000000000000000000000000000000000000000060d887901b161760008481526020819052604090205550909392505050565b60006040517f23b872dd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8516600482015273ffffffffffffffffffffffffffffffffffffffff841660248201528260448201526020600060648360008a5af13d15601f3d11600160005114161716915050806129e2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f5452414e534645525f46524f4d5f4641494c45440000000000000000000000006044820152606401612641565b5050505050565b60408051600280825260608083018452926000929190602083019080368337019050509050600181600081518110612a2357612a2361401e565b602002602001018181525050600281600181518110612a4457612a4461401e565b6020908102919091010152919050565b60408051600280825260608083018452926000929190602083019080368337019050509050612b0384612a8a6000866001612358565b6040517fffffffffffffffffffffffffffffffffffffffff000000000000000000000000606084901b16602082015260348101829052600090605401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815291905280516020909101209392505050565b81600081518110612b1657612b1661401e565b6020908102919091010152612b3284612a8a6000866002612358565b81600181518110612b4557612b4561401e565b60209081029190910101529392505050565b606060008367ffffffffffffffff811115612b7457612b746138c5565b604051908082528060200260200182016040528015612b9d578160200160208202803683370190505b50905060005b84811015612bd15783828281518110612bbe57612bbe61401e565b6020908102919091010152600101612ba3565b509392505050565b60008160025b1a92915050565b60008181612bdf565b73ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045166372ce42757f0000000000000000000000003a3bd7bb9528e159577f7c2e685cc81a765002e2600085612c576129e9565b866040518663ffffffff1660e01b8152600401612c78959493929190613f10565b600060405180830381600087803b158015612c9257600080fd5b505af1158015610b8e573d6000803e3d6000fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00821660008181526020819052604090205460ff8416908073ffffffffffffffffffffffffffffffffffffffff8116612d2b576040517fb664949500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff81163314612d7a576040517f80fee10500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612d8382612be6565b8310612dbb576040517f4e23d03500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b841515600103610b8e57612dce826127ba565b15612e05576040517fe3b0238900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612e0f82846136f7565b600085815260208190526040902055505050505050565b6040805160028082526060808301845292600092919060208301908036833701905050905082612e57576000612e5a565b60015b60ff1681600081518110612e7057612e7061401e565b60200260200101818152505082612e88576001612e8b565b60005b60ff1681600181518110612ea157612ea161401e565b602090810291909101015292915050565b600081612edf7f0100000000000000000000000000000000000000000000000000000000000000826142ac565b9392505050565b60007f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47808380099150808283098181820990508181840992508183850993508184840992508183840990508181820982818309905082818209905082818209905082818309915082828609945082858609915082828309915082828509935082848509915082828309915082828309915082828509915082828609945082858609915082828309915082828309915082828609915082828509935082848609945082858609915082828309915082828509935082848509915082828309905082818209905082818209905082818309915082828609945082858509935082848509915082828309915082828309915082828609945082858609915082828309915082828609915082828309915082828309915082828609915082828509935082848509915082828309905082818209905082818309905082818509905082818209905082818209905082818209905082818209905082818309915082828609945082858609915082828609915082828509935082848509915082828509915082828309915082828309905082818309905082818209838182099050838182099050838182099050838182099050838183099150508281830991508282860994508285850993508284850991508282860994508285850993508284860994508285850993508284860994508285860991508282860991508282830991508282850993508284850991508282830991508282860994508285850993508284850991508282850991508282860994508285850993508284860994508285850993508284850991508282830991508282850991508282860994508285860991508282860991508282850993508284860994508285850993508284860994508285850993508284850991508282850991508282830991508282860994508285850993508284850991508282850991508282830991508282860994508285860991508282830990508281820990508281830990508281860990508281820990508281820990508281820990508281820990508281830991508282850993508284860994508285850993508284860994508285860991508282860991508282830991508282830991508282830991508282860991508282850993508284850991508282850991508282830991508282860994508285860991508282860991508282850993508284860994508285860991508282830991508282850993508284860994508285860991508282850993508284860994508285850993508284850991508282850991508282860994508285850993508284850991508282850991508282830991508282830991508282860994508285860991508282830991508282830991508282860991508282850993508284860994508285860991508282860990508281820990508281820990508281830991508282850993508284850991508282860994508285850993508284860994508285850993508284860994508285850993508284850991508282850990508281850991508282830991508282830991508282820991505081818509935081848409925081838509935081848409925081838509935081848509905081818509905081818409925050808284099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808384099250808383099392505050565b6040516000907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00906136d7908690869086906020016142bf565b604051602081830303815290604052805190602001201690509392505050565b6000828060011a60f81b7fff00000000000000000000000000000000000000000000000000000000000000161561375a576040517fb36eb03600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7dff000000000000000000000000000000000000000000000000000000000060e884901b16177e0100000000000000000000000000000000000000000000000000000000000017905092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146137cd57600080fd5b919050565b600080604083850312156137e557600080fd5b6137ee836137a9565b946020939093013593505050565b60006020828403121561380e57600080fd5b5035919050565b60006020828403121561382757600080fd5b610696826137a9565b60008083601f84011261384257600080fd5b50813567ffffffffffffffff81111561385a57600080fd5b60208301915083602082850101111561387257600080fd5b9250929050565b60008060006040848603121561388e57600080fd5b83359250602084013567ffffffffffffffff8111156138ac57600080fd5b6138b886828701613830565b9497909650939450505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561393b5761393b6138c5565b604052919050565b600067ffffffffffffffff82111561395d5761395d6138c5565b5060051b60200190565b600082601f83011261397857600080fd5b8135602061398d61398883613943565b6138f4565b82815260059290921b840181019181810190868411156139ac57600080fd5b8286015b848110156139c757803583529183019183016139b0565b509695505050505050565b600080604083850312156139e557600080fd5b823567ffffffffffffffff808211156139fd57600080fd5b818501915085601f830112613a1157600080fd5b81356020613a2161398883613943565b82815260059290921b84018101918181019089841115613a4057600080fd5b948201945b83861015613a6557613a56866137a9565b82529482019490820190613a45565b96505086013592505080821115613a7b57600080fd5b50613a8885828601613967565b9150509250929050565b600081518084526020808501945080840160005b83811015613ac257815187529582019590820190600101613aa6565b509495945050505050565b6020815260006106966020830184613a92565b60008083601f840112613af257600080fd5b50813567ffffffffffffffff811115613b0a57600080fd5b6020830191508360208260051b850101111561387257600080fd5b60008060008060008060a08789031215613b3e57600080fd5b613b47876137a9565b95506020870135945060408701359350606087013567ffffffffffffffff811115613b7157600080fd5b613b7d89828a01613ae0565b979a9699509497949695608090950135949350505050565b8015158114613ba357600080fd5b50565b60008060408385031215613bb957600080fd5b823591506020830135613bcb81613b95565b809150509250929050565b60008060408385031215613be957600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b031215613c1457600080fd5b613c1d896137a9565b9750613c2b60208a016137a9565b9650604089013567ffffffffffffffff80821115613c4857600080fd5b613c548c838d01613ae0565b909850965060608b0135915080821115613c6d57600080fd5b613c798c838d01613ae0565b909650945060808b0135915080821115613c9257600080fd5b50613c9f8b828c01613830565b999c989b5096995094979396929594505050565b600080600060608486031215613cc857600080fd5b505081359360208301359350604090920135919050565b600080600060408486031215613cf457600080fd5b83359250602084013567ffffffffffffffff811115613d1257600080fd5b6138b886828701613ae0565b60008060008060008060a08789031215613d3757600080fd5b613d40876137a9565b9550613d4e602088016137a9565b94506040870135935060608701359250608087013567ffffffffffffffff811115613d7857600080fd5b613d8489828a01613830565b979a9699509497509295939492505050565b600060208284031215613da857600080fd5b5051919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b838152604060208201526000610c36604083018486613daf565b604080825283519082018190526000906020906060840190828701845b82811015613e6157815173ffffffffffffffffffffffffffffffffffffffff1684529284019290840190600101613e2f565b50505083810382850152613e758186613a92565b9695505050505050565b60006020808385031215613e9257600080fd5b825167ffffffffffffffff811115613ea957600080fd5b8301601f81018513613eba57600080fd5b8051613ec861398882613943565b81815260059190911b82018301908381019087831115613ee757600080fd5b928401925b82841015613f0557835182529284019290840190613eec565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff8616815284602082015283604082015260a060608201526000613f4b60a0830185613a92565b90508260808301529695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525060a06040830152613f9660a0830185613a92565b8281036060840152613fa88185613a92565b838103608090940193909352505060008152602001949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8181038181111561069957610699613fc5565b808202811582820484141761069957610699613fc5565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60008261408b5761408b61404d565b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156140c257600080fd5b8260051b80836020870137939093016020019392505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a0604083015261411460a0830186613a92565b8281036060840152614127818587614090565b83810360809094019390935250506000815260200195945050505050565b73ffffffffffffffffffffffffffffffffffffffff85168152836020820152826040820152608060608201526000613e756080830184613a92565b604081526000614194604083018587614090565b9050826020830152949350505050565b8281526040602082015260006141bd6040830184613a92565b949350505050565b6000602082840312156141d757600080fd5b8151612edf81613b95565b600073ffffffffffffffffffffffffffffffffffffffff808916835280881660208401525085604083015284606083015260a0608083015261422860a083018486613daf565b98975050505050505050565b6000826142435761424361404d565b500690565b60005b8381101561426357818101518382015260200161424b565b50506000910152565b6000825161427e818460208701614248565b9190910192915050565b6000806040838503121561429b57600080fd5b505080516020909101519092909150565b8082018082111561069957610699613fc5565b73ffffffffffffffffffffffffffffffffffffffff841681528260208201526060604082015260008251806060840152614300816080850160208701614248565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160800194935050505056fea2646970667358221220cb002f701e1383f3770988bb92900d67a44a83a2d126941d16180c38af3bdf6664736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea04760450000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d
-----Decoded View---------------
Arg [0] : _ctf (address): 0x4D97DCd97eC945f40cF65F87097ACe5EA0476045
Arg [1] : _collateral (address): 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
Arg [2] : _vault (address): 0x7f67327E88c258932D7d8f72950bE0d46975E11D
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000004d97dcd97ec945f40cf65f87097ace5ea0476045
Arg [1] : 0000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174
Arg [2] : 0000000000000000000000007f67327e88c258932d7d8f72950be0d46975e11d
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$979.84
Net Worth in POL
Token Allocations
USDC
100.00%
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| POL | 100.00% | $0.999887 | 979.9481 | $979.84 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.