Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Initialize | 41790019 | 10 hrs ago | IN | 0 ETH | 0.00000054 |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SportsAMMV2
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/proxy/Clones.sol";
// internal
import "../../utils/proxy/ProxyReentrancyGuard.sol";
import "../../utils/proxy/ProxyOwned.sol";
import "../../utils/proxy/ProxyPausable.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 "@thales-dao/contracts/contracts/interfaces/IPriceFeed.sol";
import "./Ticket.sol";
import "../../interfaces/ISportsAMMV2.sol";
import "../../interfaces/ISportsAMMV2Manager.sol";
import "../../interfaces/ISportsAMMV2RiskManager.sol";
import "../../interfaces/ISportsAMMV2ResultManager.sol";
import "../../interfaces/ISportsAMMV2LiquidityPool.sol";
import "../../interfaces/IWeth.sol";
import "../../interfaces/IProxyBetting.sol";
/// @title Sports AMM V2 contract
/// @author vladan
contract SportsAMMV2 is Initializable, ProxyOwned, ProxyPausable, ProxyReentrancyGuard {
/* ========== LIBRARIES ========== */
using SafeERC20 for IERC20;
/* ========== CONST VARIABLES ========== */
uint private constant ONE = 1e18;
uint private constant MAX_APPROVAL = type(uint256).max;
uint8 private constant NON_SYSTEM_BET = 0;
/* ========== ERRORS ========== */
error SBDOutOfRange();
error IllegalInputAmounts();
error OnlyOwner();
error OnlyDedicatedProcessor();
error UndefinedRecipient();
error UnknownTicket();
error UnsupportedSender();
error OfframpOnlyDefaultCollateralAllowed();
error InsuffETHSent();
error ZeroPriceForCollateral();
error MultiCollateralDisabled();
error InsuffReceived();
error InvalidLength();
error InvalidSender();
error ZeroAmount();
error InvalidPosition();
error MultiCollatDisabled();
error OnlyTicketOwner();
/* ========== STRUCT VARIABLES ========== */
struct TradeDataInternal {
uint _buyInAmount;
uint _expectedPayout;
uint _additionalSlippage;
address _recipient;
bool _isLive;
address _collateral;
address _collateralPool;
uint _collateralPriceInUSD;
bool _isSGP;
}
/* ========== STATE VARIABLES ========== */
// merkle tree root per game
mapping(bytes32 => bytes32) public rootPerGame;
// the default token used for payment
IERC20 public defaultCollateral;
// Liquidity pool instance for the given collateral
mapping(address => address) public liquidityPoolForCollateral;
// decimals of the default collateral
uint private defaultCollateralDecimals;
// manager address
ISportsAMMV2Manager public manager;
// risk manager address
ISportsAMMV2RiskManager public riskManager;
// result manager address
ISportsAMMV2ResultManager public resultManager;
// referrals address
IReferrals public referrals;
// ticket mastercopy address
address public ticketMastercopy;
// safe box address
address public safeBox;
// safe box fee paid on each trade
uint public safeBoxFee;
// multi-collateral on/off ramp address
IMultiCollateralOnOffRamp public multiCollateralOnOffRamp;
// is multi-collateral enabled
bool private multicollateralEnabled;
// staking thales address
IStakingThales private stakingThales;
// CL client that processes live requests
address public liveTradingProcessor;
// the contract that processes all free bets
address public freeBetsHolder;
// support bonus payouts for some collaterals (e.g. THALES)
mapping(address => uint) public addedPayoutPercentagePerCollateral;
// support different SB per collateral, namely THALES as a collateral will be directly burned
mapping(address => address) public safeBoxPerCollateral;
// the contract that processes betting with StakedTHALES
address public stakingThalesBettingProxy;
struct TradeDataQuoteInternal {
uint _buyInAmount;
bool _shouldCheckRisks;
uint _buyInAmountInDefaultCollateral;
address _collateral;
bool _isLive;
bool _isSGP;
uint _approvedQuote;
}
struct TradeProcessingParams {
uint _totalQuote;
uint _payout;
uint _fees;
uint _addedPayoutPercentage;
uint _payoutWithFees;
}
// CL client that processes SGP requests
address public sgpTradingProcessor;
struct TradeTypeData {
uint8 _systemBetDenominator;
bool _isSGP;
bool _isLive;
}
// declare that it can receive eth
receive() external payable {}
/* ========== CONSTRUCTOR ========== */
/// @notice initialize the storage in the proxy contract with the parameters
/// @param _owner owner for using the onlyOwner functions
function initialize(address _owner) public initializer {
setOwner(_owner);
initNonReentrant();
}
/* ========== EXTERNAL READ FUNCTIONS ========== */
/// @notice get roots for the list of games
/// @param _games to return roots for
/// @notice get roots for the list of games
/// @param _games to return roots for
function getRootsPerGames(bytes32[] calldata _games) external view returns (bytes32[] memory _roots) {
uint len = _games.length;
_roots = new bytes32[](len);
unchecked {
for (uint i; i < len; ++i) {
_roots[i] = rootPerGame[_games[i]];
}
}
}
/// @notice gets trade quote
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _collateral different collateral used for payment
/// @param _isLive whether this is a live bet
/// @return totalQuote total ticket quote
/// @return payout expected payout
/// @return fees ticket fees
/// @return amountsToBuy amounts per market
/// @return buyInAmountInDefaultCollateral buy-in amount in default collateral
/// @return riskStatus risk status
function tradeQuote(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
address _collateral,
bool _isLive
)
external
view
returns (
uint totalQuote,
uint payout,
uint fees,
uint[] memory amountsToBuy,
uint buyInAmountInDefaultCollateral,
ISportsAMMV2RiskManager.RiskStatus riskStatus
)
{
(totalQuote, payout, fees, amountsToBuy, buyInAmountInDefaultCollateral, riskStatus) = _tradeQuoteCommon(
_tradeData,
_buyInAmount,
_collateral,
_isLive,
NON_SYSTEM_BET
);
}
/// @notice gets trade quote
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _collateral different collateral used for payment
/// @param _isLive whether this is a live bet
/// @param _systemBetDenominator the denominator for system bets
/// @return totalQuote total ticket quote
/// @return payout expected payout
/// @return fees ticket fees
/// @return amountsToBuy amounts per market
/// @return buyInAmountInDefaultCollateral buy-in amount in default collateral
/// @return riskStatus risk status
function tradeQuoteSystem(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
address _collateral,
bool _isLive,
uint8 _systemBetDenominator
)
external
view
returns (
uint totalQuote,
uint payout,
uint fees,
uint[] memory amountsToBuy,
uint buyInAmountInDefaultCollateral,
ISportsAMMV2RiskManager.RiskStatus riskStatus
)
{
(totalQuote, payout, fees, amountsToBuy, buyInAmountInDefaultCollateral, riskStatus) = _tradeQuoteCommon(
_tradeData,
_buyInAmount,
_collateral,
_isLive,
_systemBetDenominator
);
}
function _tradeQuoteCommon(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
address _collateral,
bool _isLive,
uint8 _systemBetDenominator
)
internal
view
returns (
uint totalQuote,
uint payout,
uint fees,
uint[] memory amountsToBuy,
uint buyInAmountInDefaultCollateral,
ISportsAMMV2RiskManager.RiskStatus riskStatus
)
{
uint useAmount = _buyInAmount;
buyInAmountInDefaultCollateral = _buyInAmount;
if (_collateral != address(0) && _collateral != address(defaultCollateral)) {
address liqPoolToUse = liquidityPoolForCollateral[_collateral];
if (liqPoolToUse == address(0)) {
buyInAmountInDefaultCollateral = multiCollateralOnOffRamp.getMinimumReceived(_collateral, _buyInAmount);
useAmount = buyInAmountInDefaultCollateral;
} else {
buyInAmountInDefaultCollateral = _transformToUSD(
_buyInAmount,
ISportsAMMV2LiquidityPool(liqPoolToUse).getCollateralPrice(),
ISportsAMMV2Manager(_collateral).decimals()
);
}
}
if (useAmount == 0) revert ZeroAmount();
(totalQuote, payout, fees, amountsToBuy, riskStatus) = _tradeQuote(
_tradeData,
TradeDataQuoteInternal(useAmount, true, buyInAmountInDefaultCollateral, _collateral, _isLive, false, 0),
_systemBetDenominator
);
}
/* ========== EXTERNAL WRITE FUNCTIONS ========== */
/// @notice make a trade and create a ticket
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _expectedQuote expected payout got from quote method
/// @param _additionalSlippage slippage tolerance
/// @param _referrer referrer to get referral fee
/// @param _collateral different collateral used for payment
/// @param _isEth pay with ETH
/// @return _createdTicket the address of the created ticket
function trade(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
uint _additionalSlippage,
address _referrer,
address _collateral,
bool _isEth
) external payable nonReentrant notPaused returns (address _createdTicket) {
_createdTicket = _tradeInternal(
_tradeData,
TradeTypeData(NON_SYSTEM_BET, false, false),
_buyInAmount,
_expectedQuote,
_additionalSlippage,
_referrer,
_collateral,
_isEth,
msg.sender
);
}
/// @notice make a SGP trade and create a ticket
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _approvedQuote quote approved by sgpTradingProcessor
/// @param _referrer referrer to get referral fee
/// @param _collateral different collateral used for payment
/// @return _createdTicket the address of the created ticket
function tradeSGP(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _approvedQuote,
address _recipient,
address _referrer,
address _collateral
) external payable nonReentrant notPaused onlyValidRecipient(_recipient) returns (address _createdTicket) {
if (msg.sender != sgpTradingProcessor) revert OnlyDedicatedProcessor();
_createdTicket = _tradeInternal(
_tradeData,
TradeTypeData(NON_SYSTEM_BET, true, false),
_buyInAmount,
_approvedQuote,
0, //no additional slippage as quote is assigned by CL node
_referrer,
_collateral,
false,
_recipient
);
}
/// @notice make a trade and create a ticket
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _expectedQuote expected payout got from quote method
/// @param _additionalSlippage slippage tolerance
/// @param _referrer referrer to get referral fee
/// @param _collateral different collateral used for payment
/// @param _isEth pay with ETH
/// @param _systemBetDenominator minimum number of winning bets for a system bet
/// @return _createdTicket the address of the created ticket
function tradeSystemBet(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
uint _additionalSlippage,
address _referrer,
address _collateral,
bool _isEth,
uint8 _systemBetDenominator
) external payable nonReentrant notPaused returns (address _createdTicket) {
if (_systemBetDenominator <= 1 || _systemBetDenominator >= _tradeData.length) revert SBDOutOfRange();
_createdTicket = _tradeInternal(
_tradeData,
TradeTypeData(_systemBetDenominator, false, false),
_buyInAmount,
_expectedQuote,
_additionalSlippage,
_referrer,
_collateral,
_isEth,
msg.sender
);
}
/// @notice make a live trade and create a ticket
/// @param _tradeData trade data with all market info needed for ticket
/// @param _buyInAmount ticket buy-in amount
/// @param _expectedQuote expected payout got from LiveTradingProcessor method
/// @param _recipient different recipient of the ticket
/// @param _referrer referrer to get referral fee
/// @param _collateral different collateral used for payment
/// @return _createdTicket the address of the created ticket
function tradeLive(
ISportsAMMV2.TradeData[] calldata _tradeData,
uint _buyInAmount,
uint _expectedQuote,
address _recipient,
address _referrer,
address _collateral
) external nonReentrant notPaused onlyValidRecipient(_recipient) returns (address _createdTicket) {
if (msg.sender != liveTradingProcessor) revert OnlyDedicatedProcessor();
_createdTicket = _tradeInternal(
_tradeData,
TradeTypeData(NON_SYSTEM_BET, false, true),
_buyInAmount,
_expectedQuote,
0, //no additional slippage as quote is assigned by CL node
_referrer,
_collateral,
false,
_recipient
);
}
function _tradeInternal(
ISportsAMMV2.TradeData[] memory _tradeData,
TradeTypeData memory _tradeTypeData,
uint _buyInAmount,
uint _expectedQuote,
uint _additionalSlippage,
address _referrer,
address _collateral,
bool _isEth,
address _recipient
) internal returns (address _createdTicket) {
if (_expectedQuote == 0 || _buyInAmount == 0) revert IllegalInputAmounts();
_setReferrer(_referrer, _recipient);
address useLPpool;
uint collateralPriceInUSD;
(useLPpool, collateralPriceInUSD, _buyInAmount, _collateral) = _handleCollateral(
_buyInAmount,
_collateral,
_recipient,
_isEth
);
_createdTicket = _trade(
_tradeData,
TradeDataInternal(
_buyInAmount,
_divWithDecimals(_buyInAmount, _expectedQuote), // quote to expected payout
_additionalSlippage,
_recipient,
_tradeTypeData._isLive,
_collateral,
useLPpool,
collateralPriceInUSD,
_tradeTypeData._isSGP
),
_tradeTypeData._systemBetDenominator
);
}
/**
* @notice Resolves a ticket by exercising, canceling, or marking it as lost.
* @dev
* - Anyone can call this to exercise a ticket.
* - Only addresses whitelisted as MARKET_RESOLVING can cancel or mark a ticket as lost.
* - Uses internal _exerciseTicket logic with the appropriate flags.
* @param _ticket The address of the ticket to be resolved.
* @param action The type of resolution action to perform:
* - TicketAction.Exercise: Exercise a resolved ticket (no whitelist required)
* - TicketAction.Cancel: Cancel the ticket (whitelist required)
* - TicketAction.MarkLost: Mark the ticket as lost (whitelist required)
*/
function handleTicketResolving(
address _ticket,
ISportsAMMV2.TicketAction action
) external nonReentrant notPaused onlyKnownTickets(_ticket) {
if (action != ISportsAMMV2.TicketAction.Exercise) {
if (!manager.isWhitelistedAddress(msg.sender, ISportsAMMV2Manager.Role.MARKET_RESOLVING)) {
revert UnsupportedSender();
}
}
if (action == ISportsAMMV2.TicketAction.Cancel) {
_exerciseTicket(_ticket, address(0), true, false);
} else if (action == ISportsAMMV2.TicketAction.MarkLost) {
_exerciseTicket(_ticket, address(0), false, true);
} else {
_exerciseTicket(_ticket, address(0), false, false);
}
}
/// @notice exercise specific ticket to an off ramp collateral
/// @param _ticket ticket address
/// @param _exerciseCollateral collateral address to off ramp to
function exerciseTicketOffRamp(
address _ticket,
address _exerciseCollateral
) external nonReentrant notPaused onlyKnownTickets(_ticket) {
if (msg.sender != Ticket(_ticket).ticketOwner()) revert OnlyTicketOwner();
_exerciseTicket(_ticket, _exerciseCollateral, false, false);
}
/// @notice Withdraws collateral from a specified Ticket contract and sends it to the target address
/// @param ticketAddress The address of the Ticket contract
/// @param recipient The address to receive the withdrawn collateral
function withdrawCollateralFromTicket(address ticketAddress, address recipient) external onlyOwner {
// Call withdrawCollateral on the specified Ticket contract
Ticket(ticketAddress).withdrawCollateral(recipient);
}
/// @notice expire provided tickets
/// @param _tickets array of tickets to be expired
function expireTickets(address[] calldata _tickets) external onlyOwner {
unchecked {
for (uint i; i < _tickets.length; ++i) {
address ticketAddress = _tickets[i];
address ticketOwner = Ticket(ticketAddress).ticketOwner();
if (ticketOwner != freeBetsHolder && ticketOwner != stakingThalesBettingProxy) {
Ticket(ticketAddress).expire(msg.sender);
manager.expireKnownTicket(ticketAddress, ticketOwner);
}
}
}
}
/* ========== INTERNAL FUNCTIONS ========== */
function _tradeQuote(
ISportsAMMV2.TradeData[] memory _tradeData,
TradeDataQuoteInternal memory _tradeDataQuoteInternal,
uint8 _systemBetDenominator
)
internal
view
returns (
uint totalQuote,
uint payout,
uint fees,
uint[] memory amountsToBuy,
ISportsAMMV2RiskManager.RiskStatus riskStatus
)
{
uint numOfMarkets = _tradeData.length;
amountsToBuy = new uint[](numOfMarkets);
uint maxSupportedOdds = riskManager.maxSupportedOdds();
bool isSystemBet = _systemBetDenominator > 1;
uint addedPayoutPercentage = addedPayoutPercentagePerCollateral[_tradeDataQuoteInternal._collateral];
for (uint i; i < numOfMarkets; ++i) {
ISportsAMMV2.TradeData memory marketTradeData = _tradeData[i];
riskManager.verifyMerkleTree(marketTradeData, rootPerGame[marketTradeData.gameId]);
if (marketTradeData.odds.length <= marketTradeData.position) revert InvalidPosition();
uint marketOdds = marketTradeData.odds[marketTradeData.position];
marketOdds =
(marketOdds * ONE) /
((ONE + addedPayoutPercentage) - _mulWithDecimals(addedPayoutPercentage, marketOdds));
amountsToBuy[i] =
_divWithDecimals(_tradeDataQuoteInternal._buyInAmount, marketOdds) -
_tradeDataQuoteInternal._buyInAmount;
if (isSystemBet) {
amountsToBuy[i] = (amountsToBuy[i] * ONE * _systemBetDenominator) / (numOfMarkets * ONE);
}
// amounts to buy should be decreased by buyinamount
totalQuote = totalQuote == 0 ? marketOdds : _mulWithDecimals(totalQuote, marketOdds);
}
if (totalQuote != 0) {
if (isSystemBet) {
(payout, totalQuote) = riskManager.getMaxSystemBetPayout(
_tradeData,
_systemBetDenominator,
_tradeDataQuoteInternal._buyInAmount,
addedPayoutPercentage
);
} else {
if (_tradeDataQuoteInternal._isSGP) {
totalQuote = _tradeDataQuoteInternal._approvedQuote;
totalQuote =
(totalQuote * ONE) /
((ONE + addedPayoutPercentage) - _mulWithDecimals(addedPayoutPercentage, totalQuote));
}
payout = _divWithDecimals(_tradeDataQuoteInternal._buyInAmount, totalQuote);
}
if (totalQuote < maxSupportedOdds) {
totalQuote = maxSupportedOdds;
payout = _divWithDecimals(_tradeDataQuoteInternal._buyInAmount, totalQuote);
}
fees = _getFees(_tradeDataQuoteInternal._buyInAmount);
if (_tradeDataQuoteInternal._shouldCheckRisks) {
bool[] memory isMarketOutOfLiquidity;
(riskStatus, isMarketOutOfLiquidity) = riskManager.checkRisks(
_tradeData,
_tradeDataQuoteInternal._buyInAmountInDefaultCollateral,
_tradeDataQuoteInternal._isLive,
_systemBetDenominator
);
unchecked {
for (uint i; i < numOfMarkets; ++i) {
if (isMarketOutOfLiquidity[i]) amountsToBuy[i] = 0;
}
}
if (riskStatus != ISportsAMMV2RiskManager.RiskStatus.NoRisk) {
totalQuote = payout = 0;
}
}
}
}
function _handleCollateral(
uint _buyInAmount,
address _collateral,
address _fromAddress,
bool _isEth
) internal returns (address lqPool, uint collateralPrice, uint buyInAmount, address collateralAfterOnramp) {
buyInAmount = _buyInAmount;
// Default collateral path (including address(0) case)
if (_collateral == address(0) || _collateral == address(defaultCollateral)) {
collateralAfterOnramp = address(defaultCollateral);
defaultCollateral.safeTransferFrom(_fromAddress, address(this), _buyInAmount);
}
// Non-default collateral path
else {
collateralAfterOnramp = _collateral;
// Handle ETH or ERC20 transfer
if (_isEth) {
if (_collateral != multiCollateralOnOffRamp.WETH9() || msg.value < _buyInAmount) revert InsuffETHSent();
IWeth(_collateral).deposit{value: msg.value}();
} else {
IERC20(_collateral).safeTransferFrom(_fromAddress, address(this), _buyInAmount);
}
// Check if direct liquidity pool exists for collateral
lqPool = liquidityPoolForCollateral[_collateral];
if (lqPool != address(0)) {
collateralPrice = ISportsAMMV2LiquidityPool(lqPool).getCollateralPrice();
if (collateralPrice == 0) revert ZeroPriceForCollateral();
}
// Handle onramping if no direct pool
else {
if (address(multiCollateralOnOffRamp) == address(0)) revert MultiCollatDisabled();
IERC20(_collateral).approve(address(multiCollateralOnOffRamp), _buyInAmount);
buyInAmount = multiCollateralOnOffRamp.onramp(_collateral, _buyInAmount);
if (buyInAmount < multiCollateralOnOffRamp.getMinimumReceived(_collateral, _buyInAmount))
revert InsuffReceived();
collateralAfterOnramp = address(defaultCollateral);
}
}
// Get final liquidity pool
lqPool = liquidityPoolForCollateral[collateralAfterOnramp];
}
function _trade(
ISportsAMMV2.TradeData[] memory _tradeData,
TradeDataInternal memory _tradeDataInternal,
uint8 _systemBetDenominator
) internal returns (address) {
TradeProcessingParams memory processingParams;
processingParams._addedPayoutPercentage = addedPayoutPercentagePerCollateral[_tradeDataInternal._collateral];
if (!_tradeDataInternal._isLive) {
(processingParams._totalQuote, processingParams._payout, processingParams._fees, , ) = _tradeQuote(
_tradeData,
TradeDataQuoteInternal(
_tradeDataInternal._buyInAmount,
false,
0,
_tradeDataInternal._collateral,
_tradeDataInternal._isLive,
_tradeDataInternal._isSGP,
_divWithDecimals(_tradeDataInternal._buyInAmount, _tradeDataInternal._expectedPayout)
),
_systemBetDenominator
);
} else {
uint numOfMarkets = _tradeData.length;
uint added = processingParams._addedPayoutPercentage;
// Chainlink returns this as the guardrail base quote (NO bonus)
uint approvedBaseQuote = _tradeDataInternal._expectedPayout == 0
? 0
: _divWithDecimals(_tradeDataInternal._buyInAmount, _tradeDataInternal._expectedPayout);
// NOTE: despite the name, this is "min implied probability" (i.e. max supported decimal odds)
uint minImplied = riskManager.maxSupportedOdds();
if (numOfMarkets == 1) {
uint legOdd = _tradeData[0].odds[_tradeData[0].position];
uint boosted = _applyBonusToOdd(legOdd, added);
// ===== CLAMP (same behavior as prematch) =====
if (boosted < minImplied) boosted = minImplied;
processingParams._totalQuote = boosted;
} else {
uint baseQuote = 0;
uint boostedQuote = 0;
for (uint i = 0; i < numOfMarkets; ++i) {
ISportsAMMV2.TradeData memory td = _tradeData[i];
if (td.odds.length <= td.position) revert InvalidPosition();
uint legOdd = td.odds[td.position];
require(legOdd > 0, "Zero leg odd");
baseQuote = (baseQuote == 0) ? legOdd : _mulWithDecimals(baseQuote, legOdd);
uint boostedLeg = _applyBonusToOdd(legOdd, added);
boostedQuote = (boostedQuote == 0) ? boostedLeg : _mulWithDecimals(boostedQuote, boostedLeg);
}
// ===== Guardrail (clamp-aware) =====
uint relTol = 1e12; // 1 ppm
require(approvedBaseQuote > 0, "Bad approved quote");
// If the *boosted* parlay implies odds above max (boostedQuote < minImplied),
// then the node will clamp the approved quote to minImplied, and we should
// validate against the clamp instead of baseQuote.
if (boostedQuote < minImplied) {
uint diffClamp = _absDiff(minImplied, approvedBaseQuote);
require((diffClamp * ONE) / approvedBaseQuote <= relTol, "Approved quote mismatch");
} else {
uint diffBase = _absDiff(baseQuote, approvedBaseQuote);
require((diffBase * ONE) / approvedBaseQuote <= relTol, "Approved quote mismatch");
}
processingParams._totalQuote = boostedQuote;
// Clamp final boosted quote (same behavior as prematch)
if (processingParams._totalQuote < minImplied) processingParams._totalQuote = minImplied;
}
processingParams._payout = _divWithDecimals(_tradeDataInternal._buyInAmount, processingParams._totalQuote);
processingParams._fees = _getFees(_tradeDataInternal._buyInAmount);
// Align expected payout with final (bonus-inclusive) payout for checkLimits
_tradeDataInternal._expectedPayout = processingParams._payout;
}
processingParams._payoutWithFees = processingParams._payout + processingParams._fees;
checkRisksLimits(
_tradeData,
processingParams._totalQuote,
processingParams._payout,
_tradeDataInternal,
_systemBetDenominator
);
// Clone a ticket
Ticket.MarketData[] memory markets = _getTicketMarkets(_tradeData, processingParams._addedPayoutPercentage);
Ticket ticket = Ticket(Clones.clone(ticketMastercopy));
// 1) Initialize the ticket (unchanged)
ticket.initialize(
Ticket.TicketInit(
markets,
_tradeDataInternal._buyInAmount,
processingParams._fees,
processingParams._totalQuote,
address(this),
_tradeDataInternal._recipient,
IERC20(_tradeDataInternal._collateral),
(block.timestamp + riskManager.expiryDuration()),
_tradeDataInternal._isLive,
_systemBetDenominator,
_tradeDataInternal._isSGP
)
);
// 2) Track ticket on the manager (unchanged)
manager.addNewKnownTicket(_tradeData, address(ticket), _tradeDataInternal._recipient);
// 3) Commit trade to LP (unchanged)
ISportsAMMV2LiquidityPool(_tradeDataInternal._collateralPool).commitTrade(
address(ticket),
processingParams._payoutWithFees - _tradeDataInternal._buyInAmount
);
// 4) Fund the ticket with the full expected amount (unchanged)
IERC20(_tradeDataInternal._collateral).safeTransfer(address(ticket), processingParams._payoutWithFees);
// 5) Lock the accounting: tell the Ticket what the authoritative funded amount is
ticket.setExpectedFinalPayout(processingParams._payoutWithFees);
emit NewTicket(
markets,
address(ticket),
_tradeDataInternal._buyInAmount,
processingParams._payout,
_tradeDataInternal._isLive
);
emit TicketCreated(
address(ticket),
_tradeDataInternal._recipient,
_tradeDataInternal._buyInAmount,
processingParams._fees,
processingParams._payout,
processingParams._totalQuote,
_tradeDataInternal._collateral
);
return address(ticket);
}
// Checks risk and updates Staking Volume
function checkRisksLimits(
ISportsAMMV2.TradeData[] memory _tradeData,
uint _totalQuote,
uint _payout,
TradeDataInternal memory _tradeDataInternal,
uint8 _systemBetDenominator
) internal {
uint _buyInAmount = _tradeDataInternal._buyInAmount;
uint _collateralPriceInUSD = _tradeDataInternal._collateralPriceInUSD;
uint _expectedPayout = _tradeDataInternal._expectedPayout;
if (_collateralPriceInUSD > 0) {
uint collateralDecimals = ISportsAMMV2Manager(_tradeDataInternal._collateral).decimals();
_buyInAmount = _transformToUSD(_buyInAmount, _collateralPriceInUSD, collateralDecimals);
_payout = _transformToUSD(_payout, _collateralPriceInUSD, collateralDecimals);
_expectedPayout = _transformToUSD(_expectedPayout, _collateralPriceInUSD, collateralDecimals);
}
riskManager.checkAndUpdateRisks(
_tradeData,
_buyInAmount,
_payout,
_tradeDataInternal._isLive,
_systemBetDenominator,
_tradeDataInternal._isSGP
);
riskManager.checkLimits(
_buyInAmount,
_totalQuote,
_payout,
_expectedPayout,
_tradeDataInternal._additionalSlippage,
_tradeData.length
);
}
function _getTicketMarkets(
ISportsAMMV2.TradeData[] memory _tradeData,
uint _addedPayoutPercentage
) internal pure returns (Ticket.MarketData[] memory markets) {
uint len = _tradeData.length;
markets = new Ticket.MarketData[](len);
for (uint i; i < len; ++i) {
ISportsAMMV2.TradeData memory marketTradeData = _tradeData[i];
uint odds = marketTradeData.odds[marketTradeData.position];
markets[i] = Ticket.MarketData(
marketTradeData.gameId,
marketTradeData.sportId,
marketTradeData.typeId,
marketTradeData.maturity,
marketTradeData.status,
marketTradeData.line,
marketTradeData.playerId,
marketTradeData.position,
(odds * ONE) / ((ONE + _addedPayoutPercentage) - _mulWithDecimals(_addedPayoutPercentage, odds)),
marketTradeData.combinedPositions[marketTradeData.position]
);
}
}
function _handleFees(uint _buyInAmount, address _tickerOwner, IERC20 _collateral) internal returns (uint fees) {
uint referrerShare;
address referrer = referrals.sportReferrals(_tickerOwner);
uint ammBalance = _collateral.balanceOf(address(this));
if (referrer != address(0) && _tickerOwner != address(freeBetsHolder)) {
uint referrerFeeByTier = referrals.getReferrerFee(referrer);
if (referrerFeeByTier > 0) {
referrerShare = _mulWithDecimals(_buyInAmount, referrerFeeByTier);
if (ammBalance >= referrerShare) {
_collateral.safeTransfer(referrer, referrerShare);
emit ReferrerPaid(referrer, _tickerOwner, referrerShare, _buyInAmount, address(_collateral));
ammBalance -= referrerShare;
}
}
}
fees = _getFees(_buyInAmount);
if (fees > referrerShare) {
uint safeBoxAmount = fees - referrerShare;
if (ammBalance >= safeBoxAmount) {
address _safeBoxPerCollateral = safeBoxPerCollateral[address(_collateral)];
_collateral.safeTransfer(
_safeBoxPerCollateral != address(0) ? _safeBoxPerCollateral : safeBox,
safeBoxAmount
);
emit SafeBoxFeePaid(safeBoxFee, safeBoxAmount, address(_collateral));
}
}
}
// Transform collateral to USD
function _transformToUSD(
uint _amountInCollateral,
uint _collateralPriceInUSD,
uint _collateralDecimals
) internal view returns (uint amountInUSD) {
amountInUSD = _mulWithDecimals(_amountInCollateral, _collateralPriceInUSD);
if (_collateralDecimals < defaultCollateralDecimals) {
amountInUSD = amountInUSD * 10 ** (defaultCollateralDecimals - _collateralDecimals);
} else if (_collateralDecimals > defaultCollateralDecimals) {
amountInUSD = amountInUSD / 10 ** (_collateralDecimals - defaultCollateralDecimals);
}
}
function _getFees(uint _buyInAmount) internal view returns (uint) {
return (_buyInAmount * safeBoxFee) / ONE;
}
function _divWithDecimals(uint _dividend, uint _divisor) internal pure returns (uint) {
return (ONE * _dividend) / _divisor;
}
function _mulWithDecimals(uint _firstMul, uint _secondMul) internal pure returns (uint) {
return (_firstMul * _secondMul) / ONE;
}
function _setReferrer(address _referrer, address _recipient) internal {
if (_referrer != address(0) && _recipient != address(freeBetsHolder)) referrals.setReferrer(_referrer, _recipient);
}
function _exerciseTicket(address _ticket, address _exerciseCollateral, bool _cancelTicket, bool _markLost) internal {
Ticket ticket = Ticket(_ticket);
uint userWonAmount;
if (_markLost) {
userWonAmount = ticket.markAsLost();
} else if (_cancelTicket) {
userWonAmount = ticket.cancel();
} else {
userWonAmount = ticket.exercise(_exerciseCollateral);
}
IERC20 ticketCollateral = ticket.collateral();
address ticketOwner = ticket.ticketOwner();
if (ticketOwner == freeBetsHolder || ticketOwner == stakingThalesBettingProxy) {
IProxyBetting(ticketOwner).confirmTicketResolved(_ticket);
}
if (!ticket.cancelled()) {
_handleFees(ticket.buyInAmount(), ticketOwner, ticketCollateral);
}
manager.resolveKnownTicket(_ticket, ticketOwner);
emit TicketResolved(_ticket, ticketOwner, ticket.isUserTheWinner());
if (userWonAmount > 0 && _exerciseCollateral != address(0) && _exerciseCollateral != address(ticketCollateral)) {
if (ticketCollateral != defaultCollateral) revert OfframpOnlyDefaultCollateralAllowed();
IERC20(_exerciseCollateral).safeTransfer(
ticketOwner,
multiCollateralOnOffRamp.offramp(_exerciseCollateral, userWonAmount)
);
}
// mark ticket as exercised in LiquidityPool and return any funds to the pool if ticket was lost or cancelled
ISportsAMMV2LiquidityPool(liquidityPoolForCollateral[address(ticketCollateral)]).transferToPool(
_ticket,
ticketCollateral.balanceOf(address(this))
);
}
function _applyBonusToOdd(uint odd, uint addedPayoutPercentage) internal pure returns (uint) {
// odd' = odd / ((1 + a) - a*odd)
return (odd * ONE) / ((ONE + addedPayoutPercentage) - _mulWithDecimals(addedPayoutPercentage, odd));
}
function _absDiff(uint a, uint b) internal pure returns (uint) {
return a >= b ? (a - b) : (b - a);
}
/* ========== SETTERS ========== */
/// @notice set roots of merkle tree
/// @param _games game IDs
/// @param _roots new roots
function setRootsPerGames(bytes32[] memory _games, bytes32[] memory _roots) external onlyWhitelistedAddresses {
if (_games.length != _roots.length) revert InvalidLength();
unchecked {
for (uint i; i < _games.length; ++i) {
_setRootForGame(_games[i], _roots[i]);
}
}
}
/// @notice set root of merkle tree
/// @param _game game ID
/// @param _root new root
function setRootForGame(bytes32 _game, bytes32 _root) external onlyWhitelistedAddresses {
_setRootForGame(_game, _root);
}
function _setRootForGame(bytes32 _game, bytes32 _root) internal {
rootPerGame[_game] = _root;
emit GameRootUpdated(_game, _root);
}
/// @notice sets main addresses
/// @param _defaultCollateral the default token used for payment
/// @param _manager manager address
/// @param _riskManager risk manager address
/// @param _resultManager result manager address
/// @param _referrals referrals address
/// @param _safeBox safeBox address
function setAddresses(
IERC20 _defaultCollateral,
address _manager,
address _riskManager,
address _resultManager,
address _referrals,
address _safeBox
) external onlyOwner {
defaultCollateral = _defaultCollateral;
defaultCollateralDecimals = ISportsAMMV2Manager(address(defaultCollateral)).decimals();
manager = ISportsAMMV2Manager(_manager);
riskManager = ISportsAMMV2RiskManager(_riskManager);
resultManager = ISportsAMMV2ResultManager(_resultManager);
referrals = IReferrals(_referrals);
safeBox = _safeBox;
emit AddressesUpdated(_defaultCollateral, _manager, _riskManager, _resultManager, _referrals, _safeBox);
}
/**
* @notice Sets the addresses of various betting processors.
* @dev This function can only be called by the contract owner.
* @param _liveTradingProcessor Address of the live trading processor contract.
* @param _sgpTradingProcessor Address of the single-game parlay trading processor contract.
* @param _freeBetsHolder Address of the free bets holder contract.
*/
function setBettingProcessors(
address _liveTradingProcessor,
address _sgpTradingProcessor,
address _freeBetsHolder
) external onlyOwner {
liveTradingProcessor = _liveTradingProcessor;
sgpTradingProcessor = _sgpTradingProcessor;
freeBetsHolder = _freeBetsHolder;
emit SetBettingProcessors(liveTradingProcessor, sgpTradingProcessor, freeBetsHolder);
}
/// @notice sets new Ticket Mastercopy address
/// @param _ticketMastercopy new Ticket Mastercopy address
function setTicketMastercopy(address _ticketMastercopy) external onlyOwner {
ticketMastercopy = _ticketMastercopy;
emit TicketMastercopyUpdated(_ticketMastercopy);
}
/// @notice sets multi-collateral on/off ramp contract and enable/disable
/// @param _onOffRamper new multi-collateral on/off ramp address
function setMultiCollateralOnOffRamp(address _onOffRamper) external onlyOwner {
_updateApproval(defaultCollateral, address(multiCollateralOnOffRamp), _onOffRamper);
multiCollateralOnOffRamp = IMultiCollateralOnOffRamp(_onOffRamper);
emit SetMultiCollateralOnOffRamp(_onOffRamper);
}
/// @notice sets different amounts
/// @param _safeBoxFee safe box fee paid on each trade
function setAmounts(uint _safeBoxFee) external onlyOwner {
safeBoxFee = _safeBoxFee;
emit AmountsUpdated(_safeBoxFee);
}
/// @notice Sets parameters related to a collateral asset.
/// @dev Only updates fields if the new value differs from the stored one.
/// @param _collateral The collateral token address.
/// @param _liquidityPool New liquidity pool address (optional, skip if same).
/// @param _addedPayout New added payout percentage (optional, skip if same).
/// @param _safeBox New dedicated SafeBox address (optional, skip if same).
function configureCollateral(
address _collateral,
address _liquidityPool,
uint _addedPayout,
address _safeBox
) external onlyOwner {
// Liquidity pool update
if (liquidityPoolForCollateral[_collateral] != _liquidityPool) {
_updateApproval(IERC20(_collateral), liquidityPoolForCollateral[_collateral], _liquidityPool);
liquidityPoolForCollateral[_collateral] = _liquidityPool;
}
// Added payout percentage update
addedPayoutPercentagePerCollateral[_collateral] = _addedPayout;
// SafeBox override update
safeBoxPerCollateral[_collateral] = _safeBox;
emit CollateralConfigured(_collateral, _liquidityPool, _addedPayout, _safeBox);
}
function _updateApproval(IERC20 token, address oldSpender, address newSpender) internal {
if (oldSpender != address(0)) {
token.approve(oldSpender, 0);
}
if (newSpender != address(0)) {
token.approve(newSpender, MAX_APPROVAL);
}
}
/* ========== MODIFIERS ========== */
modifier onlyKnownTickets(address _ticket) {
if (!manager.isKnownTicket(_ticket)) revert UnknownTicket();
_;
}
modifier onlyWhitelistedAddresses() {
if (!manager.isWhitelistedAddress(msg.sender, ISportsAMMV2Manager.Role.ROOT_SETTING) && msg.sender != owner)
revert InvalidSender();
_;
}
modifier onlyValidRecipient(address _recipient) {
if (_recipient == address(0)) revert UndefinedRecipient();
_;
}
/* ========== EVENTS ========== */
event NewTicket(Ticket.MarketData[] markets, address ticket, uint buyInAmount, uint payout, bool isLive);
event TicketCreated(
address ticket,
address recipient,
uint buyInAmount,
uint fees,
uint payout,
uint totalQuote,
address collateral
);
event TicketResolved(address ticket, address ticketOwner, bool isUserTheWinner);
event ReferrerPaid(address refferer, address trader, uint amount, uint volume, address collateral);
event SafeBoxFeePaid(uint safeBoxFee, uint safeBoxAmount, address collateral);
event GameRootUpdated(bytes32 game, bytes32 root);
event AmountsUpdated(uint safeBoxFee);
event AddressesUpdated(
IERC20 defaultCollateral,
address manager,
address riskManager,
address resultManager,
address referrals,
address safeBox
);
event TicketMastercopyUpdated(address ticketMastercopy);
event SetMultiCollateralOnOffRamp(address onOffRamper);
event SetBettingProcessors(address liveTradingProcessor, address sgpTradingProcessor, address freeBetsHolder);
event CollateralConfigured(address collateral, address liquidityPool, uint addedPayout, address safeBox);
}// 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
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 IPriceFeed {
// Structs
struct RateAndUpdatedTime {
uint216 rate;
uint40 time;
}
// Mutative functions
function addAggregator(bytes32 currencyKey, address aggregatorAddress) external;
function removeAggregator(bytes32 currencyKey) external;
// Views
function rateForCurrency(bytes32 currencyKey) external view returns (uint);
function rateAndUpdatedTime(bytes32 currencyKey) external view returns (uint rate, uint time);
function getRates() external view returns (uint[] memory);
function getCurrencies() external view returns (bytes32[] memory);
}// 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;
uint public expectedFinalPayout;
/* ========== CONSTRUCTOR and INITIALIZERS========== */
/// @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;
}
/**
* @notice Sets the expected final payout amount for this ticket.
* @dev
* - Can only be called by the SportsAMM contract.
* - This value represents the total amount of collateral (including fees)
* that was initially funded to the ticket upon creation.
* - Used later in `exercise()` to prevent manipulation or overfunding attacks,
* ensuring payout calculations rely only on the original committed collateral
* and not on the current token balance of the contract.
* - Once set, this value should remain constant throughout the ticket lifecycle.
*
* @param amount The total expected collateral amount that should be held by this ticket.
* Must include both user buy-in and fees.
*
* Emits a {ExpectedFinalPayoutSet} event.
*/
function setExpectedFinalPayout(uint amount) external onlyAMM {
expectedFinalPayout = amount;
emit ExpectedFinalPayoutSet(amount);
}
/* ========== 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");
require(expectedFinalPayout > 0, "Expected final payout not set");
uint payoutWithFees = expectedFinalPayout;
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);
event ExpectedFinalPayoutSet(uint amount);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "./IProxyBetting.sol";
interface IFreeBetsHolder is IProxyBetting {
function ticketToUser(address _createdTicket) external view returns (address);
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);
function confirmSpeedOrChainedSpeedMarketTrade(
bytes32 _requestId,
address _speedMarketAddress,
address _collateral,
uint _buyinAmount,
bool _isChained
) external;
function confirmSpeedMarketResolved(
address _resolvedTicket,
uint _exercized,
uint _buyInAmount,
address _collateral,
bool isChained
) external;
}// 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 calculateTotalRiskOnGame(
bytes32 _gameId,
uint16 _sportId,
uint _maturity
) external view returns (uint totalRisk);
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.20;
interface IWeth {
function deposit() external payable;
function withdraw(uint256) external;
}// 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"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ERC1167FailedCreateClone","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"IllegalInputAmounts","type":"error"},{"inputs":[],"name":"InsuffETHSent","type":"error"},{"inputs":[],"name":"InsuffReceived","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidLength","type":"error"},{"inputs":[],"name":"InvalidPosition","type":"error"},{"inputs":[],"name":"InvalidSender","type":"error"},{"inputs":[],"name":"MultiCollatDisabled","type":"error"},{"inputs":[],"name":"MultiCollateralDisabled","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"OfframpOnlyDefaultCollateralAllowed","type":"error"},{"inputs":[],"name":"OnlyDedicatedProcessor","type":"error"},{"inputs":[],"name":"OnlyOwner","type":"error"},{"inputs":[],"name":"OnlyTicketOwner","type":"error"},{"inputs":[],"name":"SBDOutOfRange","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UndefinedRecipient","type":"error"},{"inputs":[],"name":"UnknownTicket","type":"error"},{"inputs":[],"name":"UnsupportedSender","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"inputs":[],"name":"ZeroPriceForCollateral","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20","name":"defaultCollateral","type":"address"},{"indexed":false,"internalType":"address","name":"manager","type":"address"},{"indexed":false,"internalType":"address","name":"riskManager","type":"address"},{"indexed":false,"internalType":"address","name":"resultManager","type":"address"},{"indexed":false,"internalType":"address","name":"referrals","type":"address"},{"indexed":false,"internalType":"address","name":"safeBox","type":"address"}],"name":"AddressesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"safeBoxFee","type":"uint256"}],"name":"AmountsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"collateral","type":"address"},{"indexed":false,"internalType":"address","name":"liquidityPool","type":"address"},{"indexed":false,"internalType":"uint256","name":"addedPayout","type":"uint256"},{"indexed":false,"internalType":"address","name":"safeBox","type":"address"}],"name":"CollateralConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"game","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"GameRootUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint8","name":"position","type":"uint8"},{"internalType":"uint256","name":"odd","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[]"}],"indexed":false,"internalType":"struct Ticket.MarketData[]","name":"markets","type":"tuple[]"},{"indexed":false,"internalType":"address","name":"ticket","type":"address"},{"indexed":false,"internalType":"uint256","name":"buyInAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isLive","type":"bool"}],"name":"NewTicket","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":"address","name":"refferer","type":"address"},{"indexed":false,"internalType":"address","name":"trader","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"volume","type":"uint256"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"}],"name":"ReferrerPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"safeBoxFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"safeBoxAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"}],"name":"SafeBoxFeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"liveTradingProcessor","type":"address"},{"indexed":false,"internalType":"address","name":"sgpTradingProcessor","type":"address"},{"indexed":false,"internalType":"address","name":"freeBetsHolder","type":"address"}],"name":"SetBettingProcessors","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"onOffRamper","type":"address"}],"name":"SetMultiCollateralOnOffRamp","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ticket","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"buyInAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fees","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payout","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalQuote","type":"uint256"},{"indexed":false,"internalType":"address","name":"collateral","type":"address"}],"name":"TicketCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ticketMastercopy","type":"address"}],"name":"TicketMastercopyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ticket","type":"address"},{"indexed":false,"internalType":"address","name":"ticketOwner","type":"address"},{"indexed":false,"internalType":"bool","name":"isUserTheWinner","type":"bool"}],"name":"TicketResolved","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"addedPayoutPercentagePerCollateral","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"address","name":"_liquidityPool","type":"address"},{"internalType":"uint256","name":"_addedPayout","type":"uint256"},{"internalType":"address","name":"_safeBox","type":"address"}],"name":"configureCollateral","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"defaultCollateral","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ticket","type":"address"},{"internalType":"address","name":"_exerciseCollateral","type":"address"}],"name":"exerciseTicketOffRamp","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tickets","type":"address[]"}],"name":"expireTickets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"freeBetsHolder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_games","type":"bytes32[]"}],"name":"getRootsPerGames","outputs":[{"internalType":"bytes32[]","name":"_roots","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ticket","type":"address"},{"internalType":"enum ISportsAMMV2.TicketAction","name":"action","type":"uint8"}],"name":"handleTicketResolving","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"initNonReentrant","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastPauseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"liquidityPoolForCollateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"liveTradingProcessor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"manager","outputs":[{"internalType":"contract ISportsAMMV2Manager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"multiCollateralOnOffRamp","outputs":[{"internalType":"contract IMultiCollateralOnOffRamp","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":"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":[],"name":"referrals","outputs":[{"internalType":"contract IReferrals","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resultManager","outputs":[{"internalType":"contract ISportsAMMV2ResultManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"riskManager","outputs":[{"internalType":"contract ISportsAMMV2RiskManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"rootPerGame","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safeBox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safeBoxFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"safeBoxPerCollateral","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"_defaultCollateral","type":"address"},{"internalType":"address","name":"_manager","type":"address"},{"internalType":"address","name":"_riskManager","type":"address"},{"internalType":"address","name":"_resultManager","type":"address"},{"internalType":"address","name":"_referrals","type":"address"},{"internalType":"address","name":"_safeBox","type":"address"}],"name":"setAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_safeBoxFee","type":"uint256"}],"name":"setAmounts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_liveTradingProcessor","type":"address"},{"internalType":"address","name":"_sgpTradingProcessor","type":"address"},{"internalType":"address","name":"_freeBetsHolder","type":"address"}],"name":"setBettingProcessors","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_onOffRamper","type":"address"}],"name":"setMultiCollateralOnOffRamp","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":"bytes32","name":"_game","type":"bytes32"},{"internalType":"bytes32","name":"_root","type":"bytes32"}],"name":"setRootForGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_games","type":"bytes32[]"},{"internalType":"bytes32[]","name":"_roots","type":"bytes32[]"}],"name":"setRootsPerGames","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ticketMastercopy","type":"address"}],"name":"setTicketMastercopy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"sgpTradingProcessor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stakingThalesBettingProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ticketMastercopy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"uint256","name":"_expectedQuote","type":"uint256"},{"internalType":"uint256","name":"_additionalSlippage","type":"uint256"},{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bool","name":"_isEth","type":"bool"}],"name":"trade","outputs":[{"internalType":"address","name":"_createdTicket","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"uint256","name":"_expectedQuote","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"address","name":"_collateral","type":"address"}],"name":"tradeLive","outputs":[{"internalType":"address","name":"_createdTicket","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bool","name":"_isLive","type":"bool"}],"name":"tradeQuote","outputs":[{"internalType":"uint256","name":"totalQuote","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256[]","name":"amountsToBuy","type":"uint256[]"},{"internalType":"uint256","name":"buyInAmountInDefaultCollateral","type":"uint256"},{"internalType":"enum ISportsAMMV2RiskManager.RiskStatus","name":"riskStatus","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bool","name":"_isLive","type":"bool"},{"internalType":"uint8","name":"_systemBetDenominator","type":"uint8"}],"name":"tradeQuoteSystem","outputs":[{"internalType":"uint256","name":"totalQuote","type":"uint256"},{"internalType":"uint256","name":"payout","type":"uint256"},{"internalType":"uint256","name":"fees","type":"uint256"},{"internalType":"uint256[]","name":"amountsToBuy","type":"uint256[]"},{"internalType":"uint256","name":"buyInAmountInDefaultCollateral","type":"uint256"},{"internalType":"enum ISportsAMMV2RiskManager.RiskStatus","name":"riskStatus","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"uint256","name":"_approvedQuote","type":"uint256"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"address","name":"_collateral","type":"address"}],"name":"tradeSGP","outputs":[{"internalType":"address","name":"_createdTicket","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"gameId","type":"bytes32"},{"internalType":"uint16","name":"sportId","type":"uint16"},{"internalType":"uint16","name":"typeId","type":"uint16"},{"internalType":"uint256","name":"maturity","type":"uint256"},{"internalType":"uint8","name":"status","type":"uint8"},{"internalType":"int24","name":"line","type":"int24"},{"internalType":"uint24","name":"playerId","type":"uint24"},{"internalType":"uint256[]","name":"odds","type":"uint256[]"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"},{"internalType":"uint8","name":"position","type":"uint8"},{"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[][]"}],"internalType":"struct ISportsAMMV2.TradeData[]","name":"_tradeData","type":"tuple[]"},{"internalType":"uint256","name":"_buyInAmount","type":"uint256"},{"internalType":"uint256","name":"_expectedQuote","type":"uint256"},{"internalType":"uint256","name":"_additionalSlippage","type":"uint256"},{"internalType":"address","name":"_referrer","type":"address"},{"internalType":"address","name":"_collateral","type":"address"},{"internalType":"bool","name":"_isEth","type":"bool"},{"internalType":"uint8","name":"_systemBetDenominator","type":"uint8"}],"name":"tradeSystemBet","outputs":[{"internalType":"address","name":"_createdTicket","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"proxyAddress","type":"address"}],"name":"transferOwnershipAtInit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ticketAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawCollateralFromTicket","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
608060405234801561001057600080fd5b5061589f80620000216000396000f3fe60806040526004361061028c5760003560e01c806391b4ded91161015a578063c3b83f5f116100c1578063e6d1c8a61161007a578063e6d1c8a6146107ed578063ebc797721461080d578063f453ea7d14610822578063f5bf372e14610842578063f8a940b01461086f578063fd47e5ec1461088f57600080fd5b8063c3b83f5f1461072d578063c4d66de81461074d578063ce18a8371461076d578063d3dc75391461078d578063d43b3576146107ad578063e481a342146107cd57600080fd5b8063aeb0f16411610113578063aeb0f16414610657578063b4e7e5c614610677578063b6a3670414610697578063b8e15ed0146106b7578063c2c9e276146106ed578063c301086c1461070d57600080fd5b806391b4ded9146105ae57806393b0c2ae146105c4578063942b67dc146105d75780639a23be78146105f75780639a618c0f14610617578063ace81b711461063757600080fd5b806347842663116101fe5780636cfb6bf9116101b75780636cfb6bf9146104e75780636dbf6cc7146105075780637649226c1461052757806379ba5097146105595780638da5cb5b1461056e5780638ff9d5cf1461058e57600080fd5b80634784266314610410578063481c6a751461043057806348663e951461045057806350631ddc1461047057806353a47bb71461049d5780635c975abb146104bd57600080fd5b80631627540c116102505780631627540c1461034357806316c38b3c14610363578063177957a81461038357806329cf5368146103b957806338ea7103146103cc57806344cab7ee146103f057600080fd5b8063014e17b01461029857806304de96c5146102c15780630ca08207146102e15780630fe621901461030357806313af40351461032357600080fd5b3661029357005b600080fd5b6102ab6102a636600461453c565b6108bc565b6040516102b891906145d4565b60405180910390f35b3480156102cd57600080fd5b506013546102ab906001600160a01b031681565b3480156102ed57600080fd5b506103016102fc3660046145e8565b61096b565b005b34801561030f57600080fd5b506017546102ab906001600160a01b031681565b34801561032f57600080fd5b5061030161033e3660046145e8565b6109e6565b34801561034f57600080fd5b5061030161035e3660046145e8565b610af2565b34801561036f57600080fd5b5061030161037e366004614605565b610b45565b34801561038f57600080fd5b506102ab61039e3660046145e8565b6008602052600090815260409020546001600160a01b031681565b6102ab6103c7366004614622565b610bb7565b3480156103d857600080fd5b506103e260105481565b6040519081526020016102b8565b3480156103fc57600080fd5b506018546102ab906001600160a01b031681565b34801561041c57600080fd5b50600b546102ab906001600160a01b031681565b34801561043c57600080fd5b50600a546102ab906001600160a01b031681565b34801561045c57600080fd5b50600f546102ab906001600160a01b031681565b34801561047c57600080fd5b506103e261048b3660046146b1565b60066020526000908152604090205481565b3480156104a957600080fd5b506001546102ab906001600160a01b031681565b3480156104c957600080fd5b506003546104d79060ff1681565b60405190151581526020016102b8565b3480156104f357600080fd5b506103016105023660046146ca565b610cb1565b34801561051357600080fd5b5061030161052236600461486b565b610df3565b34801561053357600080fd5b506105476105423660046148ce565b610f14565b6040516102b896959493929190614957565b34801561056557600080fd5b50610301610f52565b34801561057a57600080fd5b506000546102ab906001600160a01b031681565b34801561059a57600080fd5b50600c546102ab906001600160a01b031681565b3480156105ba57600080fd5b506103e260025481565b6102ab6105d23660046149e4565b61102a565b3480156105e357600080fd5b506103016105f2366004614a8b565b611108565b34801561060357600080fd5b50610301610612366004614aad565b6111c0565b34801561062357600080fd5b506011546102ab906001600160a01b031681565b34801561064357600080fd5b50610547610652366004614ae6565b61122a565b34801561066357600080fd5b506007546102ab906001600160a01b031681565b34801561068357600080fd5b50610301610692366004614b66565b611269565b3480156106a357600080fd5b50600e546102ab906001600160a01b031681565b3480156106c357600080fd5b506102ab6106d23660046145e8565b6016602052600090815260409020546001600160a01b031681565b3480156106f957600080fd5b50610301610708366004614bb1565b6112f5565b34801561071957600080fd5b506103016107283660046145e8565b611497565b34801561073957600080fd5b506103016107483660046145e8565b6114ea565b34801561075957600080fd5b506103016107683660046145e8565b6115da565b34801561077957600080fd5b506014546102ab906001600160a01b031681565b34801561079957600080fd5b50600d546102ab906001600160a01b031681565b3480156107b957600080fd5b506103016107c8366004614bf2565b6116e4565b3480156107d957600080fd5b506102ab6107e8366004614622565b6117ee565b3480156107f957600080fd5b50610301610808366004614aad565b6118c1565b34801561081957600080fd5b50610301611a4e565b34801561082e57600080fd5b5061030161083d3660046146b1565b611aac565b34801561084e57600080fd5b506103e261085d3660046145e8565b60156020526000908152604090205481565b34801561087b57600080fd5b5061030161088a366004614c52565b611ae9565b34801561089b57600080fd5b506108af6108aa366004614bb1565b611cc1565b6040516102b89190614cbb565b60006001600460008282546108d19190614ce4565b909155505060045460035460ff16156109055760405162461bcd60e51b81526004016108fc90614cf7565b60405180910390fd5b61093b6109128a8c614ea1565b60408051606081018252600080825260208201819052918101919091528a8a8a8a8a8a33611d6c565b9150600454811461095e5760405162461bcd60e51b81526004016108fc90615012565b5098975050505050505050565b610973611e4b565b600754601154610990916001600160a01b03908116911683611ebf565b601180546001600160a01b0319166001600160a01b0383161790556040517f7d16d7e66eb2263f48c2c24af20e095395796ce3d05df64d84d9991a4d436247906109db9083906145d4565b60405180910390a150565b6001600160a01b038116610a385760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064016108fc565b600154600160a01b900460ff1615610aa45760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016108fc565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b031990911617815560405160008051602061584a833981519152916109db918490615049565b610afa611e4b565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906109db9083906145d4565b610b4d611e4b565b60035460ff16151581151514610bb4576003805460ff191682151590811790915560ff1615610b7b57426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5906020016109db565b50565b6000600160046000828254610bcc9190614ce4565b909155505060045460035460ff1615610bf75760405162461bcd60e51b81526004016108fc90614cf7565b846001600160a01b038116610c1f576040516328f6040160e21b815260040160405180910390fd5b6018546001600160a01b03163314610c4a57604051637bcec4fb60e01b815260040160405180910390fd5b610c81610c578a8c614ea1565b60408051606081018252600080825260016020830152918101829052908b908b908a8a828e611d6c565b9250506004548114610ca55760405162461bcd60e51b81526004016108fc90615012565b50979650505050505050565b610cb9611e4b565b600780546001600160a01b0319166001600160a01b0388169081179091556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190615063565b600955600a80546001600160a01b038781166001600160a01b03199283168117909355600b80548883169084168117909155600c80548884169085168117909155600d80548885169086168117909155600f805488861696168617905560408051948d1685526020850196909652948301919091526060820152608081019290925260a08201527f1962de5c532b26a8a72c8524fe745d05421f16a6521fc531ce010572f742a6939060c0015b60405180910390a1505050505050565b600a5460405163e760c39560e01b81526001600160a01b039091169063e760c39590610e2690339060009060040161507c565b602060405180830381865afa158015610e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6791906150a9565b158015610e7f57506000546001600160a01b03163314155b15610e9d57604051636edaef2f60e11b815260040160405180910390fd5b8051825114610ebf5760405163251f56a160e21b815260040160405180910390fd5b60005b8251811015610f0f57610f07838281518110610ee057610ee06150c6565b6020026020010151838381518110610efa57610efa6150c6565b6020026020010151611fca565b600101610ec2565b505050565b60008060006060600080610f2d8b8b8b8b8b6000612019565b809650819750829850839950849a50859b505050505050509550955095509550955095565b6001546001600160a01b03163314610fca5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016108fc565b60005460015460405160008051602061584a83398151915292610ffb926001600160a01b0391821692911690615049565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b600060016004600082825461103f9190614ce4565b909155505060045460035460ff161561106a5760405162461bcd60e51b81526004016108fc90614cf7565b60018360ff16111580611080575060ff83168a11155b1561109e57604051631a0a722b60e01b815260040160405180910390fd5b6110d76110ab8b8d614ea1565b6040805160608101825260ff87168152600060208201819052918101919091528b8b8b8b8b8b33611d6c565b915060045481146110fa5760405162461bcd60e51b81526004016108fc90615012565b509998505050505050505050565b600a5460405163e760c39560e01b81526001600160a01b039091169063e760c3959061113b90339060009060040161507c565b602060405180830381865afa158015611158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117c91906150a9565b15801561119457506000546001600160a01b03163314155b156111b257604051636edaef2f60e11b815260040160405180910390fd5b6111bc8282611fca565b5050565b6111c8611e4b565b604051634946980760e11b81526001600160a01b0383169063928d300e906111f49084906004016145d4565b600060405180830381600087803b15801561120e57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050505050565b600080600060606000806112428c8c8c8c8c8c612019565b809650819750829850839950849a50859b5050505050505096509650965096509650969050565b611271611e4b565b601380546001600160a01b038581166001600160a01b0319928316811790935560188054868316908416811790915560148054928616929093168217909255604080519384526020840192909252908201527f2b8bc92a77df3bf6abc793bbc13c813f4e0028dd6de7aefb204a96ade4ddc4739060600160405180910390a1505050565b6112fd611e4b565b60005b81811015610f0f57600083838381811061131c5761131c6150c6565b905060200201602081019061133191906145e8565b90506000816001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611372573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139691906150dc565b6014549091506001600160a01b038083169116148015906113c557506017546001600160a01b03828116911614155b1561148d5760405163646d919f60e11b81526001600160a01b0383169063c8db233e906113f69033906004016145d4565b600060405180830381600087803b15801561141057600080fd5b505af1158015611424573d6000803e3d6000fd5b5050600a5460405163f033d0f960e01b81526001600160a01b03909116925063f033d0f9915061145a9085908590600401615049565b600060405180830381600087803b15801561147457600080fd5b505af1158015611488573d6000803e3d6000fd5b505050505b5050600101611300565b61149f611e4b565b600e80546001600160a01b0319166001600160a01b0383161790556040517fab496e3942a33c5a729be5985af46209e18077a462af550b750246460950eb7f906109db9083906145d4565b6114f2611e4b565b6001600160a01b03811661153a5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016108fc565b600154600160a81b900460ff161561158a5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016108fc565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b17905560405160008051602061584a833981519152916109db918490615049565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561161f5750825b90506000826001600160401b0316600114801561163b5750303b155b905081158015611649575080155b156116675760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561169157845460ff60401b1916600160401b1785555b61169a866109e6565b6116a2611a4e565b831561122257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602001610de3565b6116ec611e4b565b6001600160a01b03848116600090815260086020526040902054811690841614611766576001600160a01b038085166000908152600860205260409020546117379186911685611ebf565b6001600160a01b03848116600090815260086020526040902080546001600160a01b0319169185169190911790555b6001600160a01b038481166000818152601560209081526040808320879055601682529182902080546001600160a01b031916868616908117909155825193845293871690830152810184905260608101919091527f2083b2a6d9c12b8cd65a8a4d92a82708aac25a81a524e9d13e92559bf818db569060800160405180910390a150505050565b60006001600460008282546118039190614ce4565b909155505060045460035460ff161561182e5760405162461bcd60e51b81526004016108fc90614cf7565b846001600160a01b038116611856576040516328f6040160e21b815260040160405180910390fd5b6013546001600160a01b0316331461188157604051637bcec4fb60e01b815260040160405180910390fd5b610c8161188e8a8c614ea1565b6040518060600160405280600060ff168152602001600015158152602001600115158152508a8a60008a8a60008e611d6c565b6001600460008282546118d49190614ce4565b909155505060045460035460ff16156118ff5760405162461bcd60e51b81526004016108fc90614cf7565b600a546040516321875b5760e01b815284916001600160a01b0316906321875b579061192f9084906004016145d4565b602060405180830381865afa15801561194c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197091906150a9565b61198d57604051634f8c20e160e01b815260040160405180910390fd5b836001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ee91906150dc565b6001600160a01b0316336001600160a01b031614611a1f5760405163bba02e7160e01b815260040160405180910390fd5b611a2c8484600080612264565b506004548114610f0f5760405162461bcd60e51b81526004016108fc90615012565b60055460ff1615611a975760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016108fc565b6005805460ff19166001908117909155600455565b611ab4611e4b565b60108190556040518181527f5da87bc83066ddf563cfd9de25e562860f147b358751f50766847996202e5d33906020016109db565b600160046000828254611afc9190614ce4565b909155505060045460035460ff1615611b275760405162461bcd60e51b81526004016108fc90614cf7565b600a546040516321875b5760e01b815284916001600160a01b0316906321875b5790611b579084906004016145d4565b602060405180830381865afa158015611b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9891906150a9565b611bb557604051634f8c20e160e01b815260040160405180910390fd5b6000836002811115611bc957611bc9614941565b14611c5f57600a5460405163e760c39560e01b81526001600160a01b039091169063e760c39590611c0190339060029060040161507c565b602060405180830381865afa158015611c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4291906150a9565b611c5f57604051637830359760e01b815260040160405180910390fd5b6001836002811115611c7357611c73614941565b03611c8c57611c8784600060016000612264565b611a2c565b6002836002811115611ca057611ca0614941565b03611cb357611c87846000806001612264565b611a2c846000806000612264565b606081806001600160401b03811115611cdc57611cdc61474c565b604051908082528060200260200182016040528015611d05578160200160208202803683370190505b50915060005b81811015611d645760066000868684818110611d2957611d296150c6565b90506020020135815260200190815260200160002054838281518110611d5157611d516150c6565b6020908102919091010152600101611d0b565b505092915050565b6000861580611d79575087155b15611d975760405163d1892e7760e01b815260040160405180910390fd5b611da185836128a7565b600080611db08a878688612904565b604080516101208101909152828152919d5098509193509150611e3b908d9060208101611ddd8e8e612d02565b81526020018b8152602001876001600160a01b031681526020018e6040015115158152602001896001600160a01b03168152602001856001600160a01b031681526020018481526020018e6020015115158152508d60000151612d2a565b9c9b505050505050505050505050565b6000546001600160a01b03163314611ebd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016108fc565b565b6001600160a01b03821615611f425760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390611efd9085906000906004016150f9565b6020604051808303816000875af1158015611f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4091906150a9565b505b6001600160a01b03811615610f0f5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390611f81908490600019906004016150f9565b6020604051808303816000875af1158015611fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc491906150a9565b50505050565b60008281526006602090815260409182902083905581518481529081018390527fc6fa3d673d901ef180e5a314ff8ede38ac8ba226ce71c9d822ed8a438020a1ab910160405180910390a15050565b6000808060608782816001600160a01b038a161580159061204857506007546001600160a01b038b8116911614155b156121cd576001600160a01b03808b1660009081526008602052604090205416806120fb57601160009054906101000a90046001600160a01b03166001600160a01b031663cb4ba5248c8e6040518363ffffffff1660e01b81526004016120b09291906150f9565b602060405180830381865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f19190615063565b93508391506121cb565b6121c88c826001600160a01b031663f7683bbc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121619190615063565b8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561219f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c39190615063565b61357b565b93505b505b806000036121ee57604051631f2a200560e01b815260040160405180910390fd5b6122406121fb8d8f614ea1565b6040805160e081018252848152600160208201529081018690526001600160a01b038d1660608201528b15156080820152600060a0820181905260c08201528a6135f1565b809650819850829950839a50849b5050505050505096509650965096509650969050565b83600082156122d857816001600160a01b0316636a265aa96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d19190615063565b9050612390565b831561231e57816001600160a01b031663ea8a1af06040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ad573d6000803e3d6000fd5b604051630d8acc1560e11b81526001600160a01b03831690631b15982a9061234a9088906004016145d4565b6020604051808303816000875af1158015612369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238d9190615063565b90505b6000826001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f491906150dc565b90506000836001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612435573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245991906150dc565b6014549091506001600160a01b038083169116148061248557506017546001600160a01b038281169116145b156124e95760405163509eb5b560e11b81526001600160a01b0382169063a13d6b6a906124b6908b906004016145d4565b600060405180830381600087803b1580156124d057600080fd5b505af11580156124e4573d6000803e3d6000fd5b505050505b836001600160a01b0316639a82a09a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b91906150a9565b6125bd576125bb846001600160a01b031663d165dac26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b49190615063565b8284613b53565b505b600a546040516306ef036760e01b81526001600160a01b03909116906306ef0367906125ef908b908590600401615049565b600060405180830381600087803b15801561260957600080fd5b505af115801561261d573d6000803e3d6000fd5b505050507f1a208f07d825103c5b1eb3bb1109b420fd544123300beb9e220fc951cbd7dd0b8882866001600160a01b0316633356a35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a691906150a9565b604080516001600160a01b03948516815293909216602084015215159082015260600160405180910390a16000831180156126e957506001600160a01b03871615155b80156127075750816001600160a01b0316876001600160a01b031614155b156127c6576007546001600160a01b0383811691161461273a5760405163c6338d5560e01b815260040160405180910390fd5b601154604051630992646d60e31b81526127c69183916001600160a01b0390911690634c93236890612772908c9089906004016150f9565b6020604051808303816000875af1158015612791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b59190615063565b6001600160a01b038a169190613e37565b6001600160a01b03808316600081815260086020526040908190205490516370a0823160e01b815292169163d7efa129918b916370a082319061280d9030906004016145d4565b602060405180830381865afa15801561282a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284e9190615063565b6040518363ffffffff1660e01b815260040161286b9291906150f9565b600060405180830381600087803b15801561288557600080fd5b505af1158015612899573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b038216158015906128cd57506014546001600160a01b03828116911614155b156111bc57600d5460405163bbddaca360e01b81526001600160a01b039091169063bbddaca3906111f49085908590600401615049565b60008085816001600160a01b038716158061292c57506007546001600160a01b038881169116145b1561294f57506007546001600160a01b031661294a8187308b613e8f565b612cd9565b50858415612a6457601160009054906101000a90046001600160a01b03166001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906150dc565b6001600160a01b0316876001600160a01b03161415806129ed57508734105b15612a0b57604051634f4d1d8760e01b815260040160405180910390fd5b866001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4657600080fd5b505af1158015612a5a573d6000803e3d6000fd5b5050505050612a79565b612a796001600160a01b03881687308b613e8f565b6001600160a01b038088166000908152600860205260409020541693508315612b2157836001600160a01b031663f7683bbc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ada573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612afe9190615063565b92508260000361294a5760405163577f86e160e11b815260040160405180910390fd5b6011546001600160a01b0316612b4a57604051630d5f109960e21b815260040160405180910390fd5b60115460405163095ea7b360e01b81526001600160a01b038981169263095ea7b392612b7e92909116908c906004016150f9565b6020604051808303816000875af1158015612b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc191906150a9565b506011546040516322ceb11360e21b81526001600160a01b0390911690638b3ac44c90612bf4908a908c906004016150f9565b6020604051808303816000875af1158015612c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c379190615063565b6011546040516332d2e94960e21b81529193506001600160a01b03169063cb4ba52490612c6a908a908c906004016150f9565b602060405180830381865afa158015612c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cab9190615063565b821015612ccb5760405163a3b7d2e560e01b815260040160405180910390fd5b506007546001600160a01b03165b6001600160a01b0380821660009081526008602052604090205416989297509095509350915050565b600081612d1784670de0b6b3a7640000615112565b612d219190615129565b90505b92915050565b6000612d5e6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60a08401516001600160a01b031660009081526015602052604090205460608201526080840151612e0b57612df8856040518060e0016040528087600001518152602001600015158152602001600081526020018760a001516001600160a01b0316815260200187608001511515815260200187610100015115158152602001612df088600001518960200151612d02565b9052856135f1565b5050604084015260208301528152613185565b84516060820151602086015160009015612e3657612e3187600001518860200151612d02565b612e39565b60005b90506000600b60009054906101000a90046001600160a01b03166001600160a01b031663e88698bf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb49190615063565b905083600103612f3d57600089600081518110612ed357612ed36150c6565b602002602001015160e001518a600081518110612ef257612ef26150c6565b6020026020010151610120015160ff1681518110612f1257612f126150c6565b602002602001015190506000612f288286613ec8565b905082811015612f355750815b865250613153565b60008060005b868110156130535760008c8281518110612f5f57612f5f6150c6565b6020026020010151905080610120015160ff168160e001515111612f965760405163673f032f60e11b815260040160405180910390fd5b60008160e0015182610120015160ff1681518110612fb657612fb66150c6565b6020026020010151905060008111612fff5760405162461bcd60e51b815260206004820152600c60248201526b16995c9bc81b1959c81bd91960a21b60448201526064016108fc565b84156130145761300f8582613f02565b613016565b805b94506000613024828a613ec8565b9050841561303b576130368582613f02565b61303d565b805b94505050508061304c9061514b565b9050612f43565b5064e8d4a510008461309c5760405162461bcd60e51b815260206004820152601260248201527142616420617070726f7665642071756f746560701b60448201526064016108fc565b838210156130f45760006130b08587613f17565b905081866130c6670de0b6b3a764000084615112565b6130d09190615129565b11156130ee5760405162461bcd60e51b81526004016108fc90615164565b50613140565b60006131008487613f17565b90508186613116670de0b6b3a764000084615112565b6131209190615129565b111561313e5760405162461bcd60e51b81526004016108fc90615164565b505b8188528382101561314f578388525b5050505b875185516131619190612d02565b6020860152875161317190613f3a565b604086015250505060208083015190860152505b806040015181602001516131999190614ce4565b6080820152805160208201516131b29187918787613f5d565b60006131c28683606001516140fc565b600e549091506000906131dd906001600160a01b0316614304565b9050806001600160a01b031663b5ac8d98604051806101600160405280858152602001896000015181526020018660400151815260200186600001518152602001306001600160a01b0316815260200189606001516001600160a01b031681526020018960a001516001600160a01b03168152602001600b60009054906101000a90046001600160a01b03166001600160a01b031663b3ee14246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ca9190615063565b6132d49042614ce4565b81526020018960800151151581526020018860ff16815260200189610100015115158152506040518263ffffffff1660e01b815260040161331591906152c4565b600060405180830381600087803b15801561332f57600080fd5b505af1158015613343573d6000803e3d6000fd5b5050600a54606089015160405163514dd41d60e11b81526001600160a01b03909216935063a29ba83a925061337e918b918691600401615507565b600060405180830381600087803b15801561339857600080fd5b505af11580156133ac573d6000803e3d6000fd5b505050508560c001516001600160a01b03166358c09cc082886000015186608001516133d8919061553a565b6040518363ffffffff1660e01b81526004016133f59291906150f9565b600060405180830381600087803b15801561340f57600080fd5b505af1158015613423573d6000803e3d6000fd5b505050608084015160a088015161344692506001600160a01b0316908390613e37565b608083015160405163242c6c2d60e01b815260048101919091526001600160a01b0382169063242c6c2d90602401600060405180830381600087803b15801561348e57600080fd5b505af11580156134a2573d6000803e3d6000fd5b505050507fece8b280c05fcdb1e6f073f39266f576f9ee1f91bfe098dbb5f7b5e3dce305ba8282886000015186602001518a608001516040516134e995949392919061554d565b60405180910390a16060868101518751604086810151602080890151895160a0808f015186516001600160a01b038c81168252998a16958101959095528487019790975297830193909352608082015294850152911660c0830152517fddd6ef4a731d70ec093d7f6a82160e586a40dde73b44129dcb771a5b64557d8a9181900360e00190a1925050505b9392505050565b60006135878484613f02565b90506009548210156135bd57816009546135a1919061553a565b6135ac90600a615673565b6135b69082615112565b9050613574565b600954821115613574576009546135d4908361553a565b6135df90600a615673565b6135e99082615129565b949350505050565b6000806000606060008088519050806001600160401b038111156136175761361761474c565b604051908082528060200260200182016040528015613640578160200160208202803683370190505b5092506000600b60009054906101000a90046001600160a01b03166001600160a01b031663e88698bf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bc9190615063565b60608a01516001600160a01b0316600090815260156020526040812054919250600160ff8b161191905b848110156138f95760008d8281518110613702576137026150c6565b602090810291909101810151600b548151600090815260069093526040928390205492516311b3db5760e11b81529193506001600160a01b031691632367b6ae9161375191859160040161567f565b60006040518083038186803b15801561376957600080fd5b505afa15801561377d573d6000803e3d6000fd5b5050505080610120015160ff168160e0015151116137ae5760405163673f032f60e11b815260040160405180910390fd5b60008160e0015182610120015160ff16815181106137ce576137ce6150c6565b602002602001015190506137e28482613f02565b6137f485670de0b6b3a7640000614ce4565b6137fe919061553a565b613810670de0b6b3a764000083615112565b61381a9190615129565b8e519091506138298183612d02565b613833919061553a565b898481518110613845576138456150c6565b60200260200101818152505084156138cd57613869670de0b6b3a764000088615112565b8d60ff16670de0b6b3a76400008b8681518110613888576138886150c6565b602002602001015161389a9190615112565b6138a49190615112565b6138ae9190615129565b8984815181106138c0576138c06150c6565b6020026020010181815250505b8b156138e2576138dd8c82613f02565b6138e4565b805b9b505050806138f29061514b565b90506136e6565b508815613b4457811561399a57600b60009054906101000a90046001600160a01b03166001600160a01b031663ff527ee38d8c8e60000151856040518563ffffffff1660e01b815260040161395194939291906156a1565b6040805180830381865afa15801561396d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399191906156d3565b995097506139ff565b8a60a00151156139f0578a60c0015198506139b5818a613f02565b6139c782670de0b6b3a7640000614ce4565b6139d1919061553a565b6139e3670de0b6b3a76400008b615112565b6139ed9190615129565b98505b8a516139fc908a612d02565b97505b82891015613a1b57829850613a188b600001518a612d02565b97505b8a51613a2690613f3a565b96508a6020015115613b44576060600b60009054906101000a90046001600160a01b03166001600160a01b031663c360aded8e8e604001518f608001518f6040518563ffffffff1660e01b8152600401613a8394939291906156f7565b600060405180830381865afa158015613aa0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ac89190810190615729565b909650905060005b85811015613b2057818181518110613aea57613aea6150c6565b602002602001015115613b18576000888281518110613b0b57613b0b6150c6565b6020026020010181815250505b600101613ad0565b506000866002811115613b3557613b35614941565b14613b4257600098508899505b505b50505050939792965093509350565b600d54604051630293b59d60e31b8152600091829182916001600160a01b03169063149dace890613b889088906004016145d4565b602060405180830381865afa158015613ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc991906150dc565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613bf991906145d4565b602060405180830381865afa158015613c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3a9190615063565b90506001600160a01b03821615801590613c6257506014546001600160a01b03878116911614155b15613d7057600d5460405163c7d1f5f160e01b81526000916001600160a01b03169063c7d1f5f190613c989086906004016145d4565b602060405180830381865afa158015613cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd99190615063565b90508015613d6e57613ceb8882613f02565b9350838210613d6e57613d086001600160a01b0387168486613e37565b604080516001600160a01b0385811682528981166020830152818301879052606082018b90528816608082015290517f2f60e9c3fac363f0b03efb55d381f3d47475dbf1230e99201c9cdf4b9f577fc79181900360a00190a1613d6b848361553a565b91505b505b613d7987613f3a565b935082841115613e2d576000613d8f848661553a565b9050808210613e2b576001600160a01b0380871660009081526016602052604090205416613ddf81613dcc57600f546001600160a01b0316613dce565b815b6001600160a01b0389169084613e37565b60105460408051918252602082018490526001600160a01b03891682820152517f05b8bddc7eed21b7839baa291868ed966dd7299b79495dadd406c782b9770fe79181900360600190a1505b505b5050509392505050565b610f0f83846001600160a01b031663a9059cbb8585604051602401613e5d9291906150f9565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050614376565b6040516001600160a01b038481166024830152838116604483015260648201839052611fc49186918216906323b872dd90608401613e5d565b6000613ed48284613f02565b613ee683670de0b6b3a7640000614ce4565b613ef0919061553a565b612d17670de0b6b3a764000085615112565b6000670de0b6b3a7640000612d178385615112565b600081831015613f3057613f2b838361553a565b612d21565b612d21828461553a565b6000670de0b6b3a764000060105483613f539190615112565b612d249190615129565b815160e0830151602084015181156140025760008560a001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613fb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd79190615063565b9050613fe484848361357b565b9350613ff187848361357b565b9650613ffe82848361357b565b9150505b600b5460808601516101008701516040516354c0545160e01b81526001600160a01b03909316926354c0545192614046928d9289928d9290918c91906004016157d9565b600060405180830381600087803b15801561406057600080fd5b505af1158015614074573d6000803e3d6000fd5b5050600b546040888101518c5191516318542d5360e31b815260048101899052602481018d9052604481018c905260648101879052608481019190915260a48101919091526001600160a01b03909116925063c2a16a98915060c40160006040518083038186803b1580156140e857600080fd5b505afa158015612899573d6000803e3d6000fd5b8151606090806001600160401b038111156141195761411961474c565b60405190808252806020026020018201604052801561419a57816020015b60408051610140810182526000808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e0830182905261010083019190915261012082015282526000199092019101816141375790505b50915060005b81811015611d645760008582815181106141bc576141bc6150c6565b6020026020010151905060008160e0015182610120015160ff16815181106141e6576141e66150c6565b6020026020010151905060405180610140016040528083600001518152602001836020015161ffff168152602001836040015161ffff16815260200183606001518152602001836080015160ff1681526020018360a0015160020b81526020018360c0015162ffffff16815260200183610120015160ff16815260200161426d8884613f02565b61427f89670de0b6b3a7640000614ce4565b614289919061553a565b61429b670de0b6b3a764000085615112565b6142a59190615129565b815260200183610140015184610120015160ff16815181106142c9576142c96150c6565b60200260200101518152508584815181106142e6576142e66150c6565b60200260200101819052505050806142fd9061514b565b90506141a0565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116614371576040516330be1a3d60e21b815260040160405180910390fd5b919050565b600061438b6001600160a01b038416836143d0565b905080516000141580156143b05750808060200190518101906143ae91906150a9565b155b15610f0f5782604051635274afe760e01b81526004016108fc91906145d4565b6060612d218383600084600080856001600160a01b031684866040516143f6919061581a565b60006040518083038185875af1925050503d8060008114614433576040519150601f19603f3d011682016040523d82523d6000602084013e614438565b606091505b5091509150614448868383614452565b9695505050505050565b60608261446757614462826144a5565b613574565b815115801561447e57506001600160a01b0384163b155b1561449e5783604051639996b31560e01b81526004016108fc91906145d4565b5080613574565b8051156144b55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f8401126144e057600080fd5b5081356001600160401b038111156144f757600080fd5b6020830191508360208260051b850101111561451257600080fd5b9250929050565b6001600160a01b0381168114610bb457600080fd5b8015158114610bb457600080fd5b60008060008060008060008060e0898b03121561455857600080fd5b88356001600160401b0381111561456e57600080fd5b61457a8b828c016144ce565b90995097505060208901359550604089013594506060890135935060808901356145a381614519565b925060a08901356145b381614519565b915060c08901356145c38161452e565b809150509295985092959890939650565b6001600160a01b0391909116815260200190565b6000602082840312156145fa57600080fd5b813561357481614519565b60006020828403121561461757600080fd5b81356135748161452e565b600080600080600080600060c0888a03121561463d57600080fd5b87356001600160401b0381111561465357600080fd5b61465f8a828b016144ce565b9098509650506020880135945060408801359350606088013561468181614519565b9250608088013561469181614519565b915060a08801356146a181614519565b8091505092959891949750929550565b6000602082840312156146c357600080fd5b5035919050565b60008060008060008060c087890312156146e357600080fd5b86356146ee81614519565b955060208701356146fe81614519565b9450604087013561470e81614519565b9350606087013561471e81614519565b9250608087013561472e81614519565b915060a087013561473e81614519565b809150509295509295509295565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156147845761478461474c565b60405290565b60405161016081016001600160401b03811182821017156147845761478461474c565b604051601f8201601f191681016001600160401b03811182821017156147d5576147d561474c565b604052919050565b60006001600160401b038211156147f6576147f661474c565b5060051b60200190565b600082601f83011261481157600080fd5b81356020614826614821836147dd565b6147ad565b82815260059290921b8401810191818101908684111561484557600080fd5b8286015b848110156148605780358352918301918301614849565b509695505050505050565b6000806040838503121561487e57600080fd5b82356001600160401b038082111561489557600080fd5b6148a186838701614800565b935060208501359150808211156148b757600080fd5b506148c485828601614800565b9150509250929050565b6000806000806000608086880312156148e657600080fd5b85356001600160401b038111156148fc57600080fd5b614908888289016144ce565b90965094505060208601359250604086013561492381614519565b915060608601356149338161452e565b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b600060c082018883526020888185015287604085015260c0606085015281875180845260e086019150828901935060005b818110156149a457845183529383019391830191600101614988565b5050809350505050836080830152600383106149c2576149c2614941565b8260a0830152979650505050505050565b803560ff8116811461437157600080fd5b60008060008060008060008060006101008a8c031215614a0357600080fd5b89356001600160401b03811115614a1957600080fd5b614a258c828d016144ce565b909a5098505060208a0135965060408a0135955060608a0135945060808a0135614a4e81614519565b935060a08a0135614a5e81614519565b925060c08a0135614a6e8161452e565b9150614a7c60e08b016149d3565b90509295985092959850929598565b60008060408385031215614a9e57600080fd5b50508035926020909101359150565b60008060408385031215614ac057600080fd5b8235614acb81614519565b91506020830135614adb81614519565b809150509250929050565b60008060008060008060a08789031215614aff57600080fd5b86356001600160401b03811115614b1557600080fd5b614b2189828a016144ce565b909750955050602087013593506040870135614b3c81614519565b92506060870135614b4c8161452e565b9150614b5a608088016149d3565b90509295509295509295565b600080600060608486031215614b7b57600080fd5b8335614b8681614519565b92506020840135614b9681614519565b91506040840135614ba681614519565b809150509250925092565b60008060208385031215614bc457600080fd5b82356001600160401b03811115614bda57600080fd5b614be6858286016144ce565b90969095509350505050565b60008060008060808587031215614c0857600080fd5b8435614c1381614519565b93506020850135614c2381614519565b9250604085013591506060850135614c3a81614519565b939692955090935050565b60038110610bb457600080fd5b60008060408385031215614c6557600080fd5b8235614c7081614519565b91506020830135614adb81614c45565b600081518084526020808501945080840160005b83811015614cb057815187529582019590820190600101614c94565b509495945050505050565b602081526000612d216020830184614c80565b634e487b7160e01b600052601160045260246000fd5b80820180821115612d2457612d24614cce565b6020808252603c908201527f5468697320616374696f6e2063616e6e6f7420626520706572666f726d65642060408201527f7768696c652074686520636f6e74726163742069732070617573656400000000606082015260800190565b803561ffff8116811461437157600080fd5b8035600281900b811461437157600080fd5b803562ffffff8116811461437157600080fd5b600082601f830112614d9c57600080fd5b81356020614dac614821836147dd565b82815260059290921b84018101918181019086841115614dcb57600080fd5b8286015b848110156148605780356001600160401b03811115614dee5760008081fd5b8701603f81018913614e005760008081fd5b848101356040614e12614821836147dd565b8281526060928302840182019288820191908d851115614e325760008081fd5b948301945b84861015614e8f5780868f031215614e4f5760008081fd5b614e57614762565b614e6087614d54565b8152614e6d8b88016149d3565b8b820152614e7c858801614d66565b8186015283529485019491890191614e37565b50875250505092840192508301614dcf565b6000614eaf614821846147dd565b80848252602080830192508560051b850136811115614ecd57600080fd5b855b818110156150065780356001600160401b0380821115614eef5760008081fd5b81890191506101608236031215614f065760008081fd5b614f0e61478a565b82358152614f1d868401614d54565b868201526040614f2e818501614d54565b90820152606083810135908201526080614f498185016149d3565b9082015260a0614f5a848201614d66565b9082015260c0614f6b848201614d78565b9082015260e08381013583811115614f835760008081fd5b614f8f36828701614800565b8284015250506101008084013583811115614faa5760008081fd5b614fb636828701614800565b828401525050610120614fca8185016149d3565b908201526101408381013583811115614fe35760008081fd5b614fef36828701614d8b565b918301919091525087525050938201938201614ecf565b50919695505050505050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561507557600080fd5b5051919050565b6001600160a01b0383168152604081016004831061509c5761509c614941565b8260208301529392505050565b6000602082840312156150bb57600080fd5b81516135748161452e565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156150ee57600080fd5b815161357481614519565b6001600160a01b03929092168252602082015260400190565b8082028115828204841417612d2457612d24614cce565b60008261514657634e487b7160e01b600052601260045260246000fd5b500490565b60006001820161515d5761515d614cce565b5060010190565b602080825260179082015276082e0e0e4deeccac840e2eadee8ca40dad2e6dac2e8c6d604b1b604082015260600190565b600081518084526020808501945080840160005b83811015614cb0578151805161ffff1688528381015160ff168489015260409081015160020b90880152606090960195908201906001016151a9565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389528151610140815186528682015161522c8888018261ffff169052565b5060408281015161ffff16908701526060808301519087015260808083015160ff169087015260a080830151600281900b82890152505060c08281015162ffffff169087015260e08083015160ff16908701526101008083015190870152610120918201519186018190526152a381870183615195565b9a87019a9550505090840190600101615203565b5091979650505050505050565b60208152600082516101608060208501526152e36101808501836151e5565b9150602085015160408501526040850151606085015260608501516080850152608085015161531d60a08601826001600160a01b03169052565b5060a08501516001600160a01b03811660c08601525060c08501516001600160a01b03811660e08601525060e08501516101008581019190915285015161012061536a8187018315159052565b86015190506101406153808682018360ff169052565b90950151151593019290925250919050565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389526153c8848351615195565b988501989350908401906001016153b0565b60006101608251845260208301516153f8602086018261ffff169052565b50604083015161540e604086018261ffff169052565b5060608301516060850152608083015161542d608086018260ff169052565b5060a083015161544260a086018260020b9052565b5060c083015161545960c086018262ffffff169052565b5060e08301518160e086015261547182860182614c80565b915050610100808401518583038287015261548c8382614c80565b92505050610120808401516154a58287018260ff169052565b505061014080840151858303828701526144488382615392565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389526154f58483516153da565b988501989350908401906001016154dd565b60608152600061551a60608301866154bf565b6001600160a01b0394851660208401529290931660409091015292915050565b81810381811115612d2457612d24614cce565b60a08152600061556060a08301886151e5565b6001600160a01b0396909616602083015250604081019390935260608301919091521515608090910152919050565b600181815b808511156155ca5781600019048211156155b0576155b0614cce565b808516156155bd57918102915b93841c9390800290615594565b509250929050565b6000826155e157506001612d24565b816155ee57506000612d24565b8160018114615604576002811461560e5761562a565b6001915050612d24565b60ff84111561561f5761561f614cce565b50506001821b612d24565b5060208310610133831016604e8410600b841016171561564d575081810a612d24565b615657838361558f565b806000190482111561566b5761566b614cce565b029392505050565b6000612d2183836155d2565b60408152600061569260408301856153da565b90508260208301529392505050565b6080815260006156b460808301876154bf565b60ff959095166020830152506040810192909252606090910152919050565b600080604083850312156156e657600080fd5b505080516020909101519092909150565b60808152600061570a60808301876154bf565b602083019590955250911515604083015260ff16606090910152919050565b6000806040838503121561573c57600080fd5b825161574781614c45565b809250506020808401516001600160401b0381111561576557600080fd5b8401601f8101861361577657600080fd5b8051615784614821826147dd565b81815260059190911b820183019083810190888311156157a357600080fd5b928401925b828410156157ca5783516157bb8161452e565b825292840192908401906157a8565b80955050505050509250929050565b60c0815260006157ec60c08301896154bf565b6020830197909752506040810194909452911515606084015260ff166080830152151560a090910152919050565b6000825160005b8181101561583b5760208186018101518583015201615821565b50600092019182525091905056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca264697066735822122001d222d0729a5101b73b0bc400952abd0a3d1f18640222f9c1e262674629c70464736f6c63430008140033
Deployed Bytecode
0x60806040526004361061028c5760003560e01c806391b4ded91161015a578063c3b83f5f116100c1578063e6d1c8a61161007a578063e6d1c8a6146107ed578063ebc797721461080d578063f453ea7d14610822578063f5bf372e14610842578063f8a940b01461086f578063fd47e5ec1461088f57600080fd5b8063c3b83f5f1461072d578063c4d66de81461074d578063ce18a8371461076d578063d3dc75391461078d578063d43b3576146107ad578063e481a342146107cd57600080fd5b8063aeb0f16411610113578063aeb0f16414610657578063b4e7e5c614610677578063b6a3670414610697578063b8e15ed0146106b7578063c2c9e276146106ed578063c301086c1461070d57600080fd5b806391b4ded9146105ae57806393b0c2ae146105c4578063942b67dc146105d75780639a23be78146105f75780639a618c0f14610617578063ace81b711461063757600080fd5b806347842663116101fe5780636cfb6bf9116101b75780636cfb6bf9146104e75780636dbf6cc7146105075780637649226c1461052757806379ba5097146105595780638da5cb5b1461056e5780638ff9d5cf1461058e57600080fd5b80634784266314610410578063481c6a751461043057806348663e951461045057806350631ddc1461047057806353a47bb71461049d5780635c975abb146104bd57600080fd5b80631627540c116102505780631627540c1461034357806316c38b3c14610363578063177957a81461038357806329cf5368146103b957806338ea7103146103cc57806344cab7ee146103f057600080fd5b8063014e17b01461029857806304de96c5146102c15780630ca08207146102e15780630fe621901461030357806313af40351461032357600080fd5b3661029357005b600080fd5b6102ab6102a636600461453c565b6108bc565b6040516102b891906145d4565b60405180910390f35b3480156102cd57600080fd5b506013546102ab906001600160a01b031681565b3480156102ed57600080fd5b506103016102fc3660046145e8565b61096b565b005b34801561030f57600080fd5b506017546102ab906001600160a01b031681565b34801561032f57600080fd5b5061030161033e3660046145e8565b6109e6565b34801561034f57600080fd5b5061030161035e3660046145e8565b610af2565b34801561036f57600080fd5b5061030161037e366004614605565b610b45565b34801561038f57600080fd5b506102ab61039e3660046145e8565b6008602052600090815260409020546001600160a01b031681565b6102ab6103c7366004614622565b610bb7565b3480156103d857600080fd5b506103e260105481565b6040519081526020016102b8565b3480156103fc57600080fd5b506018546102ab906001600160a01b031681565b34801561041c57600080fd5b50600b546102ab906001600160a01b031681565b34801561043c57600080fd5b50600a546102ab906001600160a01b031681565b34801561045c57600080fd5b50600f546102ab906001600160a01b031681565b34801561047c57600080fd5b506103e261048b3660046146b1565b60066020526000908152604090205481565b3480156104a957600080fd5b506001546102ab906001600160a01b031681565b3480156104c957600080fd5b506003546104d79060ff1681565b60405190151581526020016102b8565b3480156104f357600080fd5b506103016105023660046146ca565b610cb1565b34801561051357600080fd5b5061030161052236600461486b565b610df3565b34801561053357600080fd5b506105476105423660046148ce565b610f14565b6040516102b896959493929190614957565b34801561056557600080fd5b50610301610f52565b34801561057a57600080fd5b506000546102ab906001600160a01b031681565b34801561059a57600080fd5b50600c546102ab906001600160a01b031681565b3480156105ba57600080fd5b506103e260025481565b6102ab6105d23660046149e4565b61102a565b3480156105e357600080fd5b506103016105f2366004614a8b565b611108565b34801561060357600080fd5b50610301610612366004614aad565b6111c0565b34801561062357600080fd5b506011546102ab906001600160a01b031681565b34801561064357600080fd5b50610547610652366004614ae6565b61122a565b34801561066357600080fd5b506007546102ab906001600160a01b031681565b34801561068357600080fd5b50610301610692366004614b66565b611269565b3480156106a357600080fd5b50600e546102ab906001600160a01b031681565b3480156106c357600080fd5b506102ab6106d23660046145e8565b6016602052600090815260409020546001600160a01b031681565b3480156106f957600080fd5b50610301610708366004614bb1565b6112f5565b34801561071957600080fd5b506103016107283660046145e8565b611497565b34801561073957600080fd5b506103016107483660046145e8565b6114ea565b34801561075957600080fd5b506103016107683660046145e8565b6115da565b34801561077957600080fd5b506014546102ab906001600160a01b031681565b34801561079957600080fd5b50600d546102ab906001600160a01b031681565b3480156107b957600080fd5b506103016107c8366004614bf2565b6116e4565b3480156107d957600080fd5b506102ab6107e8366004614622565b6117ee565b3480156107f957600080fd5b50610301610808366004614aad565b6118c1565b34801561081957600080fd5b50610301611a4e565b34801561082e57600080fd5b5061030161083d3660046146b1565b611aac565b34801561084e57600080fd5b506103e261085d3660046145e8565b60156020526000908152604090205481565b34801561087b57600080fd5b5061030161088a366004614c52565b611ae9565b34801561089b57600080fd5b506108af6108aa366004614bb1565b611cc1565b6040516102b89190614cbb565b60006001600460008282546108d19190614ce4565b909155505060045460035460ff16156109055760405162461bcd60e51b81526004016108fc90614cf7565b60405180910390fd5b61093b6109128a8c614ea1565b60408051606081018252600080825260208201819052918101919091528a8a8a8a8a8a33611d6c565b9150600454811461095e5760405162461bcd60e51b81526004016108fc90615012565b5098975050505050505050565b610973611e4b565b600754601154610990916001600160a01b03908116911683611ebf565b601180546001600160a01b0319166001600160a01b0383161790556040517f7d16d7e66eb2263f48c2c24af20e095395796ce3d05df64d84d9991a4d436247906109db9083906145d4565b60405180910390a150565b6001600160a01b038116610a385760405162461bcd60e51b815260206004820152601960248201527804f776e657220616464726573732063616e6e6f74206265203603c1b60448201526064016108fc565b600154600160a01b900460ff1615610aa45760405162461bcd60e51b815260206004820152602960248201527f416c726561647920696e697469616c697a65642c20757365206e6f6d696e617460448201526832a732bba7bbb732b960b91b60648201526084016108fc565b6001805460ff60a01b1916600160a01b179055600080546001600160a01b0383166001600160a01b031990911617815560405160008051602061584a833981519152916109db918490615049565b610afa611e4b565b600180546001600160a01b0319166001600160a01b0383161790556040517f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906109db9083906145d4565b610b4d611e4b565b60035460ff16151581151514610bb4576003805460ff191682151590811790915560ff1615610b7b57426002555b60035460405160ff909116151581527f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5906020016109db565b50565b6000600160046000828254610bcc9190614ce4565b909155505060045460035460ff1615610bf75760405162461bcd60e51b81526004016108fc90614cf7565b846001600160a01b038116610c1f576040516328f6040160e21b815260040160405180910390fd5b6018546001600160a01b03163314610c4a57604051637bcec4fb60e01b815260040160405180910390fd5b610c81610c578a8c614ea1565b60408051606081018252600080825260016020830152918101829052908b908b908a8a828e611d6c565b9250506004548114610ca55760405162461bcd60e51b81526004016108fc90615012565b50979650505050505050565b610cb9611e4b565b600780546001600160a01b0319166001600160a01b0388169081179091556040805163313ce56760e01b8152905163313ce567916004808201926020929091908290030181865afa158015610d12573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d369190615063565b600955600a80546001600160a01b038781166001600160a01b03199283168117909355600b80548883169084168117909155600c80548884169085168117909155600d80548885169086168117909155600f805488861696168617905560408051948d1685526020850196909652948301919091526060820152608081019290925260a08201527f1962de5c532b26a8a72c8524fe745d05421f16a6521fc531ce010572f742a6939060c0015b60405180910390a1505050505050565b600a5460405163e760c39560e01b81526001600160a01b039091169063e760c39590610e2690339060009060040161507c565b602060405180830381865afa158015610e43573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6791906150a9565b158015610e7f57506000546001600160a01b03163314155b15610e9d57604051636edaef2f60e11b815260040160405180910390fd5b8051825114610ebf5760405163251f56a160e21b815260040160405180910390fd5b60005b8251811015610f0f57610f07838281518110610ee057610ee06150c6565b6020026020010151838381518110610efa57610efa6150c6565b6020026020010151611fca565b600101610ec2565b505050565b60008060006060600080610f2d8b8b8b8b8b6000612019565b809650819750829850839950849a50859b505050505050509550955095509550955095565b6001546001600160a01b03163314610fca5760405162461bcd60e51b815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527402063616e20616363657074206f776e65727368697605c1b60648201526084016108fc565b60005460015460405160008051602061584a83398151915292610ffb926001600160a01b0391821692911690615049565b60405180910390a160018054600080546001600160a01b03199081166001600160a01b03841617909155169055565b600060016004600082825461103f9190614ce4565b909155505060045460035460ff161561106a5760405162461bcd60e51b81526004016108fc90614cf7565b60018360ff16111580611080575060ff83168a11155b1561109e57604051631a0a722b60e01b815260040160405180910390fd5b6110d76110ab8b8d614ea1565b6040805160608101825260ff87168152600060208201819052918101919091528b8b8b8b8b8b33611d6c565b915060045481146110fa5760405162461bcd60e51b81526004016108fc90615012565b509998505050505050505050565b600a5460405163e760c39560e01b81526001600160a01b039091169063e760c3959061113b90339060009060040161507c565b602060405180830381865afa158015611158573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117c91906150a9565b15801561119457506000546001600160a01b03163314155b156111b257604051636edaef2f60e11b815260040160405180910390fd5b6111bc8282611fca565b5050565b6111c8611e4b565b604051634946980760e11b81526001600160a01b0383169063928d300e906111f49084906004016145d4565b600060405180830381600087803b15801561120e57600080fd5b505af1158015611222573d6000803e3d6000fd5b505050505050565b600080600060606000806112428c8c8c8c8c8c612019565b809650819750829850839950849a50859b5050505050505096509650965096509650969050565b611271611e4b565b601380546001600160a01b038581166001600160a01b0319928316811790935560188054868316908416811790915560148054928616929093168217909255604080519384526020840192909252908201527f2b8bc92a77df3bf6abc793bbc13c813f4e0028dd6de7aefb204a96ade4ddc4739060600160405180910390a1505050565b6112fd611e4b565b60005b81811015610f0f57600083838381811061131c5761131c6150c6565b905060200201602081019061133191906145e8565b90506000816001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611372573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139691906150dc565b6014549091506001600160a01b038083169116148015906113c557506017546001600160a01b03828116911614155b1561148d5760405163646d919f60e11b81526001600160a01b0383169063c8db233e906113f69033906004016145d4565b600060405180830381600087803b15801561141057600080fd5b505af1158015611424573d6000803e3d6000fd5b5050600a5460405163f033d0f960e01b81526001600160a01b03909116925063f033d0f9915061145a9085908590600401615049565b600060405180830381600087803b15801561147457600080fd5b505af1158015611488573d6000803e3d6000fd5b505050505b5050600101611300565b61149f611e4b565b600e80546001600160a01b0319166001600160a01b0383161790556040517fab496e3942a33c5a729be5985af46209e18077a462af550b750246460950eb7f906109db9083906145d4565b6114f2611e4b565b6001600160a01b03811661153a5760405162461bcd60e51b815260206004820152600f60248201526e496e76616c6964206164647265737360881b60448201526064016108fc565b600154600160a81b900460ff161561158a5760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481d1c985b9cd9995c9c9959606a1b60448201526064016108fc565b600080546001600160a01b0383166001600160a01b031990911681179091556001805460ff60a81b1916600160a81b17905560405160008051602061584a833981519152916109db918490615049565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff1615906001600160401b031660008115801561161f5750825b90506000826001600160401b0316600114801561163b5750303b155b905081158015611649575080155b156116675760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561169157845460ff60401b1916600160401b1785555b61169a866109e6565b6116a2611a4e565b831561122257845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602001610de3565b6116ec611e4b565b6001600160a01b03848116600090815260086020526040902054811690841614611766576001600160a01b038085166000908152600860205260409020546117379186911685611ebf565b6001600160a01b03848116600090815260086020526040902080546001600160a01b0319169185169190911790555b6001600160a01b038481166000818152601560209081526040808320879055601682529182902080546001600160a01b031916868616908117909155825193845293871690830152810184905260608101919091527f2083b2a6d9c12b8cd65a8a4d92a82708aac25a81a524e9d13e92559bf818db569060800160405180910390a150505050565b60006001600460008282546118039190614ce4565b909155505060045460035460ff161561182e5760405162461bcd60e51b81526004016108fc90614cf7565b846001600160a01b038116611856576040516328f6040160e21b815260040160405180910390fd5b6013546001600160a01b0316331461188157604051637bcec4fb60e01b815260040160405180910390fd5b610c8161188e8a8c614ea1565b6040518060600160405280600060ff168152602001600015158152602001600115158152508a8a60008a8a60008e611d6c565b6001600460008282546118d49190614ce4565b909155505060045460035460ff16156118ff5760405162461bcd60e51b81526004016108fc90614cf7565b600a546040516321875b5760e01b815284916001600160a01b0316906321875b579061192f9084906004016145d4565b602060405180830381865afa15801561194c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061197091906150a9565b61198d57604051634f8c20e160e01b815260040160405180910390fd5b836001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119ee91906150dc565b6001600160a01b0316336001600160a01b031614611a1f5760405163bba02e7160e01b815260040160405180910390fd5b611a2c8484600080612264565b506004548114610f0f5760405162461bcd60e51b81526004016108fc90615012565b60055460ff1615611a975760405162461bcd60e51b8152602060048201526013602482015272105b1c9958591e481a5b9a5d1a585b1a5e9959606a1b60448201526064016108fc565b6005805460ff19166001908117909155600455565b611ab4611e4b565b60108190556040518181527f5da87bc83066ddf563cfd9de25e562860f147b358751f50766847996202e5d33906020016109db565b600160046000828254611afc9190614ce4565b909155505060045460035460ff1615611b275760405162461bcd60e51b81526004016108fc90614cf7565b600a546040516321875b5760e01b815284916001600160a01b0316906321875b5790611b579084906004016145d4565b602060405180830381865afa158015611b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b9891906150a9565b611bb557604051634f8c20e160e01b815260040160405180910390fd5b6000836002811115611bc957611bc9614941565b14611c5f57600a5460405163e760c39560e01b81526001600160a01b039091169063e760c39590611c0190339060029060040161507c565b602060405180830381865afa158015611c1e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c4291906150a9565b611c5f57604051637830359760e01b815260040160405180910390fd5b6001836002811115611c7357611c73614941565b03611c8c57611c8784600060016000612264565b611a2c565b6002836002811115611ca057611ca0614941565b03611cb357611c87846000806001612264565b611a2c846000806000612264565b606081806001600160401b03811115611cdc57611cdc61474c565b604051908082528060200260200182016040528015611d05578160200160208202803683370190505b50915060005b81811015611d645760066000868684818110611d2957611d296150c6565b90506020020135815260200190815260200160002054838281518110611d5157611d516150c6565b6020908102919091010152600101611d0b565b505092915050565b6000861580611d79575087155b15611d975760405163d1892e7760e01b815260040160405180910390fd5b611da185836128a7565b600080611db08a878688612904565b604080516101208101909152828152919d5098509193509150611e3b908d9060208101611ddd8e8e612d02565b81526020018b8152602001876001600160a01b031681526020018e6040015115158152602001896001600160a01b03168152602001856001600160a01b031681526020018481526020018e6020015115158152508d60000151612d2a565b9c9b505050505050505050505050565b6000546001600160a01b03163314611ebd5760405162461bcd60e51b815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201526e37b936903a3434b99030b1ba34b7b760891b60648201526084016108fc565b565b6001600160a01b03821615611f425760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390611efd9085906000906004016150f9565b6020604051808303816000875af1158015611f1c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f4091906150a9565b505b6001600160a01b03811615610f0f5760405163095ea7b360e01b81526001600160a01b0384169063095ea7b390611f81908490600019906004016150f9565b6020604051808303816000875af1158015611fa0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fc491906150a9565b50505050565b60008281526006602090815260409182902083905581518481529081018390527fc6fa3d673d901ef180e5a314ff8ede38ac8ba226ce71c9d822ed8a438020a1ab910160405180910390a15050565b6000808060608782816001600160a01b038a161580159061204857506007546001600160a01b038b8116911614155b156121cd576001600160a01b03808b1660009081526008602052604090205416806120fb57601160009054906101000a90046001600160a01b03166001600160a01b031663cb4ba5248c8e6040518363ffffffff1660e01b81526004016120b09291906150f9565b602060405180830381865afa1580156120cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120f19190615063565b93508391506121cb565b6121c88c826001600160a01b031663f7683bbc6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561213d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121619190615063565b8d6001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801561219f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c39190615063565b61357b565b93505b505b806000036121ee57604051631f2a200560e01b815260040160405180910390fd5b6122406121fb8d8f614ea1565b6040805160e081018252848152600160208201529081018690526001600160a01b038d1660608201528b15156080820152600060a0820181905260c08201528a6135f1565b809650819850829950839a50849b5050505050505096509650965096509650969050565b83600082156122d857816001600160a01b0316636a265aa96040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122d19190615063565b9050612390565b831561231e57816001600160a01b031663ea8a1af06040518163ffffffff1660e01b81526004016020604051808303816000875af11580156122ad573d6000803e3d6000fd5b604051630d8acc1560e11b81526001600160a01b03831690631b15982a9061234a9088906004016145d4565b6020604051808303816000875af1158015612369573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061238d9190615063565b90505b6000826001600160a01b031663d8dfeb456040518163ffffffff1660e01b8152600401602060405180830381865afa1580156123d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123f491906150dc565b90506000836001600160a01b031662641e8b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612435573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061245991906150dc565b6014549091506001600160a01b038083169116148061248557506017546001600160a01b038281169116145b156124e95760405163509eb5b560e11b81526001600160a01b0382169063a13d6b6a906124b6908b906004016145d4565b600060405180830381600087803b1580156124d057600080fd5b505af11580156124e4573d6000803e3d6000fd5b505050505b836001600160a01b0316639a82a09a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612527573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061254b91906150a9565b6125bd576125bb846001600160a01b031663d165dac26040518163ffffffff1660e01b8152600401602060405180830381865afa158015612590573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b49190615063565b8284613b53565b505b600a546040516306ef036760e01b81526001600160a01b03909116906306ef0367906125ef908b908590600401615049565b600060405180830381600087803b15801561260957600080fd5b505af115801561261d573d6000803e3d6000fd5b505050507f1a208f07d825103c5b1eb3bb1109b420fd544123300beb9e220fc951cbd7dd0b8882866001600160a01b0316633356a35a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612682573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126a691906150a9565b604080516001600160a01b03948516815293909216602084015215159082015260600160405180910390a16000831180156126e957506001600160a01b03871615155b80156127075750816001600160a01b0316876001600160a01b031614155b156127c6576007546001600160a01b0383811691161461273a5760405163c6338d5560e01b815260040160405180910390fd5b601154604051630992646d60e31b81526127c69183916001600160a01b0390911690634c93236890612772908c9089906004016150f9565b6020604051808303816000875af1158015612791573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b59190615063565b6001600160a01b038a169190613e37565b6001600160a01b03808316600081815260086020526040908190205490516370a0823160e01b815292169163d7efa129918b916370a082319061280d9030906004016145d4565b602060405180830381865afa15801561282a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061284e9190615063565b6040518363ffffffff1660e01b815260040161286b9291906150f9565b600060405180830381600087803b15801561288557600080fd5b505af1158015612899573d6000803e3d6000fd5b505050505050505050505050565b6001600160a01b038216158015906128cd57506014546001600160a01b03828116911614155b156111bc57600d5460405163bbddaca360e01b81526001600160a01b039091169063bbddaca3906111f49085908590600401615049565b60008085816001600160a01b038716158061292c57506007546001600160a01b038881169116145b1561294f57506007546001600160a01b031661294a8187308b613e8f565b612cd9565b50858415612a6457601160009054906101000a90046001600160a01b03166001600160a01b0316634aa4a4fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156129aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129ce91906150dc565b6001600160a01b0316876001600160a01b03161415806129ed57508734105b15612a0b57604051634f4d1d8760e01b815260040160405180910390fd5b866001600160a01b031663d0e30db0346040518263ffffffff1660e01b81526004016000604051808303818588803b158015612a4657600080fd5b505af1158015612a5a573d6000803e3d6000fd5b5050505050612a79565b612a796001600160a01b03881687308b613e8f565b6001600160a01b038088166000908152600860205260409020541693508315612b2157836001600160a01b031663f7683bbc6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612ada573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612afe9190615063565b92508260000361294a5760405163577f86e160e11b815260040160405180910390fd5b6011546001600160a01b0316612b4a57604051630d5f109960e21b815260040160405180910390fd5b60115460405163095ea7b360e01b81526001600160a01b038981169263095ea7b392612b7e92909116908c906004016150f9565b6020604051808303816000875af1158015612b9d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612bc191906150a9565b506011546040516322ceb11360e21b81526001600160a01b0390911690638b3ac44c90612bf4908a908c906004016150f9565b6020604051808303816000875af1158015612c13573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c379190615063565b6011546040516332d2e94960e21b81529193506001600160a01b03169063cb4ba52490612c6a908a908c906004016150f9565b602060405180830381865afa158015612c87573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612cab9190615063565b821015612ccb5760405163a3b7d2e560e01b815260040160405180910390fd5b506007546001600160a01b03165b6001600160a01b0380821660009081526008602052604090205416989297509095509350915050565b600081612d1784670de0b6b3a7640000615112565b612d219190615129565b90505b92915050565b6000612d5e6040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b60a08401516001600160a01b031660009081526015602052604090205460608201526080840151612e0b57612df8856040518060e0016040528087600001518152602001600015158152602001600081526020018760a001516001600160a01b0316815260200187608001511515815260200187610100015115158152602001612df088600001518960200151612d02565b9052856135f1565b5050604084015260208301528152613185565b84516060820151602086015160009015612e3657612e3187600001518860200151612d02565b612e39565b60005b90506000600b60009054906101000a90046001600160a01b03166001600160a01b031663e88698bf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612e90573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612eb49190615063565b905083600103612f3d57600089600081518110612ed357612ed36150c6565b602002602001015160e001518a600081518110612ef257612ef26150c6565b6020026020010151610120015160ff1681518110612f1257612f126150c6565b602002602001015190506000612f288286613ec8565b905082811015612f355750815b865250613153565b60008060005b868110156130535760008c8281518110612f5f57612f5f6150c6565b6020026020010151905080610120015160ff168160e001515111612f965760405163673f032f60e11b815260040160405180910390fd5b60008160e0015182610120015160ff1681518110612fb657612fb66150c6565b6020026020010151905060008111612fff5760405162461bcd60e51b815260206004820152600c60248201526b16995c9bc81b1959c81bd91960a21b60448201526064016108fc565b84156130145761300f8582613f02565b613016565b805b94506000613024828a613ec8565b9050841561303b576130368582613f02565b61303d565b805b94505050508061304c9061514b565b9050612f43565b5064e8d4a510008461309c5760405162461bcd60e51b815260206004820152601260248201527142616420617070726f7665642071756f746560701b60448201526064016108fc565b838210156130f45760006130b08587613f17565b905081866130c6670de0b6b3a764000084615112565b6130d09190615129565b11156130ee5760405162461bcd60e51b81526004016108fc90615164565b50613140565b60006131008487613f17565b90508186613116670de0b6b3a764000084615112565b6131209190615129565b111561313e5760405162461bcd60e51b81526004016108fc90615164565b505b8188528382101561314f578388525b5050505b875185516131619190612d02565b6020860152875161317190613f3a565b604086015250505060208083015190860152505b806040015181602001516131999190614ce4565b6080820152805160208201516131b29187918787613f5d565b60006131c28683606001516140fc565b600e549091506000906131dd906001600160a01b0316614304565b9050806001600160a01b031663b5ac8d98604051806101600160405280858152602001896000015181526020018660400151815260200186600001518152602001306001600160a01b0316815260200189606001516001600160a01b031681526020018960a001516001600160a01b03168152602001600b60009054906101000a90046001600160a01b03166001600160a01b031663b3ee14246040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132a6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132ca9190615063565b6132d49042614ce4565b81526020018960800151151581526020018860ff16815260200189610100015115158152506040518263ffffffff1660e01b815260040161331591906152c4565b600060405180830381600087803b15801561332f57600080fd5b505af1158015613343573d6000803e3d6000fd5b5050600a54606089015160405163514dd41d60e11b81526001600160a01b03909216935063a29ba83a925061337e918b918691600401615507565b600060405180830381600087803b15801561339857600080fd5b505af11580156133ac573d6000803e3d6000fd5b505050508560c001516001600160a01b03166358c09cc082886000015186608001516133d8919061553a565b6040518363ffffffff1660e01b81526004016133f59291906150f9565b600060405180830381600087803b15801561340f57600080fd5b505af1158015613423573d6000803e3d6000fd5b505050608084015160a088015161344692506001600160a01b0316908390613e37565b608083015160405163242c6c2d60e01b815260048101919091526001600160a01b0382169063242c6c2d90602401600060405180830381600087803b15801561348e57600080fd5b505af11580156134a2573d6000803e3d6000fd5b505050507fece8b280c05fcdb1e6f073f39266f576f9ee1f91bfe098dbb5f7b5e3dce305ba8282886000015186602001518a608001516040516134e995949392919061554d565b60405180910390a16060868101518751604086810151602080890151895160a0808f015186516001600160a01b038c81168252998a16958101959095528487019790975297830193909352608082015294850152911660c0830152517fddd6ef4a731d70ec093d7f6a82160e586a40dde73b44129dcb771a5b64557d8a9181900360e00190a1925050505b9392505050565b60006135878484613f02565b90506009548210156135bd57816009546135a1919061553a565b6135ac90600a615673565b6135b69082615112565b9050613574565b600954821115613574576009546135d4908361553a565b6135df90600a615673565b6135e99082615129565b949350505050565b6000806000606060008088519050806001600160401b038111156136175761361761474c565b604051908082528060200260200182016040528015613640578160200160208202803683370190505b5092506000600b60009054906101000a90046001600160a01b03166001600160a01b031663e88698bf6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613698573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906136bc9190615063565b60608a01516001600160a01b0316600090815260156020526040812054919250600160ff8b161191905b848110156138f95760008d8281518110613702576137026150c6565b602090810291909101810151600b548151600090815260069093526040928390205492516311b3db5760e11b81529193506001600160a01b031691632367b6ae9161375191859160040161567f565b60006040518083038186803b15801561376957600080fd5b505afa15801561377d573d6000803e3d6000fd5b5050505080610120015160ff168160e0015151116137ae5760405163673f032f60e11b815260040160405180910390fd5b60008160e0015182610120015160ff16815181106137ce576137ce6150c6565b602002602001015190506137e28482613f02565b6137f485670de0b6b3a7640000614ce4565b6137fe919061553a565b613810670de0b6b3a764000083615112565b61381a9190615129565b8e519091506138298183612d02565b613833919061553a565b898481518110613845576138456150c6565b60200260200101818152505084156138cd57613869670de0b6b3a764000088615112565b8d60ff16670de0b6b3a76400008b8681518110613888576138886150c6565b602002602001015161389a9190615112565b6138a49190615112565b6138ae9190615129565b8984815181106138c0576138c06150c6565b6020026020010181815250505b8b156138e2576138dd8c82613f02565b6138e4565b805b9b505050806138f29061514b565b90506136e6565b508815613b4457811561399a57600b60009054906101000a90046001600160a01b03166001600160a01b031663ff527ee38d8c8e60000151856040518563ffffffff1660e01b815260040161395194939291906156a1565b6040805180830381865afa15801561396d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061399191906156d3565b995097506139ff565b8a60a00151156139f0578a60c0015198506139b5818a613f02565b6139c782670de0b6b3a7640000614ce4565b6139d1919061553a565b6139e3670de0b6b3a76400008b615112565b6139ed9190615129565b98505b8a516139fc908a612d02565b97505b82891015613a1b57829850613a188b600001518a612d02565b97505b8a51613a2690613f3a565b96508a6020015115613b44576060600b60009054906101000a90046001600160a01b03166001600160a01b031663c360aded8e8e604001518f608001518f6040518563ffffffff1660e01b8152600401613a8394939291906156f7565b600060405180830381865afa158015613aa0573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052613ac89190810190615729565b909650905060005b85811015613b2057818181518110613aea57613aea6150c6565b602002602001015115613b18576000888281518110613b0b57613b0b6150c6565b6020026020010181815250505b600101613ad0565b506000866002811115613b3557613b35614941565b14613b4257600098508899505b505b50505050939792965093509350565b600d54604051630293b59d60e31b8152600091829182916001600160a01b03169063149dace890613b889088906004016145d4565b602060405180830381865afa158015613ba5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613bc991906150dc565b90506000846001600160a01b03166370a08231306040518263ffffffff1660e01b8152600401613bf991906145d4565b602060405180830381865afa158015613c16573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c3a9190615063565b90506001600160a01b03821615801590613c6257506014546001600160a01b03878116911614155b15613d7057600d5460405163c7d1f5f160e01b81526000916001600160a01b03169063c7d1f5f190613c989086906004016145d4565b602060405180830381865afa158015613cb5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cd99190615063565b90508015613d6e57613ceb8882613f02565b9350838210613d6e57613d086001600160a01b0387168486613e37565b604080516001600160a01b0385811682528981166020830152818301879052606082018b90528816608082015290517f2f60e9c3fac363f0b03efb55d381f3d47475dbf1230e99201c9cdf4b9f577fc79181900360a00190a1613d6b848361553a565b91505b505b613d7987613f3a565b935082841115613e2d576000613d8f848661553a565b9050808210613e2b576001600160a01b0380871660009081526016602052604090205416613ddf81613dcc57600f546001600160a01b0316613dce565b815b6001600160a01b0389169084613e37565b60105460408051918252602082018490526001600160a01b03891682820152517f05b8bddc7eed21b7839baa291868ed966dd7299b79495dadd406c782b9770fe79181900360600190a1505b505b5050509392505050565b610f0f83846001600160a01b031663a9059cbb8585604051602401613e5d9291906150f9565b604051602081830303815290604052915060e01b6020820180516001600160e01b038381831617835250505050614376565b6040516001600160a01b038481166024830152838116604483015260648201839052611fc49186918216906323b872dd90608401613e5d565b6000613ed48284613f02565b613ee683670de0b6b3a7640000614ce4565b613ef0919061553a565b612d17670de0b6b3a764000085615112565b6000670de0b6b3a7640000612d178385615112565b600081831015613f3057613f2b838361553a565b612d21565b612d21828461553a565b6000670de0b6b3a764000060105483613f539190615112565b612d249190615129565b815160e0830151602084015181156140025760008560a001516001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015613fb3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fd79190615063565b9050613fe484848361357b565b9350613ff187848361357b565b9650613ffe82848361357b565b9150505b600b5460808601516101008701516040516354c0545160e01b81526001600160a01b03909316926354c0545192614046928d9289928d9290918c91906004016157d9565b600060405180830381600087803b15801561406057600080fd5b505af1158015614074573d6000803e3d6000fd5b5050600b546040888101518c5191516318542d5360e31b815260048101899052602481018d9052604481018c905260648101879052608481019190915260a48101919091526001600160a01b03909116925063c2a16a98915060c40160006040518083038186803b1580156140e857600080fd5b505afa158015612899573d6000803e3d6000fd5b8151606090806001600160401b038111156141195761411961474c565b60405190808252806020026020018201604052801561419a57816020015b60408051610140810182526000808252602080830182905292820181905260608083018290526080830182905260a0830182905260c0830182905260e0830182905261010083019190915261012082015282526000199092019101816141375790505b50915060005b81811015611d645760008582815181106141bc576141bc6150c6565b6020026020010151905060008160e0015182610120015160ff16815181106141e6576141e66150c6565b6020026020010151905060405180610140016040528083600001518152602001836020015161ffff168152602001836040015161ffff16815260200183606001518152602001836080015160ff1681526020018360a0015160020b81526020018360c0015162ffffff16815260200183610120015160ff16815260200161426d8884613f02565b61427f89670de0b6b3a7640000614ce4565b614289919061553a565b61429b670de0b6b3a764000085615112565b6142a59190615129565b815260200183610140015184610120015160ff16815181106142c9576142c96150c6565b60200260200101518152508584815181106142e6576142e66150c6565b60200260200101819052505050806142fd9061514b565b90506141a0565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008260601b60e81c176000526e5af43d82803e903d91602b57fd5bf38260781b17602052603760096000f090506001600160a01b038116614371576040516330be1a3d60e21b815260040160405180910390fd5b919050565b600061438b6001600160a01b038416836143d0565b905080516000141580156143b05750808060200190518101906143ae91906150a9565b155b15610f0f5782604051635274afe760e01b81526004016108fc91906145d4565b6060612d218383600084600080856001600160a01b031684866040516143f6919061581a565b60006040518083038185875af1925050503d8060008114614433576040519150601f19603f3d011682016040523d82523d6000602084013e614438565b606091505b5091509150614448868383614452565b9695505050505050565b60608261446757614462826144a5565b613574565b815115801561447e57506001600160a01b0384163b155b1561449e5783604051639996b31560e01b81526004016108fc91906145d4565b5080613574565b8051156144b55780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b60008083601f8401126144e057600080fd5b5081356001600160401b038111156144f757600080fd5b6020830191508360208260051b850101111561451257600080fd5b9250929050565b6001600160a01b0381168114610bb457600080fd5b8015158114610bb457600080fd5b60008060008060008060008060e0898b03121561455857600080fd5b88356001600160401b0381111561456e57600080fd5b61457a8b828c016144ce565b90995097505060208901359550604089013594506060890135935060808901356145a381614519565b925060a08901356145b381614519565b915060c08901356145c38161452e565b809150509295985092959890939650565b6001600160a01b0391909116815260200190565b6000602082840312156145fa57600080fd5b813561357481614519565b60006020828403121561461757600080fd5b81356135748161452e565b600080600080600080600060c0888a03121561463d57600080fd5b87356001600160401b0381111561465357600080fd5b61465f8a828b016144ce565b9098509650506020880135945060408801359350606088013561468181614519565b9250608088013561469181614519565b915060a08801356146a181614519565b8091505092959891949750929550565b6000602082840312156146c357600080fd5b5035919050565b60008060008060008060c087890312156146e357600080fd5b86356146ee81614519565b955060208701356146fe81614519565b9450604087013561470e81614519565b9350606087013561471e81614519565b9250608087013561472e81614519565b915060a087013561473e81614519565b809150509295509295509295565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b03811182821017156147845761478461474c565b60405290565b60405161016081016001600160401b03811182821017156147845761478461474c565b604051601f8201601f191681016001600160401b03811182821017156147d5576147d561474c565b604052919050565b60006001600160401b038211156147f6576147f661474c565b5060051b60200190565b600082601f83011261481157600080fd5b81356020614826614821836147dd565b6147ad565b82815260059290921b8401810191818101908684111561484557600080fd5b8286015b848110156148605780358352918301918301614849565b509695505050505050565b6000806040838503121561487e57600080fd5b82356001600160401b038082111561489557600080fd5b6148a186838701614800565b935060208501359150808211156148b757600080fd5b506148c485828601614800565b9150509250929050565b6000806000806000608086880312156148e657600080fd5b85356001600160401b038111156148fc57600080fd5b614908888289016144ce565b90965094505060208601359250604086013561492381614519565b915060608601356149338161452e565b809150509295509295909350565b634e487b7160e01b600052602160045260246000fd5b600060c082018883526020888185015287604085015260c0606085015281875180845260e086019150828901935060005b818110156149a457845183529383019391830191600101614988565b5050809350505050836080830152600383106149c2576149c2614941565b8260a0830152979650505050505050565b803560ff8116811461437157600080fd5b60008060008060008060008060006101008a8c031215614a0357600080fd5b89356001600160401b03811115614a1957600080fd5b614a258c828d016144ce565b909a5098505060208a0135965060408a0135955060608a0135945060808a0135614a4e81614519565b935060a08a0135614a5e81614519565b925060c08a0135614a6e8161452e565b9150614a7c60e08b016149d3565b90509295985092959850929598565b60008060408385031215614a9e57600080fd5b50508035926020909101359150565b60008060408385031215614ac057600080fd5b8235614acb81614519565b91506020830135614adb81614519565b809150509250929050565b60008060008060008060a08789031215614aff57600080fd5b86356001600160401b03811115614b1557600080fd5b614b2189828a016144ce565b909750955050602087013593506040870135614b3c81614519565b92506060870135614b4c8161452e565b9150614b5a608088016149d3565b90509295509295509295565b600080600060608486031215614b7b57600080fd5b8335614b8681614519565b92506020840135614b9681614519565b91506040840135614ba681614519565b809150509250925092565b60008060208385031215614bc457600080fd5b82356001600160401b03811115614bda57600080fd5b614be6858286016144ce565b90969095509350505050565b60008060008060808587031215614c0857600080fd5b8435614c1381614519565b93506020850135614c2381614519565b9250604085013591506060850135614c3a81614519565b939692955090935050565b60038110610bb457600080fd5b60008060408385031215614c6557600080fd5b8235614c7081614519565b91506020830135614adb81614c45565b600081518084526020808501945080840160005b83811015614cb057815187529582019590820190600101614c94565b509495945050505050565b602081526000612d216020830184614c80565b634e487b7160e01b600052601160045260246000fd5b80820180821115612d2457612d24614cce565b6020808252603c908201527f5468697320616374696f6e2063616e6e6f7420626520706572666f726d65642060408201527f7768696c652074686520636f6e74726163742069732070617573656400000000606082015260800190565b803561ffff8116811461437157600080fd5b8035600281900b811461437157600080fd5b803562ffffff8116811461437157600080fd5b600082601f830112614d9c57600080fd5b81356020614dac614821836147dd565b82815260059290921b84018101918181019086841115614dcb57600080fd5b8286015b848110156148605780356001600160401b03811115614dee5760008081fd5b8701603f81018913614e005760008081fd5b848101356040614e12614821836147dd565b8281526060928302840182019288820191908d851115614e325760008081fd5b948301945b84861015614e8f5780868f031215614e4f5760008081fd5b614e57614762565b614e6087614d54565b8152614e6d8b88016149d3565b8b820152614e7c858801614d66565b8186015283529485019491890191614e37565b50875250505092840192508301614dcf565b6000614eaf614821846147dd565b80848252602080830192508560051b850136811115614ecd57600080fd5b855b818110156150065780356001600160401b0380821115614eef5760008081fd5b81890191506101608236031215614f065760008081fd5b614f0e61478a565b82358152614f1d868401614d54565b868201526040614f2e818501614d54565b90820152606083810135908201526080614f498185016149d3565b9082015260a0614f5a848201614d66565b9082015260c0614f6b848201614d78565b9082015260e08381013583811115614f835760008081fd5b614f8f36828701614800565b8284015250506101008084013583811115614faa5760008081fd5b614fb636828701614800565b828401525050610120614fca8185016149d3565b908201526101408381013583811115614fe35760008081fd5b614fef36828701614d8b565b918301919091525087525050938201938201614ecf565b50919695505050505050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6001600160a01b0392831681529116602082015260400190565b60006020828403121561507557600080fd5b5051919050565b6001600160a01b0383168152604081016004831061509c5761509c614941565b8260208301529392505050565b6000602082840312156150bb57600080fd5b81516135748161452e565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156150ee57600080fd5b815161357481614519565b6001600160a01b03929092168252602082015260400190565b8082028115828204841417612d2457612d24614cce565b60008261514657634e487b7160e01b600052601260045260246000fd5b500490565b60006001820161515d5761515d614cce565b5060010190565b602080825260179082015276082e0e0e4deeccac840e2eadee8ca40dad2e6dac2e8c6d604b1b604082015260600190565b600081518084526020808501945080840160005b83811015614cb0578151805161ffff1688528381015160ff168489015260409081015160020b90880152606090960195908201906001016151a9565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389528151610140815186528682015161522c8888018261ffff169052565b5060408281015161ffff16908701526060808301519087015260808083015160ff169087015260a080830151600281900b82890152505060c08281015162ffffff169087015260e08083015160ff16908701526101008083015190870152610120918201519186018190526152a381870183615195565b9a87019a9550505090840190600101615203565b5091979650505050505050565b60208152600082516101608060208501526152e36101808501836151e5565b9150602085015160408501526040850151606085015260608501516080850152608085015161531d60a08601826001600160a01b03169052565b5060a08501516001600160a01b03811660c08601525060c08501516001600160a01b03811660e08601525060e08501516101008581019190915285015161012061536a8187018315159052565b86015190506101406153808682018360ff169052565b90950151151593019290925250919050565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389526153c8848351615195565b988501989350908401906001016153b0565b60006101608251845260208301516153f8602086018261ffff169052565b50604083015161540e604086018261ffff169052565b5060608301516060850152608083015161542d608086018260ff169052565b5060a083015161544260a086018260020b9052565b5060c083015161545960c086018262ffffff169052565b5060e08301518160e086015261547182860182614c80565b915050610100808401518583038287015261548c8382614c80565b92505050610120808401516154a58287018260ff169052565b505061014080840151858303828701526144488382615392565b600081518084526020808501808196508360051b8101915082860160005b858110156152b75782840389526154f58483516153da565b988501989350908401906001016154dd565b60608152600061551a60608301866154bf565b6001600160a01b0394851660208401529290931660409091015292915050565b81810381811115612d2457612d24614cce565b60a08152600061556060a08301886151e5565b6001600160a01b0396909616602083015250604081019390935260608301919091521515608090910152919050565b600181815b808511156155ca5781600019048211156155b0576155b0614cce565b808516156155bd57918102915b93841c9390800290615594565b509250929050565b6000826155e157506001612d24565b816155ee57506000612d24565b8160018114615604576002811461560e5761562a565b6001915050612d24565b60ff84111561561f5761561f614cce565b50506001821b612d24565b5060208310610133831016604e8410600b841016171561564d575081810a612d24565b615657838361558f565b806000190482111561566b5761566b614cce565b029392505050565b6000612d2183836155d2565b60408152600061569260408301856153da565b90508260208301529392505050565b6080815260006156b460808301876154bf565b60ff959095166020830152506040810192909252606090910152919050565b600080604083850312156156e657600080fd5b505080516020909101519092909150565b60808152600061570a60808301876154bf565b602083019590955250911515604083015260ff16606090910152919050565b6000806040838503121561573c57600080fd5b825161574781614c45565b809250506020808401516001600160401b0381111561576557600080fd5b8401601f8101861361577657600080fd5b8051615784614821826147dd565b81815260059190911b820183019083810190888311156157a357600080fd5b928401925b828410156157ca5783516157bb8161452e565b825292840192908401906157a8565b80955050505050509250929050565b60c0815260006157ec60c08301896154bf565b6020830197909752506040810194909452911515606084015260ff166080830152151560a090910152919050565b6000825160005b8181101561583b5760208186018101518583015201615821565b50600092019182525091905056feb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159ca264697066735822122001d222d0729a5101b73b0bc400952abd0a3d1f18640222f9c1e262674629c70464736f6c63430008140033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.