Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
PremierAccessERC1155
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 4294967295 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity 0.8.28;
/*
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@ @@@@@@@@@@
@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@@@@
@@! @@@ @@! @@@ @@! @@! @@@ @@! @@! @@!
!@! @!@ !@! @!@ !@! !@! @!@ !@! !@! !@!
@!@ !@! @!@!!@! @!!!:! @!@!@!@! @!! !!@ @!@
!@! !!! !!@!@! !!!!!: !!!@!!!! !@! ! !@!
!!: !!! !!: :!! !!: !!: !!! !!: !!: by no_side666
:!: !:! :!: !:! :!: :!: !:! :!: :!:
:::: :: :: ::: :: :::: :: ::: ::: :: dreamstack.xyz
:: : : : : : : :: :: : : : : :
@@@@@@ @@@@@@@ @@@@@@ @@@@@@@ @@@ @@@ @@@ @@@ @@@@@@
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@@ @@@ @@@ @@@ @@@ @@@@@@@@
!@@ @@! @@! @@@ !@@ @@! !@@ @@! @@@ @@@
!@! !@! !@! @!@ !@! !@! @!! !@! @!@ @!@
!!@@!! @!! @!@!@!@! !@! @!@@!@! @!@ !@! !!@
!!@!!! !!! !!!@!!!! !!! !!@!!! !@! !!! !!:
!:! !!: !!: !!! :!! !!: :!! :!: !!: !:!
!:! :!: :!: !:! :!: :!: !:! ::!!:! :!:
:::: :: :: :: ::: ::: ::: :: ::: :::: :: :::::
:: : : : : : : :: :: : : ::: : :: : :::
**/
import "lib/solady/src/utils/SafeTransferLib.sol";
import "./modded/creator-token-standards/ERC1155C.sol";
import "./modded/creator-token-standards/BasicRoyalties.sol";
import "./Refunds.sol";
import "./Interfaces.sol";
import "./Errors.sol";
import "./LICENSE.sol";
contract PremierAccessERC1155 is ERC1155C, IPremierAccessERC1155, BasicRoyalties, Refunds {
IHub immutable hub;
uint256 public maxExclusivityWindow = 52 weeks; // 1 year
uint256 public extendExclusivityPricePerWeek = 0.005 ether;
uint256 public constant ONE = 1 ether;
uint256 public feePercentage = 5 * ONE / 100;
mapping(uint256 => ExclusivityData) private _exclusivityData;
mapping(uint256 => Supply) private _supplies;
event NewExclusiveToken(uint256 curationTokenId);
event MaxExclusivityWindowUpdated(uint256 newMaxExclusivityWindow);
event ExclusivityWindowUpdated(uint256 curationTokenId, uint256 newExclusivityWindow);
event ExtendExclusivityPriceUpdated(uint256 newExtenExclusivityPrice);
event PremiumAccessPriceUpdated(uint256 curationTokenId, uint256 newPrice);
event PremiumAccessMaxUpdated(uint256 curationTokenId, uint256 newMax);
event MetadataUpdate(uint256 _tokenId);
constructor(IHub hub_, IRefunder refunder_)
BasicRoyalties(hub_.ownerOf(hub_.HUB_OWNER_TOKENID()), uint96(hub_.hubRoyalty()))
{
hub = hub_;
refunder = refunder_;
}
function supply(uint256 curationTokenId) external view returns (Supply memory) {
return _supplies[curationTokenId];
}
function mint(uint256 curationTokenId, uint256 qty, address to) external payable {
mintTo(curationTokenId, qty, to, bytes(""));
}
function mintToDream(uint256 curationTokenId, uint256 qty, uint256 dreamId) external payable {
mintTo(curationTokenId, qty, address(hub.dreams()), abi.encode(dreamId));
}
function mintTo(uint256 curationTokenId, uint256 qty, address to, bytes memory data) public payable {
ExclusivityData memory ed = _exclusivityData[curationTokenId];
// can't mint if after exclusivity period
// this check also prevents malicious attempt to mint from curationTokensId's that haven't had exclusivity set
if (!(block.timestamp < ed.exclusivityWindow)) revert MustRespectExclusivity_error();
Supply memory supply_ = _supplies[curationTokenId];
// forge-lint: disable-start(unsafe-typecast)
if (qty + uint256(supply_.totalMinted) > ed.premiumAccessMax) revert ExceedsMaxSupply_error();
supply_.totalMinted += uint128(qty);
supply_.totalSupply += uint128(qty);
_supplies[curationTokenId] = supply_;
// forge-lint: disable-end(unsafe-typecast)
if (msg.sender != hub.ownerOf(curationTokenId)) {
// will throw if curationTokenId was burned
uint256 cost = qty * ed.premiumAccessPrice;
if (msg.value < cost) revert InsufficientValue_error(cost);
uint256 excess = msg.value - cost;
if (excess > 0) {
_setRefund(msg.sender, excess);
}
uint256 fee = feePercentage * cost / ONE;
Type t = hub.immortalizer().immortalizedType(curationTokenId);
if (cost > fee) {
if (Type.NONE < t && t < Type.COLLECTION) {
IPaymentFilterer pf = hub.paymentFilterer();
unchecked {
if (pf.payeesLength(curationTokenId) < 1) {
// strict tab
(, address target) = hub.beneficiariesOf(curationTokenId);
if (target != address(hub)) _setRefund(target, cost - fee);
} else {
// texture tab or frame
pf.receivePayment{value: cost - fee}(curationTokenId);
}
} // uc
} else {
revert InvalidInput_error();
}
}
if (address(this).balance > 0) {
(bool success,) = address(hub).call{value: address(this).balance}(""); // fee and dust
if (!success) revert FailedCall_error();
}
}
_mint(to, curationTokenId, qty, data);
}
function updatePremiumAccessPrice(uint256 curationTokenId, uint256 newPrice) external {
if (newPrice > type(uint112).max) revert InvalidInput_error();
_requireCallerIsTokenOwner(curationTokenId); // will throw if curationTokenId was burned
ExclusivityData memory ed = _exclusivityData[curationTokenId];
// forge-lint: disable-next-line(unsafe-typecast)
ed.premiumAccessPrice = uint112(newPrice);
_exclusivityData[curationTokenId] = ed;
emit PremiumAccessPriceUpdated(curationTokenId, newPrice);
emit MetadataUpdate(curationTokenId);
}
function updatePremiumAccessMax(uint256 curationTokenId, uint256 newMax) external {
_requireCallerIsTokenOwner(curationTokenId); // will throw if curationTokenId was burned
ExclusivityData memory ed = _exclusivityData[curationTokenId];
if (!(newMax < ed.premiumAccessMax)) revert InvalidInput_error(); // only want descending max lol
// forge-lint: disable-next-line(unsafe-typecast)
ed.premiumAccessMax = uint112(newMax);
_exclusivityData[curationTokenId] = ed;
emit PremiumAccessMaxUpdated(curationTokenId, newMax);
emit MetadataUpdate(curationTokenId);
}
// anyone can extend
function extendExclusivityPeriod(uint256 curationTokenId, uint256 nMoreWeeks) external payable {
hub.ownerOf(curationTokenId); // throws if dne
ExclusivityData memory ed = _exclusivityData[curationTokenId];
if (!(block.timestamp < ed.exclusivityWindow)) revert ExclusivityLapsed_error();
uint256 maxWeeks = maxExclusivityWindow / 1 weeks;
if (nMoreWeeks > maxWeeks) revert MustRespectExclusivity_error();
uint256 cost = nMoreWeeks * extendExclusivityPricePerWeek;
if (msg.value != cost) revert InsufficientValue_error(cost);
// forge-lint: disable-next-line(unsafe-typecast)
ed.exclusivityWindow += uint64(nMoreWeeks * 1 weeks);
_exclusivityData[curationTokenId] = ed;
ICrews crews = hub.crews();
IERC721 crew = crews.claimsCrew(hub.originator(curationTokenId));
if (crews.isApprovedCrew(crew)) {
SafeTransferLib.forceSafeTransferETH(crews.crewTreasury(crew), cost / 2);
}
(bool success,) = address(hub).call{value: address(this).balance}(""); // fee and dust
if (!success) revert FailedCall_error();
emit ExclusivityWindowUpdated(curationTokenId, ed.exclusivityWindow);
}
function burn(uint256 curationTokenId, uint256 qty) external {
Supply memory supply_ = _supplies[curationTokenId];
// forge-lint: disable-next-line(unsafe-typecast)
supply_.totalSupply -= uint128(qty);
_supplies[curationTokenId] = supply_;
_burn(msg.sender, curationTokenId, qty);
}
// since the hub itself can be sold lol!
function setDefaultRoyalty() external {
_setDefaultRoyalty(address(hub), uint96(hub.hubRoyalty()));
}
function setFeePercentage(uint256 newFeePercentage) external {
_requireCallerIsContractOwner();
feePercentage = newFeePercentage;
}
function setMaxExclusivityWindow(uint256 newMaxExclusivityWindow) external {
_requireCallerIsContractOwner();
maxExclusivityWindow = newMaxExclusivityWindow;
emit MaxExclusivityWindowUpdated(newMaxExclusivityWindow);
}
function setExtendExclusivityPrice(uint256 newExtendExclusivityPricePerWeek) external {
_requireCallerIsContractOwner();
extendExclusivityPricePerWeek = newExtendExclusivityPricePerWeek;
emit ExtendExclusivityPriceUpdated(newExtendExclusivityPricePerWeek);
}
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data)
public
override(ERC1155, IERC1155)
{
super.safeTransferFrom(from, to, id, amount, data);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public override(ERC1155, IERC1155) {
super.safeBatchTransferFrom(from, to, ids, amounts, data);
}
function setApprovalForAll(address operator, bool isApproved) public override(ERC1155, IERC1155) {
super.setApprovalForAll(operator, isApproved);
}
function exclusivityData(uint256 curationTokenId) external view returns (ExclusivityData memory) {
return _exclusivityData[curationTokenId];
}
function uri(uint256 curationTokenId) public view override(ERC1155, IERC1155MetadataURI) returns (string memory) {
if (
hub.restrictedViewing(curationTokenId)
&& !(msg.sender == tx.origin
|| hub.platformApprovedWrapper(msg.sender)
|| hub.ownerApprovedTokenWrapper(curationTokenId, msg.sender))
) revert NoWrapping_error();
return hub.uriRenderer().hubURI(curationTokenId);
}
function balanceOf(address owner, uint256 curationTokenId)
public
view
override(ERC1155, IERC1155)
returns (uint256)
{
return super.balanceOf(owner, curationTokenId);
}
function isApprovedForAll(address owner, address operator) public view override(ERC1155, IERC1155) returns (bool) {
return super.isApprovedForAll(owner, operator);
}
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(ERC1155C, ERC2981, IERC165)
returns (bool)
{
return ERC1155C.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId)
|| super.supportsInterface(interfaceId);
}
function setExclusivityData(uint256 curationTokenId, ExclusivityData memory exclusivityData_) external {
_onlyImmortalizer();
ExclusivityData memory newED = exclusivityData_;
if (!(newED.exclusivityWindow < maxExclusivityWindow)) revert InvalidExclusivityParams_error();
newED.exclusivityWindow += uint64(block.timestamp);
_exclusivityData[curationTokenId] = newED;
emit NewExclusiveToken(curationTokenId);
}
function processAccess(address account, uint256 curationTokenId) external returns (bool ok) {
_onlyHub();
bool exists = hub.exists(curationTokenId);
ExclusivityData memory ed = _exclusivityData[curationTokenId];
if (exists && !(block.timestamp < ed.exclusivityWindow)) {
return true;
} // after exclusiveUntil
if (exists && ed.sharesWithCrew) {
ICrews crews = hub.crews();
IERC721 crew = crews.claimsCrew(hub.originator(curationTokenId));
if (crews.isApprovedCrew(crew) && crews.claimsCrew(account) == crew) return true;
}
if (balanceOf(account, curationTokenId) < 1) return false;
Supply memory supply_ = _supplies[curationTokenId];
supply_.totalSupply -= uint128(1);
_supplies[curationTokenId] = supply_;
_burn(account, curationTokenId, 1);
return true;
}
function emitMetadataUpdate(uint256 curationTokenId) external {
emit MetadataUpdate(curationTokenId);
}
function _onlyImmortalizer() private view {
if (msg.sender != address(IHub(hub).immortalizer())) revert NotImmortalizer_error();
}
function _onlyHub() private view {
if (msg.sender != address(hub)) revert NotHub_error();
}
function _requireCallerIsTokenOwner(uint256 curationTokenId) internal view {
if (msg.sender != hub.ownerOf(curationTokenId)) revert NotOwner_error();
}
function _requireCallerIsContractOwner() internal view override {
_requireCallerIsTokenOwner(hub.HUB_OWNER_TOKENID());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ETH transfer has failed.
error ETHTransferFailed();
/// @dev The ERC20 `transferFrom` has failed.
error TransferFromFailed();
/// @dev The ERC20 `transfer` has failed.
error TransferFailed();
/// @dev The ERC20 `approve` has failed.
error ApproveFailed();
/// @dev The ERC20 `totalSupply` query has failed.
error TotalSupplyQueryFailed();
/// @dev The Permit2 operation has failed.
error Permit2Failed();
/// @dev The Permit2 amount must be less than `2**160 - 1`.
error Permit2AmountOverflow();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
/// @dev Suggested gas stipend for contract receiving ETH to perform a few
/// storage reads and writes, but low enough to prevent griefing.
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
/// @dev The unique EIP-712 domain domain separator for the DAI token contract.
bytes32 internal constant DAI_DOMAIN_SEPARATOR =
0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;
/// @dev The address for the WETH9 contract on Ethereum mainnet.
address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
/// @dev The canonical Permit2 address.
/// [Github](https://github.com/Uniswap/permit2)
/// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ETH OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
//
// The regular variants:
// - Forwards all remaining gas to the target.
// - Reverts if the target reverts.
// - Reverts if the current contract has insufficient balance.
//
// The force variants:
// - Forwards with an optional gas stipend
// (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
// - If the target reverts, or if the gas stipend is exhausted,
// creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
// Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
// - Reverts if the current contract has insufficient balance.
//
// The try variants:
// - Forwards with a mandatory gas stipend.
// - Instead of reverting, returns whether the transfer succeeded.
/// @dev Sends `amount` (in wei) ETH to `to`.
function safeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Sends all the ETH in the current contract to `to`.
function safeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// Transfer all the ETH and check if it succeeded or not.
if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
/// @solidity memory-safe-assembly
assembly {
if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferETH(address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
function forceSafeTransferAllETH(address to) internal {
/// @solidity memory-safe-assembly
assembly {
// forgefmt: disable-next-item
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
mstore(0x00, to) // Store the address in scratch space.
mstore8(0x0b, 0x73) // Opcode `PUSH20`.
mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
}
}
}
/// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
}
}
/// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC20 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for
/// the current contract to manage.
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function trySafeTransferFrom(address token, address from, address to, uint256 amount)
internal
returns (bool success)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x60, amount) // Store the `amount` argument.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends all of ERC20 `token` from `from` to `to`.
/// Reverts upon failure.
///
/// The `from` account must have their entire balance approved for the current contract to manage.
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40) // Cache the free memory pointer.
mstore(0x40, to) // Store the `to` argument.
mstore(0x2c, shl(96, from)) // Store the `from` argument.
mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x60, 0) // Restore the zero slot to zero.
mstore(0x40, m) // Restore the free memory pointer.
}
}
/// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransfer(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sends all of ERC20 `token` from the current contract to `to`.
/// Reverts upon failure.
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
mstore(0x20, address()) // Store the address of the current contract.
// Read the balance, reverting upon failure.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
mstore(0x14, to) // Store the `to` argument.
amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
// Perform the transfer, reverting upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// Reverts upon failure.
function safeApprove(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
/// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
/// then retries the approval again (some tokens, e.g. USDT, requires this).
/// Reverts upon failure.
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, to) // Store the `to` argument.
mstore(0x34, amount) // Store the `amount` argument.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
// Perform the approval, retrying upon failure.
let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x34, 0) // Store 0 for the `amount`.
mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
mstore(0x34, amount) // Store back the original `amount`.
// Retry the approval, reverting upon failure.
success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
if iszero(and(eq(mload(0x00), 1), success)) {
// Check the `extcodesize` again just in case the token selfdestructs lol.
if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
revert(0x1c, 0x04)
}
}
}
}
mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
}
}
/// @dev Returns the amount of ERC20 `token` owned by `account`.
/// Returns zero if the `token` does not exist.
function balanceOf(address token, address account) internal view returns (uint256 amount) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x14, account) // Store the `account` argument.
mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
amount :=
mul( // The arguments of `mul` are evaluated from right to left.
mload(0x20),
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x1f), // At least 32 bytes returned.
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
/// @dev Returns the total supply of the `token`.
/// Reverts if the token does not exist or does not implement `totalSupply()`.
function totalSupply(address token) internal view returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, 0x18160ddd) // `totalSupply()`.
if iszero(
and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
) {
mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
revert(0x1c, 0x04)
}
result := mload(0x00)
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
/// If the initial attempt fails, try to use Permit2 to transfer the token.
/// Reverts upon failure.
///
/// The `from` account must have at least `amount` approved for the current contract to manage.
function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
if (!trySafeTransferFrom(token, from, to, amount)) {
permit2TransferFrom(token, from, to, amount);
}
}
/// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
/// Reverts upon failure.
function permit2TransferFrom(address token, address from, address to, uint256 amount)
internal
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(add(m, 0x74), shr(96, shl(96, token)))
mstore(add(m, 0x54), amount)
mstore(add(m, 0x34), to)
mstore(add(m, 0x20), shl(96, from))
// `transferFrom(address,address,uint160,address)`.
mstore(m, 0x36c78516000000000000000000000000)
let p := PERMIT2
let exists := eq(chainid(), 1)
if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
if iszero(
and(
call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
lt(iszero(extcodesize(token)), exists) // Token has code and Permit2 exists.
)
) {
mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
}
}
}
/// @dev Permit a user to spend a given amount of
/// another user's tokens via native EIP-2612 permit if possible, falling
/// back to Permit2 if native permit fails or is not implemented on the token.
function permit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
bool success;
/// @solidity memory-safe-assembly
assembly {
for {} shl(96, xor(token, WETH9)) {} {
mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
if iszero(
and( // The arguments of `and` are evaluated from right to left.
lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
// Gas stipend to limit gas burn for tokens that don't refund gas when
// an non-existing function is called. 5K should be enough for a SLOAD.
staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
)
) { break }
// After here, we can be sure that token is a contract.
let m := mload(0x40)
mstore(add(m, 0x34), spender)
mstore(add(m, 0x20), shl(96, owner))
mstore(add(m, 0x74), deadline)
if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
mstore(0x14, owner)
mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
mstore(add(m, 0x94), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
// `nonces` is already at `add(m, 0x54)`.
// `1` is already stored at `add(m, 0x94)`.
mstore(add(m, 0xb4), and(0xff, v))
mstore(add(m, 0xd4), r)
mstore(add(m, 0xf4), s)
success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
break
}
mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
mstore(add(m, 0x54), amount)
mstore(add(m, 0x94), and(0xff, v))
mstore(add(m, 0xb4), r)
mstore(add(m, 0xd4), s)
success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
break
}
}
if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
}
/// @dev Simple permit on the Permit2 contract.
function simplePermit2(
address token,
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
mstore(m, 0x927da105) // `allowance(address,address,address)`.
{
let addressMask := shr(96, not(0))
mstore(add(m, 0x20), and(addressMask, owner))
mstore(add(m, 0x40), and(addressMask, token))
mstore(add(m, 0x60), and(addressMask, spender))
mstore(add(m, 0xc0), and(addressMask, spender))
}
let p := mul(PERMIT2, iszero(shr(160, amount)))
if iszero(
and( // The arguments of `and` are evaluated from right to left.
gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
)
) {
mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
revert(add(0x18, shl(2, iszero(p))), 0x04)
}
mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
// `owner` is already `add(m, 0x20)`.
// `token` is already at `add(m, 0x40)`.
mstore(add(m, 0x60), amount)
mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
// `nonce` is already at `add(m, 0xa0)`.
// `spender` is already at `add(m, 0xc0)`.
mstore(add(m, 0xe0), deadline)
mstore(add(m, 0x100), 0x100) // `signature` offset.
mstore(add(m, 0x120), 0x41) // `signature` length.
mstore(add(m, 0x140), r)
mstore(add(m, 0x160), s)
mstore(add(m, 0x180), shl(248, v))
if iszero( // Revert if token does not have code, or if the call fails.
mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
revert(0x1c, 0x04)
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./CreatorTokenBase.sol";
import "lib/solady/src/tokens/ERC1155.sol";
// modified by no_side666 to favor the solady library
/**
* @title ERC1155C
* @author Limit Break, Inc.
* @notice Extends OpenZeppelin's ERC1155 implementation with Creator Token functionality, which
* allows the contract owner to update the transfer validation logic by managing a security policy in
* an external transfer validation security policy registry. See {CreatorTokenTransferValidator}.
*/
abstract contract ERC1155C is ERC1155, CreatorTokenBase {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(ICreatorToken).interfaceId || super.supportsInterface(interfaceId);
}
/// @dev Ties the solady _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory, /*amounts*/
bytes memory /*data*/
)
internal
virtual
override
{
uint256 idsArrayLength = ids.length;
for (uint256 i; i < idsArrayLength;) {
_validateBeforeTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
/// @dev Ties the solady _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory, /*amounts*/
bytes memory /*data*/
)
internal
virtual
override
{
uint256 idsArrayLength = ids.length;
for (uint256 i; i < idsArrayLength;) {
_validateAfterTransfer(from, to, ids[i]);
unchecked {
++i;
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "lib/openzeppelin-contracts/contracts/token/common/ERC2981.sol";
/**
* @title BasicRoyaltiesBase
* @author Limit Break, Inc.
* @dev Base functionality of an NFT mix-in contract implementing the most basic form of programmable royalties.
*/
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
/**
* @title BasicRoyalties
* @author Limit Break, Inc.
* @notice Constructable BasicRoyalties Contract implementation.
*/
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./Interfaces.sol";
import "./Errors.sol";
import "./LICENSE.sol";
// by no_side666
abstract contract Refunds is IRefunds {
IRefunder public refunder;
function _setRefunder(IRefunder refunder_) internal {
if (address(refunder) != address(0)) revert AlreadySet_error();
refunder = refunder_;
}
function refundAvailable(address account) external view returns (uint256) {
return refunder.refundAvailable(account);
}
function claimRefund() external {
return refunder.claimRefund(msg.sender);
}
function _setRefund(address account, uint256 amount) internal {
return refunder.setRefund{value: amount}(account);
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
import "./modded/creator-token-standards/TransferPolicy.sol";
import "./Structs.sol";
import "./FixedPoint.sol";
import "./IBlockHashBeacon.sol";
import "./IDiscountDemon.sol";
import "./LICENSE.sol";
/*
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@ @@@@@@@@@@
@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@@@@
@@! @@@ @@! @@@ @@! @@! @@@ @@! @@! @@!
!@! @!@ !@! @!@ !@! !@! @!@ !@! !@! !@!
@!@ !@! @!@!!@! @!!!:! @!@!@!@! @!! !!@ @!@
!@! !!! !!@!@! !!!!!: !!!@!!!! !@! ! !@!
!!: !!! !!: :!! !!: !!: !!! !!: !!: by no_side666
:!: !:! :!: !:! :!: :!: !:! :!: :!:
:::: :: :: ::: :: :::: :: ::: ::: :: dreamstack.xyz
:: : : : : : : :: :: : : : : :
@@@@@@ @@@@@@@ @@@@@@ @@@@@@@ @@@ @@@ @@@ @@@ @@@@@@
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@@ @@@ @@@ @@@ @@@ @@@@@@@@
!@@ @@! @@! @@@ !@@ @@! !@@ @@! @@@ @@@
!@! !@! !@! @!@ !@! !@! @!! !@! @!@ @!@
!!@@!! @!! @!@!@!@! !@! @!@@!@! @!@ !@! !!@
!!@!!! !!! !!!@!!!! !!! !!@!!! !@! !!! !!:
!:! !!: !!: !!! :!! !!: :!! :!: !!: !:!
!:! :!: :!: !:! :!: :!: !:! ::!!:! :!:
:::: :: :: :: ::: ::: ::: :: ::: :::: :: :::::
:: : : : : : : :: :: : : ::: : :: : :::
**/
interface IFS {
function flzCompressContents(bytes calldata contents) external pure returns (bytes memory);
function fileBundleFromContents(bytes calldata contents) external view returns (FileBundle memory);
function saveFileBundle(FileBundle calldata fb) external returns (FSPtr memory ptr);
function readFile(FSPtr memory ptr) external view returns (bytes memory);
}
interface IFiltererMaster {
function isPaymentFilterIniter(address account) external view returns (bool);
function beneficiariesOf(uint256 payeeId) external view returns (uint256 beneficiaryId, address target);
function freelancerPercentage() external view returns (uint256);
function accountIncentivizedReleaseOptedOut(address account) external view returns (bool);
}
interface IERC7572 {
function contractURI() external view returns (string memory);
}
interface IHub is IFiltererMaster, IERC7572 {
function owner() external view returns (address);
function HUB_OWNER_TOKENID() external view returns (uint256);
function hubRoyalty() external view returns (uint256);
function hubPercentage() external view returns (uint256);
function HUB_DIVISOR() external view returns (uint256);
function paymentFilterer() external view returns (IPaymentFilterer);
function discountDemon() external view returns (IDiscountDemon);
function blockHashBeacon() external view returns (IBlockHashBeacon);
function blockHashBeaconRewardPercentage() external view returns (uint256);
function immortalizer() external view returns (IImmortalizer);
function immortalStorage() external view returns (IImmortalStorage);
function robustRenderer() external view returns (IRobustRenderer);
function uriRenderer() external view returns (IURI);
function crews() external view returns (ICrews);
function dreams() external view returns (IDreams);
function framesAnimated() external view returns (bool);
function originator(uint256 curationTokenId) external view returns (address);
function nftTemplates(uint256 nftTemplateId) external view returns (address);
function nftTemplatesLength() external view returns (uint256);
function validityLens() external view returns (IValidityLens);
function totalSupply() external view returns (uint256);
function totalMinted() external view returns (uint256);
function ownerOf(uint256 tokenId) external view returns (address);
function exists(uint256 tokenId) external view returns (bool);
function burned(uint256 tokenId) external view returns (bool);
function emitUpdated(uint256 curationTokenId) external;
function beneficiariesOf(uint256 tokenId) external view returns (uint256 beneficiary, address holder);
function curationTokenFramedOptedIn(uint256 curationTokenId) external view returns (bool);
function minFeeNumerator() external view returns (uint96);
function maxBurnWindow() external view returns (uint256);
function setMaxBurnWindow(uint256) external;
function addNewNFTTemplate(address) external;
function freelancerPercentage() external view returns (uint256);
function premierAccess() external view returns (IPremierAccessERC1155);
function platformApprovedWrapper(address account) external view returns (bool);
function ownerApprovedTokenWrapper(uint256 curationTokenId, address account) external view returns (bool);
function restrictedViewing(uint256 curationTokenId) external view returns (bool);
function bridging() external view returns (IBridging);
function prover() external view returns (IProver);
function updateContractURIImage(uint256 curationTokenId, FileBundle memory imageData, address customRenderer)
external;
function immortalizeCollection(ImmortalizeCollectionData calldata icd)
external
payable
returns (uint256 curationTokenId);
function getCollection(uint256 curationTokenId) external view returns (INFT);
function collectionCurationTokenId(INFT) external view returns (uint256);
function pledgedRevealTimestamps(bytes32 encryptionReference) external view returns (uint256);
function pledgedRevealTimestamp(uint256 curationTokenId) external view returns (uint256);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
interface IImmortalizer {
function immortalize(
Type t,
uint256[] calldata featuredIds, // unique array by client, validated in contract
bytes32 encrypted,
FileBundle calldata compressed,
ExclusivityData calldata exclusivityData,
uint256 tokenId
) external;
function immortalizeFrame(
uint256[] calldata featuredIds, // unique array by client, validated in contract
bytes32 encrypted,
FileBundle calldata compressedFrame,
ExclusivityData calldata exclusivityData,
uint256 tokenId
) external;
function setColorClassOverrides(uint256 curationTokenId, FileBundle memory compressedColorClassOverrides) external;
function immortalizeCollection(ImmortalizeCollectionData calldata icd, uint256 tokenId)
external
returns (INFT nftClone);
function immortalizeDream(uint256 tokenId, FileBundle memory compressedDream) external;
function getDream(uint256 tokenId) external view returns (DreamData memory);
function updateContractURIImage(uint256 id, FileBundle calldata fb, address customRenderer) external;
function getContractURIData(uint256 collectionId) external view returns (bytes memory data, address renderer);
function fs() external view returns (IFS);
function immortalized(bytes32 fingerprint) external view returns (uint256 id);
function decrypted(uint256 id) external view returns (bool tf);
function encryptionReference(uint256 id) external view returns (bytes32);
function getTypedPtr(uint256 id) external view returns (TypedPtr memory tp);
function immortalizedType(uint256 id) external view returns (Type);
function isWalker(uint256 id) external view returns (bool);
function reveal(bytes32 encryptionReference, bytes32 key) external;
function decompressCollectionData(uint256 collectionCurationId) external view returns (CollectionData memory);
function decompressFrame(uint256 frameId) external view returns (Frame memory);
function decompressTab(uint256 tabId)
external
view
returns (
bytes[] memory attributes,
bytes[] memory paints,
bytes[][2] memory paintRoots,
uint256 resolution,
bytes[] memory paths
);
function decompressKVOverrides(uint256 curationTokenId) external view returns (KVOverride[] memory kvos);
function getNumberOfFrameStates(uint256 frameId) external view returns (uint256);
function key(uint256 id) external view returns (bytes32);
function keySafe(uint256 id) external view returns (bytes32);
function setGenericData(bytes32 namespace, FileBundle memory compressed) external;
function getGenericData(bytes32 namespace) external view returns (bytes memory);
}
interface IComponentValidator {
function validateTabPayees(IHub hub, uint256 tabId, bytes[][2] calldata colorClasses)
external
view
returns (bool ok);
function validateFramePayeeConfiguration(IHub hub, Frame calldata frame, uint256 frameId)
external
view
returns (bool ok);
function validateCollectionPayees(
IHub,
uint256 collectionId,
uint256[] calldata frameIds,
KVOverride[] memory overrides
) external view returns (bool ok);
function validateDimensions(FixedPoint.FP memory a, FixedPoint.FP memory b) external pure;
}
interface INFT is IERC7572 {
function curationTokenId() external view returns (uint256);
function owner() external view returns (address);
function ownerOf(uint256 tokenId) external view returns (address);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function contractURI() external view returns (string memory);
function emitContractURIUpdated() external;
function emitBatchMetadataUpdate(uint256 fromTokenId, uint256 toTokenId) external;
function tokenURI(uint256 tokenId) external view returns (string memory);
function mintedAtBlock(uint256 tokenId) external view returns (uint256);
function description() external view returns (string memory);
function website() external view returns (string memory);
function maxSupply() external view returns (uint256);
function totalSupply() external view returns (uint256);
function totalMinted() external view returns (uint256);
function qtyAvailableToMint() external view returns (uint256);
function mintStarts() external view returns (uint256);
function mintEnds() external view returns (uint256);
function mintStarted() external view returns (bool);
function mintRevealBlockOffset() external view returns (uint256);
function mintPriceCurrent() external view returns (uint256);
function mintPricesInRange(uint256 nth, uint256 qty) external view returns (uint256[] memory);
function paymentPushGranularity() external view returns (uint256);
function mintPrices() external view returns (uint256[] memory mintQtyCheckpoints, uint256[] memory mintPrices);
function ONE() external view returns (uint256);
function mintEconomics() external view returns (MintEconomics memory);
function willBeFinalized() external view returns (uint256);
function initialize(
uint256 curationTokenId,
IRefunder refunder_,
CollectionNames calldata names,
MintEconomics calldata mintEconomics,
DiscountData calldata dd,
bytes calldata auxData
) external;
function paymentFilterer() external view returns (IPaymentFilterer);
function pushETHToPaymentFilterer() external;
function setMintEnds(uint256 mintEndsTime) external;
function updateSupply() external;
function mint(address to, uint256 qty) external payable;
function mintDiscounted(address to, IERC721[] calldata collections, uint256[] calldata tokenIds) external payable;
function burn(uint256[] memory ids) external;
}
interface IERC1155 is IERC165 {
function balanceOf(address account, uint256 id) external view returns (uint256);
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) external;
}
interface IERC1155MetadataURI {
function uri(uint256 id) external view returns (string memory);
}
interface IPremierAccessERC1155 is IERC1155, IERC1155MetadataURI {
function ONE() external view returns (uint256);
function feePercentage() external view returns (uint256);
function setExclusivityData(uint256 curationTokenId, ExclusivityData calldata xclusivityData) external;
function exclusivityData(uint256 curationTokenId) external view returns (ExclusivityData memory);
function supply(uint256 curationTokenId) external view returns (Supply memory);
function processAccess(address account, uint256 curationTokenId) external returns (bool ok);
function mint(uint256 curationTokenId, uint256 qty, address to) external payable;
function emitMetadataUpdate(uint256 curationTokenId) external;
}
interface IImmortalizerDecompressUtil {
function decompressCollectionData(bytes32 key, bytes memory compressed)
external
view
returns (CollectionData memory ret);
function decompressFrame(bytes32 key, bytes memory packed) external view returns (Frame memory frame);
function decompressTab(bytes32 key, bytes memory compressedTab)
external
view
returns (
bytes[] memory attributes,
bytes[] memory paints,
bytes[][2] memory paintRoots,
uint256 dimension,
bytes[] memory paths
);
function decompressKVOverrides(bytes memory compressedOverrides) external view returns (KVOverride[] memory kvos);
function decompressDreamData(bytes memory compressedDreamData) external view returns (DreamData memory dreamData);
}
interface IImmortalStorage {
function setCompressedPtr(uint256 id, TypedPtr memory tp) external;
function getCompressedPtr(uint256 id) external view returns (TypedPtr memory tp);
function setImmortalized(bytes32 fingerprint, uint256 id) external;
function getImmortalized(bytes32 fingerprint) external view returns (uint256 id);
function setEncryptionReference(uint256 id, bytes32 encryptionReference) external;
function getEncryptionReference(uint256 id) external view returns (bytes32 encryptionRference);
function setKey(bytes32 encryptionReference, bytes32 key) external;
function getKey(bytes32 encryptionReference) external view returns (bytes32 key);
function setContractURIImagePtr(uint256 id, FSPtr memory ptr) external;
function getContractURIImagePtr(uint256 id) external view returns (FSPtr memory ptr);
function setContractURIImageRenderer(uint256 id, address renderer) external;
function getContractURIImageRenderer(uint256 id) external view returns (address renderer);
function getGenericData(bytes32 hash) external view returns (FSPtr memory ptr);
function setGenericData(bytes32 hash, FSPtr memory ptr) external;
}
interface IRobustRenderer {
function renderMinimal(uint256 id, PointAndBounded calldata pb) external view returns (Element memory);
function renderFrame(uint256 frameId, uint256 entropy, uint256 seed, PointAndBounded calldata pb)
external
view
returns (Element memory);
function renderCollection(uint256 collectionId, uint256 entropy, uint256 seed, PointAndBounded calldata pb)
external
view
returns (RenderedCollectionData memory renderedCollectionData);
function renderContractURIImage(uint256 id) external view returns (string memory);
function formSVG(FixedPoint.FP memory resolution, PointAndBounded memory pb, bytes memory nestedData)
external
pure
returns (string memory);
}
interface IColorUtils {
function shadingToRoot(bytes memory shadingKey, bytes memory shadingValue)
external
pure
returns (bytes memory rootColorClassValue);
function getSLDetails(bytes memory key) external pure returns (int256 sPerc, int256 lPerc, bytes memory details);
function getSLPercs(bytes memory key, uint256 baseLength) external pure returns (int256 sPerc, int256 lPerc);
}
interface IValidityLens {
function scanValidity(uint256 id, uint256 seed, uint256 runs)
external
view
returns (Validity validity, bytes memory error);
function checkEncrypted(uint256 pledgedRevealTimestamp, bytes32 key) external view returns (Validity);
}
interface IURI {
function svgFramed() external view returns (ISVGFramed);
function uriFinisher() external view returns (IURIFinisher);
function maxMsgLength() external view returns (uint256);
function hubContractURI() external view returns (string memory);
function hubTokenURI(uint256 curationTokenId) external view returns (string memory);
function hubURI(uint256 curationTokenId) external view returns (string memory);
function collectionContractURI() external view returns (string memory);
function collectionTokenURI(uint256 tokenId, RevealedStatus revealedStatus, uint256 entropy)
external
view
returns (string memory);
}
interface ISVGFramed {
function MAT_OFFSET() external view returns (uint256);
function MAT_INNER() external view returns (uint256);
function framed(string memory color, bytes memory _msg, string memory sSvg, bool truncate, bool animateTF)
external
view
returns (string memory ret);
}
interface IURIFinisher {
function finishContractURI(
CollectionNames calldata names,
string calldata sSvg,
uint256 feeBasisPoints,
address feeRecipient
) external view returns (string memory ret);
function finishPending(Type t, Validity v, uint256 pledgedRevealTimestamp, uint256 curationTokenId)
external
view
returns (string memory ret);
function finishCollectionTokenURI(
CollectionNames calldata names,
string[][2] calldata attributes,
JSON[][2] calldata additionalAttributes,
string[][2] calldata colorClasses,
string[][2] calldata textures,
string calldata sSvg
) external view returns (string memory ret);
function finishTokenURI(
CollectionNames calldata names,
string[][2] calldata attributes,
JSON[][2] calldata additionalAttributes,
bytes memory formattedClasses,
string calldata sSvg
) external view returns (string memory ret);
function finishOutOfGas() external view returns (string memory ret);
}
interface IPaymentFilterer {
function BASIS() external view returns (uint256);
function initFilter(uint256 id, uint256[] memory payeeTokenIds, uint256[] memory shares_) external;
function receivePayment(uint256 id) external payable;
function payeesLength(uint256 id) external view returns (uint256);
function payee(uint256 id, uint256 idx) external view returns (uint256);
function shares(uint256 id, uint256 payeeTokenId) external view returns (uint256);
function balances(uint256 id) external view returns (uint256);
function totalShares(uint256 id) external view returns (uint256);
function isPayee(uint256 id, uint256 payeeTokenId) external view returns (bool);
function releasable(uint256 reflectiveId) external view returns (uint256);
function releasable(uint256 id, uint256 payeeTokenId) external view returns (uint256);
//function releasable(IERC20 token, uint256 payeeTokenId) external view returns (uint256);
function release(uint256 reflectiveId, address to) external;
function release(uint256 id, uint256 payeeTokenId, address to) external;
//function release(IERC20 token, uint256 payeeTokenId, address to) external;
function incentivizedRelease(uint256 reflectiveId) external;
function incentivizedRelease(uint256 id, uint256 payeeTokenId) external;
//function incentivizedRelease(IERC20 token, uint256 payeeTokenId) external;
}
interface IRefunds {
function refunder() external view returns (IRefunder);
function refundAvailable(address account) external view returns (uint256);
function claimRefund() external;
}
interface IRefunder {
function setCustomer(address customer) external;
function refundAvailable(address account) external view returns (uint256);
function claimRefund(address account) external;
function setRefund(address account) external payable;
}
interface IProver {
function validateProof(address to, INFT nft, uint256[] calldata tokenIds, uint256 l2Id, bytes calldata proof)
external
returns (bool);
}
interface IBridging {
function bridgeTo(address from, INFT nft, uint256[] calldata tokenIds, uint256 l2Id) external;
function bridgeFrom(address to, INFT nft, uint256[] calldata tokenIds, uint256 l2Id) external;
function isBridged(INFT nft, uint256 tokenId) external view returns (bool);
}
interface ISudoPoolValidator {
function validateAndAddSudoPoolsToWhitelist(address[] calldata sudoPools) external;
}
interface IOwnable {
function owner() external view returns (address);
}
interface ICrews {
function getCrewData(address account) external view returns (CrewData memory);
function isApprovedCrew(IERC721 crew) external view returns (bool);
function crewAdmin(IERC721 crew) external view returns (IOwnable);
function crewTreasury(IERC721 crew) external view returns (address);
function claimsCrew(address account) external view returns (IERC721);
function getCrewName(address account) external view returns (string memory);
function viewCrewImage(IERC721 crew) external view returns (bytes memory);
function setCrewImage(IERC721 crew, FileBundle calldata imageData) external;
function defineCrew(IERC721 crew, IOwnable newAdmin, address payable newTreasury) external;
function tryDefineCollectionCrew(INFT collection) external;
function retroDefineCollectionCrew(uint256 collectionCurationTokenId) external;
function claimCrew(IERC721 crew) external;
function leftCrew(IERC721 crew, address account) external;
function setNewCrewAdmin(IERC721 crew, IOwnable newAdmin) external;
function setCrewTreasury(IERC721 crew, address payable newTreasury) external;
}
interface IDreams {
function numAvailableBackgrounds() external view returns (uint256);
function viewBackground(uint256 backgroundId) external view returns (string memory);
function immortalizeDream(
string calldata name,
uint256 crewPercentage_,
FileBundle calldata compressedDream,
address to
) external;
function exists(uint256 tokenId) external view returns (bool);
function extendedDreamData(uint256 tokenId) external view returns (ExtendedDreamData memory);
function balanceETH(uint256 tokenId) external view returns (uint256);
function withdrawnETH(uint256 tokenId) external view returns (uint256);
function ownsERC721(uint256 dreamId, IERC721 token) external view returns (uint256[] memory tokenIdsOwned);
function balancesERC1155(uint256 dreamId, IERC1155 token)
external
view
returns (uint256[] memory tokens, uint256[] memory balances);
}
interface IDreamsRenderer {
function render(uint256 tokenId, string memory name, DreamData memory dd, bytes memory compressedRenderData)
external
view
returns (string memory);
}
interface IERC721Supplied is IERC721 {
function totalSupply() external view returns (uint256);
function totalMinted() external view returns (uint256);
function exists(uint256 tokenId) external view returns (bool);
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE pragma solidity ^0.8.25; import "./LICENSE.sol"; error AlreadyImmortalized_error(); error IDOrdering_error(); error MustRespectExclusivity_error(); error ExclusivityLapsed_error(); error InvalidExclusivityParams_error(); error InvalidOptionsLength_error(); error RevealTimeNotSet_error(); error RevealOrdering_error(); error NotOwner_error(); error NotApproved_error(); error InsufficientImmortalizeFee_error(); error FailedCall_error(); error ExceedsMaxFreeMintsPerTx_error(); error MalformedInputs_error(); error ZeroInput_error(); error RepeatedEncryptionReference_error(); error InvalidCommitment_error(); error InvalidKey_error(); error InvalidFeeNumerator_error(); error BadMintPrices_error(); error BadMintCheckpoints_error(); error TrivialMaxSupply_error(); error MintEconomicsOrderering_error(); error NotHub_error(); error NotDreams_error(); error NotRobustRenderer_error(); error NotImmortalizer_error(); error AlreadyRevealed_error(); error NotRevealed_error(); error InvalidInput_error(); error TrivialData_error(); error InvalidComponent_error(); error InvalidDimensions_error(); error InvalidResolution_error(); error InvalidData_error(); error InvalidColor_error(); error InvalidPaint_error(); error InvalidRune_error(); error InvalidTexture_error(); error InvalidCaller_error(); error TrivialFrame_error(); error NoWrapping_error(); error UnpermittedKey_error(); error NotReady_error(); error CollectionFinalized_error(); error FramePayees_error(); error TabPayees_error(); error CollectionPayees_error(); error NotCollection_error(); error Transfer_error(); error InvalidLengths_error(); error InvalidPath_error(); error PathsNotOrdered_error(); error InvalidFileBundle_error(); error InvalidTabFingerprint_error(); error InvalidFrameFingerprint_error(); error InvalidColorClassAliases_error(); error RefundFailed_error(); error InsufficientValue_error(uint256 expected); error ExceedsMaxSupply_error(); error MintNotStarted_error(); error MintEnded_error(); error DiscountAlreadyClaimed_error(); error CollectionNotDiscounted_error(); error BridgingNotCurrentlySupported_error(); error InvalidProof_error(); error NotDistinct_error(); error ReadFile_error(); error AlreadySet_error(); error InvalidCollection_error(); error InvalidBurnWindow_error(); error InvalidMintCheckpoints_error(); error InvalidNFTTemplateVersion_error(); error InvalidMaxFreeMintsPerTx_error(); error InvalidMintRevealBlockOffset_error(); error Overflow_error(); error CyclesDisallowed_error(); error AlreadyInitialized_error(); error OnlyMasterApproved_error(); error IsFrozen_error(); error Unsupported_error(); error UninitializedCacheMap_error(); error InvalidShading_error(); error InvalidHex_error(); error InvalidByte_error(); error InvalidType_error(); error InvalidBackground_error(); // from ethfs error SliceOutOfBounds(address pointer, uint32 codeSize, uint32 sliceStart, uint32 sliceEnd); error AssertShouldNotHappen_error(); error AlreadyPaid_error(); error AlreadyApprovedCrew_error(); error Poser_error(); error CrewNotApproved_error(); error HasBeenRevealed_error(); error CanStillBeRevealed_error(); error NameAlreadyExists_error(); error UnsafeClear_error();
// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE pragma solidity 0.8.28; /* HEXED VIRAL PUBLIC LICENSE Copyleft (c) 2025 DreamStack. This WORK protected by voodoo and is hereby relinquished of all associated ownership, attribution and copy rights, and redistribution or use of any kind, with or without modification, is permitted without restriction subject to the following conditions: 1. Redistributions of this WORK, or ANY work that makes use of ANY of the contents of this WORK by ANY kind of copying, dependency, linkage, or ANY other possible form of DERIVATION or COMBINATION, must retain the ENTIRETY of this license. 2. No further restrictions of ANY kind may be applied. 3. While not legally binding, tongue-in-cheek hex spells may be cast on anyone who intentionally forks a HVPL project with the intent to siphon or vampire attack the project's business, earnings, or influence. Fully permissive, viral software license. Like VPL (VIRAL PUBLIC LICENSE), the HVPL (HEXED VIRAL PUBLIC LICENSE) is designed to achieve and extend the GPL's strong copyleft without the burden of its obligations and restrictions, but with a dash of witchcraft nudging humans to copy or borrow with decency. The HVPL's sole restriction is its own viral continuity, allowing it to effectively and permanently infect any work it touches with absolute permissiveness, and reign supreme in its sorcery. **/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "lib/openzeppelin-contracts/contracts/interfaces/IERC165.sol";
import "./OwnablePermissions.sol";
import "./ICreatorToken.sol";
import "./ICreatorTokenTransferValidator.sol";
import "./TransferValidation.sol";
/**
* @title CreatorTokenBase
* @author Limit Break, Inc.
* @notice CreatorTokenBase is an abstract contract that provides basic functionality for managing token
* transfer policies through an implementation of ICreatorTokenTransferValidator. This contract is intended to be used
* as a base for creator-specific token contracts, enabling customizable transfer restrictions and security policies.
*
* <h4>Features:</h4>
* <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul>
* <ul>TransferValidation: Implements the basic token transfer validation interface.</ul>
* <ul>ICreatorToken: Implements the interface for creator tokens, providing view functions for token security policies.</ul>
*
* <h4>Benefits:</h4>
* <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul>
* <ul>Allows creators to enforce policies such as whitelisted operators and permitted contract receivers.</ul>
* <ul>Can be easily integrated into other token contracts as a base contract.</ul>
*
* <h4>Intended Usage:</h4>
* <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and
* security policies.</ul>
* <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the
* creator token.</ul>
*/
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
error CreatorTokenBase__InvalidTransferValidatorContract();
error CreatorTokenBase__SetTransferValidatorFirst();
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x0000721C310194CcfC01E523fc93C9cCcFa2A0Ac);
TransferSecurityLevels public constant DEFAULT_TRANSFER_SECURITY_LEVEL = TransferSecurityLevels.One;
uint120 public constant DEFAULT_OPERATOR_WHITELIST_ID = uint120(1);
ICreatorTokenTransferValidator private transferValidator;
/**
* @notice Allows the contract owner to set the transfer validator to the official validator contract
* and set the security policy to the recommended default settings.
* @dev May be overridden to change the default behavior of an individual collection.
*/
function setToDefaultSecurityPolicy() public virtual {
_requireCallerIsContractOwner();
setTransferValidator(DEFAULT_TRANSFER_VALIDATOR);
ICreatorTokenTransferValidator(DEFAULT_TRANSFER_VALIDATOR)
.setTransferSecurityLevelOfCollection(address(this), DEFAULT_TRANSFER_SECURITY_LEVEL);
ICreatorTokenTransferValidator(DEFAULT_TRANSFER_VALIDATOR)
.setOperatorWhitelistOfCollection(address(this), DEFAULT_OPERATOR_WHITELIST_ID);
}
/**
* @notice Allows the contract owner to set the transfer validator to a custom validator contract
* and set the security policy to their own custom settings.
*/
function setToCustomValidatorAndSecurityPolicy(
address validator,
TransferSecurityLevels level,
uint120 operatorWhitelistId,
uint120 permittedContractReceiversAllowlistId
) public virtual {
_requireCallerIsContractOwner();
setTransferValidator(validator);
ICreatorTokenTransferValidator(validator).setTransferSecurityLevelOfCollection(address(this), level);
ICreatorTokenTransferValidator(validator).setOperatorWhitelistOfCollection(address(this), operatorWhitelistId);
ICreatorTokenTransferValidator(validator)
.setPermittedContractReceiverAllowlistOfCollection(address(this), permittedContractReceiversAllowlistId);
}
/**
* @notice Allows the contract owner to set the security policy to their own custom settings.
* @dev Reverts if the transfer validator has not been set.
*/
function setToCustomSecurityPolicy(
TransferSecurityLevels level,
uint120 operatorWhitelistId,
uint120 permittedContractReceiversAllowlistId
) public virtual {
_requireCallerIsContractOwner();
ICreatorTokenTransferValidator validator = getTransferValidator();
if (address(validator) == address(0)) {
revert CreatorTokenBase__SetTransferValidatorFirst();
}
validator.setTransferSecurityLevelOfCollection(address(this), level);
validator.setOperatorWhitelistOfCollection(address(this), operatorWhitelistId);
validator.setPermittedContractReceiverAllowlistOfCollection(
address(this), permittedContractReceiversAllowlistId
);
}
/**
* @notice Sets the transfer validator for the token contract.
*
* @dev Throws when provided validator contract is not the zero address and doesn't support
* the ICreatorTokenTransferValidator interface.
* @dev Throws when the caller is not the contract owner.
*
* @dev <h4>Postconditions:</h4>
* 1. The transferValidator address is updated.
* 2. The `TransferValidatorUpdated` event is emitted.
*
* @param transferValidator_ The address of the transfer validator contract.
*/
function setTransferValidator(address transferValidator_) public virtual {
_requireCallerIsContractOwner();
bool isValidTransferValidator = false;
if (transferValidator_.code.length > 0) {
try IERC165(transferValidator_)
.supportsInterface(type(ICreatorTokenTransferValidator).interfaceId) returns (
bool supportsInterface
) {
isValidTransferValidator = supportsInterface;
} catch {}
}
if (transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(transferValidator), transferValidator_);
transferValidator = ICreatorTokenTransferValidator(transferValidator_);
}
/**
* @notice Returns the transfer validator contract address for this token contract.
*/
function getTransferValidator() public view override returns (ICreatorTokenTransferValidator) {
return transferValidator;
}
/**
* @notice Returns the security policy for this token contract, which includes:
* Transfer security level, operator whitelist id, permitted contract receiver allowlist id.
*/
function getSecurityPolicy() public view override returns (CollectionSecurityPolicy memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getCollectionSecurityPolicy(address(this));
}
return CollectionSecurityPolicy({
transferSecurityLevel: TransferSecurityLevels.Zero, operatorWhitelistId: 0, permittedContractReceiversId: 0
});
}
/**
* @notice Returns the list of all whitelisted operators for this token contract.
* @dev This can be an expensive call and should only be used in view-only functions.
*/
function getWhitelistedOperators() public view override returns (address[] memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getWhitelistedOperators(
transferValidator.getCollectionSecurityPolicy(address(this)).operatorWhitelistId
);
}
return new address[](0);
}
/**
* @notice Returns the list of permitted contract receivers for this token contract.
* @dev This can be an expensive call and should only be used in view-only functions.
*/
function getPermittedContractReceivers() public view override returns (address[] memory) {
if (address(transferValidator) != address(0)) {
return transferValidator.getPermittedContractReceivers(
transferValidator.getCollectionSecurityPolicy(address(this)).permittedContractReceiversId
);
}
return new address[](0);
}
/**
* @notice Checks if an operator is whitelisted for this token contract.
* @param operator The address of the operator to check.
*/
function isOperatorWhitelisted(address operator) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
return transferValidator.isOperatorWhitelisted(
transferValidator.getCollectionSecurityPolicy(address(this)).operatorWhitelistId, operator
);
}
return false;
}
/**
* @notice Checks if a contract receiver is permitted for this token contract.
* @param receiver The address of the receiver to check.
*/
function isContractReceiverPermitted(address receiver) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
return transferValidator.isContractReceiverPermitted(
transferValidator.getCollectionSecurityPolicy(address(this)).permittedContractReceiversId, receiver
);
}
return false;
}
/**
* @notice Determines if a transfer is allowed based on the token contract's security policy. Use this function
* to simulate whether or not a transfer made by the specified `caller` from the `from` address to the `to`
* address would be allowed by this token's security policy.
*
* @notice This function only checks the security policy restrictions and does not check whether token ownership
* or approvals are in place.
*
* @param caller The address of the simulated caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @return True if the transfer is allowed, false otherwise.
*/
function isTransferAllowed(address caller, address from, address to) public view override returns (bool) {
if (address(transferValidator) != address(0)) {
try transferValidator.applyCollectionTransferPolicy(caller, from, to) {
return true;
} catch {
return false;
}
}
return true;
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256,
/*tokenId*/
uint256 /*value*/
)
internal
virtual
override
{
if (address(transferValidator) != address(0)) {
transferValidator.applyCollectionTransferPolicy(caller, from, to);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC1155 implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC1155.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC1155.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC1155/ERC1155.sol)
///
/// @dev Note:
/// - The ERC1155 standard allows for self-approvals.
/// For performance, this implementation WILL NOT revert for such actions.
/// Please add any checks with overrides if desired.
/// - The transfer functions use the identity precompile (0x4)
/// to copy memory internally.
///
/// If you are overriding:
/// - Make sure all variables written to storage are properly cleaned
// (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
/// change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC1155 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The lengths of the input arrays are not the same.
error ArrayLengthsMismatch();
/// @dev Cannot mint or transfer to the zero address.
error TransferToZeroAddress();
/// @dev The recipient's balance has overflowed.
error AccountBalanceOverflow();
/// @dev Insufficient balance.
error InsufficientBalance();
/// @dev Only the token owner or an approved account can manage the tokens.
error NotOwnerNorApproved();
/// @dev Cannot safely transfer to a contract that does not implement
/// the ERC1155Receiver interface.
error TransferToNonERC1155ReceiverImplementer();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when `amount` of token `id` is transferred
/// from `from` to `to` by `operator`.
event TransferSingle(
address indexed operator,
address indexed from,
address indexed to,
uint256 id,
uint256 amount
);
/// @dev Emitted when `amounts` of token `ids` are transferred
/// from `from` to `to` by `operator`.
event TransferBatch(
address indexed operator,
address indexed from,
address indexed to,
uint256[] ids,
uint256[] amounts
);
/// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);
/// @dev Emitted when the Uniform Resource Identifier (URI) for token `id`
/// is updated to `value`. This event is not used in the base contract.
/// You may need to emit this event depending on your URI logic.
///
/// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
event URI(string value, uint256 indexed id);
/// @dev `keccak256(bytes("TransferSingle(address,address,address,uint256,uint256)"))`.
uint256 private constant _TRANSFER_SINGLE_EVENT_SIGNATURE =
0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62;
/// @dev `keccak256(bytes("TransferBatch(address,address,address,uint256[],uint256[])"))`.
uint256 private constant _TRANSFER_BATCH_EVENT_SIGNATURE =
0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb;
/// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `ownerSlotSeed` of a given owner is given by.
/// ```
/// let ownerSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner))
/// ```
///
/// The balance slot of `owner` is given by.
/// ```
/// mstore(0x20, ownerSlotSeed)
/// mstore(0x00, id)
/// let balanceSlot := keccak256(0x00, 0x40)
/// ```
///
/// The operator approval slot of `owner` is given by.
/// ```
/// mstore(0x20, ownerSlotSeed)
/// mstore(0x00, operator)
/// let operatorApprovalSlot := keccak256(0x0c, 0x34)
/// ```
uint256 private constant _ERC1155_MASTER_SLOT_SEED = 0x9a31110384e0b0c9;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1155 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the URI for token `id`.
///
/// You can either return the same templated URI for all token IDs,
/// (e.g. "https://example.com/api/{id}.json"),
/// or return a unique URI for each `id`.
///
/// See: https://eips.ethereum.org/EIPS/eip-1155#metadata
function uri(uint256 id) public view virtual returns (string memory);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1155 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the amount of `id` owned by `owner`.
function balanceOf(address owner, uint256 id) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, owner)
mstore(0x00, id)
result := sload(keccak256(0x00, 0x40))
}
}
/// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
function isApprovedForAll(address owner, address operator)
public
view
virtual
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, owner)
mstore(0x00, operator)
result := sload(keccak256(0x0c, 0x34))
}
}
/// @dev Sets whether `operator` is approved to manage the tokens of the caller.
///
/// Emits a {ApprovalForAll} event.
function setApprovalForAll(address operator, bool isApproved) public virtual {
/// @solidity memory-safe-assembly
assembly {
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`msg.sender`, `operator`).
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, caller())
mstore(0x00, operator)
sstore(keccak256(0x0c, 0x34), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
// forgefmt: disable-next-line
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
}
}
/// @dev Transfers `amount` of `id` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - If the caller is not `from`,
/// it must be approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) public virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
mstore(0x20, fromSlotSeed)
// Clear the upper 96 bits.
from := shr(96, fromSlotSeed)
to := shr(96, toSlotSeed)
// Revert if `to` is the zero address.
if iszero(to) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// If the caller is not `from`, do the authorization check.
if iszero(eq(caller(), from)) {
mstore(0x00, caller())
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Subtract and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), from, to)
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
// Do the {onERC1155Received} check if `to` is a smart contract.
if extcodesize(to) {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155Received(address,address,uint256,uint256,bytes)`.
mstore(m, 0xf23a6e61)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), from)
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), amount)
mstore(add(m, 0xa0), 0xa0)
calldatacopy(add(m, 0xc0), sub(data.offset, 0x20), add(0x20, data.length))
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, data.length), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Transfers `amounts` of `ids` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - `ids` and `amounts` must have the same length.
/// - If the caller is not `from`,
/// it must be approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) public virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(ids.length, amounts.length)) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, from))
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, shl(96, to))
mstore(0x20, fromSlotSeed)
// Clear the upper 96 bits.
from := shr(96, fromSlotSeed)
to := shr(96, toSlotSeed)
// Revert if `to` is the zero address.
if iszero(to) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// If the caller is not `from`, do the authorization check.
if iszero(eq(caller(), from)) {
mstore(0x00, caller())
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, ids.length) } i {} {
i := sub(i, 0x20)
let amount := calldataload(add(amounts.offset, i))
// Subtract and store the updated balance of `from`.
{
mstore(0x20, fromSlotSeed)
mstore(0x00, calldataload(add(ids.offset, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, ids.length))
let o := add(m, 0x40)
calldatacopy(o, sub(ids.offset, 0x20), n)
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, n))
calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)
// Do the emit.
log4(m, add(add(n, n), 0x40), _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), from, to)
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransferCalldata(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
// Do the {onERC1155BatchReceived} check if `to` is a smart contract.
if extcodesize(to) {
mstore(0x00, to) // Cache `to` to prevent stack too deep.
let m := mload(0x40)
// Prepare the calldata.
// `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
mstore(m, 0xbc197c81)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), from)
// Copy the `ids`.
mstore(add(m, 0x60), 0xa0)
let n := add(0x20, shl(5, ids.length))
let o := add(m, 0xc0)
calldatacopy(o, sub(ids.offset, 0x20), n)
// Copy the `amounts`.
let s := add(0xa0, n)
mstore(add(m, 0x80), s)
calldatacopy(add(o, n), sub(amounts.offset, 0x20), n)
// Copy the `data`.
mstore(add(m, 0xa0), add(s, n))
calldatacopy(add(o, add(n, n)), sub(data.offset, 0x20), add(0x20, data.length))
let nAll := add(0xc4, add(data.length, add(n, n)))
// Revert if the call reverts.
if iszero(call(gas(), mload(0x00), 0, add(m, 0x1c), nAll, m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Returns the amounts of `ids` for `owners.
///
/// Requirements:
/// - `owners` and `ids` must have the same length.
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids)
public
view
virtual
returns (uint256[] memory balances)
{
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(ids.length, owners.length)) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
balances := mload(0x40)
mstore(balances, ids.length)
let o := add(balances, 0x20)
let i := shl(5, ids.length)
mstore(0x40, add(i, o))
// Loop through all the `ids` and load the balances.
for {} i {} {
i := sub(i, 0x20)
let owner := calldataload(add(owners.offset, i))
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, shl(96, owner)))
mstore(0x00, calldataload(add(ids.offset, i)))
mstore(add(o, i), sload(keccak256(0x00, 0x40)))
}
}
}
/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
/// See: https://eips.ethereum.org/EIPS/eip-165
/// This function call must use less than 30000 gas.
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let s := shr(224, interfaceId)
// ERC165: 0x01ffc9a7, ERC1155: 0xd9b67a26, ERC1155MetadataURI: 0x0e89341c.
result := or(or(eq(s, 0x01ffc9a7), eq(s, 0xd9b67a26)), eq(s, 0x0e89341c))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints `amount` of `id` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function _mint(address to, uint256 id, uint256 amount, bytes memory data) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(address(0), to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, to)
mstore(0x00, id)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(address(0), to, _single(id), _single(amount), data);
}
if (_hasCode(to)) _checkOnERC1155Received(address(0), to, id, amount, data);
}
/// @dev Mints `amounts` of `ids` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `ids` and `amounts` must have the same length.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function _batchMint(
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(address(0), to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
// Loop through all the `ids` and update the balances.
{
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Increase and store the updated balance of `to`.
{
mstore(0x00, mload(add(ids, i)))
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), 0, shr(96, to_))
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(address(0), to, ids, amounts, data);
}
if (_hasCode(to)) _checkOnERC1155BatchReceived(address(0), to, ids, amounts, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_burn(address(0), from, id, amount)`.
function _burn(address from, uint256 id, uint256 amount) internal virtual {
_burn(address(0), from, id, amount);
}
/// @dev Destroys `amount` of `id` from `from`.
///
/// Requirements:
/// - `from` must have at least `amount` of `id`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
///
/// Emits a {TransferSingle} event.
function _burn(address by, address from, uint256 id, uint256 amount) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, address(0), _single(id), _single(amount), "");
}
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
if iszero(or(iszero(shl(96, by)), eq(shl(96, by), from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Decrease and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, address(0), _single(id), _single(amount), "");
}
}
/// @dev Equivalent to `_batchBurn(address(0), from, ids, amounts)`.
function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
{
_batchBurn(address(0), from, ids, amounts);
}
/// @dev Destroys `amounts` of `ids` from `from`.
///
/// Requirements:
/// - `ids` and `amounts` must have the same length.
/// - `from` must have at least `amounts` of `ids`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
///
/// Emits a {TransferBatch} event.
function _batchBurn(address by, address from, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
{
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, address(0), ids, amounts, "");
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let from_ := shl(96, from)
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Decrease and store the updated balance of `from`.
{
mstore(0x00, mload(add(ids, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), 0)
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, address(0), ids, amounts, "");
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL APPROVAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Approve or remove the `operator` as an operator for `by`,
/// without authorization checks.
///
/// Emits a {ApprovalForAll} event.
function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`by`, `operator`).
mstore(0x20, _ERC1155_MASTER_SLOT_SEED)
mstore(0x14, by)
mstore(0x00, operator)
sstore(keccak256(0x0c, 0x34), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
let m := shr(96, not(0))
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, and(m, by), and(m, operator))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_safeTransfer(address(0), from, to, id, amount, data)`.
function _safeTransfer(address from, address to, uint256 id, uint256 amount, bytes memory data)
internal
virtual
{
_safeTransfer(address(0), from, to, id, amount, data);
}
/// @dev Transfers `amount` of `id` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `from` must have at least `amount` of `id`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155Received}, which is called upon a batch transfer.
///
/// Emits a {TransferSingle} event.
function _safeTransfer(
address by,
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, _single(id), _single(amount), data);
}
/// @solidity memory-safe-assembly
assembly {
let from_ := shl(96, from)
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, from_))
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Subtract and store the updated balance of `from`.
{
mstore(0x00, id)
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, or(_ERC1155_MASTER_SLOT_SEED, to_))
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
// Emit a {TransferSingle} event.
mstore(0x20, amount)
// forgefmt: disable-next-line
log4(0x00, 0x40, _TRANSFER_SINGLE_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, _single(id), _single(amount), data);
}
if (_hasCode(to)) _checkOnERC1155Received(from, to, id, amount, data);
}
/// @dev Equivalent to `_safeBatchTransfer(address(0), from, to, ids, amounts, data)`.
function _safeBatchTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
_safeBatchTransfer(address(0), from, to, ids, amounts, data);
}
/// @dev Transfers `amounts` of `ids` from `from` to `to`.
///
/// Requirements:
/// - `to` cannot be the zero address.
/// - `ids` and `amounts` must have the same length.
/// - `from` must have at least `amounts` of `ids`.
/// - If `by` is not the zero address, it must be either `from`,
/// or approved to manage the tokens of `from`.
/// - If `to` refers to a smart contract, it must implement
/// {ERC1155-onERC1155BatchReceived}, which is called upon a batch transfer.
///
/// Emits a {TransferBatch} event.
function _safeBatchTransfer(
address by,
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {
if (_useBeforeTokenTransfer()) {
_beforeTokenTransfer(from, to, ids, amounts, data);
}
/// @solidity memory-safe-assembly
assembly {
if iszero(eq(mload(ids), mload(amounts))) {
mstore(0x00, 0x3b800a46) // `ArrayLengthsMismatch()`.
revert(0x1c, 0x04)
}
let from_ := shl(96, from)
let to_ := shl(96, to)
// Revert if `to` is the zero address.
if iszero(to_) {
mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`.
revert(0x1c, 0x04)
}
let fromSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, from_)
let toSlotSeed := or(_ERC1155_MASTER_SLOT_SEED, to_)
mstore(0x20, fromSlotSeed)
// If `by` is not the zero address, and not equal to `from`,
// check if it is approved to manage all the tokens of `from`.
let by_ := shl(96, by)
if iszero(or(iszero(by_), eq(by_, from_))) {
mstore(0x00, by)
if iszero(sload(keccak256(0x0c, 0x34))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Loop through all the `ids` and update the balances.
{
for { let i := shl(5, mload(ids)) } i { i := sub(i, 0x20) } {
let amount := mload(add(amounts, i))
// Subtract and store the updated balance of `from`.
{
mstore(0x20, fromSlotSeed)
mstore(0x00, mload(add(ids, i)))
let fromBalanceSlot := keccak256(0x00, 0x40)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
}
// Increase and store the updated balance of `to`.
{
mstore(0x20, toSlotSeed)
let toBalanceSlot := keccak256(0x00, 0x40)
let toBalanceBefore := sload(toBalanceSlot)
let toBalanceAfter := add(toBalanceBefore, amount)
if lt(toBalanceAfter, toBalanceBefore) {
mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`.
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceAfter)
}
}
}
// Emit a {TransferBatch} event.
{
let m := mload(0x40)
// Copy the `ids`.
mstore(m, 0x40)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0x40)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
mstore(add(m, 0x20), add(0x40, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
n := sub(add(o, returndatasize()), m)
// Do the emit.
log4(m, n, _TRANSFER_BATCH_EVENT_SIGNATURE, caller(), shr(96, from_), shr(96, to_))
}
}
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, ids, amounts, data);
}
if (_hasCode(to)) _checkOnERC1155BatchReceived(from, to, ids, amounts, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS FOR OVERRIDING */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override this function to return true if `_beforeTokenTransfer` is used.
/// This is to help the compiler avoid producing dead bytecode.
function _useBeforeTokenTransfer() internal view virtual returns (bool) {
return false;
}
/// @dev Hook that is called before any token transfer.
/// This includes minting and burning, as well as batched variants.
///
/// The same hook is called on both single and batched variants.
/// For single transfers, the length of the `id` and `amount` arrays are 1.
function _beforeTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/// @dev Override this function to return true if `_afterTokenTransfer` is used.
/// This is to help the compiler avoid producing dead bytecode.
function _useAfterTokenTransfer() internal view virtual returns (bool) {
return false;
}
/// @dev Hook that is called after any token transfer.
/// This includes minting and burning, as well as batched variants.
///
/// The same hook is called on both single and batched variants.
/// For single transfers, the length of the `id` and `amount` arrays are 1.
function _afterTokenTransfer(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) internal virtual {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Helper for calling the `_afterTokenTransfer` hook.
/// This is to help the compiler avoid producing dead bytecode.
function _afterTokenTransferCalldata(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata amounts,
bytes calldata data
) private {
if (_useAfterTokenTransfer()) {
_afterTokenTransfer(from, to, ids, amounts, data);
}
}
/// @dev Returns if `a` has bytecode of non-zero length.
function _hasCode(address a) private view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := extcodesize(a) // Can handle dirty upper bits.
}
}
/// @dev Perform a call to invoke {IERC1155Receiver-onERC1155Received} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC1155Received(
address from,
address to,
uint256 id,
uint256 amount,
bytes memory data
) private {
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155Received(address,address,uint256,uint256,bytes)`.
mstore(m, 0xf23a6e61)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), amount)
mstore(add(m, 0xa0), 0xa0)
let n := mload(data)
mstore(add(m, 0xc0), n)
if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xe0), n)) }
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(0xc4, n), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xf23a6e61))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Perform a call to invoke {IERC1155Receiver-onERC1155BatchReceived} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC1155BatchReceived(
address from,
address to,
uint256[] memory ids,
uint256[] memory amounts,
bytes memory data
) private {
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
// `onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)`.
mstore(m, 0xbc197c81)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
// Copy the `ids`.
mstore(add(m, 0x60), 0xa0)
let n := add(0x20, shl(5, mload(ids)))
let o := add(m, 0xc0)
pop(staticcall(gas(), 4, ids, n, o, n))
// Copy the `amounts`.
let s := add(0xa0, returndatasize())
mstore(add(m, 0x80), s)
o := add(o, returndatasize())
n := add(0x20, shl(5, mload(amounts)))
pop(staticcall(gas(), 4, amounts, n, o, n))
// Copy the `data`.
mstore(add(m, 0xa0), add(s, returndatasize()))
o := add(o, returndatasize())
n := add(0x20, mload(data))
pop(staticcall(gas(), 4, data, n, o, n))
n := sub(add(o, returndatasize()), add(m, 0x1c))
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), n, m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it with the function selector.
if iszero(eq(mload(m), shl(224, 0xbc197c81))) {
mstore(0x00, 0x9c05499b) // `TransferToNonERC1155ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns `x` in an array with a single element.
function _single(uint256 x) private pure returns (uint256[] memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
mstore(0x40, add(result, 0x40))
mstore(result, 1)
mstore(add(result, 0x20), x)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
enum AllowlistTypes {
Operators,
PermittedContractReceivers
}
enum ReceiverConstraints {
None,
NoCode,
EOA
}
enum CallerConstraints {
None,
OperatorWhitelistEnableOTC,
OperatorWhitelistDisableOTC
}
enum StakerConstraints {
None,
CallerIsTxOrigin,
EOA
}
enum TransferSecurityLevels {
Zero,
One,
Two,
Three,
Four,
Five,
Six
}
struct TransferSecurityPolicy {
CallerConstraints callerConstraints;
ReceiverConstraints receiverConstraints;
}
struct CollectionSecurityPolicy {
TransferSecurityLevels transferSecurityLevel;
uint120 operatorWhitelistId;
uint120 permittedContractReceiversId;
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
/*
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@ @@@@@@@@@@
@@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@ @@@@@@@@@@@
@@! @@@ @@! @@@ @@! @@! @@@ @@! @@! @@!
!@! @!@ !@! @!@ !@! !@! @!@ !@! !@! !@!
@!@ !@! @!@!!@! @!!!:! @!@!@!@! @!! !!@ @!@
!@! !!! !!@!@! !!!!!: !!!@!!!! !@! ! !@!
!!: !!! !!: :!! !!: !!: !!! !!: !!: by no_side666
:!: !:! :!: !:! :!: :!: !:! :!: :!:
:::: :: :: ::: :: :::: :: ::: ::: :: dreamstack.xyz
:: : : : : : : :: :: : : : : :
@@@@@@ @@@@@@@ @@@@@@ @@@@@@@ @@@ @@@ @@@ @@@ @@@@@@
@@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@@ @@@ @@@ @@@ @@@ @@@@@@@@
!@@ @@! @@! @@@ !@@ @@! !@@ @@! @@@ @@@
!@! !@! !@! @!@ !@! !@! @!! !@! @!@ @!@
!!@@!! @!! @!@!@!@! !@! @!@@!@! @!@ !@! !!@
!!@!!! !!! !!!@!!!! !!! !!@!!! !@! !!! !!:
!:! !!: !!: !!! :!! !!: :!! :!: !!: !:!
!:! :!: :!: !:! :!: :!: !:! ::!!:! :!:
:::: :: :: :: ::: ::: ::: :: ::: :::: :: :::::
:: : : : : : : :: :: : : ::: : :: : :::
**/
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "./Interfaces.sol";
import "./FixedPoint.sol";
import "./LICENSE.sol";
struct Supply {
uint128 totalSupply;
uint128 totalMinted;
}
struct ImmortalizeCompressed {
uint256[] featuredIds;
FileBundle fileBundle;
}
struct ImmortalizeComponentData {
uint256[] featuredIds;
bytes32 encrypted;
FileBundle compressed;
ExclusivityData exclusivityData;
address to;
}
struct ImmortalizeCollectionData {
CollectionNames names;
bytes32 encrypted; // if ANY frame has encrypted reference then this must be set
uint256[] featuredIds;
FileBundle compressedCollectionData;
MintEconomics mintEconomics;
DiscountData dd;
address to;
uint256 nftVersionId;
bytes auxData;
}
struct Element {
string[][2] attributes;
string[][2] colorClasses;
string[][2] textures;
string svg;
FixedPoint.FP resolution;
bytes background;
}
struct CollectionNames {
string name;
string symbol;
string description;
bool walker;
}
enum MintPricingType {
TIMED,
BATCHED
}
struct MintEconomics {
uint256 curatorShare;
uint256 mintStarts;
uint256 mintEnds;
uint256 maxFreeMintsPerTx;
uint256 burnWindow;
uint256 mintRevealBlockOffset;
uint256 paymentPushGranularity;
MintPricingType mintPricingType;
uint256 maxSupply;
uint96 feeNumerator;
uint256[] mintCheckpoints;
uint256[] mintPrices;
}
struct ExclusivityData {
uint64 exclusivityWindow; // uint32 is too small
uint112 premiumAccessMax;
uint112 premiumAccessPrice;
bool sharesWithCrew;
}
struct DiscountData {
IERC721[] discountedCollections;
uint256[] discountFactors;
}
struct DreamData {
uint256 suggestedDonationETH;
uint256 targetETH;
uint256 fontSize;
uint256 backgroundId;
bytes description;
bytes data;
bytes[] keywords;
}
struct ExtendedDreamData {
address originator;
string name;
uint256 crewPercentage;
DreamData dreamData;
}
/////////////////////////
/*
// reference
struct Tab {
bytes[] attributes;
bytes[] paints;
bytes[] paintRoots;
uint256 dimension;
bytes[] paths;
}
*/
struct RenderedCollectionData {
string[][2] attributes;
string[][2] colorClasses;
string[][2] textures;
string sSvg;
FixedPoint.FP resolution;
bytes background;
}
struct Frame {
uint256 dimension; // validated so that all children tabs match dimension
bytes backgroundColor;
bytes[] attributes; // {face: pretty, .. etc}
uint256[] tabProbabilities; // can be len=0 if a walker
uint256[] tabIds; // checked against payment splitter on render
bytes forkAttributeKey;
uint256[] forkProbabilities; // can be len=0 if a walker
Fork[] forks;
bytes[][2] overrides; // smart ui ensures all textures have backfills
}
struct Fork {
bytes forkAttributeValue;
uint256[] frameIds; // checked against payment splitter on render
uint256[] footprints; // footprint & dimension gives scale
uint256[] positions; // array w len%2=0 for obvs reasons.. x,y..
}
struct CollectionData {
bytes32 idxBlinder;
uint256[] frameProbabilities; // can be len=0 if a walker
uint256[] frameIds; // checked against payment splitter on render, see _validatePayeeConficguration
KVOverride[] overrides;
bytes[][2] textureBackfills; // smart ui ensures all textures have backfills
AttributeOverride[] attributeOverrides;
}
struct KVOverride {
bytes k;
uint256[] probabilityKeys; // can be len=0 if a walker
bytes[] vs;
bytes[] aliases;
}
struct TextureInstanceStringData {
string id;
string backgroundColorClass;
}
struct AttributeOverride {
uint256 curationTokenId;
bytes[] attributes;
}
enum Type {
NONE,
TAB,
TAB_ENCRYPTED,
FRAME,
FRAME_ENCRYPTED,
COLLECTION,
COLLECTION_ENCRYPTED
}
struct TypedPtr {
bool encrypted;
bool walker;
Type t;
FSPtr ptr;
}
enum FSType {
MINIMAL,
MULTI
}
struct FSPtr {
address ptr;
FSType fsType;
}
enum PaintType {
STANDARD,
COLORCLASS,
TEXTURE,
BACKGROUND
}
enum ShadingType {
ROOT,
SHADING
}
enum Validity {
UNKNOWN,
PENDING_DECRYPTION,
VALID,
INVALID
}
enum CallStatus {
OK,
OUT_OF_GAS,
REVERTED
}
struct Point {
uint256 x;
uint256 y;
}
struct PointAndBounded {
Point p;
Point b;
}
struct UIBasicData {
Type t;
uint256 tokenId;
bool burned;
bool encrypted;
uint256 pledgedRevealTimestamp;
CollectionNames names;
MintEconomics mintEconomics;
ExclusivityData exclusivityData;
Supply exclusivitySupply;
address owner; // obviously can change and should prompt updates
address originator;
CrewData crewData;
string website;
}
struct CrewData {
IERC721 crew;
bool isApprovedCrew;
IOwnable crewAdmin;
address crewTreasury;
string name;
}
struct CounterPtr {
uint256 tally;
}
struct FileBundle {
// delaySaveChunks is a safeguard against eip-7825 gas limitations on tx. allows to passively save chunks to break up a big transaction
bool delaySaveChunks;
bytes compressedFile;
bytes[] chunks;
}
enum JSONType {
STRING,
DATE,
NUMBER,
ARRAY,
OBJ
}
struct JSON {
JSONType t;
bytes data;
}
enum RevealedStatus {
PENDING,
REVEALED
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "lib/solady/src/utils/FixedPointMathLib.sol";
import "lib/solady/src/utils/LibString.sol";
import {LibDynamicBuffer} from "./LibDynamicThing.sol";
import "./Common.sol";
import "./Append.sol";
import "./LICENSE.sol";
library FixedPoint {
struct FP {
uint256 value;
}
struct iFP {
int256 value;
}
function toFixedPointNumber(uint256 x) internal pure returns (FP memory fp) {
x *= 1 ether;
fp.value = x;
}
function toFixedPointNumberRaw(uint256 x) internal pure returns (FP memory fp) {
fp.value = x;
}
function toFixedPointNumberRaw(int256 x) internal pure returns (iFP memory fp) {
fp.value = x;
}
function toNaturalNumber(FixedPoint.FP memory fp) internal pure returns (uint256) {
unchecked {
return fp.value / 1 ether;
} // uc
}
function add(FP memory a, FP memory b) internal pure returns (FP memory res) {
res.value = a.value + b.value;
}
function sub(FP memory a, FP memory b) internal pure returns (FP memory res) {
res.value = a.value - b.value;
}
function mul(FP memory a, FP memory b) internal pure returns (FP memory res) {
res.value = a.value * b.value / 1 ether;
}
function div(FP memory a, FP memory b) internal pure returns (FP memory res) {
res.value = a.value * 1 ether / b.value;
}
function mulDiv(FP memory a, FP memory b, FP memory d) internal pure returns (FP memory res) {
return div(mul(a, b), d);
}
function eq(FP memory a, FP memory b) internal pure returns (bool) {
return a.value == b.value;
}
function toString(uint256 x) internal pure returns (string memory ret) {
return toString(toFixedPointNumberRaw(x));
}
function toString(FP memory x) internal pure returns (string memory ret) {
unchecked {
uint256 value = x.value;
LibDynamicBuffer.DynamicBuffer memory db = LibDynamicBuffer.newDynamicBuffer();
LibDynamicBuffer.p(db, bytes(LibString.toString(value / 1 ether)));
uint256 decimals = value % 1 ether;
if (decimals > 0) {
LibDynamicBuffer.p(db, bytes("."));
uint256 numZeros = 17 - FixedPointMathLib.log10(decimals);
LibDynamicBuffer.p(db, bytes(sZeros(numZeros)));
while (decimals > 1 && decimals % 10 == 0) {
decimals /= 10;
}
LibDynamicBuffer.p(db, bytes(LibString.toString(decimals)));
}
ret = string(LibDynamicBuffer.getBuffer(db));
} // uc
}
function toString(iFP memory x) internal pure returns (string memory ret) {
ret = toString(toFixedPointNumberRaw(FixedPointMathLib.abs(x.value)));
if (x.value < 0) ret = string(_concat("-", bytes(ret)));
}
function sZeros(uint256 numZeros) internal pure returns (string memory ret) {
ret = _allocateString(numZeros);
assembly {
for { let i := 0 } 1 {} {
mstore8(add(ret, add(0x20, i)), 48)
i := add(i, 1)
if iszero(lt(i, numZeros)) { break }
}
// 48 is utf8 for "0"
}
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./LICENSE.sol";
interface IBlockHashBeacon {
function blockHashAt(uint256 blockNumber) external view returns (bytes32);
function rewards(uint256 blockNumber) external view returns (uint256);
function rewardsInRange(uint256 from, uint256 to)
external
view
returns (bytes32[] memory blockHashes, uint256[] memory rewardsPerBlock);
function fundReward(uint256 blockNumber) external payable;
function etchBlockHash(uint256 blockNumber, address payable rewardTo) external;
function etchBlockHashBulk(uint256[] calldata blockNumbers, address payable rewardTo) external;
function etchBlockHashBulkRange(uint256 from, uint256 to, address payable rewardTo) external;
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "./IERC173.sol";
import "./LICENSE.sol";
interface IDiscountDemon is IERC173, IERC165 {
function getDiscountData(address thing)
external
view
returns (IERC721[] memory collections, uint256[] memory factors);
function discountedCollections(address thing) external view returns (IERC721[] memory);
function collectionIsDiscounted(address thing, IERC721 collection) external view returns (bool);
function discountedCollectionFactors(address thing, IERC721 collection) external view returns (uint256);
function initializeDiscounts(IERC721[] calldata collections, uint256[] calldata discountFactors) external;
function discountClaimed(address thing, IERC721 collection, uint256 tokenId) external view returns (bool);
function processDiscount(
IERC721 collection,
address claimer,
uint256 claimingTokenId,
uint256 mintPrice,
uint256 divisor
) external returns (uint256 updatedMintPrice);
function claimDiscount(IERC721 collection, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
abstract contract OwnablePermissions {
function _requireCallerIsContractOwner() internal view virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./ICreatorTokenTransferValidator.sol";
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (ICreatorTokenTransferValidator);
function getSecurityPolicy() external view returns (CollectionSecurityPolicy memory);
function getWhitelistedOperators() external view returns (address[] memory);
function getPermittedContractReceivers() external view returns (address[] memory);
function isOperatorWhitelisted(address operator) external view returns (bool);
function isContractReceiverPermitted(address receiver) external view returns (bool);
function isTransferAllowed(address caller, address from, address to) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./IEOARegistry.sol";
import "./ITransferSecurityRegistry.sol";
import "./ITransferValidator.sol";
interface ICreatorTokenTransferValidator is ITransferSecurityRegistry, ITransferValidator, IEOARegistry {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "lib/openzeppelin-contracts/contracts/utils/Context.sol";
/**
* @title TransferValidation
* @author Limit Break, Inc.
* @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks.
* Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows
* developers to validate or customize transfers within the context of a mint, a burn, or a transfer.
*/
abstract contract TransferValidation is Context {
error ShouldNotMintToBurnAddress();
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if (fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if (fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, msg.value);
} else if (toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if (fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if (fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, msg.value);
} else if (toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value)
internal
virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value)
internal
virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.0;
import "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol)
library FixedPointMathLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error ExpOverflow();
/// @dev The operation failed, as the output exceeds the maximum value of uint256.
error FactorialOverflow();
/// @dev The operation failed, due to an overflow.
error RPowOverflow();
/// @dev The mantissa is too big to fit.
error MantissaOverflow();
/// @dev The operation failed, due to an multiplication overflow.
error MulWadFailed();
/// @dev The operation failed, due to an multiplication overflow.
error SMulWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error DivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error SDivWadFailed();
/// @dev The operation failed, either due to a multiplication overflow, or a division by a zero.
error MulDivFailed();
/// @dev The division failed, as the denominator is zero.
error DivFailed();
/// @dev The full precision multiply-divide operation failed, either due
/// to the result being larger than 256 bits, or a division by a zero.
error FullMulDivFailed();
/// @dev The output is undefined, as the input is less-than-or-equal to zero.
error LnWadUndefined();
/// @dev The input outside the acceptable domain.
error OutOfDomain();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The scalar of ETH and most ERC20s.
uint256 internal constant WAD = 1e18;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIMPLIFIED FIXED POINT OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function mulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if gt(x, div(not(0), y)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down.
function sMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require((x == 0 || z / x == y) && !(x == -1 && y == type(int256).min))`.
if iszero(gt(or(iszero(x), eq(sdiv(z, x), y)), lt(not(x), eq(y, shl(255, 1))))) {
mstore(0x00, 0xedcd4dd4) // `SMulWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawMulWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded down, but without overflow checks.
function rawSMulWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, y), WAD)
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up.
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
if iszero(eq(div(z, y), x)) {
if y {
mstore(0x00, 0xbac65e5b) // `MulWadFailed()`.
revert(0x1c, 0x04)
}
}
z := add(iszero(iszero(mod(z, WAD))), div(z, WAD))
}
}
/// @dev Equivalent to `(x * y) / WAD` rounded up, but without overflow checks.
function rawMulWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, y), WAD))), div(mul(x, y), WAD))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function divWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down.
function sDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, WAD)
// Equivalent to `require(y != 0 && ((x * WAD) / WAD == x))`.
if iszero(mul(y, eq(sdiv(z, WAD), x))) {
mstore(0x00, 0x5c43740d) // `SDivWadFailed()`.
revert(0x1c, 0x04)
}
z := sdiv(z, y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawDivWad(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded down, but without overflow and divide by zero checks.
function rawSDivWad(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(mul(x, WAD), y)
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up.
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `require(y != 0 && x <= type(uint256).max / WAD)`.
if iszero(mul(y, lt(x, add(1, div(not(0), WAD))))) {
mstore(0x00, 0x7c5f487d) // `DivWadFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `(x * WAD) / y` rounded up, but without overflow and divide by zero checks.
function rawDivWadUp(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(iszero(iszero(mod(mul(x, WAD), y))), div(mul(x, WAD), y))
}
}
/// @dev Equivalent to `x` to the power of `y`.
/// because `x ** y = (e ** ln(x)) ** y = e ** (ln(x) * y)`.
/// Note: This function is an approximation.
function powWad(int256 x, int256 y) internal pure returns (int256) {
// Using `ln(x)` means `x` must be greater than 0.
return expWad((lnWad(x) * y) / int256(WAD));
}
/// @dev Returns `exp(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function expWad(int256 x) internal pure returns (int256 r) {
unchecked {
// When the result is less than 0.5 we return zero.
// This happens when `x <= (log(1e-18) * 1e18) ~ -4.15e19`.
if (x <= -41446531673892822313) return r;
/// @solidity memory-safe-assembly
assembly {
// When the result is greater than `(2**255 - 1) / 1e18` we can not represent it as
// an int. This happens when `x >= floor(log((2**255 - 1) / 1e18) * 1e18) ≈ 135`.
if iszero(slt(x, 135305999368893231589)) {
mstore(0x00, 0xa37bfec9) // `ExpOverflow()`.
revert(0x1c, 0x04)
}
}
// `x` is now in the range `(-42, 136) * 1e18`. Convert to `(-42, 136) * 2**96`
// for more intermediate precision and a binary basis. This base conversion
// is a multiplication by 1e18 / 2**96 = 5**18 / 2**78.
x = (x << 78) / 5 ** 18;
// Reduce range of x to (-½ ln 2, ½ ln 2) * 2**96 by factoring out powers
// of two such that exp(x) = exp(x') * 2**k, where k is an integer.
// Solving this gives k = round(x / log(2)) and x' = x - k * log(2).
int256 k = ((x << 96) / 54916777467707473351141471128 + 2 ** 95) >> 96;
x = x - k * 54916777467707473351141471128;
// `k` is in the range `[-61, 195]`.
// Evaluate using a (6, 7)-term rational approximation.
// `p` is made monic, we'll multiply by a scale factor later.
int256 y = x + 1346386616545796478920950773328;
y = ((y * x) >> 96) + 57155421227552351082224309758442;
int256 p = y + x - 94201549194550492254356042504812;
p = ((p * y) >> 96) + 28719021644029726153956944680412240;
p = p * x + (4385272521454847904659076985693276 << 96);
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
int256 q = x - 2855989394907223263936484059900;
q = ((q * x) >> 96) + 50020603652535783019961831881945;
q = ((q * x) >> 96) - 533845033583426703283633433725380;
q = ((q * x) >> 96) + 3604857256930695427073651918091429;
q = ((q * x) >> 96) - 14423608567350463180887372962807573;
q = ((q * x) >> 96) + 26449188498355588339934803723976023;
/// @solidity memory-safe-assembly
assembly {
// Div in assembly because solidity adds a zero check despite the unchecked.
// The q polynomial won't have zeros in the domain as all its roots are complex.
// No scaling is necessary because p is already `2**96` too large.
r := sdiv(p, q)
}
// r should be in the range `(0.09, 0.25) * 2**96`.
// We now need to multiply r by:
// - The scale factor `s ≈ 6.031367120`.
// - The `2**k` factor from the range reduction.
// - The `1e18 / 2**96` factor for base conversion.
// We do this all at once, with an intermediate result in `2**213`
// basis, so the final right shift is always by a positive amount.
r = int256(
(uint256(r) * 3822833074963236453042738258902158003155416615667) >> uint256(195 - k)
);
}
}
/// @dev Returns `ln(x)`, denominated in `WAD`.
/// Credit to Remco Bloemen under MIT license: https://2π.com/22/exp-ln
/// Note: This function is an approximation. Monotonically increasing.
function lnWad(int256 x) internal pure returns (int256 r) {
/// @solidity memory-safe-assembly
assembly {
// We want to convert `x` from `10**18` fixed point to `2**96` fixed point.
// We do this by multiplying by `2**96 / 10**18`. But since
// `ln(x * C) = ln(x) + ln(C)`, we can simply do nothing here
// and add `ln(2**96 / 10**18)` at the end.
// Compute `k = log2(x) - 96`, `r = 159 - k = 255 - log2(x) = 255 ^ log2(x)`.
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// We place the check here for more optimal stack operations.
if iszero(sgt(x, 0)) {
mstore(0x00, 0x1615e638) // `LnWadUndefined()`.
revert(0x1c, 0x04)
}
// forgefmt: disable-next-item
r := xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff))
// Reduce range of x to (1, 2) * 2**96
// ln(2^k * x) = k * ln(2) + ln(x)
x := shr(159, shl(r, x))
// Evaluate using a (8, 8)-term rational approximation.
// `p` is made monic, we will multiply by a scale factor later.
// forgefmt: disable-next-item
let p := sub( // This heavily nested expression is to avoid stack-too-deep for via-ir.
sar(96, mul(add(43456485725739037958740375743393,
sar(96, mul(add(24828157081833163892658089445524,
sar(96, mul(add(3273285459638523848632254066296,
x), x))), x))), x)), 11111509109440967052023855526967)
p := sub(sar(96, mul(p, x)), 45023709667254063763336534515857)
p := sub(sar(96, mul(p, x)), 14706773417378608786704636184526)
p := sub(mul(p, x), shl(96, 795164235651350426258249787498))
// We leave `p` in `2**192` basis so we don't need to scale it back up for the division.
// `q` is monic by convention.
let q := add(5573035233440673466300451813936, x)
q := add(71694874799317883764090561454958, sar(96, mul(x, q)))
q := add(283447036172924575727196451306956, sar(96, mul(x, q)))
q := add(401686690394027663651624208769553, sar(96, mul(x, q)))
q := add(204048457590392012362485061816622, sar(96, mul(x, q)))
q := add(31853899698501571402653359427138, sar(96, mul(x, q)))
q := add(909429971244387300277376558375, sar(96, mul(x, q)))
// `p / q` is in the range `(0, 0.125) * 2**96`.
// Finalization, we need to:
// - Multiply by the scale factor `s = 5.549…`.
// - Add `ln(2**96 / 10**18)`.
// - Add `k * ln(2)`.
// - Multiply by `10**18 / 2**96 = 5**18 >> 78`.
// The q polynomial is known not to have zeros in the domain.
// No scaling required because p is already `2**96` too large.
p := sdiv(p, q)
// Multiply by the scaling factor: `s * 5**18 * 2**96`, base is now `5**18 * 2**192`.
p := mul(1677202110996718588342820967067443963516166, p)
// Add `ln(2) * k * 5**18 * 2**192`.
// forgefmt: disable-next-item
p := add(mul(16597577552685614221487285958193947469193820559219878177908093499208371, sub(159, r)), p)
// Add `ln(2**96 / 10**18) * 5**18 * 2**192`.
p := add(600920179829731861736702779321621459595472258049074101567377883020018308, p)
// Base conversion: mul `2**18 / 2**192`.
r := sar(174, p)
}
}
/// @dev Returns `W_0(x)`, denominated in `WAD`.
/// See: https://en.wikipedia.org/wiki/Lambert_W_function
/// a.k.a. Product log function. This is an approximation of the principal branch.
/// Note: This function is an approximation. Monotonically increasing.
function lambertW0Wad(int256 x) internal pure returns (int256 w) {
// forgefmt: disable-next-item
unchecked {
if ((w = x) <= -367879441171442322) revert OutOfDomain(); // `x` less than `-1/e`.
(int256 wad, int256 p) = (int256(WAD), x);
uint256 c; // Whether we need to avoid catastrophic cancellation.
uint256 i = 4; // Number of iterations.
if (w <= 0x1ffffffffffff) {
if (-0x4000000000000 <= w) {
i = 1; // Inputs near zero only take one step to converge.
} else if (w <= -0x3ffffffffffffff) {
i = 32; // Inputs near `-1/e` take very long to converge.
}
} else if (uint256(w >> 63) == uint256(0)) {
/// @solidity memory-safe-assembly
assembly {
// Inline log2 for more performance, since the range is small.
let v := shr(49, w)
let l := shl(3, lt(0xff, v))
l := add(or(l, byte(and(0x1f, shr(shr(l, v), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000)), 49)
w := sdiv(shl(l, 7), byte(sub(l, 31), 0x0303030303030303040506080c13))
c := gt(l, 60)
i := add(2, add(gt(l, 53), c))
}
} else {
int256 ll = lnWad(w = lnWad(w));
/// @solidity memory-safe-assembly
assembly {
// `w = ln(x) - ln(ln(x)) + b * ln(ln(x)) / ln(x)`.
w := add(sdiv(mul(ll, 1023715080943847266), w), sub(w, ll))
i := add(3, iszero(shr(68, x)))
c := iszero(shr(143, x))
}
if (c == uint256(0)) {
do { // If `x` is big, use Newton's so that intermediate values won't overflow.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := mul(w, div(e, wad))
w := sub(w, sdiv(sub(t, x), div(add(e, t), wad)))
}
if (p <= w) break;
p = w;
} while (--i != uint256(0));
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
return w;
}
}
do { // Otherwise, use Halley's for faster convergence.
int256 e = expWad(w);
/// @solidity memory-safe-assembly
assembly {
let t := add(w, wad)
let s := sub(mul(w, e), mul(x, wad))
w := sub(w, sdiv(mul(s, wad), sub(mul(e, t), sdiv(mul(add(t, wad), s), add(t, t)))))
}
if (p <= w) break;
p = w;
} while (--i != c);
/// @solidity memory-safe-assembly
assembly {
w := sub(w, sgt(w, 2))
}
// For certain ranges of `x`, we'll use the quadratic-rate recursive formula of
// R. Iacono and J.P. Boyd for the last iteration, to avoid catastrophic cancellation.
if (c == uint256(0)) return w;
int256 t = w | 1;
/// @solidity memory-safe-assembly
assembly {
x := sdiv(mul(x, wad), t)
}
x = (t * (wad + lnWad(x)));
/// @solidity memory-safe-assembly
assembly {
w := sdiv(x, add(wad, t))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GENERAL NUMBER UTILITIES */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `a * b == x * y`, with full precision.
function fullMulEq(uint256 a, uint256 b, uint256 x, uint256 y)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
result := and(eq(mul(a, b), mul(x, y)), eq(mulmod(x, y, not(0)), mulmod(a, b, not(0))))
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Remco Bloemen under MIT license: https://2π.com/21/muldiv
function fullMulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// 512-bit multiply `[p1 p0] = x * y`.
// Compute the product mod `2**256` and mod `2**256 - 1`
// then use the Chinese Remainder Theorem to reconstruct
// the 512 bit result. The result is stored in two 256
// variables such that `product = p1 * 2**256 + p0`.
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`.
for {} 1 {} {
// If overflows.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
/*------------------- 512 by 256 division --------------------*/
// Make division exact by subtracting the remainder from `[p1 p0]`.
let r := mulmod(x, y, d) // Compute remainder using mulmod.
let t := and(d, sub(0, d)) // The least significant bit of `d`. `t >= 1`.
// Make sure `z` is less than `2**256`. Also prevents `d == 0`.
// Placing the check here seems to give more optimal stack operations.
if iszero(gt(d, p1)) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
d := div(d, t) // Divide `d` by `t`, which is a power of two.
// Invert `d mod 2**256`
// Now that `d` is an odd number, it has an inverse
// modulo `2**256` such that `d * inv = 1 mod 2**256`.
// Compute the inverse by starting with a seed that is correct
// correct for four bits. That is, `d * inv = 1 mod 2**4`.
let inv := xor(2, mul(3, d))
// Now use 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.
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**8
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**16
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**32
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**64
inv := mul(inv, sub(2, mul(d, inv))) // inverse mod 2**128
z :=
mul(
// Divide [p1 p0] by the factors of two.
// Shift in bits from `p1` into `p0`. For this we need
// to flip `t` such that it is `2**256 / t`.
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv) // inverse mod 2**256
)
break
}
z := div(z, d)
break
}
}
}
/// @dev Calculates `floor(x * y / d)` with full precision.
/// Behavior is undefined if `d` is zero or the final result cannot fit in 256 bits.
/// Performs the full 512 bit calculation regardless.
function fullMulDivUnchecked(uint256 x, uint256 y, uint256 d)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z)))
let t := and(d, sub(0, d))
let r := mulmod(x, y, d)
d := div(d, t)
let inv := xor(2, mul(3, d))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
inv := mul(inv, sub(2, mul(d, inv)))
z :=
mul(
or(mul(sub(p1, gt(r, z)), add(div(sub(0, t), t), 1)), div(sub(z, r), t)),
mul(sub(2, mul(d, inv)), inv)
)
}
}
/// @dev Calculates `floor(x * y / d)` with full precision, rounded up.
/// Throws if result overflows a uint256 or when `d` is zero.
/// Credit to Uniswap-v3-core under MIT license:
/// https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/FullMath.sol
function fullMulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
z = fullMulDiv(x, y, d);
/// @solidity memory-safe-assembly
assembly {
if mulmod(x, y, d) {
z := add(z, 1)
if iszero(z) {
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Calculates `floor(x * y / 2 ** n)` with full precision.
/// Throws if result overflows a uint256.
/// Credit to Philogy under MIT license:
/// https://github.com/SorellaLabs/angstrom/blob/main/contracts/src/libraries/X128MathLib.sol
function fullMulDivN(uint256 x, uint256 y, uint8 n) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// Temporarily use `z` as `p0` to save gas.
z := mul(x, y) // Lower 256 bits of `x * y`. We'll call this `z`.
for {} 1 {} {
if iszero(or(iszero(x), eq(div(z, x), y))) {
let k := and(n, 0xff) // `n`, cleaned.
let mm := mulmod(x, y, not(0))
let p1 := sub(mm, add(z, lt(mm, z))) // Upper 256 bits of `x * y`.
// | p1 | z |
// Before: | p1_0 ¦ p1_1 | z_0 ¦ z_1 |
// Final: | 0 ¦ p1_0 | p1_1 ¦ z_0 |
// Check that final `z` doesn't overflow by checking that p1_0 = 0.
if iszero(shr(k, p1)) {
z := add(shl(sub(256, k), p1), shr(k, z))
break
}
mstore(0x00, 0xae47f702) // `FullMulDivFailed()`.
revert(0x1c, 0x04)
}
z := shr(and(n, 0xff), z)
break
}
}
}
/// @dev Returns `floor(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDiv(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := div(z, d)
}
}
/// @dev Returns `ceil(x * y / d)`.
/// Reverts if `x * y` overflows, or `d` is zero.
function mulDivUp(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(x, y)
// Equivalent to `require(d != 0 && (y == 0 || x <= type(uint256).max / y))`.
if iszero(mul(or(iszero(x), eq(div(z, x), y)), d)) {
mstore(0x00, 0xad251c27) // `MulDivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(z, d))), div(z, d))
}
}
/// @dev Returns `x`, the modular multiplicative inverse of `a`, such that `(a * x) % n == 1`.
function invMod(uint256 a, uint256 n) internal pure returns (uint256 x) {
/// @solidity memory-safe-assembly
assembly {
let g := n
let r := mod(a, n)
for { let y := 1 } 1 {} {
let q := div(g, r)
let t := g
g := r
r := sub(t, mul(r, q))
let u := x
x := y
y := sub(u, mul(y, q))
if iszero(r) { break }
}
x := mul(eq(g, 1), add(x, mul(slt(x, 0), n)))
}
}
/// @dev Returns `ceil(x / d)`.
/// Reverts if `d` is zero.
function divUp(uint256 x, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
if iszero(d) {
mstore(0x00, 0x65244e4e) // `DivFailed()`.
revert(0x1c, 0x04)
}
z := add(iszero(iszero(mod(x, d))), div(x, d))
}
}
/// @dev Returns `max(0, x - y)`.
function zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(gt(x, y), sub(x, y))
}
}
/// @dev Returns `condition ? x : y`, without branching.
function ternary(bool condition, uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), iszero(condition)))
}
}
/// @dev Exponentiate `x` to `y` by squaring, denominated in base `b`.
/// Reverts if the computation overflows.
function rpow(uint256 x, uint256 y, uint256 b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mul(b, iszero(y)) // `0 ** 0 = 1`. Otherwise, `0 ** n = 0`.
if x {
z := xor(b, mul(xor(b, x), and(y, 1))) // `z = isEven(y) ? scale : x`
let half := shr(1, b) // Divide `b` by 2.
// Divide `y` by 2 every iteration.
for { y := shr(1, y) } y { y := shr(1, y) } {
let xx := mul(x, x) // Store x squared.
let xxRound := add(xx, half) // Round to the nearest number.
// Revert if `xx + half` overflowed, or if `x ** 2` overflows.
if or(lt(xxRound, xx), shr(128, x)) {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
x := div(xxRound, b) // Set `x` to scaled `xxRound`.
// If `y` is odd:
if and(y, 1) {
let zx := mul(z, x) // Compute `z * x`.
let zxRound := add(zx, half) // Round to the nearest number.
// If `z * x` overflowed or `zx + half` overflowed:
if or(xor(div(zx, x), z), lt(zxRound, zx)) {
// Revert if `x` is non-zero.
if x {
mstore(0x00, 0x49f7642b) // `RPowOverflow()`.
revert(0x1c, 0x04)
}
}
z := div(zxRound, b) // Return properly scaled `zxRound`.
}
}
}
}
}
/// @dev Returns the square root of `x`, rounded down.
function sqrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
// `floor(sqrt(2**15)) = 181`. `sqrt(2**15) - 181 = 2.84`.
z := 181 // The "correct" value is 1, but this saves a multiplication later.
// This segment is to get a reasonable initial estimate for the Babylonian method. With a bad
// start, the correct # of bits increases ~linearly each iteration instead of ~quadratically.
// Let `y = x / 2**r`. We check `y >= 2**(k + 8)`
// but shift right by `k` bits to ensure that if `x >= 256`, then `y >= 256`.
let r := shl(7, lt(0xffffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffffff, shr(r, x))))
z := shl(shr(1, r), z)
// Goal was to get `z*z*y` within a small factor of `x`. More iterations could
// get y in a tighter range. Currently, we will have y in `[256, 256*(2**16))`.
// We ensured `y >= 256` so that the relative difference between `y` and `y+1` is small.
// That's not possible if `x < 256` but we can just verify those cases exhaustively.
// Now, `z*z*y <= x < z*z*(y+1)`, and `y <= 2**(16+8)`, and either `y >= 256`, or `x < 256`.
// Correctness can be checked exhaustively for `x < 256`, so we assume `y >= 256`.
// Then `z*sqrt(y)` is within `sqrt(257)/sqrt(256)` of `sqrt(x)`, or about 20bps.
// For `s` in the range `[1/256, 256]`, the estimate `f(s) = (181/1024) * (s+1)`
// is in the range `(1/2.84 * sqrt(s), 2.84 * sqrt(s))`,
// with largest error when `s = 1` and when `s = 256` or `1/256`.
// Since `y` is in `[256, 256*(2**16))`, let `a = y/65536`, so that `a` is in `[1/256, 256)`.
// Then we can estimate `sqrt(y)` using
// `sqrt(65536) * 181/1024 * (a + 1) = 181/4 * (y + 65536)/65536 = 181 * (y + 65536)/2**18`.
// There is no overflow risk here since `y < 2**136` after the first branch above.
z := shr(18, mul(z, add(shr(r, x), 65536))) // A `mul()` is saved from starting `z` at 181.
// Given the worst case multiplicative error of 2.84 above, 7 iterations should be enough.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// If `x+1` is a perfect square, the Babylonian method cycles between
// `floor(sqrt(x))` and `ceil(sqrt(x))`. This statement ensures we return floor.
// See: https://en.wikipedia.org/wiki/Integer_square_root#Using_only_integer_division
z := sub(z, lt(div(x, z), z))
}
}
/// @dev Returns the cube root of `x`, rounded down.
/// Credit to bout3fiddy and pcaversaccio under AGPLv3 license:
/// https://github.com/pcaversaccio/snekmate/blob/main/src/utils/Math.vy
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrt(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
let r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// Makeshift lookup table to nudge the approximate log2 result.
z := div(shl(div(r, 3), shl(lt(0xf, shr(r, x)), 0xf)), xor(7, mod(r, 3)))
// Newton-Raphson's.
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
z := div(add(add(div(x, mul(z, z)), z), z), 3)
// Round down.
z := sub(z, lt(div(x, mul(z, z)), z))
}
}
/// @dev Returns the square root of `x`, denominated in `WAD`, rounded down.
function sqrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 18) return sqrt(x * 10 ** 18);
z = (1 + sqrt(x)) * 10 ** 9;
z = (fullMulDivUnchecked(x, 10 ** 18, z) + z) >> 1;
}
/// @solidity memory-safe-assembly
assembly {
z := sub(z, gt(999999999999999999, sub(mulmod(z, z, x), 1))) // Round down.
}
}
/// @dev Returns the cube root of `x`, denominated in `WAD`, rounded down.
/// Formally verified by xuwinnie:
/// https://github.com/vectorized/solady/blob/main/audits/xuwinnie-solady-cbrt-proof.pdf
function cbrtWad(uint256 x) internal pure returns (uint256 z) {
unchecked {
if (x <= type(uint256).max / 10 ** 36) return cbrt(x * 10 ** 36);
z = (1 + cbrt(x)) * 10 ** 12;
z = (fullMulDivUnchecked(x, 10 ** 36, z * z) + z + z) / 3;
}
/// @solidity memory-safe-assembly
assembly {
let p := x
for {} 1 {} {
if iszero(shr(229, p)) {
if iszero(shr(199, p)) {
p := mul(p, 100000000000000000) // 10 ** 17.
break
}
p := mul(p, 100000000) // 10 ** 8.
break
}
if iszero(shr(249, p)) { p := mul(p, 100) }
break
}
let t := mulmod(mul(z, z), z, p)
z := sub(z, gt(lt(t, shr(1, p)), iszero(t))) // Round down.
}
}
/// @dev Returns the factorial of `x`.
function factorial(uint256 x) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := 1
if iszero(lt(x, 58)) {
mstore(0x00, 0xaba0f2a2) // `FactorialOverflow()`.
revert(0x1c, 0x04)
}
for {} x { x := sub(x, 1) } { z := mul(z, x) }
}
}
/// @dev Returns the log2 of `x`.
/// Equivalent to computing the index of the most significant bit (MSB) of `x`.
/// Returns 0 if `x` is zero.
function log2(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Returns the log2 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log2Up(uint256 x) internal pure returns (uint256 r) {
r = log2(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(r, 1), x))
}
}
/// @dev Returns the log10 of `x`.
/// Returns 0 if `x` is zero.
function log10(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
if iszero(lt(x, 100000000000000000000000000000000000000)) {
x := div(x, 100000000000000000000000000000000000000)
r := 38
}
if iszero(lt(x, 100000000000000000000)) {
x := div(x, 100000000000000000000)
r := add(r, 20)
}
if iszero(lt(x, 10000000000)) {
x := div(x, 10000000000)
r := add(r, 10)
}
if iszero(lt(x, 100000)) {
x := div(x, 100000)
r := add(r, 5)
}
r := add(r, add(gt(x, 9), add(gt(x, 99), add(gt(x, 999), gt(x, 9999)))))
}
}
/// @dev Returns the log10 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log10Up(uint256 x) internal pure returns (uint256 r) {
r = log10(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(exp(10, r), x))
}
}
/// @dev Returns the log256 of `x`.
/// Returns 0 if `x` is zero.
function log256(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(shr(3, r), lt(0xff, shr(r, x)))
}
}
/// @dev Returns the log256 of `x`, rounded up.
/// Returns 0 if `x` is zero.
function log256Up(uint256 x) internal pure returns (uint256 r) {
r = log256(x);
/// @solidity memory-safe-assembly
assembly {
r := add(r, lt(shl(shl(3, r), 1), x))
}
}
/// @dev Returns the scientific notation format `mantissa * 10 ** exponent` of `x`.
/// Useful for compressing prices (e.g. using 25 bit mantissa and 7 bit exponent).
function sci(uint256 x) internal pure returns (uint256 mantissa, uint256 exponent) {
/// @solidity memory-safe-assembly
assembly {
mantissa := x
if mantissa {
if iszero(mod(mantissa, 1000000000000000000000000000000000)) {
mantissa := div(mantissa, 1000000000000000000000000000000000)
exponent := 33
}
if iszero(mod(mantissa, 10000000000000000000)) {
mantissa := div(mantissa, 10000000000000000000)
exponent := add(exponent, 19)
}
if iszero(mod(mantissa, 1000000000000)) {
mantissa := div(mantissa, 1000000000000)
exponent := add(exponent, 12)
}
if iszero(mod(mantissa, 1000000)) {
mantissa := div(mantissa, 1000000)
exponent := add(exponent, 6)
}
if iszero(mod(mantissa, 10000)) {
mantissa := div(mantissa, 10000)
exponent := add(exponent, 4)
}
if iszero(mod(mantissa, 100)) {
mantissa := div(mantissa, 100)
exponent := add(exponent, 2)
}
if iszero(mod(mantissa, 10)) {
mantissa := div(mantissa, 10)
exponent := add(exponent, 1)
}
}
}
}
/// @dev Convenience function for packing `x` into a smaller number using `sci`.
/// The `mantissa` will be in bits [7..255] (the upper 249 bits).
/// The `exponent` will be in bits [0..6] (the lower 7 bits).
/// Use `SafeCastLib` to safely ensure that the `packed` number is small
/// enough to fit in the desired unsigned integer type:
/// ```
/// uint32 packed = SafeCastLib.toUint32(FixedPointMathLib.packSci(777 ether));
/// ```
function packSci(uint256 x) internal pure returns (uint256 packed) {
(x, packed) = sci(x); // Reuse for `mantissa` and `exponent`.
/// @solidity memory-safe-assembly
assembly {
if shr(249, x) {
mstore(0x00, 0xce30380c) // `MantissaOverflow()`.
revert(0x1c, 0x04)
}
packed := or(shl(7, x), packed)
}
}
/// @dev Convenience function for unpacking a packed number from `packSci`.
function unpackSci(uint256 packed) internal pure returns (uint256 unpacked) {
unchecked {
unpacked = (packed >> 7) * 10 ** (packed & 0x7f);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards zero.
function avg(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = (x & y) + ((x ^ y) >> 1);
}
}
/// @dev Returns the average of `x` and `y`. Rounds towards negative infinity.
function avg(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = (x >> 1) + (y >> 1) + (x & y & 1);
}
}
/// @dev Returns the absolute value of `x`.
function abs(int256 x) internal pure returns (uint256 z) {
unchecked {
z = (uint256(x) + uint256(x >> 255)) ^ uint256(x >> 255);
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, gt(x, y)), sub(y, x)), gt(x, y))
}
}
/// @dev Returns the absolute distance between `x` and `y`.
function dist(int256 x, int256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := add(xor(sub(0, sgt(x, y)), sub(y, x)), sgt(x, y))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), lt(y, x)))
}
}
/// @dev Returns the minimum of `x` and `y`.
function min(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), slt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), gt(y, x)))
}
}
/// @dev Returns the maximum of `x` and `y`.
function max(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, y), sgt(y, x)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(uint256 x, uint256 minValue, uint256 maxValue)
internal
pure
returns (uint256 z)
{
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), gt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), lt(maxValue, z)))
}
}
/// @dev Returns `x`, bounded to `minValue` and `maxValue`.
function clamp(int256 x, int256 minValue, int256 maxValue) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := xor(x, mul(xor(x, minValue), sgt(minValue, x)))
z := xor(z, mul(xor(z, maxValue), slt(maxValue, z)))
}
}
/// @dev Returns greatest common divisor of `x` and `y`.
function gcd(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
for { z := x } y {} {
let t := y
y := mod(z, y)
z := t
}
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`,
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(uint256 a, uint256 b, uint256 t, uint256 begin, uint256 end)
internal
pure
returns (uint256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
unchecked {
if (b >= a) return a + fullMulDiv(b - a, t - begin, end - begin);
return a - fullMulDiv(a - b, t - begin, end - begin);
}
}
/// @dev Returns `a + (b - a) * (t - begin) / (end - begin)`.
/// with `t` clamped between `begin` and `end` (inclusive).
/// Agnostic to the order of (`a`, `b`) and (`end`, `begin`).
/// If `begins == end`, returns `t <= begin ? a : b`.
function lerp(int256 a, int256 b, int256 t, int256 begin, int256 end)
internal
pure
returns (int256)
{
if (begin > end) (t, begin, end) = (~t, ~begin, ~end);
if (t <= begin) return a;
if (t >= end) return b;
// forgefmt: disable-next-item
unchecked {
if (b >= a) return int256(uint256(a) + fullMulDiv(uint256(b - a),
uint256(t - begin), uint256(end - begin)));
return int256(uint256(a) - fullMulDiv(uint256(a - b),
uint256(t - begin), uint256(end - begin)));
}
}
/// @dev Returns if `x` is an even number. Some people may need this.
function isEven(uint256 x) internal pure returns (bool) {
return x & uint256(1) == uint256(0);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RAW NUMBER OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x + y`, without checking for overflow.
function rawAdd(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x + y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x - y`, without checking for underflow.
function rawSub(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x - y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(uint256 x, uint256 y) internal pure returns (uint256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x * y`, without checking for overflow.
function rawMul(int256 x, int256 y) internal pure returns (int256 z) {
unchecked {
z = x * y;
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function rawSDiv(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := sdiv(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawMod(uint256 x, uint256 y) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function rawSMod(int256 x, int256 y) internal pure returns (int256 z) {
/// @solidity memory-safe-assembly
assembly {
z := smod(x, y)
}
}
/// @dev Returns `(x + y) % d`, return 0 if `d` if zero.
function rawAddMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := addmod(x, y, d)
}
}
/// @dev Returns `(x * y) % d`, return 0 if `d` if zero.
function rawMulMod(uint256 x, uint256 y, uint256 d) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mulmod(x, y, d)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBytes} from "./LibBytes.sol";
/// @notice Library for converting numbers into strings and other string operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
///
/// @dev Note:
/// For performance and bytecode compactness, most of the string operations are restricted to
/// byte strings (7-bit ASCII), except where otherwise specified.
/// Usage of byte string operations on charsets with runes spanning two or more bytes
/// can lead to undefined behavior.
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated string storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct StringStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/// @dev The input string must be a 7-bit ASCII.
error StringNot7BitASCII();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
/// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
/// @dev Lookup for '0123456789'.
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
/// @dev Lookup for '0123456789abcdefABCDEF'.
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
/// @dev Lookup for '01234567'.
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
/// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
/// @dev Lookup for ' \t\n\r\x0b\x0c'.
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRING STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the string storage `$` to `s`.
function set(StringStorage storage $, string memory s) internal {
LibBytes.set(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to `s`.
function setCalldata(StringStorage storage $, string calldata s) internal {
LibBytes.setCalldata(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to the empty string.
function clear(StringStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty string "".
function isEmpty(StringStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(StringStorage storage $) internal view returns (uint256) {
return LibBytes.length(bytesStorage($));
}
/// @dev Returns the value stored in `$`.
function get(StringStorage storage $) internal view returns (string memory) {
return string(LibBytes.get(bytesStorage($)));
}
/// @dev Helper to cast `$` to a `BytesStorage`.
function bytesStorage(StringStorage storage $)
internal
pure
returns (LibBytes.BytesStorage storage casted)
{
/// @solidity memory-safe-assembly
assembly {
casted.slot := $.slot
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end of the memory to calculate the length later.
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 1)`.
// Store the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10) // Keep dividing `temp` until zero.
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = toString(~uint256(value) + 1);
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let n := mload(result) // Load the string length.
mstore(result, 0x2d) // Store the '-' character.
result := sub(result, 1) // Move back the string pointer by a byte.
mstore(result, add(n, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2 + 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, byteCount);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(byteCount, byteCount))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := add(mload(result), 2) // Compute the length.
mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := mload(result) // Get the length.
result := add(result, o) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory result) {
result = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(result, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Allocate memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
result := add(result, 2)
mstore(result, 40) // Store the length.
let o := add(result, 0x20)
mstore(add(o, 40), 0) // Zeroize the slot after the string.
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory result) {
result = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(raw)
result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(result, add(n, n)) // Store the length of the output.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let o := add(result, 0x20)
let end := add(raw, n)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
let mask := shl(7, div(not(0), 255))
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string,
/// AND all characters are in the `allowed` lookup.
/// Note: If `s` is empty, returns true regardless of `allowed`.
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
/// @dev Converts the bytes in the 7-bit ASCII string `s` to
/// an allowed lookup for use in `is7BitASCII(s, allowed)`.
/// To save runtime gas, you can cache the result in an immutable variable.
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
revert(0x1c, 0x04)
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory)
{
return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.indexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.contains(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.startsWith(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.endsWith(bytes(subject), bytes(needle));
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
return string(LibBytes.repeat(bytes(subject), times));
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory)
{
return string(LibBytes.slice(bytes(subject), start, end));
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start) internal pure returns (string memory) {
return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory)
{
return LibBytes.indicesOf(bytes(subject), bytes(needle));
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
/// @solidity memory-safe-assembly
assembly {
result := a
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b) internal pure returns (string memory) {
return string(LibBytes.concat(bytes(a), bytes(b)));
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n) // Store the length.
let o := add(result, 0x20)
mstore(o, s) // Store the bytes of the string.
mstore(add(o, n), 0) // Zeroize the slot after the string.
mstore(0x40, add(result, 0x40)) // Allocate memory.
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), c)
o := add(o, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(o, mload(0x19)) // "\\u00XX".
o := add(o, 6)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Encodes `s` so that it can be safely used in a URI,
/// just like `encodeURIComponent` in JavaScript.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
/// See: https://datatracker.ietf.org/doc/html/rfc2396
/// See: https://datatracker.ietf.org/doc/html/rfc3986
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Store "0123456789ABCDEF" in scratch space.
// Uppercased to be consistent with JavaScript's implementation.
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// If not in `[0-9A-Z-a-z-_.!~*'()]`.
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25) // '%'.
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40) // Grab the free memory pointer.
mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
mstore(result, 0) // Zeroize the length slot.
mstore(add(result, 0x1f), packed) // Store the length and bytes.
mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
or( // Load the length and the bytes of `a` and `b`.
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
// `totalLen != 0 && totalLen < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLen, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
resultA := mload(0x40) // Grab the free memory pointer.
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./Append.sol";
import "./Structs.sol";
import "./LICENSE.sol";
// by no_side666
library LibDynamicJSONKVArr {
struct LinkedKVs {
LibDynamicThing.LinkedThings lks;
LibDynamicThing.LinkedThings lvs;
}
function newDynamicKVArr() internal pure returns (LinkedKVs memory ret) {
ret = LinkedKVs(LibDynamicThing.newLinkedThings(), LibDynamicThing.newLinkedThings());
}
function p(LinkedKVs memory lkvs, bytes memory kData, bytes memory vData) internal pure {
p(lkvs, kData, vData, JSONType.STRING);
}
function p(LinkedKVs memory lkvs, bytes memory kData, bytes memory vData, JSONType valueType) internal pure {
if (vData.length < 1) return; // note: don't forget it ignores kvs with trivial value!!
JSON memory k = JSON(JSONType.STRING, kData);
JSON memory v = JSON(valueType, vData);
uint256 kPtr;
uint256 vPtr;
assembly {
kPtr := k
vPtr := v
}
LibDynamicThing.p(lkvs.lks, kPtr);
LibDynamicThing.p(lkvs.lvs, vPtr);
}
function dump(LinkedKVs memory lkvs) internal pure returns (JSON[][2] memory aakvs) {
uint256[] memory kPtrs = LibDynamicThing.dump(lkvs.lks);
uint256[] memory vPtrs = LibDynamicThing.dump(lkvs.lvs);
JSON[] memory ks;
JSON[] memory vs;
assembly {
ks := kPtrs
vs := vPtrs
}
aakvs[0] = ks;
aakvs[1] = vs;
}
}
library LibDynamicKVArr {
struct LinkedKVs {
LibDynamicThing.LinkedThings lks;
LibDynamicThing.LinkedThings lvs;
}
function newDynamicKVArr() internal pure returns (LinkedKVs memory ret) {
ret = LinkedKVs(LibDynamicThing.newLinkedThings(), LibDynamicThing.newLinkedThings());
}
function p(LinkedKVs memory lkvs, bytes memory kData, bytes memory vData) internal pure {
if (vData.length < 1) return; // note: don't forget it ignores kvs with trivial value!!
uint256 kPtr;
uint256 vPtr;
assembly {
kPtr := kData
vPtr := vData
}
LibDynamicThing.p(lkvs.lks, kPtr);
LibDynamicThing.p(lkvs.lvs, vPtr);
}
function dump(LinkedKVs memory lkvs) internal pure returns (bytes[][2] memory aakvs) {
uint256[] memory kPtrs = LibDynamicThing.dump(lkvs.lks);
uint256[] memory vPtrs = LibDynamicThing.dump(lkvs.lvs);
bytes[] memory ks;
bytes[] memory vs;
assembly {
ks := kPtrs
vs := vPtrs
}
aakvs[0] = ks;
aakvs[1] = vs;
}
}
library LibDynamicBytesArr {
struct LinkedBytes {
LibDynamicThing.LinkedThings ldt;
}
function newDynamicBytesArr() internal pure returns (LinkedBytes memory ret) {
return LinkedBytes(LibDynamicThing.newLinkedThings());
}
function p(LinkedBytes memory ls, bytes memory b) internal pure {
uint256 ptr;
assembly {
ptr := b
}
LibDynamicThing.p(ls.ldt, ptr);
}
function dump(LinkedBytes memory lb) internal pure returns (bytes[] memory ret) {
uint256[] memory ptrs = LibDynamicThing.dump(lb.ldt);
uint256 length = ptrs.length;
ret = _allocateArr(length);
assembly {
for { let i := 0 } 1 {} {
// hail solady
let ptr := mload(add(ptrs, add(0x20, mul(i, 0x20))))
mstore(add(ret, add(0x20, mul(i, 0x20))), ptr)
i := add(i, 1)
if iszero(lt(i, length)) { break }
}
}
/* // does this
uint256 length = ptrs.length;
ret = new string[](length);
uint256 ptr;
string memory str;
for (uint256 i; i < length; ++i) {
ptr = ptrs[i];
assembly {
str := ptr
}
ret[i] = str;
}
*/
}
function shift(LinkedBytes memory lb) internal pure returns (bytes memory ret) {
uint256 ptr = LibDynamicThing.shift(lb.ldt);
if (ptr == 0) return ret;
assembly {
ret := ptr
}
}
}
library LibDynamicStringArr {
struct LinkedStrings {
LibDynamicThing.LinkedThings ldt;
}
function newDynamicStringArr() internal pure returns (LinkedStrings memory ret) {
return LinkedStrings(LibDynamicThing.newLinkedThings());
}
function p(LinkedStrings memory ls, string memory str) internal pure {
uint256 ptr;
assembly {
ptr := str
}
LibDynamicThing.p(ls.ldt, ptr);
}
function dump(LinkedStrings memory ls) internal pure returns (string[] memory ret) {
uint256[] memory ptrs = LibDynamicThing.dump(ls.ldt);
uint256 length = ptrs.length;
ret = _allocateStringArr(length);
assembly {
for { let i := 0 } 1 {} {
// hail solady
let ptr := mload(add(ptrs, add(0x20, mul(i, 0x20))))
mstore(add(ret, add(0x20, mul(i, 0x20))), ptr)
i := add(i, 1)
if iszero(lt(i, length)) { break }
}
}
/* // does this
uint256 length = ptrs.length;
ret = new string[](length);
uint256 ptr;
string memory str;
for (uint256 i; i < length; ++i) {
ptr = ptrs[i];
assembly {
str := ptr
}
ret[i] = str;
}
*/
}
}
library LibDynamicUint256Arr {
struct LinkedUint256s {
LibDynamicThing.LinkedThings ldt;
}
function newDynamicUint256Arr() internal pure returns (LinkedUint256s memory ret) {
return LinkedUint256s(LibDynamicThing.newLinkedThings());
}
function p(LinkedUint256s memory ls, uint256 n) internal pure {
LibDynamicThing.p(ls.ldt, n);
}
function dump(LinkedUint256s memory ls) internal pure returns (uint256[] memory ret) {
ret = LibDynamicThing.dump(ls.ldt);
}
}
library LibDynamicInt256Arr {
struct LinkedInt256s {
LibDynamicThing.LinkedThings ldt;
}
function newDynamicInt256Arr() internal pure returns (LinkedInt256s memory ret) {
return LinkedInt256s(LibDynamicThing.newLinkedThings());
}
function p(LinkedInt256s memory ls, int256 n) internal pure {
// forge-lint: disable-next-line(unsafe-typecast)
LibDynamicThing.p(ls.ldt, uint256(n));
}
function dump(LinkedInt256s memory ls) internal pure returns (int256[] memory ret) {
uint256[] memory preRet = LibDynamicThing.dump(ls.ldt);
assembly {
ret := preRet
}
}
}
library LibDynamicBuffer {
struct DynamicBuffer {
uint256 numThings; // not used. but for some reason having it as buffer reduces gas!?
uint256 first;
uint256 last;
}
struct Thing {
uint256 ptr;
uint256 next;
}
function newDynamicBuffer() internal pure returns (DynamicBuffer memory ret) {
Thing memory first;
assembly {
mstore(add(ret, 0x20), first)
mstore(add(ret, 0x40), first)
}
}
function p(DynamicBuffer memory ls, bytes memory data) internal pure {
LibDynamicThing.Thing memory t;
assembly {
mstore(t, data)
let newPtr := t
let lastPtr := mload(add(ls, 0x40))
mstore(add(lastPtr, 0x20), newPtr)
mstore(add(ls, 0x40), newPtr)
}
}
// will need concat but had issues w it so deprecated it
function getBuffer(DynamicBuffer memory lts) internal pure returns (bytes memory ret) {
assembly {
ret := mload(0x40)
let len := 0x20 // offset
let nextPtr := mload(add(lts, 0x20)) // lt.first
for {} 1 {} {
nextPtr := mload(add(nextPtr, 0x20)) // ptr to next LinkedThing
if iszero(nextPtr) { break }
let ptr := mload(nextPtr) // ptr to actual thing
mcopy(add(ret, len), add(ptr, 0x20), mload(ptr))
len := add(len, mload(ptr))
}
mstore(0x40, add(ret, and(add(len, 0x1f), not(0x1f))))
mstore(ret, sub(len, 0x20))
}
}
}
library LibDynamicThing {
struct LinkedThings {
uint256 numThings;
uint256 first;
uint256 last;
}
struct Thing {
uint256 ptr;
uint256 next;
}
// will need concat but had issues w it so deprecated it
function newLinkedThings() internal pure returns (LinkedThings memory ret) {
Thing memory first;
assembly {
mstore(add(ret, 0x20), first)
mstore(add(ret, 0x40), first)
}
/* // it does this ...
Thing memory first;
uint256 ptr;
assembly {
ptr := first
}
ret.first = ptr;
ret.last = ptr;
*/
}
function p(LinkedThings memory lts, uint256 ptr) internal pure {
//Thing memory t;
assembly {
let t := mload(0x40)
mstore(0x40, add(t, and(add(0x40, 0x1f), not(0x1f))))
mstore(t, ptr)
let newPtr := t
let lastPtr := mload(add(lts, 0x40))
mstore(add(lastPtr, 0x20), newPtr)
mstore(add(lts, 0x40), newPtr)
//mstore(lts, add(mload(lts), 1)) // TODO deprecate numThings
}
/*// it does this ...
Thing memory t;
t.ptr = ptr;
uint256 newPtr;
assembly {
newPtr := t
}
uint256 lastPtr = lt.last;
Thing memory lastThing;
assembly {
lastThing := lastPtr
}
lastThing.next = newPtr;
lt.last = newPtr;
++lt.numThings;
*/
}
function dump(LinkedThings memory lts) internal pure returns (uint256[] memory ret) {
assembly {
ret := mload(0x40)
let len
let nextPtr := mload(add(lts, 0x20)) // lt.first
for {} 1 {} {
nextPtr := mload(add(nextPtr, 0x20))
if iszero(nextPtr) { break }
mstore(add(ret, add(0x20, mul(len, 0x20))), mload(nextPtr))
len := add(len, 1)
}
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
/* // it does this ..
uint256 length = lts.numThings;
ret = new uint256[](length);
uint256 length = lt.numThings;
ret = new uint256[](length);
Thing memory t;
uint256 nextPtr = lt.first;
assembly {
t := nextPtr
}
for (uint256 i; i < length; ++i) {
nextPtr = t.next;
assembly {
t := nextPtr
}
ret[i] = t.ptr;
}
*/
}
function shift(LinkedThings memory lts) internal pure returns (uint256 ret) {
Thing memory t;
assembly {
t := mload(add(lts, 0x20)) // lts.first
}
ret = t.ptr;
if (ret == 0) return ret;
lts.first = t.next;
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "lib/solady/src/utils/FixedPointMathLib.sol";
import "lib/solady/src/utils/LibBytes.sol";
import "./Append.sol";
import "./Structs.sol";
import "./Errors.sol";
import "./MemoryMappings.sol";
import "./LibPack.sol";
import "./LibDynamicThing.sol";
import "./LICENSE.sol";
function splitAtFirst(bytes memory subject, bytes memory needle, uint256 starting)
pure
returns (bool ok, bytes[2] memory ret)
{
uint256 idx = LibBytes.indexOf(subject, needle, starting);
if (idx < 1 || idx > subject.length) {
return (ok, ret);
}
ok = true;
unchecked {
ret[0] = _substring(subject, starting, idx);
ret[1] = __tail(subject, idx + needle.length);
} // uc
}
function atoi(bytes memory a) pure returns (uint256 ret) {
unchecked {
uint256 c;
for (uint256 i; i < a.length; ++i) {
c = uint256(uint8(_at(a, i)));
if (!(48 <= c && c <= 57)) revert InvalidRune_error();
c -= 48;
ret += (c * (10 ** (a.length - i - 1)));
}
} // uc
}
function toBytes32(bytes memory b) pure returns (bytes32 ret) {
assembly {
ret := mload(add(b, 0x20))
}
}
function toBytes(bytes32 b32) pure returns (bytes memory ret) {
ret = _allocateBytes(32);
assembly {
mstore(add(ret, 0x20), b32)
}
}
function allAreDistinct(uint256[] memory arr) pure returns (bool ret) {
// note: may not be ordered! so have to use map!
MemoryMappings.MemoryMapping memory m = MemoryMappings.newMemoryMapping({overwrite: false, sorted: false});
unchecked {
for (uint256 i; i < arr.length; ++i) {
MemoryMappings.add(m, bytes32(_at(arr, i)), bytes32(0));
}
} // uc
return arr.length == m.totalKeys;
}
function hashPair(uint256 a, uint256 b) pure returns (uint256 result) {
assembly {
mstore(0x0, a)
mstore(0x20, b)
result := keccak256(0x0, 0x40)
}
}
// shoutout vectorized!
function hashArr(uint256[] memory arr) pure returns (bytes32 result) {
assembly {
result := keccak256(add(arr, 0x20), shl(5, mload(arr)))
}
}
function hashArr(bytes32[] memory arr) pure returns (bytes32 result) {
assembly {
result := keccak256(add(arr, 0x20), shl(5, mload(arr)))
}
}
function _concat(bytes memory a, bytes memory b) pure returns (bytes memory ret) {
unchecked {
ret = _allocateBytes(a.length + b.length);
assembly {
mstore(ret, 0)
}
_append(ret, a);
_append(ret, b);
} // uc
}
function _concat(bytes memory a, bytes memory b, bytes memory c) pure returns (bytes memory ret) {
unchecked {
ret = _allocateBytes(a.length + b.length + c.length);
assembly {
mstore(ret, 0)
}
_append(ret, a);
_append(ret, b);
_append(ret, c);
} // uc
}
function _concat(bytes memory a, bytes memory b, bytes memory c, bytes memory d) pure returns (bytes memory ret) {
unchecked {
ret = _allocateBytes(a.length + b.length + c.length + d.length);
assembly {
mstore(ret, 0)
}
_append(ret, a);
_append(ret, b);
_append(ret, c);
_append(ret, d);
} // uc
}
function typeToString(Type t) pure returns (string memory ret) {
if (t == Type.NONE) {
ret = "NONE";
} else if (t == Type.TAB) {
ret = "TAB";
} else if (t == Type.TAB_ENCRYPTED) {
ret = "TAB_ENCRYPTED";
} else if (t == Type.FRAME) {
ret = "FRAME";
} else if (t == Type.FRAME_ENCRYPTED) {
ret = "FRAME_ENCRYPTED";
} else if (t == Type.COLLECTION) {
ret = "COLLECTION";
} else if (t == Type.COLLECTION_ENCRYPTED) {
ret = "COLLECTION_ENCRYPTED";
} else {
revert Unsupported_error();
}
}
function typeToStringDECRYPTED(Type t) pure returns (string memory ret) {
if (t == Type.NONE) {
ret = "NONE";
} else if (t == Type.TAB) {
ret = "TAB";
} else if (t == Type.TAB_ENCRYPTED) {
ret = "TAB_DECRYPTED";
} else if (t == Type.FRAME) {
ret = "FRAME";
} else if (t == Type.FRAME_ENCRYPTED) {
ret = "FRAME_DECRYPTED";
} else if (t == Type.COLLECTION) {
ret = "COLLECTION";
} else if (t == Type.COLLECTION_ENCRYPTED) {
ret = "COLLECTION_DECRYPTED";
} else {
revert Unsupported_error();
}
}
function validityToString(Validity v) pure returns (string memory ret) {
if (v == Validity.UNKNOWN) {
ret = "UNKNOWN";
} else if (v == Validity.PENDING_DECRYPTION) {
ret = "PENDING_DECRYPTION";
} else if (v == Validity.VALID) {
ret = "VALID";
} else if (v == Validity.INVALID) {
ret = "INVALID";
} else {
revert Unsupported_error();
}
}
function boolToString(bool tf) pure returns (string memory ret) {
if (tf) return "true";
return "false";
}
// single split is more efficient than others
function _splitBy(bytes memory data, bytes8 rune) pure returns (bool ok, bytes[2] memory ret) {
unchecked {
for (uint256 i; i < data.length; ++i) {
if (_at(data, i) == rune) {
bytes memory start = _allocateBytes(i);
assembly {
mstore(start, 0)
}
_appendSubstring(start, data, 0, i);
ret[0] = start;
bytes memory finish = _allocateBytes(data.length - i);
assembly {
mstore(finish, 0)
}
_appendSubstring(finish, data, i + 1, data.length);
ret[1] = finish;
ok = true;
break;
}
}
} // uc
}
// not the most efficient but very useful for validating given the "ok"
function _splitByEvery(bytes memory data, bytes8 rune) pure returns (bool ok, bytes[] memory ret) {
LibDynamicBytesArr.LinkedBytes memory lb = LibDynamicBytesArr.newDynamicBytesArr();
uint256 lastIdx;
bytes memory b;
uint256 size;
unchecked {
for (uint256 i; i < data.length; ++i) {
if (_at(data, i) == rune) {
size = i - lastIdx;
if (size < 1) {
lastIdx = i;
continue;
}
b = _allocateBytes(size);
assembly {
mstore(b, 0)
}
_appendSubstring(b, data, lastIdx, i);
LibDynamicBytesArr.p(lb, b);
lastIdx = i;
ok = true;
}
}
size = data.length - lastIdx;
if (size > 0) {
// don't forget last section :)
b = _allocateBytes(size);
assembly {
mstore(b, 0)
}
_appendSubstring(b, data, lastIdx, data.length);
LibDynamicBytesArr.p(lb, b);
}
ret = LibDynamicBytesArr.dump(lb);
} // uc
}
// this protects ux from long msgs
function _cropWithDots(bytes memory _msg, uint256 maxLength) pure returns (bytes memory) {
if (_msg.length < maxLength) return _msg;
assembly {
mstore(_msg, maxLength)
let start := sub(maxLength, 3) // assumes maxLength is greater than 3
for { let i := start } 1 {} {
mstore8(add(_msg, add(0x20, i)), 0x2e)
i := add(i, 1)
if iszero(lt(i, maxLength)) { break }
}
}
return _msg;
}
function validateNumeral(bytes memory subject) pure returns (bool ok) {
unchecked {
uint256 c;
for (uint256 i; i < subject.length; ++i) {
c = uint256(uint8(_at(subject, i)));
if (!(48 <= c && c <= 57)) return false;
}
ok = true;
} // uc
}
function validateHexColor(bytes memory subject, uint256 startIdx) pure returns (bool ok) {
unchecked {
uint256 length = subject.length;
if (length != 6 + startIdx) return false; // the 7 - is safe within this contract
uint256 c;
for (uint256 i = startIdx; i < length; ++i) {
c = uint256(uint8(_at(subject, i)));
// [0-9] || [a-f]
if (!((48 <= c && c <= 57) || (97 <= c && c <= 102))) return false;
}
} // uc
ok = true;
}
function _getPaintType(bytes memory paintKey) pure returns (PaintType ret) {
// forge-lint: disable-start(unsafe-typecast)
if (paintKey.length < 1) revert InvalidPaint_error();
bytes1 first = _at(paintKey, 0);
if (first == bytes1("_")[0]) {
return PaintType.STANDARD;
} else if (first == bytes1("-")[0]) {
return PaintType.COLORCLASS;
} else if (first == bytes1("T")[0]) {
return PaintType.TEXTURE;
} else if (first == bytes1("B")[0]) {
return PaintType.BACKGROUND;
}
revert InvalidPaint_error();
// forge-lint: disable-end(unsafe-typecast)
}
function _getShadingType(bytes memory paintKey) pure returns (ShadingType ret) {
unchecked {
if (paintKey.length < 1) revert InvalidPaint_error();
bytes1 last = _at(paintKey, paintKey.length - 1);
// forge-lint: disable-next-line(unsafe-typecast)
if (last == bytes1("S")[0]) ret = ShadingType.SHADING;
} // uc
}
function _validateTexture(uint256 dimension, bytes[][2] memory paintRoots) pure {
if (!LibBit.isPo2(dimension)) revert InvalidDimensions_error();
bytes[] memory keys = _at(paintRoots, 0);
unchecked {
for (uint256 i; i < keys.length; ++i) {
bytes memory key = _at(keys, i);
PaintType t = _getPaintType(key);
if (t == PaintType.TEXTURE) revert InvalidPaint_error();
}
} // uc
}
function getDeclaredFingerprint(FileBundle memory compressed) pure returns (bytes32 ret) {
if (compressed.chunks.length == 0) revert InvalidFileBundle_error();
return toBytes32(LibPack.bytesAt(_at(compressed.chunks, 0), 0));
}
function _hashPrefixIfHexColor(bytes memory subject) pure returns (bytes memory ret) {
if (validateHexColor(subject, 0)) {
return _concat(bytes("#"), subject);
}
return subject;
}
function _formatIfTextureInstance(bytes memory subject) pure returns (bytes memory ret) {
if (subject.length < 2) return subject;
uint256 c = uint256(uint8(subject[1]));
if (!(47 < c && c < 58)) return subject;
return _formatTextureInstance(subject);
}
function _getTextureInstanceStringData(bytes memory subject) pure returns (TextureInstanceStringData memory ret) {
(bool ok, bytes[2] memory valueSplit) = splitAtFirst(_tail(subject), "t", 0);
if (!ok) revert InvalidTexture_error();
ret = TextureInstanceStringData({id: string(valueSplit[0]), backgroundColorClass: string(valueSplit[1])});
}
function _formatTextureInstance(bytes memory subject) pure returns (bytes memory ret) {
TextureInstanceStringData memory tisd = _getTextureInstanceStringData(subject);
bytes memory background = bytes(tisd.backgroundColorClass);
if (keccak256(background) == keccak256("none")) {
ret = bytes(tisd.id);
} else {
PaintType pt = _getPaintType(background);
background = _tail(background); // a form of colorclass, has been validated in rr
if (pt == PaintType.STANDARD) {
background = _concat("#", background);
}
LibDynamicBuffer.DynamicBuffer memory db = LibDynamicBuffer.newDynamicBuffer();
LibDynamicBuffer.p(db, bytes(tisd.id));
LibDynamicBuffer.p(db, " ");
LibDynamicBuffer.p(db, background);
ret = LibDynamicBuffer.getBuffer(db);
}
}
// returns 0 when trivial frame. caller must interpret this
function getFrameHash(Frame memory frame) pure returns (bytes32) {
unchecked {
MemoryMappings.MemoryMapping memory m = MemoryMappings.newMemoryMapping({overwrite: true, sorted: true});
uint256[] memory ids = frame.tabIds;
uint256[] memory spots = new uint256[](4);
bytes32 hash;
uint256 count = 1; // both compressFrame and decompressFrame checks "allAreDistinct" so count is 1..
for (uint256 i; i < ids.length; ++i) {
spots[0] = _at(ids, i);
//spots[1] = 0; // "origin"
//spots[2] = 0;
//spots[3] = 0;
hash = hashArr(spots);
MemoryMappings.add(m, hash, bytes32(count));
}
Fork[] memory forks = frame.forks;
Fork memory fork;
bool ok;
bytes32 b32Count;
for (uint256 i; i < forks.length; ++i) {
fork = forks[i];
ids = fork.frameIds;
for (uint256 j; j < ids.length; ++j) {
spots[0] = _at(ids, j);
spots[1] = _at(fork.footprints, j);
spots[2] = _at(fork.positions, 2 * j);
spots[3] = _at(fork.positions, 2 * j + 1);
hash = hashArr(spots);
(ok, b32Count) = MemoryMappings.get(m, hash);
if (ok) {
count = uint256(b32Count);
++count;
} else {
count = 1;
}
MemoryMappings.add(m, hash, bytes32(count));
}
}
(bytes32[] memory ks, bytes32[] memory vs) = MemoryMappings.dump(m);
if (ks.length == 0) return bytes32(0); // caller interprets this
if (vs.length == 1 && _at(vs, 0) == bytes32(uint256(1))) return bytes32(0); // caller interprets this
// this strategy is cheaper gas than keccak256(abi.encode(ks,vs)) lol
spots[0] = uint256(hashArr(ks));
spots[1] = uint256(hashArr(vs));
spots[2] = 0;
spots[3] = 0;
return hashArr(spots);
} // uc
}
function _byteFromHexRune(bytes1 hexRune) pure returns (uint256 ret) {
uint256 c = uint256(uint8(hexRune));
if (c >= 48 && c <= 57) {
// [0-9]
return c - 48;
} else if (c >= 87 && c <= 102) {
// [a-f]
return c - 87;
}
revert InvalidByte_error();
}
// assumes dev KNOWS idx is within byte length, so can be unchecked since bytelength wouldn't be type max (unless bytes data is corrupted.. in which case.. FML)
function _byteFromStringAt(bytes memory b, uint256 idx) pure returns (uint256 ret) {
unchecked {
ret = _byteFromHexRune(_at(b, idx++)) << 4;
ret |= _byteFromHexRune(_at(b, idx));
} // uc
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(bytes memory b, uint256 i) pure returns (bytes1 ret) {
assembly {
ret := mload(add(b, add(0x20, i)))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(uint256[] memory ks, uint256 i) pure returns (uint256 ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(bytes32[] memory ks, uint256 i) pure returns (bytes32 ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _atB(bytes32[] memory ks, uint256 i) pure returns (bytes memory ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _atU(bytes32[] memory ks, uint256 i) pure returns (uint256 ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(bytes[] memory ks, uint256 i) pure returns (bytes memory ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(string[] memory ks, uint256 i) pure returns (string memory ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(JSON[] memory ks, uint256 i) pure returns (JSON memory ret) {
assembly {
ret := mload(add(ks, add(0x20, mul(i, 0x20))))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
// ASSUMES def knows index exists: will not revert if reads out of bounds
function _at(JSON[][2] memory aakvs, uint256 i) pure returns (JSON[] memory ret) {
assembly {
ret := mload(add(aakvs, mul(i, 0x20)))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
function _at(bytes[][2] memory kvs, uint256 i) pure returns (bytes[] memory ret) {
assembly {
ret := mload(add(kvs, mul(i, 0x20)))
}
}
// this stupid trick is 75% gas of normal access, AND it reduces contract size!!
function _at(string[][2] memory kvs, uint256 i) pure returns (string[] memory ret) {
assembly {
ret := mload(add(kvs, mul(i, 0x20)))
}
}
function _respectOrder(uint256 value, uint256[] memory arr, uint256 i, uint256 length) pure {
unchecked {
if (i < length - 1 && !(value < _at(arr, i + 1))) revert IDOrdering_error();
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./Allocate.sol";
import "./LICENSE.sol";
// cheaper than bytes concat :)
function _append(bytes memory dst, bytes memory src) pure {
assembly {
// resize
let priorLength := mload(dst)
mstore(dst, add(priorLength, mload(src)))
// copy
mcopy(add(dst, add(0x20, priorLength)), add(src, 0x20), mload(src))
}
}
error InvalidIndices_error();
// assumes dev is not stupid and startIdx < endIdx
function _appendSubstring(bytes memory dst, bytes memory src, uint256 startIdx, uint256 endIdx) pure {
if (endIdx < startIdx) revert InvalidIndices_error();
assembly {
// resize
let priorLength := mload(dst)
let substringLength := sub(endIdx, startIdx)
mstore(dst, add(priorLength, substringLength))
// copy
mcopy(add(dst, add(0x20, priorLength)), add(src, add(0x20, startIdx)), substringLength)
}
}
function _tail(bytes memory subject) pure returns (bytes memory ret) {
return __tail(subject, 1);
}
// we don't overload _tail since it is used as a fn ptr and confuses the poor compiler
function __tail(bytes memory subject, uint256 from) pure returns (bytes memory ret) {
uint256 length = subject.length;
if (!(from < length)) return ret;
unchecked {
ret = _allocateBytes(length - from);
} // uc
assembly {
mstore(ret, 0)
}
_appendSubstring(ret, subject, from, length);
}
function __head(bytes memory subject, uint256 to) pure returns (bytes memory ret) {
uint256 length = subject.length;
if (!(to < length)) return ret;
ret = _allocateBytes(to);
assembly {
mstore(ret, 0)
}
_appendSubstring(ret, subject, 0, to);
}
function _substring(bytes memory subject, uint256 from, uint256 to) pure returns (bytes memory ret) {
uint256 length = subject.length;
if (!(to < length)) return ret;
if (!(from < to)) revert InvalidIndices_error();
unchecked {
ret = _allocateBytes(to - from);
} // uc
assembly {
mstore(ret, 0)
}
_appendSubstring(ret, subject, from, to);
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
interface IERC173 {
function owner() external view returns (address);
function transferOwnership(address _newOwner) external payable;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "lib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sol";
interface IEOARegistry is IERC165 {
function isVerifiedEOA(address account) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./TransferPolicy.sol";
interface ITransferSecurityRegistry {
event AddedToAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
event CreatedAllowlist(AllowlistTypes indexed kind, uint256 indexed id, string indexed name);
event ReassignedAllowlistOwnership(AllowlistTypes indexed kind, uint256 indexed id, address indexed newOwner);
event RemovedFromAllowlist(AllowlistTypes indexed kind, uint256 indexed id, address indexed account);
event SetAllowlist(AllowlistTypes indexed kind, address indexed collection, uint120 indexed id);
event SetTransferSecurityLevel(address indexed collection, TransferSecurityLevels level);
function createOperatorWhitelist(string calldata name) external returns (uint120);
function createPermittedContractReceiverAllowlist(string calldata name) external returns (uint120);
function reassignOwnershipOfOperatorWhitelist(uint120 id, address newOwner) external;
function reassignOwnershipOfPermittedContractReceiverAllowlist(uint120 id, address newOwner) external;
function renounceOwnershipOfOperatorWhitelist(uint120 id) external;
function renounceOwnershipOfPermittedContractReceiverAllowlist(uint120 id) external;
function setTransferSecurityLevelOfCollection(address collection, TransferSecurityLevels level) external;
function setOperatorWhitelistOfCollection(address collection, uint120 id) external;
function setPermittedContractReceiverAllowlistOfCollection(address collection, uint120 id) external;
function addOperatorToWhitelist(uint120 id, address operator) external;
function addPermittedContractReceiverToAllowlist(uint120 id, address receiver) external;
function removeOperatorFromWhitelist(uint120 id, address operator) external;
function removePermittedContractReceiverFromAllowlist(uint120 id, address receiver) external;
function getCollectionSecurityPolicy(address collection) external view returns (CollectionSecurityPolicy memory);
function getWhitelistedOperators(uint120 id) external view returns (address[] memory);
function getPermittedContractReceivers(uint120 id) external view returns (address[] memory);
function isOperatorWhitelisted(uint120 id, address operator) external view returns (bool);
function isContractReceiverPermitted(uint120 id, address receiver) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./TransferPolicy.sol";
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(and(packed, 0xff), 0xff)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
/// To load an address, you can use `address(bytes20(load(a, offset)))`.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
/// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./Allocate.sol";
library MemoryMappings {
struct MemoryMapping {
bool sorted; // more efficient read/write when NOT sorted
// note sorted only for uint256/bytes32 NOT for bytes key
bool overwrite;
uint256 totalKeys;
Tree tree;
}
struct Tree {
bool exists;
bytes32 sortingKey;
bytes32 key;
bytes32 value;
Tree[] children;
}
function newMemoryMapping(bool sorted, bool overwrite) internal pure returns (MemoryMapping memory) {
Tree memory empty;
return MemoryMapping({sorted: sorted, overwrite: overwrite, totalKeys: 0, tree: empty});
}
function add(MemoryMapping memory mm, bytes32 key, bytes memory value) internal pure {
bytes32 sortingKey = key;
if (!mm.sorted) {
assembly {
mstore(0x0, sortingKey)
sortingKey := keccak256(0x0, 0x20)
}
}
_add(mm, sortingKey, key, value);
}
// note that won't be sorted if keys are bytes
function add(MemoryMapping memory mm, bytes memory key, bytes memory value) internal pure {
bytes32 keyHash;
bytes32 keyPtr;
assembly {
keyHash := keccak256(add(0x20, key), mload(key))
keyPtr := key
}
_add(mm, keyHash, keyPtr, value);
}
function add(MemoryMapping memory mm, bytes32 key, bytes32 value) internal pure {
bytes32 sortingKey = key;
if (!mm.sorted) {
assembly {
mstore(0x0, sortingKey)
sortingKey := keccak256(0x0, 0x20)
}
}
if (mm.totalKeys < 1) {
// bootstrapping
++mm.totalKeys;
Tree[] memory children = new Tree[](2);
mm.tree = Tree(true, sortingKey, key, value, children);
return;
}
bool newValue = _add(mm.tree, mm.overwrite, sortingKey, key, value);
if (newValue) ++mm.totalKeys;
}
function _add(MemoryMapping memory mm, bytes32 sortingKey, bytes32 key, bytes memory value) private pure {
bytes32 valuePtr;
assembly {
valuePtr := value
}
if (mm.totalKeys < 1) {
// bootstrapping
++mm.totalKeys;
Tree[] memory children = new Tree[](2);
mm.tree = Tree(true, sortingKey, key, valuePtr, children);
return;
}
bool newValue = _add(mm.tree, mm.overwrite, sortingKey, key, valuePtr);
if (newValue) ++mm.totalKeys;
}
function get(MemoryMapping memory mm, bytes32 key) internal pure returns (bool ok, bytes32 value) {
bytes32 sortingKey = key;
if (!mm.sorted) {
assembly {
mstore(0x0, sortingKey)
sortingKey := keccak256(0x0, 0x20)
}
}
return _get(mm, sortingKey);
}
function get(MemoryMapping memory mm, bytes memory key) internal pure returns (bool ok, bytes32 value) {
bytes32 keyHash;
assembly {
keyHash := keccak256(add(0x20, key), mload(key))
}
return _get(mm, keyHash);
}
function _get(MemoryMapping memory mm, bytes32 sortingKey) private pure returns (bool ok, bytes32 value) {
return _get(mm.tree, sortingKey);
}
function dump(MemoryMapping memory mm) internal pure returns (bytes32[] memory keys, bytes32[] memory values) {
if (mm.totalKeys < 1) return (keys, values);
keys = _allocateBytes32Arr(mm.totalKeys);
values = _allocateBytes32Arr(mm.totalKeys);
assembly {
mstore(keys, 0)
mstore(values, 0)
}
_dump(mm.tree, keys, values);
}
function dumpKeys(MemoryMapping memory mm) internal pure returns (bytes32[] memory keys) {
if (mm.totalKeys < 1) return keys;
keys = _allocateBytes32Arr(mm.totalKeys);
assembly {
mstore(keys, 0)
}
_dumpKeys(mm.tree, keys);
}
function dumpValues(MemoryMapping memory mm) internal pure returns (bytes32[] memory values) {
if (mm.totalKeys < 1) return values;
values = _allocateBytes32Arr(mm.totalKeys);
assembly {
mstore(values, 0)
}
_dumpValues(mm.tree, values);
}
function _add(Tree memory tree, bool overwrite, bytes32 sortingKey, bytes32 key, bytes32 value)
private
pure
returns (bool newValue)
{
Tree memory _tree = tree;
while (true) {
if (_tree.sortingKey == sortingKey) {
newValue = !_tree.exists;
if (overwrite || newValue) {
_tree.exists = true;
_tree.value = value;
if (newValue) _tree.children = new Tree[](2);
return newValue;
}
return newValue;
}
if (sortingKey < _tree.sortingKey) {
_tree = _tree.children[0];
} else {
_tree = _tree.children[1];
}
if (!_tree.exists) {
_tree.sortingKey = sortingKey;
_tree.key = key;
}
}
}
function _get(Tree memory tree, bytes32 sortingKey) private pure returns (bool ok, bytes32 value) {
Tree memory _tree = tree;
while (true) {
if (_tree.sortingKey == sortingKey) {
ok = true;
value = _tree.value;
return (ok, value);
}
//bool isNewNode = _tree.children.length < 1;
if (_tree.children.length < 1) {
// ok = false;
return (ok, value);
}
if (sortingKey < _tree.sortingKey) {
_tree = _tree.children[0];
} else {
_tree = _tree.children[1];
}
}
}
function _dump(Tree memory tree, bytes32[] memory keys, bytes32[] memory values) private pure {
Tree memory other = tree.children[0];
if (other.exists) _dump(other, keys, values); // left
// center
// assembly does this:
//uint256 idx = keys.length;
//keys[idx] = tree.key;
//values[idx++] = tree.value;
assembly {
// assumes arrays come in allocated BUT have their length initialized to 0 so will know how many added
let idx := mload(keys)
mstore(keys, add(idx, 1))
mstore(values, add(idx, 1))
mstore(add(keys, add(0x20, mul(idx, 0x20))), mload(add(tree, 0x40)))
mstore(add(values, add(0x20, mul(idx, 0x20))), mload(add(tree, 0x60)))
}
other = tree.children[1];
if (other.exists) _dump(other, keys, values); // right
}
function _dumpKeys(Tree memory tree, bytes32[] memory keys) private pure {
Tree memory other = tree.children[0];
if (other.exists) _dumpKeys(other, keys); // left
// center
// assembly does this:
//uint256 idx = keys.length;
//keys[idx] = tree.key;
assembly {
// assumes arrays come in allocated BUT have their length initialized to 0 so will know how many added
let idx := mload(keys)
mstore(keys, add(idx, 1))
mstore(add(keys, add(0x20, mul(idx, 0x20))), mload(add(tree, 0x40)))
}
other = tree.children[1];
if (other.exists) _dumpKeys(other, keys); // right
}
function _dumpValues(Tree memory tree, bytes32[] memory values) private pure {
Tree memory other = tree.children[0];
if (other.exists) _dumpValues(other, values); // left
// center
// assembly does this:
//uint256 idx = values.length;
//values[idx++] = tree.value;
assembly {
// assumes arrays come in allocated BUT have their length initialized to 0 so will know how many added
let idx := mload(values)
mstore(values, add(idx, 1))
mstore(add(values, add(0x20, mul(idx, 0x20))), mload(add(tree, 0x60)))
}
other = tree.children[1];
if (other.exists) _dumpValues(other, values); // right
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "lib/solady/src/utils/LibBit.sol";
import "lib/solady/src/utils/LibZip.sol";
import {LibDynamicBuffer} from "./LibDynamicThing.sol";
import "./Common.sol";
import "./Append.sol";
import "./Errors.sol";
import "./LICENSE.sol";
library LibPack {
function packBytesArrs(bytes[] memory arrs) internal pure returns (bytes memory ret) {
uint256[] memory positions = new uint256[](arrs.length);
uint256 position;
for (uint256 i; i < positions.length; ++i) {
positions[i] = position;
position += arrs[i].length;
}
bytes memory packedPositions = packUint256s(positions);
bytes memory bPackedPositionsLength = toBytes(bytes32(packedPositions.length));
LibDynamicBuffer.DynamicBuffer memory db = LibDynamicBuffer.newDynamicBuffer();
LibDynamicBuffer.p(db, bPackedPositionsLength);
LibDynamicBuffer.p(db, packedPositions);
for (uint256 i; i < arrs.length; ++i) {
LibDynamicBuffer.p(db, arrs[i]);
}
ret = LibDynamicBuffer.getBuffer(db);
}
function bytesAt(bytes memory input, uint256 idx) internal pure returns (bytes memory ret) {
if (input.length < 1) revert InvalidInput_error();
unchecked {
uint256 packedPositionsLength;
assembly {
packedPositionsLength := mload(add(input, 0x20))
}
bytes memory packedPositions = _allocateBytes(packedPositionsLength);
assembly {
mstore(packedPositions, 0)
}
uint256 start = 32;
uint256 end = start + packedPositionsLength;
_appendSubstring(packedPositions, input, start, end);
uint256[] memory positions = unpackBytesIntoUint256s(packedPositions);
// padding
packedPositionsLength += 32;
if (idx > positions.length - 1) revert InvalidInput_error();
start = packedPositionsLength + _at(positions, idx);
if (idx < positions.length - 1) {
end = packedPositionsLength + _at(positions, idx + 1);
} else {
end = input.length;
}
ret = _allocateBytes(end - start);
assembly {
mstore(ret, 0)
}
_appendSubstring(ret, input, start, end);
} //uc
}
function unpackBytesIntoBytesArrs(bytes memory input) internal pure returns (bytes[] memory ret) {
if (input.length < 1) revert InvalidInput_error();
unchecked {
uint256 packedPositionsLength;
assembly {
packedPositionsLength := mload(add(input, 0x20))
}
bytes memory packedPositions = _allocateBytes(packedPositionsLength);
assembly {
mstore(packedPositions, 0)
}
uint256 start = 32;
uint256 end = start + packedPositionsLength;
_appendSubstring(packedPositions, input, start, end);
uint256[] memory positions = unpackBytesIntoUint256s(packedPositions);
ret = _allocateArr(positions.length);
// padding
packedPositionsLength += 32;
uint256 bound = positions.length - 1;
bytes memory _ret;
for (uint256 i; i < bound; ++i) {
start = packedPositionsLength + _at(positions, i);
end = packedPositionsLength + _at(positions, i + 1);
_ret = _allocateBytes(end - start);
assembly {
mstore(_ret, 0)
}
_appendSubstring(_ret, input, start, end);
assembly {
mstore(add(ret, add(0x20, mul(i, 0x20))), _ret)
}
}
start = packedPositionsLength + _at(positions, bound);
end = input.length;
_ret = _allocateBytes(end - start);
assembly {
mstore(_ret, 0)
}
_appendSubstring(_ret, input, start, end);
assembly {
mstore(add(ret, add(0x20, mul(bound, 0x20))), _ret)
}
} //uc
}
function packUint256s(uint256[] memory arr) internal pure returns (bytes memory ret) {
/// forge-lint: disable-start(unsafe-typecast)
uint256 maxIdxMSB; // idx most significant bit
uint256 idxMSB;
unchecked {
for (uint256 i; i < arr.length; ++i) {
idxMSB = LibBit.fls(arr[i]);
if (idxMSB == 256) continue;
if (idxMSB > maxIdxMSB) maxIdxMSB = idxMSB;
}
uint256 bound = maxIdxMSB / 8 + 1;
ret = new bytes(arr.length * bound + 1);
uint256 retIdx;
ret[retIdx++] = bytes1(uint8(bound));
uint256 n;
for (uint256 i; i < arr.length; ++i) {
n = arr[i];
for (uint256 j; j < bound; ++j) {
ret[retIdx++] = bytes1(uint8(n >> (8 * j)));
}
}
} // uc
/// forge-lint: disable-end(unsafe-typecast)
}
function uint256At(bytes memory packed, uint256 idx) internal pure returns (uint256 ret) {
if (packed.length < 1) revert InvalidInput_error();
unchecked {
uint256 bound = uint256(uint8(packed[0]));
assembly {
idx := add(mul(idx, bound), 1)
for { let j := 0 } 1 {} {
let shift := mul(8, j)
let r := byte(0, mload(add(packed, add(0x20, idx))))
r := shl(shift, r)
ret := or(ret, r)
idx := add(idx, 1)
j := add(j, 1)
if iszero(lt(j, bound)) { break }
}
}
} // uc
}
function unpackBytesIntoUint256s(bytes memory packed) internal pure returns (uint256[] memory ret) {
uint256 idx;
if (packed.length < 1) revert InvalidInput_error();
unchecked {
uint256 bound = uint256(uint8(packed[idx++]));
ret = _allocateUintArr((packed.length - 1) / bound);
assembly {
let length := mload(ret)
for { let i := 0 } 1 {} {
let n := 0
for { let j := 0 } 1 {} {
let shift := mul(8, j)
let r := byte(0, mload(add(packed, add(0x20, idx))))
r := shl(shift, r)
n := or(n, r)
idx := add(idx, 1)
j := add(j, 1)
if iszero(lt(j, bound)) { break }
}
mstore(add(ret, add(0x20, mul(i, 0x20))), n)
i := add(i, 1)
if iszero(lt(i, length)) { break }
}
}
} // uc
// does this ...
/*
unchecked {
if (packed.length < ret.length * bound) revert InvalidInput_error();
uint256 n;
for (uint256 i; i < ret.length; ++i) {
n = 0;
for (uint256 j; j < bound; ++j) {
n |= (uint256(uint8(packed[idx++])) << (8 * j));
}
ret[i] = n;
}
} // uc
*/
}
function decomposeZ(int256 z) internal pure returns (bool negative, uint256 n) {
// forge-lint: disable-start(unsafe-typecast)
unchecked {
if (z < int256(0)) return (true, ~uint256(z) + 1);
return (false, uint256(z));
} // uc
// forge-lint: disable-end(unsafe-typecast)
}
function packInt256s(int256[] memory arr) internal pure returns (bytes memory ret) {
uint256 length = arr.length;
uint256[] memory us = new uint256[](length);
bool negative;
uint256 n;
for (uint256 i; i < arr.length; ++i) {
(negative, n) = decomposeZ(arr[i]);
n = n << 1;
us[i] = n;
if (negative) {
us[i] |= 0x1;
}
}
ret = packUint256s(us);
}
function int256At(bytes memory packed, uint256 idx) internal pure returns (int256 ret) {
uint256 n = uint256At(packed, idx);
// forge-lint: disable-next-line(unsafe-typecast)
ret = int256(n >> 1);
if (n & 0x1 == 0x1) ret *= -1;
}
function unpackBytesIntoInt256s(bytes memory packed) internal pure returns (int256[] memory ret) {
uint256 idx;
if (packed.length < 1) revert InvalidInput_error();
unchecked {
uint256 bound = uint256(uint8(packed[idx++]));
if (bound < 1) revert InvalidInput_error();
uint256 length = (packed.length - 1) / bound;
ret = _allocateIntArr(length);
assembly {
for { let i := 0 } 1 {} {
let n := 0
for { let j := 0 } 1 {} {
let shift := mul(8, j)
let r := byte(0, mload(add(packed, add(0x20, idx))))
r := shl(shift, r)
n := or(n, r)
idx := add(idx, 1)
j := add(j, 1)
if iszero(lt(j, bound)) { break }
}
let ptr := add(ret, add(0x20, mul(i, 0x20)))
mstore(ptr, shr(1, n))
if and(n, 0x1) { mstore(ptr, sub(0, mload(ptr))) }
i := add(i, 1)
if iszero(lt(i, length)) { break }
}
}
} // uc
/* // does this ...
uint256[] memory us = unpackBytesIntoUint256s(packed);
uint256 length = us.length;
uint256 n;
for (uint256 i; i < length; ++i) {
n = us[i];
ret[i] = int256(n >> 1);
if (n & 0x1 == 0x1) ret[i] *= -1;
}
*/
}
function packAddresses(address[] memory arr) internal pure returns (bytes memory ret) {
uint256 bound = 20;
ret = new bytes(arr.length * bound);
uint256 retIdx;
uint256 n;
for (uint256 i; i < arr.length; ++i) {
n = uint256(uint160(arr[i]));
for (uint256 j; j < bound; ++j) {
// forge-lint: disable-next-line(unsafe-typecast)
ret[retIdx++] = bytes1(uint8(n >> (8 * j)));
}
}
}
function addressAt(bytes memory packed, uint256 idx) internal pure returns (address ret) {
// forge-lint: disable-start(unsafe-typecast)
if (packed.length < 1) revert InvalidInput_error();
unchecked {
idx = idx * 20; // no +1 since know bound
uint256 n;
for (uint256 j; j < 20; ++j) {
n |= (uint256(uint8(packed[idx++])) << (8 * j));
}
ret = address(uint160(n));
} // uc
// forge-lint: disable-end(unsafe-typecast)
}
function unpackBytesIntoAddresses(bytes memory packed) internal pure returns (address[] memory ret) {
uint256 idx;
if (packed.length < 1) revert InvalidInput_error();
unchecked {
ret = new address[](packed.length / 20); // no +1 since know bound
if (packed.length < ret.length * 20) revert InvalidInput_error();
uint256 n;
for (uint256 i; i < ret.length; ++i) {
n = 0;
/// forge-lint: disable-start(unsafe-typecast)
for (uint256 j; j < 20; ++j) {
n |= (uint256(uint8(packed[idx++])) << (8 * j));
}
ret[i] = address(uint160(n));
/// forge-lint: disable-end(unsafe-typecast)
}
} // uc
}
}// SPDX-License-Identifier: HVPL - HEXED VIRAL PUBLIC LICENSE
pragma solidity ^0.8.25;
import "./LICENSE.sol";
function _allocateBytes(uint256 len) pure returns (bytes memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(len, 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateString(uint256 len) pure returns (string memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(len, 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateArr(uint256 len) pure returns (bytes[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateStringArr(uint256 len) pure returns (string[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateUintArr(uint256 len) pure returns (uint256[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateBytes32Arr(uint256 len) pure returns (bytes32[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateIntArr(uint256 len) pure returns (int256[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}
function _allocateAddressArr(uint256 len) pure returns (address[] memory ret) {
assembly {
ret := mload(0x40)
// new "memory end" including padding
mstore(0x40, add(ret, and(add(add(mul(len, 0x20), 0x20), 0x1f), not(0x1f))))
mstore(ret, len)
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for bit twiddling and boolean operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol)
/// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html)
library LibBit {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BIT TWIDDLING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Find last set.
/// Returns the index of the most significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
function fls(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := or(shl(8, iszero(x)), shl(7, lt(0xffffffffffffffffffffffffffffffff, x)))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := or(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0x0706060506020504060203020504030106050205030304010505030400000000))
}
}
/// @dev Count leading zeros.
/// Returns the number of zeros preceding the most significant one bit.
/// If `x` is zero, returns 256.
function clz(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x))
r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
r := add(xor(r, byte(and(0x1f, shr(shr(r, x), 0x8421084210842108cc6318c6db6d54be)),
0xf8f9f9faf9fdfafbf9fdfcfdfafbfcfef9fafdfafcfcfbfefafafcfbffffffff)), iszero(x))
}
}
/// @dev Find first set.
/// Returns the index of the least significant bit of `x`,
/// counting from the least significant bit position.
/// If `x` is zero, returns 256.
/// Equivalent to `ctz` (count trailing zeros), which gives
/// the number of zeros following the least significant one bit.
function ffs(uint256 x) internal pure returns (uint256 r) {
/// @solidity memory-safe-assembly
assembly {
// Isolate the least significant bit.
x := and(x, add(not(x), 1))
// For the upper 3 bits of the result, use a De Bruijn-like lookup.
// Credit to adhusson: https://blog.adhusson.com/cheap-find-first-set-evm/
// forgefmt: disable-next-item
r := shl(5, shr(252, shl(shl(2, shr(250, mul(x,
0xb6db6db6ddddddddd34d34d349249249210842108c6318c639ce739cffffffff))),
0x8040405543005266443200005020610674053026020000107506200176117077)))
// For the lower 5 bits of the result, use a De Bruijn lookup.
// forgefmt: disable-next-item
r := or(r, byte(and(div(0xd76453e0, shr(r, x)), 0x1f),
0x001f0d1e100c1d070f090b19131c1706010e11080a1a141802121b1503160405))
}
}
/// @dev Returns the number of set bits in `x`.
function popCount(uint256 x) internal pure returns (uint256 c) {
/// @solidity memory-safe-assembly
assembly {
let max := not(0)
let isMax := eq(x, max)
x := sub(x, and(shr(1, x), div(max, 3)))
x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5)))
x := and(add(x, shr(4, x)), div(max, 17))
c := or(shl(8, isMax), shr(248, mul(x, div(max, 255))))
}
}
/// @dev Returns whether `x` is a power of 2.
function isPo2(uint256 x) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// Equivalent to `x && !(x & (x - 1))`.
result := iszero(add(and(x, sub(x, 1)), iszero(x)))
}
}
/// @dev Returns `x` reversed at the bit level.
function reverseBits(uint256 x) internal pure returns (uint256 r) {
uint256 m0 = 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f;
uint256 m1 = m0 ^ (m0 << 2);
uint256 m2 = m1 ^ (m1 << 1);
r = reverseBytes(x);
r = (m2 & (r >> 1)) | ((m2 & r) << 1);
r = (m1 & (r >> 2)) | ((m1 & r) << 2);
r = (m0 & (r >> 4)) | ((m0 & r) << 4);
}
/// @dev Returns `x` reversed at the byte level.
function reverseBytes(uint256 x) internal pure returns (uint256 r) {
unchecked {
// Computing masks on-the-fly reduces bytecode size by about 200 bytes.
uint256 m0 = 0x100000000000000000000000000000001 * (~toUint(x == uint256(0)) >> 192);
uint256 m1 = m0 ^ (m0 << 32);
uint256 m2 = m1 ^ (m1 << 16);
uint256 m3 = m2 ^ (m2 << 8);
r = (m3 & (x >> 8)) | ((m3 & x) << 8);
r = (m2 & (r >> 16)) | ((m2 & r) << 16);
r = (m1 & (r >> 32)) | ((m1 & r) << 32);
r = (m0 & (r >> 64)) | ((m0 & r) << 64);
r = (r >> 128) | (r << 128);
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BOOLEAN OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// A Solidity bool on the stack or memory is represented as a 256-bit word.
// Non-zero values are true, zero is false.
// A clean bool is either 0 (false) or 1 (true) under the hood.
// Usually, if not always, the bool result of a regular Solidity expression,
// or the argument of a public/external function will be a clean bool.
// You can usually use the raw variants for more performance.
// If uncertain, test (best with exact compiler settings).
// Or use the non-raw variants (compiler can sometimes optimize out the double `iszero`s).
/// @dev Returns `x & y`. Inputs must be clean.
function rawAnd(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(x, y)
}
}
/// @dev Returns `x & y`.
function and(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := and(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns `x | y`. Inputs must be clean.
function rawOr(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(x, y)
}
}
/// @dev Returns `x | y`.
function or(bool x, bool y) internal pure returns (bool z) {
/// @solidity memory-safe-assembly
assembly {
z := or(iszero(iszero(x)), iszero(iszero(y)))
}
}
/// @dev Returns 1 if `b` is true, else 0. Input must be clean.
function rawToUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := b
}
}
/// @dev Returns 1 if `b` is true, else 0.
function toUint(bool b) internal pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := iszero(iszero(b))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for compressing and decompressing bytes.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibZip.sol)
/// @author Calldata compression by clabby (https://github.com/clabby/op-kompressor)
/// @author FastLZ by ariya (https://github.com/ariya/FastLZ)
///
/// @dev Note:
/// The accompanying solady.js library includes implementations of
/// FastLZ and calldata operations for convenience.
library LibZip {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* FAST LZ OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// LZ77 implementation based on FastLZ.
// Equivalent to level 1 compression and decompression at the following commit:
// https://github.com/ariya/FastLZ/commit/344eb4025f9ae866ebf7a2ec48850f7113a97a42
// Decompression is backwards compatible.
/// @dev Returns the compressed `data`.
function flzCompress(bytes memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
function ms8(d_, v_) -> _d {
mstore8(d_, v_)
_d := add(d_, 1)
}
function u24(p_) -> _u {
_u := mload(p_)
_u := or(shl(16, byte(2, _u)), or(shl(8, byte(1, _u)), byte(0, _u)))
}
function cmp(p_, q_, e_) -> _l {
for { e_ := sub(e_, q_) } lt(_l, e_) { _l := add(_l, 1) } {
e_ := mul(iszero(byte(0, xor(mload(add(p_, _l)), mload(add(q_, _l))))), e_)
}
}
function literals(runs_, src_, dest_) -> _o {
for { _o := dest_ } iszero(lt(runs_, 0x20)) { runs_ := sub(runs_, 0x20) } {
mstore(ms8(_o, 31), mload(src_))
_o := add(_o, 0x21)
src_ := add(src_, 0x20)
}
if iszero(runs_) { leave }
mstore(ms8(_o, sub(runs_, 1)), mload(src_))
_o := add(1, add(_o, runs_))
}
function mt(l_, d_, o_) -> _o {
for { d_ := sub(d_, 1) } iszero(lt(l_, 263)) { l_ := sub(l_, 262) } {
o_ := ms8(ms8(ms8(o_, add(224, shr(8, d_))), 253), and(0xff, d_))
}
if iszero(lt(l_, 7)) {
_o := ms8(ms8(ms8(o_, add(224, shr(8, d_))), sub(l_, 7)), and(0xff, d_))
leave
}
_o := ms8(ms8(o_, add(shl(5, l_), shr(8, d_))), and(0xff, d_))
}
function setHash(i_, v_) {
let p_ := add(mload(0x40), shl(2, i_))
mstore(p_, xor(mload(p_), shl(224, xor(shr(224, mload(p_)), v_))))
}
function getHash(i_) -> _h {
_h := shr(224, mload(add(mload(0x40), shl(2, i_))))
}
function hash(v_) -> _r {
_r := and(shr(19, mul(2654435769, v_)), 0x1fff)
}
function setNextHash(ip_, ipStart_) -> _ip {
setHash(hash(u24(ip_)), sub(ip_, ipStart_))
_ip := add(ip_, 1)
}
result := mload(0x40)
codecopy(result, codesize(), 0x8000) // Zeroize the hashmap.
let op := add(result, 0x8000)
let a := add(data, 0x20)
let ipStart := a
let ipLimit := sub(add(ipStart, mload(data)), 13)
for { let ip := add(2, a) } lt(ip, ipLimit) {} {
let r := 0
let d := 0
for {} 1 {} {
let s := u24(ip)
let h := hash(s)
r := add(ipStart, getHash(h))
setHash(h, sub(ip, ipStart))
d := sub(ip, r)
if iszero(lt(ip, ipLimit)) { break }
ip := add(ip, 1)
if iszero(gt(d, 0x1fff)) { if eq(s, u24(r)) { break } }
}
if iszero(lt(ip, ipLimit)) { break }
ip := sub(ip, 1)
if gt(ip, a) { op := literals(sub(ip, a), a, op) }
let l := cmp(add(r, 3), add(ip, 3), add(ipLimit, 9))
op := mt(l, d, op)
ip := setNextHash(setNextHash(add(ip, l), ipStart), ipStart)
a := ip
}
// Copy the result to compact the memory, overwriting the hashmap.
let end := sub(literals(sub(add(ipStart, mload(data)), a), a, op), 0x7fe0)
let o := add(result, 0x20)
mstore(result, sub(end, o)) // Store the length.
for {} iszero(gt(o, end)) { o := add(o, 0x20) } { mstore(o, mload(add(o, 0x7fe0))) }
mstore(end, 0) // Zeroize the slot after the string.
mstore(0x40, add(end, 0x20)) // Allocate the memory.
}
}
/// @dev Returns the decompressed `data`.
function flzDecompress(bytes memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let op := add(result, 0x20)
let end := add(add(data, 0x20), mload(data))
for { data := add(data, 0x20) } lt(data, end) {} {
let w := mload(data)
let c := byte(0, w)
let t := shr(5, c)
if iszero(t) {
mstore(op, mload(add(data, 1)))
data := add(data, add(2, c))
op := add(op, add(1, c))
continue
}
for {
let g := eq(t, 7)
let l := add(2, xor(t, mul(g, xor(t, add(7, byte(1, w)))))) // M
let s := add(add(shl(8, and(0x1f, c)), byte(add(1, g), w)), 1) // R
let r := sub(op, s)
let f := xor(s, mul(gt(s, 0x20), xor(s, 0x20)))
let j := 0
} 1 {} {
mstore(add(op, j), mload(add(r, j)))
j := add(j, f)
if lt(j, l) { continue }
data := add(data, add(2, g))
op := add(op, l)
break
}
}
mstore(result, sub(op, add(result, 0x20))) // Store the length.
mstore(op, 0) // Zeroize the slot after the string.
mstore(0x40, add(op, 0x20)) // Allocate the memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CALLDATA OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Calldata compression and decompression using selective run length encoding:
// - Sequences of 0x00 (up to 128 consecutive).
// - Sequences of 0xff (up to 32 consecutive).
//
// A run length encoded block consists of two bytes:
// (0) 0x00
// (1) A control byte with the following bit layout:
// - [7] `0: 0x00, 1: 0xff`.
// - [0..6] `runLength - 1`.
//
// The first 4 bytes are bitwise negated so that the compressed calldata
// can be dispatched into the `fallback` and `receive` functions.
/// @dev Returns the compressed `data`.
function cdCompress(bytes memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
function rle(v_, o_, d_) -> _o, _d {
mstore(o_, shl(240, or(and(0xff, add(d_, 0xff)), and(0x80, v_))))
_o := add(o_, 2)
}
result := mload(0x40)
let o := add(result, 0x20)
let z := 0 // Number of consecutive 0x00.
let y := 0 // Number of consecutive 0xff.
for { let end := add(data, mload(data)) } iszero(eq(data, end)) {} {
data := add(data, 1)
let c := byte(31, mload(data))
if iszero(c) {
if y { o, y := rle(0xff, o, y) }
z := add(z, 1)
if eq(z, 0x80) { o, z := rle(0x00, o, 0x80) }
continue
}
if eq(c, 0xff) {
if z { o, z := rle(0x00, o, z) }
y := add(y, 1)
if eq(y, 0x20) { o, y := rle(0xff, o, 0x20) }
continue
}
if y { o, y := rle(0xff, o, y) }
if z { o, z := rle(0x00, o, z) }
mstore8(o, c)
o := add(o, 1)
}
if y { o, y := rle(0xff, o, y) }
if z { o, z := rle(0x00, o, z) }
// Bitwise negate the first 4 bytes.
mstore(add(result, 4), not(mload(add(result, 4))))
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/// @dev Returns the decompressed `data`.
function cdDecompress(bytes memory data) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
if mload(data) {
result := mload(0x40)
let o := add(result, 0x20)
let s := add(data, 4)
let v := mload(s)
let end := add(data, mload(data))
mstore(s, not(v)) // Bitwise negate the first 4 bytes.
for {} lt(data, end) {} {
data := add(data, 1)
let c := byte(31, mload(data))
if iszero(c) {
data := add(data, 1)
let d := byte(31, mload(data))
// Fill with either 0xff or 0x00.
mstore(o, not(0))
if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) }
o := add(o, add(and(d, 0x7f), 1))
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(s, v) // Restore the first 4 bytes.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
}
/// @dev To be called in the `fallback` function.
/// ```
/// fallback() external payable { LibZip.cdFallback(); }
/// receive() external payable {} // Silence compiler warning to add a `receive` function.
/// ```
/// For efficiency, this function will directly return the results, terminating the context.
/// If called internally, it must be called at the end of the function.
function cdFallback() internal {
assembly {
if iszero(calldatasize()) { return(calldatasize(), calldatasize()) }
let o := 0
let f := not(3) // For negating the first 4 bytes.
for { let i := 0 } lt(i, calldatasize()) {} {
let c := byte(0, xor(add(i, f), calldataload(i)))
i := add(i, 1)
if iszero(c) {
let d := byte(0, xor(add(i, f), calldataload(i)))
i := add(i, 1)
// Fill with either 0xff or 0x00.
mstore(o, not(0))
if iszero(gt(d, 0x7f)) { codecopy(o, codesize(), add(d, 1)) }
o := add(o, add(and(d, 0x7f), 1))
continue
}
mstore8(o, c)
o := add(o, 1)
}
let success := delegatecall(gas(), address(), 0x00, o, codesize(), 0x00)
returndatacopy(0x00, 0x00, returndatasize())
if iszero(success) { revert(0x00, returndatasize()) }
return(0x00, returndatasize())
}
}
}{
"remappings": [
"creator-token-standards/lib/openzeppelin-contracts/=lib/openzeppelin-contracts/",
"creator-token-standards/lib/PermitC/lib/openzeppelin-contracts/=lib/openzeppelin-contracts/",
"creator-token-standards/lib/murky/lib/openzeppelin-contracts/=lib/openzeppelin-contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"solady/=lib/solady/src/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/",
"v2-periphery/=lib/v2-periphery/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 4294967295
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IHub","name":"hub_","type":"address"},{"internalType":"contract IRefunder","name":"refunder_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"ArrayLengthsMismatch","type":"error"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"CreatorTokenBase__SetTransferValidatorFirst","type":"error"},{"inputs":[],"name":"ExceedsMaxSupply_error","type":"error"},{"inputs":[],"name":"ExclusivityLapsed_error","type":"error"},{"inputs":[],"name":"FailedCall_error","type":"error"},{"inputs":[],"name":"InsufficientBalance","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InsufficientValue_error","type":"error"},{"inputs":[],"name":"InvalidExclusivityParams_error","type":"error"},{"inputs":[],"name":"InvalidInput_error","type":"error"},{"inputs":[],"name":"MustRespectExclusivity_error","type":"error"},{"inputs":[],"name":"NoWrapping_error","type":"error"},{"inputs":[],"name":"NotHub_error","type":"error"},{"inputs":[],"name":"NotImmortalizer_error","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NotOwner_error","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"inputs":[],"name":"TransferToNonERC1155ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"DefaultRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newExclusivityWindow","type":"uint256"}],"name":"ExclusivityWindowUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newExtenExclusivityPrice","type":"uint256"}],"name":"ExtendExclusivityPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxExclusivityWindow","type":"uint256"}],"name":"MaxExclusivityWindowUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"NewExclusiveToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"PremiumAccessMaxUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"PremiumAccessPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"TokenRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[],"name":"DEFAULT_OPERATOR_WHITELIST_ID","outputs":[{"internalType":"uint120","name":"","type":"uint120"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_TRANSFER_SECURITY_LEVEL","outputs":[{"internalType":"enum TransferSecurityLevels","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ONE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"qty","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimRefund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"emitMetadataUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"exclusivityData","outputs":[{"components":[{"internalType":"uint64","name":"exclusivityWindow","type":"uint64"},{"internalType":"uint112","name":"premiumAccessMax","type":"uint112"},{"internalType":"uint112","name":"premiumAccessPrice","type":"uint112"},{"internalType":"bool","name":"sharesWithCrew","type":"bool"}],"internalType":"struct ExclusivityData","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"nMoreWeeks","type":"uint256"}],"name":"extendExclusivityPeriod","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"extendExclusivityPricePerWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feePercentage","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPermittedContractReceivers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSecurityPolicy","outputs":[{"components":[{"internalType":"enum TransferSecurityLevels","name":"transferSecurityLevel","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversId","type":"uint120"}],"internalType":"struct CollectionSecurityPolicy","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"contract ICreatorTokenTransferValidator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWhitelistedOperators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"isContractReceiverPermitted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"isOperatorWhitelisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"isTransferAllowed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxExclusivityWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"qty","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"qty","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"mintTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"qty","type":"uint256"},{"internalType":"uint256","name":"dreamId","type":"uint256"}],"name":"mintToDream","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"processAccess","outputs":[{"internalType":"bool","name":"ok","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"refundAvailable","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"refunder","outputs":[{"internalType":"contract IRefunder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"components":[{"internalType":"uint64","name":"exclusivityWindow","type":"uint64"},{"internalType":"uint112","name":"premiumAccessMax","type":"uint112"},{"internalType":"uint112","name":"premiumAccessPrice","type":"uint112"},{"internalType":"bool","name":"sharesWithCrew","type":"bool"}],"internalType":"struct ExclusivityData","name":"exclusivityData_","type":"tuple"}],"name":"setExclusivityData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newExtendExclusivityPricePerWeek","type":"uint256"}],"name":"setExtendExclusivityPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newFeePercentage","type":"uint256"}],"name":"setFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newMaxExclusivityWindow","type":"uint256"}],"name":"setMaxExclusivityWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversAllowlistId","type":"uint120"}],"name":"setToCustomSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"validator","type":"address"},{"internalType":"enum TransferSecurityLevels","name":"level","type":"uint8"},{"internalType":"uint120","name":"operatorWhitelistId","type":"uint120"},{"internalType":"uint120","name":"permittedContractReceiversAllowlistId","type":"uint120"}],"name":"setToCustomValidatorAndSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setToDefaultSecurityPolicy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"supply","outputs":[{"components":[{"internalType":"uint128","name":"totalSupply","type":"uint128"},{"internalType":"uint128","name":"totalMinted","type":"uint128"}],"internalType":"struct Supply","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"newMax","type":"uint256"}],"name":"updatePremiumAccessMax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"},{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"updatePremiumAccessPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curationTokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60a06040526301dfe2006004556611c37937e080006005556064670de0b6b3a7640000600561002e919061031c565b6100389190610345565b600655348015610046575f5ffd5b50604051615b64380380615b648339810160408190526100659161037b565b816001600160a01b0316636352211e836001600160a01b031663d4263a536040518163ffffffff1660e01b8152600401602060405180830381865afa1580156100b0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100d491906103b3565b6040518263ffffffff1660e01b81526004016100f291815260200190565b602060405180830381865afa15801561010d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061013191906103ca565b826001600160a01b0316637c71035e6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561016d573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061019191906103b3565b61019b82826101c5565b50506001600160a01b03918216608052600380546001600160a01b031916919092161790556103ec565b6101cf828261021a565b6040516001600160601b03821681526001600160a01b038316907f8a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76ef9060200160405180910390a25050565b6127106001600160601b038216111561028d5760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b0382166102e35760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610284565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600155565b808202811582820484141761033f57634e487b7160e01b5f52601160045260245ffd5b92915050565b5f8261035f57634e487b7160e01b5f52601260045260245ffd5b500490565b6001600160a01b0381168114610378575f5ffd5b50565b5f5f6040838503121561038c575f5ffd5b825161039781610364565b60208401519092506103a881610364565b809150509250929050565b5f602082840312156103c3575f5ffd5b5051919050565b5f602082840312156103da575f5ffd5b81516103e581610364565b9392505050565b6080516156bf6104a55f395f8181610b1501528181610e0d01528181610e97015281816110f70152818161122b015281816112e7015281816113a0015281816114590152818161194d01528181611a9c01528181611be301528181611d3801528181611dba01528181611edf01528181612ba301528181612bc401528181612f93015281816130cb015281816131770152818161397401528181613cb801528181614112015281816142c9015261432e01526156bf5ff3fe6080604052600436106102ec575f3560e01c80636c3b869911610186578063b390c0ab116100dc578063e7d3fe6b11610087578063f242432a11610062578063f242432a14610a05578063f352f56f14610a24578063fd762d9214610a37575f5ffd5b8063e7d3fe6b146109b4578063e985e9c5146109c7578063ec0fb813146109e6575f5ffd5b8063c2ee3a08116100b7578063c2ee3a0814610959578063d007af5c14610974578063df4f5a7214610988575f5ffd5b8063b390c0ab14610905578063b5545a3c14610924578063be537f4314610938575f5ffd5b8063a001ecdd1161013c578063aa9b20be11610117578063aa9b20be146108b2578063ae06c1b7146108c7578063ae43a601146108e6575f5ffd5b8063a001ecdd1461085f578063a22cb46514610874578063a9fc664e14610893575f5ffd5b80636ff602101161016c5780636ff602101461070f5780637c44c511146107235780639d645a4414610840575f5ffd5b80636c3b8699146106e65780636f1b28be146106fa575f5ffd5b80632e8da829116102465780634854802e116101f15780635d4c1d46116101cc5780635d4c1d461461067457806361347162146106a85780636a9412bd146106c7575f5ffd5b80634854802e14610608578063495c8bf9146106275780634e1273f414610648575f5ffd5b80633540302311610221578063354030231461051f5780633788b083146105ca57806348302158146105e9575f5ffd5b80632e8da829146104c25780632eb2c2d6146104e15780633190b9ea14610500575f5ffd5b80630bca29c1116102a65780631c33b328116102815780631c33b328146104435780632a55205a146104645780632d2a2faf146104af575f5ffd5b80630bca29c1146103e55780630e89341c146103f85780631b25b07714610424575f5ffd5b806301ffc9a7116102d657806301ffc9a71461036c578063098144d41461039b5780630b32dd6f146103c4575f5ffd5b8062fdd58e146102f05780630146354614610322575b5f5ffd5b3480156102fb575f5ffd5b5061030f61030a366004614a61565b610a56565b6040519081526020015b60405180910390f35b34801561032d575f5ffd5b5061034771721c310194ccfc01e523fc93c9cccfa2a0ac81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610319565b348015610377575f5ffd5b5061038b610386366004614a8b565b610a7a565b6040519015158152602001610319565b3480156103a6575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff16610347565b3480156103cf575f5ffd5b506103e36103de366004614aca565b610aa2565b005b6103e36103f3366004614ae1565b610ae6565b348015610403575f5ffd5b50610417610412366004614aca565b6111f9565b6040516103199190614b01565b34801561042f575f5ffd5b5061038b61043e366004614b54565b61157d565b34801561044e575f5ffd5b50610457600181565b6040516103199190614c02565b34801561046f575f5ffd5b5061048361047e366004614ae1565b611642565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610319565b6103e36104bd366004614cd1565b611739565b3480156104cd575f5ffd5b5061038b6104dc366004614d70565b611fad565b3480156104ec575f5ffd5b506103e36104fb366004614e0a565b612110565b34801561050b575f5ffd5b506103e361051a366004614aca565b61212a565b34801561052a575f5ffd5b5061059a610539366004614aca565b604080518082019091525f8082526020820152505f908152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015290565b6040805182516fffffffffffffffffffffffffffffffff9081168252602093840151169281019290925201610319565b3480156105d5575f5ffd5b506103e36105e4366004614aca565b61215a565b3480156105f4575f5ffd5b506103e3610603366004614ae1565b612197565b348015610613575f5ffd5b506103e3610622366004614ae1565b612454565b348015610632575f5ffd5b5061063b61260e565b6040516103199190614ecd565b348015610653575f5ffd5b50610667610662366004614f25565b612787565b6040516103199190614f91565b34801561067f575f5ffd5b50610688600181565b6040516effffffffffffffffffffffffffffff9091168152602001610319565b3480156106b3575f5ffd5b506103e36106c2366004614ff0565b6127f4565b3480156106d2575f5ffd5b5061030f6106e1366004614d70565b6129eb565b3480156106f1575f5ffd5b506103e3612a7d565b348015610705575f5ffd5b5061030f60055481565b34801561071a575f5ffd5b506103e3612b9e565b34801561072e575f5ffd5b506107dd61073d366004614aca565b604080516080810182525f808252602082018190529181018290526060810191909152505f908152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff90811693820193909352600190910154918216928101929092526e010000000000000000000000000000900460ff161515606082015290565b60405161031991905f60808201905067ffffffffffffffff83511682526dffffffffffffffffffffffffffff60208401511660208301526dffffffffffffffffffffffffffff604084015116604083015260608301511515606083015292915050565b34801561084b575f5ffd5b5061038b61085a366004614d70565b612c56565b34801561086a575f5ffd5b5061030f60065481565b34801561087f575f5ffd5b506103e361088e36600461503a565b612d78565b34801561089e575f5ffd5b506103e36108ad366004614d70565b612d86565b3480156108bd575f5ffd5b5061030f60045481565b3480156108d2575f5ffd5b506103e36108e1366004614aca565b612f4c565b3480156108f1575f5ffd5b5061038b610900366004614a61565b612f59565b348015610910575f5ffd5b506103e361091f366004614ae1565b6134cf565b34801561092f575f5ffd5b506103e3613586565b348015610943575f5ffd5b5061094c6135dc565b6040516103199190615071565b348015610964575f5ffd5b5061030f670de0b6b3a764000081565b34801561097f575f5ffd5b5061063b6136c3565b348015610993575f5ffd5b506003546103479073ffffffffffffffffffffffffffffffffffffffff1681565b6103e36109c23660046150bf565b6137cb565b3480156109d2575f5ffd5b5061038b6109e13660046150ea565b6137e5565b3480156109f1575f5ffd5b506103e3610a00366004615138565b613805565b348015610a10575f5ffd5b506103e3610a1f366004615200565b61395f565b6103e3610a32366004615277565b61396d565b348015610a42575f5ffd5b506103e3610a513660046152a0565b613a1f565b679a31110384e0b0c960205260148290525f81815260408120545b90505b92915050565b5f610a8482613bab565b80610a935750610a9382613c1d565b80610a745750610a7482613c1d565b610aaa613cb3565b60058190556040518181527f8eca73c138af790ab3673dfd365ad1ab960959cd2054584d280f17d533b12640906020015b60405180910390a150565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa158015610b6f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9391906152f9565b505f828152600760209081526040918290208251608081018452815467ffffffffffffffff81168083526dffffffffffffffffffffffffffff680100000000000000009092048216948301949094526001909201549182169381019390935260ff6e01000000000000000000000000000090910416151560608301524210610c47576040517f6fb940a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f62093a80600454610c599190615341565b905080831115610c95576040517f716f95ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60055484610ca49190615379565b9050803414610ce7576040517f4a85e9b5000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b610cf48462093a80615379565b83518490610d03908390615390565b67ffffffffffffffff9081169091525f87815260076020908152604080832088518154848b01516dffffffffffffffffffffffffffff90811668010000000000000000027fffffffffffffffffffff000000000000000000000000000000000000000000009092169290971691909117178155818901516001909101805460608b015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff00000000000000000000000000000090911692909616919091179490941790935582517f87d14763000000000000000000000000000000000000000000000000000000008152925191935073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016926387d1476392600480830193928290030181865afa158015610e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7691906152f9565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663bf2bf05b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d97604348a6040518263ffffffff1660e01b8152600401610ef091815260200190565b602060405180830381865afa158015610f0b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2f91906152f9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610f96573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fba91906152f9565b6040517fe328acf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80831660048301529192509083169063e328acf890602401602060405180830381865afa158015611028573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104c91906153b0565b156110f4576040517f936450a000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526110f4919084169063936450a090602401602060405180830381865afa1580156110c0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e491906152f9565b6110ef600286615341565b613d48565b5f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f811461116a576040519150601f19603f3d011682016040523d82523d5f602084013e61116f565b606091505b50509050806111aa576040517f7d376dff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8551604080518a815267ffffffffffffffff90921660208301527f3acb1dd14adae9cca029019390e0bc436b2c13860959da818d9732c871ba39df910160405180910390a15050505050505050565b6040517f8750a4b4000000000000000000000000000000000000000000000000000000008152600481018290526060907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690638750a4b490602401602060405180830381865afa158015611285573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112a991906153b0565b801561142057503332148061136557506040517f41e0ae230000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906341e0ae2390602401602060405180830381865afa158015611341573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136591906153b0565b8061141e57506040517fcdf1bcc6000000000000000000000000000000000000000000000000000000008152600481018390523360248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063cdf1bcc690604401602060405180830381865afa1580156113fa573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141e91906153b0565b155b15611457576040517f72759a0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631dd640576040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114e491906152f9565b73ffffffffffffffffffffffffffffffffffffffff16630d4690a1836040518263ffffffff1660e01b815260040161151e91815260200190565b5f60405180830381865afa158015611538573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a7491908101906153cb565b5f805473ffffffffffffffffffffffffffffffffffffffff1615611637575f546040517f285fb8c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015284811660448301529091169063285fb8c8906064015f6040518083038186803b158015611613575f5ffd5b505afa925050508015611624575060015b61162f57505f61163b565b50600161163b565b5060015b9392505050565b5f82815260026020908152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169282019290925282916116fc57506040805180820190915260015473ffffffffffffffffffffffffffffffffffffffff811682527401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1660208201525b60208101515f906127109061171f906bffffffffffffffffffffffff1687615379565b6117299190615341565b91519350909150505b9250929050565b5f848152600760209081526040918290208251608081018452815467ffffffffffffffff81168083526dffffffffffffffffffffffffffff680100000000000000009092048216948301949094526001909201549182169381019390935260ff6e010000000000000000000000000000909104161515606083015242106117ec576040517f716f95ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f858152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff808216845270010000000000000000000000000000000090910416828201819052908301516dffffffffffffffffffffffffffff16906118579087615440565b111561188f576040517ff1e8bd7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84816020018181516118a19190615453565b6fffffffffffffffffffffffffffffffff169052508051859082906118c7908390615453565b6fffffffffffffffffffffffffffffffff9081169091525f888152600860209081526040918290208551918601518416700100000000000000000000000000000000029190931617909155517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169150636352211e9061198790899060040190815260200190565b602060405180830381865afa1580156119a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119c691906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611f99575f82604001516dffffffffffffffffffffffffffff1686611a199190615379565b905080341015611a58576040517f4a85e9b500000000000000000000000000000000000000000000000000000000815260048101829052602401610cde565b5f611a63823461547b565b90508015611a7557611a753382613d87565b5f670de0b6b3a764000083600654611a8d9190615379565b611a979190615341565b90505f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b17535b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b03573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b2791906152f9565b73ffffffffffffffffffffffffffffffffffffffff1663899021728b6040518263ffffffff1660e01b8152600401611b6191815260200190565b602060405180830381865afa158015611b7c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ba0919061548e565b905081841115611ed657806006811115611bbc57611bbc614b9c565b5f108015611bdb57506005816006811115611bd957611bd9614b9c565b105b15611ea4575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634499e42c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c4a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c6e91906152f9565b6040517f709be03b000000000000000000000000000000000000000000000000000000008152600481018d905290915060019073ffffffffffffffffffffffffffffffffffffffff83169063709be03b90602401602060405180830381865afa158015611cdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0191906154a9565b1015611e1d576040517fa278d7c0000000000000000000000000000000000000000000000000000000008152600481018c90525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063a278d7c0906024016040805180830381865afa158015611d91573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611db591906154c0565b9150507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611e1757611e1781858803613d87565b50611e9e565b6040517fe2eab483000000000000000000000000000000000000000000000000000000008152600481018c905273ffffffffffffffffffffffffffffffffffffffff82169063e2eab48390858803906024015f604051808303818588803b158015611e86575f5ffd5b505af1158015611e98573d5f5f3e3d5ffd5b50505050505b50611ed6565b6040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4715611f94575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f8114611f52576040519150601f19603f3d011682016040523d82523d5f602084013e611f57565b606091505b5050905080611f92576040517f7d376dff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050505b611fa584878786613e0e565b505050505050565b5f805473ffffffffffffffffffffffffffffffffffffffff1615612109575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063d72dde5e90829063b955455290602401606060405180830381865afa15801561203e573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061206291906154e4565b602001516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff851660248201526044015b602060405180830381865afa1580156120e5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7491906153b0565b505f919050565b6121208888888888888888613e9f565b5050505050505050565b6040518181527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790602001610adb565b612162613cb3565b60048190556040518181527ff43bb1cda675b232582f93e875f8cd862e2fb145d522a172865facc6858294b190602001610adb565b6dffffffffffffffffffffffffffff8111156121df576040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121e8826140e3565b5f60075f8481526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168152602001600182015f9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600e9054906101000a900460ff16151515158152505090508181604001906dffffffffffffffffffffffffffff1690816dffffffffffffffffffffffffffff16815250508060075f8581526020019081526020015f205f820151815f015f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506020820151815f0160086101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506040820151816001015f6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600e6101000a81548160ff0219169083151502179055509050507fb4cc9d8a7f2087aa77b6f44d52ef6b8bf25cfec23994680b6f9c399df42a26ba8383604051612413929190918252602082015260400190565b60405180910390a16040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7906020015b60405180910390a1505050565b61245d826140e3565b5f828152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff908116938201849052600190920154918216938101939093526e010000000000000000000000000000900460ff1615156060830152821061250d576040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6dffffffffffffffffffffffffffff80831660208084019182525f8681526007909152604090819020845181549351851668010000000000000000027fffffffffffffffffffff0000000000000000000000000000000000000000000090941667ffffffffffffffff909116179290921782558084015160019092018054606086015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff0000000000000000000000000000009091169390941692909217929092179055517fcca1b1528ca3159b50e18f402b9200bbf6d4f280db11b8945a9f55cae1ca64c5906124139085908590918252602082015260400190565b5f5460609073ffffffffffffffffffffffffffffffffffffffff1615612775575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690633fe5df9990829063b955455290602401606060405180830381865afa1580156126a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126c591906154e4565b602001516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff90911660048201526024015b5f60405180830381865afa15801561272b573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526127709190810190615556565b905090565b50604080515f81526020810190915290565b606083821461279d57633b800a465f526004601cfd5b6040519050818152602081018260051b8181016040525b80156127ea57602081039050808701358060601b679a31110384e0b0c91760205250808501355f5260405f2054818301526127b4565b5050949350505050565b6127fc613cb3565b5f5473ffffffffffffffffffffffffffffffffffffffff168061284b576040517f39ffc7ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fda0194c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063da0194c09061289f903090889060040161560a565b5f604051808303815f87803b1580156128b6575f5ffd5b505af11580156128c8573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8616602482015273ffffffffffffffffffffffffffffffffffffffff84169250632304aa0291506044015f604051808303815f87803b158015612947575f5ffd5b505af1158015612959573d5f5f3e3d5ffd5b50506040517f8d7443140000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff84169250638d74431491506044015b5f604051808303815f87803b1580156129d9575f5ffd5b505af1158015612120573d5f5f3e3d5ffd5b6003546040517f6a9412bd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301525f921690636a9412bd90602401602060405180830381865afa158015612a59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7491906154a9565b612a85613cb3565b612aa071721c310194ccfc01e523fc93c9cccfa2a0ac612d86565b6040517fda0194c000000000000000000000000000000000000000000000000000000000815271721c310194ccfc01e523fc93c9cccfa2a0ac9063da0194c090612af190309060019060040161560a565b5f604051808303815f87803b158015612b08575f5ffd5b505af1158015612b1a573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526001602482015271721c310194ccfc01e523fc93c9cccfa2a0ac9250632304aa0291506044015b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050565b612c547f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16637c71035e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c2b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c4f91906154a9565b6141f7565b565b5f805473ffffffffffffffffffffffffffffffffffffffff1615612109575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690639445f53090829063b955455290602401606060405180830381865afa158015612ce7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d0b91906154e4565b60409081015190517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff851660248201526044016120ca565b612d82828261425e565b5050565b612d8e613cb3565b5f73ffffffffffffffffffffffffffffffffffffffff82163b15612e58576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff8316906301ffc9a790602401602060405180830381865afa925050508015612e50575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612e4d918101906153b0565b60015b15612e585790505b73ffffffffffffffffffffffffffffffffffffffff821615801590612e7b575080155b15612eb2576040517f32483afb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac910160405180910390a1505f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612f54613cb3565b600655565b5f612f626142b1565b6040517f4f558e79000000000000000000000000000000000000000000000000000000008152600481018390525f907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690634f558e7990602401602060405180830381865afa158015612fed573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061301191906153b0565b5f848152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff90811693820193909352600190910154918216928101929092526e010000000000000000000000000000900460ff16151560608201529091508180156130a55750805167ffffffffffffffff164210155b156130b557600192505050610a74565b8180156130c3575080606001515b156133f3575f7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166387d147636040518163ffffffff1660e01b8152600401602060405180830381865afa158015613132573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061315691906152f9565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663bf2bf05b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d9760434896040518263ffffffff1660e01b81526004016131d091815260200190565b602060405180830381865afa1580156131eb573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320f91906152f9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015613276573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061329a91906152f9565b6040517fe328acf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80831660048301529192509083169063e328acf890602401602060405180830381865afa158015613308573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061332c91906153b0565b80156133de57506040517fbf2bf05b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152808316919084169063bf2bf05b90602401602060405180830381865afa1580156133a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133c691906152f9565b73ffffffffffffffffffffffffffffffffffffffff16145b156133f0576001945050505050610a74565b50505b60016133ff8686610a56565b101561340f575f92505050610a74565b5f848152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168085527001000000000000000000000000000000009092041691830191909152600190829061346d908390615634565b6fffffffffffffffffffffffffffffffff9081169091525f87815260086020908152604090912084519185015183167001000000000000000000000000000000000291909216179055506134c386866001614320565b50600195945050505050565b5f828152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff80821680855270010000000000000000000000000000000090920416918301919091528290829061352c908390615634565b6fffffffffffffffffffffffffffffffff9081169091525f8581526008602090815260409091208451918501518316700100000000000000000000000000000000029190921617905550613581338484614320565b505050565b6003546040517fbffa55d500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063bffa55d590602401612b6f565b604080516060810182525f80825260208201819052918101829052905473ffffffffffffffffffffffffffffffffffffffff16156136a3575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063b955455290602401606060405180830381865afa15801561367f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061277091906154e4565b50604080516060810182525f808252602082018190529181019190915290565b5f5460609073ffffffffffffffffffffffffffffffffffffffff1615612775575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906317e94a6c90829063b955455290602401606060405180830381865afa158015613756573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061377a91906154e4565b60409081015190517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff9091166004820152602401612711565b61358183838360405180602001604052805f815250611739565b679a31110384e0b0c960205260148290525f8181526034600c2054610a71565b61380d61432c565b6004548151829167ffffffffffffffff90911610613857576040517f3f506beb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42815f018181516138689190615390565b67ffffffffffffffff9081169091525f8581526007602090815260409182902085518154878401516dffffffffffffffffffffffffffff90811668010000000000000000027fffffffffffffffffffff0000000000000000000000000000000000000000000090921692909616919091171781558583015160019091018054606088015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff000000000000000000000000000000909116929095169190911793909317909255518581527ffaebf92d40203b20cab7d4dca7df7753513d98c27111c3f22a1d248022d0633d925001612447565b611fa586868686868661441d565b61358183837f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bb3df8b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139ff91906152f9565b604080516020810187905201604051602081830303815290604052611739565b613a27613cb3565b613a3084612d86565b6040517fda0194c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063da0194c090613a84903090879060040161560a565b5f604051808303815f87803b158015613a9b575f5ffd5b505af1158015613aad573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff87169250632304aa0291506044015f604051808303815f87803b158015613b2c575f5ffd5b505af1158015613b3e573d5f5f3e3d5ffd5b50506040517f8d7443140000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8416602482015273ffffffffffffffffffffffffffffffffffffffff87169250638d74431491506044016129c2565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f86455d28000000000000000000000000000000000000000000000000000000001480610a745750610a74826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610a7457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a74565b612c547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663d4263a536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d1f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d4391906154a9565b6140e3565b80471015613d5d5763b12d13eb5f526004601cfd5b5f385f388486620186a0f1612d8257815f526073600b5360ff6020536016600b82f0612d82573838fd5b6003546040517f2d806cdd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015290911690632d806cdd9083906024015f604051808303818588803b158015613df3575f5ffd5b505af1158015613e05573d5f5f3e3d5ffd5b50505050505050565b8360601b80613e245763ea553b345f526004601cfd5b679a31110384e0b0c960205284601452835f5260405f20805484810181811015613e55576301336cea5f526004601cfd5b808355505050826020528060601c5f337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa450833b15612b9857612b985f858585856145f2565b828514613eb357633b800a465f526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c985088613ef15763ea553b345f526004601cfd5b893314613f1257335f526034600c2054613f1257634b6e7f185f526004601cfd5b8660051b5b8015613f7f576020810390508087013583602052818a01355f5260405f20805480831115613f4c5763f4d678b85f526004601cfd5b8290039055602083905260405f20805480830181811015613f74576301336cea5f526004601cfd5b90915550613f179050565b505050604051604081528560051b602001604082018160208a03823781604001602084015281602088038383013750888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60408586010186a45050613fe35f90565b15613ff857613ff88888888888888888614695565b863b1561212057865f5260405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a001806080850152826020890384840137820160a0840152602084017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0860183800183013750808101830160c401905060208282601c85015f5f515af16140a2573d156140a2573d5f833e3d82fd5b5080517fbc197c8100000000000000000000000000000000000000000000000000000000146140d857639c05499b5f526004601cfd5b505050505050505050565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa15801561416c573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061419091906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146141f4576040517f8c1971dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b614201828261469a565b6040516bffffffffffffffffffffffff8216815273ffffffffffffffffffffffffffffffffffffffff8316907f8a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76ef9060200160405180910390a25050565b8015159050679a31110384e0b0c960205233601452815f52806034600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612c54576040517f489aea9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6135815f848484614813565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663b17535b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015614395573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143b991906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612c54576040517f237257bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c96508661445b5763ea553b345f526004601cfd5b87331461447c57335f526034600c205461447c57634b6e7f185f526004601cfd5b855f5260405f20915081548086111561449c5763f4d678b85f526004601cfd5b8581038355508060205260405f2091508154858101818110156144c6576301336cea5f526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa4843b15611fa55760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c84015f8a5af1614555573d15614555573d5f823e3d81fd5b80517ff23a6e610000000000000000000000000000000000000000000000000000000014613e0557639c05499b5f526004601cfd5b81811015613e05576145b687878784815181106145a9576145a961565c565b60200260200101516148a9565b60010161458a565b81811015613e05576145ea87878784815181106145dd576145dd61565c565b602002602001015161492c565b6001016145be565b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c0830152801561463e578060e08301826020860160045afa505b6020828260c401601c85015f8a5af161465f573d1561465f573d5f833e3d82fd5b5080517ff23a6e610000000000000000000000000000000000000000000000000000000014611fa557639c05499b5f526004601cfd5b612120565b6127106bffffffffffffffffffffffff8216111561473a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c2065786365656460448201527f2073616c655072696365000000000000000000000000000000000000000000006064820152608401610cde565b73ffffffffffffffffffffffffffffffffffffffff82166147b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610cde565b6040805180820190915273ffffffffffffffffffffffffffffffffffffffff9092168083526bffffffffffffffffffffffff90911660209092018290527401000000000000000000000000000000000000000090910217600155565b8260601b80679a31110384e0b0c917602052808560601b148560601b151761484f57845f526034600c205461484f57634b6e7f185f526004601cfd5b825f5260405f2080548084111561486d5763f4d678b85f526004601cfd5b83810382555050816020525f8160601c337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa450612b98565b73ffffffffffffffffffffffffffffffffffffffff83811615908316158180156148d05750805b15614907576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115614913575b614925565b8061490e576149253386868634614999565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff83811615908316158180156149535750805b1561498a576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8161490e578061490e57614925565b5f5473ffffffffffffffffffffffffffffffffffffffff1615614925575f546040517f285fb8c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015285811660448301529091169063285fb8c8906064015f6040518083038186803b158015614a2e575f5ffd5b505afa1580156140d8573d5f5f3e3d5ffd5b73ffffffffffffffffffffffffffffffffffffffff811681146141f4575f5ffd5b5f5f60408385031215614a72575f5ffd5b8235614a7d81614a40565b946020939093013593505050565b5f60208284031215614a9b575f5ffd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461163b575f5ffd5b5f60208284031215614ada575f5ffd5b5035919050565b5f5f60408385031215614af2575f5ffd5b50508035926020909101359150565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60608486031215614b66575f5ffd5b8335614b7181614a40565b92506020840135614b8181614a40565b91506040840135614b9181614a40565b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60078110614bfe577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610a748284614bc9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614c8457614c84614c10565b604052919050565b5f67ffffffffffffffff821115614ca557614ca5614c10565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f5f5f5f60808587031215614ce4575f5ffd5b84359350602085013592506040850135614cfd81614a40565b9150606085013567ffffffffffffffff811115614d18575f5ffd5b8501601f81018713614d28575f5ffd5b8035614d3b614d3682614c8c565b614c3d565b818152886020838501011115614d4f575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f60208284031215614d80575f5ffd5b813561163b81614a40565b5f5f83601f840112614d9b575f5ffd5b50813567ffffffffffffffff811115614db2575f5ffd5b6020830191508360208260051b8501011115611732575f5ffd5b5f5f83601f840112614ddc575f5ffd5b50813567ffffffffffffffff811115614df3575f5ffd5b602083019150836020828501011115611732575f5ffd5b5f5f5f5f5f5f5f5f60a0898b031215614e21575f5ffd5b8835614e2c81614a40565b97506020890135614e3c81614a40565b9650604089013567ffffffffffffffff811115614e57575f5ffd5b614e638b828c01614d8b565b909750955050606089013567ffffffffffffffff811115614e82575f5ffd5b614e8e8b828c01614d8b565b909550935050608089013567ffffffffffffffff811115614ead575f5ffd5b614eb98b828c01614dcc565b999c989b5096995094979396929594505050565b602080825282518282018190525f918401906040840190835b81811015614f1a57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101614ee6565b509095945050505050565b5f5f5f5f60408587031215614f38575f5ffd5b843567ffffffffffffffff811115614f4e575f5ffd5b614f5a87828801614d8b565b909550935050602085013567ffffffffffffffff811115614f79575f5ffd5b614f8587828801614d8b565b95989497509550505050565b602080825282518282018190525f918401906040840190835b81811015614f1a578351835260209384019390920191600101614faa565b600781106141f4575f5ffd5b6effffffffffffffffffffffffffffff811681146141f4575f5ffd5b5f5f5f60608486031215615002575f5ffd5b833561500d81614fc8565b9250602084013561501d81614fd4565b91506040840135614b9181614fd4565b80151581146141f4575f5ffd5b5f5f6040838503121561504b575f5ffd5b823561505681614a40565b915060208301356150668161502d565b809150509250929050565b5f606082019050615083828451614bc9565b6effffffffffffffffffffffffffffff60208401511660208301526effffffffffffffffffffffffffffff604084015116604083015292915050565b5f5f5f606084860312156150d1575f5ffd5b83359250602084013591506040840135614b9181614a40565b5f5f604083850312156150fb575f5ffd5b823561510681614a40565b9150602083013561506681614a40565b80356dffffffffffffffffffffffffffff81168114615133575f5ffd5b919050565b5f5f82840360a081121561514a575f5ffd5b8335925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561517d575f5ffd5b506040516080810167ffffffffffffffff811182821017156151a1576151a1614c10565b604052602084013567ffffffffffffffff811681146151be575f5ffd5b81526151cc60408501615116565b60208201526151dd60608501615116565b604082015260808401356151f08161502d565b6060820152919491935090915050565b5f5f5f5f5f5f60a08789031215615215575f5ffd5b863561522081614a40565b9550602087013561523081614a40565b94506040870135935060608701359250608087013567ffffffffffffffff811115615259575f5ffd5b61526589828a01614dcc565b979a9699509497509295939492505050565b5f5f5f60608486031215615289575f5ffd5b505081359360208301359350604090920135919050565b5f5f5f5f608085870312156152b3575f5ffd5b84356152be81614a40565b935060208501356152ce81614fc8565b925060408501356152de81614fd4565b915060608501356152ee81614fd4565b939692955090935050565b5f60208284031215615309575f5ffd5b815161163b81614a40565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82615374577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8082028115828204841417610a7457610a74615314565b67ffffffffffffffff8181168382160190811115610a7457610a74615314565b5f602082840312156153c0575f5ffd5b815161163b8161502d565b5f602082840312156153db575f5ffd5b815167ffffffffffffffff8111156153f1575f5ffd5b8201601f81018413615401575f5ffd5b805161540f614d3682614c8c565b818152856020838501011115615423575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b80820180821115610a7457610a74615314565b6fffffffffffffffffffffffffffffffff8181168382160190811115610a7457610a74615314565b81810381811115610a7457610a74615314565b5f6020828403121561549e575f5ffd5b815161163b81614fc8565b5f602082840312156154b9575f5ffd5b5051919050565b5f5f604083850312156154d1575f5ffd5b8251602084015190925061506681614a40565b5f60608284031280156154f5575f5ffd5b506040516060810167ffffffffffffffff8111828210171561551957615519614c10565b604052825161552781614fc8565b8152602083015161553781614fd4565b6020820152604083015161554a81614fd4565b60408201529392505050565b5f60208284031215615566575f5ffd5b815167ffffffffffffffff81111561557c575f5ffd5b8201601f8101841361558c575f5ffd5b805167ffffffffffffffff8111156155a6576155a6614c10565b8060051b6155b660208201614c3d565b918252602081840181019290810190878411156155d1575f5ffd5b6020850194505b838510156155ff57845192506155ed83614a40565b828252602094850194909101906155d8565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040810161163b6020830184614bc9565b6fffffffffffffffffffffffffffffffff8281168282160390811115610a7457610a74615314565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea2646970667358221220ba99c50716540a56af8ce692099688457d33c2348583db9e064b7c2c5dae5cc664736f6c634300081c003300000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c810000000000000000000000005006680feec67c5deb2bbd0da4e1fa4db619bc99
Deployed Bytecode
0x6080604052600436106102ec575f3560e01c80636c3b869911610186578063b390c0ab116100dc578063e7d3fe6b11610087578063f242432a11610062578063f242432a14610a05578063f352f56f14610a24578063fd762d9214610a37575f5ffd5b8063e7d3fe6b146109b4578063e985e9c5146109c7578063ec0fb813146109e6575f5ffd5b8063c2ee3a08116100b7578063c2ee3a0814610959578063d007af5c14610974578063df4f5a7214610988575f5ffd5b8063b390c0ab14610905578063b5545a3c14610924578063be537f4314610938575f5ffd5b8063a001ecdd1161013c578063aa9b20be11610117578063aa9b20be146108b2578063ae06c1b7146108c7578063ae43a601146108e6575f5ffd5b8063a001ecdd1461085f578063a22cb46514610874578063a9fc664e14610893575f5ffd5b80636ff602101161016c5780636ff602101461070f5780637c44c511146107235780639d645a4414610840575f5ffd5b80636c3b8699146106e65780636f1b28be146106fa575f5ffd5b80632e8da829116102465780634854802e116101f15780635d4c1d46116101cc5780635d4c1d461461067457806361347162146106a85780636a9412bd146106c7575f5ffd5b80634854802e14610608578063495c8bf9146106275780634e1273f414610648575f5ffd5b80633540302311610221578063354030231461051f5780633788b083146105ca57806348302158146105e9575f5ffd5b80632e8da829146104c25780632eb2c2d6146104e15780633190b9ea14610500575f5ffd5b80630bca29c1116102a65780631c33b328116102815780631c33b328146104435780632a55205a146104645780632d2a2faf146104af575f5ffd5b80630bca29c1146103e55780630e89341c146103f85780631b25b07714610424575f5ffd5b806301ffc9a7116102d657806301ffc9a71461036c578063098144d41461039b5780630b32dd6f146103c4575f5ffd5b8062fdd58e146102f05780630146354614610322575b5f5ffd5b3480156102fb575f5ffd5b5061030f61030a366004614a61565b610a56565b6040519081526020015b60405180910390f35b34801561032d575f5ffd5b5061034771721c310194ccfc01e523fc93c9cccfa2a0ac81565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610319565b348015610377575f5ffd5b5061038b610386366004614a8b565b610a7a565b6040519015158152602001610319565b3480156103a6575f5ffd5b505f5473ffffffffffffffffffffffffffffffffffffffff16610347565b3480156103cf575f5ffd5b506103e36103de366004614aca565b610aa2565b005b6103e36103f3366004614ae1565b610ae6565b348015610403575f5ffd5b50610417610412366004614aca565b6111f9565b6040516103199190614b01565b34801561042f575f5ffd5b5061038b61043e366004614b54565b61157d565b34801561044e575f5ffd5b50610457600181565b6040516103199190614c02565b34801561046f575f5ffd5b5061048361047e366004614ae1565b611642565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610319565b6103e36104bd366004614cd1565b611739565b3480156104cd575f5ffd5b5061038b6104dc366004614d70565b611fad565b3480156104ec575f5ffd5b506103e36104fb366004614e0a565b612110565b34801561050b575f5ffd5b506103e361051a366004614aca565b61212a565b34801561052a575f5ffd5b5061059a610539366004614aca565b604080518082019091525f8082526020820152505f908152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015290565b6040805182516fffffffffffffffffffffffffffffffff9081168252602093840151169281019290925201610319565b3480156105d5575f5ffd5b506103e36105e4366004614aca565b61215a565b3480156105f4575f5ffd5b506103e3610603366004614ae1565b612197565b348015610613575f5ffd5b506103e3610622366004614ae1565b612454565b348015610632575f5ffd5b5061063b61260e565b6040516103199190614ecd565b348015610653575f5ffd5b50610667610662366004614f25565b612787565b6040516103199190614f91565b34801561067f575f5ffd5b50610688600181565b6040516effffffffffffffffffffffffffffff9091168152602001610319565b3480156106b3575f5ffd5b506103e36106c2366004614ff0565b6127f4565b3480156106d2575f5ffd5b5061030f6106e1366004614d70565b6129eb565b3480156106f1575f5ffd5b506103e3612a7d565b348015610705575f5ffd5b5061030f60055481565b34801561071a575f5ffd5b506103e3612b9e565b34801561072e575f5ffd5b506107dd61073d366004614aca565b604080516080810182525f808252602082018190529181018290526060810191909152505f908152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff90811693820193909352600190910154918216928101929092526e010000000000000000000000000000900460ff161515606082015290565b60405161031991905f60808201905067ffffffffffffffff83511682526dffffffffffffffffffffffffffff60208401511660208301526dffffffffffffffffffffffffffff604084015116604083015260608301511515606083015292915050565b34801561084b575f5ffd5b5061038b61085a366004614d70565b612c56565b34801561086a575f5ffd5b5061030f60065481565b34801561087f575f5ffd5b506103e361088e36600461503a565b612d78565b34801561089e575f5ffd5b506103e36108ad366004614d70565b612d86565b3480156108bd575f5ffd5b5061030f60045481565b3480156108d2575f5ffd5b506103e36108e1366004614aca565b612f4c565b3480156108f1575f5ffd5b5061038b610900366004614a61565b612f59565b348015610910575f5ffd5b506103e361091f366004614ae1565b6134cf565b34801561092f575f5ffd5b506103e3613586565b348015610943575f5ffd5b5061094c6135dc565b6040516103199190615071565b348015610964575f5ffd5b5061030f670de0b6b3a764000081565b34801561097f575f5ffd5b5061063b6136c3565b348015610993575f5ffd5b506003546103479073ffffffffffffffffffffffffffffffffffffffff1681565b6103e36109c23660046150bf565b6137cb565b3480156109d2575f5ffd5b5061038b6109e13660046150ea565b6137e5565b3480156109f1575f5ffd5b506103e3610a00366004615138565b613805565b348015610a10575f5ffd5b506103e3610a1f366004615200565b61395f565b6103e3610a32366004615277565b61396d565b348015610a42575f5ffd5b506103e3610a513660046152a0565b613a1f565b679a31110384e0b0c960205260148290525f81815260408120545b90505b92915050565b5f610a8482613bab565b80610a935750610a9382613c1d565b80610a745750610a7482613c1d565b610aaa613cb3565b60058190556040518181527f8eca73c138af790ab3673dfd365ad1ab960959cd2054584d280f17d533b12640906020015b60405180910390a150565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018390527f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa158015610b6f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9391906152f9565b505f828152600760209081526040918290208251608081018452815467ffffffffffffffff81168083526dffffffffffffffffffffffffffff680100000000000000009092048216948301949094526001909201549182169381019390935260ff6e01000000000000000000000000000090910416151560608301524210610c47576040517f6fb940a900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f62093a80600454610c599190615341565b905080831115610c95576040517f716f95ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60055484610ca49190615379565b9050803414610ce7576040517f4a85e9b5000000000000000000000000000000000000000000000000000000008152600481018290526024015b60405180910390fd5b610cf48462093a80615379565b83518490610d03908390615390565b67ffffffffffffffff9081169091525f87815260076020908152604080832088518154848b01516dffffffffffffffffffffffffffff90811668010000000000000000027fffffffffffffffffffff000000000000000000000000000000000000000000009092169290971691909117178155818901516001909101805460608b015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff00000000000000000000000000000090911692909616919091179490941790935582517f87d14763000000000000000000000000000000000000000000000000000000008152925191935073ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8116926387d1476392600480830193928290030181865afa158015610e52573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e7691906152f9565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663bf2bf05b7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663d97604348a6040518263ffffffff1660e01b8152600401610ef091815260200190565b602060405180830381865afa158015610f0b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f2f91906152f9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015610f96573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610fba91906152f9565b6040517fe328acf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80831660048301529192509083169063e328acf890602401602060405180830381865afa158015611028573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061104c91906153b0565b156110f4576040517f936450a000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301526110f4919084169063936450a090602401602060405180830381865afa1580156110c0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110e491906152f9565b6110ef600286615341565b613d48565b5f7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f811461116a576040519150601f19603f3d011682016040523d82523d5f602084013e61116f565b606091505b50509050806111aa576040517f7d376dff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8551604080518a815267ffffffffffffffff90921660208301527f3acb1dd14adae9cca029019390e0bc436b2c13860959da818d9732c871ba39df910160405180910390a15050505050505050565b6040517f8750a4b4000000000000000000000000000000000000000000000000000000008152600481018290526060907f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1690638750a4b490602401602060405180830381865afa158015611285573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112a991906153b0565b801561142057503332148061136557506040517f41e0ae230000000000000000000000000000000000000000000000000000000081523360048201527f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16906341e0ae2390602401602060405180830381865afa158015611341573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061136591906153b0565b8061141e57506040517fcdf1bcc6000000000000000000000000000000000000000000000000000000008152600481018390523360248201527f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff169063cdf1bcc690604401602060405180830381865afa1580156113fa573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061141e91906153b0565b155b15611457576040517f72759a0000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16631dd640576040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114c0573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114e491906152f9565b73ffffffffffffffffffffffffffffffffffffffff16630d4690a1836040518263ffffffff1660e01b815260040161151e91815260200190565b5f60405180830381865afa158015611538573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610a7491908101906153cb565b5f805473ffffffffffffffffffffffffffffffffffffffff1615611637575f546040517f285fb8c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8681166004830152858116602483015284811660448301529091169063285fb8c8906064015f6040518083038186803b158015611613575f5ffd5b505afa925050508015611624575060015b61162f57505f61163b565b50600161163b565b5060015b9392505050565b5f82815260026020908152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff169282019290925282916116fc57506040805180820190915260015473ffffffffffffffffffffffffffffffffffffffff811682527401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1660208201525b60208101515f906127109061171f906bffffffffffffffffffffffff1687615379565b6117299190615341565b91519350909150505b9250929050565b5f848152600760209081526040918290208251608081018452815467ffffffffffffffff81168083526dffffffffffffffffffffffffffff680100000000000000009092048216948301949094526001909201549182169381019390935260ff6e010000000000000000000000000000909104161515606083015242106117ec576040517f716f95ea00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f858152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff808216845270010000000000000000000000000000000090910416828201819052908301516dffffffffffffffffffffffffffff16906118579087615440565b111561188f576040517ff1e8bd7d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84816020018181516118a19190615453565b6fffffffffffffffffffffffffffffffff169052508051859082906118c7908390615453565b6fffffffffffffffffffffffffffffffff9081169091525f888152600860209081526040918290208551918601518416700100000000000000000000000000000000029190931617909155517f6352211e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c81169150636352211e9061198790899060040190815260200190565b602060405180830381865afa1580156119a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119c691906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611f99575f82604001516dffffffffffffffffffffffffffff1686611a199190615379565b905080341015611a58576040517f4a85e9b500000000000000000000000000000000000000000000000000000000815260048101829052602401610cde565b5f611a63823461547b565b90508015611a7557611a753382613d87565b5f670de0b6b3a764000083600654611a8d9190615379565b611a979190615341565b90505f7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663b17535b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b03573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b2791906152f9565b73ffffffffffffffffffffffffffffffffffffffff1663899021728b6040518263ffffffff1660e01b8152600401611b6191815260200190565b602060405180830381865afa158015611b7c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611ba0919061548e565b905081841115611ed657806006811115611bbc57611bbc614b9c565b5f108015611bdb57506005816006811115611bd957611bd9614b9c565b105b15611ea4575f7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16634499e42c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611c4a573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c6e91906152f9565b6040517f709be03b000000000000000000000000000000000000000000000000000000008152600481018d905290915060019073ffffffffffffffffffffffffffffffffffffffff83169063709be03b90602401602060405180830381865afa158015611cdd573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611d0191906154a9565b1015611e1d576040517fa278d7c0000000000000000000000000000000000000000000000000000000008152600481018c90525f907f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff169063a278d7c0906024016040805180830381865afa158015611d91573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611db591906154c0565b9150507f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611e1757611e1781858803613d87565b50611e9e565b6040517fe2eab483000000000000000000000000000000000000000000000000000000008152600481018c905273ffffffffffffffffffffffffffffffffffffffff82169063e2eab48390858803906024015f604051808303818588803b158015611e86575f5ffd5b505af1158015611e98573d5f5f3e3d5ffd5b50505050505b50611ed6565b6040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b4715611f94575f7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16476040515f6040518083038185875af1925050503d805f8114611f52576040519150601f19603f3d011682016040523d82523d5f602084013e611f57565b606091505b5050905080611f92576040517f7d376dff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505b505050505b611fa584878786613e0e565b505050505050565b5f805473ffffffffffffffffffffffffffffffffffffffff1615612109575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063d72dde5e90829063b955455290602401606060405180830381865afa15801561203e573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061206291906154e4565b602001516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff851660248201526044015b602060405180830381865afa1580156120e5573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7491906153b0565b505f919050565b6121208888888888888888613e9f565b5050505050505050565b6040518181527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790602001610adb565b612162613cb3565b60048190556040518181527ff43bb1cda675b232582f93e875f8cd862e2fb145d522a172865facc6858294b190602001610adb565b6dffffffffffffffffffffffffffff8111156121df576040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6121e8826140e3565b5f60075f8481526020019081526020015f206040518060800160405290815f82015f9054906101000a900467ffffffffffffffff1667ffffffffffffffff1667ffffffffffffffff1681526020015f820160089054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168152602001600182015f9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16815260200160018201600e9054906101000a900460ff16151515158152505090508181604001906dffffffffffffffffffffffffffff1690816dffffffffffffffffffffffffffff16815250508060075f8581526020019081526020015f205f820151815f015f6101000a81548167ffffffffffffffff021916908367ffffffffffffffff1602179055506020820151815f0160086101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506040820151816001015f6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff160217905550606082015181600101600e6101000a81548160ff0219169083151502179055509050507fb4cc9d8a7f2087aa77b6f44d52ef6b8bf25cfec23994680b6f9c399df42a26ba8383604051612413929190918252602082015260400190565b60405180910390a16040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce7906020015b60405180910390a1505050565b61245d826140e3565b5f828152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff908116938201849052600190920154918216938101939093526e010000000000000000000000000000900460ff1615156060830152821061250d576040517f715622cd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6dffffffffffffffffffffffffffff80831660208084019182525f8681526007909152604090819020845181549351851668010000000000000000027fffffffffffffffffffff0000000000000000000000000000000000000000000090941667ffffffffffffffff909116179290921782558084015160019092018054606086015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff0000000000000000000000000000009091169390941692909217929092179055517fcca1b1528ca3159b50e18f402b9200bbf6d4f280db11b8945a9f55cae1ca64c5906124139085908590918252602082015260400190565b5f5460609073ffffffffffffffffffffffffffffffffffffffff1615612775575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690633fe5df9990829063b955455290602401606060405180830381865afa1580156126a1573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906126c591906154e4565b602001516040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff90911660048201526024015b5f60405180830381865afa15801561272b573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526127709190810190615556565b905090565b50604080515f81526020810190915290565b606083821461279d57633b800a465f526004601cfd5b6040519050818152602081018260051b8181016040525b80156127ea57602081039050808701358060601b679a31110384e0b0c91760205250808501355f5260405f2054818301526127b4565b5050949350505050565b6127fc613cb3565b5f5473ffffffffffffffffffffffffffffffffffffffff168061284b576040517f39ffc7ba00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fda0194c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82169063da0194c09061289f903090889060040161560a565b5f604051808303815f87803b1580156128b6575f5ffd5b505af11580156128c8573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8616602482015273ffffffffffffffffffffffffffffffffffffffff84169250632304aa0291506044015f604051808303815f87803b158015612947575f5ffd5b505af1158015612959573d5f5f3e3d5ffd5b50506040517f8d7443140000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff84169250638d74431491506044015b5f604051808303815f87803b1580156129d9575f5ffd5b505af1158015612120573d5f5f3e3d5ffd5b6003546040517f6a9412bd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301525f921690636a9412bd90602401602060405180830381865afa158015612a59573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610a7491906154a9565b612a85613cb3565b612aa071721c310194ccfc01e523fc93c9cccfa2a0ac612d86565b6040517fda0194c000000000000000000000000000000000000000000000000000000000815271721c310194ccfc01e523fc93c9cccfa2a0ac9063da0194c090612af190309060019060040161560a565b5f604051808303815f87803b158015612b08575f5ffd5b505af1158015612b1a573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526001602482015271721c310194ccfc01e523fc93c9cccfa2a0ac9250632304aa0291506044015b5f604051808303815f87803b158015612b86575f5ffd5b505af1158015612b98573d5f5f3e3d5ffd5b50505050565b612c547f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c817f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff16637c71035e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612c2b573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612c4f91906154a9565b6141f7565b565b5f805473ffffffffffffffffffffffffffffffffffffffff1615612109575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff90911690639445f53090829063b955455290602401606060405180830381865afa158015612ce7573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d0b91906154e4565b60409081015190517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff909116600482015273ffffffffffffffffffffffffffffffffffffffff851660248201526044016120ca565b612d82828261425e565b5050565b612d8e613cb3565b5f73ffffffffffffffffffffffffffffffffffffffff82163b15612e58576040517f01ffc9a70000000000000000000000000000000000000000000000000000000081525f600482015273ffffffffffffffffffffffffffffffffffffffff8316906301ffc9a790602401602060405180830381865afa925050508015612e50575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252612e4d918101906153b0565b60015b15612e585790505b73ffffffffffffffffffffffffffffffffffffffff821615801590612e7b575080155b15612eb2576040517f32483afb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f546040805173ffffffffffffffffffffffffffffffffffffffff928316815291841660208301527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac910160405180910390a1505f80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b612f54613cb3565b600655565b5f612f626142b1565b6040517f4f558e79000000000000000000000000000000000000000000000000000000008152600481018390525f907f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1690634f558e7990602401602060405180830381865afa158015612fed573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061301191906153b0565b5f848152600760209081526040918290208251608081018452815467ffffffffffffffff811682526801000000000000000090046dffffffffffffffffffffffffffff90811693820193909352600190910154918216928101929092526e010000000000000000000000000000900460ff16151560608201529091508180156130a55750805167ffffffffffffffff164210155b156130b557600192505050610a74565b8180156130c3575080606001515b156133f3575f7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff166387d147636040518163ffffffff1660e01b8152600401602060405180830381865afa158015613132573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061315691906152f9565b90505f8173ffffffffffffffffffffffffffffffffffffffff1663bf2bf05b7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663d9760434896040518263ffffffff1660e01b81526004016131d091815260200190565b602060405180830381865afa1580156131eb573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061320f91906152f9565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b16815273ffffffffffffffffffffffffffffffffffffffff9091166004820152602401602060405180830381865afa158015613276573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061329a91906152f9565b6040517fe328acf800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80831660048301529192509083169063e328acf890602401602060405180830381865afa158015613308573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061332c91906153b0565b80156133de57506040517fbf2bf05b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8881166004830152808316919084169063bf2bf05b90602401602060405180830381865afa1580156133a2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906133c691906152f9565b73ffffffffffffffffffffffffffffffffffffffff16145b156133f0576001945050505050610a74565b50505b60016133ff8686610a56565b101561340f575f92505050610a74565b5f848152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168085527001000000000000000000000000000000009092041691830191909152600190829061346d908390615634565b6fffffffffffffffffffffffffffffffff9081169091525f87815260086020908152604090912084519185015183167001000000000000000000000000000000000291909216179055506134c386866001614320565b50600195945050505050565b5f828152600860209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff80821680855270010000000000000000000000000000000090920416918301919091528290829061352c908390615634565b6fffffffffffffffffffffffffffffffff9081169091525f8581526008602090815260409091208451918501518316700100000000000000000000000000000000029190921617905550613581338484614320565b505050565b6003546040517fbffa55d500000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091169063bffa55d590602401612b6f565b604080516060810182525f80825260208201819052918101829052905473ffffffffffffffffffffffffffffffffffffffff16156136a3575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff9091169063b955455290602401606060405180830381865afa15801561367f573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061277091906154e4565b50604080516060810182525f808252602082018190529181019190915290565b5f5460609073ffffffffffffffffffffffffffffffffffffffff1615612775575f546040517fb955455200000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff909116906317e94a6c90829063b955455290602401606060405180830381865afa158015613756573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061377a91906154e4565b60409081015190517fffffffff0000000000000000000000000000000000000000000000000000000060e084901b1681526effffffffffffffffffffffffffffff9091166004820152602401612711565b61358183838360405180602001604052805f815250611739565b679a31110384e0b0c960205260148290525f8181526034600c2054610a71565b61380d61432c565b6004548151829167ffffffffffffffff90911610613857576040517f3f506beb00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b42815f018181516138689190615390565b67ffffffffffffffff9081169091525f8581526007602090815260409182902085518154878401516dffffffffffffffffffffffffffff90811668010000000000000000027fffffffffffffffffffff0000000000000000000000000000000000000000000090921692909616919091171781558583015160019091018054606088015115156e010000000000000000000000000000027fffffffffffffffffffffffffffffffffff000000000000000000000000000000909116929095169190911793909317909255518581527ffaebf92d40203b20cab7d4dca7df7753513d98c27111c3f22a1d248022d0633d925001612447565b611fa586868686868661441d565b61358183837f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663bb3df8b86040518163ffffffff1660e01b8152600401602060405180830381865afa1580156139db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906139ff91906152f9565b604080516020810187905201604051602081830303815290604052611739565b613a27613cb3565b613a3084612d86565b6040517fda0194c000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85169063da0194c090613a84903090879060040161560a565b5f604051808303815f87803b158015613a9b575f5ffd5b505af1158015613aad573d5f5f3e3d5ffd5b50506040517f2304aa020000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8516602482015273ffffffffffffffffffffffffffffffffffffffff87169250632304aa0291506044015f604051808303815f87803b158015613b2c575f5ffd5b505af1158015613b3e573d5f5f3e3d5ffd5b50506040517f8d7443140000000000000000000000000000000000000000000000000000000081523060048201526effffffffffffffffffffffffffffff8416602482015273ffffffffffffffffffffffffffffffffffffffff87169250638d74431491506044016129c2565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f86455d28000000000000000000000000000000000000000000000000000000001480610a745750610a74826301ffc9a760e09190911c90811463d9b67a26821417630e89341c9091141790565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610a7457507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831614610a74565b612c547f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663d4263a536040518163ffffffff1660e01b8152600401602060405180830381865afa158015613d1f573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613d4391906154a9565b6140e3565b80471015613d5d5763b12d13eb5f526004601cfd5b5f385f388486620186a0f1612d8257815f526073600b5360ff6020536016600b82f0612d82573838fd5b6003546040517f2d806cdd00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015290911690632d806cdd9083906024015f604051808303818588803b158015613df3575f5ffd5b505af1158015613e05573d5f5f3e3d5ffd5b50505050505050565b8360601b80613e245763ea553b345f526004601cfd5b679a31110384e0b0c960205284601452835f5260405f20805484810181811015613e55576301336cea5f526004601cfd5b808355505050826020528060601c5f337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa450833b15612b9857612b985f858585856145f2565b828514613eb357633b800a465f526004601cfd5b8760601b679a31110384e0b0c9178760601b679a31110384e0b0c917816020528160601c99508060601c985088613ef15763ea553b345f526004601cfd5b893314613f1257335f526034600c2054613f1257634b6e7f185f526004601cfd5b8660051b5b8015613f7f576020810390508087013583602052818a01355f5260405f20805480831115613f4c5763f4d678b85f526004601cfd5b8290039055602083905260405f20805480830181811015613f74576301336cea5f526004601cfd5b90915550613f179050565b505050604051604081528560051b602001604082018160208a03823781604001602084015281602088038383013750888a337f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb60408586010186a45050613fe35f90565b15613ff857613ff88888888888888888614695565b863b1561212057865f5260405163bc197c81815233602082015288604082015260a060608201528560051b60200160c082018160208a0382378160a001806080850152826020890384840137820160a0840152602084017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0860183800183013750808101830160c401905060208282601c85015f5f515af16140a2573d156140a2573d5f833e3d82fd5b5080517fbc197c8100000000000000000000000000000000000000000000000000000000146140d857639c05499b5f526004601cfd5b505050505050505050565b6040517f6352211e000000000000000000000000000000000000000000000000000000008152600481018290527f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1690636352211e90602401602060405180830381865afa15801561416c573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061419091906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146141f4576040517f8c1971dc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b614201828261469a565b6040516bffffffffffffffffffffffff8216815273ffffffffffffffffffffffffffffffffffffffff8316907f8a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76ef9060200160405180910390a25050565b8015159050679a31110384e0b0c960205233601452815f52806034600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c811614612c54576040517f489aea9a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6135815f848484614813565b7f00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c8173ffffffffffffffffffffffffffffffffffffffff1663b17535b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015614395573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906143b991906152f9565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614612c54576040517f237257bf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8560601b679a31110384e0b0c9178560601b679a31110384e0b0c917816020528160601c97508060601c96508661445b5763ea553b345f526004601cfd5b87331461447c57335f526034600c205461447c57634b6e7f185f526004601cfd5b855f5260405f20915081548086111561449c5763f4d678b85f526004601cfd5b8581038355508060205260405f2091508154858101818110156144c6576301336cea5f526004601cfd5b909255505060208390528486337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa4843b15611fa55760405163f23a6e61815233602082015286604082015284606082015283608082015260a080820152816020016020840360c08301376020818360c401601c84015f8a5af1614555573d15614555573d5f823e3d81fd5b80517ff23a6e610000000000000000000000000000000000000000000000000000000014613e0557639c05499b5f526004601cfd5b81811015613e05576145b687878784815181106145a9576145a961565c565b60200260200101516148a9565b60010161458a565b81811015613e05576145ea87878784815181106145dd576145dd61565c565b602002602001015161492c565b6001016145be565b60405163f23a6e6181523360208201528560601b60601c604082015283606082015282608082015260a08082015281518060c0830152801561463e578060e08301826020860160045afa505b6020828260c401601c85015f8a5af161465f573d1561465f573d5f833e3d82fd5b5080517ff23a6e610000000000000000000000000000000000000000000000000000000014611fa557639c05499b5f526004601cfd5b612120565b6127106bffffffffffffffffffffffff8216111561473a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c2065786365656460448201527f2073616c655072696365000000000000000000000000000000000000000000006064820152608401610cde565b73ffffffffffffffffffffffffffffffffffffffff82166147b7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f455243323938313a20696e76616c6964207265636569766572000000000000006044820152606401610cde565b6040805180820190915273ffffffffffffffffffffffffffffffffffffffff9092168083526bffffffffffffffffffffffff90911660209092018290527401000000000000000000000000000000000000000090910217600155565b8260601b80679a31110384e0b0c917602052808560601b148560601b151761484f57845f526034600c205461484f57634b6e7f185f526004601cfd5b825f5260405f2080548084111561486d5763f4d678b85f526004601cfd5b83810382555050816020525f8160601c337fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6260405fa450612b98565b73ffffffffffffffffffffffffffffffffffffffff83811615908316158180156148d05750805b15614907576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8115614913575b614925565b8061490e576149253386868634614999565b5050505050565b73ffffffffffffffffffffffffffffffffffffffff83811615908316158180156149535750805b1561498a576040517f5cbd944100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8161490e578061490e57614925565b5f5473ffffffffffffffffffffffffffffffffffffffff1615614925575f546040517f285fb8c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152868116602483015285811660448301529091169063285fb8c8906064015f6040518083038186803b158015614a2e575f5ffd5b505afa1580156140d8573d5f5f3e3d5ffd5b73ffffffffffffffffffffffffffffffffffffffff811681146141f4575f5ffd5b5f5f60408385031215614a72575f5ffd5b8235614a7d81614a40565b946020939093013593505050565b5f60208284031215614a9b575f5ffd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461163b575f5ffd5b5f60208284031215614ada575f5ffd5b5035919050565b5f5f60408385031215614af2575f5ffd5b50508035926020909101359150565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f5f5f60608486031215614b66575f5ffd5b8335614b7181614a40565b92506020840135614b8181614a40565b91506040840135614b9181614a40565b809150509250925092565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b60078110614bfe577f4e487b71000000000000000000000000000000000000000000000000000000005f52602160045260245ffd5b9052565b60208101610a748284614bc9565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715614c8457614c84614c10565b604052919050565b5f67ffffffffffffffff821115614ca557614ca5614c10565b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b5f5f5f5f60808587031215614ce4575f5ffd5b84359350602085013592506040850135614cfd81614a40565b9150606085013567ffffffffffffffff811115614d18575f5ffd5b8501601f81018713614d28575f5ffd5b8035614d3b614d3682614c8c565b614c3d565b818152886020838501011115614d4f575f5ffd5b816020840160208301375f6020838301015280935050505092959194509250565b5f60208284031215614d80575f5ffd5b813561163b81614a40565b5f5f83601f840112614d9b575f5ffd5b50813567ffffffffffffffff811115614db2575f5ffd5b6020830191508360208260051b8501011115611732575f5ffd5b5f5f83601f840112614ddc575f5ffd5b50813567ffffffffffffffff811115614df3575f5ffd5b602083019150836020828501011115611732575f5ffd5b5f5f5f5f5f5f5f5f60a0898b031215614e21575f5ffd5b8835614e2c81614a40565b97506020890135614e3c81614a40565b9650604089013567ffffffffffffffff811115614e57575f5ffd5b614e638b828c01614d8b565b909750955050606089013567ffffffffffffffff811115614e82575f5ffd5b614e8e8b828c01614d8b565b909550935050608089013567ffffffffffffffff811115614ead575f5ffd5b614eb98b828c01614dcc565b999c989b5096995094979396929594505050565b602080825282518282018190525f918401906040840190835b81811015614f1a57835173ffffffffffffffffffffffffffffffffffffffff16835260209384019390920191600101614ee6565b509095945050505050565b5f5f5f5f60408587031215614f38575f5ffd5b843567ffffffffffffffff811115614f4e575f5ffd5b614f5a87828801614d8b565b909550935050602085013567ffffffffffffffff811115614f79575f5ffd5b614f8587828801614d8b565b95989497509550505050565b602080825282518282018190525f918401906040840190835b81811015614f1a578351835260209384019390920191600101614faa565b600781106141f4575f5ffd5b6effffffffffffffffffffffffffffff811681146141f4575f5ffd5b5f5f5f60608486031215615002575f5ffd5b833561500d81614fc8565b9250602084013561501d81614fd4565b91506040840135614b9181614fd4565b80151581146141f4575f5ffd5b5f5f6040838503121561504b575f5ffd5b823561505681614a40565b915060208301356150668161502d565b809150509250929050565b5f606082019050615083828451614bc9565b6effffffffffffffffffffffffffffff60208401511660208301526effffffffffffffffffffffffffffff604084015116604083015292915050565b5f5f5f606084860312156150d1575f5ffd5b83359250602084013591506040840135614b9181614a40565b5f5f604083850312156150fb575f5ffd5b823561510681614a40565b9150602083013561506681614a40565b80356dffffffffffffffffffffffffffff81168114615133575f5ffd5b919050565b5f5f82840360a081121561514a575f5ffd5b8335925060807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08201121561517d575f5ffd5b506040516080810167ffffffffffffffff811182821017156151a1576151a1614c10565b604052602084013567ffffffffffffffff811681146151be575f5ffd5b81526151cc60408501615116565b60208201526151dd60608501615116565b604082015260808401356151f08161502d565b6060820152919491935090915050565b5f5f5f5f5f5f60a08789031215615215575f5ffd5b863561522081614a40565b9550602087013561523081614a40565b94506040870135935060608701359250608087013567ffffffffffffffff811115615259575f5ffd5b61526589828a01614dcc565b979a9699509497509295939492505050565b5f5f5f60608486031215615289575f5ffd5b505081359360208301359350604090920135919050565b5f5f5f5f608085870312156152b3575f5ffd5b84356152be81614a40565b935060208501356152ce81614fc8565b925060408501356152de81614fd4565b915060608501356152ee81614fd4565b939692955090935050565b5f60208284031215615309575f5ffd5b815161163b81614a40565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f82615374577f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b500490565b8082028115828204841417610a7457610a74615314565b67ffffffffffffffff8181168382160190811115610a7457610a74615314565b5f602082840312156153c0575f5ffd5b815161163b8161502d565b5f602082840312156153db575f5ffd5b815167ffffffffffffffff8111156153f1575f5ffd5b8201601f81018413615401575f5ffd5b805161540f614d3682614c8c565b818152856020838501011115615423575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b80820180821115610a7457610a74615314565b6fffffffffffffffffffffffffffffffff8181168382160190811115610a7457610a74615314565b81810381811115610a7457610a74615314565b5f6020828403121561549e575f5ffd5b815161163b81614fc8565b5f602082840312156154b9575f5ffd5b5051919050565b5f5f604083850312156154d1575f5ffd5b8251602084015190925061506681614a40565b5f60608284031280156154f5575f5ffd5b506040516060810167ffffffffffffffff8111828210171561551957615519614c10565b604052825161552781614fc8565b8152602083015161553781614fd4565b6020820152604083015161554a81614fd4565b60408201529392505050565b5f60208284031215615566575f5ffd5b815167ffffffffffffffff81111561557c575f5ffd5b8201601f8101841361558c575f5ffd5b805167ffffffffffffffff8111156155a6576155a6614c10565b8060051b6155b660208201614c3d565b918252602081840181019290810190878411156155d1575f5ffd5b6020850194505b838510156155ff57845192506155ed83614a40565b828252602094850194909101906155d8565b979650505050505050565b73ffffffffffffffffffffffffffffffffffffffff831681526040810161163b6020830184614bc9565b6fffffffffffffffffffffffffffffffff8281168282160390811115610a7457610a74615314565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffdfea2646970667358221220ba99c50716540a56af8ce692099688457d33c2348583db9e064b7c2c5dae5cc664736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c810000000000000000000000005006680feec67c5deb2bbd0da4e1fa4db619bc99
-----Decoded View---------------
Arg [0] : hub_ (address): 0x70f6DCFAfD058bAE381D3390f6e8b11cD91c3c81
Arg [1] : refunder_ (address): 0x5006680feeC67c5dEb2bbd0dA4E1FA4DB619bc99
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000070f6dcfafd058bae381d3390f6e8b11cd91c3c81
Arg [1] : 0000000000000000000000005006680feec67c5deb2bbd0da4e1fa4db619bc99
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.