Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SportsAMMV2ResultManager
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 100 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
// internal
import "../../utils/proxy/ProxyReentrancyGuard.sol";
import "../../utils/proxy/ProxyOwned.sol";
import "../../utils/proxy/ProxyPausable.sol";
import "../../utils/libraries/AddressSetLib.sol";
import "@thales-dao/contracts/contracts/interfaces/IReferrals.sol";
import "@thales-dao/contracts/contracts/interfaces/IMultiCollateralOnOffRamp.sol";
import "@thales-dao/contracts/contracts/interfaces/IStakingThales.sol";
import "../AMM//Ticket.sol";
import "../../interfaces/ISportsAMMV2.sol";
import "../../interfaces/ISportsAMMV2Manager.sol";
import "../../interfaces/ISportsAMMV2RiskManager.sol";
import "../../interfaces/ISportsAMMV2ResultManager.sol";
import "../../interfaces/ISportsAMMV2LiquidityPool.sol";
/// @title Sports AMM V2 contract
/// @author vladan
contract SportsAMMV2ResultManager is Initializable, ProxyOwned, ProxyPausable, ProxyReentrancyGuard {
enum ResultType {
Unassigned,
ExactPosition,
OverUnder,
CombinedPositions,
Spread
}
enum OverUnderType {
Over,
Under
}
/* ========== CONST VARIABLES ========== */
uint private constant ONE = 1e18;
uint private constant MAX_APPROVAL = type(uint256).max;
int24 public constant CANCEL_ID = -9999;
/* ========== STATE VARIABLES ========== */
// manager address
ISportsAMMV2Manager public manager;
// stores market results, market defined with gameId -> typeId -> playerId
mapping(bytes32 => mapping(uint => mapping(uint => int24[]))) public resultsPerMarket;
// indicates are results set for market, market defined with gameId -> typeId -> playerId
mapping(bytes32 => mapping(uint => mapping(uint => bool))) public areResultsPerMarketSet;
// indicates is game cancelled (parent market together with all child markets)
mapping(bytes32 => bool) public isGameCancelled;
// indicates is market explicitly cancelled, market defined with gameId -> typeId -> playerId -> line
mapping(bytes32 => mapping(uint => mapping(uint => mapping(int => bool)))) public isMarketExplicitlyCancelled;
// stores result type per market type
mapping(uint => ResultType) public resultTypePerMarketType;
// the address that can resolve markets
address public chainlinkResolver;
// number of tickets to exercise on game resolution
uint public numOfTicketsToExerciseOnGameResolution;
/* ========== CONSTRUCTOR ========== */
/// @param _manager the address of manager
function initialize(address _owner, ISportsAMMV2Manager _manager) public initializer {
setOwner(_owner);
initNonReentrant();
manager = _manager;
}
/* ========== EXTERNAL READ FUNCTIONS ========== */
/// @notice is specific market resolved
/// @param _gameId game ID
/// @param _typeId type ID
/// @param _playerId player ID (0 if not player props game)
/// @param _line line
/// @return isResolved true/false
function isMarketResolved(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) external view returns (bool isResolved) {
isResolved = _isMarketResolved(_gameId, _typeId, _playerId, _line, combinedPositions);
}
/// @notice is specific market cancelled
/// @param _gameId game ID
/// @param _typeId type ID
/// @param _playerId player ID (0 if not player props game)
/// @param _line line
/// @return isCancelled true/false
function isMarketCancelled(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) external view returns (bool isCancelled) {
if (isGameCancelled[_gameId]) {
isCancelled = true;
} else {
ResultType resultType = resultTypePerMarketType[_typeId];
if (resultType == ResultType.CombinedPositions) {
isCancelled = true;
for (uint i = 0; i < combinedPositions.length; i++) {
ISportsAMMV2.CombinedPosition memory combinedPosition = combinedPositions[i];
bool isCombinedPositionMarketCancelled = _isMarketCancelled(
_gameId,
combinedPosition.typeId,
0,
combinedPosition.line
);
if (!isCombinedPositionMarketCancelled) {
isCancelled = false;
break;
}
}
} else {
isCancelled = _isMarketCancelled(_gameId, _typeId, _playerId, _line);
}
}
}
/**
* @notice Retrieves the status of a specific market position for a given game and player.
* @param _gameId The identifier of the game.
* @param _typeId The type of the market.
* @param _playerId The identifier of the player.
* @param _line The line associated with the market position.
* @param _position The position index within the market.
* @param _combinedPositions An array of combined positions related to the market.
* @return status The status of the market position (e.g., Active, Cancelled, Resolved).
*/
function getMarketPositionStatus(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (ISportsAMMV2ResultManager.MarketPositionStatus status) {
return _getMarketPositionStatus(_gameId, _typeId, _playerId, _line, _position, _combinedPositions);
}
/**
* @notice Checks if a specific market position is a winning position.
* @param _gameId The identifier of the game.
* @param _typeId The type of the market.
* @param _playerId The identifier of the player.
* @param _line The line associated with the market position.
* @param _position The position index within the market.
* @param _combinedPositions An array of combined positions related to the market.
* @return bool True if the position is winning, otherwise false.
*/
function isWinningMarketPosition(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool) {
return _isWinningMarketPosition(_gameId, _typeId, _playerId, _line, _position, _combinedPositions);
}
/**
* @notice Checks if a specific market position has been cancelled.
* @param _gameId The identifier of the game.
* @param _typeId The type of the market.
* @param _playerId The identifier of the player.
* @param _line The line associated with the market position.
* @param _position The position index within the market.
* @param _combinedPositions An array of combined positions related to the market.
* @return isCancelled True if the position is cancelled, otherwise false.
*/
function isCancelledMarketPosition(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool isCancelled) {
ISportsAMMV2ResultManager.MarketPositionStatus marketPositionStatus = _getMarketPositionStatus(
_gameId,
_typeId,
_playerId,
_line,
_position,
_combinedPositions
);
return marketPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
}
/**
* @notice Retrieves the results for a specific market.
* @param _gameId The identifier of the game.
* @param _typeId The type of the market.
* @param _playerId The identifier of the player.
* @return results An array of integers representing the results of the market.
*/
function getResultsPerMarket(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId
) external view returns (int24[] memory results) {
return resultsPerMarket[_gameId][_typeId][_playerId];
}
/**
* @notice Checks if the market is resolved and if a specific position is a winning one.
* @param _gameId The identifier of the game.
* @param _typeId The type of the market.
* @param _playerId The identifier of the player.
* @param _line The line associated with the market position.
* @param _position The position index within the market.
* @param _combinedPositions An array of combined positions related to the market.
* @return isResolved True if the market is resolved, otherwise false.
* @return isWinning True if the position is winning, otherwise false.
*/
function isMarketResolvedAndPositionWinning(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool isResolved, bool isWinning) {
(isResolved, isWinning) = _isMarketResolvedAndPositionWinning(
_gameId,
_typeId,
_playerId,
_line,
_position,
_combinedPositions
);
}
/* ========== EXTERNAL WRITE FUNCTIONS ========== */
/// @notice set result for specific markets and exercise losing tickets (up to numOfTicketsToExerciseOnGameResolution)
/// @param _gameIds game IDs to set results for
/// @param _typeIds type IDs to set results for
/// @param _playerIds player IDs to set results for
/// @param _results market results
function setResultsPerMarkets(
bytes32[] memory _gameIds,
uint16[] memory _typeIds,
uint24[] memory _playerIds,
int24[][] memory _results
) external onlyWhitelistedAddresses(msg.sender) {
require(
_gameIds.length == _typeIds.length &&
_typeIds.length == _playerIds.length &&
_playerIds.length == _results.length,
"Incorrect params"
);
ISportsAMMV2 sportsAMM = ISportsAMMV2(manager.sportsAMM());
uint numOfTicketsToExercise = numOfTicketsToExerciseOnGameResolution;
for (uint i; i < _gameIds.length; i++) {
bytes32 gameId = _gameIds[i];
//skip cancelled games
if (isGameCancelled[gameId]) {
continue;
}
uint16 typeId = _typeIds[i];
uint24 playerId = _playerIds[i];
int24[] memory results = _results[i];
if (results[0] == CANCEL_ID) {
_cancelMarket(gameId, typeId, playerId, 0);
} else {
ResultType resultType = resultTypePerMarketType[typeId];
require(resultType != ResultType.Unassigned, "Result type not set");
if (!areResultsPerMarketSet[gameId][typeId][playerId]) {
resultsPerMarket[gameId][typeId][playerId] = results;
areResultsPerMarketSet[gameId][typeId][playerId] = true;
if (numOfTicketsToExercise > 0) {
address[] memory marketTickets = manager.getTicketsPerMarket(
0,
numOfTicketsToExerciseOnGameResolution,
gameId,
typeId,
playerId
);
numOfTicketsToExercise = _exerciseLosingTickets(marketTickets, numOfTicketsToExercise, sportsAMM);
}
emit ResultsPerMarketSet(gameId, typeId, playerId, results);
}
}
}
}
/// @notice cancel specific games
/// @param _gameIds game IDs to cancel
function cancelGames(bytes32[] memory _gameIds) external onlyWhitelistedAddresses(msg.sender) {
for (uint i; i < _gameIds.length; i++) {
bytes32 gameId = _gameIds[i];
_cancelGame(gameId);
}
}
/// @notice cancel specific game
/// @param _gameId game ID to cancel
function cancelGame(bytes32 _gameId) external onlyWhitelistedAddresses(msg.sender) {
_cancelGame(_gameId);
}
function _cancelGame(bytes32 _gameId) internal {
require(!isGameCancelled[_gameId], "Game already cancelled");
isGameCancelled[_gameId] = true;
emit GameCancelled(_gameId);
}
/// @notice cancel specific markets
/// @param _gameIds game IDs to cancel
/// @param _typeIds type IDs to cancel
/// @param _playerIds player IDs to cancel
function cancelMarkets(
bytes32[] memory _gameIds,
uint16[] memory _typeIds,
uint24[] memory _playerIds,
int24[] memory _lines
) external onlyWhitelistedAddresses(msg.sender) {
require(
_gameIds.length == _typeIds.length && _typeIds.length == _playerIds.length && _playerIds.length == _lines.length,
"Incorrect params"
);
for (uint i; i < _gameIds.length; i++) {
bytes32 gameId = _gameIds[i];
uint16 typeId = _typeIds[i];
uint24 playerId = _playerIds[i];
int24 line = _lines[i];
_cancelMarket(gameId, typeId, playerId, line);
}
}
/// @notice cancel specific markets
/// @param _gameId game ID to cancel
/// @param _typeId type ID to cancel
/// @param _playerId player ID to cancel
/// @param _line player ID to cancel
function cancelMarket(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line
) external onlyWhitelistedAddresses(msg.sender) {
_cancelMarket(_gameId, _typeId, _playerId, _line);
}
/// @notice cancel specific markets
/// @param _gameId game ID to cancel
/// @param _typeId type ID to cancel
/// @param _playerId player IDs to cancel
function _cancelMarket(bytes32 _gameId, uint16 _typeId, uint24 _playerId, int24 _line) internal {
require(!_isMarketCancelled(_gameId, _typeId, _playerId, _line), "Market already cancelled");
isMarketExplicitlyCancelled[_gameId][_typeId][_playerId][_line] = true;
emit MarketExplicitlyCancelled(_gameId, _typeId, _playerId, _line);
}
/// @notice set result types for specific markets
/// @param _marketTypeIds market type IDs to set result type for
/// @param _resultTypes result types to set
function setResultTypesPerMarketTypes(uint16[] memory _marketTypeIds, uint[] memory _resultTypes) external onlyOwner {
require(_marketTypeIds.length == _resultTypes.length, "Incorrect params");
for (uint i; i < _marketTypeIds.length; i++) {
uint16 marketTypeId = _marketTypeIds[i];
uint resultType = _resultTypes[i];
require(
resultType > uint(ResultType.Unassigned) && resultType <= uint(ResultType.Spread),
"Invalid result type"
);
resultTypePerMarketType[marketTypeId] = ResultType(resultType);
emit ResultTypePerMarketTypeSet(marketTypeId, resultType);
}
}
/* ========== INTERNAL FUNCTIONS ========== */
function _isMarketResolvedInternal(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line
) internal view returns (bool) {
return areResultsPerMarketSet[_gameId][_typeId][_playerId] || _isMarketCancelled(_gameId, _typeId, _playerId, _line);
}
function _isMarketCancelled(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line
) internal view returns (bool) {
return
isGameCancelled[_gameId] ||
isMarketExplicitlyCancelled[_gameId][_typeId][_playerId][_line] ||
isMarketExplicitlyCancelled[_gameId][_typeId][_playerId][0];
}
function _getMarketPositionStatus(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint position,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) internal view returns (ISportsAMMV2ResultManager.MarketPositionStatus status) {
ResultType resultType = resultTypePerMarketType[_typeId];
return
resultType == ResultType.CombinedPositions
? _getMarketCombinedPositionsStatus(_gameId, combinedPositions)
: _getMarketSinglePositionStatus(_gameId, _typeId, _playerId, _line, position);
}
function _getMarketSinglePositionStatus(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint position
) internal view returns (ISportsAMMV2ResultManager.MarketPositionStatus status) {
if (_isMarketCancelled(_gameId, _typeId, _playerId, _line)) {
return ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
}
if (areResultsPerMarketSet[_gameId][_typeId][_playerId]) {
int24[] memory marketResults = resultsPerMarket[_gameId][_typeId][_playerId];
ResultType resultType = resultTypePerMarketType[_typeId];
for (uint i = 0; i < marketResults.length; i++) {
int marketResult = marketResults[i];
if (resultType == ResultType.OverUnder || resultType == ResultType.Spread) {
if (marketResult == _line) {
return ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
} else {
OverUnderType winningPosition = resultType == ResultType.Spread
? (marketResult < _line ? OverUnderType.Over : OverUnderType.Under)
: (marketResult > _line ? OverUnderType.Over : OverUnderType.Under);
if (uint(winningPosition) == position) {
return ISportsAMMV2ResultManager.MarketPositionStatus.Winning;
}
}
} else {
if (marketResult == int(position)) {
return ISportsAMMV2ResultManager.MarketPositionStatus.Winning;
}
}
}
return ISportsAMMV2ResultManager.MarketPositionStatus.Losing;
}
return ISportsAMMV2ResultManager.MarketPositionStatus.Open;
}
function _getMarketCombinedPositionsStatus(
bytes32 _gameId,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) internal view returns (ISportsAMMV2ResultManager.MarketPositionStatus status) {
bool hasCancelledPosition = false;
bool hasOpenPosition = false;
for (uint i = 0; i < combinedPositions.length; i++) {
ISportsAMMV2.CombinedPosition memory combinedPosition = combinedPositions[i];
ISportsAMMV2ResultManager.MarketPositionStatus combinedPositionStatus = _getMarketSinglePositionStatus(
_gameId,
combinedPosition.typeId,
0,
combinedPosition.line,
combinedPosition.position
);
if (combinedPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Losing) {
return ISportsAMMV2ResultManager.MarketPositionStatus.Losing;
}
if (!hasCancelledPosition) {
hasCancelledPosition = combinedPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
}
if (!hasOpenPosition) {
hasOpenPosition = combinedPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Open;
}
}
return
hasCancelledPosition
? ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled
: (
hasOpenPosition
? ISportsAMMV2ResultManager.MarketPositionStatus.Open
: ISportsAMMV2ResultManager.MarketPositionStatus.Winning
);
}
function _exerciseLosingTickets(
address[] memory _tickets,
uint _numOfTicketsToExercise,
ISportsAMMV2 sportsAMM
) internal returns (uint numOfTicketsToExercise) {
numOfTicketsToExercise = _numOfTicketsToExercise;
for (uint i; i < _tickets.length; i++) {
if (numOfTicketsToExercise == 0) {
break;
}
Ticket ticket = Ticket(_tickets[i]);
if (ticket.isTicketExercisable() && !ticket.isUserTheWinner()) {
sportsAMM.handleTicketResolving(address(ticket), ISportsAMMV2.TicketAction.Exercise);
numOfTicketsToExercise--;
}
}
}
function _isMarketResolved(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) internal view returns (bool isResolved) {
if (isGameCancelled[_gameId]) {
isResolved = true;
} else {
ResultType resultType = resultTypePerMarketType[_typeId];
if (resultType == ResultType.CombinedPositions) {
isResolved = true;
for (uint i = 0; i < combinedPositions.length; i++) {
ISportsAMMV2.CombinedPosition memory combinedPosition = combinedPositions[i];
bool isCombinedPositionMarketResolved = _isMarketResolvedInternal(
_gameId,
combinedPosition.typeId,
0,
combinedPosition.line
);
if (!isCombinedPositionMarketResolved) {
isResolved = false;
break;
}
}
} else {
isResolved = _isMarketResolvedInternal(_gameId, _typeId, _playerId, _line);
}
}
}
function _isMarketResolvedAndPositionWinning(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) internal view returns (bool isResolved, bool isWinning) {
isResolved = _isMarketResolved(_gameId, _typeId, _playerId, _line, _combinedPositions);
ISportsAMMV2ResultManager.MarketPositionStatus marketPositionStatus = _getMarketPositionStatus(
_gameId,
_typeId,
_playerId,
_line,
_position,
_combinedPositions
);
isWinning =
marketPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Winning ||
marketPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
}
function _isWinningMarketPosition(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) internal view returns (bool) {
ISportsAMMV2ResultManager.MarketPositionStatus marketPositionStatus = _getMarketPositionStatus(
_gameId,
_typeId,
_playerId,
_line,
_position,
_combinedPositions
);
return
marketPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Winning ||
marketPositionStatus == ISportsAMMV2ResultManager.MarketPositionStatus.Cancelled;
}
modifier onlyWhitelistedAddresses(address sender) {
require(
sender == owner ||
sender == chainlinkResolver ||
manager.isWhitelistedAddress(sender, ISportsAMMV2Manager.Role.MARKET_RESOLVING),
"Invalid sender"
);
_;
}
/* ========== SETTERS ========== */
/// @notice sets the sports manager contract address
/// @param _manager the address of sports manager contract
function setSportsManager(address _manager) external onlyOwner {
require(_manager != address(0), "Invalid address");
manager = ISportsAMMV2Manager(_manager);
emit SetSportsManager(_manager);
}
/// @notice sets the address of a contract that can resolve markets via chainlink node
/// @param _chainlinkResolver the address of chainlink node client
function setChainlinkResolver(address _chainlinkResolver) external onlyOwner {
require(_chainlinkResolver != address(0), "Invalid address");
chainlinkResolver = _chainlinkResolver;
emit SetChainlinkResolver(_chainlinkResolver);
}
/// @notice sets the number of tickets to automatically exercise when resolving games
/// @param _numOfTicketsToExercise the maximum number of tickets to exercise per game resolution
function setNumOfTicketsToExerciseOnGameResolution(uint _numOfTicketsToExercise) external onlyOwner {
numOfTicketsToExerciseOnGameResolution = _numOfTicketsToExercise;
emit SetNumOfTicketsToExerciseOnGameResolution(_numOfTicketsToExercise);
}
/* ========== EVENTS ========== */
event ResultsPerMarketSet(bytes32 gameId, uint16 typeId, uint24 playerId, int24[] result);
event GameCancelled(bytes32 gameId);
event MarketExplicitlyCancelled(bytes32 gameId, uint16 typeId, uint24 playerId, int24 line);
event ResultTypePerMarketTypeSet(uint16 marketTypeId, uint resultType);
event SetSportsManager(address manager);
event SetChainlinkResolver(address resolver);
event SetNumOfTicketsToExerciseOnGameResolution(uint numOfTicketsToExercise);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/Clones.sol)
pragma solidity ^0.8.20;
/**
* @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
* deploying minimal proxy contracts, also known as "clones".
*
* > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
* > a minimal bytecode implementation that delegates all calls to a known, fixed address.
*
* The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
* (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
* deterministic method.
*/
library Clones {
/**
* @dev A clone instance deployment failed.
*/
error ERC1167FailedCreateClone();
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create opcode, which should never revert.
*/
function clone(address implementation) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create(0, 0x09, 0x37)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*/
function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
/// @solidity memory-safe-assembly
assembly {
// Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes
// of the `implementation` address with the bytecode before the address.
mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000))
// Packs the remaining 17 bytes of `implementation` with the bytecode after the address.
mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3))
instance := create2(0, 0x09, 0x37, salt)
}
if (instance == address(0)) {
revert ERC1167FailedCreateClone();
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(add(ptr, 0x38), deployer)
mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff)
mstore(add(ptr, 0x14), implementation)
mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73)
mstore(add(ptr, 0x58), salt)
mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37))
predicted := keccak256(add(ptr, 0x43), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt
) internal view returns (address predicted) {
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
/**
* @dev An operation with an ERC20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {FailedInnerCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert AddressInsufficientBalance(address(this));
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
* unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {FailedInnerCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.20;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the Merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates Merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
*@dev The multiproof provided is not valid.
*/
error MerkleProofInvalidMultiproof();
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*/
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a Merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all Merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the Merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all Merkle trees admit multiproofs. See {processMultiProof} for details.
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the Merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
if (leavesLen + proofLen != totalHashes + 1) {
revert MerkleProofInvalidMultiproof();
}
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
if (proofPos != proofLen) {
revert MerkleProofInvalidMultiproof();
}
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Sorts the pair (a, b) and hashes the result.
*/
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
/**
* @dev Implementation of keccak256(abi.encode(a, b)) that doesn't allocate or expand memory.
*/
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.16;
interface IMultiCollateralOnOffRamp {
function onramp(address collateral, uint collateralAmount) external returns (uint);
function onrampWithEth(uint amount) external payable returns (uint);
function getMinimumReceived(address collateral, uint amount) external view returns (uint);
function getMinimumNeeded(address collateral, uint amount) external view returns (uint);
function WETH9() external view returns (address);
function offrampIntoEth(uint amount) external returns (uint);
function offramp(address collateral, uint amount) external returns (uint);
function offrampFromIntoEth(address collateralFrom, uint amount) external returns (uint);
function offrampFrom(
address collateralFrom,
address collateralTo,
uint amount
) external returns (uint);
function priceFeed() external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.16;
interface IReferrals {
function referrals(address) external view returns (address);
function getReferrerFee(address) external view returns (uint);
function sportReferrals(address) external view returns (address);
function setReferrer(address, address) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.5.16;
interface IStakingThales {
function updateVolume(address account, uint amount) external;
function updateStakingRewards(
uint _currentPeriodRewards,
uint _extraRewards,
uint _revShare
) external;
/* ========== VIEWS / VARIABLES ========== */
function totalStakedAmount() external view returns (uint);
function stakedBalanceOf(address account) external view returns (uint);
function currentPeriodRewards() external view returns (uint);
function currentPeriodFees() external view returns (uint);
function getLastPeriodOfClaimedRewards(address account) external view returns (uint);
function getRewardsAvailable(address account) external view returns (uint);
function getRewardFeesAvailable(address account) external view returns (uint);
function getAlreadyClaimedRewards(address account) external view returns (uint);
function getContractRewardFunds() external view returns (uint);
function getContractFeeFunds() external view returns (uint);
function getAMMVolume(address account) external view returns (uint);
function decreaseAndTransferStakedThales(address account, uint amount) external;
function increaseAndTransferStakedThales(address account, uint amount) external;
function updateVolumeAtAmountDecimals(
address account,
uint amount,
uint decimals
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
// internal
import "../../interfaces/ISportsAMMV2Manager.sol";
import "../../interfaces/ISportsAMMV2.sol";
contract Ticket {
using SafeERC20 for IERC20;
uint private constant ONE = 1e18;
enum Phase {
Trading,
Maturity,
Expiry
}
struct MarketData {
bytes32 gameId;
uint16 sportId;
uint16 typeId;
uint maturity;
uint8 status;
int24 line;
uint24 playerId;
uint8 position;
uint odd;
ISportsAMMV2.CombinedPosition[] combinedPositions;
}
struct TicketInit {
MarketData[] _markets;
uint _buyInAmount;
uint _fees;
uint _totalQuote;
address _sportsAMM;
address _ticketOwner;
IERC20 _collateral;
uint _expiry;
bool _isLive;
uint8 _systemBetDenominator;
bool _isSGP;
}
ISportsAMMV2 public sportsAMM;
address public ticketOwner;
IERC20 public collateral;
uint public buyInAmount;
uint public fees;
uint public totalQuote;
uint public numOfMarkets;
uint public expiry;
uint public createdAt;
bool public resolved;
bool public paused;
bool public initialized;
bool public cancelled;
bool public isLive;
mapping(uint => MarketData) public markets;
uint public finalPayout;
bool public isSystem;
uint8 public systemBetDenominator;
bool public isSGP;
bool public isMarkedAsLost;
/* ========== CONSTRUCTOR ========== */
/// @notice initialize the ticket contract
/// @param params all parameters for Init
function initialize(TicketInit calldata params) external {
require(!initialized, "Ticket already initialized");
initialized = true;
sportsAMM = ISportsAMMV2(params._sportsAMM);
numOfMarkets = params._markets.length;
for (uint i = 0; i < numOfMarkets; i++) {
markets[i] = params._markets[i];
}
buyInAmount = params._buyInAmount;
fees = params._fees;
totalQuote = params._totalQuote;
ticketOwner = params._ticketOwner;
collateral = params._collateral;
expiry = params._expiry;
isLive = params._isLive;
createdAt = block.timestamp;
systemBetDenominator = params._systemBetDenominator;
isSystem = systemBetDenominator > 0;
isSGP = params._isSGP;
}
/* ========== EXTERNAL READ FUNCTIONS ========== */
/// @notice checks if the user lost the ticket
/// @return isTicketLost true/false
function isTicketLost() public view returns (bool) {
if (isMarkedAsLost) {
return true;
} else {
uint lostMarketsCount = 0;
for (uint i = 0; i < numOfMarkets; i++) {
(bool isMarketResolved, bool isWinningMarketPosition) = sportsAMM
.resultManager()
.isMarketResolvedAndPositionWinning(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].position,
markets[i].combinedPositions
);
if (isMarketResolved && !isWinningMarketPosition) {
if (!isSystem) {
return true;
} else {
lostMarketsCount++;
if (lostMarketsCount > (numOfMarkets - systemBetDenominator)) {
return true;
}
}
}
}
return false;
}
}
/// @notice checks are all markets of the ticket resolved
/// @return areAllMarketsResolved true/false
function areAllMarketsResolved() public view returns (bool) {
for (uint i = 0; i < numOfMarkets; i++) {
if (
!sportsAMM.resultManager().isMarketResolved(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].combinedPositions
)
) {
return false;
}
}
return true;
}
/// @notice checks if the user won the ticket
/// @return hasUserWon true/false
function isUserTheWinner() external view returns (bool hasUserWon) {
hasUserWon = _isUserTheWinner();
}
/// @notice checks if the ticket ready to be exercised
/// @return isExercisable true/false
function isTicketExercisable() public view returns (bool isExercisable) {
isExercisable = !resolved && (areAllMarketsResolved() || isTicketLost());
}
/// @notice gets current phase of the ticket
/// @return phase ticket phase
function phase() public view returns (Phase) {
return
isTicketExercisable() || resolved ? ((expiry < block.timestamp) ? Phase.Expiry : Phase.Maturity) : Phase.Trading;
}
/// @notice gets combined positions of the game
/// @return combinedPositions game combined positions
function getCombinedPositions(
uint _marketIndex
) public view returns (ISportsAMMV2.CombinedPosition[] memory combinedPositions) {
return markets[_marketIndex].combinedPositions;
}
/// @notice return the payout for this ticket
/// @return systemBetPayout the payout for this ticket
function getSystemBetPayout() external view returns (uint systemBetPayout) {
systemBetPayout = _getSystemBetPayout();
}
/* ========== EXTERNAL WRITE FUNCTIONS ========== */
/// @notice exercise ticket
function exercise(address _exerciseCollateral) external onlyAMM notPaused returns (uint) {
bool isExercisable = isTicketExercisable();
require(isExercisable, "Ticket not exercisable yet");
uint payoutWithFees = collateral.balanceOf(address(this));
uint payout = payoutWithFees - fees;
bool isCancelled = false;
if (_isUserTheWinner()) {
finalPayout = payout;
isCancelled = true;
for (uint i = 0; i < numOfMarkets; i++) {
bool isCancelledMarketPosition = sportsAMM.resultManager().isCancelledMarketPosition(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].position,
markets[i].combinedPositions
);
if (isCancelledMarketPosition) {
if (isSGP) {
isCancelled = true;
break;
}
finalPayout = (finalPayout * markets[i].odd) / ONE;
} else {
isCancelled = false;
}
}
finalPayout = isCancelled ? buyInAmount : (isSystem ? _getSystemBetPayout() : finalPayout);
collateral.safeTransfer(
_exerciseCollateral == address(0) || _exerciseCollateral == address(collateral)
? address(ticketOwner)
: address(sportsAMM),
finalPayout
);
}
// if user is lost or if the user payout was less than anticipated due to cancelled games, send the remainder to AMM
uint balance = collateral.balanceOf(address(this));
if (balance != 0) {
collateral.safeTransfer(address(sportsAMM), balance);
}
_resolve(!isTicketLost(), isCancelled);
return finalPayout;
}
/// @notice expire ticket
function expire(address _beneficiary) external onlyAMM {
require(phase() == Phase.Expiry, "Ticket not in expiry phase");
require(!resolved, "Can't expire resolved ticket");
emit Expired(_beneficiary);
_selfDestruct(_beneficiary);
}
/// @notice cancel the ticket
function cancel() external onlyAMM notPaused returns (uint) {
finalPayout = buyInAmount;
collateral.safeTransfer(address(ticketOwner), finalPayout);
uint balance = collateral.balanceOf(address(this));
if (balance != 0) {
collateral.safeTransfer(address(sportsAMM), balance);
}
_resolve(true, true);
return finalPayout;
}
/// @notice mark the ticket as lost
function markAsLost() external onlyAMM notPaused returns (uint) {
uint balance = collateral.balanceOf(address(this));
if (balance != 0) {
collateral.safeTransfer(address(sportsAMM), balance);
}
_resolve(false, false);
isMarkedAsLost = true;
return 0;
}
/// @notice withdraw collateral from the ticket
function withdrawCollateral(address recipient) external onlyAMM {
collateral.safeTransfer(recipient, collateral.balanceOf(address(this)));
}
/* ========== INTERNAL FUNCTIONS ========== */
function _resolve(bool _hasUserWon, bool _cancelled) internal {
resolved = true;
cancelled = _cancelled;
emit Resolved(_hasUserWon, _cancelled);
}
function _selfDestruct(address beneficiary) internal {
uint balance = collateral.balanceOf(address(this));
if (balance != 0) {
collateral.safeTransfer(beneficiary, balance);
}
}
function _isUserTheWinner() internal view returns (bool hasUserWon) {
if (areAllMarketsResolved()) {
hasUserWon = !isTicketLost();
}
}
/* ========== SETTERS ========== */
function setPaused(bool _paused) external {
require(msg.sender == address(sportsAMM.manager()), "Invalid sender");
if (paused == _paused) return;
paused = _paused;
emit PauseUpdated(_paused);
}
/* ========== SYSTEM BET UTILS ========== */
function _getSystemBetPayout() internal view returns (uint systemBetPayout) {
if (isSystem) {
uint8[][] memory systemCombinations = sportsAMM.riskManager().generateCombinations(
uint8(numOfMarkets),
systemBetDenominator
);
uint totalCombinations = systemCombinations.length;
uint buyinPerCombination = ((buyInAmount * ONE) / totalCombinations) / ONE;
bool[] memory winningMarkets = new bool[](numOfMarkets);
bool[] memory cancelledMarkets = new bool[](numOfMarkets);
for (uint i = 0; i < numOfMarkets; i++) {
if (
!sportsAMM.resultManager().isMarketResolved(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].combinedPositions
)
) {
return 0;
}
winningMarkets[i] = sportsAMM.resultManager().isWinningMarketPosition(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].position,
markets[i].combinedPositions
);
cancelledMarkets[i] = sportsAMM.resultManager().isCancelledMarketPosition(
markets[i].gameId,
markets[i].typeId,
markets[i].playerId,
markets[i].line,
markets[i].position,
markets[i].combinedPositions
);
}
// Loop through each stored combination
for (uint i = 0; i < totalCombinations; i++) {
uint8[] memory currentCombination = systemCombinations[i];
uint combinationQuote = ONE;
for (uint j = 0; j < currentCombination.length; j++) {
uint8 marketIndex = currentCombination[j];
if (winningMarkets[marketIndex]) {
if (!cancelledMarkets[marketIndex]) {
combinationQuote = (combinationQuote * markets[marketIndex].odd) / ONE;
}
} else {
combinationQuote = 0;
break;
}
}
if (combinationQuote > 0) {
uint combinationPayout = (buyinPerCombination * ONE) / combinationQuote;
systemBetPayout += combinationPayout;
}
}
uint maxPayout = (buyInAmount * ONE) / totalQuote;
if (systemBetPayout > maxPayout) {
systemBetPayout = maxPayout;
}
}
}
/* ========== MODIFIERS ========== */
modifier onlyAMM() {
require(msg.sender == address(sportsAMM), "Only the AMM may perform these methods");
_;
}
modifier notPaused() {
require(!paused, "Market paused");
_;
}
/* ========== EVENTS ========== */
event Resolved(bool isUserTheWinner, bool cancelled);
event Expired(address beneficiary);
event PauseUpdated(bool paused);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./IProxyBetting.sol";
interface IFreeBetsHolder is IProxyBetting {
function confirmLiveTrade(bytes32 requestId, address _createdTicket, uint _buyInAmount, address _collateral) external;
function confirmSGPTrade(bytes32 requestId, address _createdTicket, uint _buyInAmount, address _collateral) external;
function balancePerUserAndCollateral(address user, address collateral) external view returns (uint);
function freeBetExpiration(address user, address collateral) external view returns (uint);
function freeBetExpirationUpgrade() external view returns (uint);
function freeBetExpirationPeriod() external view returns (uint);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IProxyBetting {
function getActiveTicketsPerUser(uint _index, uint _pageSize, address _user) external view returns (address[] memory);
function numOfActiveTicketsPerUser(address _user) external view returns (uint);
function getResolvedTicketsPerUser(uint _index, uint _pageSize, address _user) external view returns (address[] memory);
function numOfResolvedTicketsPerUser(address _user) external view returns (uint);
function confirmTicketResolved(address _resolvedTicket) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../interfaces/ISportsAMMV2Manager.sol";
import "../interfaces/ISportsAMMV2ResultManager.sol";
import "../interfaces/ISportsAMMV2RiskManager.sol";
import "../interfaces/ISportsAMMV2Manager.sol";
import "../interfaces/IFreeBetsHolder.sol";
import "../interfaces/IStakingThalesBettingProxy.sol";
interface ISportsAMMV2 {
enum TicketAction {
Exercise,
Cancel,
MarkLost
}
struct CombinedPosition {
uint16 typeId;
uint8 position;
int24 line;
}
struct TradeData {
bytes32 gameId;
uint16 sportId;
uint16 typeId;
uint maturity;
uint8 status;
int24 line;
uint24 playerId;
uint[] odds;
bytes32[] merkleProof;
uint8 position;
CombinedPosition[][] combinedPositions;
}
function defaultCollateral() external view returns (IERC20);
function manager() external view returns (ISportsAMMV2Manager);
function resultManager() external view returns (ISportsAMMV2ResultManager);
function safeBoxFee() external view returns (uint);
function handleTicketResolving(address _ticket, ISportsAMMV2.TicketAction action) external;
function riskManager() external view returns (ISportsAMMV2RiskManager);
function freeBetsHolder() external view returns (IFreeBetsHolder);
function stakingThalesBettingProxy() external view returns (IStakingThalesBettingProxy);
function tradeLive(
TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
address _recipient,
address _referrer,
address _collateral
) external returns (address _createdTicket);
function trade(
TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
uint _additionalSlippage,
address _referrer,
address _collateral,
bool _isEth
) external returns (address _createdTicket);
function tradeSystemBet(
TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
uint _additionalSlippage,
address _referrer,
address _collateral,
bool _isEth,
uint8 _systemBetDenominator
) external returns (address _createdTicket);
function tradeSGP(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _approvedQuote,
address _recipient,
address _referrer,
address _collateral
) external returns (address _createdTicket);
function rootPerGame(bytes32 game) external view returns (bytes32);
function getRootsPerGames(bytes32[] calldata _games) external view returns (bytes32[] memory _roots);
function paused() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface ISportsAMMV2LiquidityPool {
function commitTrade(address ticket, uint amount) external;
function transferToPool(address ticket, uint amount) external;
function getTicketPool(address _ticket) external returns (address);
function collateralKey() external view returns (bytes32);
function getCollateralPrice() external view returns (uint);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./ISportsAMMV2.sol";
interface ISportsAMMV2Manager {
enum Role {
ROOT_SETTING,
RISK_MANAGING,
MARKET_RESOLVING,
TICKET_PAUSER
}
function isWhitelistedAddress(address _address, Role role) external view returns (bool);
function decimals() external view returns (uint);
function feeToken() external view returns (address);
function isActiveTicket(address _ticket) external view returns (bool);
function getActiveTickets(uint _index, uint _pageSize) external view returns (address[] memory);
function numOfActiveTickets() external view returns (uint);
function getActiveTicketsPerUser(uint _index, uint _pageSize, address _user) external view returns (address[] memory);
function numOfActiveTicketsPerUser(address _user) external view returns (uint);
function getResolvedTicketsPerUser(uint _index, uint _pageSize, address _user) external view returns (address[] memory);
function numOfResolvedTicketsPerUser(address _user) external view returns (uint);
function getTicketsPerGame(uint _index, uint _pageSize, bytes32 _gameId) external view returns (address[] memory);
function numOfTicketsPerGame(bytes32 _gameId) external view returns (uint);
function isKnownTicket(address _ticket) external view returns (bool);
function sportsAMM() external view returns (address);
function getTicketsPerMarket(
uint _index,
uint _pageSize,
bytes32 _gameId,
uint _typeId,
uint _playerId
) external view returns (address[] memory);
function numOfTicketsPerMarket(bytes32 _gameId, uint _typeId, uint _playerId) external view returns (uint);
function addNewKnownTicket(ISportsAMMV2.TradeData[] memory _tradeData, address ticket, address user) external;
function resolveKnownTicket(address ticket, address ticketOwner) external;
function expireKnownTicket(address ticket, address ticketOwner) external;
function isSystemTicket(address _ticket) external view returns (bool);
function isSGPTicket(address _ticket) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./ISportsAMMV2.sol";
interface ISportsAMMV2ResultManager {
enum MarketPositionStatus {
Open,
Cancelled,
Winning,
Losing
}
function isMarketResolved(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
ISportsAMMV2.CombinedPosition[] memory combinedPositions
) external view returns (bool isResolved);
function getMarketPositionStatus(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (MarketPositionStatus status);
function isWinningMarketPosition(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool isWinning);
function isCancelledMarketPosition(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool isCancelled);
function getResultsPerMarket(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId
) external view returns (int24[] memory results);
function resultTypePerMarketType(uint _typeId) external view returns (uint8 marketType);
function isMarketResolvedAndPositionWinning(
bytes32 _gameId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _position,
ISportsAMMV2.CombinedPosition[] memory _combinedPositions
) external view returns (bool isResolved, bool isWinning);
function setResultsPerMarkets(
bytes32[] memory _gameIds,
uint16[] memory _typeIds,
uint24[] memory _playerIds,
int24[][] memory _results
) external;
function isGameCancelled(bytes32 _gameId) external view returns (bool);
function cancelGames(bytes32[] memory _gameIds) external;
function cancelMarkets(
bytes32[] memory _gameIds,
uint16[] memory _typeIds,
uint24[] memory _playerIds,
int24[] memory _lines
) external;
function cancelMarket(bytes32 _gameId, uint16 _typeId, uint24 _playerId, int24 _line) external;
function cancelGame(bytes32 _gameId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./ISportsAMMV2.sol";
interface ISportsAMMV2RiskManager {
struct TypeCap {
uint typeId;
uint cap;
}
struct CapData {
uint capPerSport;
uint capPerChild;
TypeCap[] capPerType;
}
struct DynamicLiquidityData {
uint cutoffTimePerSport;
uint cutoffDividerPerSport;
}
struct RiskData {
uint sportId;
CapData capData;
uint riskMultiplierPerSport;
DynamicLiquidityData dynamicLiquidityData;
}
enum RiskStatus {
NoRisk,
OutOfLiquidity,
InvalidCombination
}
function minBuyInAmount() external view returns (uint);
function maxTicketSize() external view returns (uint);
function maxSupportedAmount() external view returns (uint);
function maxSupportedOdds() external view returns (uint);
function maxAllowedSystemCombinations() external view returns (uint);
function expiryDuration() external view returns (uint);
function liveTradingPerSportAndTypeEnabled(uint _sportId, uint _typeId) external view returns (bool _enabled);
function calculateCapToBeUsed(
bytes32 _gameId,
uint16 _sportId,
uint16 _typeId,
uint24 _playerId,
int24 _line,
uint _maturity,
bool _isLive
) external view returns (uint cap);
function checkRisks(
ISportsAMMV2.TradeData[] memory _tradeData,
uint _buyInAmount,
bool _isLive,
uint8 _systemBetDenominator
) external view returns (ISportsAMMV2RiskManager.RiskStatus riskStatus, bool[] memory isMarketOutOfLiquidity);
function checkLimits(
uint _buyInAmount,
uint _totalQuote,
uint _payout,
uint _expectedPayout,
uint _additionalSlippage,
uint _ticketSize
) external view;
function spentOnGame(bytes32 _gameId) external view returns (uint);
function riskPerMarketTypeAndPosition(
bytes32 _gameId,
uint _typeId,
uint _playerId,
uint _position
) external view returns (int);
function checkAndUpdateRisks(
ISportsAMMV2.TradeData[] memory _tradeData,
uint _buyInAmount,
uint _payout,
bool _isLive,
uint8 _systemBetDenominator,
bool _isSGP
) external;
function verifyMerkleTree(ISportsAMMV2.TradeData memory _marketTradeData, bytes32 _rootPerGame) external pure;
function batchVerifyMerkleTree(
ISportsAMMV2.TradeData[] memory _marketTradeData,
bytes32[] memory _rootPerGame
) external pure;
function isSportIdFuture(uint16 _sportsId) external view returns (bool);
function sgpOnSportIdEnabled(uint16 _sportsId) external view returns (bool);
function getMaxSystemBetPayout(
ISportsAMMV2.TradeData[] memory _tradeData,
uint8 _systemBetDenominator,
uint _buyInAmount,
uint _addedPayoutPercentage
) external view returns (uint systemBetPayout, uint systemBetQuote);
function generateCombinations(uint8 n, uint8 k) external pure returns (uint8[][] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./IProxyBetting.sol";
interface IStakingThalesBettingProxy is IProxyBetting {
function preConfirmLiveTrade(bytes32 requestId, uint _buyInAmount) external;
function confirmLiveTrade(bytes32 requestId, address _createdTicket, uint _buyInAmount) external;
function preConfirmSGPTrade(bytes32 requestId, uint _buyInAmount) external;
function confirmSGPTrade(bytes32 requestId, address _createdTicket, uint _buyInAmount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library AddressSetLib {
struct AddressSet {
address[] elements;
mapping(address => uint) indices;
}
function contains(AddressSet storage set, address candidate) internal view returns (bool) {
if (set.elements.length == 0) {
return false;
}
uint index = set.indices[candidate];
return index != 0 || set.elements[0] == candidate;
}
function getPage(AddressSet storage set, uint index, uint pageSize) internal view returns (address[] memory) {
// NOTE: This implementation should be converted to slice operators if the compiler is updated to v0.6.0+
uint endIndex = index + pageSize; // The check below that endIndex <= index handles overflow.
// If the page extends past the end of the list, truncate it.
if (endIndex > set.elements.length) {
endIndex = set.elements.length;
}
if (endIndex <= index) {
return new address[](0);
}
uint n = endIndex - index; // We already checked for negative overflow.
address[] memory page = new address[](n);
for (uint i; i < n; i++) {
page[i] = set.elements[i + index];
}
return page;
}
function add(AddressSet storage set, address element) internal {
// Adding to a set is an idempotent operation.
if (!contains(set, element)) {
set.indices[element] = set.elements.length;
set.elements.push(element);
}
}
function remove(AddressSet storage set, address element) internal {
require(contains(set, element), "Element not in set.");
// Replace the removed element with the last element of the list.
uint index = set.indices[element];
uint lastIndex = set.elements.length - 1; // We required that element is in the list, so it is not empty.
if (index != lastIndex) {
// No need to shift the last element if it is the one we want to delete.
address shiftedElement = set.elements[lastIndex];
set.elements[index] = shiftedElement;
set.indices[shiftedElement] = index;
}
set.elements.pop();
delete set.indices[element];
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Clone of syntetix contract without constructor
contract ProxyOwned {
address public owner;
address public nominatedOwner;
bool private _initialized;
bool private _transferredAtInit;
function setOwner(address _owner) public {
require(_owner != address(0), "Owner address cannot be 0");
require(!_initialized, "Already initialized, use nominateNewOwner");
_initialized = true;
owner = _owner;
emit OwnerChanged(address(0), _owner);
}
function nominateNewOwner(address _owner) external onlyOwner {
nominatedOwner = _owner;
emit OwnerNominated(_owner);
}
function acceptOwnership() external {
require(msg.sender == nominatedOwner, "You must be nominated before you can accept ownership");
emit OwnerChanged(owner, nominatedOwner);
owner = nominatedOwner;
nominatedOwner = address(0);
}
function transferOwnershipAtInit(address proxyAddress) external onlyOwner {
require(proxyAddress != address(0), "Invalid address");
require(!_transferredAtInit, "Already transferred");
owner = proxyAddress;
_transferredAtInit = true;
emit OwnerChanged(owner, proxyAddress);
}
modifier onlyOwner() {
_onlyOwner();
_;
}
function _onlyOwner() private view {
require(msg.sender == owner, "Only the contract owner may perform this action");
}
event OwnerNominated(address newOwner);
event OwnerChanged(address oldOwner, address newOwner);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// Inheritance
import "./ProxyOwned.sol";
// Clone of syntetix contract without constructor
contract ProxyPausable is ProxyOwned {
uint public lastPauseTime;
bool public paused;
/**
* @notice Change the paused state of the contract
* @dev Only the contract owner may call this.
*/
function setPaused(bool _paused) external onlyOwner {
// Ensure we're actually changing the state before we do anything
if (_paused == paused) {
return;
}
// Set our paused state.
paused = _paused;
// If applicable, set the last pause time.
if (paused) {
lastPauseTime = block.timestamp;
}
// Let everyone know that our pause state has changed.
emit PauseChanged(paused);
}
event PauseChanged(bool isPaused);
modifier notPaused() {
require(!paused, "This action cannot be performed while the contract is paused");
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
* available, which can be aplied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*/
contract ProxyReentrancyGuard {
/// @dev counter to allow mutex lock with only one SSTORE operation
uint256 private _guardCounter;
bool private _initialized;
function initNonReentrant() public {
require(!_initialized, "Already initialized");
_initialized = true;
_guardCounter = 1;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
}
}{
"optimizer": {
"enabled": true,
"runs": 100
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"}],"name":"GameCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"typeId","type":"uint16"},{"indexed":false,"internalType":"uint24","name":"playerId","type":"uint24"},{"indexed":false,"internalType":"int24","name":"line","type":"int24"}],"name":"MarketExplicitlyCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerNominated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"marketTypeId","type":"uint16"},{"indexed":false,"internalType":"uint256","name":"resultType","type":"uint256"}],"name":"ResultTypePerMarketTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"gameId","type":"bytes32"},{"indexed":false,"internalType":"uint16","name":"typeId","type":"uint16"},{"indexed":false,"internalType":"uint24","name":"playerId","type":"uint24"},{"indexed":false,"internalType":"int24[]","name":"result","type":"int24[]"}],"name":"ResultsPerMarketSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"resolver","type":"address"}],"name":"SetChainlinkResolver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"numOfTicketsToExercise","type":"uint256"}],"name":"SetNumOfTicketsToExerciseOnGameResolution","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"manager","type":"address"}],"name":"SetSportsManager","type":"event"},{"inputs":[],"name":"CANCEL_ID","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"areResultsPerMarketSet","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"}],"name":"cancelGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_gameIds","type":"bytes32[]"}],"name":"cancelGames","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"}],"name":"cancelMarket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_gameIds","type":"bytes32[]"},{"internalType":"uint16[]","name":"_typeIds","type":"uint16[]"},{"internalType":"uint24[]","name":"_playerIds","type":"uint24[]"},{"internalType":"int24[]","name":"_lines","type":"int24[]"}],"name":"cancelMarkets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainlinkResolver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"internalType":"uint256","name":"_position","type":"uint256"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"_combinedPositions","type":"tuple[]"}],"name":"getMarketPositionStatus","outputs":[{"internalType":"enum ISportsAMMV2ResultManager.MarketPositionStatus","name":"status","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"}],"name":"getResultsPerMarket","outputs":[{"internalType":"int24[]","name":"results","type":"int24[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initNonReentrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"contract ISportsAMMV2Manager","name":"_manager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"internalType":"uint256","name":"_position","type":"uint256"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"_combinedPositions","type":"tuple[]"}],"name":"isCancelledMarketPosition","outputs":[{"internalType":"bool","name":"isCancelled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"isGameCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"combinedPositions","type":"tuple[]"}],"name":"isMarketCancelled","outputs":[{"internalType":"bool","name":"isCancelled","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"int256","name":"","type":"int256"}],"name":"isMarketExplicitlyCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"combinedPositions","type":"tuple[]"}],"name":"isMarketResolved","outputs":[{"internalType":"bool","name":"isResolved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"internalType":"uint256","name":"_position","type":"uint256"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"_combinedPositions","type":"tuple[]"}],"name":"isMarketResolvedAndPositionWinning","outputs":[{"internalType":"bool","name":"isResolved","type":"bool"},{"internalType":"bool","name":"isWinning","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_gameId","type":"bytes32"},{"internalType":"uint16","name":"_typeId","type":"uint16"},{"internalType":"uint24","name":"_playerId","type":"uint24"},{"internalType":"int24","name":"_line","type":"int24"},{"internalType":"uint256","name":"_position","type":"uint256"},{"components":[{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"}],"internalType":"struct ISportsAMMV2.CombinedPosition[]","name":"_combinedPositions","type":"tuple[]"}],"name":"isWinningMarketPosition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPauseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract ISportsAMMV2Manager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"nominateNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nominatedOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"numOfTicketsToExerciseOnGameResolution","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"resultTypePerMarketType","outputs":[{"internalType":"enum SportsAMMV2ResultManager.ResultType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"resultsPerMarket","outputs":[{"internalType":"int24","name":"","type":"int24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_chainlinkResolver","type":"address"}],"name":"setChainlinkResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_numOfTicketsToExercise","type":"uint256"}],"name":"setNumOfTicketsToExerciseOnGameResolution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"setOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_paused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"_marketTypeIds","type":"uint16[]"},{"internalType":"uint256[]","name":"_resultTypes","type":"uint256[]"}],"name":"setResultTypesPerMarketTypes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_gameIds","type":"bytes32[]"},{"internalType":"uint16[]","name":"_typeIds","type":"uint16[]"},{"internalType":"uint24[]","name":"_playerIds","type":"uint24[]"},{"internalType":"int24[][]","name":"_results","type":"int24[][]"}],"name":"setResultsPerMarkets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_manager","type":"address"}],"name":"setSportsManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proxyAddress","type":"address"}],"name":"transferOwnershipAtInit","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561001057600080fd5b50612df4806100206000396000f3fe608060405234801561001057600080fd5b50600436106101db5760003560e01c806379ba509711610105578063b9c565801161009d578063b9c5658014610475578063bad260f514610488578063c3b83f5f1461049b578063d1e567ef146104ae578063df47035d146104c1578063ebc79772146104d4578063ec7c314c146104dc578063fd72d4c6146104ff578063fd9552e71461053357600080fd5b806379ba5097146103a75780637f8a3f8c146103af57806380be6355146103c25780638223154b146103d55780638da5cb5b146103df578063914008bc146103f257806391b4ded91461042257806399a50a081461042b578063aa0cc0961461045557600080fd5b80633f7121b0116101785780633f7121b0146102b9578063481c6a75146102cc578063485cc955146102f1578063514b75631461030457806353a47bb7146103245780635c975abb1461033757806361283ea11461034457806371752fa51461038157806376d050811461039457600080fd5b80625143a5146101e05780630ae677181461020b57806313af4035146102225780631627540c1461023757806316c38b3c1461024a57806318d83b881461025d57806319aafc59146102705780631e72f8e414610283578063397f782314610296575b600080fd5b6101f36101ee36600461225f565b610546565b60405160029190910b81526020015b60405180910390f35b610214600c5481565b604051908152602001610202565b6102356102303660046122a6565b6105a6565b005b6102356102453660046122a6565b6106c2565b6102356102583660046122d8565b610715565b61023561026b366004612553565b610787565b61023561027e3660046125ff565b610933565b610235610291366004612718565b610db6565b6102a96102a43660046127e3565b610df3565b6040519015158152602001610202565b6102356102c7366004612718565b610e0c565b6005546102e49061010090046001600160a01b031681565b604051610202919061285b565b6102356102ff36600461286f565b610edb565b6103176103123660046128a8565b611012565b6040516102029190612922565b6001546102e4906001600160a01b031681565b6003546102a99060ff1681565b6102a961035236600461225f565b600960209081526000948552604080862082529385528385208152918452828420909152825290205460ff1681565b6102a961038f366004612935565b6110b2565b6102a96103a2366004612935565b6110e7565b610235611102565b600b546102e4906001600160a01b031681565b6102356103d03660046122a6565b6111da565b6101f361270e1981565b6000546102e4906001600160a01b031681565b610415610400366004612718565b600a6020526000908152604090205460ff1681565b60405161020291906129cb565b61021460025481565b61043e610439366004612935565b611258565b604080519215158352901515602083015201610202565b610468610463366004612935565b611278565b60405161020291906129f5565b610235610483366004612a02565b611288565b6102356104963660046122a6565b61135d565b6102356104a93660046122a6565b6113d6565b6102a96104bc3660046127e3565b6114a4565b6102356104cf366004612a4f565b61157f565b6102356116ef565b6102a96104ea366004612718565b60086020526000908152604090205460ff1681565b6102a961050d366004612b09565b600760209081526000938452604080852082529284528284209052825290205460ff1681565b610235610541366004612b35565b61174d565b6006602052836000526040600020602052826000526040600020602052816000526040600020818154811061057a57600080fd5b90600052602060002090600a91828204019190066003029350935050509054906101000a900460020b81565b6001600160a01b0381166105fd5760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064015b60405180910390fd5b600154600160a01b900460ff16156106695760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016105f4565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b0319909116178155604051600080516020612d9f833981519152916106b7918490612b71565b60405180910390a150565b6106ca611855565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906106b790839061285b565b61071d611855565b60035460ff16151581151514610784576003805460ff191682151590811790915560ff161561074b57426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5906020016106b7565b50565b60005433906001600160a01b03168114806107af5750600b546001600160a01b038281169116145b8061082d575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906107ec908490600290600401612b8b565b602060405180830381865afa158015610809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d9190612bb1565b6108495760405162461bcd60e51b81526004016105f490612bce565b8351855114801561085b575082518451145b8015610868575081518351145b6108845760405162461bcd60e51b81526004016105f490612bf6565b60005b855181101561092b5760008682815181106108a4576108a4612c20565b6020026020010151905060008683815181106108c2576108c2612c20565b6020026020010151905060008684815181106108e0576108e0612c20565b6020026020010151905060008685815181106108fe576108fe612c20565b60200260200101519050610914848484846118c9565b50505050808061092390612c4c565b915050610887565b505050505050565b60005433906001600160a01b031681148061095b5750600b546001600160a01b038281169116145b806109d9575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c39590610998908490600290600401612b8b565b602060405180830381865afa1580156109b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d99190612bb1565b6109f55760405162461bcd60e51b81526004016105f490612bce565b83518551148015610a07575082518451145b8015610a14575081518351145b610a305760405162461bcd60e51b81526004016105f490612bf6565b6000600560019054906101000a90046001600160a01b03166001600160a01b031663c99252886040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa99190612c65565b600c5490915060005b8751811015610dac576000888281518110610acf57610acf612c20565b6020908102919091018101516000818152600890925260409091205490915060ff1615610afc5750610d9a565b6000888381518110610b1057610b10612c20565b602002602001015190506000888481518110610b2e57610b2e612c20565b602002602001015190506000888581518110610b4c57610b4c612c20565b6020026020010151905061270e1960020b81600081518110610b7057610b70612c20565b602002602001015160020b03610b9257610b8d84848460006118c9565b610d95565b61ffff83166000908152600a602052604081205460ff1690816004811115610bbc57610bbc6129b5565b03610bff5760405162461bcd60e51b815260206004820152601360248201527214995cdd5b1d081d1e5c19481b9bdd081cd95d606a1b60448201526064016105f4565b600085815260076020908152604080832061ffff88168452825280832062ffffff8716845290915290205460ff16610d9357600085815260066020908152604080832061ffff88168452825280832062ffffff8716845282529091208351610c699285019061219b565b50600085815260076020908152604080832061ffff88168452825280832062ffffff871684529091529020805460ff191660011790558615610d5557600554600c5460405163048dfadf60e51b815260006004820181905260248201929092526044810188905261ffff8716606482015262ffffff86166084820152909161010090046001600160a01b0316906391bf5be09060a401600060405180830381865afa158015610d1c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d449190810190612c82565b9050610d5181898b6119b0565b9750505b7fdcd786a10e38c0f82a8b25e7e6b9e0276df2edfb3fe19107add54b0c7593554b85858585604051610d8a9493929190612d10565b60405180910390a15b505b505050505b80610da481612c4c565b915050610ab2565b5050505050505050565b610dbe611855565b600c8190556040518181527f49036f75cf067392bf360ab91f66395e6731702011691226d911256085472add906020016106b7565b6000610e028686868686611b3e565b9695505050505050565b60005433906001600160a01b0316811480610e345750600b546001600160a01b038281169116145b80610eb2575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c39590610e71908490600290600401612b8b565b602060405180830381865afa158015610e8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb29190612bb1565b610ece5760405162461bcd60e51b81526004016105f490612bce565b610ed782611c05565b5050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015610f205750825b90506000826001600160401b03166001148015610f3c5750303b155b905081158015610f4a575080155b15610f685760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610f9257845460ff60401b1916600160401b1785555b610f9b876105a6565b610fa36116ef565b60058054610100600160a81b0319166101006001600160a01b03891602179055831561100957845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600083815260066020908152604080832061ffff86168452825280832062ffffff851684528252918290208054835181840281018401909452808452606093928301828280156110a457602002820191906000526020600020906000905b825461010083900a900460020b81526020600583018190049384019360010360039093019290920291018084116110705790505b505050505090509392505050565b6000806110c3888888888888611ca8565b905060015b8160038111156110da576110da6129b5565b1498975050505050505050565b60006110f7878787878787611d00565b979650505050505050565b6001546001600160a01b0316331461117a5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016105f4565b600054600154604051600080516020612d9f833981519152926111ab926001600160a01b0391821692911690612b71565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6111e2611855565b6001600160a01b0381166112085760405162461bcd60e51b81526004016105f490612d3e565b60058054610100600160a81b0319166101006001600160a01b038416021790556040517f3f95458abea6f2ed78f07dd5ee75af62322c77d86a51a87aabc86aa92d34a6b1906106b790839061285b565b600080611269888888888888611d35565b90999098509650505050505050565b60006110f7878787878787611ca8565b60005433906001600160a01b03168114806112b05750600b546001600160a01b038281169116145b8061132e575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906112ed908490600290600401612b8b565b602060405180830381865afa15801561130a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132e9190612bb1565b61134a5760405162461bcd60e51b81526004016105f490612bce565b611356858585856118c9565b5050505050565b611365611855565b6001600160a01b03811661138b5760405162461bcd60e51b81526004016105f490612d3e565b600b80546001600160a01b0319166001600160a01b0383161790556040517f306e3fdb40fb48602fc9bdf15fa992b86cf0476f1a141034292aafa47b2a9d60906106b790839061285b565b6113de611855565b6001600160a01b0381166114045760405162461bcd60e51b81526004016105f490612d3e565b600154600160a81b900460ff16156114545760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016105f4565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b179055604051600080516020612d9f833981519152916106b7918490612b71565b60008581526008602052604081205460ff16156114c357506001611576565b61ffff85166000908152600a602052604090205460ff1660038160048111156114ee576114ee6129b5565b03611565576001915060005b835181101561155f57600084828151811061151757611517612c20565b6020026020010151905060006115388a836000015160008560400151611d98565b90508061154a5760009450505061155f565b5050808061155790612c4c565b9150506114fa565b50611574565b61157187878787611d98565b91505b505b95945050505050565b611587611855565b80518251146115a85760405162461bcd60e51b81526004016105f490612bf6565b60005b82518110156116ea5760008382815181106115c8576115c8612c20565b6020026020010151905060008383815181106115e6576115e6612c20565b6020026020010151905060006004811115611603576116036129b5565b81118015611612575060048111155b6116545760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420726573756c74207479706560681b60448201526064016105f4565b806004811115611666576116666129b5565b61ffff83166000908152600a60205260409020805460ff19166001836004811115611693576116936129b5565b02179055506040805161ffff84168152602081018390527fc478d6b1f79f5e21a854090b896e0158e7ba15ce7306f4976088312888df3abf910160405180910390a1505080806116e290612c4c565b9150506115ab565b505050565b60055460ff16156117385760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016105f4565b6005805460ff19166001908117909155600455565b60005433906001600160a01b03168114806117755750600b546001600160a01b038281169116145b806117f3575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906117b2908490600290600401612b8b565b602060405180830381865afa1580156117cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f39190612bb1565b61180f5760405162461bcd60e51b81526004016105f490612bce565b60005b82518110156116ea57600083828151811061182f5761182f612c20565b6020026020010151905061184281611c05565b508061184d81612c4c565b915050611812565b6000546001600160a01b031633146118c75760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016105f4565b565b6118d584848484611d98565b1561191d5760405162461bcd60e51b815260206004820152601860248201527713585c9ad95d08185b1c9958591e4818d85b98d95b1b195960421b60448201526064016105f4565b600084815260096020908152604080832061ffff871680855290835281842062ffffff8716808652908452828520600287900b80875290855294839020805460ff191660011790558251898152938401919091529082015260608101919091527f6ec5a8dc9a5e3412ca54efb27c0872cecd2e615705463dcc2ca045e0190ede649060800160405180910390a150505050565b8160005b8451811015611b36578115611b365760008582815181106119d7576119d7612c20565b60200260200101519050806001600160a01b031663e74d3c476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a439190612bb1565b8015611aae5750806001600160a01b0316633356a35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aac9190612bb1565b155b15611b2357604051630f8a940b60e41b81526001600160a01b0385169063f8a940b090611ae2908490600090600401612d67565b600060405180830381600087803b158015611afc57600080fd5b505af1158015611b10573d6000803e3d6000fd5b505050508280611b1f90612d87565b9350505b5080611b2e81612c4c565b9150506119b4565b509392505050565b60008581526008602052604081205460ff1615611b5d57506001611576565b61ffff85166000908152600a602052604090205460ff166003816004811115611b8857611b886129b5565b03611bf9576001915060005b835181101561155f576000848281518110611bb157611bb1612c20565b602002602001015190506000611bd28a836000015160008560400151611e30565b905080611be45760009450505061155f565b50508080611bf190612c4c565b915050611b94565b61157187878787611e30565b60008181526008602052604090205460ff1615611c5d5760405162461bcd60e51b815260206004820152601660248201527511d85b5948185b1c9958591e4818d85b98d95b1b195960521b60448201526064016105f4565b60008181526008602052604090819020805460ff19166001179055517f730d9f4e127b4c1c5d999194f79025fe149736fbb95b0755b18ed20ddd01b4e0906106b79083815260200190565b61ffff85166000908152600a602052604081205460ff166003816004811115611cd357611cd36129b5565b14611cea57611ce58888888888611e70565b611cf4565b611cf488846120b0565b98975050505050505050565b600080611d11888888888888611ca8565b90506002816003811115611d2757611d276129b5565b1480611cf4575060016110c8565b600080611d458888888887611b3e565b91506000611d57898989898989611ca8565b90506002816003811115611d6d57611d6d6129b5565b1480611d8a57506001816003811115611d8857611d886129b5565b145b915050965096945050505050565b60008481526008602052604081205460ff1680611deb5750600085815260096020908152604080832061ffff88168452825280832062ffffff871684528252808320600286900b845290915290205460ff165b806115765750600085815260096020908152604080832061ffff88168452825280832062ffffff87168452825280832083805290915290205460ff1695945050505050565b600084815260076020908152604080832061ffff87168452825280832062ffffff8616845290915281205460ff1680611576575061157685858585611d98565b6000611e7e86868686611d98565b15611e8b57506001611576565b600086815260076020908152604080832061ffff89168452825280832062ffffff8816845290915290205460ff16156120a457600086815260066020908152604080832061ffff89168452825280832062ffffff88168452825280832080548251818502810185019093528083529192909190830182828015611f5057602002820191906000526020600020906000905b825461010083900a900460020b8152602060058301819004938401936001036003909301929092029101808411611f1c5790505b50505061ffff89166000908152600a602052604081205493945060ff909316929150505b8251811015612098576000838281518110611f9157611f91612c20565b602002602001015160020b905060026004811115611fb157611fb16129b5565b836004811115611fc357611fc36129b5565b1480611fe057506004836004811115611fde57611fde6129b5565b145b15612071578660020b8103611ffc576001945050505050611576565b60006004846004811115612012576120126129b5565b1461202f578760020b8213612028576001612043565b6000612043565b8760020b8212612040576001612043565b60005b905086816001811115612058576120586129b5565b0361206b57600295505050505050611576565b50612085565b858103612085576002945050505050611576565b508061209081612c4c565b915050611f74565b50600392505050611576565b50600095945050505050565b60008080805b84518110156121745760008582815181106120d3576120d3612c20565b6020026020010151905060006120fc88836000015160008560400151866020015160ff16611e70565b90506003816003811115612112576121126129b5565b0361212557600395505050505050612195565b8461214257600181600381111561213e5761213e6129b5565b1494505b8361215f57600081600381111561215b5761215b6129b5565b1493505b5050808061216c90612c4c565b9150506120b6565b508161218d5780612186576002612190565b6000612190565b60015b925050505b92915050565b82805482825590600052602060002090600901600a9004810192821561223a5791602002820160005b8382111561220957835183826101000a81548162ffffff021916908360020b62ffffff16021790555092602001926003016020816002010492830192600103026121c4565b80156122385782816101000a81549062ffffff0219169055600301602081600201049283019260010302612209565b505b5061224692915061224a565b5090565b5b80821115612246576000815560010161224b565b6000806000806080858703121561227557600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b038116811461078457600080fd5b6000602082840312156122b857600080fd5b81356122c381612291565b9392505050565b801515811461078457600080fd5b6000602082840312156122ea57600080fd5b81356122c3816122ca565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171561232d5761232d6122f5565b60405290565b604051601f8201601f191681016001600160401b038111828210171561235b5761235b6122f5565b604052919050565b60006001600160401b0382111561237c5761237c6122f5565b5060051b60200190565b600082601f83011261239757600080fd5b813560206123ac6123a783612363565b612333565b82815260059290921b840181019181810190868411156123cb57600080fd5b8286015b848110156123e657803583529183019183016123cf565b509695505050505050565b803561ffff8116811461240357600080fd5b919050565b600082601f83011261241957600080fd5b813560206124296123a783612363565b82815260059290921b8401810191818101908684111561244857600080fd5b8286015b848110156123e65761245d816123f1565b835291830191830161244c565b803562ffffff8116811461240357600080fd5b600082601f83011261248e57600080fd5b8135602061249e6123a783612363565b82815260059290921b840181019181810190868411156124bd57600080fd5b8286015b848110156123e6576124d28161246a565b83529183019183016124c1565b8035600281900b811461240357600080fd5b600082601f83011261250257600080fd5b813560206125126123a783612363565b82815260059290921b8401810191818101908684111561253157600080fd5b8286015b848110156123e657612546816124df565b8352918301918301612535565b6000806000806080858703121561256957600080fd5b84356001600160401b038082111561258057600080fd5b61258c88838901612386565b955060208701359150808211156125a257600080fd5b6125ae88838901612408565b945060408701359150808211156125c457600080fd5b6125d08883890161247d565b935060608701359150808211156125e657600080fd5b506125f3878288016124f1565b91505092959194509250565b6000806000806080858703121561261557600080fd5b84356001600160401b038082111561262c57600080fd5b61263888838901612386565b955060209150818701358181111561264f57600080fd5b61265b89828a01612408565b95505060408701358181111561267057600080fd5b61267c89828a0161247d565b94505060608701358181111561269157600080fd5b8701601f810189136126a257600080fd5b80356126b06123a782612363565b81815260059190911b8201840190848101908b8311156126cf57600080fd5b8584015b83811015612707578035868111156126eb5760008081fd5b6126f98e89838901016124f1565b8452509186019186016126d3565b50989b979a50959850505050505050565b60006020828403121561272a57600080fd5b5035919050565b600082601f83011261274257600080fd5b813560206127526123a783612363565b8281526060928302850182019282820191908785111561277157600080fd5b8387015b858110156127d65781818a03121561278d5760008081fd5b61279561230b565b61279e826123f1565b81528582013560ff811681146127b45760008081fd5b8187015260406127c58382016124df565b908201528452928401928101612775565b5090979650505050505050565b600080600080600060a086880312156127fb57600080fd5b8535945061280b602087016123f1565b93506128196040870161246a565b9250612827606087016124df565b915060808601356001600160401b0381111561284257600080fd5b61284e88828901612731565b9150509295509295909350565b6001600160a01b0391909116815260200190565b6000806040838503121561288257600080fd5b823561288d81612291565b9150602083013561289d81612291565b809150509250929050565b6000806000606084860312156128bd57600080fd5b833592506128cd602085016123f1565b91506128db6040850161246a565b90509250925092565b600081518084526020808501945080840160005b8381101561291757815160020b875295820195908201906001016128f8565b509495945050505050565b6020815260006122c360208301846128e4565b60008060008060008060c0878903121561294e57600080fd5b8635955061295e602088016123f1565b945061296c6040880161246a565b935061297a606088016124df565b92506080870135915060a08701356001600160401b0381111561299c57600080fd5b6129a889828a01612731565b9150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b60208101600583106129df576129df6129b5565b91905290565b60048110610784576107846129b5565b602081016129df836129e5565b60008060008060808587031215612a1857600080fd5b84359350612a28602086016123f1565b9250612a366040860161246a565b9150612a44606086016124df565b905092959194509250565b60008060408385031215612a6257600080fd5b82356001600160401b0380821115612a7957600080fd5b612a8586838701612408565b9350602091508185013581811115612a9c57600080fd5b85019050601f81018613612aaf57600080fd5b8035612abd6123a782612363565b81815260059190911b82018301908381019088831115612adc57600080fd5b928401925b82841015612afa57833582529284019290840190612ae1565b80955050505050509250929050565b600080600060608486031215612b1e57600080fd5b505081359360208301359350604090920135919050565b600060208284031215612b4757600080fd5b81356001600160401b03811115612b5d57600080fd5b612b6984828501612386565b949350505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038316815260408101612ba4836129e5565b8260208301529392505050565b600060208284031215612bc357600080fd5b81516122c3816122ca565b6020808252600e908201526d24b73b30b634b21039b2b73232b960911b604082015260600190565b60208082526010908201526f496e636f727265637420706172616d7360801b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c5e57612c5e612c36565b5060010190565b600060208284031215612c7757600080fd5b81516122c381612291565b60006020808385031215612c9557600080fd5b82516001600160401b03811115612cab57600080fd5b8301601f81018513612cbc57600080fd5b8051612cca6123a782612363565b81815260059190911b82018301908381019087831115612ce957600080fd5b928401925b828410156110f7578351612d0181612291565b82529284019290840190612cee565b84815261ffff8416602082015262ffffff83166040820152608060608201526000610e0260808301846128e4565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b6001600160a01b03831681526040810160038310612ba457612ba46129b5565b600081612d9657612d96612c36565b50600019019056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca2646970667358221220bb1aa39d4a923551b8b1b915f1b07970bd996bd903fec095b2964a10db81859264736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101db5760003560e01c806379ba509711610105578063b9c565801161009d578063b9c5658014610475578063bad260f514610488578063c3b83f5f1461049b578063d1e567ef146104ae578063df47035d146104c1578063ebc79772146104d4578063ec7c314c146104dc578063fd72d4c6146104ff578063fd9552e71461053357600080fd5b806379ba5097146103a75780637f8a3f8c146103af57806380be6355146103c25780638223154b146103d55780638da5cb5b146103df578063914008bc146103f257806391b4ded91461042257806399a50a081461042b578063aa0cc0961461045557600080fd5b80633f7121b0116101785780633f7121b0146102b9578063481c6a75146102cc578063485cc955146102f1578063514b75631461030457806353a47bb7146103245780635c975abb1461033757806361283ea11461034457806371752fa51461038157806376d050811461039457600080fd5b80625143a5146101e05780630ae677181461020b57806313af4035146102225780631627540c1461023757806316c38b3c1461024a57806318d83b881461025d57806319aafc59146102705780631e72f8e414610283578063397f782314610296575b600080fd5b6101f36101ee36600461225f565b610546565b60405160029190910b81526020015b60405180910390f35b610214600c5481565b604051908152602001610202565b6102356102303660046122a6565b6105a6565b005b6102356102453660046122a6565b6106c2565b6102356102583660046122d8565b610715565b61023561026b366004612553565b610787565b61023561027e3660046125ff565b610933565b610235610291366004612718565b610db6565b6102a96102a43660046127e3565b610df3565b6040519015158152602001610202565b6102356102c7366004612718565b610e0c565b6005546102e49061010090046001600160a01b031681565b604051610202919061285b565b6102356102ff36600461286f565b610edb565b6103176103123660046128a8565b611012565b6040516102029190612922565b6001546102e4906001600160a01b031681565b6003546102a99060ff1681565b6102a961035236600461225f565b600960209081526000948552604080862082529385528385208152918452828420909152825290205460ff1681565b6102a961038f366004612935565b6110b2565b6102a96103a2366004612935565b6110e7565b610235611102565b600b546102e4906001600160a01b031681565b6102356103d03660046122a6565b6111da565b6101f361270e1981565b6000546102e4906001600160a01b031681565b610415610400366004612718565b600a6020526000908152604090205460ff1681565b60405161020291906129cb565b61021460025481565b61043e610439366004612935565b611258565b604080519215158352901515602083015201610202565b610468610463366004612935565b611278565b60405161020291906129f5565b610235610483366004612a02565b611288565b6102356104963660046122a6565b61135d565b6102356104a93660046122a6565b6113d6565b6102a96104bc3660046127e3565b6114a4565b6102356104cf366004612a4f565b61157f565b6102356116ef565b6102a96104ea366004612718565b60086020526000908152604090205460ff1681565b6102a961050d366004612b09565b600760209081526000938452604080852082529284528284209052825290205460ff1681565b610235610541366004612b35565b61174d565b6006602052836000526040600020602052826000526040600020602052816000526040600020818154811061057a57600080fd5b90600052602060002090600a91828204019190066003029350935050509054906101000a900460020b81565b6001600160a01b0381166105fd5760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064015b60405180910390fd5b600154600160a01b900460ff16156106695760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016105f4565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b0319909116178155604051600080516020612d9f833981519152916106b7918490612b71565b60405180910390a150565b6106ca611855565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906106b790839061285b565b61071d611855565b60035460ff16151581151514610784576003805460ff191682151590811790915560ff161561074b57426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5906020016106b7565b50565b60005433906001600160a01b03168114806107af5750600b546001600160a01b038281169116145b8061082d575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906107ec908490600290600401612b8b565b602060405180830381865afa158015610809573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082d9190612bb1565b6108495760405162461bcd60e51b81526004016105f490612bce565b8351855114801561085b575082518451145b8015610868575081518351145b6108845760405162461bcd60e51b81526004016105f490612bf6565b60005b855181101561092b5760008682815181106108a4576108a4612c20565b6020026020010151905060008683815181106108c2576108c2612c20565b6020026020010151905060008684815181106108e0576108e0612c20565b6020026020010151905060008685815181106108fe576108fe612c20565b60200260200101519050610914848484846118c9565b50505050808061092390612c4c565b915050610887565b505050505050565b60005433906001600160a01b031681148061095b5750600b546001600160a01b038281169116145b806109d9575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c39590610998908490600290600401612b8b565b602060405180830381865afa1580156109b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109d99190612bb1565b6109f55760405162461bcd60e51b81526004016105f490612bce565b83518551148015610a07575082518451145b8015610a14575081518351145b610a305760405162461bcd60e51b81526004016105f490612bf6565b6000600560019054906101000a90046001600160a01b03166001600160a01b031663c99252886040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a85573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa99190612c65565b600c5490915060005b8751811015610dac576000888281518110610acf57610acf612c20565b6020908102919091018101516000818152600890925260409091205490915060ff1615610afc5750610d9a565b6000888381518110610b1057610b10612c20565b602002602001015190506000888481518110610b2e57610b2e612c20565b602002602001015190506000888581518110610b4c57610b4c612c20565b6020026020010151905061270e1960020b81600081518110610b7057610b70612c20565b602002602001015160020b03610b9257610b8d84848460006118c9565b610d95565b61ffff83166000908152600a602052604081205460ff1690816004811115610bbc57610bbc6129b5565b03610bff5760405162461bcd60e51b815260206004820152601360248201527214995cdd5b1d081d1e5c19481b9bdd081cd95d606a1b60448201526064016105f4565b600085815260076020908152604080832061ffff88168452825280832062ffffff8716845290915290205460ff16610d9357600085815260066020908152604080832061ffff88168452825280832062ffffff8716845282529091208351610c699285019061219b565b50600085815260076020908152604080832061ffff88168452825280832062ffffff871684529091529020805460ff191660011790558615610d5557600554600c5460405163048dfadf60e51b815260006004820181905260248201929092526044810188905261ffff8716606482015262ffffff86166084820152909161010090046001600160a01b0316906391bf5be09060a401600060405180830381865afa158015610d1c573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610d449190810190612c82565b9050610d5181898b6119b0565b9750505b7fdcd786a10e38c0f82a8b25e7e6b9e0276df2edfb3fe19107add54b0c7593554b85858585604051610d8a9493929190612d10565b60405180910390a15b505b505050505b80610da481612c4c565b915050610ab2565b5050505050505050565b610dbe611855565b600c8190556040518181527f49036f75cf067392bf360ab91f66395e6731702011691226d911256085472add906020016106b7565b6000610e028686868686611b3e565b9695505050505050565b60005433906001600160a01b0316811480610e345750600b546001600160a01b038281169116145b80610eb2575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c39590610e71908490600290600401612b8b565b602060405180830381865afa158015610e8e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610eb29190612bb1565b610ece5760405162461bcd60e51b81526004016105f490612bce565b610ed782611c05565b5050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b0316600081158015610f205750825b90506000826001600160401b03166001148015610f3c5750303b155b905081158015610f4a575080155b15610f685760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610f9257845460ff60401b1916600160401b1785555b610f9b876105a6565b610fa36116ef565b60058054610100600160a81b0319166101006001600160a01b03891602179055831561100957845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b600083815260066020908152604080832061ffff86168452825280832062ffffff851684528252918290208054835181840281018401909452808452606093928301828280156110a457602002820191906000526020600020906000905b825461010083900a900460020b81526020600583018190049384019360010360039093019290920291018084116110705790505b505050505090509392505050565b6000806110c3888888888888611ca8565b905060015b8160038111156110da576110da6129b5565b1498975050505050505050565b60006110f7878787878787611d00565b979650505050505050565b6001546001600160a01b0316331461117a5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016105f4565b600054600154604051600080516020612d9f833981519152926111ab926001600160a01b0391821692911690612b71565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b6111e2611855565b6001600160a01b0381166112085760405162461bcd60e51b81526004016105f490612d3e565b60058054610100600160a81b0319166101006001600160a01b038416021790556040517f3f95458abea6f2ed78f07dd5ee75af62322c77d86a51a87aabc86aa92d34a6b1906106b790839061285b565b600080611269888888888888611d35565b90999098509650505050505050565b60006110f7878787878787611ca8565b60005433906001600160a01b03168114806112b05750600b546001600160a01b038281169116145b8061132e575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906112ed908490600290600401612b8b565b602060405180830381865afa15801561130a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061132e9190612bb1565b61134a5760405162461bcd60e51b81526004016105f490612bce565b611356858585856118c9565b5050505050565b611365611855565b6001600160a01b03811661138b5760405162461bcd60e51b81526004016105f490612d3e565b600b80546001600160a01b0319166001600160a01b0383161790556040517f306e3fdb40fb48602fc9bdf15fa992b86cf0476f1a141034292aafa47b2a9d60906106b790839061285b565b6113de611855565b6001600160a01b0381166114045760405162461bcd60e51b81526004016105f490612d3e565b600154600160a81b900460ff16156114545760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016105f4565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b179055604051600080516020612d9f833981519152916106b7918490612b71565b60008581526008602052604081205460ff16156114c357506001611576565b61ffff85166000908152600a602052604090205460ff1660038160048111156114ee576114ee6129b5565b03611565576001915060005b835181101561155f57600084828151811061151757611517612c20565b6020026020010151905060006115388a836000015160008560400151611d98565b90508061154a5760009450505061155f565b5050808061155790612c4c565b9150506114fa565b50611574565b61157187878787611d98565b91505b505b95945050505050565b611587611855565b80518251146115a85760405162461bcd60e51b81526004016105f490612bf6565b60005b82518110156116ea5760008382815181106115c8576115c8612c20565b6020026020010151905060008383815181106115e6576115e6612c20565b6020026020010151905060006004811115611603576116036129b5565b81118015611612575060048111155b6116545760405162461bcd60e51b8152602060048201526013602482015272496e76616c696420726573756c74207479706560681b60448201526064016105f4565b806004811115611666576116666129b5565b61ffff83166000908152600a60205260409020805460ff19166001836004811115611693576116936129b5565b02179055506040805161ffff84168152602081018390527fc478d6b1f79f5e21a854090b896e0158e7ba15ce7306f4976088312888df3abf910160405180910390a1505080806116e290612c4c565b9150506115ab565b505050565b60055460ff16156117385760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016105f4565b6005805460ff19166001908117909155600455565b60005433906001600160a01b03168114806117755750600b546001600160a01b038281169116145b806117f3575060055460405163e760c39560e01b81526101009091046001600160a01b03169063e760c395906117b2908490600290600401612b8b565b602060405180830381865afa1580156117cf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117f39190612bb1565b61180f5760405162461bcd60e51b81526004016105f490612bce565b60005b82518110156116ea57600083828151811061182f5761182f612c20565b6020026020010151905061184281611c05565b508061184d81612c4c565b915050611812565b6000546001600160a01b031633146118c75760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016105f4565b565b6118d584848484611d98565b1561191d5760405162461bcd60e51b815260206004820152601860248201527713585c9ad95d08185b1c9958591e4818d85b98d95b1b195960421b60448201526064016105f4565b600084815260096020908152604080832061ffff871680855290835281842062ffffff8716808652908452828520600287900b80875290855294839020805460ff191660011790558251898152938401919091529082015260608101919091527f6ec5a8dc9a5e3412ca54efb27c0872cecd2e615705463dcc2ca045e0190ede649060800160405180910390a150505050565b8160005b8451811015611b36578115611b365760008582815181106119d7576119d7612c20565b60200260200101519050806001600160a01b031663e74d3c476040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a1f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a439190612bb1565b8015611aae5750806001600160a01b0316633356a35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a88573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611aac9190612bb1565b155b15611b2357604051630f8a940b60e41b81526001600160a01b0385169063f8a940b090611ae2908490600090600401612d67565b600060405180830381600087803b158015611afc57600080fd5b505af1158015611b10573d6000803e3d6000fd5b505050508280611b1f90612d87565b9350505b5080611b2e81612c4c565b9150506119b4565b509392505050565b60008581526008602052604081205460ff1615611b5d57506001611576565b61ffff85166000908152600a602052604090205460ff166003816004811115611b8857611b886129b5565b03611bf9576001915060005b835181101561155f576000848281518110611bb157611bb1612c20565b602002602001015190506000611bd28a836000015160008560400151611e30565b905080611be45760009450505061155f565b50508080611bf190612c4c565b915050611b94565b61157187878787611e30565b60008181526008602052604090205460ff1615611c5d5760405162461bcd60e51b815260206004820152601660248201527511d85b5948185b1c9958591e4818d85b98d95b1b195960521b60448201526064016105f4565b60008181526008602052604090819020805460ff19166001179055517f730d9f4e127b4c1c5d999194f79025fe149736fbb95b0755b18ed20ddd01b4e0906106b79083815260200190565b61ffff85166000908152600a602052604081205460ff166003816004811115611cd357611cd36129b5565b14611cea57611ce58888888888611e70565b611cf4565b611cf488846120b0565b98975050505050505050565b600080611d11888888888888611ca8565b90506002816003811115611d2757611d276129b5565b1480611cf4575060016110c8565b600080611d458888888887611b3e565b91506000611d57898989898989611ca8565b90506002816003811115611d6d57611d6d6129b5565b1480611d8a57506001816003811115611d8857611d886129b5565b145b915050965096945050505050565b60008481526008602052604081205460ff1680611deb5750600085815260096020908152604080832061ffff88168452825280832062ffffff871684528252808320600286900b845290915290205460ff165b806115765750600085815260096020908152604080832061ffff88168452825280832062ffffff87168452825280832083805290915290205460ff1695945050505050565b600084815260076020908152604080832061ffff87168452825280832062ffffff8616845290915281205460ff1680611576575061157685858585611d98565b6000611e7e86868686611d98565b15611e8b57506001611576565b600086815260076020908152604080832061ffff89168452825280832062ffffff8816845290915290205460ff16156120a457600086815260066020908152604080832061ffff89168452825280832062ffffff88168452825280832080548251818502810185019093528083529192909190830182828015611f5057602002820191906000526020600020906000905b825461010083900a900460020b8152602060058301819004938401936001036003909301929092029101808411611f1c5790505b50505061ffff89166000908152600a602052604081205493945060ff909316929150505b8251811015612098576000838281518110611f9157611f91612c20565b602002602001015160020b905060026004811115611fb157611fb16129b5565b836004811115611fc357611fc36129b5565b1480611fe057506004836004811115611fde57611fde6129b5565b145b15612071578660020b8103611ffc576001945050505050611576565b60006004846004811115612012576120126129b5565b1461202f578760020b8213612028576001612043565b6000612043565b8760020b8212612040576001612043565b60005b905086816001811115612058576120586129b5565b0361206b57600295505050505050611576565b50612085565b858103612085576002945050505050611576565b508061209081612c4c565b915050611f74565b50600392505050611576565b50600095945050505050565b60008080805b84518110156121745760008582815181106120d3576120d3612c20565b6020026020010151905060006120fc88836000015160008560400151866020015160ff16611e70565b90506003816003811115612112576121126129b5565b0361212557600395505050505050612195565b8461214257600181600381111561213e5761213e6129b5565b1494505b8361215f57600081600381111561215b5761215b6129b5565b1493505b5050808061216c90612c4c565b9150506120b6565b508161218d5780612186576002612190565b6000612190565b60015b925050505b92915050565b82805482825590600052602060002090600901600a9004810192821561223a5791602002820160005b8382111561220957835183826101000a81548162ffffff021916908360020b62ffffff16021790555092602001926003016020816002010492830192600103026121c4565b80156122385782816101000a81549062ffffff0219169055600301602081600201049283019260010302612209565b505b5061224692915061224a565b5090565b5b80821115612246576000815560010161224b565b6000806000806080858703121561227557600080fd5b5050823594602084013594506040840135936060013592509050565b6001600160a01b038116811461078457600080fd5b6000602082840312156122b857600080fd5b81356122c381612291565b9392505050565b801515811461078457600080fd5b6000602082840312156122ea57600080fd5b81356122c3816122ca565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b038111828210171561232d5761232d6122f5565b60405290565b604051601f8201601f191681016001600160401b038111828210171561235b5761235b6122f5565b604052919050565b60006001600160401b0382111561237c5761237c6122f5565b5060051b60200190565b600082601f83011261239757600080fd5b813560206123ac6123a783612363565b612333565b82815260059290921b840181019181810190868411156123cb57600080fd5b8286015b848110156123e657803583529183019183016123cf565b509695505050505050565b803561ffff8116811461240357600080fd5b919050565b600082601f83011261241957600080fd5b813560206124296123a783612363565b82815260059290921b8401810191818101908684111561244857600080fd5b8286015b848110156123e65761245d816123f1565b835291830191830161244c565b803562ffffff8116811461240357600080fd5b600082601f83011261248e57600080fd5b8135602061249e6123a783612363565b82815260059290921b840181019181810190868411156124bd57600080fd5b8286015b848110156123e6576124d28161246a565b83529183019183016124c1565b8035600281900b811461240357600080fd5b600082601f83011261250257600080fd5b813560206125126123a783612363565b82815260059290921b8401810191818101908684111561253157600080fd5b8286015b848110156123e657612546816124df565b8352918301918301612535565b6000806000806080858703121561256957600080fd5b84356001600160401b038082111561258057600080fd5b61258c88838901612386565b955060208701359150808211156125a257600080fd5b6125ae88838901612408565b945060408701359150808211156125c457600080fd5b6125d08883890161247d565b935060608701359150808211156125e657600080fd5b506125f3878288016124f1565b91505092959194509250565b6000806000806080858703121561261557600080fd5b84356001600160401b038082111561262c57600080fd5b61263888838901612386565b955060209150818701358181111561264f57600080fd5b61265b89828a01612408565b95505060408701358181111561267057600080fd5b61267c89828a0161247d565b94505060608701358181111561269157600080fd5b8701601f810189136126a257600080fd5b80356126b06123a782612363565b81815260059190911b8201840190848101908b8311156126cf57600080fd5b8584015b83811015612707578035868111156126eb5760008081fd5b6126f98e89838901016124f1565b8452509186019186016126d3565b50989b979a50959850505050505050565b60006020828403121561272a57600080fd5b5035919050565b600082601f83011261274257600080fd5b813560206127526123a783612363565b8281526060928302850182019282820191908785111561277157600080fd5b8387015b858110156127d65781818a03121561278d5760008081fd5b61279561230b565b61279e826123f1565b81528582013560ff811681146127b45760008081fd5b8187015260406127c58382016124df565b908201528452928401928101612775565b5090979650505050505050565b600080600080600060a086880312156127fb57600080fd5b8535945061280b602087016123f1565b93506128196040870161246a565b9250612827606087016124df565b915060808601356001600160401b0381111561284257600080fd5b61284e88828901612731565b9150509295509295909350565b6001600160a01b0391909116815260200190565b6000806040838503121561288257600080fd5b823561288d81612291565b9150602083013561289d81612291565b809150509250929050565b6000806000606084860312156128bd57600080fd5b833592506128cd602085016123f1565b91506128db6040850161246a565b90509250925092565b600081518084526020808501945080840160005b8381101561291757815160020b875295820195908201906001016128f8565b509495945050505050565b6020815260006122c360208301846128e4565b60008060008060008060c0878903121561294e57600080fd5b8635955061295e602088016123f1565b945061296c6040880161246a565b935061297a606088016124df565b92506080870135915060a08701356001600160401b0381111561299c57600080fd5b6129a889828a01612731565b9150509295509295509295565b634e487b7160e01b600052602160045260246000fd5b60208101600583106129df576129df6129b5565b91905290565b60048110610784576107846129b5565b602081016129df836129e5565b60008060008060808587031215612a1857600080fd5b84359350612a28602086016123f1565b9250612a366040860161246a565b9150612a44606086016124df565b905092959194509250565b60008060408385031215612a6257600080fd5b82356001600160401b0380821115612a7957600080fd5b612a8586838701612408565b9350602091508185013581811115612a9c57600080fd5b85019050601f81018613612aaf57600080fd5b8035612abd6123a782612363565b81815260059190911b82018301908381019088831115612adc57600080fd5b928401925b82841015612afa57833582529284019290840190612ae1565b80955050505050509250929050565b600080600060608486031215612b1e57600080fd5b505081359360208301359350604090920135919050565b600060208284031215612b4757600080fd5b81356001600160401b03811115612b5d57600080fd5b612b6984828501612386565b949350505050565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b038316815260408101612ba4836129e5565b8260208301529392505050565b600060208284031215612bc357600080fd5b81516122c3816122ca565b6020808252600e908201526d24b73b30b634b21039b2b73232b960911b604082015260600190565b60208082526010908201526f496e636f727265637420706172616d7360801b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201612c5e57612c5e612c36565b5060010190565b600060208284031215612c7757600080fd5b81516122c381612291565b60006020808385031215612c9557600080fd5b82516001600160401b03811115612cab57600080fd5b8301601f81018513612cbc57600080fd5b8051612cca6123a782612363565b81815260059190911b82018301908381019087831115612ce957600080fd5b928401925b828410156110f7578351612d0181612291565b82529284019290840190612cee565b84815261ffff8416602082015262ffffff83166040820152608060608201526000610e0260808301846128e4565b6020808252600f908201526e496e76616c6964206164647265737360881b604082015260600190565b6001600160a01b03831681526040810160038310612ba457612ba46129b5565b600081612d9657612d96612c36565b50600019019056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca2646970667358221220bb1aa39d4a923551b8b1b915f1b07970bd996bd903fec095b2964a10db81859264736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.