Transactions
Token Transfers
Tokens
Internal Transactions
Coin Balance History
Logs
Code
Read Contract
Write Contract
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- XUSD
- Optimization enabled
- false
- Compiler version
- v0.8.26+commit.8a97fa7a
- EVM Version
- paris
- Verified at
- 2024-09-24T16:22:09.254724Z
Constructor Arguments
0x00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000052b7d2dcc80cd2e4000000000000000000000000000000cb13ca54a9744afa2586e6232b94a58cf9b5e25c0000000000000000000000003246f31ad1b00991965d7a68aef694c4464d89eb00000000000000000000000000000000000000000000000000000000000000145855534420566962726174696c6520417373657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000045855534400000000000000000000000000000000000000000000000000000000
Arg [0] (string) : XUSD Vibratile Asset
Arg [1] (string) : XUSD
Arg [2] (uint256) : 100000000000000000000000000
Arg [3] (address) : 0xcb13ca54a9744afa2586e6232b94a58cf9b5e25c
Arg [4] (address) : 0x3246f31ad1b00991965d7a68aef694c4464d89eb
contracts/XUSD.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/structs/Checkpoints.sol";
import "./VibeRegistry.sol";
import "./AccessorMod.sol";
contract XUSD is Context, IERC20, IERC20Metadata, AccesorMod, Ownable {
using Checkpoints for Checkpoints.Trace224; // Using Checkpoints library for tracking burn history
// Storage
mapping(address => uint32[]) private _burnBlockNumbersEOA;
mapping(address => uint32[]) private _burnBlockNumbersContract;
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
mapping(address => uint256) internal _contractBurnBalances;
mapping(address => uint256) internal _eoaBurnBalances;
mapping(address => Checkpoints.Trace224) private _burnCheckpointsEOA;
mapping(address => Checkpoints.Trace224) private _burnCheckpointsContract;
uint256 internal _totalBurnedEOA;
uint256 internal _totalBurnedContract;
uint private burnIt = 700;
uint private bankIt = 300;
address tressury;
uint256 private _totalSupply;
uint256 internal _totalBurned;
string private _name;
string private _symbol;
bool private tradingOpen;
bool private paid = false;
bool private swapEnabled = false;
mapping(address => bool) private _isExcludedFromTax;
address public immutable burnAddress =
0x0000000000000000000000000000000000000369;
VibeRegistry public registry;
// Constructor
constructor(
string memory name_,
string memory symbol_,
uint256 initialBalance_,
address _access,
address t
) AccesorMod(_access) Ownable(msg.sender) {
require(initialBalance_ > 0, "Initial supply cannot be zero");
tressury = t;
_name = name_;
_symbol = symbol_;
_mint(_msgSender(), initialBalance_);
}
// View function to return burn balance of a user (Contracts)
function burnBalanceContract(
address contractAddr
) public view returns (uint256) {
return _contractBurnBalances[contractAddr];
}
// View function to return burn balance of a user (EOAs)
function burnBalanceEOA(address user) public view returns (uint256) {
return _eoaBurnBalances[user];
}
// Returns the total amount burned (combining EOAs and contracts)
function totalBurned() external view returns (uint256) {
return _totalBurnedEOA + _totalBurnedContract;
}
// Returns the name of the token
function name() public view virtual override returns (string memory) {
return _name;
}
// Returns the symbol of the token
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
// Returns the number of decimals (defaults to 18)
function decimals() public view virtual override returns (uint8) {
return 18;
}
// Returns total supply of tokens
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
// Returns the balance of a specific account
function balanceOf(
address account
) public view virtual override returns (uint256) {
return _balances[account];
}
// Returns allowance granted to spender by _owner
function allowance(
address _owner,
address spender
) public view virtual override returns (uint256) {
return _allowances[_owner][spender];
}
function setTreasury(address t) external onlyConsul(){
tressury = t;
}
function setTaxVariable(uint treasury, uint burn) external onlyConsul(){
burnIt = burn;
bankIt = treasury;
}
// Approves a spender
function approve(
address spender,
uint256 amount
) public virtual override returns (bool) {
address _owner = _msgSender();
_approve(_owner, spender, amount);
return true;
}
// Increase allowance
function increaseAllowance(
address spender,
uint256 addedValue
) public virtual returns (bool) {
address _owner = _msgSender();
_approve(_owner, spender, allowance(_owner, spender) + addedValue);
return true;
}
// Decrease allowance
function decreaseAllowance(
address spender,
uint256 subtractedValue
) public virtual returns (bool) {
address _owner = _msgSender();
uint256 currentAllowance = allowance(_owner, spender);
require(
currentAllowance >= subtractedValue,
"Decreased allowance below zero"
);
unchecked {
_approve(_owner, spender, currentAllowance - subtractedValue);
}
return true;
}
// Internal mint logic
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "Mint to zero address");
_totalSupply += amount;
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
}
// Approve function
function _approve(
address _owner,
address spender,
uint256 amount
) internal virtual {
require(_owner != address(0), "Approve from zero address");
require(spender != address(0), "Approve to zero address");
_allowances[_owner][spender] = amount;
emit Approval(_owner, spender, amount);
}
// Transfer function with tax deduction and burn logic
function transfer(
address to,
uint256 amount
) public virtual override nonReentrant returns (bool) {
address _owner = _msgSender();
// Calculate the tax fee and adjusted amount
(int fee, uint256 adjustedAmount) = registry.calculateAndSumBasis(
to,
_owner,
tx.origin,
msg.sender,
amount
);
// Only apply tax if fee is positive and both 'from' and 'to' are not excluded
if (fee > 0 && !_isExcludedFromTax[_owner] && !_isExcludedFromTax[to]) {
uint256 taxAmount = (adjustedAmount * uint256(fee)) / 10000;
if (taxAmount > 0) {
uint burnAmount = (taxAmount * burnIt) / 10000;
uint tAmount = taxAmount - burnAmount;
// Burn the tokens by sending to the zero address
if (burnAmount > 0) {
_transfer(_owner, address(0), burnAmount);
}
// Send tax to the treasury
if (tAmount > 0) {
_transfer(_owner, tressury, tAmount);
}
// Adjust the amount after the tax deduction
adjustedAmount -= taxAmount;
}
}
// Always transfer the remaining (adjusted) amount to the recipient
_transfer(_owner, to, adjustedAmount);
return true;
}
// Similar tax handling for transferFrom
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override nonReentrant returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
(int fee, uint256 adjustedAmount) = registry.calculateAndSumBasis(
to,
from,
tx.origin,
spender,
amount
);
// Only apply tax if fee is positive and both 'from' and 'to' are not excluded
if (fee > 0 && !_isExcludedFromTax[from] && !_isExcludedFromTax[to]) {
uint256 taxAmount = (adjustedAmount * uint256(fee)) / 10000;
if (taxAmount > 0) {
uint burnAmount = (taxAmount * burnIt) / 10000;
uint tAmount = taxAmount - burnAmount;
// Handle burn amount
if (burnAmount > 0) {
_transfer(from, address(0), burnAmount); // Burn the tax amount
}
// Handle treasury amount
if (tAmount > 0) {
_transfer(from, tressury, tAmount); // Send to treasury
}
// Adjust the amount after the tax
adjustedAmount -= taxAmount;
}
}
// Transfer the adjusted amount (or the original amount if no fee)
_transfer(from, to, adjustedAmount);
return true;
}
// Internal transfer function
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "Transfer from zero address");
if (to == address(0) || to == burnAddress) {
// Burning tokens
if (isContract(from)) {
_contractBurnBalances[from] += amount;
_totalBurnedContract += amount;
_updateBurnHistoryContract(from, amount);
} else {
_eoaBurnBalances[tx.origin] += amount;
_totalBurnedEOA += amount;
_updateBurnHistoryEOA(tx.origin, amount);
}
_burn(from, amount);
} else {
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "Transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
}
}
// Internal burn function
function _burn(address from, uint256 amount) internal virtual {
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "Burn amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
// Burn history tracking for EOAs
function _updateBurnHistoryEOA(address user, uint256 amount) internal {
uint224 currentBurnAmount = uint224(_eoaBurnBalances[user]);
uint224 newBurnAmount = currentBurnAmount + uint224(amount);
uint32 blockNumber = uint32(block.number);
_burnCheckpointsEOA[user].push(blockNumber, newBurnAmount);
// Track the block number for the user
_burnBlockNumbersEOA[user].push(blockNumber);
}
// Burn history tracking for Contracts
function _updateBurnHistoryContract(
address contractAddress,
uint256 amount
) internal {
uint224 currentBurnAmount = uint224(
_contractBurnBalances[contractAddress]
);
uint224 newBurnAmount = currentBurnAmount + uint224(amount);
uint32 blockNumber = uint32(block.number);
_burnCheckpointsContract[contractAddress].push(
blockNumber,
newBurnAmount
);
// Track the block number for the contract
_burnBlockNumbersContract[contractAddress].push(blockNumber);
}
// View latest burn for EOAs
function getLatestBurnEOA(address user) public view returns (uint224) {
return _burnCheckpointsEOA[user].latest();
}
function getFullBurnHistoryEOA(
address user
) public view returns (uint32[] memory blocks, uint224[] memory burns) {
uint32[] memory blockNumbers = _burnBlockNumbersEOA[user];
uint224[] memory burnAmounts = new uint224[](blockNumbers.length);
for (uint256 i = 0; i < blockNumbers.length; i++) {
burnAmounts[i] = _burnCheckpointsEOA[user].upperLookup(
blockNumbers[i]
);
}
return (blockNumbers, burnAmounts);
}
// Get the full burn history for a contract
function getFullBurnHistoryContract(
address contractAddr
) public view returns (uint32[] memory blocks, uint224[] memory burns) {
uint32[] memory blockNumbers = _burnBlockNumbersContract[contractAddr];
uint224[] memory burnAmounts = new uint224[](blockNumbers.length);
for (uint256 i = 0; i < blockNumbers.length; i++) {
burnAmounts[i] = _burnCheckpointsContract[contractAddr].upperLookup(
blockNumbers[i]
);
}
return (blockNumbers, burnAmounts);
}
// View latest burn for contracts
function getLatestBurnContract(
address contractAddr
) public view returns (uint224) {
return _burnCheckpointsContract[contractAddr].latest();
}
// Utility to check if an address is a contract
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
// Exclude accounts from tax
function setExclusionFromTax(
address account,
bool status
) external onlySenator {
_isExcludedFromTax[account] = status;
}
function isExcludedFromTax(address account) public view returns (bool) {
return _isExcludedFromTax[account];
}
// Set registry contract address
function setRegistry(address reg) public onlySenator {
require(isContract(reg), "Provided address is not a contract");
registry = VibeRegistry(reg);
}
// Reward transfer function
function Rewardtransfer(
address to,
uint256 amount
) external onlyConsul nonReentrant {
_transfer(_msgSender(), to, amount);
}
// Mint new tokens
function mint(address to, uint256 amount) public onlyConsul {
_mint(to, amount);
}
// Spend allowance
function _spendAllowance(
address _owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(_owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "Insufficient allowance");
unchecked {
_approve(_owner, spender, currentAllowance - amount);
}
}
}
}
@openzeppelin/contracts/utils/structs/Checkpoints.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/Checkpoints.sol)
// This file was procedurally generated from scripts/generate/templates/Checkpoints.js.
pragma solidity ^0.8.20;
import {Math} from "../math/Math.sol";
/**
* @dev This library defines the `Trace*` struct, for checkpointing values as they change at different points in
* time, and later looking up past values by block number. See {Votes} as an example.
*
* To create a history of checkpoints define a variable type `Checkpoints.Trace*` in your contract, and store a new
* checkpoint for the current transaction block using the {push} function.
*/
library Checkpoints {
/**
* @dev A value was attempted to be inserted on a past checkpoint.
*/
error CheckpointUnorderedInsertion();
struct Trace224 {
Checkpoint224[] _checkpoints;
}
struct Checkpoint224 {
uint32 _key;
uint224 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace224 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint32).max` key set will disable the
* library.
*/
function push(Trace224 storage self, uint32 key, uint224 value) internal returns (uint224, uint224) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace224 storage self, uint32 key) internal view returns (uint224) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace224 storage self) internal view returns (uint224) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace224 storage self) internal view returns (bool exists, uint32 _key, uint224 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint224 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace224 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace224 storage self, uint32 pos) internal view returns (Checkpoint224 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint224[] storage self, uint32 key, uint224 value) private returns (uint224, uint224) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint224 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint224({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint224({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint224[] storage self,
uint32 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint224[] storage self,
uint256 pos
) private pure returns (Checkpoint224 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace208 {
Checkpoint208[] _checkpoints;
}
struct Checkpoint208 {
uint48 _key;
uint208 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace208 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint48).max` key set will disable the
* library.
*/
function push(Trace208 storage self, uint48 key, uint208 value) internal returns (uint208, uint208) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace208 storage self, uint48 key) internal view returns (uint208) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace208 storage self) internal view returns (uint208) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace208 storage self) internal view returns (bool exists, uint48 _key, uint208 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint208 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace208 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace208 storage self, uint32 pos) internal view returns (Checkpoint208 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint208[] storage self, uint48 key, uint208 value) private returns (uint208, uint208) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint208 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint208({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint208({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint208[] storage self,
uint48 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint208[] storage self,
uint256 pos
) private pure returns (Checkpoint208 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
struct Trace160 {
Checkpoint160[] _checkpoints;
}
struct Checkpoint160 {
uint96 _key;
uint160 _value;
}
/**
* @dev Pushes a (`key`, `value`) pair into a Trace160 so that it is stored as the checkpoint.
*
* Returns previous value and new value.
*
* IMPORTANT: Never accept `key` as a user input, since an arbitrary `type(uint96).max` key set will disable the
* library.
*/
function push(Trace160 storage self, uint96 key, uint160 value) internal returns (uint160, uint160) {
return _insert(self._checkpoints, key, value);
}
/**
* @dev Returns the value in the first (oldest) checkpoint with key greater or equal than the search key, or zero if
* there is none.
*/
function lowerLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _lowerBinaryLookup(self._checkpoints, key, 0, len);
return pos == len ? 0 : _unsafeAccess(self._checkpoints, pos)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*/
function upperLookup(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 pos = _upperBinaryLookup(self._checkpoints, key, 0, len);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the last (most recent) checkpoint with key lower or equal than the search key, or zero
* if there is none.
*
* NOTE: This is a variant of {upperLookup} that is optimised to find "recent" checkpoint (checkpoints with high
* keys).
*/
function upperLookupRecent(Trace160 storage self, uint96 key) internal view returns (uint160) {
uint256 len = self._checkpoints.length;
uint256 low = 0;
uint256 high = len;
if (len > 5) {
uint256 mid = len - Math.sqrt(len);
if (key < _unsafeAccess(self._checkpoints, mid)._key) {
high = mid;
} else {
low = mid + 1;
}
}
uint256 pos = _upperBinaryLookup(self._checkpoints, key, low, high);
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns the value in the most recent checkpoint, or zero if there are no checkpoints.
*/
function latest(Trace160 storage self) internal view returns (uint160) {
uint256 pos = self._checkpoints.length;
return pos == 0 ? 0 : _unsafeAccess(self._checkpoints, pos - 1)._value;
}
/**
* @dev Returns whether there is a checkpoint in the structure (i.e. it is not empty), and if so the key and value
* in the most recent checkpoint.
*/
function latestCheckpoint(Trace160 storage self) internal view returns (bool exists, uint96 _key, uint160 _value) {
uint256 pos = self._checkpoints.length;
if (pos == 0) {
return (false, 0, 0);
} else {
Checkpoint160 memory ckpt = _unsafeAccess(self._checkpoints, pos - 1);
return (true, ckpt._key, ckpt._value);
}
}
/**
* @dev Returns the number of checkpoint.
*/
function length(Trace160 storage self) internal view returns (uint256) {
return self._checkpoints.length;
}
/**
* @dev Returns checkpoint at given position.
*/
function at(Trace160 storage self, uint32 pos) internal view returns (Checkpoint160 memory) {
return self._checkpoints[pos];
}
/**
* @dev Pushes a (`key`, `value`) pair into an ordered list of checkpoints, either by inserting a new checkpoint,
* or by updating the last one.
*/
function _insert(Checkpoint160[] storage self, uint96 key, uint160 value) private returns (uint160, uint160) {
uint256 pos = self.length;
if (pos > 0) {
// Copying to memory is important here.
Checkpoint160 memory last = _unsafeAccess(self, pos - 1);
// Checkpoint keys must be non-decreasing.
if (last._key > key) {
revert CheckpointUnorderedInsertion();
}
// Update or push new checkpoint
if (last._key == key) {
_unsafeAccess(self, pos - 1)._value = value;
} else {
self.push(Checkpoint160({_key: key, _value: value}));
}
return (last._value, value);
} else {
self.push(Checkpoint160({_key: key, _value: value}));
return (0, value);
}
}
/**
* @dev Return the index of the last (most recent) checkpoint with key lower or equal than the search key, or `high`
* if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and exclusive
* `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _upperBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key > key) {
high = mid;
} else {
low = mid + 1;
}
}
return high;
}
/**
* @dev Return the index of the first (oldest) checkpoint with key is greater or equal than the search key, or
* `high` if there is none. `low` and `high` define a section where to do the search, with inclusive `low` and
* exclusive `high`.
*
* WARNING: `high` should not be greater than the array's length.
*/
function _lowerBinaryLookup(
Checkpoint160[] storage self,
uint96 key,
uint256 low,
uint256 high
) private view returns (uint256) {
while (low < high) {
uint256 mid = Math.average(low, high);
if (_unsafeAccess(self, mid)._key < key) {
low = mid + 1;
} else {
high = mid;
}
}
return high;
}
/**
* @dev Access an element of the array without performing bounds check. The position is assumed to be within bounds.
*/
function _unsafeAccess(
Checkpoint160[] storage self,
uint256 pos
) private pure returns (Checkpoint160 storage result) {
assembly {
mstore(0, self.slot)
result.slot := add(keccak256(0, 0x20), pos)
}
}
}
contracts/VibeLibRegistry.sol
// SPDX-License-Identifier: Sharia
pragma solidity ^0.8.24;
import "./Classes/VibeBase.sol";
library VibeLibRegistry {
struct Registry {
address[] keys; // List of registered addresses
mapping(address => uint256) indexOf; // Maps an address to its index in `keys`
mapping(address => bool) inserted; // Tracks whether an address is in the registry
mapping(address => VibeBase.Importance) accessStyles; // Mapping for enumerator list
}
function GetHashByIndex(Registry storage _registry, uint index) public view returns (address) {
return _registry.keys[index];
}
function Count(Registry storage _registry) public view returns (uint256) {
return _registry.keys.length;
}
function Contains(Registry storage _registry, address key) public view returns (bool) {
return _registry.inserted[key];
}
function ReturnAllKeys(Registry storage _registry) public view returns (address[] storage) {
return _registry.keys;
}
// Register a key with its associated access style
function Register(Registry storage _registry, address key, VibeBase.Importance accessStyle) public {
if (!_registry.inserted[key]) {
_registry.inserted[key] = true;
_registry.indexOf[key] = _registry.keys.length;
_registry.keys.push(key);
_registry.accessStyles[key] = accessStyle; // Assign the access style
}
}
function Remove(Registry storage _registry, address key) public {
if (!_registry.inserted[key]) return;
delete _registry.inserted[key];
delete _registry.accessStyles[key]; // Remove the access style
uint256 index = _registry.indexOf[key];
address lastKey = _registry.keys[_registry.keys.length - 1];
_registry.indexOf[lastKey] = index;
delete _registry.indexOf[key];
_registry.keys[index] = lastKey;
_registry.keys.pop();
}
// Get the access style for a specific key
function GetAccessStyle(Registry storage _registry, address key) public view returns (VibeBase.Importance) {
require(_registry.inserted[key], "Key not found in registry");
return _registry.accessStyles[key];
}
// New function to sort the registry based on AccessStyle ranking
function SortRegistryByAccessStyle(Registry storage _registry) public {
uint256 n = _registry.keys.length;
for (uint256 i = 0; i < n - 1; i++) {
uint256 maxIndex = i;
for (uint256 j = i + 1; j < n; j++) {
// Compare based on AccessStyle rank (sorting from highest to lowest)
if (uint256(_registry.accessStyles[_registry.keys[j]]) > uint256(_registry.accessStyles[_registry.keys[maxIndex]])) {
maxIndex = j;
}
}
if (maxIndex != i) {
// Swap keys
address temp = _registry.keys[i];
_registry.keys[i] = _registry.keys[maxIndex];
_registry.keys[maxIndex] = temp;
// Update indexOf mapping
_registry.indexOf[_registry.keys[i]] = i;
_registry.indexOf[_registry.keys[maxIndex]] = maxIndex;
}
}
}
}
contracts/VibeRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import './Address.sol';
import './VibeLibRegistry.sol';
import "./registry.sol";
import "./AccessorMod.sol";
import "./atropamath.sol";
import "./XUSD.sol";
import "./Classes/VibeBase.sol";
/**
* @title VibeRegistry
* @dev This contract manages user vibes, class structures, and reward distribution through multiple registries.
* Access control is handled via the inherited AccesorMod, providing restrictions on key operations.
*/
contract VibeRegistry is AccesorMod {
using VibeLibRegistry for VibeLibRegistry.Registry;
using Address for address;
using AtropaMath for address;
using LibRegistry for LibRegistry.Registry;
using AuthLib for AuthLib.RoleData;
// Custom Errors
error NotAllowedAccess();
error UnauthorizedAccess(AuthLib.Rank roleId, address addr);
// Data structures for class and reward management
struct MaterClass {
address classAddress;
uint updatedTimestamp;
bool process;
string description;
VibeBase.Importance level;
}
struct RewardClass {
address classAddress;
bool process;
string description;
}
struct userVibe {
address userAddress;
address classAddress;
int vibes;
uint timestamp;
bool active;
}
struct VibeClass {
address classAddress;
uint aura;
uint updatedTimestamp;
bool active;
bool process;
string description;
}
struct UserProfileHash {
address userAddress;
int vibes;
LibRegistry.Registry MasterReg;
}
struct Wing {
uint64 Omnicron;
uint64 Omega;
}
// Events
event ClassAdded(address indexed classAddress, uint classType);
event ClassRemoved(address indexed classAddress, uint classType);
event ClassDeactivated(address indexed classAddress, uint classType);
event ClassLimitUpdated(uint newLimit);
event VibesCalculated(address indexed user, int vibes);
event VibeUserDeactivated(address indexed user, address classAddress);
event VibeUserActivated(address indexed user, address classAddress);
event RewardsCalculated(address indexed classAddress, bytes reason);
event WhitelistedContractAdded(address indexed contractAddress);
event MasterClassVibesUpdated(address indexed classAddress, int vibes);
event MasterClassErrorLogged(address indexed classAddress, uint Omnicron);
// State variables
XUSD public xusd;
VibeLibRegistry.Registry internal MasterClassFromRegistry;
VibeLibRegistry.Registry internal MasterClassToRegistry;
VibeLibRegistry.Registry internal MasterClassCallerRegistry;
VibeLibRegistry.Registry internal MasterClassContractRegistry;
VibeLibRegistry.Registry internal MasterClassSenderRegistry;
LibRegistry.Registry internal ErrorReg;
mapping(address => MaterClass) internal MasterClassSenderMap;
mapping(address => MaterClass) internal MasterClassFromMap;
mapping(address => MaterClass) internal MasterClassToMap;
mapping(address => MaterClass) internal MasterClassCallerMap;
mapping(address => RewardClass) internal MasterClassContractMap;
mapping(address => UserProfileHash) internal MasterUser;
mapping(address => int) internal userTotalVibes;
mapping(uint => userVibe) internal userClassVibe;
mapping(address => mapping(address => Wing)) internal userVibesMap;
mapping(uint => bool) internal TroubleShoot;
mapping(address => bool) internal whitelistedContracts;
uint internal classLimit = 50;
uint internal denominator = 7500;
int internal legatusRank = 350;
int internal gladiator = 350;
uint64 public constant MotzkinPrime = 953467954114363;
/**
* @notice Initializes the VibeRegistry contract.
* @param _accessControl The address of the access control contract.
* @param _xusd The address of the XUSD contract used for rewards.
*/
constructor(address _accessControl, address _xusd) AccesorMod(_accessControl) {
xusd = XUSD(_xusd);
}
/**
* @notice Updates the class limit for registry sorting.
* @param limit The new class limit.
* @dev Can only be called by the Consul.
*/
function setClassLimit(uint limit) external onlyConsul {
classLimit = limit;
emit ClassLimitUpdated(limit);
}
/**
* @notice Adds a new class to the specified registry.
* @param class The address of the class to be added.
* @param classType The type of class (0: To, 1: From, 2: Caller, 3: Sender, 4: Contract).
* @param _process Whether the class requires processing.
* @dev Can only be called by a Senator.
*/
function addClass(
address class,
uint classType,
bool _process
) external onlySenator {
MaterClass memory newClass = MaterClass({
classAddress: class,
updatedTimestamp: block.timestamp,
process: _process,
description: VibeBase(class).getDescription(),
level: VibeBase(class).getLevel()
});
if (classType == 0) {
MasterClassToRegistry.Register(class, VibeBase(class).getLevel());
MasterClassToMap[class] = newClass;
} else if (classType == 1) {
MasterClassFromRegistry.Register(class, VibeBase(class).getLevel());
MasterClassFromMap[class] = newClass;
} else if (classType == 2) {
MasterClassCallerRegistry.Register(class, VibeBase(class).getLevel());
MasterClassCallerMap[class] = newClass;
} else if (classType == 3) {
MasterClassSenderRegistry.Register(class, VibeBase(class).getLevel());
MasterClassSenderMap[class] = newClass;
} else if (classType == 4) {
MasterClassContractRegistry.Register(class, VibeBase(class).getLevel());
MasterClassContractMap[class] = RewardClass({
classAddress: class,
process: _process,
description: VibeBase(class).getDescription()
});
}
emit ClassAdded(class, classType);
}
/**
* @notice View function to calculate the current total vibe of a user.
* @param user The address of the user whose vibe you want to calculate.
* @return The total vibes of the user.
*/
function calculateCurrentVibe(address user) external returns (int) {
int totalVibes = 0;
// Iterate over the "to" registry for vibe classes
totalVibes += _calculateVibesForAddressView(user, MasterClassToRegistry, MasterClassToMap);
// Iterate over the "from" registry for vibe classes
totalVibes += _calculateVibesForAddressView(user, MasterClassFromRegistry, MasterClassFromMap);
// Iterate over the "caller" registry for vibe classes
totalVibes += _calculateVibesForAddressView(user, MasterClassCallerRegistry, MasterClassCallerMap);
// Iterate over the "sender" registry for vibe classes
totalVibes += _calculateVibesForAddressView(user, MasterClassSenderRegistry, MasterClassSenderMap);
// Ensure that the total vibes stay within the range 0-9999
totalVibes = totalVibes < int(0) ? int(0) : totalVibes > int(9999) ? int(9999) : totalVibes;
return totalVibes;
}
/**
* @dev Internal view function to calculate vibes for a given user from a registry.
* This function does not modify state and is safe to be used within a view function.
* @param user The user address to calculate vibes for.
* @param registry The registry to query classes from.
* @param classMap Mapping from class addresses to MaterClass structs.
* @return The calculated vibes for this specific registry.
*/
function _calculateVibesForAddressView(
address user,
VibeLibRegistry.Registry storage registry,
mapping(address => MaterClass) storage classMap
) internal returns (int) {
int sumVibes = 0;
uint count = registry.Count() >= classLimit ? classLimit : registry.Count();
for (uint i = 0; i < count; i++) {
address classAddress = registry.GetHashByIndex(i);
MaterClass storage vibeClass = classMap[classAddress];
uint Omnicron = user.hashWith(vibeClass.classAddress);
bool userHasVibe = userClassVibe[Omnicron].timestamp != 0;
if (userHasVibe && userClassVibe[Omnicron].timestamp > vibeClass.updatedTimestamp) {
sumVibes += userClassVibe[Omnicron].vibes;
} else {
try IVibeCalculator(vibeClass.classAddress).calculateTotalBasisFee(user, 0) returns (int _vibes) {
sumVibes += _vibes;
} catch {
// If there's an issue calculating vibes, ignore this class
}
}
}
return sumVibes;
}
/**
* @notice Deactivates and removes a class from the specified registry.
* @param class The address of the class to be removed.
* @param classType The type of class (0: To, 1: From, 2: Caller, 3: Sender, 4: Contract).
* @dev Can only be called by the Consul.
*/
function deactivateVibe(address class, uint classType) external onlyConsul {
if (classType == 0) {
MasterClassToRegistry.Remove(class);
} else if (classType == 1) {
MasterClassFromRegistry.Remove(class);
} else if (classType == 2) {
MasterClassCallerRegistry.Remove(class);
} else if (classType == 3) {
MasterClassSenderRegistry.Remove(class);
} else if (classType == 4) {
MasterClassContractRegistry.Remove(class);
}
emit ClassDeactivated(class, classType);
}
/**
* @notice Calculates vibes for multiple addresses, sums them, and applies to the caller.
* @param to The address of the recipient.
* @param from The address of the sender.
* @param _caller The address of the contract caller.
* @param sender The address of the transaction initiator.
* @param amount The amount to process.
* @return The sum of calculated vibes and the original amount.
*/
function calculateAndSumBasis(
address to,
address from,
address _caller,
address sender,
uint amount
) external returns (int, uint) {
int sumVibes = 0;
int vibe = 0;
// Calculate vibes for each address and update the total sum
(vibe, ) = calculateVibesForAddress(to, MasterClassToRegistry, MasterClassToMap, amount);
sumVibes += vibe;
(vibe, ) = calculateVibesForAddress(from, MasterClassFromRegistry, MasterClassFromMap, amount);
sumVibes += vibe;
(vibe, ) = calculateVibesForAddress(_caller, MasterClassCallerRegistry, MasterClassCallerMap, amount);
sumVibes += vibe;
(vibe, ) = calculateVibesForAddress(sender, MasterClassSenderRegistry, MasterClassSenderMap, amount);
sumVibes += vibe;
calculateRewards(to, from, _caller, sender, amount, sumVibes);
sumVibes = sumVibes < int(0) ? int(0) : sumVibes > int(9999) ? int(9999) : sumVibes;
userTotalVibes[_caller] = sumVibes;
if (whitelistedContracts[to] || whitelistedContracts[from] || whitelistedContracts[_caller] || whitelistedContracts[sender]) {
sumVibes = 0;
}
emit VibesCalculated(_caller, sumVibes);
return (sumVibes, amount);
}
/**
* @notice View the current vibes of a specific user.
* @param user The address of the user whose vibes you want to query.
* @return The current vibes of the user.
*/
function viewVibes(address user) external view returns (int) {
return userTotalVibes[user];
}
/**
* @dev Internal function to calculate vibes for an address.
* Sorts the registry if the class limit is reached.
* @param user The user address to calculate vibes for.
* @param registry The registry to query classes from.
* @param classMap Mapping from class addresses to MaterClass structs.
* @param amount The transaction amount.
* @return The calculated vibes and the input amount.
*/
function calculateVibesForAddress(
address user,
VibeLibRegistry.Registry storage registry,
mapping(address => MaterClass) storage classMap,
uint amount
) internal returns (int, uint) {
int sumVibes = 0;
if (registry.Count() >= classLimit) {
registry.SortRegistryByAccessStyle();
}
uint count = registry.Count() >= classLimit ? classLimit : registry.Count();
for (uint i; i < count; ) {
address classAddress = registry.GetHashByIndex(i);
MaterClass storage vibeClass = classMap[classAddress];
uint Omnicron = user.hashWith(vibeClass.classAddress);
bool userHasVibe = userClassVibe[Omnicron].timestamp != 0;
if (userHasVibe && userClassVibe[Omnicron].timestamp > vibeClass.updatedTimestamp) {
if (!vibeClass.process) {
userClassVibe[Omnicron].timestamp = block.timestamp;
sumVibes += userClassVibe[Omnicron].vibes;
} else {
try IVibeCalculator(vibeClass.classAddress).calculateTotalBasisFee(user, amount) returns (int _vibes) {
userClassVibe[Omnicron].vibes = _vibes;
userClassVibe[Omnicron].timestamp = block.timestamp;
} catch {
registry.Remove(classAddress);
return (0, amount); // Return without updating vibes
}
sumVibes += userClassVibe[Omnicron].vibes;
}
} else {
try IVibeCalculator(vibeClass.classAddress).calculateTotalBasisFee(user, amount) returns (int _vibes) {
userClassVibe[Omnicron].vibes = _vibes;
userClassVibe[Omnicron].timestamp = block.timestamp;
} catch {
registry.Remove(classAddress);
return (0, amount); // Return without updating vibes
}
sumVibes += userClassVibe[Omnicron].vibes;
}
unchecked {
i++;
}
}
emit MasterClassVibesUpdated(user, sumVibes);
return (sumVibes, amount);
}
/**
* @dev Internal function to calculate rewards for users.
* Calls external reward modules for each active contract class.
* @param to The address of the recipient.
* @param from The address of the sender.
* @param _caller The address of the contract caller.
* @param sender The address of the transaction initiator.
* @param amount The amount to process.
* @param sumVibes The calculated sum of vibes.
*/
function calculateRewards(
address to,
address from,
address _caller,
address sender,
uint amount,
int sumVibes
) internal {
uint count = MasterClassContractRegistry.Count();
if (count >= classLimit) {
MasterClassContractRegistry.SortRegistryByAccessStyle();
}
for (uint i; i < count; ) {
address classHash = MasterClassContractRegistry.GetHashByIndex(i);
RewardClass storage rewardClass = MasterClassContractMap[classHash];
try IRewardsModule(rewardClass.classAddress).calculateRewards(to, from, _caller, sender, amount, sumVibes) {
// Successful reward calculation
} catch (bytes memory reason) {
// Log the error without reverting
emit RewardsCalculationFailed(classHash, reason);
}
unchecked {
i++;
}
}
}
// Event to log the errors
event RewardsCalculationFailed(address indexed classHash, bytes reason);
/**
* @notice Sets a contract as whitelisted for vibe calculations.
* @param contractWhite The address of the contract to whitelist.
* @dev Can only be called by a Senator.
*/
function setWhitelistedContract(address contractWhite) external onlySenator {
whitelistedContracts[contractWhite] = true;
emit WhitelistedContractAdded(contractWhite);
}
/**
* @notice Deactivates a user's vibe entry for a specific class.
* @param user The address of the user.
* @param class The address of the class.
* @dev Can only be called by the Consul.
*/
function deactivateVibeUser(address user, address class) external onlyConsul {
uint Omnicron = user.hashWith(class);
userClassVibe[Omnicron].active = true;
emit VibeUserDeactivated(user, class);
}
/**
* @notice Reactivates a user's vibe entry for a specific class.
* @param user The address of the user.
* @param class The address of the class.
* @dev Can only be called by the Consul.
*/
function activateVibeUser(address user, address class) external onlyConsul {
uint Omnicron = user.hashWith(class);
userClassVibe[Omnicron].active = false;
emit VibeUserActivated(user, class);
}
/**
* @dev Example function to log a class error.
* @param class The address of the class where the error occurred.
* @param Omnicron The hashed value identifying the error.
*/
function logMasterClassError(address class, uint Omnicron) internal {
ErrorReg.Register(Omnicron);
emit MasterClassErrorLogged(class, Omnicron);
}
}
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.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 Ownable is Context {
address private _owner;
/**
* @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.
*/
constructor(address initialOwner) {
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) {
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 {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @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 Context {
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;
}
}
@openzeppelin/contracts/utils/math/Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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 towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (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 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
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.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 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.
uint256 twos = denominator & (0 - denominator);
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 (unsignedRoundsUp(rounding) && 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
* towards zero.
*
* 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 + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* 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 + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}
contracts/AccessorMod.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./Classes/AccessManager.sol";
/**
* @title BaseClass
* @dev This is an abstract base class contract that includes basic functionalities for user activation and class basis management.
*/
abstract contract AccesorMod {
using AuthLib for AuthLib.RoleData;
AccessManager accessControl;
constructor(address access){
accessControl = AccessManager(access);
}
modifier onlyPreatormaximus() {
require(accessControl.checkRole(msg.sender, AuthLib.Rank.PREATORMAXIMUS),"Access Restricted");
_;
}
modifier onlyGladiator() {
require(accessControl.checkRole(msg.sender, AuthLib.Rank.GLADIATOR), "Access Restricted");
_;
}
modifier onlySenator() {
require(accessControl.checkRole(msg.sender, AuthLib.Rank.SENATOR), "Access Restricted");
_;
}
modifier onlyConsul() {
require(accessControl.checkRole(msg.sender, AuthLib.Rank.CONSUL),"Access Restricted");
_;
}
modifier onlyLegatus() {
require(accessControl.checkRole(msg.sender, AuthLib.Rank.LEGATUS),"Access Restricted");
_;
}
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
}
contracts/Address.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return
functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data
) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data
) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
contracts/Classes/Access.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/**
* @title AuthLib
* @dev A library for managing role-based access control (RBAC) using ranks. Allows accounts to be granted or revoked roles, and checks for required ranks.
*/
library AuthLib {
// Custom error for unauthorized account access
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
// Enum representing different ranks in the system
enum Rank {
PRINCEPS,
GLADIATOR,
LEGATUS,
SENATOR,
CONSUL,
PREATORMAXIMUS
}
// Registry structure to store keys and their corresponding ranks
struct Registry {
uint256[] keys; // Array to hold registered keys
mapping(uint256 => uint256) indexOf; // Maps key to its index in the keys array
mapping(uint256 => bool) inserted; // Tracks whether a key is inserted
mapping(uint256 => Rank) keyRoles; // Maps key to its assigned rank
}
// RoleData structure for managing roles of accounts
struct RoleData {
Registry registry; // Holds the registry for keys and roles
mapping(address => Rank) ranks; // Maps accounts to their assigned ranks
}
// Events
event RoleGranted(address indexed account, Rank role);
event RoleRevoked(address indexed account, Rank role);
/**
* @dev Registers a key with a specified rank in the registry.
* @param _registry The registry where the key will be stored.
* @param key The key to register (typically the address cast to uint256).
* @param rank The rank to assign to the key.
*/
function Register(Registry storage _registry, uint256 key, Rank rank) public {
if (!_registry.inserted[key]) {
_registry.inserted[key] = true;
_registry.indexOf[key] = _registry.keys.length;
_registry.keys.push(key);
_registry.keyRoles[key] = rank; // Store the rank with the key
} else {
// Update the rank if already registered
_registry.keyRoles[key] = rank;
}
}
/**
* @dev Removes a key from the registry.
* @param _registry The registry from which the key will be removed.
* @param key The key to remove.
*/
function Remove(Registry storage _registry, uint256 key) public {
if (!_registry.inserted[key]) return;
delete _registry.inserted[key];
uint256 index = _registry.indexOf[key];
uint256 lastKey = _registry.keys[_registry.keys.length - 1];
_registry.keys[index] = lastKey;
_registry.indexOf[lastKey] = index;
delete _registry.indexOf[key];
_registry.keys.pop();
delete _registry.keyRoles[key]; // Remove the associated role
}
/**
* @dev Grants a role (rank) to an account. This updates the registry and emits a RoleGranted event.
* @param roleData The RoleData struct that holds the registry and ranks.
* @param account The account to grant the role to.
* @param rank The rank to assign to the account.
*/
function grantRole(RoleData storage roleData, address account, Rank rank) public {
uint256 key = uint256(uint160(account));
roleData.ranks[account] = rank;
Register(roleData.registry, key, rank);
emit RoleGranted(account, rank); // Emit event for granting role
}
/**
* @dev Revokes a role (rank) from an account. This updates the registry and emits a RoleRevoked event.
* @param roleData The RoleData struct that holds the registry and ranks.
* @param account The account from which the role will be revoked.
*/
function revokeRole(RoleData storage roleData, address account) public {
uint256 key = uint256(uint160(account));
Rank role = roleData.ranks[account]; // Capture the role before removal for the event
delete roleData.ranks[account];
Remove(roleData.registry, key);
emit RoleRevoked(account, role); // Emit event for revoking role
}
/**
* @dev Checks whether an account holds the required role (rank) or higher.
* @param roleData The RoleData struct that holds the registry and ranks.
* @param requiredRank The minimum required rank for the account.
* @param account The account to check for the required rank.
*/
function checkRole(RoleData storage roleData, Rank requiredRank, address account) public view {
require(roleData.ranks[account] >= requiredRank, "AccessControlUnauthorizedAccount");
}
/**
* @dev Retrieves the highest rank assigned to an account.
* @param roleData The RoleData struct that holds the registry and ranks.
* @param account The account whose rank is being queried.
* @return The highest rank held by the account.
*/
function getHighestRankForAccount(RoleData storage roleData, address account) public view returns (Rank) {
return roleData.ranks[account];
}
}
contracts/Classes/AccessManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./Access.sol"; // Assuming AuthLib includes all the functionality as discussed
/**
* @title AccessManager
* @dev A contract for managing role-based access control. Allows accounts to be granted or revoked roles, and checks for required ranks.
* This contract uses the AuthLib library for role management.
*/
contract AccessManager {
using AuthLib for AuthLib.RoleData;
// State variable for storing role data
AuthLib.RoleData private roleData;
// Event declarations for logging changes in role assignments
event RoleGranted(address indexed account, AuthLib.Rank role);
event RoleRevoked(address indexed account);
modifier onlyGladiator() {
require(checkRole(msg.sender, AuthLib.Rank.GLADIATOR), "Access Restricted");
_;
}
modifier onlySenator() {
require(checkRole(msg.sender, AuthLib.Rank.SENATOR), "Access Restricted");
_;
}
modifier onlyConsul() {
require(checkRole(msg.sender, AuthLib.Rank.CONSUL),"Access Restricted");
_;
}
modifier onlyLegatus() {
require(checkRole(msg.sender, AuthLib.Rank.LEGATUS),"Access Restricted");
_;
}
modifier onlyPreatormaximus() {
require(checkRole(msg.sender, AuthLib.Rank.PREATORMAXIMUS),"Access Restricted");
_;
}
uint256 private locked = 1;
modifier nonReentrant() virtual {
require(locked == 1, "REENTRANCY");
locked = 2;
_;
locked = 1;
}
/**
* @dev Constructor that grants the contract deployer the highest role (PREATORMAXIMUS).
*/
constructor() {
// Grant the deployer the highest role initially
roleData.grantRole(msg.sender, AuthLib.Rank.PREATORMAXIMUS);
}
/**
* @notice Grants a specific role to an account.
* @dev Only accounts with the CONSUL or higher role can grant roles.
* @param account The address of the account to grant the role to.
* @param rank The rank (role) to assign to the account.
*/
function grantRole(address account, AuthLib.Rank rank) public {
// Check if the caller has sufficient privileges (CONSUL or higher)
require(
roleData.getHighestRankForAccount(msg.sender) >= AuthLib.Rank.CONSUL,
"Insufficient privileges to grant roles."
);
// Grant the role to the specified account
roleData.grantRole(account, rank);
// Emit an event for logging
emit RoleGranted(account, rank);
}
/**
* @notice Revokes a role from a specific account.
* @dev Only accounts with the CONSUL or higher role can revoke roles.
* @param account The address of the account to revoke the role from.
*/
function revokeRole(address account) public {
// Check if the caller has sufficient privileges (CONSUL or higher)
require(
roleData.getHighestRankForAccount(msg.sender) >= AuthLib.Rank.CONSUL,
"Insufficient privileges to revoke roles."
);
// Revoke the role from the specified account
roleData.revokeRole(account);
// Emit an event for logging
emit RoleRevoked(account);
}
/**
* @notice Checks if an account has a specific role or higher.
* @param account The address of the account to check.
* @param rank The required rank to check against.
* @return True if the account holds the required rank or higher, false otherwise.
*/
function checkRole(address account, AuthLib.Rank rank) public view returns (bool) {
// Check if the account has the specified role or higher
return roleData.getHighestRankForAccount(account) >= rank;
}
/**
* @notice Returns the highest rank (role) assigned to an account.
* @param account The address of the account to query.
* @return The rank held by the account.
*/
function getAccountRank(address account) public view returns (AuthLib.Rank) {
// Retrieve the highest rank assigned to the account
return roleData.getHighestRankForAccount(account);
}
}
contracts/Classes/IVibeCalculator.sol
pragma solidity ^0.8.26;
interface IVibeCalculator{
//function isRewards() external returns (bool);
function calculateTotalBasisFee(address addy, uint amount) external returns (int);
}
interface IRewardsModule{
//function isRewards() external returns (bool);
function calculateRewards(address to, address from, address caller, address sender, uint amount, int vibes) external ;
}
contracts/Classes/VibeBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./IVibeCalculator.sol";
import "../AccessorMod.sol";
/**
* @title BaseClass
* @dev This is an abstract base class contract that includes basic functionalities for user activation and class basis management.
*/
contract VibeBase is IVibeCalculator, AccesorMod {
mapping(uint => bool) public UserActiveList;
string public description;
enum Importance {
Low, // 0
Medium, // 1
High // 2
}
struct VibeInfo {
address creatorAddress;
string info;
Importance level;
}
VibeInfo public id;
constructor(VibeInfo memory _id, address access) AccesorMod(access) {
id = _id;
}
function setBaseImportance(Importance level) external {
id.level = level;
}
function getLevel() public view returns(Importance){
return id.level;
}
function getDescription() external view returns (string memory) {
return description;
}
function calculateTotalBasisFee(
address addy,
uint amount
) external virtual nonReentrant returns (int) {
return 500;
}
}
contracts/atropamath.sol
// SPDX-License-Identifier: Sharia
pragma solidity ^0.8.26;
interface RNG {
function Random() external returns(uint64);
}
library AtropaMath {
uint64 constant public MotzkinPrime = 953467954114363;
// RNG private RandomNumberGeneratorToken;
// ERC20 private DaiToken;
// ERC20 private USDCToken;
// ERC20 private USDTToken;
// ERC20 private G5Token;
// ERC20 private PIToken;
// constructor() {}
// function Random() public returns(uint64) {
// if(totalSupply() <= (1111111111 * 10 ** decimals()))
// _mint(address(this), 1 * 10 ** decimals());
// return RandomNumberGeneratorToken.Random();
// }
function hashWith(address a, address b) public returns (uint256 hash) {
hash = 0;
uint160 _a = uint160(a);
uint160 _b = uint160(b) / 15;
unchecked {
while(hash == 0) {
hash = (_a**_b)%MotzkinPrime;
_b = _b/2;
}
}
return modExp(uint256(uint160(a)), uint256(uint160(b)), MotzkinPrime);
}
function hashWithHash(address a, uint b) public returns (uint256 hash) {
hash = 0;
uint160 _a = uint160(a);
uint160 _b = uint160(b) / 15;
unchecked {
while(hash == 0) {
hash = (_a**_b)%MotzkinPrime;
_b = _b/2;
}
}
return modExp(uint256(uint160(a)), uint256(uint160(b)), MotzkinPrime);
}
function modExp64(uint64 _b, uint64 _e, uint64 _m) public returns(uint64 result) {
uint256 B = _b;
uint256 E = _e;
uint256 M = _m;
uint64 R = uint64(modExp(B, E, M) % 18446744073709551615);
return R;
}
function modExp(uint256 _b, uint256 _e, uint256 _m) public returns (uint256 result) {
assembly {
// Free memory pointer
let pointer := mload(0x40)
// Define length of base, exponent and modulus. 0x20 == 32 bytes
mstore(pointer, 0x20)
mstore(add(pointer, 0x20), 0x20)
mstore(add(pointer, 0x40), 0x20)
// Define variables base, exponent and modulus
mstore(add(pointer, 0x60), _b)
mstore(add(pointer, 0x80), _e)
mstore(add(pointer, 0xa0), _m)
// Store the result
let value := mload(0xc0)
// Call the precompiled contract 0x05 = bigModExp
if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {
revert(0, 0)
}
result := mload(value)
}
}
function sortThree(uint64 a, uint64 b, uint64 c) public pure returns (uint64, uint64, uint64) {
// Check if all three are equal
if (a == b && b == c) {
return (0, 0, a); // All are equal
}
// Handling pairs of equal values
if (a == b) {
return (0, a, c > a ? c : a); // a == b
}
if (a == c) {
return (0, a, b > a ? b : a); // a == c
}
if (b == c) {
return (0, b, a > b ? a : b); // b == c
}
// All values are distinct
if (a <= b && a <= c) {
if (b <= c) {
return (a, b, c); // a < b < c
} else {
return (a, c, b); // a < c < b
}
} else if (b <= a && b <= c) {
if (a <= c) {
return (b, a, c); // b < a < c
} else {
return (b, c, a); // b < c < a
}
} else {
if (a <= b) {
return (c, a, b); // c < a < b
} else {
return (c, b, a); // c < b < a
}
}
}
}
contracts/registry.sol
// SPDX-License-Identifier: Sharia
pragma solidity ^0.8.24;
library LibRegistry {
struct Registry {
uint256[] keys;
mapping(uint256 => uint256) indexOf;
mapping(uint256 => bool) inserted;
}
function GetHashByIndex(Registry storage _registry, uint256 index) public view returns(uint256) {
return _registry.keys[index];
}
function Count(Registry storage _registry) public view returns(uint256) {
return _registry.keys.length;
}
function Contains(Registry storage _registry, uint256 key) public view returns(bool) {
return _registry.inserted[key];
}
function ReturnAllKeys(Registry storage _registry) public view returns(uint256 [] storage) {
return _registry.keys;
}
function Register(Registry storage _registry, uint256 key) public {
if(!_registry.inserted[key])
{
_registry.inserted[key] = true;
_registry.indexOf[key] = _registry.keys.length;
_registry.keys.push(key);
}
}
function Remove(Registry storage _registry, uint256 key) public {
if(!_registry.inserted[key]) return;
delete _registry.inserted[key];
uint256 index = _registry.indexOf[key];
uint256 lastKey = _registry.keys[_registry.keys.length - 1];
_registry.indexOf[lastKey] = index;
delete _registry.indexOf[key];
_registry.keys[index] = lastKey;
_registry.keys.pop();
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"],"":["ast"]}},"optimizer":{"runs":200,"enabled":false},"libraries":{},"evmVersion":"paris"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"string","name":"name_","internalType":"string"},{"type":"string","name":"symbol_","internalType":"string"},{"type":"uint256","name":"initialBalance_","internalType":"uint256"},{"type":"address","name":"_access","internalType":"address"},{"type":"address","name":"t","internalType":"address"}]},{"type":"error","name":"CheckpointUnorderedInsertion","inputs":[]},{"type":"error","name":"OwnableInvalidOwner","inputs":[{"type":"address","name":"owner","internalType":"address"}]},{"type":"error","name":"OwnableUnauthorizedAccount","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"event","name":"Approval","inputs":[{"type":"address","name":"owner","internalType":"address","indexed":true},{"type":"address","name":"spender","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"Transfer","inputs":[{"type":"address","name":"from","internalType":"address","indexed":true},{"type":"address","name":"to","internalType":"address","indexed":true},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"Rewardtransfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"allowance","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"spender","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"approve","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"burnAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"burnBalanceContract","inputs":[{"type":"address","name":"contractAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"burnBalanceEOA","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint8","name":"","internalType":"uint8"}],"name":"decimals","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"decreaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"subtractedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32[]","name":"blocks","internalType":"uint32[]"},{"type":"uint224[]","name":"burns","internalType":"uint224[]"}],"name":"getFullBurnHistoryContract","inputs":[{"type":"address","name":"contractAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint32[]","name":"blocks","internalType":"uint32[]"},{"type":"uint224[]","name":"burns","internalType":"uint224[]"}],"name":"getFullBurnHistoryEOA","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint224","name":"","internalType":"uint224"}],"name":"getLatestBurnContract","inputs":[{"type":"address","name":"contractAddr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint224","name":"","internalType":"uint224"}],"name":"getLatestBurnEOA","inputs":[{"type":"address","name":"user","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"increaseAllowance","inputs":[{"type":"address","name":"spender","internalType":"address"},{"type":"uint256","name":"addedValue","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isExcludedFromTax","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"mint","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"name","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract VibeRegistry"}],"name":"registry","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setExclusionFromTax","inputs":[{"type":"address","name":"account","internalType":"address"},{"type":"bool","name":"status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"reg","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTaxVariable","inputs":[{"type":"uint256","name":"treasury","internalType":"uint256"},{"type":"uint256","name":"burn","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setTreasury","inputs":[{"type":"address","name":"t","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"string","name":"","internalType":"string"}],"name":"symbol","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalBurned","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transfer","inputs":[{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"transferFrom","inputs":[{"type":"address","name":"from","internalType":"address"},{"type":"address","name":"to","internalType":"address"},{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
Contract Creation Code
0x60a0604052600180556102bc600d5561012c600e556000601460016101000a81548160ff0219169083151502179055506000601460026101000a81548160ff02191690831515021790555061036973ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff1681525034801561008b57600080fd5b5060405161485038038061485083398181016040528101906100ad9190610653565b3382806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16036101625760006040517f1e4fbdf70000000000000000000000000000000000000000000000000000000081526004016101599190610715565b60405180910390fd5b6101718161023d60201b60201c565b50600083116101b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101ac9061078d565b60405180910390fd5b80600f60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550846012908161020591906109c4565b50836013908161021591906109c4565b5061023361022761030360201b60201c565b8461030b60201b60201c565b5050505050610b8f565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff160361037a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161037190610ae2565b60405180910390fd5b806010600082825461038c9190610b31565b9250508190555080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8360405161043e9190610b74565b60405180910390a35050565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6104b182610468565b810181811067ffffffffffffffff821117156104d0576104cf610479565b5b80604052505050565b60006104e361044a565b90506104ef82826104a8565b919050565b600067ffffffffffffffff82111561050f5761050e610479565b5b61051882610468565b9050602081019050919050565b60005b83811015610543578082015181840152602081019050610528565b60008484015250505050565b600061056261055d846104f4565b6104d9565b90508281526020810184848401111561057e5761057d610463565b5b610589848285610525565b509392505050565b600082601f8301126105a6576105a561045e565b5b81516105b684826020860161054f565b91505092915050565b6000819050919050565b6105d2816105bf565b81146105dd57600080fd5b50565b6000815190506105ef816105c9565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610620826105f5565b9050919050565b61063081610615565b811461063b57600080fd5b50565b60008151905061064d81610627565b92915050565b600080600080600060a0868803121561066f5761066e610454565b5b600086015167ffffffffffffffff81111561068d5761068c610459565b5b61069988828901610591565b955050602086015167ffffffffffffffff8111156106ba576106b9610459565b5b6106c688828901610591565b94505060406106d7888289016105e0565b93505060606106e88882890161063e565b92505060806106f98882890161063e565b9150509295509295909350565b61070f81610615565b82525050565b600060208201905061072a6000830184610706565b92915050565b600082825260208201905092915050565b7f496e697469616c20737570706c792063616e6e6f74206265207a65726f000000600082015250565b6000610777601d83610730565b915061078282610741565b602082019050919050565b600060208201905081810360008301526107a68161076a565b9050919050565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806107ff57607f821691505b602082108103610812576108116107b8565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b60006008830261087a7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8261083d565b610884868361083d565b95508019841693508086168417925050509392505050565b6000819050919050565b60006108c16108bc6108b7846105bf565b61089c565b6105bf565b9050919050565b6000819050919050565b6108db836108a6565b6108ef6108e7826108c8565b84845461084a565b825550505050565b600090565b6109046108f7565b61090f8184846108d2565b505050565b5b81811015610933576109286000826108fc565b600181019050610915565b5050565b601f8211156109785761094981610818565b6109528461082d565b81016020851015610961578190505b61097561096d8561082d565b830182610914565b50505b505050565b600082821c905092915050565b600061099b6000198460080261097d565b1980831691505092915050565b60006109b4838361098a565b9150826002028217905092915050565b6109cd826107ad565b67ffffffffffffffff8111156109e6576109e5610479565b5b6109f082546107e7565b6109fb828285610937565b600060209050601f831160018114610a2e5760008415610a1c578287015190505b610a2685826109a8565b865550610a8e565b601f198416610a3c86610818565b60005b82811015610a6457848901518255600182019150602085019450602081019050610a3f565b86831015610a815784890151610a7d601f89168261098a565b8355505b6001600288020188555050505b505050505050565b7f4d696e7420746f207a65726f2061646472657373000000000000000000000000600082015250565b6000610acc601483610730565b9150610ad782610a96565b602082019050919050565b60006020820190508181036000830152610afb81610abf565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610b3c826105bf565b9150610b47836105bf565b9250828201905080821115610b5f57610b5e610b02565b5b92915050565b610b6e816105bf565b82525050565b6000602082019050610b896000830184610b65565b92915050565b608051613c9f610bb160003960008181610e1c0152611eca0152613c9f6000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c80638756201211610104578063be183492116100a2578063dd62ed3e11610071578063dd62ed3e146105a7578063e6993191146105d7578063f0f4426014610607578063f2fde38b14610623576101da565b8063be183492146104f7578063cae5cb5014610528578063cb4ca63114610559578063d89135cd14610589576101da565b80639c53417b116100de5780639c53417b1461044b578063a457c2d71461047b578063a9059cbb146104ab578063a91ee0dc146104db576101da565b806387562012146103f35780638da5cb5b1461040f57806395d89b411461042d576101da565b806340c10f191161017c57806370a082311161014b57806370a082311461037d57806370d5ae05146103ad578063715018a6146103cb5780637b103999146103d5576101da565b806340c10f19146102e55780634274e43d14610301578063493722e5146103315780636fe34e891461034d576101da565b806323b872dd116101b857806323b872dd1461024b578063313ce5671461027b57806339509351146102995780633bf4c874146102c9576101da565b806306fdde03146101df578063095ea7b3146101fd57806318160ddd1461022d575b600080fd5b6101e761063f565b6040516101f49190612de1565b60405180910390f35b61021760048036038101906102129190612e9c565b6106d1565b6040516102249190612ef7565b60405180910390f35b6102356106f4565b6040516102429190612f21565b60405180910390f35b61026560048036038101906102609190612f3c565b6106fe565b6040516102729190612ef7565b60405180910390f35b610283610999565b6040516102909190612fab565b60405180910390f35b6102b360048036038101906102ae9190612e9c565b6109a2565b6040516102c09190612ef7565b60405180910390f35b6102e360048036038101906102de9190612e9c565b6109d9565b005b6102ff60048036038101906102fa9190612e9c565b610b1e565b005b61031b60048036038101906103169190612fc6565b610c08565b6040516103289190612f21565b60405180910390f35b61034b6004803603810190610346919061301f565b610c51565b005b61036760048036038101906103629190612fc6565b610d88565b6040516103749190612f21565b60405180910390f35b61039760048036038101906103929190612fc6565b610dd1565b6040516103a49190612f21565b60405180910390f35b6103b5610e1a565b6040516103c2919061306e565b60405180910390f35b6103d3610e3e565b005b6103dd610e52565b6040516103ea91906130e8565b60405180910390f35b61040d60048036038101906104089190613103565b610e78565b005b610417610f66565b604051610424919061306e565b60405180910390f35b610435610f90565b6040516104429190612de1565b60405180910390f35b61046560048036038101906104609190612fc6565b611022565b604051610472919061317a565b60405180910390f35b61049560048036038101906104909190612e9c565b611072565b6040516104a29190612ef7565b60405180910390f35b6104c560048036038101906104c09190612e9c565b6110e9565b6040516104d29190612ef7565b60405180910390f35b6104f560048036038101906104f09190612fc6565b611378565b005b610511600480360381019061050c9190612fc6565b6114e0565b60405161051f929190613321565b60405180910390f35b610542600480360381019061053d9190612fc6565b6116de565b604051610550929190613321565b60405180910390f35b610573600480360381019061056e9190612fc6565b6118dc565b6040516105809190612ef7565b60405180910390f35b610591611932565b60405161059e9190612f21565b60405180910390f35b6105c160048036038101906105bc9190613358565b611949565b6040516105ce9190612f21565b60405180910390f35b6105f160048036038101906105ec9190612fc6565b6119d0565b6040516105fe919061317a565b60405180910390f35b610621600480360381019061061c9190612fc6565b611a20565b005b61063d60048036038101906106389190612fc6565b611b40565b005b60606012805461064e906133c7565b80601f016020809104026020016040519081016040528092919081815260200182805461067a906133c7565b80156106c75780601f1061069c576101008083540402835291602001916106c7565b820191906000526020600020905b8154815290600101906020018083116106aa57829003601f168201915b5050505050905090565b6000806106dc611bc6565b90506106e9818585611bce565b600191505092915050565b6000601054905090565b60006001805414610744576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073b90613444565b60405180910390fd5b60026001819055506000610756611bc6565b9050610763858285611d97565b600080601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663640562b1878932878a6040518663ffffffff1660e01b81526004016107c9959493929190613464565b60408051808303816000875af11580156107e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080b9190613502565b915091506000821380156108695750601560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b80156108bf5750601560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b1561097957600061271083836108d59190613571565b6108df91906135e2565b90506000811115610977576000612710600d54836108fd9190613571565b61090791906135e2565b9050600081836109179190613613565b9050600082111561092f5761092e8a600084611e23565b5b6000811115610966576109658a600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e23565b5b82846109729190613613565b935050505b505b610984878783611e23565b60019350505050600180819055509392505050565b60006012905090565b6000806109ad611bc6565b90506109ce8185856109bf8589611949565b6109c99190613647565b611bce565b600191505092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610a359291906136f2565b602060405180830381865afa158015610a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a769190613730565b610ab5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aac906137a9565b60405180910390fd5b6001805414610af9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af090613444565b60405180910390fd5b6002600181905550610b13610b0c611bc6565b8383611e23565b600180819055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610b7a9291906136f2565b602060405180830381865afa158015610b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbb9190613730565b610bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf1906137a9565b60405180910390fd5b610c0482826121b8565b5050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360036040518363ffffffff1660e01b8152600401610cad9291906136f2565b602060405180830381865afa158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee9190613730565b610d2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d24906137a9565b60405180910390fd5b80601560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b610e466122f7565b610e50600061237e565b565b601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610ed49291906136f2565b602060405180830381865afa158015610ef1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f159190613730565b610f54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4b906137a9565b60405180910390fd5b80600d8190555081600e819055505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060138054610f9f906133c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610fcb906133c7565b80156110185780601f10610fed57610100808354040283529160200191611018565b820191906000526020600020905b815481529060010190602001808311610ffb57829003601f168201915b5050505050905090565b600061106b600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612444565b9050919050565b60008061107d611bc6565b9050600061108b8286611949565b9050838110156110d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110c790613815565b60405180910390fd5b6110dd8286868403611bce565b60019250505092915050565b6000600180541461112f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112690613444565b60405180910390fd5b60026001819055506000611141611bc6565b9050600080601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663640562b1878532338a6040518663ffffffff1660e01b81526004016111a9959493929190613464565b60408051808303816000875af11580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb9190613502565b915091506000821380156112495750601560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b801561129f5750601560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b1561135957600061271083836112b59190613571565b6112bf91906135e2565b90506000811115611357576000612710600d54836112dd9190613571565b6112e791906135e2565b9050600081836112f79190613613565b9050600082111561130f5761130e86600084611e23565b5b60008111156113465761134586600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e23565b5b82846113529190613613565b935050505b505b611364838783611e23565b600193505050506001808190555092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360036040518363ffffffff1660e01b81526004016113d49291906136f2565b602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190613730565b611454576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144b906137a9565b60405180910390fd5b61145d816124ae565b61149c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611493906138a7565b60405180910390fd5b80601660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060806000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561159a57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161155d5790505b505050505090506000815167ffffffffffffffff8111156115be576115bd6138c7565b5b6040519080825280602002602001820160405280156115ec5781602001602082028036833780820191505090505b50905060005b82518110156116d057611666838281518110611611576116106138f6565b5b6020026020010151600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206124c190919063ffffffff16565b828281518110611679576116786138f6565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505080806001019150506115f2565b508181935093505050915091565b6060806000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561179857602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161175b5790505b505050505090506000815167ffffffffffffffff8111156117bc576117bb6138c7565b5b6040519080825280602002602001820160405280156117ea5781602001602082028036833780820191505090505b50905060005b82518110156118ce5761186483828151811061180f5761180e6138f6565b5b6020026020010151600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206124c190919063ffffffff16565b828281518110611877576118766138f6565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505080806001019150506117f0565b508181935093505050915091565b6000601560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000600c54600b546119449190613647565b905090565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000611a19600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612444565b9050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401611a7c9291906136f2565b602060405180830381865afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190613730565b611afc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611af3906137a9565b60405180910390fd5b80600f60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611b486122f7565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611bba5760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611bb1919061306e565b60405180910390fd5b611bc38161237e565b50565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611c3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3490613971565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611cac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca3906139dd565b60405180910390fd5b80600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051611d8a9190612f21565b60405180910390a3505050565b6000611da38484611949565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e1d5781811015611e0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e0690613a49565b60405180910390fd5b611e1c8484848403611bce565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611e92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8990613ab5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480611f1857507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561203257611f26836124ae565b15611fa95780600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611f7a9190613647565b9250508190555080600c6000828254611f939190613647565b92505081905550611fa48382612541565b612023565b80600860003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611ff89190613647565b9250508190555080600b60008282546120119190613647565b925050819055506120223282612681565b5b61202d83826127c1565b6121b3565b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156120b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120b090613b21565b60405180910390fd5b818103600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516121a99190612f21565b60405180910390a3505b505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612227576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161221e90613b8d565b60405180910390fd5b80601060008282546122399190613647565b9250508190555080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516122eb9190612f21565b60405180910390a35050565b6122ff611bc6565b73ffffffffffffffffffffffffffffffffffffffff1661231d610f66565b73ffffffffffffffffffffffffffffffffffffffff161461237c57612340611bc6565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401612373919061306e565b60405180910390fd5b565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008082600001805490509050600081146124a3576124728360000160018361246d9190613613565b612909565b60000160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166124a6565b60005b915050919050565b600080823b905060008111915050919050565b6000808360000180549050905060006124e0856000018560008561291e565b90506000811461253457612503856000016001836124fe9190613613565b612909565b60000160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16612537565b60005b9250505092915050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600082826125939190613bad565b905060004390506125ed8183600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206129919092919063ffffffff16565b5050600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055505050505050565b6000600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600082826126d39190613bad565b9050600043905061272d8183600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206129919092919063ffffffff16565b5050600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055505050505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015612848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161283f90613c49565b60405180910390fd5b818103600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081601060008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516128fc9190612f21565b60405180910390a3505050565b60008260005281602060002001905092915050565b60005b8183101561298657600061293584846129ae565b90508463ffffffff166129488783612909565b60000160009054906101000a900463ffffffff1663ffffffff16111561297057809250612980565b60018161297d9190613647565b93505b50612921565b819050949350505050565b6000806129a28560000185856129d4565b91509150935093915050565b600060028284186129bf91906135e2565b8284166129cc9190613647565b905092915050565b6000806000858054905090506000811115612c61576000612a01876001846129fc9190613613565b612909565b6040518060400160405290816000820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505090508563ffffffff16816000015163ffffffff161115612aec576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8563ffffffff16816000015163ffffffff1603612b705784612b1a88600185612b159190613613565b612909565b60000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550612c50565b8660405180604001604052808863ffffffff168152602001877bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555050505b806020015185935093505050612d49565b8560405180604001604052808763ffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550505060008492509250505b935093915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d8b578082015181840152602081019050612d70565b60008484015250505050565b6000601f19601f8301169050919050565b6000612db382612d51565b612dbd8185612d5c565b9350612dcd818560208601612d6d565b612dd681612d97565b840191505092915050565b60006020820190508181036000830152612dfb8184612da8565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612e3382612e08565b9050919050565b612e4381612e28565b8114612e4e57600080fd5b50565b600081359050612e6081612e3a565b92915050565b6000819050919050565b612e7981612e66565b8114612e8457600080fd5b50565b600081359050612e9681612e70565b92915050565b60008060408385031215612eb357612eb2612e03565b5b6000612ec185828601612e51565b9250506020612ed285828601612e87565b9150509250929050565b60008115159050919050565b612ef181612edc565b82525050565b6000602082019050612f0c6000830184612ee8565b92915050565b612f1b81612e66565b82525050565b6000602082019050612f366000830184612f12565b92915050565b600080600060608486031215612f5557612f54612e03565b5b6000612f6386828701612e51565b9350506020612f7486828701612e51565b9250506040612f8586828701612e87565b9150509250925092565b600060ff82169050919050565b612fa581612f8f565b82525050565b6000602082019050612fc06000830184612f9c565b92915050565b600060208284031215612fdc57612fdb612e03565b5b6000612fea84828501612e51565b91505092915050565b612ffc81612edc565b811461300757600080fd5b50565b60008135905061301981612ff3565b92915050565b6000806040838503121561303657613035612e03565b5b600061304485828601612e51565b92505060206130558582860161300a565b9150509250929050565b61306881612e28565b82525050565b6000602082019050613083600083018461305f565b92915050565b6000819050919050565b60006130ae6130a96130a484612e08565b613089565b612e08565b9050919050565b60006130c082613093565b9050919050565b60006130d2826130b5565b9050919050565b6130e2816130c7565b82525050565b60006020820190506130fd60008301846130d9565b92915050565b6000806040838503121561311a57613119612e03565b5b600061312885828601612e87565b925050602061313985828601612e87565b9150509250929050565b60007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61317481613143565b82525050565b600060208201905061318f600083018461316b565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600063ffffffff82169050919050565b6131da816131c1565b82525050565b60006131ec83836131d1565b60208301905092915050565b6000602082019050919050565b600061321082613195565b61321a81856131a0565b9350613225836131b1565b8060005b8381101561325657815161323d88826131e0565b9750613248836131f8565b925050600181019050613229565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61329881613143565b82525050565b60006132aa838361328f565b60208301905092915050565b6000602082019050919050565b60006132ce82613263565b6132d8818561326e565b93506132e38361327f565b8060005b838110156133145781516132fb888261329e565b9750613306836132b6565b9250506001810190506132e7565b5085935050505092915050565b6000604082019050818103600083015261333b8185613205565b9050818103602083015261334f81846132c3565b90509392505050565b6000806040838503121561336f5761336e612e03565b5b600061337d85828601612e51565b925050602061338e85828601612e51565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806133df57607f821691505b6020821081036133f2576133f1613398565b5b50919050565b7f5245454e5452414e435900000000000000000000000000000000000000000000600082015250565b600061342e600a83612d5c565b9150613439826133f8565b602082019050919050565b6000602082019050818103600083015261345d81613421565b9050919050565b600060a082019050613479600083018861305f565b613486602083018761305f565b613493604083018661305f565b6134a0606083018561305f565b6134ad6080830184612f12565b9695505050505050565b6000819050919050565b6134ca816134b7565b81146134d557600080fd5b50565b6000815190506134e7816134c1565b92915050565b6000815190506134fc81612e70565b92915050565b6000806040838503121561351957613518612e03565b5b6000613527858286016134d8565b9250506020613538858286016134ed565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061357c82612e66565b915061358783612e66565b925082820261359581612e66565b915082820484148315176135ac576135ab613542565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006135ed82612e66565b91506135f883612e66565b925082613608576136076135b3565b5b828204905092915050565b600061361e82612e66565b915061362983612e66565b925082820390508181111561364157613640613542565b5b92915050565b600061365282612e66565b915061365d83612e66565b925082820190508082111561367557613674613542565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600681106136bb576136ba61367b565b5b50565b60008190506136cc826136aa565b919050565b60006136dc826136be565b9050919050565b6136ec816136d1565b82525050565b6000604082019050613707600083018561305f565b61371460208301846136e3565b9392505050565b60008151905061372a81612ff3565b92915050565b60006020828403121561374657613745612e03565b5b60006137548482850161371b565b91505092915050565b7f4163636573732052657374726963746564000000000000000000000000000000600082015250565b6000613793601183612d5c565b915061379e8261375d565b602082019050919050565b600060208201905081810360008301526137c281613786565b9050919050565b7f44656372656173656420616c6c6f77616e63652062656c6f77207a65726f0000600082015250565b60006137ff601e83612d5c565b915061380a826137c9565b602082019050919050565b6000602082019050818103600083015261382e816137f2565b9050919050565b7f50726f76696465642061646472657373206973206e6f74206120636f6e74726160008201527f6374000000000000000000000000000000000000000000000000000000000000602082015250565b6000613891602283612d5c565b915061389c82613835565b604082019050919050565b600060208201905081810360008301526138c081613884565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f417070726f76652066726f6d207a65726f206164647265737300000000000000600082015250565b600061395b601983612d5c565b915061396682613925565b602082019050919050565b6000602082019050818103600083015261398a8161394e565b9050919050565b7f417070726f766520746f207a65726f2061646472657373000000000000000000600082015250565b60006139c7601783612d5c565b91506139d282613991565b602082019050919050565b600060208201905081810360008301526139f6816139ba565b9050919050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b6000613a33601683612d5c565b9150613a3e826139fd565b602082019050919050565b60006020820190508181036000830152613a6281613a26565b9050919050565b7f5472616e736665722066726f6d207a65726f2061646472657373000000000000600082015250565b6000613a9f601a83612d5c565b9150613aaa82613a69565b602082019050919050565b60006020820190508181036000830152613ace81613a92565b9050919050565b7f5472616e7366657220616d6f756e7420657863656564732062616c616e636500600082015250565b6000613b0b601f83612d5c565b9150613b1682613ad5565b602082019050919050565b60006020820190508181036000830152613b3a81613afe565b9050919050565b7f4d696e7420746f207a65726f2061646472657373000000000000000000000000600082015250565b6000613b77601483612d5c565b9150613b8282613b41565b602082019050919050565b60006020820190508181036000830152613ba681613b6a565b9050919050565b6000613bb882613143565b9150613bc383613143565b925082820190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115613bf757613bf6613542565b5b92915050565b7f4275726e20616d6f756e7420657863656564732062616c616e63650000000000600082015250565b6000613c33601b83612d5c565b9150613c3e82613bfd565b602082019050919050565b60006020820190508181036000830152613c6281613c26565b905091905056fea2646970667358221220bcd58db043af6115737612c62b8e91eefa677eb705676283a5c41e15bc77dfbb64736f6c634300081a003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000052b7d2dcc80cd2e4000000000000000000000000000000cb13ca54a9744afa2586e6232b94a58cf9b5e25c0000000000000000000000003246f31ad1b00991965d7a68aef694c4464d89eb00000000000000000000000000000000000000000000000000000000000000145855534420566962726174696c6520417373657400000000000000000000000000000000000000000000000000000000000000000000000000000000000000045855534400000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106101da5760003560e01c80638756201211610104578063be183492116100a2578063dd62ed3e11610071578063dd62ed3e146105a7578063e6993191146105d7578063f0f4426014610607578063f2fde38b14610623576101da565b8063be183492146104f7578063cae5cb5014610528578063cb4ca63114610559578063d89135cd14610589576101da565b80639c53417b116100de5780639c53417b1461044b578063a457c2d71461047b578063a9059cbb146104ab578063a91ee0dc146104db576101da565b806387562012146103f35780638da5cb5b1461040f57806395d89b411461042d576101da565b806340c10f191161017c57806370a082311161014b57806370a082311461037d57806370d5ae05146103ad578063715018a6146103cb5780637b103999146103d5576101da565b806340c10f19146102e55780634274e43d14610301578063493722e5146103315780636fe34e891461034d576101da565b806323b872dd116101b857806323b872dd1461024b578063313ce5671461027b57806339509351146102995780633bf4c874146102c9576101da565b806306fdde03146101df578063095ea7b3146101fd57806318160ddd1461022d575b600080fd5b6101e761063f565b6040516101f49190612de1565b60405180910390f35b61021760048036038101906102129190612e9c565b6106d1565b6040516102249190612ef7565b60405180910390f35b6102356106f4565b6040516102429190612f21565b60405180910390f35b61026560048036038101906102609190612f3c565b6106fe565b6040516102729190612ef7565b60405180910390f35b610283610999565b6040516102909190612fab565b60405180910390f35b6102b360048036038101906102ae9190612e9c565b6109a2565b6040516102c09190612ef7565b60405180910390f35b6102e360048036038101906102de9190612e9c565b6109d9565b005b6102ff60048036038101906102fa9190612e9c565b610b1e565b005b61031b60048036038101906103169190612fc6565b610c08565b6040516103289190612f21565b60405180910390f35b61034b6004803603810190610346919061301f565b610c51565b005b61036760048036038101906103629190612fc6565b610d88565b6040516103749190612f21565b60405180910390f35b61039760048036038101906103929190612fc6565b610dd1565b6040516103a49190612f21565b60405180910390f35b6103b5610e1a565b6040516103c2919061306e565b60405180910390f35b6103d3610e3e565b005b6103dd610e52565b6040516103ea91906130e8565b60405180910390f35b61040d60048036038101906104089190613103565b610e78565b005b610417610f66565b604051610424919061306e565b60405180910390f35b610435610f90565b6040516104429190612de1565b60405180910390f35b61046560048036038101906104609190612fc6565b611022565b604051610472919061317a565b60405180910390f35b61049560048036038101906104909190612e9c565b611072565b6040516104a29190612ef7565b60405180910390f35b6104c560048036038101906104c09190612e9c565b6110e9565b6040516104d29190612ef7565b60405180910390f35b6104f560048036038101906104f09190612fc6565b611378565b005b610511600480360381019061050c9190612fc6565b6114e0565b60405161051f929190613321565b60405180910390f35b610542600480360381019061053d9190612fc6565b6116de565b604051610550929190613321565b60405180910390f35b610573600480360381019061056e9190612fc6565b6118dc565b6040516105809190612ef7565b60405180910390f35b610591611932565b60405161059e9190612f21565b60405180910390f35b6105c160048036038101906105bc9190613358565b611949565b6040516105ce9190612f21565b60405180910390f35b6105f160048036038101906105ec9190612fc6565b6119d0565b6040516105fe919061317a565b60405180910390f35b610621600480360381019061061c9190612fc6565b611a20565b005b61063d60048036038101906106389190612fc6565b611b40565b005b60606012805461064e906133c7565b80601f016020809104026020016040519081016040528092919081815260200182805461067a906133c7565b80156106c75780601f1061069c576101008083540402835291602001916106c7565b820191906000526020600020905b8154815290600101906020018083116106aa57829003601f168201915b5050505050905090565b6000806106dc611bc6565b90506106e9818585611bce565b600191505092915050565b6000601054905090565b60006001805414610744576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073b90613444565b60405180910390fd5b60026001819055506000610756611bc6565b9050610763858285611d97565b600080601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663640562b1878932878a6040518663ffffffff1660e01b81526004016107c9959493929190613464565b60408051808303816000875af11580156107e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061080b9190613502565b915091506000821380156108695750601560008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b80156108bf5750601560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b1561097957600061271083836108d59190613571565b6108df91906135e2565b90506000811115610977576000612710600d54836108fd9190613571565b61090791906135e2565b9050600081836109179190613613565b9050600082111561092f5761092e8a600084611e23565b5b6000811115610966576109658a600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e23565b5b82846109729190613613565b935050505b505b610984878783611e23565b60019350505050600180819055509392505050565b60006012905090565b6000806109ad611bc6565b90506109ce8185856109bf8589611949565b6109c99190613647565b611bce565b600191505092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610a359291906136f2565b602060405180830381865afa158015610a52573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a769190613730565b610ab5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610aac906137a9565b60405180910390fd5b6001805414610af9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af090613444565b60405180910390fd5b6002600181905550610b13610b0c611bc6565b8383611e23565b600180819055505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610b7a9291906136f2565b602060405180830381865afa158015610b97573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bbb9190613730565b610bfa576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bf1906137a9565b60405180910390fd5b610c0482826121b8565b5050565b6000600860008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360036040518363ffffffff1660e01b8152600401610cad9291906136f2565b602060405180830381865afa158015610cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610cee9190613730565b610d2d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d24906137a9565b60405180910390fd5b80601560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548160ff0219169083151502179055505050565b6000600760008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b6000600560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b7f000000000000000000000000000000000000000000000000000000000000036981565b610e466122f7565b610e50600061237e565b565b601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401610ed49291906136f2565b602060405180830381865afa158015610ef1573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f159190613730565b610f54576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610f4b906137a9565b60405180910390fd5b80600d8190555081600e819055505050565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606060138054610f9f906133c7565b80601f0160208091040260200160405190810160405280929190818152602001828054610fcb906133c7565b80156110185780601f10610fed57610100808354040283529160200191611018565b820191906000526020600020905b815481529060010190602001808311610ffb57829003601f168201915b5050505050905090565b600061106b600960008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612444565b9050919050565b60008061107d611bc6565b9050600061108b8286611949565b9050838110156110d0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016110c790613815565b60405180910390fd5b6110dd8286868403611bce565b60019250505092915050565b6000600180541461112f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161112690613444565b60405180910390fd5b60026001819055506000611141611bc6565b9050600080601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663640562b1878532338a6040518663ffffffff1660e01b81526004016111a9959493929190613464565b60408051808303816000875af11580156111c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111eb9190613502565b915091506000821380156112495750601560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b801561129f5750601560008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff16155b1561135957600061271083836112b59190613571565b6112bf91906135e2565b90506000811115611357576000612710600d54836112dd9190613571565b6112e791906135e2565b9050600081836112f79190613613565b9050600082111561130f5761130e86600084611e23565b5b60008111156113465761134586600f60009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1683611e23565b5b82846113529190613613565b935050505b505b611364838783611e23565b600193505050506001808190555092915050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360036040518363ffffffff1660e01b81526004016113d49291906136f2565b602060405180830381865afa1580156113f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114159190613730565b611454576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161144b906137a9565b60405180910390fd5b61145d816124ae565b61149c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611493906138a7565b60405180910390fd5b80601660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6060806000600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561159a57602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161155d5790505b505050505090506000815167ffffffffffffffff8111156115be576115bd6138c7565b5b6040519080825280602002602001820160405280156115ec5781602001602082028036833780820191505090505b50905060005b82518110156116d057611666838281518110611611576116106138f6565b5b6020026020010151600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206124c190919063ffffffff16565b828281518110611679576116786138f6565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505080806001019150506115f2565b508181935093505050915091565b6060806000600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548060200260200160405190810160405280929190818152602001828054801561179857602002820191906000526020600020906000905b82829054906101000a900463ffffffff1663ffffffff168152602001906004019060208260030104928301926001038202915080841161175b5790505b505050505090506000815167ffffffffffffffff8111156117bc576117bb6138c7565b5b6040519080825280602002602001820160405280156117ea5781602001602082028036833780820191505090505b50905060005b82518110156118ce5761186483828151811061180f5761180e6138f6565b5b6020026020010151600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206124c190919063ffffffff16565b828281518110611877576118766138f6565b5b60200260200101907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505080806001019150506117f0565b508181935093505050915091565b6000601560008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900460ff169050919050565b6000600c54600b546119449190613647565b905090565b6000600660008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b6000611a19600a60008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020612444565b9050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323a3ad723360046040518363ffffffff1660e01b8152600401611a7c9291906136f2565b602060405180830381865afa158015611a99573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611abd9190613730565b611afc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611af3906137a9565b60405180910390fd5b80600f60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b611b486122f7565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603611bba5760006040517f1e4fbdf7000000000000000000000000000000000000000000000000000000008152600401611bb1919061306e565b60405180910390fd5b611bc38161237e565b50565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611c3d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c3490613971565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603611cac576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ca3906139dd565b60405180910390fd5b80600660008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92583604051611d8a9190612f21565b60405180910390a3505050565b6000611da38484611949565b90507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611e1d5781811015611e0f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e0690613a49565b60405180910390fd5b611e1c8484848403611bce565b5b50505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1603611e92576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e8990613ab5565b60405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161480611f1857507f000000000000000000000000000000000000000000000000000000000000036973ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b1561203257611f26836124ae565b15611fa95780600760008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611f7a9190613647565b9250508190555080600c6000828254611f939190613647565b92505081905550611fa48382612541565b612023565b80600860003273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254611ff89190613647565b9250508190555080600b60008282546120119190613647565b925050819055506120223282612681565b5b61202d83826127c1565b6121b3565b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050818110156120b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120b090613b21565b60405180910390fd5b818103600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516121a99190612f21565b60405180910390a3505b505050565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612227576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161221e90613b8d565b60405180910390fd5b80601060008282546122399190613647565b9250508190555080600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040516122eb9190612f21565b60405180910390a35050565b6122ff611bc6565b73ffffffffffffffffffffffffffffffffffffffff1661231d610f66565b73ffffffffffffffffffffffffffffffffffffffff161461237c57612340611bc6565b6040517f118cdaa7000000000000000000000000000000000000000000000000000000008152600401612373919061306e565b60405180910390fd5b565b6000600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008082600001805490509050600081146124a3576124728360000160018361246d9190613613565b612909565b60000160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff166124a6565b60005b915050919050565b600080823b905060008111915050919050565b6000808360000180549050905060006124e0856000018560008561291e565b90506000811461253457612503856000016001836124fe9190613613565b612909565b60000160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16612537565b60005b9250505092915050565b6000600760008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600082826125939190613bad565b905060004390506125ed8183600a60008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206129919092919063ffffffff16565b5050600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055505050505050565b6000600860008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050600082826126d39190613bad565b9050600043905061272d8183600960008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206129919092919063ffffffff16565b5050600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190806001815401808255809150506001900390600052602060002090600891828204019190066004029091909190916101000a81548163ffffffff021916908363ffffffff1602179055505050505050565b6000600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905081811015612848576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161283f90613c49565b60405180910390fd5b818103600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555081601060008282540392505081905550600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516128fc9190612f21565b60405180910390a3505050565b60008260005281602060002001905092915050565b60005b8183101561298657600061293584846129ae565b90508463ffffffff166129488783612909565b60000160009054906101000a900463ffffffff1663ffffffff16111561297057809250612980565b60018161297d9190613647565b93505b50612921565b819050949350505050565b6000806129a28560000185856129d4565b91509150935093915050565b600060028284186129bf91906135e2565b8284166129cc9190613647565b905092915050565b6000806000858054905090506000811115612c61576000612a01876001846129fc9190613613565b612909565b6040518060400160405290816000820160009054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160049054906101000a90047bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152505090508563ffffffff16816000015163ffffffff161115612aec576040517f2520601d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8563ffffffff16816000015163ffffffff1603612b705784612b1a88600185612b159190613613565b612909565b60000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550612c50565b8660405180604001604052808863ffffffff168152602001877bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff16021790555050505b806020015185935093505050612d49565b8560405180604001604052808763ffffffff168152602001867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff168152509080600181540180825580915050600190039060005260206000200160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a8154817bffffffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837bffffffffffffffffffffffffffffffffffffffffffffffffffffffff160217905550505060008492509250505b935093915050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612d8b578082015181840152602081019050612d70565b60008484015250505050565b6000601f19601f8301169050919050565b6000612db382612d51565b612dbd8185612d5c565b9350612dcd818560208601612d6d565b612dd681612d97565b840191505092915050565b60006020820190508181036000830152612dfb8184612da8565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000612e3382612e08565b9050919050565b612e4381612e28565b8114612e4e57600080fd5b50565b600081359050612e6081612e3a565b92915050565b6000819050919050565b612e7981612e66565b8114612e8457600080fd5b50565b600081359050612e9681612e70565b92915050565b60008060408385031215612eb357612eb2612e03565b5b6000612ec185828601612e51565b9250506020612ed285828601612e87565b9150509250929050565b60008115159050919050565b612ef181612edc565b82525050565b6000602082019050612f0c6000830184612ee8565b92915050565b612f1b81612e66565b82525050565b6000602082019050612f366000830184612f12565b92915050565b600080600060608486031215612f5557612f54612e03565b5b6000612f6386828701612e51565b9350506020612f7486828701612e51565b9250506040612f8586828701612e87565b9150509250925092565b600060ff82169050919050565b612fa581612f8f565b82525050565b6000602082019050612fc06000830184612f9c565b92915050565b600060208284031215612fdc57612fdb612e03565b5b6000612fea84828501612e51565b91505092915050565b612ffc81612edc565b811461300757600080fd5b50565b60008135905061301981612ff3565b92915050565b6000806040838503121561303657613035612e03565b5b600061304485828601612e51565b92505060206130558582860161300a565b9150509250929050565b61306881612e28565b82525050565b6000602082019050613083600083018461305f565b92915050565b6000819050919050565b60006130ae6130a96130a484612e08565b613089565b612e08565b9050919050565b60006130c082613093565b9050919050565b60006130d2826130b5565b9050919050565b6130e2816130c7565b82525050565b60006020820190506130fd60008301846130d9565b92915050565b6000806040838503121561311a57613119612e03565b5b600061312885828601612e87565b925050602061313985828601612e87565b9150509250929050565b60007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff82169050919050565b61317481613143565b82525050565b600060208201905061318f600083018461316b565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b600063ffffffff82169050919050565b6131da816131c1565b82525050565b60006131ec83836131d1565b60208301905092915050565b6000602082019050919050565b600061321082613195565b61321a81856131a0565b9350613225836131b1565b8060005b8381101561325657815161323d88826131e0565b9750613248836131f8565b925050600181019050613229565b5085935050505092915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b61329881613143565b82525050565b60006132aa838361328f565b60208301905092915050565b6000602082019050919050565b60006132ce82613263565b6132d8818561326e565b93506132e38361327f565b8060005b838110156133145781516132fb888261329e565b9750613306836132b6565b9250506001810190506132e7565b5085935050505092915050565b6000604082019050818103600083015261333b8185613205565b9050818103602083015261334f81846132c3565b90509392505050565b6000806040838503121561336f5761336e612e03565b5b600061337d85828601612e51565b925050602061338e85828601612e51565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806133df57607f821691505b6020821081036133f2576133f1613398565b5b50919050565b7f5245454e5452414e435900000000000000000000000000000000000000000000600082015250565b600061342e600a83612d5c565b9150613439826133f8565b602082019050919050565b6000602082019050818103600083015261345d81613421565b9050919050565b600060a082019050613479600083018861305f565b613486602083018761305f565b613493604083018661305f565b6134a0606083018561305f565b6134ad6080830184612f12565b9695505050505050565b6000819050919050565b6134ca816134b7565b81146134d557600080fd5b50565b6000815190506134e7816134c1565b92915050565b6000815190506134fc81612e70565b92915050565b6000806040838503121561351957613518612e03565b5b6000613527858286016134d8565b9250506020613538858286016134ed565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061357c82612e66565b915061358783612e66565b925082820261359581612e66565b915082820484148315176135ac576135ab613542565b5b5092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006135ed82612e66565b91506135f883612e66565b925082613608576136076135b3565b5b828204905092915050565b600061361e82612e66565b915061362983612e66565b925082820390508181111561364157613640613542565b5b92915050565b600061365282612e66565b915061365d83612e66565b925082820190508082111561367557613674613542565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b600681106136bb576136ba61367b565b5b50565b60008190506136cc826136aa565b919050565b60006136dc826136be565b9050919050565b6136ec816136d1565b82525050565b6000604082019050613707600083018561305f565b61371460208301846136e3565b9392505050565b60008151905061372a81612ff3565b92915050565b60006020828403121561374657613745612e03565b5b60006137548482850161371b565b91505092915050565b7f4163636573732052657374726963746564000000000000000000000000000000600082015250565b6000613793601183612d5c565b915061379e8261375d565b602082019050919050565b600060208201905081810360008301526137c281613786565b9050919050565b7f44656372656173656420616c6c6f77616e63652062656c6f77207a65726f0000600082015250565b60006137ff601e83612d5c565b915061380a826137c9565b602082019050919050565b6000602082019050818103600083015261382e816137f2565b9050919050565b7f50726f76696465642061646472657373206973206e6f74206120636f6e74726160008201527f6374000000000000000000000000000000000000000000000000000000000000602082015250565b6000613891602283612d5c565b915061389c82613835565b604082019050919050565b600060208201905081810360008301526138c081613884565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f417070726f76652066726f6d207a65726f206164647265737300000000000000600082015250565b600061395b601983612d5c565b915061396682613925565b602082019050919050565b6000602082019050818103600083015261398a8161394e565b9050919050565b7f417070726f766520746f207a65726f2061646472657373000000000000000000600082015250565b60006139c7601783612d5c565b91506139d282613991565b602082019050919050565b600060208201905081810360008301526139f6816139ba565b9050919050565b7f496e73756666696369656e7420616c6c6f77616e636500000000000000000000600082015250565b6000613a33601683612d5c565b9150613a3e826139fd565b602082019050919050565b60006020820190508181036000830152613a6281613a26565b9050919050565b7f5472616e736665722066726f6d207a65726f2061646472657373000000000000600082015250565b6000613a9f601a83612d5c565b9150613aaa82613a69565b602082019050919050565b60006020820190508181036000830152613ace81613a92565b9050919050565b7f5472616e7366657220616d6f756e7420657863656564732062616c616e636500600082015250565b6000613b0b601f83612d5c565b9150613b1682613ad5565b602082019050919050565b60006020820190508181036000830152613b3a81613afe565b9050919050565b7f4d696e7420746f207a65726f2061646472657373000000000000000000000000600082015250565b6000613b77601483612d5c565b9150613b8282613b41565b602082019050919050565b60006020820190508181036000830152613ba681613b6a565b9050919050565b6000613bb882613143565b9150613bc383613143565b925082820190507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811115613bf757613bf6613542565b5b92915050565b7f4275726e20616d6f756e7420657863656564732062616c616e63650000000000600082015250565b6000613c33601b83612d5c565b9150613c3e82613bfd565b602082019050919050565b60006020820190508181036000830152613c6281613c26565b905091905056fea2646970667358221220bcd58db043af6115737612c62b8e91eefa677eb705676283a5c41e15bc77dfbb64736f6c634300081a0033