Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- CoinFlip
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2024-01-18T21:35:08.993112Z
contracts/Pulsepot/CoinFlip/CoinFlip.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import '../Library/SwapperUpgradeable.sol';
import '../Library/Rand.sol';
import '../../interfaces/Pulsepot/IPLSP.sol';
import '../../interfaces/Pulsepot/IPLSPStaking.sol';
import '../../interfaces/Pulsepot/IPulsepotBurnPool.sol';
import '../../interfaces/Pulsepot/IParticipation.sol';
import '../../interfaces/IPulseXRouter.sol';
import '../../interfaces/IPRC20.sol';
contract CoinFlip is OwnableUpgradeable, ReentrancyGuardUpgradeable, SwapperUpgradeable {
enum RoundStatus {
WAITING,
STARTED,
CALCUATING,
FINISHED,
CANCELLED
}
struct BetToken {
string name;
uint8 decimal;
address tokenAddress;
uint256 price;
bool isStable;
bool isEnabled;
}
struct Bet {
uint256 tokenId;
uint256 amount;
uint256 usdAmount;
address swappedInto;
uint256 swappedAmount;
}
struct Round {
uint256 roundID;
uint256 price;
address creator;
address opponent;
uint256 createdAt;
uint256 endedAt;
uint256 endBlock;
uint256 feeAmount;
uint8 result; // 0: front, 1: back
uint8 creatorExpectation;
Bet creatorBet;
Bet opponentBet;
RoundStatus status;
}
/* Base contracts */
IPLSP public PLSP;
IPLSPStaking public PLSPStaking;
IPulsepotBurnPool public burnPool;
IPulsepotParticipationPool public participationPool;
/* Bet Token Infos */
BetToken[] public betTokens;
uint256 public PLSPTokenId;
/* Round Infos */
Round[] public rounds;
uint256 public roundIds;
uint256 blockWait;
/* events */
event CreatedRound(uint256 roundId, address creator, string tokenName, uint256 usdAmount, uint8 creatorExpectation, uint256 timestamp);
event EnteredRound(uint256 roundId, address player, string tokenName, uint256 usdAmount, uint256 timestamp);
event RoundFinished(uint256 roundId, uint8 result, address winner, uint256 ppBonus, uint256 usdAmount, uint256 fee, uint256 plspBurnt);
event RoundCancelled(uint256 roundId);
modifier excludeContract() {
require(msg.sender == tx.origin, 'contract not allowed');
_;
}
function initialize(address _PLSPAddress, address _stakingAddress, address _burnPoolAddress, address _participationAddress, address _routerAddress, address _usdtAddress) public initializer {
PLSP = IPLSP(_PLSPAddress);
PLSPStaking = IPLSPStaking(_stakingAddress);
burnPool = IPulsepotBurnPool(_burnPoolAddress);
participationPool = IPulsepotParticipationPool(_participationAddress);
blockWait = 1; // after two blocks
PLSPTokenId = 3;
__Ownable_init();
__ReentrancyGuard_init();
__Swapper_init(_routerAddress, _usdtAddress);
}
function createRound(uint256 tokenId, uint256 usdAmount, uint8 expectation) external payable nonReentrant excludeContract {
BetToken storage tokenInfo = betTokens[tokenId];
require(tokenInfo.isEnabled, 'token disabled');
require(expectation < 2, 'wrong expecation value');
(address swappedInto, uint256 amount, uint256 swappedAmountOut) = _receive(tokenId, usdAmount);
rounds.push();
Round storage newRound = rounds[roundIds];
newRound.roundID = roundIds;
newRound.creator = msg.sender;
newRound.creatorBet.tokenId = tokenId;
newRound.creatorBet.amount = amount;
newRound.creatorBet.usdAmount = usdAmount;
newRound.creatorBet.swappedInto = swappedInto;
newRound.creatorBet.swappedAmount = swappedAmountOut;
newRound.creatorExpectation = expectation;
newRound.createdAt = block.timestamp;
newRound.status = RoundStatus.STARTED;
emit CreatedRound(roundIds, msg.sender, tokenInfo.name, usdAmount, expectation, block.timestamp);
roundIds++;
}
function enterRound(uint256 roundId, uint256 tokenId) external payable excludeContract nonReentrant {
Round storage roundInfo = rounds[roundId];
BetToken storage tokenInfo = betTokens[tokenId];
require(roundInfo.status == RoundStatus.STARTED, 'cannot enter');
require(msg.sender != roundInfo.creator, 'creator');
uint256 usdAmount = roundInfo.price;
(address swappedInto, uint256 amount, uint256 swappedAmountOut) = _receive(tokenId, usdAmount);
roundInfo.opponent = msg.sender;
roundInfo.opponentBet.amount = amount;
roundInfo.opponentBet.tokenId = tokenId;
roundInfo.opponentBet.swappedInto = swappedInto;
roundInfo.opponentBet.usdAmount = usdAmount;
roundInfo.opponentBet.swappedAmount = swappedAmountOut;
roundInfo.status = RoundStatus.CALCUATING;
roundInfo.endedAt = block.timestamp;
roundInfo.endBlock = block.number;
emit EnteredRound(roundId, msg.sender, tokenInfo.name, usdAmount, block.timestamp);
}
function finishRound(uint256 roundId) external excludeContract nonReentrant {
Round storage roundInfo = rounds[roundId];
uint256 seedBlock = roundInfo.endBlock + blockWait;
require(roundInfo.status == RoundStatus.CALCUATING, 'cannot finish');
require(block.number > seedBlock, 'should wait for blocks');
require(roundInfo.creator == msg.sender || roundInfo.opponent == msg.sender, 'only players can finish');
// Determine winner
bytes32 seed = blockhash(seedBlock);
uint256 nonce = RandLibrary.fulFillRandomnessWithSeed(seed);
uint8 result = uint8(nonce % 2);
address winner = roundInfo.creator;
Bet storage winnerBet = roundInfo.creatorBet;
if (result != roundInfo.creatorExpectation) {
winner = roundInfo.opponent;
winnerBet = roundInfo.opponentBet;
}
// Take Fees and send rewards
uint256 totalUSD = roundInfo.price * 2;
uint256 feeAmount = _calculateFeeAmount(totalUSD, winner);
uint256 plspAmount = _takeFees(roundId, feeAmount);
uint256 ppBonus;
_sendReward(roundId, winner);
if (winnerBet.tokenId != PLSPTokenId) {
ppBonus = participationPool.requestPPBonus(winner, totalUSD);
}
roundInfo.status = RoundStatus.FINISHED;
emit RoundFinished(roundId, result, winner, ppBonus, totalUSD, feeAmount, plspAmount);
}
function cancelRound(uint256 roundId) external {
Round storage roundInfo = rounds[roundId];
require(msg.sender == roundInfo.creator, 'only creator can cancel');
require(roundInfo.status == RoundStatus.STARTED, 'cannot cancel');
roundInfo.status = RoundStatus.CANCELLED;
Bet storage creatorBet = roundInfo.creatorBet;
_swap(creatorBet.swappedInto, betTokens[creatorBet.tokenId].tokenAddress, creatorBet.swappedAmount, msg.sender);
emit RoundCancelled(roundId);
}
function _sendReward(uint256 roundId, address winner) internal {
Round storage roundInfo = rounds[roundId];
Bet storage creatorBet = roundInfo.creatorBet;
Bet storage opponentBet = roundInfo.opponentBet;
_swap(creatorBet.swappedInto, betTokens[creatorBet.tokenId].tokenAddress, creatorBet.swappedAmount, winner);
_swap(opponentBet.swappedInto, betTokens[opponentBet.tokenId].tokenAddress, opponentBet.swappedAmount, winner);
}
function _receive(uint256 tokenId, uint256 usdAmount) internal returns (address swappedInto, uint256 amount, uint256 outputAmount) {
BetToken storage tokenInfo = betTokens[tokenId];
address tokenAddress = tokenInfo.tokenAddress;
bool isStable = tokenInfo.isStable;
uint256 requiredAmount = _getAmountsIn(tokenAddress, usdtAddress, usdAmount)[0];
if (isStable) {
requiredAmount = usdAmount * 10 ** tokenInfo.decimal / 10 ** 18;
}
// receive money
if (tokenAddress == address(0)) {
require(msg.value >= requiredAmount, 'not enough pls');
if (msg.value > requiredAmount) {
payable(msg.sender).transfer(msg.value - requiredAmount);
}
} else {
IPRC20 token = IPRC20(tokenAddress);
token.transferFrom(msg.sender, address(this), requiredAmount);
}
if (isStable) {
return (tokenAddress, requiredAmount, requiredAmount);
}
_swap(tokenAddress, usdtAddress, requiredAmount, address(this));
return (usdtAddress, requiredAmount, usdAmount);
}
function _takeFees(uint256 roundId, uint256 usdAmount) internal returns (uint256 plspAmount) {
Round storage roundInfo = rounds[roundId];
Bet storage betInfo;
if (roundInfo.creatorBet.tokenId != PLSPTokenId) {
betInfo = roundInfo.creatorBet;
} else {
betInfo = roundInfo.opponentBet;
}
address swapTokenAddress = betInfo.swappedInto;
uint256 amount = betInfo.swappedAmount * usdAmount / roundInfo.price;
betInfo.swappedAmount -= amount;
plspAmount = _swapFees(swapTokenAddress, amount);
PLSP.approve(address(burnPool), plspAmount);
burnPool.deposit(plspAmount);
}
function _swapFees(address tokenAddress, uint256 amount) internal returns(uint256) {
uint256 plspAmount = _swap(tokenAddress, address(PLSP), amount, address(this));
return plspAmount;
}
function _calculateFeeAmount(uint256 totalUSD, address winner) internal view returns (uint256) {
IPLSPStaking.StakingInfo memory stakingInfo = PLSPStaking.getUserStakingInfo(winner);
uint256 amount = stakingInfo.totalAmount;
uint256 fee = 300;
if (amount >= 76200 * 10 ** 18) {
fee = 20;
} else if (amount >= 62000 * 10 ** 18) {
fee = 40;
} else if (amount >= 50000 * 10 ** 18) {
fee = 60;
} else if (amount >= 32000 * 10 ** 18) {
fee = 80;
} else if (amount >= 16000 * 10 ** 18) {
fee = 100;
} else if (amount >= 8000 * 10 ** 18) {
fee = 120;
} else if (amount >= 4000 * 10 ** 18) {
fee = 140;
} else if (amount >= 3500 * 10 ** 18) {
fee = 160;
} else if (amount >= 3000 * 10 ** 18) {
fee = 180;
} else if (amount >= 2500 * 10 ** 18) {
fee = 200;
} else if (amount >= 2000 * 10 ** 18) {
fee = 220;
} else if (amount >= 1500 * 10 ** 18) {
fee = 240;
} else if (amount >= 1000 * 10 ** 18) {
fee = 260;
} else if (amount >= 500 * 10 ** 18) {
fee = 280;
} else {
fee = 300;
}
return (totalUSD * fee) / 10000;
}
function addBetTokens(BetToken[] memory _newBetTokens) external onlyOwner {
uint256 length = _newBetTokens.length;
for (uint256 i = 0; i < length; i++) {
betTokens.push(_newBetTokens[i]);
setTokenStable(_newBetTokens[i].tokenAddress, _newBetTokens[i].isStable);
}
}
function getBetTokens() external view returns (BetToken[] memory, uint256[] memory) {
uint256 length = betTokens.length;
uint256[] memory prices = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
prices[i] = getTokenPrice(betTokens[i].tokenAddress, betTokens[i].decimal);
}
return (betTokens, prices);
}
function updateBetToken(uint256 tokenId, BetToken memory info) external onlyOwner {
betTokens[tokenId] = info;
}
}
@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.7;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so 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.
*
* 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.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}
@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}
contracts/Pulsepot/Library/Rand.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
library RandLibrary {
function fulFillRandomness() internal view returns (uint256) {
return uint256(uint128(bytes16(keccak256(abi.encodePacked(block.prevrandao, block.timestamp)))));
}
function fulFillRandomnessWithSeed(bytes32 seed) internal view returns(uint256) {
return uint256(uint128(bytes16(keccak256(abi.encodePacked(block.prevrandao, block.timestamp, seed)))));
}
}
contracts/Pulsepot/Library/SwapperUpgradeable.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '../../interfaces/IPulseXRouter.sol';
import '../../interfaces/IPRC20.sol';
abstract contract SwapperUpgradeable is Initializable {
IPulseXRouter02 public router;
mapping(address => bool) public isTokenStable;
address public usdtAddress;
/**
* @dev Initializes the contract router and usdtAddress
*/
function __Swapper_init(address _routerAddress, address _usdtAddress) internal onlyInitializing {
__Swapper_init_unchained(_routerAddress, _usdtAddress);
}
function __Swapper_init_unchained(address _routerAddress, address _usdtAddress) internal onlyInitializing {
router = IPulseXRouter02(_routerAddress);
usdtAddress = _usdtAddress;
}
function setTokenStable(address addr, bool value) internal {
isTokenStable[addr] = value;
}
function getTokenPrice(address tokenAddress, uint256 decimal) public view returns (uint256) {
uint8 usdtDecimals = IPRC20(usdtAddress).decimals();
uint256 price;
if (isTokenStable[tokenAddress]) return 10 ** 18;
if (tokenAddress == address(0) || tokenAddress == router.WPLS()) {
address[] memory path = new address[](2);
path[0] = router.WPLS();
path[1] = usdtAddress;
price = router.getAmountsOut(10 ** decimal, path)[1];
} else {
address[] memory path = new address[](3);
path[0] = tokenAddress;
path[1] = router.WPLS();
path[2] = usdtAddress;
price = router.getAmountsOut(10 ** decimal, path)[2];
}
return price * 10 ** (18 - usdtDecimals);
}
function _swap(address tokenFrom, address tokenTo, uint256 amount, address receiver) internal returns (uint256 outputAmount) {
if (amount == 0) return outputAmount;
if (tokenFrom == tokenTo) return amount;
if (tokenTo != address(0)) {
if (tokenFrom == address(0)) {
address[] memory path = new address[](2);
path[0] = router.WPLS();
path[1] = tokenTo;
outputAmount = router.swapExactETHForTokens{ value: amount }(0, path, receiver, block.timestamp)[
1
];
} else if (tokenFrom == router.WPLS()) {
address[] memory path = new address[](2);
path[1] = router.WPLS();
path[2] = tokenTo;
IPRC20(tokenFrom).approve(address(router), amount);
outputAmount = router.swapExactTokensForTokens(amount, 0, path, receiver, block.timestamp)[1];
} else {
address[] memory path = new address[](3);
path[0] = tokenFrom;
path[1] = router.WPLS();
path[2] = tokenTo;
uint256 prevBalance = IPRC20(tokenTo).balanceOf(receiver);
IPRC20(tokenFrom).approve(address(router), amount);
router.swapExactTokensForTokensSupportingFeeOnTransferTokens(
amount,
0,
path,
receiver,
block.timestamp
);
uint256 afterBalance = IPRC20(tokenTo).balanceOf(receiver);
outputAmount = afterBalance - prevBalance;
}
} else {
address[] memory path = new address[](2);
path[0] = tokenFrom;
path[1] = router.WPLS();
IPRC20(tokenFrom).approve(address(router), amount);
uint256 prevBalance = receiver.balance;
router.swapExactTokensForETHSupportingFeeOnTransferTokens(amount, 0, path, receiver, block.timestamp);
uint256 afterBalance = receiver.balance;
outputAmount = afterBalance - prevBalance;
}
}
function _getAmountsIn(
address tokenFrom,
address tokenTo,
uint256 amountOut
) internal view returns (uint256[] memory amounts) {
address[] memory path;
if (tokenFrom == address(0) || tokenFrom == router.WPLS()) {
path = new address[](2);
path[0] = router.WPLS();
path[1] = tokenTo;
} else {
path = new address[](3);
path[0] = tokenFrom;
path[1] = router.WPLS();
path[2] = tokenTo;
}
amounts = router.getAmountsIn(amountOut, path);
}
function _updateUSDTAddress(address addr) internal {
usdtAddress = addr;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}
contracts/interfaces/IPRC20.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
interface IPRC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
function decimals() external view returns (uint8);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contracts/interfaces/IPulseXRouter.sol
//SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
interface IPulseXRouter01 {
function factory() external pure returns (address);
function WPLS() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function swapTokensForExactETH(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactTokensForETH(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapETHForExactTokens(
uint amountOut,
address[] calldata path,
address to,
uint deadline
) external payable returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
interface IPulseXRouter02 is IPulseXRouter01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax,
uint8 v,
bytes32 r,
bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
contracts/interfaces/Pulsepot/IPLSP.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
interface IPLSP {
event Approval(address indexed owner, address indexed spender, uint256 value);
function mint(address to, uint256 amount) external;
function burn(uint256 amount) external;
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
contracts/interfaces/Pulsepot/IPLSPStaking.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.7;
interface IPLSPStaking {
struct Stake {
uint256 id;
address user;
uint256 amount;
uint256 timestamp;
uint256 startedUnstakingAt;
uint256 status; // 0: staking, 1: started unstaking, 2: finished unstaking
}
struct StakingInfo {
uint256 totalAmount;
uint256 stakeCount;
uint256[] stakeIds;
}
function stakeList(uint256) external view returns (Stake memory);
function userStakingInfo(address) external view returns (StakingInfo memory);
function totalAmount() external view returns (uint256);
function lockTime() external view returns (uint256);
event UserStakingAmountChanged(address user, uint256 stakingId, uint256 totalAmount, bool isFinished);
event StartedUnstaking(uint256 id);
function getUserStakingList(address user) external view returns (Stake[] memory);
function getUserStakingListByPages(
address user,
uint256 start,
uint256 length
) external view returns (Stake[] memory);
function getUserStakingInfo(address user) external view returns(StakingInfo memory);
}
contracts/interfaces/Pulsepot/IParticipation.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
interface IPulsepotParticipationPool {
function usdRequiredPerWPLSP() external view returns (uint256);
function requestPPBonus(address receiver, uint256 usdValue) external returns(uint256);
}
contracts/interfaces/Pulsepot/IPulsepotBurnPool.sol
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.7;
interface IPulsepotBurnPool {
event ReceivedFee(address sender, uint256 amount);
event Burned(uint256 amount);
function burn() external;
function deposit(uint256 amount) external;
}
Compiler Settings
{"viaIR":true,"outputSelection":{"*":{"*":["*"],"":["*"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"event","name":"CreatedRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":false},{"type":"address","name":"creator","internalType":"address","indexed":false},{"type":"string","name":"tokenName","internalType":"string","indexed":false},{"type":"uint256","name":"usdAmount","internalType":"uint256","indexed":false},{"type":"uint8","name":"creatorExpectation","internalType":"uint8","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"EnteredRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":false},{"type":"address","name":"player","internalType":"address","indexed":false},{"type":"string","name":"tokenName","internalType":"string","indexed":false},{"type":"uint256","name":"usdAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Initialized","inputs":[{"type":"uint8","name":"version","internalType":"uint8","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoundCancelled","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RoundFinished","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256","indexed":false},{"type":"uint8","name":"result","internalType":"uint8","indexed":false},{"type":"address","name":"winner","internalType":"address","indexed":false},{"type":"uint256","name":"ppBonus","internalType":"uint256","indexed":false},{"type":"uint256","name":"usdAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"fee","internalType":"uint256","indexed":false},{"type":"uint256","name":"plspBurnt","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPLSP"}],"name":"PLSP","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPLSPStaking"}],"name":"PLSPStaking","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"PLSPTokenId","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBetTokens","inputs":[{"type":"tuple[]","name":"_newBetTokens","internalType":"struct CoinFlip.BetToken[]","components":[{"type":"string","name":"name","internalType":"string"},{"type":"uint8","name":"decimal","internalType":"uint8"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isEnabled","internalType":"bool"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"name","internalType":"string"},{"type":"uint8","name":"decimal","internalType":"uint8"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isEnabled","internalType":"bool"}],"name":"betTokens","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPulsepotBurnPool"}],"name":"burnPool","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"cancelRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"createRound","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"usdAmount","internalType":"uint256"},{"type":"uint8","name":"expectation","internalType":"uint8"}]},{"type":"function","stateMutability":"payable","outputs":[],"name":"enterRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"finishRound","inputs":[{"type":"uint256","name":"roundId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct CoinFlip.BetToken[]","components":[{"type":"string","name":"name","internalType":"string"},{"type":"uint8","name":"decimal","internalType":"uint8"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isEnabled","internalType":"bool"}]},{"type":"uint256[]","name":"","internalType":"uint256[]"}],"name":"getBetTokens","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getTokenPrice","inputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"decimal","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_PLSPAddress","internalType":"address"},{"type":"address","name":"_stakingAddress","internalType":"address"},{"type":"address","name":"_burnPoolAddress","internalType":"address"},{"type":"address","name":"_participationAddress","internalType":"address"},{"type":"address","name":"_routerAddress","internalType":"address"},{"type":"address","name":"_usdtAddress","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTokenStable","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPulsepotParticipationPool"}],"name":"participationPool","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"roundIds","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"roundID","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"address","name":"creator","internalType":"address"},{"type":"address","name":"opponent","internalType":"address"},{"type":"uint256","name":"createdAt","internalType":"uint256"},{"type":"uint256","name":"endedAt","internalType":"uint256"},{"type":"uint256","name":"endBlock","internalType":"uint256"},{"type":"uint256","name":"feeAmount","internalType":"uint256"},{"type":"uint8","name":"result","internalType":"uint8"},{"type":"uint8","name":"creatorExpectation","internalType":"uint8"},{"type":"tuple","name":"creatorBet","internalType":"struct CoinFlip.Bet","components":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"usdAmount","internalType":"uint256"},{"type":"address","name":"swappedInto","internalType":"address"},{"type":"uint256","name":"swappedAmount","internalType":"uint256"}]},{"type":"tuple","name":"opponentBet","internalType":"struct CoinFlip.Bet","components":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"usdAmount","internalType":"uint256"},{"type":"address","name":"swappedInto","internalType":"address"},{"type":"uint256","name":"swappedAmount","internalType":"uint256"}]},{"type":"uint8","name":"status","internalType":"enum CoinFlip.RoundStatus"}],"name":"rounds","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IPulseXRouter02"}],"name":"router","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updateBetToken","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"tuple","name":"info","internalType":"struct CoinFlip.BetToken","components":[{"type":"string","name":"name","internalType":"string"},{"type":"uint8","name":"decimal","internalType":"uint8"},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"bool","name":"isStable","internalType":"bool"},{"type":"bool","name":"isEnabled","internalType":"bool"}]}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"usdtAddress","inputs":[]}]
Contract Creation Code
0x6080806040523461001657612fc7908161001c8239f35b600080fdfe608080604052600436101561001357600080fd5b600090813560e01c90816316c82e41146118be5750806317cd8066146118255780631987ba6f146117fc5780631fe0ff5814610ffa578063250fa2bc14610fbb5780634c82b28514610e5f5780634dd72fdd14610c4d5780635eef64ad14610c2f578063610a1457146109d0578063715018a6146109725780637e07ab091461083f57806385f6b18f146108165780638c65c81f146106ab5780638da5cb5b146106825780639119e91d146106315780639ab4a44514610608578063a54b2a73146105df578063c9f7153c146105af578063cc2a9a5b146103a9578063ec5297091461038b578063f2fde38b146102fa578063f887ea40146102d15763f96aa1d61461011e57600080fd5b60403660031901126102ce5760043560243561013b323314611ddf565b61014a60026065541415611d93565b600260655561015882611c01565b5091610163826118e3565b5091601384019360ff85541660058110156102ba576001036102865760028101546001600160a01b03959086163314610257577f918dfb54a58cd2197505867c9367f48420b6a6ed7d581439922b2dc18d850351956001830154936101c88582611f67565b9390919260038701926001600160601b0360a01b933385825416179055600f880155600e870155601186019216908254161790558360108401556012830155600260ff19825416179055426005820155600643910155610240604051938493845233602085015260a0604085015260a0840190611e22565b9060608301524260808301520390a1600160655580f35b60405162461bcd60e51b815260206004820152600760248201526631b932b0ba37b960c91b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b31b0b73737ba1032b73a32b960a11b6044820152606490fd5b634e487b7160e01b87526021600452602487fd5b80fd5b50346102ce57806003193601126102ce576097546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce57610314611aee565b61031c611c92565b6001600160a01b038116156103375761033490611cea565b80f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346102ce57806003193601126102ce57602060d054604051908152f35b50346102ce5760c03660031901126102ce576103c3611aee565b6001600160a01b03602435818116908190036105aa57604435928284168094036105aa576064358381168091036105aa57608435948486168096036105aa5760a435938585168095036105aa5787549560ff8760081c16159687809861059d575b8015610586575b1561052a5760ff1981166001178a5587610519575b506001600160601b0360a01b94168460cb54161760cb558360cc54161760cc558260cd54161760cd558160ce54161760ce55600160d355600360d05561049560ff865460081c1661049081611d33565b611d33565b61049e33611cea565b8454936104cb60ff8660081c166104b481611d33565b6104bd81611d33565b600160655561049081611d33565b81609754161760975560995416176099556104e4575080f35b61ff00191681557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180f35b61ffff191661010117895538610440565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b15801561042b5750600160ff82161461042b565b50600160ff821610610424565b600080fd5b50346102ce5760403660031901126102ce5760206105d76105ce611aee565b6024359061257b565b604051908152f35b50346102ce57806003193601126102ce5760cd546040516001600160a01b039091168152602090f35b50346102ce57806003193601126102ce576099546040516001600160a01b039091168152602090f35b50346102ce5760403660031901126102ce576024356001600160401b03811161067e57610665610334913690600401611b28565b61066d611c92565b6106786004356118e3565b90612340565b5080fd5b50346102ce57806003193601126102ce576033546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce5760043560d15481101561067e576106d390611c01565b50805490600181015490600160a01b600190038060028301541690600383015416600483015460058401546006850154906007860154926008870154946009880161071d90611c3c565b9661072a600e8a01611c3c565b986013015460ff16996040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e086015260ff811661010086015260081c60ff1661012085015261014084016107b0916080809180518452602081015160208501526040810151604085015260018060a01b0360608201511660608501520151910152565b80516101e08401526020810151610200840152604081015161022084015260608101516001600160a01b0316610240840152608001516102608301526005811015610802576102a09250610280820152f35b634e487b7160e01b83526021600452602483fd5b50346102ce57806003193601126102ce5760cc546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce5760043561085d81611c01565b5060028101546001600160a01b0392908316330361092d57601382019182549060ff821660058110156102ba576001036108f8577fbf7aeff89cf7a4c3d0145879e39aa6a19e8e64ed585090ef86bf31f4d2ae57bf9460209460046108ed9460ff191617905580600c830154169060016108da60098501546118e3565b50015460081c16600d3393015491612910565b50604051908152a180f35b60405162461bcd60e51b815260206004820152600d60248201526c18d85b9b9bdd0818d85b98d95b609a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063726561746f722063616e2063616e63656c0000000000000000006044820152606490fd5b50346102ce57806003193601126102ce5761098b611c92565b603380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346102ce57806003193601126102ce5760cf546109ed81611b04565b916109fb60405193846119e7565b818352610a0782611b04565b6020928484019291601f1901368437815b818110610bd65750610a2981611b04565b93610a3760405195866119e7565b81855260cf835280850191837facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf29845b838310610b5a57505050506040519586956040870190604088525180915260609081880191808260051b8a0101959287915b838310610adb575050505086840387840152505180835291810193925b828110610ac457505050500390f35b835185528695509381019392810192600101610ab5565b919398999580809998600193959798605f199082030186528b5190610b08825160c0808452830190611aae565b9160ff848201511684830152858060a01b036040820151166040830152868101518783015260808082015115159083015260a08091015115159101529a019301930190928a9998969795949293610a98565b60048560019260409c9799989a9b9c51610b7381611996565b610b7c86611a08565b81528486015460ff9081811685840152600890878060a01b0390821c16604084015260028801546060840152600388015490828216151560808501521c16151560a082015281520192019201919098979694959398610a66565b80610c15610beb610c259397959496976118e3565b5060019081015460081c6001600160a01b03169060ff90610c0b856118e3565b500154169061257b565b610c1f8289611f1d565b52611eb8565b9392909193610a18565b50346102ce57806003193601126102ce57602060d254604051908152f35b5060603660031901126102ce576004356024356044359060ff8216928383036105aa57610c7f60026065541415611d93565b6002606555610c8f323314611ddf565b610c98816118e3565b509260ff600385015460081c1615610e29576002851015610deb57610cbd8383611f67565b91909360d154600160401b811015610dd757937fbcae0a440e0b42801c2e791a064d61a4387593b0e094b91979810b0f75744ca89693601393610db39793610d10886001610dcc9e9d9a0160d155611c01565b505060d25494610d1f86611c01565b5095865560028601916001600160601b0360a01b9233848254161790556009870155600a86015586600b860155600c85019160018060a01b031690825416179055600d830155600882019061ff0082549160081b169061ff00191617905542600482015501600160ff1982541617905560d2549460405193849387855233602086015260c0604086015260c0850190611e22565b91606084015260808301524260a08301520390a1611eb8565b60d255600160655580f35b634e487b7160e01b8a52604160045260248afd5b60405162461bcd60e51b815260206004820152601660248201527577726f6e672065787065636174696f6e2076616c756560501b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d1d1bdad95b88191a5cd8589b195960921b6044820152606490fd5b50346102ce5760208060031936011261067e57600435906001600160401b0390818311610fb75736602384011215610fb757826004013591610ea083611b04565b93610eae60405195866119e7565b838552828501906024809560051b82010192368411610fb357858201925b848410610f89575050505050610ee0611c92565b825191845b838110610ef0578580f35b610efa8186611f1d565b5160cf805490600160401b821015610f76579161067882610f7195946001610f24950190556118e3565b610f6c6001600160a01b036040610f3b848a611f1d565b510151166080610f4b848a611f1d565b510151151590895260988652604089209060ff801983541691151516179055565b611eb8565b610ee5565b634e487b7160e01b895260416004528489fd5b8335828111610faf578691610fa483928a3691880101611b28565b815201930192610ecc565b8980fd5b8780fd5b8380fd5b50346102ce5760203660031901126102ce5760209060ff906040906001600160a01b03610fe6611aee565b168152609884522054166040519015158152f35b50346102ce5760203660031901126102ce57611017323314611ddf565b61102660026065541415611d93565b6002606555611036600435611c01565b50600681015460d35481018091116117e85760ff60138301541660058110156117d45760020361179f57804311156117615760028201546001600160a01b031690338214801561174b575b15611706576001906040516020810191448352426040830152406060820152606081526110ad816119b1565b51902060801c1690916009810160ff600883015460081c1683036116ec575b6001820154808060011b04600214811517156116d85760cc5460405163101266c160e31b81526001600160a01b0387811660048301529091889183916024918391165afa9081156116cd57879161161b575b505161012c90691022cf6e5318dda00000811061147757505061271061114960145b8360011b611edd565b0491611156600435611c01565b5060098101805460d0541461146c57905b60018060a01b036003830154169160048101549160016111878885611edd565b910154908115611458576111a66111bb95949392600492048094611f5a565b91015560018060a01b0360cb54163092612910565b60cb5460cd5460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905292969291602091839160449183918e91165af1801561141e57611429575b5060cd5488906001600160a01b0316803b1561067e57819060246040518094819363b6b55f2560e01b83528b60048401525af1801561141e5761140b575b5087916112ce88611253600435611c01565b506112928260018060a01b03600c8401541661127260098501546118e3565b5060010154600d8501549160089190911c6001600160a01b031690612910565b5060018060a01b036011820154169060126112b0600e8301546118e3565b50600101549101549160089190911c6001600160a01b031690612910565b505460d0540361134e575b907fda9190ca87ab93aa17e331018af4f13243e5b051d046b000a49ea3c5361559fc9660e096959493926013600360ff19828401541617910155604051956004358752602087015260018060a01b03166040860152606085015260011b608084015260a083015260c0820152a1600160655580f35b60ce54604051631e7a863d60e11b81526001600160a01b038981166004830152600186901b602483015292935091602091839160449183918d91165af19081156114005788916113a0575b50906112d9565b959493929190506020863d6020116113f8575b816113c0602093836119e7565b810103126105aa57945193949293919290917fda9190ca87ab93aa17e331018af4f13243e5b051d046b000a49ea3c5361559fc611399565b3d91506113b3565b6040513d8a823e3d90fd5b6114179098919861196d565b9638611241565b6040513d8b823e3d90fd5b61144a9060203d602011611451575b61144281836119e7565b810190611f42565b5038611203565b503d611438565b634e487b7160e01b8c52601260045260248cfd5b50600e810190611167565b690d2106d815ebeac0000081106114975750506127106111496028611140565b690a968163f0a57b40000081106114b7575050612710611149603c611140565b6906c6b935b8bbd400000081106114d75750506127106111496050611140565b6903635c9adc5dea00000081106114f75750506127106111496064611140565b6901b1ae4d6e2ef500000081106115175750506127106111496078611140565b68d8d726b7177a8000008110611536575050612710611149608c611140565b68bdbc41e0348b300000811061155557505061271061114960a0611140565b68a2a15d09519be00000811061157457505061271061114960b4611140565b68878678326eac900000811061159357505061271061114960c8611140565b686c6b935b8bbd40000081106115b257505061271061114960dc611140565b685150ae84a8cdf0000081106115d157505061271061114960f0611140565b683635c9adc5dea0000081106115f1575050612710611149610104611140565b681b1ae4d6e2ef5000001161160f5750612710611149610118611140565b61114961271091611140565b90503d8088833e61162c81836119e7565b6020828281010312610fb3578151916001600160401b0383116116c957606083820183830103126116c95760405192606084018481106001600160401b038211176116b557604090815282820180518652602080820151908701520151906001600160401b0382116116b1576116a69383019201016122e2565b60408201523861111e565b8a80fd5b634e487b7160e01b8b52604160045260248bfd5b8880fd5b6040513d89823e3d90fd5b634e487b7160e01b86526011600452602486fd5b5060038101546001600160a01b03169250600e81016110cc565b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c7920706c61796572732063616e2066696e6973680000000000000000006044820152606490fd5b5060038301546001600160a01b03163314611081565b60405162461bcd60e51b815260206004820152601660248201527573686f756c64207761697420666f7220626c6f636b7360501b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c0c6c2dcdcdee840ccd2dcd2e6d609b1b6044820152606490fd5b634e487b7160e01b84526021600452602484fd5b634e487b7160e01b83526011600452602483fd5b50346102ce57806003193601126102ce5760cb546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce576004359060cf548210156102ce57611883611851836118e3565b5061185b81611a08565b9060ff600182015491600360028201549101549060405195869560c0875260c0870190611aae565b8385166020870152600894851c6001600160a01b03166040870152606086019190915281831615156080860152921c16151560a08301520390f35b90503461067e578160031936011261067e5760ce546001600160a01b03168152602090f35b60cf5481101561191d5760cf60005260021b7facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf290190600090565b634e487b7160e01b600052603260045260246000fd5b90600182811c92168015611963575b602083101461194d57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611942565b6001600160401b03811161198057604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b0382111761198057604052565b608081019081106001600160401b0382111761198057604052565b606081019081106001600160401b0382111761198057604052565b90601f801991011681019081106001600160401b0382111761198057604052565b9060405191826000825492611a1c84611933565b908184526001948581169081600014611a8b5750600114611a48575b5050611a46925003836119e7565b565b9093915060005260209081600020936000915b818310611a73575050611a4693508201013880611a38565b85548884018501529485019487945091830191611a5b565b915050611a4694506020925060ff191682840152151560051b8201013880611a38565b919082519283825260005b848110611ada575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611ab9565b600435906001600160a01b03821682036105aa57565b6001600160401b0381116119805760051b60200190565b359081151582036105aa57565b91909160c0818403126105aa5760405190611b4282611996565b819381356001600160401b03908181116105aa5783019082601f830112156105aa5781359081116119805760405191602093611b8785601f19601f86011601856119e7565b8284528483830101116105aa57816000928580930183860137830101528352808201359060ff821682036105aa578301526040810135906001600160a01b03821682036105aa5760a0611bfc918193604086015260608101356060860152611bf160808201611b1b565b608086015201611b1b565b910152565b60d15481101561191d5760149060d1600052027f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce30190600090565b9060405160a081018181106001600160401b03821117611980576040908152835482526001840154602083015260028401549082015260038301546001600160a01b031660608201526004909201546080830152565b6033546001600160a01b03163303611ca657565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b15611d3a57565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b15611d9a57565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b15611de657565b60405162461bcd60e51b815260206004820152601460248201527318dbdb9d1c9858dd081b9bdd08185b1b1bddd95960621b6044820152606490fd5b9060009291805491611e3383611933565b918282526001938481169081600014611e955750600114611e55575b50505050565b90919394506000526020928360002092846000945b838610611e81575050505001019038808080611e4f565b805485870183015294019385908201611e6a565b9294505050602093945060ff191683830152151560051b01019038808080611e4f565b6000198114611ec75760010190565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715611ec757565b80511561191d5760200190565b80516001101561191d5760400190565b80516002101561191d5760600190565b805182101561191d5760209160051b010190565b60ff16604d8111611ec757600a0a90565b908160209103126105aa575180151581036105aa5790565b91908203918211611ec757565b611f70906118e3565b509160018301549260018060a01b039060ff6003838760081c169201541694826099541690600090831580928115612281575b50156121f65760405192611fb6846119cc565b600284526040366020860137600484602088609754166040519384809263ef8ef56f60e01b82525afa80156121ea57612005926000916121bc575b5088611ffc83611ef0565b91169052611efd565b525b61203d60008660975416946040958a87518095819482936307c0329d60e21b845260048401528a6024840152604483019061253e565b03915afa9081156121b157899493929161205f91600091612190575b50611ef0565b5198612167575b501561210b578634106120d7578634116120a5575b505b61209c57612092908583609954163092612910565b5060995416929190565b93925082919050565b60008080806120b48b34611f5a565b8181156120ce575b3390f161207b575b513d6000823e3d90fd5b506108fc6120bc565b5162461bcd60e51b815260206004820152600e60248201526d6e6f7420656e6f75676820706c7360901b6044820152606490fd5b80516323b872dd60e01b815233600482015230602482015260448101889052906020826064816000885af19081156120c45750612149575b5061207d565b6121609060203d81116114515761144281836119e7565b5038612143565b670de0b6b3a764000091985061218260ff6121889216611f31565b88611edd565b049638612066565b6121ab913d8091833e6121a381836119e7565b810190612516565b38612059565b84513d6000823e3d90fd5b6121dd915060203d81116121e3575b6121d581836119e7565b8101906124e9565b38611ff1565b503d6121cb565b6040513d6000823e3d90fd5b60405192612203846119b1565b6003845260603660208601376004848661221c82611ef0565b52602088609754166040519384809263ef8ef56f60e01b82525afa80156121ea5761225d92600091612263575b508861225483611efd565b91169052611f0d565b52612007565b61227b915060203d81116121e3576121d581836119e7565b38612249565b90506004602087609754166040519283809263ef8ef56f60e01b82525afa9182156122d6579087926122b8575b5016841438611fa3565b6122d0915060203d81116121e3576121d581836119e7565b386122ae565b604051903d90823e3d90fd5b81601f820112156105aa578051916122f983611b04565b9261230760405194856119e7565b808452602092838086019260051b8201019283116105aa578301905b828210612331575050505090565b81518152908301908301612323565b906124d35781518051906001600160401b038211611980576123628354611933565b601f811161248b575b50602090601f831160011461242057918060a09492600394600092612415575b50508160011b9160001990851b1c19161781555b6001810160ff602086015116815490610100600160a81b03604088015160081b16916affffffffffffffffffffff60a81b16171790556060840151600282015501916123fd60808201511515849060ff801983541691151516179055565b0151815461ff00191690151560081b61ff0016179055565b01519050388061238b565b90601f1983169184600052816000209260005b818110612473575092600192859260039660a098961061245b575b505050811b01815561239f565b015160001983871b60f8161c1916905538808061244e565b92936020600181928786015181550195019301612433565b600084815260208120601f850160051c810192602086106124c9575b601f0160051c01915b8281106124be57505061236b565b8181556001016124b0565b90925082906124a7565b634e487b7160e01b600052600060045260246000fd5b908160209103126105aa57516001600160a01b03811681036105aa5790565b604d8111611ec757600a0a90565b906020828203126105aa5781516001600160401b0381116105aa5761253b92016122e2565b90565b90815180825260208080930193019160005b82811061255e575050505090565b83516001600160a01b031685529381019392810192600101612550565b6099546040805163313ce56760e01b81529360049391926020926001600160a01b03929183169084888881855afa9788156128cb57600098612890575b5083600091168082526098865260ff878320541661287b5780158015612820575b1561270e5750508451936125ec856119cc565b60028552853682870137836097541693865163ef8ef56f60e01b815282818a81895afa9283156127035792612671979592600097959261264b9589936126e4575b505061263887611ef0565b9116905261264585611efd565b52612508565b855180958194829363d06ca61f60e01b84528a840152886024840152604483019061253e565b03915afa9182156120c4575060ff91612692916000916126cb575b50611efd565b51925b166012039060ff82116126b65750906126b061253b92611f31565b90611edd565b601190634e487b7160e01b6000525260246000fd5b6126de913d8091833e6121a381836119e7565b3861268c565b6126fb929350803d106121e3576121d581836119e7565b90388061262d565b88513d6000823e3d90fd5b939291909486519461271f866119b1565b600386526060368388013761273386611ef0565b52836097541693875163ef8ef56f60e01b815282818b81895afa92831561281657928897959288979592612783956127a99b936127f7575b505061277687611efd565b9116905261264585611f0d565b865180968194829363d06ca61f60e01b84528b840152896024840152604483019061253e565b03915afa9283156127ed5750916127cb918360ff94926127d2575b5050611f0d565b5192612695565b6127e692503d8091833e6121a381836119e7565b38806127c4565b51903d90823e3d90fd5b61280e929350803d106121e3576121d581836119e7565b90388061276b565b89513d8a823e3d90fd5b508786866097541689519283809263ef8ef56f60e01b82525afa908115612871579086918491612854575b501681146125d9565b61286b9150883d8a116121e3576121d581836119e7565b3861284b565b88513d85823e3d90fd5b505050505050505050670de0b6b3a764000090565b8581819a939a3d83116128c4575b6128a881836119e7565b8101031261067e57519060ff821682036102ce575096386125b8565b503d61289e565b86513d6000823e3d90fd5b906080926128fc919695949683526000602084015260a0604084015260a083019061253e565b6001600160a01b0390951660608201520152565b9392906000948315611e4f576001600160a01b03918216908216808214612f88578115612e1b5780612a4a5750908591604094855161294e816119cc565b6002815286366020830137836097541692875163ef8ef56f60e01b8152602081600481885afa908115612a4057906129ce949392918891612a22575b508661299584611ef0565b911690526129a282611efd565b528751637ff36ab560e01b8152600481018790526080602482015296879586948593608485019061253e565b9116604483015242606483015203925af1918215612a195750836129fa9394926129fe575b5050611efd565b5190565b612a1292503d8091833e6121a381836119e7565b38806129f3565b513d85823e3d90fd5b612a3a915060203d81116121e3576121d581836119e7565b3861298a565b89513d89823e3d90fd5b9192909594938360975416966040948551809563ef8ef56f60e01b808352828c602094859160049b8c915afa908115612e11579085918d91612df4575b50168203612bc9578a9b5088999a97985194612aa2866119cc565b600286528a36858801378460975416918b5190815284818c81865afa908115612bbf57928a8c8e8b95612b2698958b8d8c9a8793612b9c575b50612ae590611efd565b91169052612af28c611f0d565b525163095ea7b360e01b81526001600160a01b03909316908301908152602081019490945290948593849291839160400190565b03925af18015612a40579087939291612b7e575b50506097541692612b608851978896879586946338ed173960e01b8652429386016128d6565b03925af1918215612a195750836129fa9394926129fe575050611efd565b81612b9492903d106114515761144281836119e7565b503880612b3a565b612ae5919350612bb8908c8d3d106121e3576121d581836119e7565b9290612adb565b8c513d8c823e3d90fd5b90989a949196999592885191612bde836119b1565b600383526060368a8501378a612bf384611ef0565b52895190815288818d818a5afa908115612dea57908c979695949392918991612dcd575b5081612c2284611efd565b9116905284612c3083611f0d565b5289519a6370a0823160e01b96878d528c8387169e8f9101528a8d6024818a5afa9c8d15612bbf578a9d612d8e575b508b5163095ea7b360e01b81526001600160a01b03909116818a019081526020810186905290918b9183919082908d90829060400103925af18015612d8457612d67575b506097541691823b15610fb35791869391888094612cd68d5197889687958694635c11d79560e01b8652429386016128d6565b03925af18015612d5d57908694939291612d47575b50906024918751998a94859384528301525afa9283156127ed575091612d17575b5061253b9250611f5a565b905082813d8311612d40575b612d2d81836119e7565b810103126105aa5761253b915138612d0c565b503d612d23565b94612d55602493929661196d565b949091612ceb565b87513d87823e3d90fd5b612d7d908a3d8c116114515761144281836119e7565b5038612ca3565b8b513d8b823e3d90fd5b9091929394959697989c508a81813d8311612dc6575b612dae81836119e7565b81010312610faf57519b979695949392919084612c5f565b503d612da4565b612de491508a3d8c116121e3576121d581836119e7565b38612c17565b8a513d8a823e3d90fd5b612e0b9150853d87116121e3576121d581836119e7565b38612a87565b8a513d8e823e3d90fd5b9193905085604091825193612e2f856119cc565b6002855260209084368388013780612e4687611ef0565b528760975416855163ef8ef56f60e01b81528381600481855afa908115612f7e579284928692612ebc958991612f61575b508c612e828c611efd565b91169052885163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290928391908290889082906044820190565b03925af18015612f5757612f39575b505084319560975416803b15612f35578583612eff9686519788958694859363791ac94760e01b85524292600486016128d6565b03925af1908115612f2c575061253b949550612f1d575b5031611f5a565b612f269061196d565b38612f16565b513d87823e3d90fd5b8280fd5b81612f4f92903d106114515761144281836119e7565b503880612ecb565b85513d86823e3d90fd5b612f789150853d87116121e3576121d581836119e7565b38612e77565b87513d88823e3d90fd5b5092945050505056fea2646970667358221220ff4175ebaf8361ba29e92f8923220e6efe8af5f1186e9a77e8b86e6cbad79c5a64736f6c63430008130033
Deployed ByteCode
0x608080604052600436101561001357600080fd5b600090813560e01c90816316c82e41146118be5750806317cd8066146118255780631987ba6f146117fc5780631fe0ff5814610ffa578063250fa2bc14610fbb5780634c82b28514610e5f5780634dd72fdd14610c4d5780635eef64ad14610c2f578063610a1457146109d0578063715018a6146109725780637e07ab091461083f57806385f6b18f146108165780638c65c81f146106ab5780638da5cb5b146106825780639119e91d146106315780639ab4a44514610608578063a54b2a73146105df578063c9f7153c146105af578063cc2a9a5b146103a9578063ec5297091461038b578063f2fde38b146102fa578063f887ea40146102d15763f96aa1d61461011e57600080fd5b60403660031901126102ce5760043560243561013b323314611ddf565b61014a60026065541415611d93565b600260655561015882611c01565b5091610163826118e3565b5091601384019360ff85541660058110156102ba576001036102865760028101546001600160a01b03959086163314610257577f918dfb54a58cd2197505867c9367f48420b6a6ed7d581439922b2dc18d850351956001830154936101c88582611f67565b9390919260038701926001600160601b0360a01b933385825416179055600f880155600e870155601186019216908254161790558360108401556012830155600260ff19825416179055426005820155600643910155610240604051938493845233602085015260a0604085015260a0840190611e22565b9060608301524260808301520390a1600160655580f35b60405162461bcd60e51b815260206004820152600760248201526631b932b0ba37b960c91b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b31b0b73737ba1032b73a32b960a11b6044820152606490fd5b634e487b7160e01b87526021600452602487fd5b80fd5b50346102ce57806003193601126102ce576097546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce57610314611aee565b61031c611c92565b6001600160a01b038116156103375761033490611cea565b80f35b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b50346102ce57806003193601126102ce57602060d054604051908152f35b50346102ce5760c03660031901126102ce576103c3611aee565b6001600160a01b03602435818116908190036105aa57604435928284168094036105aa576064358381168091036105aa57608435948486168096036105aa5760a435938585168095036105aa5787549560ff8760081c16159687809861059d575b8015610586575b1561052a5760ff1981166001178a5587610519575b506001600160601b0360a01b94168460cb54161760cb558360cc54161760cc558260cd54161760cd558160ce54161760ce55600160d355600360d05561049560ff865460081c1661049081611d33565b611d33565b61049e33611cea565b8454936104cb60ff8660081c166104b481611d33565b6104bd81611d33565b600160655561049081611d33565b81609754161760975560995416176099556104e4575080f35b61ff00191681557f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498602060405160018152a180f35b61ffff191661010117895538610440565b60405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b6064820152608490fd5b50303b15801561042b5750600160ff82161461042b565b50600160ff821610610424565b600080fd5b50346102ce5760403660031901126102ce5760206105d76105ce611aee565b6024359061257b565b604051908152f35b50346102ce57806003193601126102ce5760cd546040516001600160a01b039091168152602090f35b50346102ce57806003193601126102ce576099546040516001600160a01b039091168152602090f35b50346102ce5760403660031901126102ce576024356001600160401b03811161067e57610665610334913690600401611b28565b61066d611c92565b6106786004356118e3565b90612340565b5080fd5b50346102ce57806003193601126102ce576033546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce5760043560d15481101561067e576106d390611c01565b50805490600181015490600160a01b600190038060028301541690600383015416600483015460058401546006850154906007860154926008870154946009880161071d90611c3c565b9661072a600e8a01611c3c565b986013015460ff16996040519b8c5260208c015260408b015260608a0152608089015260a088015260c087015260e086015260ff811661010086015260081c60ff1661012085015261014084016107b0916080809180518452602081015160208501526040810151604085015260018060a01b0360608201511660608501520151910152565b80516101e08401526020810151610200840152604081015161022084015260608101516001600160a01b0316610240840152608001516102608301526005811015610802576102a09250610280820152f35b634e487b7160e01b83526021600452602483fd5b50346102ce57806003193601126102ce5760cc546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce5760043561085d81611c01565b5060028101546001600160a01b0392908316330361092d57601382019182549060ff821660058110156102ba576001036108f8577fbf7aeff89cf7a4c3d0145879e39aa6a19e8e64ed585090ef86bf31f4d2ae57bf9460209460046108ed9460ff191617905580600c830154169060016108da60098501546118e3565b50015460081c16600d3393015491612910565b50604051908152a180f35b60405162461bcd60e51b815260206004820152600d60248201526c18d85b9b9bdd0818d85b98d95b609a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c792063726561746f722063616e2063616e63656c0000000000000000006044820152606490fd5b50346102ce57806003193601126102ce5761098b611c92565b603380546001600160a01b031981169091556000906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50346102ce57806003193601126102ce5760cf546109ed81611b04565b916109fb60405193846119e7565b818352610a0782611b04565b6020928484019291601f1901368437815b818110610bd65750610a2981611b04565b93610a3760405195866119e7565b81855260cf835280850191837facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf29845b838310610b5a57505050506040519586956040870190604088525180915260609081880191808260051b8a0101959287915b838310610adb575050505086840387840152505180835291810193925b828110610ac457505050500390f35b835185528695509381019392810192600101610ab5565b919398999580809998600193959798605f199082030186528b5190610b08825160c0808452830190611aae565b9160ff848201511684830152858060a01b036040820151166040830152868101518783015260808082015115159083015260a08091015115159101529a019301930190928a9998969795949293610a98565b60048560019260409c9799989a9b9c51610b7381611996565b610b7c86611a08565b81528486015460ff9081811685840152600890878060a01b0390821c16604084015260028801546060840152600388015490828216151560808501521c16151560a082015281520192019201919098979694959398610a66565b80610c15610beb610c259397959496976118e3565b5060019081015460081c6001600160a01b03169060ff90610c0b856118e3565b500154169061257b565b610c1f8289611f1d565b52611eb8565b9392909193610a18565b50346102ce57806003193601126102ce57602060d254604051908152f35b5060603660031901126102ce576004356024356044359060ff8216928383036105aa57610c7f60026065541415611d93565b6002606555610c8f323314611ddf565b610c98816118e3565b509260ff600385015460081c1615610e29576002851015610deb57610cbd8383611f67565b91909360d154600160401b811015610dd757937fbcae0a440e0b42801c2e791a064d61a4387593b0e094b91979810b0f75744ca89693601393610db39793610d10886001610dcc9e9d9a0160d155611c01565b505060d25494610d1f86611c01565b5095865560028601916001600160601b0360a01b9233848254161790556009870155600a86015586600b860155600c85019160018060a01b031690825416179055600d830155600882019061ff0082549160081b169061ff00191617905542600482015501600160ff1982541617905560d2549460405193849387855233602086015260c0604086015260c0850190611e22565b91606084015260808301524260a08301520390a1611eb8565b60d255600160655580f35b634e487b7160e01b8a52604160045260248afd5b60405162461bcd60e51b815260206004820152601660248201527577726f6e672065787065636174696f6e2076616c756560501b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d1d1bdad95b88191a5cd8589b195960921b6044820152606490fd5b50346102ce5760208060031936011261067e57600435906001600160401b0390818311610fb75736602384011215610fb757826004013591610ea083611b04565b93610eae60405195866119e7565b838552828501906024809560051b82010192368411610fb357858201925b848410610f89575050505050610ee0611c92565b825191845b838110610ef0578580f35b610efa8186611f1d565b5160cf805490600160401b821015610f76579161067882610f7195946001610f24950190556118e3565b610f6c6001600160a01b036040610f3b848a611f1d565b510151166080610f4b848a611f1d565b510151151590895260988652604089209060ff801983541691151516179055565b611eb8565b610ee5565b634e487b7160e01b895260416004528489fd5b8335828111610faf578691610fa483928a3691880101611b28565b815201930192610ecc565b8980fd5b8780fd5b8380fd5b50346102ce5760203660031901126102ce5760209060ff906040906001600160a01b03610fe6611aee565b168152609884522054166040519015158152f35b50346102ce5760203660031901126102ce57611017323314611ddf565b61102660026065541415611d93565b6002606555611036600435611c01565b50600681015460d35481018091116117e85760ff60138301541660058110156117d45760020361179f57804311156117615760028201546001600160a01b031690338214801561174b575b15611706576001906040516020810191448352426040830152406060820152606081526110ad816119b1565b51902060801c1690916009810160ff600883015460081c1683036116ec575b6001820154808060011b04600214811517156116d85760cc5460405163101266c160e31b81526001600160a01b0387811660048301529091889183916024918391165afa9081156116cd57879161161b575b505161012c90691022cf6e5318dda00000811061147757505061271061114960145b8360011b611edd565b0491611156600435611c01565b5060098101805460d0541461146c57905b60018060a01b036003830154169160048101549160016111878885611edd565b910154908115611458576111a66111bb95949392600492048094611f5a565b91015560018060a01b0360cb54163092612910565b60cb5460cd5460405163095ea7b360e01b81526001600160a01b0391821660048201526024810184905292969291602091839160449183918e91165af1801561141e57611429575b5060cd5488906001600160a01b0316803b1561067e57819060246040518094819363b6b55f2560e01b83528b60048401525af1801561141e5761140b575b5087916112ce88611253600435611c01565b506112928260018060a01b03600c8401541661127260098501546118e3565b5060010154600d8501549160089190911c6001600160a01b031690612910565b5060018060a01b036011820154169060126112b0600e8301546118e3565b50600101549101549160089190911c6001600160a01b031690612910565b505460d0540361134e575b907fda9190ca87ab93aa17e331018af4f13243e5b051d046b000a49ea3c5361559fc9660e096959493926013600360ff19828401541617910155604051956004358752602087015260018060a01b03166040860152606085015260011b608084015260a083015260c0820152a1600160655580f35b60ce54604051631e7a863d60e11b81526001600160a01b038981166004830152600186901b602483015292935091602091839160449183918d91165af19081156114005788916113a0575b50906112d9565b959493929190506020863d6020116113f8575b816113c0602093836119e7565b810103126105aa57945193949293919290917fda9190ca87ab93aa17e331018af4f13243e5b051d046b000a49ea3c5361559fc611399565b3d91506113b3565b6040513d8a823e3d90fd5b6114179098919861196d565b9638611241565b6040513d8b823e3d90fd5b61144a9060203d602011611451575b61144281836119e7565b810190611f42565b5038611203565b503d611438565b634e487b7160e01b8c52601260045260248cfd5b50600e810190611167565b690d2106d815ebeac0000081106114975750506127106111496028611140565b690a968163f0a57b40000081106114b7575050612710611149603c611140565b6906c6b935b8bbd400000081106114d75750506127106111496050611140565b6903635c9adc5dea00000081106114f75750506127106111496064611140565b6901b1ae4d6e2ef500000081106115175750506127106111496078611140565b68d8d726b7177a8000008110611536575050612710611149608c611140565b68bdbc41e0348b300000811061155557505061271061114960a0611140565b68a2a15d09519be00000811061157457505061271061114960b4611140565b68878678326eac900000811061159357505061271061114960c8611140565b686c6b935b8bbd40000081106115b257505061271061114960dc611140565b685150ae84a8cdf0000081106115d157505061271061114960f0611140565b683635c9adc5dea0000081106115f1575050612710611149610104611140565b681b1ae4d6e2ef5000001161160f5750612710611149610118611140565b61114961271091611140565b90503d8088833e61162c81836119e7565b6020828281010312610fb3578151916001600160401b0383116116c957606083820183830103126116c95760405192606084018481106001600160401b038211176116b557604090815282820180518652602080820151908701520151906001600160401b0382116116b1576116a69383019201016122e2565b60408201523861111e565b8a80fd5b634e487b7160e01b8b52604160045260248bfd5b8880fd5b6040513d89823e3d90fd5b634e487b7160e01b86526011600452602486fd5b5060038101546001600160a01b03169250600e81016110cc565b60405162461bcd60e51b815260206004820152601760248201527f6f6e6c7920706c61796572732063616e2066696e6973680000000000000000006044820152606490fd5b5060038301546001600160a01b03163314611081565b60405162461bcd60e51b815260206004820152601660248201527573686f756c64207761697420666f7220626c6f636b7360501b6044820152606490fd5b60405162461bcd60e51b815260206004820152600d60248201526c0c6c2dcdcdee840ccd2dcd2e6d609b1b6044820152606490fd5b634e487b7160e01b84526021600452602484fd5b634e487b7160e01b83526011600452602483fd5b50346102ce57806003193601126102ce5760cb546040516001600160a01b039091168152602090f35b50346102ce5760203660031901126102ce576004359060cf548210156102ce57611883611851836118e3565b5061185b81611a08565b9060ff600182015491600360028201549101549060405195869560c0875260c0870190611aae565b8385166020870152600894851c6001600160a01b03166040870152606086019190915281831615156080860152921c16151560a08301520390f35b90503461067e578160031936011261067e5760ce546001600160a01b03168152602090f35b60cf5481101561191d5760cf60005260021b7facb8d954e2cfef495862221e91bd7523613cf8808827cb33edfe4904cc51bf290190600090565b634e487b7160e01b600052603260045260246000fd5b90600182811c92168015611963575b602083101461194d57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611942565b6001600160401b03811161198057604052565b634e487b7160e01b600052604160045260246000fd5b60c081019081106001600160401b0382111761198057604052565b608081019081106001600160401b0382111761198057604052565b606081019081106001600160401b0382111761198057604052565b90601f801991011681019081106001600160401b0382111761198057604052565b9060405191826000825492611a1c84611933565b908184526001948581169081600014611a8b5750600114611a48575b5050611a46925003836119e7565b565b9093915060005260209081600020936000915b818310611a73575050611a4693508201013880611a38565b85548884018501529485019487945091830191611a5b565b915050611a4694506020925060ff191682840152151560051b8201013880611a38565b919082519283825260005b848110611ada575050826000602080949584010152601f8019910116010190565b602081830181015184830182015201611ab9565b600435906001600160a01b03821682036105aa57565b6001600160401b0381116119805760051b60200190565b359081151582036105aa57565b91909160c0818403126105aa5760405190611b4282611996565b819381356001600160401b03908181116105aa5783019082601f830112156105aa5781359081116119805760405191602093611b8785601f19601f86011601856119e7565b8284528483830101116105aa57816000928580930183860137830101528352808201359060ff821682036105aa578301526040810135906001600160a01b03821682036105aa5760a0611bfc918193604086015260608101356060860152611bf160808201611b1b565b608086015201611b1b565b910152565b60d15481101561191d5760149060d1600052027f695fb3134ad82c3b8022bc5464edd0bcc9424ef672b52245dcb6ab2374327ce30190600090565b9060405160a081018181106001600160401b03821117611980576040908152835482526001840154602083015260028401549082015260038301546001600160a01b031660608201526004909201546080830152565b6033546001600160a01b03163303611ca657565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b603380546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b15611d3a57565b60405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201526a6e697469616c697a696e6760a81b6064820152608490fd5b15611d9a57565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b15611de657565b60405162461bcd60e51b815260206004820152601460248201527318dbdb9d1c9858dd081b9bdd08185b1b1bddd95960621b6044820152606490fd5b9060009291805491611e3383611933565b918282526001938481169081600014611e955750600114611e55575b50505050565b90919394506000526020928360002092846000945b838610611e81575050505001019038808080611e4f565b805485870183015294019385908201611e6a565b9294505050602093945060ff191683830152151560051b01019038808080611e4f565b6000198114611ec75760010190565b634e487b7160e01b600052601160045260246000fd5b81810292918115918404141715611ec757565b80511561191d5760200190565b80516001101561191d5760400190565b80516002101561191d5760600190565b805182101561191d5760209160051b010190565b60ff16604d8111611ec757600a0a90565b908160209103126105aa575180151581036105aa5790565b91908203918211611ec757565b611f70906118e3565b509160018301549260018060a01b039060ff6003838760081c169201541694826099541690600090831580928115612281575b50156121f65760405192611fb6846119cc565b600284526040366020860137600484602088609754166040519384809263ef8ef56f60e01b82525afa80156121ea57612005926000916121bc575b5088611ffc83611ef0565b91169052611efd565b525b61203d60008660975416946040958a87518095819482936307c0329d60e21b845260048401528a6024840152604483019061253e565b03915afa9081156121b157899493929161205f91600091612190575b50611ef0565b5198612167575b501561210b578634106120d7578634116120a5575b505b61209c57612092908583609954163092612910565b5060995416929190565b93925082919050565b60008080806120b48b34611f5a565b8181156120ce575b3390f161207b575b513d6000823e3d90fd5b506108fc6120bc565b5162461bcd60e51b815260206004820152600e60248201526d6e6f7420656e6f75676820706c7360901b6044820152606490fd5b80516323b872dd60e01b815233600482015230602482015260448101889052906020826064816000885af19081156120c45750612149575b5061207d565b6121609060203d81116114515761144281836119e7565b5038612143565b670de0b6b3a764000091985061218260ff6121889216611f31565b88611edd565b049638612066565b6121ab913d8091833e6121a381836119e7565b810190612516565b38612059565b84513d6000823e3d90fd5b6121dd915060203d81116121e3575b6121d581836119e7565b8101906124e9565b38611ff1565b503d6121cb565b6040513d6000823e3d90fd5b60405192612203846119b1565b6003845260603660208601376004848661221c82611ef0565b52602088609754166040519384809263ef8ef56f60e01b82525afa80156121ea5761225d92600091612263575b508861225483611efd565b91169052611f0d565b52612007565b61227b915060203d81116121e3576121d581836119e7565b38612249565b90506004602087609754166040519283809263ef8ef56f60e01b82525afa9182156122d6579087926122b8575b5016841438611fa3565b6122d0915060203d81116121e3576121d581836119e7565b386122ae565b604051903d90823e3d90fd5b81601f820112156105aa578051916122f983611b04565b9261230760405194856119e7565b808452602092838086019260051b8201019283116105aa578301905b828210612331575050505090565b81518152908301908301612323565b906124d35781518051906001600160401b038211611980576123628354611933565b601f811161248b575b50602090601f831160011461242057918060a09492600394600092612415575b50508160011b9160001990851b1c19161781555b6001810160ff602086015116815490610100600160a81b03604088015160081b16916affffffffffffffffffffff60a81b16171790556060840151600282015501916123fd60808201511515849060ff801983541691151516179055565b0151815461ff00191690151560081b61ff0016179055565b01519050388061238b565b90601f1983169184600052816000209260005b818110612473575092600192859260039660a098961061245b575b505050811b01815561239f565b015160001983871b60f8161c1916905538808061244e565b92936020600181928786015181550195019301612433565b600084815260208120601f850160051c810192602086106124c9575b601f0160051c01915b8281106124be57505061236b565b8181556001016124b0565b90925082906124a7565b634e487b7160e01b600052600060045260246000fd5b908160209103126105aa57516001600160a01b03811681036105aa5790565b604d8111611ec757600a0a90565b906020828203126105aa5781516001600160401b0381116105aa5761253b92016122e2565b90565b90815180825260208080930193019160005b82811061255e575050505090565b83516001600160a01b031685529381019392810192600101612550565b6099546040805163313ce56760e01b81529360049391926020926001600160a01b03929183169084888881855afa9788156128cb57600098612890575b5083600091168082526098865260ff878320541661287b5780158015612820575b1561270e5750508451936125ec856119cc565b60028552853682870137836097541693865163ef8ef56f60e01b815282818a81895afa9283156127035792612671979592600097959261264b9589936126e4575b505061263887611ef0565b9116905261264585611efd565b52612508565b855180958194829363d06ca61f60e01b84528a840152886024840152604483019061253e565b03915afa9182156120c4575060ff91612692916000916126cb575b50611efd565b51925b166012039060ff82116126b65750906126b061253b92611f31565b90611edd565b601190634e487b7160e01b6000525260246000fd5b6126de913d8091833e6121a381836119e7565b3861268c565b6126fb929350803d106121e3576121d581836119e7565b90388061262d565b88513d6000823e3d90fd5b939291909486519461271f866119b1565b600386526060368388013761273386611ef0565b52836097541693875163ef8ef56f60e01b815282818b81895afa92831561281657928897959288979592612783956127a99b936127f7575b505061277687611efd565b9116905261264585611f0d565b865180968194829363d06ca61f60e01b84528b840152896024840152604483019061253e565b03915afa9283156127ed5750916127cb918360ff94926127d2575b5050611f0d565b5192612695565b6127e692503d8091833e6121a381836119e7565b38806127c4565b51903d90823e3d90fd5b61280e929350803d106121e3576121d581836119e7565b90388061276b565b89513d8a823e3d90fd5b508786866097541689519283809263ef8ef56f60e01b82525afa908115612871579086918491612854575b501681146125d9565b61286b9150883d8a116121e3576121d581836119e7565b3861284b565b88513d85823e3d90fd5b505050505050505050670de0b6b3a764000090565b8581819a939a3d83116128c4575b6128a881836119e7565b8101031261067e57519060ff821682036102ce575096386125b8565b503d61289e565b86513d6000823e3d90fd5b906080926128fc919695949683526000602084015260a0604084015260a083019061253e565b6001600160a01b0390951660608201520152565b9392906000948315611e4f576001600160a01b03918216908216808214612f88578115612e1b5780612a4a5750908591604094855161294e816119cc565b6002815286366020830137836097541692875163ef8ef56f60e01b8152602081600481885afa908115612a4057906129ce949392918891612a22575b508661299584611ef0565b911690526129a282611efd565b528751637ff36ab560e01b8152600481018790526080602482015296879586948593608485019061253e565b9116604483015242606483015203925af1918215612a195750836129fa9394926129fe575b5050611efd565b5190565b612a1292503d8091833e6121a381836119e7565b38806129f3565b513d85823e3d90fd5b612a3a915060203d81116121e3576121d581836119e7565b3861298a565b89513d89823e3d90fd5b9192909594938360975416966040948551809563ef8ef56f60e01b808352828c602094859160049b8c915afa908115612e11579085918d91612df4575b50168203612bc9578a9b5088999a97985194612aa2866119cc565b600286528a36858801378460975416918b5190815284818c81865afa908115612bbf57928a8c8e8b95612b2698958b8d8c9a8793612b9c575b50612ae590611efd565b91169052612af28c611f0d565b525163095ea7b360e01b81526001600160a01b03909316908301908152602081019490945290948593849291839160400190565b03925af18015612a40579087939291612b7e575b50506097541692612b608851978896879586946338ed173960e01b8652429386016128d6565b03925af1918215612a195750836129fa9394926129fe575050611efd565b81612b9492903d106114515761144281836119e7565b503880612b3a565b612ae5919350612bb8908c8d3d106121e3576121d581836119e7565b9290612adb565b8c513d8c823e3d90fd5b90989a949196999592885191612bde836119b1565b600383526060368a8501378a612bf384611ef0565b52895190815288818d818a5afa908115612dea57908c979695949392918991612dcd575b5081612c2284611efd565b9116905284612c3083611f0d565b5289519a6370a0823160e01b96878d528c8387169e8f9101528a8d6024818a5afa9c8d15612bbf578a9d612d8e575b508b5163095ea7b360e01b81526001600160a01b03909116818a019081526020810186905290918b9183919082908d90829060400103925af18015612d8457612d67575b506097541691823b15610fb35791869391888094612cd68d5197889687958694635c11d79560e01b8652429386016128d6565b03925af18015612d5d57908694939291612d47575b50906024918751998a94859384528301525afa9283156127ed575091612d17575b5061253b9250611f5a565b905082813d8311612d40575b612d2d81836119e7565b810103126105aa5761253b915138612d0c565b503d612d23565b94612d55602493929661196d565b949091612ceb565b87513d87823e3d90fd5b612d7d908a3d8c116114515761144281836119e7565b5038612ca3565b8b513d8b823e3d90fd5b9091929394959697989c508a81813d8311612dc6575b612dae81836119e7565b81010312610faf57519b979695949392919084612c5f565b503d612da4565b612de491508a3d8c116121e3576121d581836119e7565b38612c17565b8a513d8a823e3d90fd5b612e0b9150853d87116121e3576121d581836119e7565b38612a87565b8a513d8e823e3d90fd5b9193905085604091825193612e2f856119cc565b6002855260209084368388013780612e4687611ef0565b528760975416855163ef8ef56f60e01b81528381600481855afa908115612f7e579284928692612ebc958991612f61575b508c612e828c611efd565b91169052885163095ea7b360e01b81526001600160a01b039091166004820152602481019290925290928391908290889082906044820190565b03925af18015612f5757612f39575b505084319560975416803b15612f35578583612eff9686519788958694859363791ac94760e01b85524292600486016128d6565b03925af1908115612f2c575061253b949550612f1d575b5031611f5a565b612f269061196d565b38612f16565b513d87823e3d90fd5b8280fd5b81612f4f92903d106114515761144281836119e7565b503880612ecb565b85513d86823e3d90fd5b612f789150853d87116121e3576121d581836119e7565b38612e77565b87513d88823e3d90fd5b5092945050505056fea2646970667358221220ff4175ebaf8361ba29e92f8923220e6efe8af5f1186e9a77e8b86e6cbad79c5a64736f6c63430008130033