DiamondCollection
Deploy on AlchemyContract Information
This contract is a proxy and the implementation details are not yet known.
More Info
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {INiftyKitAppRegistry} from "../interfaces/INiftyKitAppRegistry.sol";
import {INiftyKitV3} from "../interfaces/INiftyKitV3.sol";
library BaseStorage {
enum Transfer {
AllowAll,
AllowedOperatorsOnly,
BlockAll
}
struct URIEntry {
bool isValue;
string tokenURI;
}
bytes32 private constant STORAGE_SLOT = keccak256("niftykit.base.storage");
uint256 public constant ADMIN_ROLE = 1 << 0;
uint256 public constant MANAGER_ROLE = 1 << 1;
uint256 public constant API_ROLE = 1 << 2;
struct Layout {
mapping(bytes32 => INiftyKitAppRegistry.App) _apps;
mapping(address => bool) _allowedOperators;
mapping(uint256 => bool) _blockedTokenIds;
mapping(uint256 => URIEntry) _tokenURIs;
bool _operatorFilteringEnabled;
Transfer _transferStatus;
INiftyKitV3 _niftyKit;
uint8 _baseVersion;
address _treasury;
string _baseURI;
}
function layout() internal pure returns (Layout storage ds) {
bytes32 position = STORAGE_SLOT;
// solhint-disable-next-line no-inline-assembly
assembly {
ds.slot := position
}
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {INiftyKitAppRegistry} from "../interfaces/INiftyKitAppRegistry.sol";
import {INiftyKitV3} from "../interfaces/INiftyKitV3.sol";
import {IDiamondCut} from "../interfaces/IDiamondCut.sol";
import {LibDiamond} from "../libraries/LibDiamond.sol";
import {BaseStorage} from "./BaseStorage.sol";
contract DiamondCollection {
constructor(
address owner,
address treasury,
address royalty,
uint16 royaltyBps,
string memory name,
string memory symbol,
bytes32[] memory apps
) {
BaseStorage.Layout storage layout = BaseStorage.layout();
layout._niftyKit = INiftyKitV3(msg.sender);
INiftyKitAppRegistry registry = INiftyKitAppRegistry(
layout._niftyKit.appRegistry()
);
INiftyKitAppRegistry.Base memory base = registry.getBase();
IDiamondCut.FacetCut[] memory facetCuts = new IDiamondCut.FacetCut[](
apps.length + 1
);
layout._treasury = treasury;
layout._baseVersion = base.version;
facetCuts = _appFacets(facetCuts, layout, registry, apps);
facetCuts = _baseFacet(facetCuts, base);
LibDiamond.diamondCut(
facetCuts,
base.implementation,
abi.encodeWithSignature(
"_initialize(address,string,string,address,uint16)",
owner,
name,
symbol,
royalty,
royaltyBps
)
);
}
function _appFacets(
IDiamondCut.FacetCut[] memory facetCuts,
BaseStorage.Layout storage layout,
INiftyKitAppRegistry registry,
bytes32[] memory apps
) internal returns (IDiamondCut.FacetCut[] memory) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
uint256 appsLength = apps.length;
for (uint256 i = 0; i < appsLength; ) {
INiftyKitAppRegistry.App memory app = registry.getApp(apps[i]);
if (app.version == 0) revert("App does not exist");
facetCuts[i] = IDiamondCut.FacetCut({
facetAddress: app.implementation,
action: IDiamondCut.FacetCutAction.Add,
functionSelectors: app.selectors
});
ds.supportedInterfaces[app.interfaceId] = true;
layout._apps[apps[i]] = app;
unchecked {
i++;
}
}
return facetCuts;
}
function _baseFacet(
IDiamondCut.FacetCut[] memory facetCuts,
INiftyKitAppRegistry.Base memory base
) internal returns (IDiamondCut.FacetCut[] memory) {
LibDiamond.DiamondStorage storage ds = LibDiamond.diamondStorage();
facetCuts[facetCuts.length - 1] = IDiamondCut.FacetCut({
facetAddress: base.implementation,
action: IDiamondCut.FacetCutAction.Add,
functionSelectors: base.selectors
});
uint256 idsLength = base.interfaceIds.length;
for (uint256 i = 0; i < idsLength; ) {
ds.supportedInterfaces[base.interfaceIds[i]] = true;
unchecked {
i++;
}
}
return facetCuts;
}
// Find facet for function that is called and execute the
// function if a facet is found and return any value.
fallback() external payable {
LibDiamond.DiamondStorage storage ds;
bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
// get diamond storage
assembly {
ds.slot := position
}
// get facet from function selector
address facet = address(bytes20(ds.facets[msg.sig]));
require(facet != address(0), "Diamond: Function does not exist");
// Execute external function from facet using delegatecall and return any value.
assembly {
// copy function selector and any arguments
calldatacopy(0, 0, calldatasize())
// execute function call using the facet
let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
// get any return value
returndatacopy(0, 0, returndatasize())
// return any return value or error back to the caller
switch result
case 0 {
revert(0, returndatasize())
}
default {
return(0, returndatasize())
}
}
}
receive() external payable {}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
interface IDiamondCut {
enum FacetCutAction {Add, Replace, Remove}
// Add=0, Replace=1, Remove=2
struct FacetCut {
address facetAddress;
FacetCutAction action;
bytes4[] functionSelectors;
}
/// @notice Add/replace/remove any number of functions and optionally execute
/// a function with delegatecall
/// @param _diamondCut Contains the facet addresses and function selectors
/// @param _init The address of the contract or facet to execute _calldata
/// @param _calldata A function call, including function selector and arguments
/// _calldata is executed with delegatecall on _init
function diamondCut(
FacetCut[] calldata _diamondCut,
address _init,
bytes calldata _calldata
) external;
event DiamondCut(FacetCut[] _diamondCut, address _init, bytes _calldata);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface INiftyKitAppRegistry {
struct App {
address implementation;
bytes4 interfaceId;
bytes4[] selectors;
uint8 version;
}
struct Base {
address implementation;
bytes4[] interfaceIds;
bytes4[] selectors;
uint8 version;
}
/**
* Get App Facet by app name
* @param name app name
*/
function getApp(bytes32 name) external view returns (App memory);
/**
* Get base Facet
*/
function getBase() external view returns (Base memory);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
interface INiftyKitV3 {
/**
* @dev Returns app registry address.
*/
function appRegistry() external returns (address);
/**
* @dev Returns the commission amount (sellerFee, buyerFee).
*/
function commission(
address collection,
uint256 amount
) external view returns (uint256, uint256);
/**
* @dev Get fees by amount (called from collection)
*/
function getFees(uint256 amount) external view returns (uint256, uint256);
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/******************************************************************************\
* Author: Nick Mudge <[email protected]> (https://twitter.com/mudgen)
* EIP-2535 Diamonds: https://eips.ethereum.org/EIPS/eip-2535
/******************************************************************************/
import { IDiamondCut } from "../interfaces/IDiamondCut.sol";
// Remember to add the loupe functions from DiamondLoupeFacet to the diamond.
// The loupe functions are required by the EIP2535 Diamonds standard
error InitializationFunctionReverted(address _initializationContractAddress, bytes _calldata);
library LibDiamond {
bytes32 constant DIAMOND_STORAGE_POSITION = keccak256("diamond.standard.diamond.storage");
struct DiamondStorage {
// maps function selectors to the facets that execute the functions.
// and maps the selectors to their position in the selectorSlots array.
// func selector => address facet, selector position
mapping(bytes4 => bytes32) facets;
// array of slots of function selectors.
// each slot holds 8 function selectors.
mapping(uint256 => bytes32) selectorSlots;
// The number of function selectors in selectorSlots
uint16 selectorCount;
// Used to query if a contract implements an interface.
// Used to implement ERC-165.
mapping(bytes4 => bool) supportedInterfaces;
// owner of the contract
address contractOwner;
}
function diamondStorage() internal pure returns (DiamondStorage storage ds) {
bytes32 position = DIAMOND_STORAGE_POSITION;
assembly {
ds.slot := position
}
}
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function setContractOwner(address _newOwner) internal {
DiamondStorage storage ds = diamondStorage();
address previousOwner = ds.contractOwner;
ds.contractOwner = _newOwner;
emit OwnershipTransferred(previousOwner, _newOwner);
}
function contractOwner() internal view returns (address contractOwner_) {
contractOwner_ = diamondStorage().contractOwner;
}
function enforceIsContractOwner() internal view {
require(msg.sender == diamondStorage().contractOwner, "LibDiamond: Must be contract owner");
}
event DiamondCut(IDiamondCut.FacetCut[] _diamondCut, address _init, bytes _calldata);
bytes32 constant CLEAR_ADDRESS_MASK = bytes32(uint256(0xffffffffffffffffffffffff));
bytes32 constant CLEAR_SELECTOR_MASK = bytes32(uint256(0xffffffff << 224));
// Internal function version of diamondCut
// This code is almost the same as the external diamondCut,
// except it is using 'Facet[] memory _diamondCut' instead of
// 'Facet[] calldata _diamondCut'.
// The code is duplicated to prevent copying calldata to memory which
// causes an error for a two dimensional array.
function diamondCut(
IDiamondCut.FacetCut[] memory _diamondCut,
address _init,
bytes memory _calldata
) internal {
DiamondStorage storage ds = diamondStorage();
uint256 originalSelectorCount = ds.selectorCount;
uint256 selectorCount = originalSelectorCount;
bytes32 selectorSlot;
// Check if last selector slot is not full
// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8"
if (selectorCount & 7 > 0) {
// get last selectorSlot
// "selectorSlot >> 3" is a gas efficient division by 8 "selectorSlot / 8"
selectorSlot = ds.selectorSlots[selectorCount >> 3];
}
// loop through diamond cut
for (uint256 facetIndex; facetIndex < _diamondCut.length; ) {
(selectorCount, selectorSlot) = addReplaceRemoveFacetSelectors(
selectorCount,
selectorSlot,
_diamondCut[facetIndex].facetAddress,
_diamondCut[facetIndex].action,
_diamondCut[facetIndex].functionSelectors
);
unchecked {
facetIndex++;
}
}
if (selectorCount != originalSelectorCount) {
ds.selectorCount = uint16(selectorCount);
}
// If last selector slot is not full
// "selectorCount & 7" is a gas efficient modulo by eight "selectorCount % 8"
if (selectorCount & 7 > 0) {
// "selectorSlot >> 3" is a gas efficient division by 8 "selectorSlot / 8"
ds.selectorSlots[selectorCount >> 3] = selectorSlot;
}
emit DiamondCut(_diamondCut, _init, _calldata);
initializeDiamondCut(_init, _calldata);
}
function addReplaceRemoveFacetSelectors(
uint256 _selectorCount,
bytes32 _selectorSlot,
address _newFacetAddress,
IDiamondCut.FacetCutAction _action,
bytes4[] memory _selectors
) internal returns (uint256, bytes32) {
DiamondStorage storage ds = diamondStorage();
require(_selectors.length > 0, "LibDiamondCut: No selectors in facet to cut");
if (_action == IDiamondCut.FacetCutAction.Add) {
enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Add facet has no code");
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
require(address(bytes20(oldFacet)) == address(0), "LibDiamondCut: Can't add function that already exists");
// add facet for selector
ds.facets[selector] = bytes20(_newFacetAddress) | bytes32(_selectorCount);
// "_selectorCount & 7" is a gas efficient modulo by eight "_selectorCount % 8"
// " << 5 is the same as multiplying by 32 ( * 32)
uint256 selectorInSlotPosition = (_selectorCount & 7) << 5;
// clear selector position in slot and add selector
_selectorSlot = (_selectorSlot & (CLEAR_SELECTOR_MASK >> selectorInSlotPosition)) | (bytes32(selector) >> selectorInSlotPosition);
// if slot is full then write it to storage
if (selectorInSlotPosition == 224) {
// "_selectorSlot >> 3" is a gas efficient division by 8 "_selectorSlot / 8"
ds.selectorSlots[_selectorCount >> 3] = _selectorSlot;
_selectorSlot = 0;
}
_selectorCount++;
unchecked {
selectorIndex++;
}
}
} else if (_action == IDiamondCut.FacetCutAction.Replace) {
enforceHasContractCode(_newFacetAddress, "LibDiamondCut: Replace facet has no code");
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
address oldFacetAddress = address(bytes20(oldFacet));
// only useful if immutable functions exist
require(oldFacetAddress != address(this), "LibDiamondCut: Can't replace immutable function");
require(oldFacetAddress != _newFacetAddress, "LibDiamondCut: Can't replace function with same function");
require(oldFacetAddress != address(0), "LibDiamondCut: Can't replace function that doesn't exist");
// replace old facet address
ds.facets[selector] = (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(_newFacetAddress);
unchecked {
selectorIndex++;
}
}
} else if (_action == IDiamondCut.FacetCutAction.Remove) {
require(_newFacetAddress == address(0), "LibDiamondCut: Remove facet address must be address(0)");
// "_selectorCount >> 3" is a gas efficient division by 8 "_selectorCount / 8"
uint256 selectorSlotCount = _selectorCount >> 3;
// "_selectorCount & 7" is a gas efficient modulo by eight "_selectorCount % 8"
uint256 selectorInSlotIndex = _selectorCount & 7;
for (uint256 selectorIndex; selectorIndex < _selectors.length; ) {
if (_selectorSlot == 0) {
// get last selectorSlot
selectorSlotCount--;
_selectorSlot = ds.selectorSlots[selectorSlotCount];
selectorInSlotIndex = 7;
} else {
selectorInSlotIndex--;
}
bytes4 lastSelector;
uint256 oldSelectorsSlotCount;
uint256 oldSelectorInSlotPosition;
// adding a block here prevents stack too deep error
{
bytes4 selector = _selectors[selectorIndex];
bytes32 oldFacet = ds.facets[selector];
require(address(bytes20(oldFacet)) != address(0), "LibDiamondCut: Can't remove function that doesn't exist");
// only useful if immutable functions exist
require(address(bytes20(oldFacet)) != address(this), "LibDiamondCut: Can't remove immutable function");
// replace selector with last selector in ds.facets
// gets the last selector
// " << 5 is the same as multiplying by 32 ( * 32)
lastSelector = bytes4(_selectorSlot << (selectorInSlotIndex << 5));
if (lastSelector != selector) {
// update last selector slot position info
ds.facets[lastSelector] = (oldFacet & CLEAR_ADDRESS_MASK) | bytes20(ds.facets[lastSelector]);
}
delete ds.facets[selector];
uint256 oldSelectorCount = uint16(uint256(oldFacet));
// "oldSelectorCount >> 3" is a gas efficient division by 8 "oldSelectorCount / 8"
oldSelectorsSlotCount = oldSelectorCount >> 3;
// "oldSelectorCount & 7" is a gas efficient modulo by eight "oldSelectorCount % 8"
// " << 5 is the same as multiplying by 32 ( * 32)
oldSelectorInSlotPosition = (oldSelectorCount & 7) << 5;
}
if (oldSelectorsSlotCount != selectorSlotCount) {
bytes32 oldSelectorSlot = ds.selectorSlots[oldSelectorsSlotCount];
// clears the selector we are deleting and puts the last selector in its place.
oldSelectorSlot =
(oldSelectorSlot & (CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
(bytes32(lastSelector) >> oldSelectorInSlotPosition);
// update storage with the modified slot
ds.selectorSlots[oldSelectorsSlotCount] = oldSelectorSlot;
} else {
// clears the selector we are deleting and puts the last selector in its place.
_selectorSlot =
(_selectorSlot & (CLEAR_SELECTOR_MASK >> oldSelectorInSlotPosition)) |
(bytes32(lastSelector) >> oldSelectorInSlotPosition);
}
if (selectorInSlotIndex == 0) {
delete ds.selectorSlots[selectorSlotCount];
_selectorSlot = 0;
}
unchecked {
selectorIndex++;
}
}
_selectorCount = selectorSlotCount * 8 + selectorInSlotIndex;
} else {
revert("LibDiamondCut: Incorrect FacetCutAction");
}
return (_selectorCount, _selectorSlot);
}
function initializeDiamondCut(address _init, bytes memory _calldata) internal {
if (_init == address(0)) {
return;
}
enforceHasContractCode(_init, "LibDiamondCut: _init address has no code");
(bool success, bytes memory error) = _init.delegatecall(_calldata);
if (!success) {
if (error.length > 0) {
// bubble up error
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(error)
revert(add(32, error), returndata_size)
}
} else {
revert InitializationFunctionReverted(_init, _calldata);
}
}
}
function enforceHasContractCode(address _contract, string memory _errorMessage) internal view {
uint256 contractSize;
assembly {
contractSize := extcodesize(_contract)
}
require(contractSize > 0, _errorMessage);
}
}
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"royalty","type":"address"},{"internalType":"uint16","name":"royaltyBps","type":"uint16"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"bytes32[]","name":"apps","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_initializationContractAddress","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"InitializationFunctionReverted","type":"error"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"treasury","type":"address"},{"internalType":"address","name":"royalty","type":"address"},{"internalType":"uint16","name":"royaltyBps","type":"uint16"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"bytes32[]","name":"apps","type":"bytes32[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"_initializationContractAddress","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"InitializationFunctionReverted","type":"error"},{"stateMutability":"payable","type":"fallback"},{"stateMutability":"payable","type":"receive"}]
608060405234801561001057600080fd5b506040516118ea3803806118ea83398101604081905261002f9161120d565b7f45f38af8fd646bf817698fe2be76218d850d401ba88ffd7c9cd1b4f5c9a1db5a805462010000600160b01b031916336201000090810291909117918290556040805163bb4fceb960e01b815290517f45f38af8fd646bf817698fe2be76218d850d401ba88ffd7c9cd1b4f5c9a1db56936000936001600160a01b039104169163bb4fceb9916004828101926020929190829003018187875af11580156100da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fe91906112e1565b90506000816001600160a01b031663d104a1366040518163ffffffff1660e01b8152600401600060405180830381865afa158015610140573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610168919081019061138e565b905060008451600161017a9190611456565b6001600160401b0381111561019157610191611082565b6040519080825280602002602001820160405280156101de57816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816101af5790505b506005850180546001600160a01b0319166001600160a01b038d16179055606083015160048601805460ff60b01b1916600160b01b60ff909316929092029190911790559050610230818585886102a3565b905061023c81836104ca565b90506102938183600001518d8a8a8e8e604051602401610260959493929190611495565b60408051601f198184030181529190526020810180516001600160e01b039081166375a2840360e01b179091526105ab16565b5050505050505050505050611734565b80516060906000805160206118568339815191529060005b818110156104be576000866001600160a01b03166342c71f1d8784815181106102e6576102e66114e8565b60200260200101516040518263ffffffff1660e01b815260040161030c91815260200190565b600060405180830381865afa158015610329573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261035191908101906114fe565b9050806060015160ff166000036103a45760405162461bcd60e51b8152602060048201526012602482015271105c1c08191bd95cc81b9bdd08195e1a5cdd60721b60448201526064015b60405180910390fd5b604080516060810190915281516001600160a01b03168152602081016000815260200182604001518152508983815181106103e1576103e16114e8565b602090810291909101810191909152818101516001600160e01b03191660009081526003860190915260408120805460ff19166001179055865182918a91899086908110610431576104316114e8565b6020908102919091018101518252818101929092526040908101600020835181548585015160e01c600160a01b026001600160c01b03199091166001600160a01b0390921691909117178155908301518051919261049792600185019290910190610fa5565b50606091909101516002909101805460ff191660ff909216919091179055506001016102bb565b50959695505050505050565b604080516060818101835283516001600160a01b0316825260006020830152838301519282019290925283516000805160206118568339815191529190859061051590600190611587565b81518110610525576105256114e8565b60200260200101819052506000836020015151905060005b8181101561059e57600183600301600087602001518481518110610563576105636114e8565b6020908102919091018101516001600160e01b0319168252810191909152604001600020805460ff191691151591909117905560010161053d565b5084925050505b92915050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131e546000805160206118568339815191529061ffff8116908190600090600716156106085750600381901c60009081526001840160205260409020545b60005b875181101561068b5761067e83838a848151811061062b5761062b6114e8565b6020026020010151600001518b8581518110610649576106496114e8565b6020026020010151602001518c8681518110610667576106676114e8565b60200260200101516040015161071760201b60201c565b909350915060010161060b565b508282146106a75760028401805461ffff191661ffff84161790555b60078216156106c957600382901c600090815260018501602052604090208190555b7f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738787876040516106fc9392919061159a565b60405180910390a161070e8686610eb8565b50505050505050565b60008080600080516020611856833981519152905060008451116107915760405162461bcd60e51b815260206004820152602b60248201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161039b565b60008560028111156107a5576107a5611571565b03610913576107cc8660405180606001604052806024815260200161187660249139610f84565b60005b845181101561090d5760008582815181106107ec576107ec6114e8565b6020908102919091018101516001600160e01b03198116600090815291859052604090912054909150606081901c1561088d5760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c7265616479206578697374730000000000000000000000606482015260840161039b565b6001600160e01b031980831660008181526020879052604090206001600160601b031960608d901b168e17905560e060058e901b811692831c199c909c1690821c179a8190036108f15760038c901c600090815260018601602052604081209b909b555b8b6108fb8161169a565b9c5050600190930192506107cf915050565b50610eac565b600185600281111561092757610927611571565b03610b235761094e866040518060600160405280602881526020016118c260289139610f84565b60005b845181101561090d57600085828151811061096e5761096e6114e8565b6020908102919091018101516001600160e01b03198116600090815291859052604090912054909150606081901c308103610a035760405162461bcd60e51b815260206004820152602f60248201527f4c69624469616d6f6e644375743a2043616e2774207265706c61636520696d6d60448201526e3aba30b1363290333ab731ba34b7b760891b606482015260840161039b565b896001600160a01b0316816001600160a01b031603610a785760405162461bcd60e51b8152602060048201526038602482015260008051602061183683398151915260448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161039b565b6001600160a01b038116610ae25760405162461bcd60e51b8152602060048201526038602482015260008051602061183683398151915260448201527f6374696f6e207468617420646f65736e27742065786973740000000000000000606482015260840161039b565b506001600160e01b031990911660009081526020849052604090206001600160601b03919091166001600160601b031960608a901b16179055600101610951565b6002856002811115610b3757610b37611571565b03610e54576001600160a01b03861615610bb95760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d757374206265206164647265737328302900000000000000000000606482015260840161039b565b600388901c6007891660005b8651811015610e345760008a9003610c015782610be1816116b3565b60008181526001870160205260409020549b50935060079250610c0f9050565b81610c0b816116b3565b9250505b6000806000808a8581518110610c2757610c276114e8565b6020908102919091018101516001600160e01b031981166000908152918a9052604090912054909150606081901c610cc75760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161039b565b30606082901c03610d315760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161039b565b600587901b8f901b94506001600160e01b031980861690831614610d82576001600160e01b03198516600090815260208a90526040902080546001600160601b0319166001600160601b0383161790555b6001600160e01b031991909116600090815260208990526040812055600381901c611fff16925060051b60e0169050858214610de7576000828152600188016020526040902080546001600160e01b031980841c19909116908516831c179055610e0b565b80836001600160e01b031916901c816001600160e01b031960001b901c198e16179c505b84600003610e2957600086815260018801602052604081208190559c505b505050600101610bc5565b5080610e418360086116ca565b610e4b9190611456565b99505050610eac565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b606482015260840161039b565b50959694955050505050565b6001600160a01b038216610eca575050565b610eec8260405180606001604052806028815260200161189a60289139610f84565b600080836001600160a01b031683604051610f0791906116e1565b600060405180830381855af49150503d8060008114610f42576040519150601f19603f3d011682016040523d82523d6000602084013e610f47565b606091505b509150915081610f7e57805115610f615780518082602001fd5b838360405163192105d760e01b815260040161039b9291906116fd565b50505050565b813b8181610f7e5760405162461bcd60e51b815260040161039b9190611721565b828054828255906000526020600020906007016008900481019282156110415791602002820160005b8382111561100f57835183826101000a81548163ffffffff021916908360e01c02179055509260200192600401602081600301049283019260010302610fce565b801561103f5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261100f565b505b5061104d929150611051565b5090565b5b8082111561104d5760008155600101611052565b80516001600160a01b038116811461107d57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156110ba576110ba611082565b60405290565b604051601f8201601f191681016001600160401b03811182821017156110e8576110e8611082565b604052919050565b60005b8381101561110b5781810151838201526020016110f3565b50506000910152565b600082601f83011261112557600080fd5b81516001600160401b0381111561113e5761113e611082565b611151601f8201601f19166020016110c0565b81815284602083860101111561116657600080fd5b6111778260208301602087016110f0565b949350505050565b60006001600160401b0382111561119857611198611082565b5060051b60200190565b600082601f8301126111b357600080fd5b815160206111c86111c38361117f565b6110c0565b82815260059290921b840181019181810190868411156111e757600080fd5b8286015b8481101561120257805183529183019183016111eb565b509695505050505050565b600080600080600080600060e0888a03121561122857600080fd5b61123188611066565b965061123f60208901611066565b955061124d60408901611066565b9450606088015161ffff8116811461126457600080fd5b60808901519094506001600160401b038082111561128157600080fd5b61128d8b838c01611114565b945060a08a01519150808211156112a357600080fd5b6112af8b838c01611114565b935060c08a01519150808211156112c557600080fd5b506112d28a828b016111a2565b91505092959891949750929550565b6000602082840312156112f357600080fd5b6112fc82611066565b9392505050565b80516001600160e01b03198116811461107d57600080fd5b600082601f83011261132c57600080fd5b8151602061133c6111c38361117f565b82815260059290921b8401810191818101908684111561135b57600080fd5b8286015b848110156112025761137081611303565b835291830191830161135f565b805160ff8116811461107d57600080fd5b6000602082840312156113a057600080fd5b81516001600160401b03808211156113b757600080fd5b90830190608082860312156113cb57600080fd5b6113d3611098565b6113dc83611066565b81526020830151828111156113f057600080fd5b6113fc8782860161131b565b60208301525060408301518281111561141457600080fd5b6114208782860161131b565b6040830152506114326060840161137d565b606082015295945050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105a5576105a5611440565b600081518084526114818160208601602086016110f0565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a060208401526114b760a0840188611469565b83810360408501526114c98188611469565b959091166060840152505061ffff919091166080909101529392505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561151057600080fd5b81516001600160401b038082111561152757600080fd5b908301906080828603121561153b57600080fd5b611543611098565b61154c83611066565b815261155a60208401611303565b602082015260408301518281111561141457600080fd5b634e487b7160e01b600052602160045260246000fd5b818103818111156105a5576105a5611440565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561166a57898403607f19018652815180516001600160a01b0316855283810151898601906003811061160957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156116555783516001600160e01b031916825292860192600192909201919086019061162b565b509785019795505050908201906001016115c3565b50506001600160a01b038a1690880152868103604088015261168c8189611469565b9a9950505050505050505050565b6000600182016116ac576116ac611440565b5060010190565b6000816116c2576116c2611440565b506000190190565b80820281158282048414176105a5576105a5611440565b600082516116f38184602087016110f0565b9190910192915050565b6001600160a01b038316815260406020820181905260009061117790830184611469565b6020815260006112fc6020830184611469565b60f4806117426000396000f3fe608060405236600a57005b600080356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6020819052604090912054819060601c80609b5760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f74206578697374604482015260640160405180910390fd5b3660008037600080366000845af43d6000803e80801560b9573d6000f35b3d6000fdfea26469706673582212206d25102b4d75f611f80bca95f71de85c40d00ec95bee8807fc20e6d745f0f01464736f6c634300081300334c69624469616d6f6e644375743a2043616e2774207265706c6163652066756ec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a2041646420666163657420686173206e6f20636f64654c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a205265706c61636520666163657420686173206e6f20636f646500000000000000000000000031f3e61407ab33ecf0df1f3d1ef3383cd500722e0000000000000000000000002f9cb9d1b5ba7c26c96df479ceae12198a84fdaa0000000000000000000000002f9cb9d1b5ba7c26c96df479ceae12198a84fdaa000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000074e4b20546573740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e4b54000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016f297c61b5c92ef107ffd30cd56affe5a273e841d202d87dff9baf0090116b99
608060405234801561001057600080fd5b506040516118ea3803806118ea83398101604081905261002f9161120d565b7f45f38af8fd646bf817698fe2be76218d850d401ba88ffd7c9cd1b4f5c9a1db5a805462010000600160b01b031916336201000090810291909117918290556040805163bb4fceb960e01b815290517f45f38af8fd646bf817698fe2be76218d850d401ba88ffd7c9cd1b4f5c9a1db56936000936001600160a01b039104169163bb4fceb9916004828101926020929190829003018187875af11580156100da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100fe91906112e1565b90506000816001600160a01b031663d104a1366040518163ffffffff1660e01b8152600401600060405180830381865afa158015610140573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610168919081019061138e565b905060008451600161017a9190611456565b6001600160401b0381111561019157610191611082565b6040519080825280602002602001820160405280156101de57816020015b604080516060808201835260008083526020830152918101919091528152602001906001900390816101af5790505b506005850180546001600160a01b0319166001600160a01b038d16179055606083015160048601805460ff60b01b1916600160b01b60ff909316929092029190911790559050610230818585886102a3565b905061023c81836104ca565b90506102938183600001518d8a8a8e8e604051602401610260959493929190611495565b60408051601f198184030181529190526020810180516001600160e01b039081166375a2840360e01b179091526105ab16565b5050505050505050505050611734565b80516060906000805160206118568339815191529060005b818110156104be576000866001600160a01b03166342c71f1d8784815181106102e6576102e66114e8565b60200260200101516040518263ffffffff1660e01b815260040161030c91815260200190565b600060405180830381865afa158015610329573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261035191908101906114fe565b9050806060015160ff166000036103a45760405162461bcd60e51b8152602060048201526012602482015271105c1c08191bd95cc81b9bdd08195e1a5cdd60721b60448201526064015b60405180910390fd5b604080516060810190915281516001600160a01b03168152602081016000815260200182604001518152508983815181106103e1576103e16114e8565b602090810291909101810191909152818101516001600160e01b03191660009081526003860190915260408120805460ff19166001179055865182918a91899086908110610431576104316114e8565b6020908102919091018101518252818101929092526040908101600020835181548585015160e01c600160a01b026001600160c01b03199091166001600160a01b0390921691909117178155908301518051919261049792600185019290910190610fa5565b50606091909101516002909101805460ff191660ff909216919091179055506001016102bb565b50959695505050505050565b604080516060818101835283516001600160a01b0316825260006020830152838301519282019290925283516000805160206118568339815191529190859061051590600190611587565b81518110610525576105256114e8565b60200260200101819052506000836020015151905060005b8181101561059e57600183600301600087602001518481518110610563576105636114e8565b6020908102919091018101516001600160e01b0319168252810191909152604001600020805460ff191691151591909117905560010161053d565b5084925050505b92915050565b7fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131e546000805160206118568339815191529061ffff8116908190600090600716156106085750600381901c60009081526001840160205260409020545b60005b875181101561068b5761067e83838a848151811061062b5761062b6114e8565b6020026020010151600001518b8581518110610649576106496114e8565b6020026020010151602001518c8681518110610667576106676114e8565b60200260200101516040015161071760201b60201c565b909350915060010161060b565b508282146106a75760028401805461ffff191661ffff84161790555b60078216156106c957600382901c600090815260018501602052604090208190555b7f8faa70878671ccd212d20771b795c50af8fd3ff6cf27f4bde57e5d4de0aeb6738787876040516106fc9392919061159a565b60405180910390a161070e8686610eb8565b50505050505050565b60008080600080516020611856833981519152905060008451116107915760405162461bcd60e51b815260206004820152602b60248201527f4c69624469616d6f6e644375743a204e6f2073656c6563746f727320696e206660448201526a1858d95d081d1bc818dd5d60aa1b606482015260840161039b565b60008560028111156107a5576107a5611571565b03610913576107cc8660405180606001604052806024815260200161187660249139610f84565b60005b845181101561090d5760008582815181106107ec576107ec6114e8565b6020908102919091018101516001600160e01b03198116600090815291859052604090912054909150606081901c1561088d5760405162461bcd60e51b815260206004820152603560248201527f4c69624469616d6f6e644375743a2043616e2774206164642066756e6374696f60448201527f6e207468617420616c7265616479206578697374730000000000000000000000606482015260840161039b565b6001600160e01b031980831660008181526020879052604090206001600160601b031960608d901b168e17905560e060058e901b811692831c199c909c1690821c179a8190036108f15760038c901c600090815260018601602052604081209b909b555b8b6108fb8161169a565b9c5050600190930192506107cf915050565b50610eac565b600185600281111561092757610927611571565b03610b235761094e866040518060600160405280602881526020016118c260289139610f84565b60005b845181101561090d57600085828151811061096e5761096e6114e8565b6020908102919091018101516001600160e01b03198116600090815291859052604090912054909150606081901c308103610a035760405162461bcd60e51b815260206004820152602f60248201527f4c69624469616d6f6e644375743a2043616e2774207265706c61636520696d6d60448201526e3aba30b1363290333ab731ba34b7b760891b606482015260840161039b565b896001600160a01b0316816001600160a01b031603610a785760405162461bcd60e51b8152602060048201526038602482015260008051602061183683398151915260448201527f6374696f6e20776974682073616d652066756e6374696f6e0000000000000000606482015260840161039b565b6001600160a01b038116610ae25760405162461bcd60e51b8152602060048201526038602482015260008051602061183683398151915260448201527f6374696f6e207468617420646f65736e27742065786973740000000000000000606482015260840161039b565b506001600160e01b031990911660009081526020849052604090206001600160601b03919091166001600160601b031960608a901b16179055600101610951565b6002856002811115610b3757610b37611571565b03610e54576001600160a01b03861615610bb95760405162461bcd60e51b815260206004820152603660248201527f4c69624469616d6f6e644375743a2052656d6f7665206661636574206164647260448201527f657373206d757374206265206164647265737328302900000000000000000000606482015260840161039b565b600388901c6007891660005b8651811015610e345760008a9003610c015782610be1816116b3565b60008181526001870160205260409020549b50935060079250610c0f9050565b81610c0b816116b3565b9250505b6000806000808a8581518110610c2757610c276114e8565b6020908102919091018101516001600160e01b031981166000908152918a9052604090912054909150606081901c610cc75760405162461bcd60e51b815260206004820152603760248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f76652066756e6360448201527f74696f6e207468617420646f65736e2774206578697374000000000000000000606482015260840161039b565b30606082901c03610d315760405162461bcd60e51b815260206004820152602e60248201527f4c69624469616d6f6e644375743a2043616e27742072656d6f766520696d6d7560448201526d3a30b1363290333ab731ba34b7b760911b606482015260840161039b565b600587901b8f901b94506001600160e01b031980861690831614610d82576001600160e01b03198516600090815260208a90526040902080546001600160601b0319166001600160601b0383161790555b6001600160e01b031991909116600090815260208990526040812055600381901c611fff16925060051b60e0169050858214610de7576000828152600188016020526040902080546001600160e01b031980841c19909116908516831c179055610e0b565b80836001600160e01b031916901c816001600160e01b031960001b901c198e16179c505b84600003610e2957600086815260018801602052604081208190559c505b505050600101610bc5565b5080610e418360086116ca565b610e4b9190611456565b99505050610eac565b60405162461bcd60e51b815260206004820152602760248201527f4c69624469616d6f6e644375743a20496e636f727265637420466163657443756044820152663a20b1ba34b7b760c91b606482015260840161039b565b50959694955050505050565b6001600160a01b038216610eca575050565b610eec8260405180606001604052806028815260200161189a60289139610f84565b600080836001600160a01b031683604051610f0791906116e1565b600060405180830381855af49150503d8060008114610f42576040519150601f19603f3d011682016040523d82523d6000602084013e610f47565b606091505b509150915081610f7e57805115610f615780518082602001fd5b838360405163192105d760e01b815260040161039b9291906116fd565b50505050565b813b8181610f7e5760405162461bcd60e51b815260040161039b9190611721565b828054828255906000526020600020906007016008900481019282156110415791602002820160005b8382111561100f57835183826101000a81548163ffffffff021916908360e01c02179055509260200192600401602081600301049283019260010302610fce565b801561103f5782816101000a81549063ffffffff021916905560040160208160030104928301926001030261100f565b505b5061104d929150611051565b5090565b5b8082111561104d5760008155600101611052565b80516001600160a01b038116811461107d57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604051608081016001600160401b03811182821017156110ba576110ba611082565b60405290565b604051601f8201601f191681016001600160401b03811182821017156110e8576110e8611082565b604052919050565b60005b8381101561110b5781810151838201526020016110f3565b50506000910152565b600082601f83011261112557600080fd5b81516001600160401b0381111561113e5761113e611082565b611151601f8201601f19166020016110c0565b81815284602083860101111561116657600080fd5b6111778260208301602087016110f0565b949350505050565b60006001600160401b0382111561119857611198611082565b5060051b60200190565b600082601f8301126111b357600080fd5b815160206111c86111c38361117f565b6110c0565b82815260059290921b840181019181810190868411156111e757600080fd5b8286015b8481101561120257805183529183019183016111eb565b509695505050505050565b600080600080600080600060e0888a03121561122857600080fd5b61123188611066565b965061123f60208901611066565b955061124d60408901611066565b9450606088015161ffff8116811461126457600080fd5b60808901519094506001600160401b038082111561128157600080fd5b61128d8b838c01611114565b945060a08a01519150808211156112a357600080fd5b6112af8b838c01611114565b935060c08a01519150808211156112c557600080fd5b506112d28a828b016111a2565b91505092959891949750929550565b6000602082840312156112f357600080fd5b6112fc82611066565b9392505050565b80516001600160e01b03198116811461107d57600080fd5b600082601f83011261132c57600080fd5b8151602061133c6111c38361117f565b82815260059290921b8401810191818101908684111561135b57600080fd5b8286015b848110156112025761137081611303565b835291830191830161135f565b805160ff8116811461107d57600080fd5b6000602082840312156113a057600080fd5b81516001600160401b03808211156113b757600080fd5b90830190608082860312156113cb57600080fd5b6113d3611098565b6113dc83611066565b81526020830151828111156113f057600080fd5b6113fc8782860161131b565b60208301525060408301518281111561141457600080fd5b6114208782860161131b565b6040830152506114326060840161137d565b606082015295945050505050565b634e487b7160e01b600052601160045260246000fd5b808201808211156105a5576105a5611440565b600081518084526114818160208601602086016110f0565b601f01601f19169290920160200192915050565b600060018060a01b03808816835260a060208401526114b760a0840188611469565b83810360408501526114c98188611469565b959091166060840152505061ffff919091166080909101529392505050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561151057600080fd5b81516001600160401b038082111561152757600080fd5b908301906080828603121561153b57600080fd5b611543611098565b61154c83611066565b815261155a60208401611303565b602082015260408301518281111561141457600080fd5b634e487b7160e01b600052602160045260246000fd5b818103818111156105a5576105a5611440565b60006060808301818452808751808352608092508286019150828160051b8701016020808b0160005b8481101561166a57898403607f19018652815180516001600160a01b0316855283810151898601906003811061160957634e487b7160e01b600052602160045260246000fd5b868601526040918201519186018a905281519081905290840190600090898701905b808310156116555783516001600160e01b031916825292860192600192909201919086019061162b565b509785019795505050908201906001016115c3565b50506001600160a01b038a1690880152868103604088015261168c8189611469565b9a9950505050505050505050565b6000600182016116ac576116ac611440565b5060010190565b6000816116c2576116c2611440565b506000190190565b80820281158282048414176105a5576105a5611440565b600082516116f38184602087016110f0565b9190910192915050565b6001600160a01b038316815260406020820181905260009061117790830184611469565b6020815260006112fc6020830184611469565b60f4806117426000396000f3fe608060405236600a57005b600080356001600160e01b03191681527fc8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c6020819052604090912054819060601c80609b5760405162461bcd60e51b815260206004820181905260248201527f4469616d6f6e643a2046756e6374696f6e20646f6573206e6f74206578697374604482015260640160405180910390fd5b3660008037600080366000845af43d6000803e80801560b9573d6000f35b3d6000fdfea26469706673582212206d25102b4d75f611f80bca95f71de85c40d00ec95bee8807fc20e6d745f0f01464736f6c634300081300334c69624469616d6f6e644375743a2043616e2774207265706c6163652066756ec8fcad8db84d3cc18b4c41d551ea0ee66dd599cde068d998e57d5e09332c131c4c69624469616d6f6e644375743a2041646420666163657420686173206e6f20636f64654c69624469616d6f6e644375743a205f696e6974206164647265737320686173206e6f20636f64654c69624469616d6f6e644375743a205265706c61636520666163657420686173206e6f20636f646500000000000000000000000031f3e61407ab33ecf0df1f3d1ef3383cd500722e0000000000000000000000002f9cb9d1b5ba7c26c96df479ceae12198a84fdaa0000000000000000000000002f9cb9d1b5ba7c26c96df479ceae12198a84fdaa000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000074e4b20546573740000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034e4b54000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016f297c61b5c92ef107ffd30cd56affe5a273e841d202d87dff9baf0090116b99