Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 9967714 | 246 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
DeathFun
Compiler Version
v0.8.24+commit.e11b9ed9
ZkSolc Version
v1.5.12
Optimization Enabled:
Yes with Mode z
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
// Revert to standard OpenZeppelin imports
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; // Import ECDSA
/**
* @title DeathRaceGame
* @dev Smart contract to manage Death Race game on Abstract L2 (zkSync Era)
*
* The contract handles game creation, payout management, and provable fairness
* for the Death Race game, where players navigate through a grid to maximize
* their potential winnings. Requires server-signed parameters for critical actions.
*/
contract DeathFun is Initializable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
using Strings for uint256;
// ===================
// State Variables
// ===================
/// @notice Counter for unique on-chain game IDs
uint256 public gameCounter;
/// @notice Prefix used in messageHash for domain separation
string public messagePrefix;
/// @notice Mapping of admin addresses (can call privileged functions)
mapping(address => bool) public isAdmin;
/// @notice Mapping from preliminary game ID to on-chain game ID
mapping(string => uint256) public preliminaryToOnChainId;
/// @notice Game status enum
enum GameStatus {
Active,
Won,
Lost
}
/// @notice Game data structure
struct Game {
uint256 createdAt; // Block timestamp when game was created
address player; // Player's wallet address
uint256 betAmount; // Original bet amount in wei
GameStatus status; // Current game status
uint256 payoutAmount; // Final payout amount (0 if lost)
bytes32 gameSeedHash; // Hash of the seed + gameConfig + algoVersion
string gameSeed; // Seed used to generate the game state
string algoVersion; // Algorithm version for going from seed to game state
string gameConfig; // JSON string containing game configuration
string gameState; // JSON string containing final game state/player moves
}
/// @notice Mapping from on-chain game ID to Game data
mapping(uint256 => Game) public games;
/// @notice Reserved slots for upgradeability
uint256[50] private __gap; // 50 reserved slots
// ===================
// Events
// ===================
/// @notice Emitted when a new game is created
event GameCreated(
string preliminaryGameId,
uint256 indexed onChainGameId,
address indexed player,
uint256 betAmount,
bytes32 gameSeedHash // Keep seed hash in event for listener correlation
);
/// @notice Emitted when a payout is sent to a player
event PayoutSent(
uint256 indexed onChainGameId,
uint256 amount,
address indexed recipient
);
/// @notice Emitted when a game status is updated
event GameStatusUpdated(
uint256 indexed onChainGameId,
GameStatus status
);
/// @notice Emitted when funds are deposited directly into the contract
event DepositReceived(address indexed sender, uint256 amount);
/// @notice Emitted when an admin is added
event AdminAdded(address indexed newAdmin);
/// @notice Emitted when an admin is removed
event AdminRemoved(address indexed removedAdmin);
// ===================
// Errors
// ===================
/// @notice Error when game already exists
error GameAlreadyExists(string preliminaryGameId);
/// @notice Error when game doesn't exist
error GameDoesNotExist(uint256 onChainGameId);
/// @notice Error when caller is not the player
error NotGamePlayer(uint256 onChainGameId, address caller);
/// @notice Error when game is not in active status
error GameNotActive(uint256 onChainGameId);
/// @notice Error when payout fails
error PayoutFailed(uint256 onChainGameId, uint256 amount);
/// @notice Error when server signature is invalid or doesn't match expected signer
error InvalidServerSignature();
// ===================
// Constructor
// ===================
/**
* @dev Initializer sets the contract owner and initial server signer address
* @param _messagePrefix The prefix used in messageHash for domain separation
*/
function initialize(string memory _messagePrefix) public initializer {
__Ownable_init(msg.sender);
__ReentrancyGuard_init();
gameCounter = 0;
messagePrefix = _messagePrefix;
isAdmin[msg.sender] = true;
emit AdminAdded(msg.sender);
}
// ===================
// External Functions
// ===================
/**
* @notice Creates a new game placeholder on-chain. Requires server signature.
* Only gameSeedHash is needed for provable fairness.
* @param preliminaryGameId The preliminary game ID generated by the backend
* @param gameSeedHash Hash of the actual game seed (used for listener correlation)
* @param algoVersion The algorithm version for provable fairness
* @param gameConfig JSON string containing game configuration
* @param deadline The latest timestamp this signature is valid for
* @param serverSignature Signature from the server authorizing this game creation
*/
function createGame(
string calldata preliminaryGameId,
bytes32 gameSeedHash,
string calldata algoVersion,
string calldata gameConfig,
uint256 deadline,
bytes calldata serverSignature
) external payable {
require(block.timestamp <= deadline, "Signature expired");
// Use domain separation and abi.encode for signature
bytes32 messageHash = keccak256(
abi.encode(
string.concat(messagePrefix, ":createGame"),
preliminaryGameId,
gameSeedHash,
algoVersion,
gameConfig,
msg.sender,
msg.value,
deadline
)
);
_verifyAnyAdminSignature(messageHash, serverSignature);
if (preliminaryToOnChainId[preliminaryGameId] != 0) {
revert GameAlreadyExists(preliminaryGameId);
}
gameCounter += 1;
uint256 onChainGameId = gameCounter;
preliminaryToOnChainId[preliminaryGameId] = onChainGameId;
// Create game struct with all metadata
games[onChainGameId] = Game({
player: msg.sender,
betAmount: msg.value,
gameSeedHash: gameSeedHash,
status: GameStatus.Active,
payoutAmount: 0,
gameSeed: "",
algoVersion: algoVersion,
gameConfig: gameConfig,
gameState: "",
createdAt: block.timestamp
});
emit GameCreated(preliminaryGameId, onChainGameId, msg.sender, msg.value, gameSeedHash);
}
/**
* @notice Processes a cash out. Callable by an admin (no signature) or by the player with a valid server signature.
* @param onChainGameId The on-chain game ID.
* @param payoutAmount The NET amount to pay out.
* @param gameState JSON string containing final game state/player moves
* @param gameSeed The final game seed to store for provable fairness
* @param deadline The latest timestamp this signature is valid for (only required if called by player)
* @param serverSignature Signature from an admin authorizing this cash out (only required if called by player)
*/
function cashOut(
uint256 onChainGameId,
uint256 payoutAmount,
string calldata gameState,
string calldata gameSeed,
uint256 deadline,
bytes calldata serverSignature
) external nonReentrant {
Game storage game = games[onChainGameId];
if (game.player == address(0)) {
revert GameDoesNotExist(onChainGameId);
}
// Check status - This prevents cashing out already Won/Lost games
if (game.status != GameStatus.Active) {
revert GameNotActive(onChainGameId);
}
require(payoutAmount > 0, "PayoutZero");
address playerAddress = game.player;
if (!isAdmin[msg.sender]) {
require(msg.sender == playerAddress, "Not authorized");
require(block.timestamp <= deadline, "Signature expired");
bytes32 messageHash = keccak256(
abi.encode(
string(abi.encodePacked(messagePrefix, ":cashOut")),
onChainGameId,
payoutAmount,
gameState,
gameSeed,
deadline
)
);
_verifyAnyAdminSignature(messageHash, serverSignature);
}
// --- EFFECTS (set state before external call) ---
game.status = GameStatus.Won;
game.payoutAmount = payoutAmount;
game.gameState = gameState;
game.gameSeed = gameSeed; // Store the game seed
// --- INTERACTION ---
(bool success, ) = payable(playerAddress).call{value: payoutAmount}("");
if (!success) {
revert PayoutFailed(onChainGameId, payoutAmount);
}
emit GameStatusUpdated(onChainGameId, GameStatus.Won);
emit PayoutSent(onChainGameId, payoutAmount, playerAddress);
}
/**
* @notice Mark a game as lost. Callable by an admin (no signature) or by the player with a valid server signature.
* @param onChainGameId The on-chain game ID
* @param gameState JSON string containing final game state/player moves
* @param gameSeed The final game seed to store for provable fairness
* @param deadline The latest timestamp this signature is valid for (only required if called by player)
* @param serverSignature Signature from an admin authorizing this loss (only required if called by player)
*/
function markGameAsLost(
uint256 onChainGameId,
string calldata gameState,
string calldata gameSeed,
uint256 deadline,
bytes calldata serverSignature
) external {
Game storage game = games[onChainGameId];
if (game.player == address(0)) {
revert GameDoesNotExist(onChainGameId);
}
if (game.status != GameStatus.Active) {
revert GameNotActive(onChainGameId);
}
address playerAddress = game.player;
if (!isAdmin[msg.sender]) {
require(msg.sender == playerAddress, "Not authorized");
require(block.timestamp <= deadline, "Signature expired");
bytes32 messageHash = keccak256(
abi.encode(
string(abi.encodePacked(messagePrefix, ":markGameAsLost")),
onChainGameId,
gameState,
gameSeed,
deadline
)
);
_verifyAnyAdminSignature(messageHash, serverSignature);
}
game.status = GameStatus.Lost;
game.gameState = gameState;
game.gameSeed = gameSeed; // Store the game seed
emit GameStatusUpdated(onChainGameId, GameStatus.Lost);
}
/**
* @notice Get details for a specific game
* @param onChainGameId The on-chain game ID
* @return Game struct with all game details
*/
function getGameDetails(uint256 onChainGameId) external view returns (Game memory) {
if (games[onChainGameId].player == address(0)) { // Check if game actually exists
revert GameDoesNotExist(onChainGameId);
}
return games[onChainGameId];
}
/**
* @notice Get on-chain ID from preliminary ID
* @param preliminaryGameId The preliminary game ID
* @return onChainGameId The corresponding on-chain game ID (0 if not found)
*/
function getOnChainGameId(string calldata preliminaryGameId) external view returns (uint256) {
return preliminaryToOnChainId[preliminaryGameId];
}
// ===================
// Admin Functions
// ===================
/**
* @notice Withdraw contract funds to a specified recipient. Only callable by the owner.
* Funds represent implicitly collected fees (Total Bets - Total Net Payouts).
* @param amount The amount to withdraw.
* @param recipient The address to send the withdrawn funds to.
*/
function withdrawFunds(uint256 amount, address payable recipient) external onlyOwner nonReentrant {
require(amount > 0, "Withdraw amount must be positive");
require(recipient != address(0), "Invalid recipient address");
require(amount <= address(this).balance, "Insufficient contract balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Withdrawal failed");
}
/**
* @notice Receive function to accept direct Ether deposits into the treasury.
*/
receive() external payable {
emit DepositReceived(msg.sender, msg.value);
}
/**
* @notice Adds a new admin address. Only callable by the contract owner.
* @param newAdmin The address to grant admin privileges.
*/
function addAdmin(address newAdmin) external onlyOwner {
require(newAdmin != address(0), "Invalid admin address");
require(!isAdmin[newAdmin], "Already admin");
isAdmin[newAdmin] = true;
emit AdminAdded(newAdmin);
}
/**
* @notice Removes an admin address. Only callable by the contract owner.
* @param adminToRemove The address to revoke admin privileges from.
*/
function removeAdmin(address adminToRemove) external onlyOwner {
require(isAdmin[adminToRemove], "Not an admin");
require(adminToRemove != owner(), "Cannot remove owner");
isAdmin[adminToRemove] = false;
emit AdminRemoved(adminToRemove);
}
/**
* @notice Allows the owner to manually set the gameCounter (for migration/upgrades).
* @param newCounter The new value for gameCounter. Must be >= current value.
*/
function setGameCounter(uint256 newCounter) external onlyOwner {
require(newCounter >= gameCounter, "Cannot decrease gameCounter");
gameCounter = newCounter;
}
// ===============================
// Internal Helper Functions
// ===============================
/**
* @dev Verifies that the provided signature for the given hash was generated by any admin.
* Reverts with InvalidServerSignature if verification fails.
* @param _hash The hash that was signed.
* @param _signature The signature bytes (expected length 65).
*/
function _verifyAnyAdminSignature(bytes32 _hash, bytes calldata _signature) internal view {
// Use OpenZeppelin's ECDSA library for robust verification
bytes32 prefixedHash = ECDSA.toEthSignedMessageHash(_hash);
address recoveredSigner = ECDSA.recover(prefixedHash, _signature);
if (recoveredSigner == address(0) || !isAdmin[recoveredSigner]) {
revert InvalidServerSignature();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {ContextUpgradeable} from "../utils/ContextUpgradeable.sol";
import {Initializable} from "../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.
*
* The initial owner is set to the address provided by the deployer. 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 {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation = 0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(address initialOwner) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(address initialOwner) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @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) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling 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 {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../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 EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
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;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._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() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
pragma solidity ^0.8.0;
import "./math/Math.sol";
import "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _SYMBOLS = "0123456789abcdef";
uint8 private constant _ADDRESS_LENGTH = 20;
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toString(int256 value) internal pure returns (string memory) {
return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)
pragma solidity ^0.8.0;
import "../Strings.sol";
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
enum RecoverError {
NoError,
InvalidSignature,
InvalidSignatureLength,
InvalidSignatureS,
InvalidSignatureV // Deprecated in v4.8
}
function _throwError(RecoverError error) private pure {
if (error == RecoverError.NoError) {
return; // no error: do nothing
} else if (error == RecoverError.InvalidSignature) {
revert("ECDSA: invalid signature");
} else if (error == RecoverError.InvalidSignatureLength) {
revert("ECDSA: invalid signature length");
} else if (error == RecoverError.InvalidSignatureS) {
revert("ECDSA: invalid signature 's' value");
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature` or error string. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*
* Documentation for signature generation:
* - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
* - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
if (signature.length == 65) {
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
/// @solidity memory-safe-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return tryRecover(hash, v, r, s);
} else {
return (address(0), RecoverError.InvalidSignatureLength);
}
}
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, signature);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
*
* See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError) {
bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
uint8 v = uint8((uint256(vs) >> 255) + 27);
return tryRecover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
*
* _Available since v4.2._
*/
function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, r, vs);
_throwError(error);
return recovered;
}
/**
* @dev Overload of {ECDSA-tryRecover} that receives the `v`,
* `r` and `s` signature fields separately.
*
* _Available since v4.3._
*/
function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
return (address(0), RecoverError.InvalidSignatureS);
}
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
if (signer == address(0)) {
return (address(0), RecoverError.InvalidSignature);
}
return (signer, RecoverError.NoError);
}
/**
* @dev Overload of {ECDSA-recover} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
(address recovered, RecoverError error) = tryRecover(hash, v, r, s);
_throwError(error);
return recovered;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 message) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, "\x19Ethereum Signed Message:\n32")
mstore(0x1c, hash)
message := keccak256(0x00, 0x3c)
}
}
/**
* @dev Returns an Ethereum Signed Message, created from `s`. This
* produces hash corresponding to the one signed with the
* https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
* JSON-RPC method as part of EIP-191.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
}
/**
* @dev Returns an Ethereum Signed Typed Data, created from a
* `domainSeparator` and a `structHash`. This produces hash corresponding
* to the one signed with the
* https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
* JSON-RPC method as part of EIP-712.
*
* See {recover}.
*/
function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 data) {
/// @solidity memory-safe-assembly
assembly {
let ptr := mload(0x40)
mstore(ptr, "\x19\x01")
mstore(add(ptr, 0x02), domainSeparator)
mstore(add(ptr, 0x22), structHash)
data := keccak256(ptr, 0x42)
}
}
/**
* @dev Returns an Ethereum Signed Data with intended validator, created from a
* `validator` and `data` according to the version 0 of EIP-191.
*
* See {recover}.
*/
function toDataWithIntendedValidatorHash(address validator, bytes memory data) internal pure returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x00", validator, data));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../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;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1, "Math: mulDiv overflow");
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10, rounded down, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256, rounded down, of a positive value.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}{
"evmVersion": "paris",
"optimizer": {
"enabled": true,
"mode": "z",
"fallback_to_optimizing_for_size": true
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"detectMissingLibraries": false,
"forceEVMLA": false,
"enableEraVMExtensions": true,
"codegen": "evmla",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"preliminaryGameId","type":"string"}],"name":"GameAlreadyExists","type":"error"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"}],"name":"GameDoesNotExist","type":"error"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"}],"name":"GameNotActive","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"InvalidServerSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"internalType":"address","name":"caller","type":"address"}],"name":"NotGamePlayer","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"PayoutFailed","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"removedAdmin","type":"address"}],"name":"AdminRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"preliminaryGameId","type":"string"},{"indexed":true,"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"indexed":true,"internalType":"address","name":"player","type":"address"},{"indexed":false,"internalType":"uint256","name":"betAmount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"gameSeedHash","type":"bytes32"}],"name":"GameCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"indexed":false,"internalType":"enum DeathFun.GameStatus","name":"status","type":"uint8"}],"name":"GameStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"}],"name":"PayoutSent","type":"event"},{"inputs":[{"internalType":"address","name":"newAdmin","type":"address"}],"name":"addAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"internalType":"uint256","name":"payoutAmount","type":"uint256"},{"internalType":"string","name":"gameState","type":"string"},{"internalType":"string","name":"gameSeed","type":"string"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"serverSignature","type":"bytes"}],"name":"cashOut","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"preliminaryGameId","type":"string"},{"internalType":"bytes32","name":"gameSeedHash","type":"bytes32"},{"internalType":"string","name":"algoVersion","type":"string"},{"internalType":"string","name":"gameConfig","type":"string"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"serverSignature","type":"bytes"}],"name":"createGame","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gameCounter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"games","outputs":[{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"betAmount","type":"uint256"},{"internalType":"enum DeathFun.GameStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"payoutAmount","type":"uint256"},{"internalType":"bytes32","name":"gameSeedHash","type":"bytes32"},{"internalType":"string","name":"gameSeed","type":"string"},{"internalType":"string","name":"algoVersion","type":"string"},{"internalType":"string","name":"gameConfig","type":"string"},{"internalType":"string","name":"gameState","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"}],"name":"getGameDetails","outputs":[{"components":[{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"address","name":"player","type":"address"},{"internalType":"uint256","name":"betAmount","type":"uint256"},{"internalType":"enum DeathFun.GameStatus","name":"status","type":"uint8"},{"internalType":"uint256","name":"payoutAmount","type":"uint256"},{"internalType":"bytes32","name":"gameSeedHash","type":"bytes32"},{"internalType":"string","name":"gameSeed","type":"string"},{"internalType":"string","name":"algoVersion","type":"string"},{"internalType":"string","name":"gameConfig","type":"string"},{"internalType":"string","name":"gameState","type":"string"}],"internalType":"struct DeathFun.Game","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"preliminaryGameId","type":"string"}],"name":"getOnChainGameId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_messagePrefix","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"onChainGameId","type":"uint256"},{"internalType":"string","name":"gameState","type":"string"},{"internalType":"string","name":"gameSeed","type":"string"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"serverSignature","type":"bytes"}],"name":"markGameAsLost","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messagePrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"","type":"string"}],"name":"preliminaryToOnChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"adminToRemove","type":"address"}],"name":"removeAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newCounter","type":"uint256"}],"name":"setGameCounter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010003736d2a4d7266ca5ae403e420507c93062aa95020ac72c2c830ad296b6b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x000400000000000200160000000000020000006004100270000003190340019700030000003103550002000000010355000003190040019d00000001002001900000008002000039000000000c0004160000002004000039000000710000c13d000000400020043f000000040030008c000000780000413d000000000201043b000000e0092002700000031d0090009c000000040210037000000044081003700000006407100370000000a4051003700000008406100370000001000b00008a000002390000613d0000031e0090009c000001d60000613d00000004040000390000031f0090009c000000890000613d000000020a000039000003200090009c0000017d0000613d000003210090009c000000e60000613d000003220090009c000002140000613d000003230090009c0000015b0000613d000003240090009c000000240d100370000001080000613d000003250090009c000003510000613d000003260090009c0000015f0000613d000003270090009c000003630000613d000003280090009c000001d00000613d000003290090009c000002280000613d0000032a0090009c000001e80000613d0000032b0090009c0000014b0000613d0000032c0090009c000001900000613d0000032d0090009c000001710000613d0000032e0090009c0000036d0000c13d00000000000c004b0000036d0000c13d00000000010300190c6009f90000040f00000000060100190000032f01000041000000000201041a00000330052001970000033101200198000003c00000613d000000010010008c000003c20000c13d0000000001000410001400000001001d000080020100003900000024030000390000000004000415000000140440008a0000000504400210001100000002001d0000033202000041001200000005001d001300000006001d0c600b760000040f000000110200002900000013060000290000001205000029000000000001004b000003c20000c13d000003330120019700000001011001bf000003340220019700000335022001c7000000000005004b000000000201c0190000032f01000041000000000021041b00000330002001980000006e0000613d0000000001000411001200000005001d001300000006001d0c600ab30000040f00000013080000290000032f01000041000000000101041a0000033000100198000004420000c13d000000400100043d0000033e02000041000003c40000013d000000400020043f00000000000c004b0000036d0000c13d000001000040044300000120000004430000031a0100004100000c610001042e000000000003004b0000036d0000c13d0000008000c0043f0000000001000414000003190010009c0000031901008041000000c0011002100000031b011001c70000800d02000039000000020300003900000000050004110000031c040000410c600b8d0000040f00000001002001900000036d0000613d000000000100001900000c610001042e000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b000000000010043f000100910000003d00000c280000013d0000000002010019001300000001001d0000000401100039000000000101041a000e00000001001d0000000501200039000000000101041a000d00000001001d0000000301200039000000000101041a001200000001001d0000000201200039000000000101041a001100000001001d0000000101200039000000000101041a000f00000001001d000000000102041a001000000001001d00000006012000390c6009610000040f000a00000001001d000000130100002900000007011000390c6009610000040f000b00000001001d000000130100002900000008011000390c6009610000040f00000013020000290000000902200039000c00000001001d00000000010200190c6009610000040f0000000f020000290000034002200197000000400400043d00000020034000390000000000230435000000400240003900000011030000290000000000320435000000100200002900000000002404350000001202000029000000ff0520018f000000020050008c000003a20000213d001200000001001d000000c00240003900000140030000390000000000320435000000a0024000390000000d03000029000000000032043500000080024000390000000e0300002900000000003204350000006002400039000000000052043500000140024000390000000a01000029001300000004001d0c6009ad0000040f000000000201001900000013030000290000000001310049000000e00330003900000000001304350000000b010000290c6009ad0000040f000000000201001900000013030000290000010001300039000000000332004900000000003104350000000c010000290c6009ad0000040f000000000201001900000013030000290000012001300039000000000332004900000000003104350000001201000029000004200000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000202043b000001c001000039000000400010043f000000800000043f000000a00000043f000000c00000043f000000e00000043f000001000000043f000001200000043f0000006001000039000001400010043f000001600010043f000001800010043f000001a00010043f001300000002001d000000000020043f000100fc0000003d00000c280000013d00000000030100190000000101100039000000000101041a00000340011001980000036f0000c13d0000034901000041000001c00010043f0000001301000029000001c40010043f000001c00100003900000024020000390c600b4f0000040f000000a40030008c0000036d0000413d00000000000c004b0000036d0000c13d00000000050d043b000003310050009c0000036d0000213d0000002307500039000000000037004b0000036d0000813d0000000407500039000000000771034f000000000707043b001300000007001d000003310070009c0000036d0000213d0000002407500039001200000007001d0000001305700029000000000035004b0000036d0000213d000000000508043b000003310050009c0000036d0000213d0000002307500039000000000037004b0000036d0000813d0000000407500039000000000771034f000000000707043b001100000007001d000003310070009c0000036d0000213d0000002407500039001000000007001d0000001105700029000000000035004b0000036d0000213d000000000506043b000003310050009c0000036d0000213d0000002306500039000000000036004b0000036d0000813d0000000406500039000000000161034f000000000101043b000f00000001001d000003310010009c0000036d0000213d0000002405500039000e00000005001d0000000f01500029000000000031004b0000036d0000213d000000000102043b000d00000001001d000000000010043f000101440000003d00000c280000013d000c00000001001d0000000101100039000000000101041a000b03400010019c000004fc0000c13d0000034901000041000005c50000013d00000000000c004b0000036d0000c13d00000000010300190c6009f90000040f0000000013010434001200000003001d000000400200043d001300000002001d0c6009a10000040f0000001203000029000000130100002900000000041300190000000302000039000000000024043500000020023000390000020f0000013d00000000000c004b0000036d0000c13d000000000100041a000002240000013d00000000000c004b0000036d0000c13d0c600b400000040f0000034b01000041000000000201041a0000035103200197000000000031041b00000000010004140000034005200197000003190010009c0000031901008041000000c00110021000000339011001c70000800d02000039000000030300003900000352040000410000000006000019000000840000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b001300000001001d000003400010009c0000036d0000213d0c600b400000040f00000013010000290c600ab30000040f000000870000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b000003400010009c0000036d0000213d001303400010019b0c600b400000040f000101880000003d00000c180000013d000003c70000c13d000000400100043d00000044021000390000035803000041000000000032043500000024021000390000000c03000039000004a70000013d00130000000d0353000000c40030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000608043b000003310060009c0000036d0000213d0000002308600039000000000038004b0000036d0000813d0000000408600039000000000881034f000000000808043b001200000008001d000003310080009c0000036d0000213d0000002408600039001100000008001d0000001206800029000000000036004b0000036d0000213d000000000607043b000003310060009c0000036d0000213d0000002307600039000000000037004b0000036d0000813d0000000407600039000000000771034f000000000707043b001000000007001d000003310070009c0000036d0000213d0000002407600039000f00000007001d0000001006700029000000000036004b0000036d0000213d000000000505043b000003310050009c0000036d0000213d0000002306500039000000000036004b0000036d0000813d0000000406500039000000000161034f000000000101043b000e00000001001d000003310010009c0000036d0000213d0000002405500039000d00000005001d0000000e01500029000000000031004b0000036d0000213d0000033601000041000000000301041a000000020030008c0000059d0000c13d0000034a01000041000000800010043f0000008001000039000003c50000013d00000000000c004b0000036d0000c13d0000034b01000041000000000101041a0000034001100197000002240000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b001300000001001d0c600b400000040f000000000100041a0000001302000029000000000012004b000003a80000813d000000400100043d00000044021000390000035903000041000000000032043500000024021000390000001b03000039000004a70000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b000003310010009c0000036d0000213d000000040110003900000000020300190c6009340000040f0000001f0420018f000000200300008a00000000053201700000000206100367000000400100043d0000000003510019000001fe0000613d000000000706034f0000000008010019000101fd0000003d00000c4e0000013d000001fb0000c13d000000000004004b00000003070000390000020c0000613d000000000556034f0000000304400210000000000603043300000000064601cf000000000646022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000464019f00000000004304350000000003210019000000000073043500000020022000390c600b610000040f000000000201041a000000400100043d0000000000210435000002260000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b000003400010009c0000036d0000213d000000000010043f0000002000a0043f000000400200003900000000010000190c600b610000040f000000000101041a000000ff001001900000000001000039000000010100c039000000800010043f00000080010000390000002002000039000004230000013d00000000000c004b0000036d0000c13d0000000102000039000000000302041a000000010430019000000001013002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000553013f0000000100500190000003aa0000613d0000035f01000041000000000010043f0000002201000039000003a50000013d000000c40030008c0000036d0000413d000000000202043b000003310020009c0000036d0000213d0000002304200039000000000034004b0000036d0000813d0000000404200039000000000441034f000000000404043b001300000004001d000003310040009c0000036d0000213d0000002404200039001200000004001d0000001302400029000000000032004b0000036d0000213d000000000208043b000003310020009c0000036d0000213d0000002304200039000000000034004b0000036d0000813d0000000404200039000000000441034f000000000404043b001100000004001d000003310040009c0000036d0000213d0000002404200039001000000004001d0000001102400029000000000032004b0000036d0000213d000000000207043b000003310020009c0000036d0000213d0000002304200039000000000034004b0000036d0000813d0000000404200039000000000441034f000000000404043b000f00000004001d000003310040009c0000036d0000213d0000002404200039000e00000004001d0000000f02400029000000000032004b0000036d0000213d000000000205043b000003310020009c0000036d0000213d0000002304200039000000000034004b0000036d0000813d0000000404200039000000000141034f000000000101043b000d00000001001d000003310010009c0000036d0000213d0000002402200039000b00000002001d0000000d01200029000000000031004b0000036d0000213d000000000106043b000c00000001001d000102830000003d00000c220000013d00000342020000410c600b760000040f000800000001001d0000000c0010006c000102890000003d00000c420000013d000a00000001001d00000020011000390c600a1a0000040f0000035a0200004100000000002104350000000a040000290000000001410049000000150210008a00000000002404350000002a01100039000102950000003d00000bfd0000013d000c00000002001d000003310020009c000004490000213d0000000100300190000004490000c13d00000000010400190000000c04000029000000400040043f00000020024000390000010003000039000600000002001d000000000032043500000120024000390c6009ad0000040f0000000c030000290000000002310049000000200220008a00000040033000390000000000230435000000200200008a0000001303000029000000000423017000000000023104360009001f00300193000a00000004001d000000000342001900000002010003670000001204100360000002b80000613d000000000504034f0000000006020019000000005705043c0000000006760436000000000036004b000002b40000c13d0000000905000029000000000005004b0007000300500218000002c70000613d0000000a044003600000000005030433000000070600002900000000056501cf000000000565022f000000000404043b0000010006600089000000000464022f00000000046401cf000000000454019f00000000004304350000001305000029000000000352001900000000000304350000002403100370000000000303043b0000000c06000029000000600460003900000000003404350000001f03500039000000200500008a000500000053017300000005022000290000000003620049000000200330008a0000008004600039000000000034043500000010041003600000001103000029000000000232043600000000055301700000001f0630018f0000000003520019000002e30000613d000000000704034f0000000008020019000102e20000003d00000c4e0000013d000002e00000c13d000000000006004b000002e90000613d000000000454034f0000000305600210000102e90000003d00000ba10000013d0000001104000029000000000342001900000000000304350000001f03400039000000200600008a000000000363016f00000000023200190000000c040000290000000003420049000000200330008a000000a00440003900000000003404350000000e051003600000000f04000029000000000342043600000000066401700000001f0740018f0000000004630019000003020000613d000000000805034f0000000009030019000000008a08043c0000000009a90436000000000049004b000002fe0000c13d000000000007004b000003060000613d000103060000003d00000bab0000013d0000000f06000029000000000463001900000000000404350000000c07000029000000e00470003900000000050004160000000000540435000000c004700039000000000500041100000000005404350000008401100370000000000101043b000001000470003900000000001404350000001f01600039000000200400008a000000000141016f00000000017100490000000003310019000000000112001900000000001704350000001f01300039000000000241016f0000000001720019000000000021004b00000000020000390000000102004039000003310010009c000004490000213d0000000100200190000004490000c13d000000400010043f0000000c01000029000000000201043300000006010000290c600b610000040f0000000b020000290000000d030000290c600ad00000040f0000001201000029000600020000036b000d00020010036b000000400100043d0000000a021000290000000a0000006b0000033a0000613d0000000d0300035f0000000004010019000000003503043c0000000004540436000000000024004b000003360000c13d000000090000006b0000000d0400035f000c000a00400364000003400000613d000103400000003d00000beb0000013d00000013030000290000000002310019000000030400003900000000004204350000002002300039000b00000002001d0c600b610000040f000000000101041a000000000001004b0000069d0000c13d000000000100041a000400010010003e000006d00000c13d0000035f01000041000000000010043f0000001101000039000003a50000013d000000240030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b000003400010009c0000036d0000213d001303400010019b0c600b400000040f000000130000006b000003e20000c13d000000400100043d00000044021000390000035403000041000000000032043500000024021000390000001503000039000004a70000013d000000440030008c0000036d0000413d00000000000c004b0000036d0000c13d000000000102043b001300000001001d00000000010d043b001200000001001d000003400010009c000003b80000a13d000000000100001900000c62000104300000030002000039000000400020043f000000000203041a000001c00020043f000001e00010043f0000000201300039000000000101041a000002000010043f0000000301300039000000000101041a000000ff0110018f000000020010008c000003a20000213d000002200010043f0000000401300039000000000101041a000002400010043f0000000501300039000000000101041a000002600010043f0000000601300039001300000003001d0c6009610000040f000002800010043f000000130100002900000007011000390c6009610000040f000002a00010043f000000130100002900000008011000390c6009610000040f000002c00010043f000000130100002900000009011000390c6009610000040f000002e00010043f0000002001000039000000400300043d0000000001130436000001c00200043d0000000000210435000001e00100043d0000034001100197000000400230003900000000001204350000006001300039000002000200043d0000000000210435000002200100043d000000020010008c000004020000a13d0000035f01000041000000000010043f0000002101000039000000040010043f000003600100004100000c6200010430000000000020041b000000870000013d000000800010043f000000000004004b000003d40000613d000000000020043f00000338020000410000000003000019000000a004300039000000000013004b000003d90000813d000000000502041a000000000054043500000020033000390000000102200039000003b00000013d0c600b400000040f0000033601000041000000000201041a000000020020008c000003f30000c13d000000400100043d0000034a02000041000003c40000013d000000000005004b0000005b0000613d000000400100043d0000033f02000041000000000021043500000004020000390c600b4f0000040f0000034b03000041000000000303041a00000340033001970000001305000029000000000035004b000004250000c13d000000400100043d00000044021000390000035703000041000000000032043500000024021000390000001303000039000004a70000013d0000000002b3016f000000a00020043f000000000001004b000000c004000039000000a004006039000000800240008a00000080010000390c60094e0000040f0000002001000039000000400200043d001300000002001d00000000021204360000008001000039000004200000013d000103e40000003d00000c180000013d000004310000c13d000001000300008a000000000232016f00000001022001bf000000000021041b0000000001000414000003190010009c0000031901008041000000c00110021000000339011001c70000800d0200003900000002030000390000033a040000410000001305000029000000840000013d0000000202000039000000000021041b000000130000006b000004380000c13d000000400100043d000000440210003900000350030000410000000000320435000003470200004100000000002104350000002402100039000000200300003900000000003204350000000402100039000004ac0000013d00000080023000390000000000120435000000a001300039000002400200043d0000000000210435000000c001300039000002600200043d0000000000210435000000e0023000390000000004030019001300000003001d0000014003000039000002800100043d00000000003204350000016002400039000104130000003d00000c2d0000013d0000010004400039000002a00100043d0000000000340435000104180000003d00000c2d0000013d0000012004400039000002c00100043d00000000003404350001041d0000003d00000c2d0000013d0000014004400039000002e00100043d00000000003404350c6009ad0000040f000000130210006a000000130100002900000000030000190c600b570000040f000001000300008a000000000232016f000000000021041b0000000001000414000003190010009c0000031901008041000000c00110021000000339011001c70000800d0200003900000002030000390000035604000041000000840000013d000000400100043d00000044021000390000035303000041000000000032043500000024021000390000000d03000039000004a70000013d000000120100002900000340011001980000044d0000c13d000000400100043d00000044021000390000034f03000041000000000032043500000024021000390000001903000039000004a70000013d00000001050000390000033601000041000000000051041b000000000000041b0000000001080433000003310010009c000004610000a13d0000035f01000041000000000010043f0000004101000039000003a50000013d001200000001001d0000000001000410001500000001001d0000800a0100003900000024030000390000000004000415000000150440008a00000005044002100000034c020000410c600b760000040f0000001303000029000000000013004b0000047b0000a13d000000400100043d00000044021000390000034e03000041000000000032043500000024021000390000001d03000039000004a70000013d000000000305041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000343013f0000000100300190000002350000c13d000000200020008c0000048f0000413d000000000050043f0000001f031000390000000503300270000003370330009a000000200010008c00000338030040410000001f022000390000000502200270000003370220009a000000000023004b0000048f0000813d000000000003041b0000000103300039000004760000013d0000000001000414000003190010009c0000031901008041000000c00110021000000339011001c70000800902000039000000120400002900000000050000190c600b8d0000040f0000006003100270000103190030019d000300000001035500130001002001930c600a810000040f000000130000006b000004a10000613d00000001010000390000033602000041000000000012041b000000870000013d0000001f0010008c000004af0000a13d0000000007050019000000000050043f000000200200008a000000000321016f000003380200004100000000040000190000002006000039000000000034004b0000000005860019000004bf0000813d0000000005050433000000000052041b000000200440003900000020066000390000000102200039000004980000013d000000400100043d00000044021000390000034d0300004100000000003204350000002402100039000000110300003900000000003204350000034702000041000000000021043500000004021000390000002003000039000000000032043500000064020000390c600b4f0000040f000000000001004b0000000002000019000004b50000613d0000001302000029000000200220003900000000020204330000000303100210000000010400008a000000000334022f000000000343013f000000000232016f0000000101100210000000000112019f00000000020004110000000203000039000004ce0000013d000000000013004b000004c90000813d0000000303100210000000f80330018f000000010400008a000000000334022f000000000343013f0000000004050433000000000334016f000000000032041b000000010110021000000001011001bf000000000200041100000002030000390000000005070019000000000015041b000000000020043f000000200030043f000000400200003900000000010000190c600b610000040f000000000201041a000001000300008a000000000232016f00000001022001bf000000000021041b000000400100043d001300000001001d0000000001000414000003190010009c0000031901008041000000c00110021000000339011001c70000800d0200003900000002030000390000033a0400004100000000050004110c600b8d0000040f00000001002001900000036d0000613d000000120000006b000000870000c13d0000032f01000041000000000201041a0000033b02200197000000000021041b000000010300003900000013010000290000000000310435000003190010009c000003190100804100000040011002100000000002000414000003190020009c0000031902008041000000c002200210000000000112019f0000033c011001c70000800d020000390000033d04000041000000840000013d0000000c010000290000000301100039000a00000001001d000000000101041a000900000001001d000000ff0110018f000000020010008c000003a20000213d000000000001004b000005c40000c13d0000000001000411000105090000003d00000bd60000013d0000057f0000c13d00000000010004110000000b0010006c000000000100003900000001010060390c600a750000040f00000064010000390000000201100367000000000101043b000d00000001001d000105150000003d00000c220000013d00000342020000410c600b760000040f0000000d0010006c0001051a0000003d00000c420000013d000b00000001001d00000020011000390c600a1a0000040f000003550200004100000000002104350000000b040000290000000001410049000000110210008a00000000002404350000002e01100039000105260000003d00000bfd0000013d000d00000002001d000003310020009c000004490000213d0000000100300190000004490000c13d00000000010400190000000d04000029000000400040043f0000002002400039000000a003000039000800000002001d0000000000320435000000c0024000390c6009ad0000040f0000000d060000290000000002610049000000200320008a00000002020003670000000404200370000000000404043b0000006005600039000000000035043500000040036000390000000000430435000000200300008a0000001305000029000000000435017000000000015104360000001f0550018f000000120620036000000000034100190000054b0000613d000000000706034f00000000080100190001054a0000003d00000c4e0000013d000005480000c13d000000000005004b000005510000613d000000000446034f0000000305500210000105510000003d00000ba10000013d0000001304000029000105540000003d00000c470000013d0000000d040000290000000003410049000000200330008a0000008004400039000000000034043500000010052003600000001104000029000000000341043600000000066401700000001f0740018f0000000004630019000005660000613d000000000805034f0000000009030019000000008a08043c0000000009a90436000000000049004b000005620000c13d000000000007004b0000056a0000613d0001056a0000003d00000bab0000013d0000001105000029000000000453001900000000000404350000006402200370000000000202043b0000000d06000029000000a004600039000105730000003d00000bc70000013d000003310010009c000004490000213d0000000100200190000004490000c13d000000400010043f0000000d01000029000000000201043300000008010000290c600b610000040f0000000e020000290000000f030000290c600ad00000040f000001000100008a000000090110017f00000002011001bf0000000a02000029000000000012041b0000000c010000290000000901100039000f00000001001d000105890000003d00000b970000013d000002350000c13d0000000f0100002900000013030000290c600a5c0000040f0000001301000029000000200010008c000006700000413d0000000f01000029000105930000003d00000bf70000013d000000130320017f000000020200036700000000040000190000001206000029000000000034004b00000000056400190000067a0000813d0001059c0000003d00000be50000013d000005970000013d0000000203000039000000000031041b000000000102043b000c00000001001d000000000010043f000105a40000003d00000c280000013d000b00000001001d0000000101100039000000000101041a000a03400010019c000005ab0000c13d0000034901000041000005c90000013d0000000b010000290000000301100039000900000001001d000000000101041a000800000001001d000000ff0110018f000000020010008c000003a20000213d000000000001004b000005c80000c13d000000130100035f000000000101043b001300000001001d000000000001004b000005ce0000c13d0000034701000041000000800010043f0000002001000039000000840010043f0000000a01000039000000a40010043f0000034801000041000000c40010043f0000008001000039000004ad0000013d0000034101000041000000800010043f0000000d01000029000005cb0000013d0000034101000041000000800010043f0000000c01000029000000840010043f0000008001000039000001060000013d0000000001000411000105d10000003d00000bd60000013d0000064f0000c13d00000000010004110000000a0010006c000000000100003900000001010060390c600a750000040f00000084010000390000000201100367000000000101043b001300000001001d000105dd0000003d00000c220000013d00000342020000410c600b760000040f000000130010006c000105e20000003d00000c420000013d000c00000001001d00000020011000390c600a1a0000040f000003430200004100000000002104350000000c040000290000000001410049000000180210008a00000000002404350000002701100039000105ee0000003d00000bfd0000013d001300000002001d000003310020009c000004490000213d0000000100300190000004490000c13d00000000010400190000001304000029000000400040043f0000002002400039000000c003000039000700000002001d0000000000320435000000e0024000390c6009ad0000040f00000002020003670000000403200370000000000303043b0000001305000029000000400450003900000000003404350000002403200370000000000303043b000000600450003900000000003404350000000003510049000000200330008a00000080045000390000000000340435000000200300008a0000001205000029000000000435017000000000015104360000001f0550018f00000011062003600000000003410019000006170000613d000000000706034f0000000008010019000106160000003d00000c4e0000013d000006140000c13d000000000005004b0000061d0000613d000000000446034f00000003055002100001061d0000003d00000ba10000013d0000001204000029000106200000003d00000c470000013d00000013040000290000000003410049000000200330008a000000a00440003900000000003404350000000f052003600000001004000029000000000341043600000000066401700000001f0740018f0000000004630019000006320000613d000000000805034f0000000009030019000000008a08043c0000000009a90436000000000049004b0000062e0000c13d000000000007004b000006360000613d000106360000003d00000bab0000013d0000001005000029000000000453001900000000000404350000008402200370000000000202043b0000001306000029000000c0046000390001063f0000003d00000bc70000013d000003310010009c000004490000213d0000000100200190000004490000c13d000000400010043f0000001301000029000000000201043300000007010000290c600b610000040f0000000d020000290000000e030000290c600ad00000040f00000024010000390000000201100367000000000101043b001300000001001d000001000100008a000000080110017f00000001011001bf0000000902000029000000000012041b0000000b0200002900000004012000390000001303000029000000000031041b0000000901200039001300000001001d0001065c0000003d00000b970000013d000002350000c13d000000130100002900000012030000290c600a5c0000040f0000001201000029000000200010008c0000077d0000413d0000001301000029000106660000003d00000bf70000013d000000120320017f000000020200036700000000040000190000001106000029000000000034004b0000000005640019000007870000813d0001066f0000003d00000be50000013d0000066a0000013d000000130000006b0000000001000019000006760000613d00000012010000290000000201100367000000000101043b0000001304000029000106790000003d00000bb70000013d000006820000013d000000130030006c0000067f0000813d00000013030000290001067f0000003d00000c0e0000013d0000001301000029000000010110021000000001011001bf0000000f02000029000000000012041b0000000c010000290000000601100039001300000001001d000106890000003d00000b970000013d000002350000c13d000000130100002900000011030000290c600a5c0000040f00000011010000290000001f0010008c000006ab0000a13d0000001301000029000106930000003d00000bf70000013d000000110320017f000000020200036700000000040000190000001006000029000000000034004b0000000005640019000006b50000813d0001069c0000003d00000be50000013d000006970000013d000000400300043d001100000003001d0000035b0100004100000000001304350000000401300039000000200200003900000000002104350000002403300039000000120100002900000013020000290c600a3c0000040f000000110210006a00000011010000290c600b4f0000040f0000000202000367000000110000006b0000000001000019000006b10000613d0000001001200360000000000101043b0000001105000029000106b40000003d00000c330000013d000006bd0000013d000000110030006c000006ba0000813d0000001103000029000106ba0000003d00000c040000013d0000001101000029000000010110021000000001011001bf0000001303000029000000000013041b000000400100043d000000020300003900000000003104350000000402200370000000000502043b000003190010009c000003190100804100000040011002100000000002000414000003190020009c0000031902008041000000c002200210000000000112019f0000033c011001c70000800d020000390000034404000041000000840000013d0000000401000029000000000010041b000000400100043d0000000a021000290000000a0000006b0000000d0500035f000006dc0000613d0000000003010019000000005405043c0000000003430436000000000023004b000006d80000c13d000000090000006b000006e00000613d000106e00000003d00000beb0000013d0000001302100029000000030300003900000000003204350000000b020000290c600b610000040f0000000402000029000000000021041b000000400100043d000d00000001001d0000035c0010009c000004490000213d0000000d030000290000014001300039000000400010043f00000040023000390000000001000416000c00000002001d000000000012043500000020023000390000000001000411000300000002001d0000000000120435000000080100002900000000001304350000008001300039000800000001001d00000000000104350000006001300039000b00000001001d0000000000010435000000a002300039000000060100035f0000002401100370000000000101043b000600000002001d0000000000120435000000400100043d0000035d0010009c000004490000213d0000002002100039000000400020043f00000000000104350000000d02000029000000c002200039000200000002001d00000000001204350000000003000031000000100100002900000011020000290c6009c00000040f0000000d02000029000000e002200039001100000002001d000000000012043500000000030000310000000e010000290000000f020000290c6009c00000040f0000000d020000290000010002200039001000000002001d0000000000120435000000400100043d0000035d0010009c000004490000213d0000002002100039000000400020043f00000000000104350000000d020000290000012002200039000e00000002001d00000000001204350000000401000029000000000010043f0000000401000039000000200010043f000000400200003900000000010000190c600b610000040f0000000d020000290000000002020433000000000021041b0000000302000029000000000202043300000340042001970000000102100039000000000302041a0000035103300197000000000343019f000000000032041b0000000c020000290000000003020433000f00000001001d0000000202100039000000000032041b0000000b010000290000000001010433000000030010008c000003a20000813d0000000f050000290000000302500039000000000302041a000001000400008a000000000343016f000000000113019f000000000012041b000000080100002900000000010104330000000402500039000000000012041b000000050150003900000006020000290000000002020433000000000021041b00000002010000290000000001010433000c00000001001d0000000021010434000800000002001d000d00000001001d000003310010009c000004490000213d0000000f010000290000000601100039000b00000001001d000000000101041a000000010310019000000001021002700000007f0220618f0000001f0020008c00000000010000390000000101002039000000000013004b000002350000c13d0000000b010000290000000d030000290c600a5c0000040f0000000d020000290000001f0020008c000600010020021800030003002002180000080d0000a13d0000000b01000029000107710000003d00000c520000013d0000000d0220017f00000000030000190000000c05000029000000000023004b0000000004560019000008180000813d0000000004040433000000000041041b000000200330003900000020066000390000000101100039000007740000013d000000120000006b0000000001000019000007830000613d00000011010000290000000201100367000000000101043b0000001204000029000107860000003d00000bb70000013d0000078f0000013d000000120030006c0000078c0000813d00000012030000290001078c0000003d00000c0e0000013d0000001201000029000000010110021000000001011001bf0000001302000029000000000012041b0000000b010000290000000601100039001300000001001d000107960000003d00000b970000013d000002350000c13d000000130100002900000010030000290c600a5c0000040f00000010010000290000001f0010008c000007aa0000a13d0000001301000029000107a00000003d00000bf70000013d000000100320017f000000020200036700000000040000190000000f06000029000000000034004b0000000005640019000007b40000813d000107a90000003d00000be50000013d000007a40000013d0000000202000367000000100000006b0000000001000019000007b00000613d0000000f01200360000000000101043b0000001005000029000107b30000003d00000c330000013d000007bc0000013d000000100030006c000007b90000813d0000001003000029000107b90000003d00000c040000013d0000001001000029000000010110021000000001011001bf0000001303000029000000000013041b0000002401200370000000000301043b0000000001000414000000000003004b000007c60000c13d0000000a020000290c6008fe0000040f000007d20000013d000003190010009c0000031901008041000000c00110021000000339011001c700008009020000390000000a0400002900000000050000190c600b8d0000040f0000006003100270000103190030019d0003000000010355000000010120018f001300000001001d0c600a810000040f000000400100043d00000002020003670000000403200370000000000503043b000000130000006b000007e40000c13d00000346030000410000000000310435000000040310003900000000005304350000002402200370000000000202043b0000002403100039000000000023043500000044020000390c600b4f0000040f00000001020000390000000000210435000003190010009c000003190100804100000040011002100000000002000414000003190020009c0000031902008041000000c002200210000000000112019f0000033c011001c70000800d02000039000000020300003900000344040000410c600b8d0000040f00000001002001900000036d0000613d00000002010003670000002402100370000000000202043b000000400300043d00000000002304350000000401100370000000000501043b000003190030009c000003190300804100000040013002100000000002000414000003190020009c0000031902008041000000c002200210000000000112019f0000033c011001c70000800d02000039000000030300003900000345040000410000000a060000290c600b8d0000040f00000001002001900000036d0000613d0000048b0000013d0000000d0000006b0000000001000019000008120000613d00000008010000290000000001010433000000010300008a0000000302300250000000000232013f000000000121016f00000006011001af0000081f0000013d0000000d0020006c0000081d0000813d00000003020000290001081d0000003d00000bbf0000013d000000060100002900000001011001bf0000000b02000029000000000012041b00000011010000290000000001010433000d00000001001d0000000021010434000b00000002001d001100000001001d000003310010009c000004490000213d0000000f010000290000000701100039000c00000001001d0001082e0000003d00000b970000013d000002350000c13d0000000c0100002900000011030000290c600a5c0000040f00000011020000290000001f0020008c00080001002002180006000300200218000008460000a13d0000000c010000290001083a0000003d00000c520000013d000000110220017f00000000030000190000000d05000029000000000023004b0000000004560019000008510000813d0000000004040433000000000041041b0000002003300039000000200660003900000001011000390000083d0000013d000000110000006b00000000010000190000084b0000613d0000000b010000290000000001010433000000010300008a0000000602300250000000000232013f000000000121016f00000008011001af000008580000013d000000110020006c000008560000813d0000000602000029000108560000003d00000bbf0000013d000000080100002900000001011001bf0000000c02000029000000000012041b00000010010000290000000001010433001000000001001d0000000021010434001100000002001d000d00000001001d000003310010009c000004490000213d0000000f010000290000000801100039000c00000001001d000108670000003d00000b970000013d000002350000c13d0000000c010000290000000d030000290c600a5c0000040f0000000d010000290000001f0010008c0000087a0000a13d0000000c01000029000108710000003d00000c590000013d0000000d0220017f0000000003000019000000000023004b00000011050000290000001004500029000008830000813d000108790000003d00000c3b0000013d000008730000013d0000000d0000006b00000000010000190000087f0000613d000000110100002900000000010104330000000d04000029000108820000003d00000bb70000013d0000088c0000013d0000000d0020006c000008890000813d0000000d020000290000000302200210000108890000003d00000bbf0000013d0000000d01000029000000010110021000000001011001bf0000000c02000029000000000012041b0000000e010000290000000001010433001000000001001d0000000021010434001100000002001d000e00000001001d000003310010009c000004490000213d0000000f010000290000000901100039000f00000001001d0001089b0000003d00000b970000013d000002350000c13d0000000f010000290000000e030000290c600a5c0000040f0000000e010000290000001f0010008c000008b80000a13d0000000f01000029000108a50000003d00000c590000013d0000000e0220017f0000000003000019000000000023004b00000011050000290000001004500029000008ae0000813d000108ad0000003d00000c3b0000013d000008a70000013d0000000e0020006c000008b40000813d0000000e020000290000000302200210000108b40000003d00000bbf0000013d0000000e01000029000000010110021000000001011001bf000008c00000013d0000000e0000006b0000000001000019000008bd0000613d000000110100002900000000010104330000000e04000029000108c00000003d00000bb70000013d0000000f02000029000000000012041b000000400100043d0000006002100039000000130300002900000000003204350000006002000039000000000221043600000080041000390000000a05400029000000020300036700000012063003600000000a0000006b000008d40000613d000000000706034f0000000008040019000000007907043c0000000008980436000000000058004b000008d00000c13d000000090000006b000008e10000613d0000000a066003600000000007050433000000070800002900000000078701cf000000000787022f000000000606043b0000010008800089000000000686022f00000000068601cf000000000676019f000000000065043500000013044000290000000000040435000000000400041600000000004204350000002402300370000000000202043b00000040031000390000000000230435000003190010009c0000031901008041000000400110021000000005020000290000008002200039000003190020009c00000319020080410000006002200210000000000121019f0000000002000414000003190020009c0000031902008041000000c002200210000000000112019f00000339011001c70000800d0200003900000003030000390000035e0400004100000004050000290000000006000411000000840000013d000003190010009c0000031901008041000000c0011002100c600b8d0000040f0000006003100270000103190030019d0003000000010355000000010120018f000000000001042d0001000000000002000100000003001d000003190010009c0000031901008041000000c001100210000003190020009c00000319020080410000004002200210000000000112019f00000361011001c700000001020000390c600b920000040f000000010900002900000060031002700000031903300197000000200030008c000000200400003900000000040340190000001f0540018f00000020064001900000000004690019000009220000613d000000000701034f000000007807043c0000000009890436000000000049004b0000091e0000c13d000000010220018f000000000005004b000009300000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000100000003001f00030000000103550000000001020019000000000001042d0000001f03100039000000000023004b0000000004000019000003620400404100000362052001970000036203300197000000000653013f000000000053004b00000000030000190000036203002041000003620060009c000000000304c019000000000003004b0000094c0000613d0000000203100367000000000303043b000003310030009c0000094c0000213d00000020011000390000000004310019000000000024004b0000094c0000213d0000000002030019000000000001042d000000000100001900000c62000104300000001f02200039000000200300008a000000000232016f0000000001120019000000000021004b00000000020000390000000102004039000003310010009c0000095b0000213d00000001002001900000095b0000c13d000000400010043f000000000001042d0000035f01000041000000000010043f0000004101000039000000040010043f000003600100004100000c62000104300003000000000002000000000201041a000000010320019000000001052002700000007f0550618f0000001f0050008c00000000040000390000000104002039000000000043004b000009970000c13d000000400400043d0000000006540436000000000003004b000009830000613d000300000004001d000000000010043f00000020020000390000000001000019000200000005001d000100000006001d0c600b610000040f000000010600002900000002050000290000000002000019000000000052004b000009810000813d0000000003260019000000000401041a000000000043043500000020022000390000000101100039000009790000013d0000000304000029000009890000013d000001000100008a000000000112016f0000000000160435000000000005004b000000200200003900000000020060390000003f01200039000000200200008a000000000221016f0000000001420019000000000021004b00000000020000390000000102004039000003310010009c0000099b0000213d00000001002001900000099b0000c13d000000400010043f0000000001040019000000000001042d0000035f01000041000000000010043f00000022010000390000099e0000013d0000035f01000041000000000010043f0000004101000039000000040010043f000003600100004100000c62000104300000000004000019000000000034004b000009aa0000813d00000000052400190000000006140019000000000606043300000000006504350000002004400039000009a20000013d00000000012300190000000000010435000000000001042d0000002004100039000000000301043300000000013204360000000002000019000000000032004b000009b90000813d00000000051200190000000006240019000000000606043300000000006504350000002002200039000009b10000013d000000000213001900000000000204350000001f02300039000000200300008a000000000232016f0000000001210019000000000001042d000003630020009c000009f10000813d00000000040100190000001f01200039000000200600008a000000000161016f0000003f01100039000000000561016f000000400100043d0000000005510019000000000015004b00000000070000390000000107004039000003310050009c000009f10000213d0000000100700190000009f10000c13d000000400050043f00000000052104360000000007420019000000000037004b000009f70000213d00000000066201700000001f0720018f00000002044003670000000003650019000009e10000613d000000000804034f0000000009050019000000008a08043c0000000009a90436000000000039004b000009dd0000c13d000000000007004b000009ee0000613d000000000464034f0000000306700210000000000703043300000000076701cf000000000767022f000000000404043b0000010006600089000000000464022f00000000046401cf000000000474019f000000000043043500000000022500190000000000020435000000000001042d0000035f01000041000000000010043f0000004101000039000000040010043f000003600100004100000c6200010430000000000100001900000c6200010430000003640010009c00000a0c0000213d0000000003010019000000230010008c00000a0c0000a13d00000002020003670000000401200370000000000101043b000003310010009c00000a0c0000213d0000002304100039000000000034004b00000a0c0000813d0000000404100039000000000242034f000000000202043b00000024011000390c6009c00000040f000000000001042d000000000100001900000c6200010430000000000001004b00000a110000613d000000000001042d000000400100043d000000440210003900000365030000410000000000320435000000240210003900000011030000390000000000320435000003470200004100000bdf0000013d0000000104000039000000000304041a000000010530019000000001023002700000007f0220618f0000001f0020008c00000000060000390000000106002039000000000065004b00000a360000c13d000000000005004b00000a310000613d000000000040043f00000338030000410000000004000019000000000024004b00000a340000813d0000000005140019000000000603041a00000000006504350000002004400039000000010330003900000a290000013d000001000400008a000000000343016f00000000003104350000000001120019000000000001042d0000035f01000041000000000010043f0000002201000039000000040010043f000003600100004100000c62000104300000000003230436000000200400008a00000000064201700000001f0720018f0000000005630019000000020110036700000a490000613d000000000801034f0000000009030019000000008a08043c0000000009a90436000000000059004b00000a450000c13d000000000007004b00000a560000613d000000000161034f0000000306700210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f0000000000150435000000000123001900000000000104350000001f01200039000000000141016f0000000001130019000000000001042d0002000000000002000000200020008c00000a740000413d000000000010043f000200000002001d00000020020000390000000001000019000100000003001d0c600b610000040f00000001040000290000001f024000390000000503200270000000200040008c000000000300401900000002020000290000001f02200039000000050220027000000000022100190000000001310019000000000021004b00000a740000813d000000000001041b000000010110003900000a6f0000013d000000000001042d000000000001004b00000a780000613d000000000001042d000000400100043d00000044021000390000036603000041000000000032043500000024021000390000000e030000390000000000320435000003470200004100000bdf0000013d000000010100003200000aac0000613d000003630010009c00000aad0000813d0000001f03100039000000200200008a000000000323016f0000003f03300039000000000423016f000000400300043d0000000004430019000000000034004b00000000050000390000000105004039000003310040009c00000aad0000213d000000010050019000000aad0000c13d000000400040043f000000000513043600000000022101700000001f0310018f0000000001250019000000030400036700000a9f0000613d000000000604034f000000006706043c0000000005750436000000000015004b00000a9b0000c13d000000000003004b00000aac0000613d000000000224034f0000000303300210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f0000000000210435000000000001042d0000035f01000041000000000010043f0000004101000039000000040010043f000003600100004100000c6200010430000003400610019800000ac70000613d0000034b01000041000000000201041a0000035103200197000000000363019f000000000031041b00000000010004140000034005200197000003190010009c0000031901008041000000c00110021000000339011001c70000800d02000039000000030300003900000352040000410c600b8d0000040f000000010020019000000ace0000613d000000000001042d000000400100043d000003670200004100000000002104350000000402100039000000000002043500000024020000390c600b4f0000040f000000000100001900000c62000104300004000000000002000400000003001d000300000002001d0000036802000041000000000020043f0000001c0010043f0000003c0200003900000000010000190c600b610000040f000200000001001d0000000003000031000000030100002900000004020000290c6009c00000040f000000400200043d0000000034010434000000410040008c00000aff0000c13d000000400410003900000000040404330000036a0040009c00000b0c0000213d0000006001100039000000000101043300000000030304330000006005200039000000000045043500000040042000390000000000340435000000f8011002700000002003200039000000000013043500000002010000290000000000120435000000000000043f000000000100041400000000030000190c6009070000040f000000000001004b00000b1e0000613d000000000100043d000003400110019800000b320000613d00010afd0000003d00000bd60000013d00000b3b0000613d000000000001042d00000044012000390000036903000041000000000031043500000024012000390000001f03000039000000000031043500000347010000410000000000120435000000040120003900000020030000390000000000310435000000640300003900000b1b0000013d00000064012000390000036d03000041000000000031043500000044012000390000036e030000410000000000310435000000240120003900000022030000390000000000310435000003470100004100000000001204350000000401200039000000200300003900000000003104350000008403000039000000000102001900000000020300190c600b4f0000040f0000000304000367000000200100008a000000010200003100000000051201700000001f0620018f000000400100043d000000000351001900000b2b0000613d000000000704034f000000000801001900010b2a0000003d00000c4e0000013d00000b280000c13d000000000006004b00000b310000613d000000000454034f000000030560021000010b310000003d00000ba10000013d0c600b4f0000040f000000400100043d00000044021000390000036c030000410000000000320435000000240210003900000018030000390000000000320435000003470200004100000bdf0000013d000000400100043d0000036b02000041000000000021043500000004020000390c600b4f0000040f0000034b01000041000000000101041a00000340011001970000000002000411000000000021004b00000b470000c13d000000000001042d000000400100043d0000036f0300004100000000003104350000000403100039000000000023043500000024020000390c600b4f0000040f000000000001042f000003190010009c00000319010080410000004001100210000003190020009c00000319020080410000006002200210000000000112019f00000c6200010430000003190010009c00000319010080410000004001100210000003190020009c00000319020080410000006002200210000000000112019f000000e002300210000000000121019f00000c610001042e000003190010009c00000319010080410000004001100210000003190020009c00000319020080410000006002200210000000000112019f0000000002000414000003190020009c0000031902008041000000c002200210000000000112019f00000339011001c700008010020000390c600b920000040f000000010020019000000b740000613d000000000101043b000000000001042d000000000100001900000c620001043000000000050100190000000000200443000000040030008c00000b7d0000a13d000000050140027000000000010100310000000400100443000003190030009c000003190300804100000060013002100000000002000414000003190020009c0000031902008041000000c002200210000000000112019f00000370011001c700000000020500190c600b920000040f000000010020019000000b8c0000613d000000000101043b000000000001042d000000000001042f00000b90002104210000000102000039000000000001042d0000000002000019000000000001042d00000b95002104230000000102000039000000000001042d0000000002000019000000000001042d000000000101041a000000010010019000000001021002700000007f0220618f0000001f0020008c00000000030000390000000103002039000000000131013f0000000100100190000000010000013b000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000430435000000010000013b000000000565034f0000000306700210000000000704043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f0000000000540435000000010000013b0000000302400210000000010300008a000000000223022f000000000232013f000000000121016f0000000102400210000000000121019f000000010000013b000000f80220018f000000010300008a000000000223022f000000000232013f0000000003040433000000000223016f000000000021041b000000010000013b00000000002404350000001f02500039000000200400008a000000000242016f00000000026200490000000001210019000000000016043500000000013200190000001f01100039000000000241016f0000000001620019000000000021004b00000000020000390000000102004039000000010000013b000000000010043f0000000201000039000000200010043f000000400200003900000000010000190c600b610000040f000000000101041a000000ff00100190000000010000013b000000000021043500000004021000390000002003000039000000000032043500000064020000390c600b4f0000040f000000000552034f000000000505043b000000000051041b00000020044000390000000101100039000000010000013b0000000003020433000000070500002900000000035301cf000000000353022f0000000c0400035f000000000404043b0000010005500089000000000454022f00000000045401cf000000000334019f0000000000320435000000010000013b000000000010043f000000200200003900000000010000190c600b610000040f000000200200008a000000010000013b000000200200008a000000000321016f0000000002430019000000000032004b00000000030000390000000103004039000000010000013b0000000303300210000000f80330018f000000010400008a000000000334022f000000000343013f000000000452034f000000000404043b000000000334016f000000000031041b000000010000013b0000000303300210000000f80330018f000000010400008a000000000334022f000000000343013f000000000252034f000000000202043b000000000232016f000000000021041b000000010000013b0000001301000029000000000010043f0000000201000039000000200010043f000000400200003900000000010000190c600b610000040f000000000201041a000000ff00200190000000010000013b0000800b0100003900000004030000390000000004000415000000160440008a0000000504400210000000010000013b000000200040043f000000400200003900000000010000190c600b610000040f000000010000013b0c6009ad0000040f000000000201001900000013040000290000000001410049000000200310008a000000010000013b0000000303500210000000010400008a000000000334022f000000000343013f000000000131016f0000000103500210000000000131019f000000010000013b0000000004040433000000000041041b00000020033000390000001104000029001100200040003d0000000101100039000000010000013b0000000001000039000000010100a0390c600a0e0000040f000000400100043d000000010000013b000000000341001900000000000304350000001f03400039000000200600008a000000000363016f0000000001310019000000010000013b000000007907043c0000000008980436000000000038004b000000010000013b000000000010043f000000200200003900000000010000190c600b610000040f0000002006000039000000200200008a000000010000013b000000000010043f00000020020000390000000001000019001100000002001d0c600b610000040f000000200200008a000000010000013b00000c600000043200000c610001042e00000c6200010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff000000020000000000000000000000000000004000000100000000000000000002000000000000000000000000000000000000200000008000000000000000009936746a4565f9766fa768f88f56a7487c78780ac179562773d1c75c5269537e00000000000000000000000000000000000000000000000000000000001308d80000000000000000000000000000000000000000000000000000000002153e2900000000000000000000000000000000000000000000000000000000117a5b90000000000000000000000000000000000000000000000000000000001785f53c000000000000000000000000000000000000000000000000000000001b31abda0000000000000000000000000000000000000000000000000000000024d7806c000000000000000000000000000000000000000000000000000000002e0be39a000000000000000000000000000000000000000000000000000000003979c6a1000000000000000000000000000000000000000000000000000000007048027500000000000000000000000000000000000000000000000000000000715018a600000000000000000000000000000000000000000000000000000000744bfe61000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000091da2b3d0000000000000000000000000000000000000000000000000000000096696da100000000000000000000000000000000000000000000000000000000a40d8f4800000000000000000000000000000000000000000000000000000000f04b8dc700000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f62d1888f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000100000000000000019b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f004ef1d2ad89edf8c4d91132028e8195cdf30bb4b5053d4f8cd260341d4805f30ab10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6020000000000000000000000000000000000000000000000000000000000000044d6d25963f097ad14f29f06854a01f575648a1ef82f30e562ccd3889717e339ffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff0200000000000000000000000000000000000020000000000000000000000000c7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2d7e6bcf800000000000000000000000000000000000000000000000000000000f92ee8a900000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff7ffcba5a00000000000000000000000000000000000000000000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391323a636173684f75740000000000000000000000000000000000000000000000004e27b06662347b2bd7ed6e8bde0a4b793dae7d7d05b102ef743cbd9c8d824e4eca18b3e4c1f4a1342b2e2e8b6c68bd49c1ff679624d67b618db852effe04dcbafa9c4e620000000000000000000000000000000000000000000000000000000008c379a0000000000000000000000000000000000000000000000000000000005061796f75745a65726f000000000000000000000000000000000000000000006faf77ea000000000000000000000000000000000000000000000000000000003ee5aeb5000000000000000000000000000000000000000000000000000000009016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c1993009cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f395769746864726177616c206661696c6564000000000000000000000000000000496e73756666696369656e7420636f6e74726163742062616c616e6365000000496e76616c696420726563697069656e74206164647265737300000000000000576974686472617720616d6f756e74206d75737420626520706f736974697665ffffffffffffffffffffffff00000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0416c72656164792061646d696e00000000000000000000000000000000000000496e76616c69642061646d696e206164647265737300000000000000000000003a6d61726b47616d6541734c6f73740000000000000000000000000000000000a3b62bc36326052d97ea62d63c3d60308ed4c3ea8ac079dd8499f1e9c4f80c0f43616e6e6f742072656d6f7665206f776e6572000000000000000000000000004e6f7420616e2061646d696e000000000000000000000000000000000000000043616e6e6f742064656372656173652067616d65436f756e74657200000000003a63726561746547616d65000000000000000000000000000000000000000000106cfcb100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fffffffffffffebf000000000000000000000000000000000000000000000000ffffffffffffffdf5ab4782178ec00656b6f3f3f73d1739ea9d5cba22c641e4b20767fbb571609434e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000080000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5369676e617475726520657870697265640000000000000000000000000000004e6f7420617574686f72697a65640000000000000000000000000000000000001e4fbdf70000000000000000000000000000000000000000000000000000000019457468657265756d205369676e6564204d6573736167653a0a33320000000045434453413a20696e76616c6964207369676e6174757265206c656e677468007fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0f7c071fd0000000000000000000000000000000000000000000000000000000045434453413a20696e76616c6964207369676e61747572650000000000000000756500000000000000000000000000000000000000000000000000000000000045434453413a20696e76616c6964207369676e6174757265202773272076616c118cdaa7000000000000000000000000000000000000000000000000000000000200000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039c6e4a0a0d937a70af6177845d405bc5a8eb0a8e15f34872132f4a0f8847dad
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.