Source Code
Latest 25 from a total of 687 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Deploy Token | 2798809 | 281 days ago | IN | 0.0001 HYPE | 0.00020508 | ||||
| Deploy Token | 2745505 | 282 days ago | IN | 0.0001 HYPE | 0.00020508 | ||||
| Deploy Token | 2745498 | 282 days ago | IN | 0.0001 HYPE | 0.00020508 | ||||
| Deploy Token | 1448411 | 311 days ago | IN | 0.0001 HYPE | 0.00023305 | ||||
| Deploy Token | 1380757 | 313 days ago | IN | 0.00001 HYPE | 0.00091481 | ||||
| Deploy Token | 1379238 | 313 days ago | IN | 0.0001 HYPE | 0.00084147 | ||||
| Deploy Token | 1379176 | 313 days ago | IN | 0.000001 HYPE | 0.00084147 | ||||
| Update Liquidity... | 1379036 | 313 days ago | IN | 0 HYPE | 0.00000293 | ||||
| Deploy Token | 1372418 | 313 days ago | IN | 0.0001 HYPE | 0.00084841 | ||||
| Update Position ... | 1372402 | 313 days ago | IN | 0 HYPE | 0.00000291 | ||||
| Update Liquidity... | 1372397 | 313 days ago | IN | 0 HYPE | 0.00000293 | ||||
| Update Position ... | 1372352 | 313 days ago | IN | 0 HYPE | 0.00000291 | ||||
| Deploy Token | 1371953 | 313 days ago | IN | 0.0001 HYPE | 0.00084774 | ||||
| Update Swap Rout... | 1371941 | 313 days ago | IN | 0 HYPE | 0.00000293 | ||||
| Update Uni V3Fac... | 1371932 | 313 days ago | IN | 0 HYPE | 0.0000029 | ||||
| Update Position ... | 1371921 | 313 days ago | IN | 0 HYPE | 0.00000291 | ||||
| Update Liquidity... | 1370419 | 313 days ago | IN | 0 HYPE | 0.00000293 | ||||
| Update Swap Rout... | 1370419 | 313 days ago | IN | 0 HYPE | 0.00000293 | ||||
| Update Uni V3Fac... | 1370415 | 313 days ago | IN | 0 HYPE | 0.0000029 | ||||
| Update Position ... | 1370403 | 313 days ago | IN | 0 HYPE | 0.00000291 | ||||
| Deploy Token | 548996 | 331 days ago | IN | 0.0001 HYPE | 0.0002306 | ||||
| Deploy Token | 548853 | 331 days ago | IN | 0.0001 HYPE | 0.00022373 | ||||
| Deploy Token | 547816 | 331 days ago | IN | 0.0001 HYPE | 0.00022373 | ||||
| Deploy Token | 547808 | 331 days ago | IN | 0.0001 HYPE | 0.00022373 | ||||
| Deploy Token | 526342 | 332 days ago | IN | 0.1 HYPE | 0.0002333 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 2798809 | 281 days ago | Contract Creation | 0 HYPE | |||
| 2745505 | 282 days ago | Contract Creation | 0 HYPE | |||
| 2745498 | 282 days ago | Contract Creation | 0 HYPE | |||
| 1448411 | 311 days ago | Contract Creation | 0 HYPE | |||
| 1380757 | 313 days ago | 0.00000975 HYPE | ||||
| 1380757 | 313 days ago | 0.00000025 HYPE | ||||
| 1380757 | 313 days ago | Contract Creation | 0 HYPE | |||
| 1379238 | 313 days ago | 0.0000975 HYPE | ||||
| 1379238 | 313 days ago | 0.0000025 HYPE | ||||
| 1379238 | 313 days ago | Contract Creation | 0 HYPE | |||
| 1379176 | 313 days ago | 0.00000097 HYPE | ||||
| 1379176 | 313 days ago | 0.00000002 HYPE | ||||
| 1379176 | 313 days ago | Contract Creation | 0 HYPE | |||
| 1372418 | 313 days ago | 0.0000975 HYPE | ||||
| 1372418 | 313 days ago | 0.0000025 HYPE | ||||
| 1372418 | 313 days ago | Contract Creation | 0 HYPE | |||
| 1371953 | 313 days ago | 0.0000975 HYPE | ||||
| 1371953 | 313 days ago | 0.0000025 HYPE | ||||
| 1371953 | 313 days ago | Contract Creation | 0 HYPE | |||
| 548996 | 331 days ago | Contract Creation | 0 HYPE | |||
| 548853 | 331 days ago | Contract Creation | 0 HYPE | |||
| 547816 | 331 days ago | Contract Creation | 0 HYPE | |||
| 547808 | 331 days ago | Contract Creation | 0 HYPE | |||
| 526342 | 332 days ago | Contract Creation | 0 HYPE | |||
| 526216 | 332 days ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
BangerV3
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {TickMath} from "@uniswap/v3-core/contracts/libraries/TickMath.sol";
import {IERC1155Receiver} from "@openzeppelin/contracts/interfaces/IERC1155Receiver.sol";
import {INet} from "../INet.sol";
import {IStorage} from "../IStorage.sol";
import {IInscribedDrops} from "../IInscribedDrops.sol";
import {INonfungiblePositionManager, IUniswapV3Factory, ILockerFactory, ILocker, ExactInputSingleParams, ISwapRouter} from "../interface.sol";
import {Bytes32AddressLib} from "../Bytes32AddressLib.sol";
import {LibString} from "../LibString.sol";
import {Base64} from "../Base64.sol";
import {BangerV3Token} from "./BangerV3Token.sol";
contract BangerV3 is IERC1155Receiver, Ownable {
using TickMath for int24;
using Bytes32AddressLib for bytes32;
using LibString for address;
using LibString for uint256;
error Deprecated();
event TokenCreated(
address tokenAddress,
uint256 lpNftId,
address deployer,
uint256 fid,
string name,
string symbol,
uint256 supply,
address lockerAddress,
string extraStringData,
bool isMsgSenderOwner
);
address public taxCollector =
address(0x2a67566660714AfaD6eB80A8a64eb7431B121F3c);
uint64 public defaultLockingPeriod = 33275115461;
uint8 public taxRate = 25; // 25 / 1000 -> 2.5 %
uint8 public lpFeesCut = 50; // 5 / 100 -> 5%
uint8 public protocolCut = 30; // 3 / 100 -> 3%
uint24 public fee = 10_000;
ILockerFactory public liquidityLocker =
ILockerFactory(address(0x00000000a4944d1E707f869356fF4B48e527370f));
address public weth = address(0x4200000000000000000000000000000000000006);
IUniswapV3Factory public uniswapV3Factory =
IUniswapV3Factory(address(0x33128a8fC17869897dcE68Ed026d694621f6FDfD));
INonfungiblePositionManager public positionManager =
INonfungiblePositionManager(
address(0x03a520b32C04BF3bEEf7BEb72E919cf822Ed34f1)
);
address public swapRouter =
address(0x2626664c2603336E57B271c5C0b26F421741e481);
address internal constant netAddress =
address(0x00000000B24D62781dB359b07880a105cD0b64e6);
address internal constant netStorageAddress =
address(0x00000000DB40fcB9f4466330982372e27Fd7Bbf5);
address internal constant inscribedDropsAddress =
address(0x000000001c147E48f5aaD3C69e8E4d2305523c62);
bool public deprecated;
bool public bundleFeeSwitch = true;
constructor()
Ownable(address(0xcC4193B652FcB25347Bb44a88d2b09B52585643F))
{}
function deployToken(
uint256 _supply,
int24 _initialTick,
bytes32 _salt,
address _deployer,
uint256 _fid,
uint256 mintPrice,
uint256 mintEndTimestamp,
uint256 maxMintSupply,
string calldata _name,
string calldata _symbol,
string calldata _image,
string calldata _animation,
string calldata _extraStringData,
bytes calldata _extraBytesData
) external payable returns (BangerV3Token token, uint256 tokenId) {
if (deprecated) revert Deprecated();
int24 tickSpacing = uniswapV3Factory.feeAmountTickSpacing(fee);
require(
tickSpacing != 0 && _initialTick % tickSpacing == 0,
"Invalid tick"
);
token = new BangerV3Token{
salt: keccak256(abi.encode(_deployer, _salt))
}(
_name,
_symbol,
_supply,
_deployer,
_fid,
_image,
_animation,
_extraStringData,
_extraBytesData
);
// Makes sure that the token address is less than the WETH address. This is so that the token
// is first in the pool. Just makes things consistent.
require(address(token) < weth, "Invalid salt");
uint160 sqrtPriceX96 = _initialTick.getSqrtRatioAtTick();
address pool = uniswapV3Factory.createPool(address(token), weth, fee);
IUniswapV3Factory(pool).initialize(sqrtPriceX96);
INonfungiblePositionManager.MintParams
memory params = INonfungiblePositionManager.MintParams(
address(token),
weth,
fee,
_initialTick,
maxUsableTick(tickSpacing),
_supply,
0,
0,
0,
address(this),
block.timestamp
);
token.approve(address(positionManager), _supply);
(tokenId, , , ) = positionManager.mint(params);
address lockerAddress = liquidityLocker.deploy(
address(positionManager),
_deployer,
defaultLockingPeriod,
tokenId,
lpFeesCut
);
positionManager.safeTransferFrom(address(this), lockerAddress, tokenId);
ILocker(lockerAddress).initializer(tokenId);
if (msg.value > 0) {
uint256 remainingFundsToBuyTokens = msg.value;
if (bundleFeeSwitch) {
uint256 protocolFees = (msg.value * taxRate) / 1000;
remainingFundsToBuyTokens = msg.value - protocolFees;
(bool success, ) = payable(taxCollector).call{
value: protocolFees
}("");
if (!success) {
revert("Failed to send protocol fees");
}
}
ExactInputSingleParams memory swapParams = ExactInputSingleParams({
tokenIn: weth, // The token we are exchanging from (ETH wrapped as WETH)
tokenOut: address(token), // The token we are exchanging to
fee: fee, // The pool fee
recipient: _deployer, // The recipient address
amountIn: remainingFundsToBuyTokens, // The amount of ETH (WETH) to be swapped
amountOutMinimum: 0, // Minimum amount to receive
sqrtPriceLimitX96: 0 // No price limit
});
// The call to `exactInputSingle` executes the swap.
ISwapRouter(swapRouter).exactInputSingle{
value: remainingFundsToBuyTokens
}(swapParams);
}
// Send Net message
uint256 msgIdx = INet(netAddress).getTotalMessagesCount();
INet(netAddress).sendMessageViaApp(
msg.sender,
string.concat(
"Deployed ",
_name,
" (",
_symbol,
") to ",
address(token).toHexStringChecksumed(),
" (pool: ",
pool.toHexStringChecksumed(),
")"
),
address(token).toHexStringChecksumed(),
// Use encode rather than encodePacked so that the data can be easily decoded
abi.encode(
msgIdx,
pool,
token,
lockerAddress,
tokenId,
_deployer,
_fid,
_extraStringData,
_extraBytesData
)
);
// Create drop
uint256 dropIdx = IInscribedDrops(inscribedDropsAddress).totalDrops();
IInscribedDrops(inscribedDropsAddress).inscribe(
mintPrice,
maxMintSupply,
mintEndTimestamp,
// No mint limit per wallet because this contract is the minter
// of all tokens and so mint limit would not work with that.
0,
getUri(
_name,
_symbol,
_image,
_animation,
_extraStringData,
address(token)
)
);
// Transfer the first minted token to _deployer, which supports if a bot deploys tokens on
// behalf of a user
IInscribedDrops(inscribedDropsAddress).safeTransferFrom(
address(this),
_deployer,
dropIdx,
1,
""
);
// Map the token address to relevant data
IStorage(netStorageAddress).put(
bytes32(uint256(uint160(address(token)))),
"",
// Use encode rather than encodePacked so that the data can be easily decoded
abi.encode(
msgIdx,
dropIdx,
inscribedDropsAddress,
pool,
lockerAddress,
tokenId
)
);
// Map the drop idx to the message idx and token address
IStorage(netStorageAddress).put(
bytes32(dropIdx),
"",
// Use encode rather than encodePacked so that the data can be easily decoded
abi.encode(dropIdx, token, pool)
);
emit TokenCreated(
address(token),
tokenId,
_deployer,
_fid,
_name,
_symbol,
_supply,
lockerAddress,
_extraStringData,
msg.sender == owner()
);
}
function getUri(
string calldata name,
string calldata symbol,
string calldata image,
string calldata animation,
string calldata extraStringData,
address token
) internal pure returns (string memory) {
return
string.concat(
'{"name":"',
name,
" (",
symbol,
")",
'","description":"Memecoin-NFT created via Net. Memecoin is located at ',
token.toHexStringChecksumed(),
"\\n\\n",
extraStringData,
'","image":"',
bytes(image).length > 0
? image
: string.concat(
"data:image/svg+xml;base64,",
Base64.encode(
bytes(
string.concat(
'<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500" style="background-color:#000"><text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" style="font-family:monospace;font-size:24px;fill:#0f7">',
name,
"</text></svg>"
)
)
)
),
'","animation_url":"',
animation,
'"}'
);
}
function mint(address token, uint256 quantity) external payable {
// Get the message index and drop index
(, bytes memory tokenData) = IStorage(netStorageAddress).get(
bytes32(uint256(uint160(token))),
address(this)
);
// We know tokenData consists of uint256, uint256, address, address, address, uint256 so we can unpack them
(, uint256 dropIdx, address readDropsAddress, address pool, , ) = abi
.decode(
tokenData,
(uint256, uint256, address, address, address, uint256)
);
// Mint NFTs
// NOTE: we use readDropsAddress to future-proof this contract in case the inscribedDropsAddress changes
IInscribedDrops(readDropsAddress).mint{value: msg.value}(
dropIdx,
quantity
);
// Transfer NFTs to msg.sender
IInscribedDrops(readDropsAddress).safeTransferFrom(
address(this),
msg.sender,
dropIdx,
quantity,
""
);
// Send mint message
INet(netAddress).sendMessageViaApp(
msg.sender,
"mint",
address(token).toHexStringChecksumed(),
// Use encode rather than encodePacked so that the data can be easily decoded
abi.encode(quantity, dropIdx, token, pool)
);
// Use ETH to purchase tokens if value is greater than 0
if (msg.value > 0) {
uint256 amountIn = msg.value -
(IInscribedDrops(inscribedDropsAddress).feeBps() * msg.value) /
10_000;
ExactInputSingleParams memory swapParams = ExactInputSingleParams({
tokenIn: weth, // The token we are exchanging from (ETH wrapped as WETH)
tokenOut: address(token), // The token we are exchanging to
fee: fee, // The pool fee
recipient: msg.sender, // The recipient address
amountIn: amountIn, // The amount of ETH (WETH) to be swapped
amountOutMinimum: 0, // Minimum amount of DAI to receive
sqrtPriceLimitX96: 0 // No price limit
});
// The call to `exactInputSingle` executes the swap.
ISwapRouter(swapRouter).exactInputSingle{value: amountIn}(
swapParams
);
}
}
function initialSwapTokens(address token, uint24 _fee) public payable {
ExactInputSingleParams memory swapParams = ExactInputSingleParams({
tokenIn: weth, // The token we are exchanging from (ETH wrapped as WETH)
tokenOut: address(token), // The token we are exchanging to
fee: _fee, // The pool fee
recipient: msg.sender, // The recipient address
amountIn: msg.value, // The amount of ETH (WETH) to be swapped
amountOutMinimum: 0, // Minimum amount of DAI to receive
sqrtPriceLimitX96: 0 // No price limit
});
// The call to `exactInputSingle` executes the swap.
ISwapRouter(swapRouter).exactInputSingle{value: msg.value}(swapParams);
}
function predictToken(
address deployer,
uint256 fid,
string calldata name,
string calldata symbol,
string calldata image,
string calldata animation,
string calldata extraStringData,
bytes calldata extraBytesData,
uint256 supply,
bytes32 salt
) public view returns (address) {
bytes32 create2Salt = keccak256(abi.encode(deployer, salt));
return
keccak256(
abi.encodePacked(
bytes1(0xFF),
address(this),
create2Salt,
keccak256(
abi.encodePacked(
type(BangerV3Token).creationCode,
abi.encode(
name,
symbol,
supply,
deployer,
fid,
image,
animation,
extraStringData,
extraBytesData
)
)
)
)
).fromLast20Bytes();
}
function generateSalt(
address deployer,
uint256 fid,
string calldata name,
string calldata symbol,
string calldata image,
string calldata animation,
string calldata extraStringData,
bytes calldata extraBytesData,
uint256 supply
) external view returns (bytes32 salt, address token) {
for (uint256 i; ; i++) {
salt = bytes32(i);
token = predictToken(
deployer,
fid,
name,
symbol,
image,
animation,
extraStringData,
extraBytesData,
supply,
salt
);
if (token < weth && token.code.length == 0) {
break;
}
}
}
function toggleBundleFeeSwitch(bool _enabled) external onlyOwner {
bundleFeeSwitch = _enabled;
}
function setDeprecated(bool _deprecated) external onlyOwner {
deprecated = _deprecated;
}
function updateTaxCollector(address newCollector) external onlyOwner {
taxCollector = newCollector;
}
function updateLiquidityLocker(address newLocker) external onlyOwner {
liquidityLocker = ILockerFactory(newLocker);
}
function updatePositionManager(
address newPositionManager
) external onlyOwner {
positionManager = INonfungiblePositionManager(newPositionManager);
}
function updateUniV3Factory(address newFactory) external onlyOwner {
uniswapV3Factory = IUniswapV3Factory(newFactory);
}
function updateSwapRouter(address newRouter) external onlyOwner {
swapRouter = newRouter;
}
function updateWeth(address newWeth) external onlyOwner {
weth = newWeth;
}
function updateDefaultLockingPeriod(uint64 newPeriod) external onlyOwner {
defaultLockingPeriod = newPeriod;
}
function updateProtocolFees(uint8 newFee) external onlyOwner {
lpFeesCut = newFee;
}
function updateTaxRate(uint8 newRate) external onlyOwner {
taxRate = newRate;
}
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4) {
return this.onERC1155Received.selector;
}
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4) {
return this.onERC1155BatchReceived.selector;
}
function supportsInterface(
bytes4 interfaceId
) external view returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId;
}
fallback() external payable {}
receive() external payable {}
}
/// @notice Given a tickSpacing, compute the maximum usable tick
function maxUsableTick(int24 tickSpacing) pure returns (int24) {
unchecked {
return (TickMath.MAX_TICK / tickSpacing) * tickSpacing;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Library for converting between addresses and bytes32 values.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Bytes32AddressLib.sol)
library Bytes32AddressLib {
function fromLast20Bytes(
bytes32 bytesValue
) internal pure returns (address) {
return address(uint160(uint256(bytesValue)));
}
function fillLast12Bytes(
address addressValue
) internal pure returns (bytes32) {
return bytes32(bytes20(addressValue));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;
/// @title InscribedDrops
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice NFT mints created by inscribing token uris and mint configurations in Net messages.
interface IInscribedDrops {
function totalDrops() external view returns (uint256);
function feeBps() external view returns (uint256);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function inscribe(
uint256 mintPrice,
uint256 maxSupply,
uint256 mintEndTimestamp,
uint256 maxMintsPerWallet,
string calldata tokenUri
) external;
function setFeeBps(uint256 newFeeBps) external;
function mint(uint256 id, uint256 quantity) external payable;
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 amount,
bytes calldata data
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;
interface INet {
struct Message {
address app;
address sender;
uint256 timestamp;
bytes data;
string text;
string topic;
}
function sendMessageViaApp(
address sender,
string calldata text,
string calldata topic,
bytes calldata extraData
) external;
function sendMessage(
string calldata text,
string calldata topic,
bytes calldata extraData
) external;
// **************
// Fetch Messages
// **************
// Fetch message indexes
function getMessageIdxForApp(
uint256 idx,
address app
) external view returns (uint256);
function getMessageIdxForAppUser(
uint256 idx,
address app,
address user
) external view returns (uint256);
function getMessageIdxForAppTopic(
uint256 idx,
address app,
string calldata topic
) external view returns (uint256);
function getMessageIdxForAppUserTopic(
uint256 idx,
address app,
address user,
string calldata topic
) external view returns (uint256);
// Fetch single message
function getMessage(uint256 idx) external view returns (Message memory);
function getMessageForApp(
uint256 idx,
address app
) external view returns (Message memory);
function getMessageForAppUser(
uint256 idx,
address app,
address user
) external view returns (Message memory);
function getMessageForAppTopic(
uint256 idx,
address app,
string calldata topic
) external view returns (Message memory);
function getMessageForAppUserTopic(
uint256 idx,
address app,
address user,
string calldata topic
) external view returns (Message memory);
// Fetch multiple messages
function getMessagesInRange(
uint256 startIdx,
uint256 endIdx
) external view returns (Message[] memory);
function getMessagesInRangeForApp(
uint256 startIdx,
uint256 endIdx,
address app
) external view returns (Message[] memory);
function getMessagesInRangeForAppUser(
uint256 startIdx,
uint256 endIdx,
address app,
address user
) external view returns (Message[] memory);
function getMessagesInRangeForAppTopic(
uint256 startIdx,
uint256 endIdx,
address app,
string calldata topic
) external view returns (Message[] memory);
function getMessagesInRangeForAppUserTopic(
uint256 startIdx,
uint256 endIdx,
address app,
address user,
string calldata topic
) external view returns (Message[] memory);
// **************
// Message counts
// **************
function getTotalMessagesCount() external view returns (uint256);
function getTotalMessagesForAppCount(
address app
) external view returns (uint256);
function getTotalMessagesForAppUserCount(
address app,
address user
) external view returns (uint256);
function getTotalMessagesForAppTopicCount(
address app,
string calldata topic
) external view returns (uint256);
function getTotalMessagesForAppUserTopicCount(
address app,
address user,
string calldata topic
) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.8.17 .0;
/// @title Storage
/// @author Aspyn Palatnick (aspyn.eth, stuckinaboot.eth)
/// @notice Data storage with persistent history using Net
interface IStorage {
event Stored(bytes32 indexed key, address indexed operator);
struct BulkPutParams {
bytes32 key;
string text;
bytes value;
}
struct BulkGetParams {
bytes32 key;
address operator;
}
struct BulkGetValueAtIndexParams {
bytes32 key;
address operator;
uint256 idx;
}
struct BulkGetResult {
string text;
bytes value;
}
/// @notice Store value for a given key
/// @param key key
/// @param text text
/// @param value value
function put(
bytes32 key,
string calldata text,
bytes calldata value
) external;
/// @notice Store values for given params
/// @param params params
function bulkPut(BulkPutParams[] calldata params) external;
/// @notice Get value for a particular key and operator
/// @param key key
/// @param operator user that stored key
/// @return (text, data) stored value for the particular key-operator pair
function get(
bytes32 key,
address operator
) external view returns (string memory, bytes memory);
/// @notice Bulk get values for particular parameters
/// @param params parameters
/// @return results for stored values for the particular parameters
function bulkGet(
BulkGetParams[] calldata params
) external view returns (BulkGetResult[] memory results);
/// @notice Get value at index for a particular key and operator
/// @param key key
/// @param operator user that stored key
/// @param idx index
/// @return (text, data) stored value at index for the particular key-operator pair
function getValueAtIndex(
bytes32 key,
address operator,
uint256 idx
) external view returns (string memory, bytes memory);
/// @notice Bulk get value at index for particular parameters
/// @param params parameters
/// @return results for stored values for the particular parameters
function bulkGetValueAtIndex(
BulkGetValueAtIndexParams[] calldata params
) external view returns (BulkGetResult[] memory results);
/// @notice Get total number of writes to a particular key for a given operator
/// @param key key
/// @param operator user that stored key
/// @return total total writes count
function getTotalWrites(
bytes32 key,
address operator
) external view returns (uint256);
/// @notice Bulk get total writes for particular parameters
/// @param params parameters
/// @return results for total writes for the particular parameters
function bulkGetTotalWrites(
BulkGetParams[] calldata params
) external view returns (uint256[] memory results);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @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)
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `length` of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory str) {
/// @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.
str := add(mload(0x40), 0x80)
// Update the free memory pointer to allocate.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
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 {
} {
str := add(str, w) // `sub(str, 1)`.
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
if iszero(temp) {
break
}
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory str) {
if (value >= 0) {
return toString(uint256(value));
}
unchecked {
str = toString(uint256(-value));
}
/// @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 length := mload(str) // Load the string length.
mstore(str, 0x2d) // Store the '-' character.
str := sub(str, 1) // Move back the string pointer by a byte.
mstore(str, add(length, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2 + 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexString(
uint256 value,
uint256 length
) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value, length);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexStringNoPrefix(
uint256 value,
uint256 length
) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 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.
str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(str, add(length, length))
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 {
} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(str, start)) {
break
}
}
if temp {
// Store the function selector of `HexLengthInsufficient()`.
mstore(0x00, 0x2194895a)
// Revert with (offset, size).
revert(0x1c, 0x04)
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @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 str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @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 str) {
/// @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.
str := add(mload(0x40), 0x80)
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
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 {
} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) {
break
}
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @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 toHexStringChecksumed(
address value
) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 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 str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write 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 str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the 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(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
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 str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write 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 str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
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, and(add(o, 31), not(31))) // Allocate the 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
}
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, all indices of the following operations
// are byte (ASCII) offsets, not UTF character offsets.
/// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
function replace(
string memory subject,
string memory search,
string memory replacement
) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
let replacementLength := mload(replacement)
subject := add(subject, 0x20)
search := add(search, 0x20)
replacement := add(replacement, 0x20)
result := add(mload(0x40), 0x20)
let subjectEnd := add(subject, subjectLength)
if iszero(gt(searchLength, subjectLength)) {
let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
let h := 0
if iszero(lt(searchLength, 32)) {
h := keccak256(search, searchLength)
}
let m := shl(3, sub(32, and(searchLength, 31)))
let s := mload(search)
for {
} 1 {
} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) {
break
}
continue
}
}
// Copy the `replacement` one word at a time.
for {
let o := 0
} 1 {
} {
mstore(add(result, o), mload(add(replacement, o)))
o := add(o, 0x20)
if iszero(lt(o, replacementLength)) {
break
}
}
result := add(result, replacementLength)
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) {
break
}
continue
}
}
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) {
break
}
}
}
let resultRemainder := result
result := add(mload(0x40), 0x20)
let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
// Copy the rest of the string one word at a time.
for {
} lt(subject, subjectEnd) {
} {
mstore(resultRemainder, mload(subject))
resultRemainder := add(resultRemainder, 0x20)
subject := add(subject, 0x20)
}
result := sub(result, 0x20)
// Zeroize the slot after the string.
let last := add(add(result, 0x20), k)
mstore(last, 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 31), not(31)))
// Store the length of the result.
mstore(result, k)
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(
string memory subject,
string memory search,
uint256 from
) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {
let subjectLength := mload(subject)
} 1 {
} {
if iszero(mload(search)) {
if iszero(gt(from, subjectLength)) {
result := from
break
}
result := subjectLength
break
}
let searchLength := mload(search)
let subjectStart := add(subject, 0x20)
result := not(0) // Initialize to `NOT_FOUND`.
subject := add(subjectStart, from)
let end := add(
sub(add(subjectStart, subjectLength), searchLength),
1
)
let m := shl(3, sub(32, and(searchLength, 31)))
let s := mload(add(search, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLength))) {
break
}
if iszero(lt(searchLength, 32)) {
for {
let h := keccak256(add(search, 0x20), searchLength)
} 1 {
} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
/// searching from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(
string memory subject,
string memory search
) internal pure returns (uint256 result) {
result = indexOf(subject, search, 0);
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(
string memory subject,
string memory search,
uint256 from
) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
for {
} 1 {
} {
result := not(0) // Initialize to `NOT_FOUND`.
let searchLength := mload(search)
if gt(searchLength, mload(subject)) {
break
}
let w := result
let fromMax := sub(mload(subject), searchLength)
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(search, 0x20), searchLength)
} 1 {
} {
if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
/// searching from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(
string memory subject,
string memory search
) internal pure returns (uint256 result) {
result = lastIndexOf(subject, search, uint256(int256(-1)));
}
/// @dev Returns whether `subject` starts with `search`.
function startsWith(
string memory subject,
string memory search
) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
iszero(gt(searchLength, mload(subject))),
eq(
keccak256(add(subject, 0x20), searchLength),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns whether `subject` ends with `search`.
function endsWith(
string memory subject,
string memory search
) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
let subjectLength := mload(subject)
// Whether `search` is not longer than `subject`.
let withinRange := iszero(gt(searchLength, subjectLength))
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
withinRange,
eq(
keccak256(
// `subject + 0x20 + max(subjectLength - searchLength, 0)`.
add(
add(subject, 0x20),
mul(withinRange, sub(subjectLength, searchLength))
),
searchLength
),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(
string memory subject,
uint256 times
) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(or(iszero(times), iszero(subjectLength))) {
subject := add(subject, 0x20)
result := mload(0x40)
let output := add(result, 0x20)
for {
} 1 {
} {
// Copy the `subject` one word at a time.
for {
let o := 0
} 1 {
} {
mstore(add(output, o), mload(add(subject, o)))
o := add(o, 0x20)
if iszero(lt(o, subjectLength)) {
break
}
}
output := add(output, subjectLength)
times := sub(times, 1)
if iszero(times) {
break
}
}
// Zeroize the slot after the string.
mstore(output, 0)
// Store the length.
let resultLength := sub(output, add(result, 0x20))
mstore(result, resultLength)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(result, and(add(resultLength, 63), not(31))))
}
}
}
/// @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 result) {
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(gt(subjectLength, end)) {
end := subjectLength
}
if iszero(gt(subjectLength, start)) {
start := subjectLength
}
if lt(start, end) {
result := mload(0x40)
let resultLength := sub(end, start)
mstore(result, resultLength)
subject := add(subject, start)
let w := not(31)
// Copy the `subject` one word at a time, backwards.
for {
let o := and(add(resultLength, 31), w)
} 1 {
} {
mstore(add(result, o), mload(add(subject, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) {
break
}
}
// Zeroize the slot after the string.
mstore(add(add(result, 0x20), resultLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(result, and(add(resultLength, 63), w)))
}
}
}
/// @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 result) {
result = slice(subject, start, uint256(int256(-1)));
}
/// @dev Returns all the indices of `search` in `subject`.
/// The indices are byte offsets.
function indicesOf(
string memory subject,
string memory search
) internal pure returns (uint256[] memory result) {
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
if iszero(gt(searchLength, subjectLength)) {
subject := add(subject, 0x20)
search := add(search, 0x20)
result := add(mload(0x40), 0x20)
let subjectStart := subject
let subjectSearchEnd := add(
sub(add(subject, subjectLength), searchLength),
1
)
let h := 0
if iszero(lt(searchLength, 32)) {
h := keccak256(search, searchLength)
}
let m := shl(3, sub(32, and(searchLength, 31)))
let s := mload(search)
for {
} 1 {
} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) {
break
}
continue
}
}
// Append to `result`.
mstore(result, sub(subject, subjectStart))
result := add(result, 0x20)
// Advance `subject` by `searchLength`.
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) {
break
}
continue
}
}
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) {
break
}
}
let resultEnd := result
// Assign `result` to the free memory pointer.
result := mload(0x40)
// Store the length of `result`.
mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(resultEnd, 0x20))
}
}
}
/// @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) {
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(31)
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))
let prevIndex := 0
for {
} 1 {
} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let elementLength := sub(index, prevIndex)
mstore(element, elementLength)
// Copy the `subject` one word at a time, backwards.
for {
let o := and(add(elementLength, 31), w)
} 1 {
} {
mstore(
add(element, o),
mload(add(add(subject, prevIndex), o))
)
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) {
break
}
}
// Zeroize the slot after the string.
mstore(add(add(element, 0x20), elementLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(elementLength, 63), w)))
// Store the `element` into the array.
mstore(indexPtr, element)
}
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 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 result) {
/// @solidity memory-safe-assembly
assembly {
let w := not(31)
result := mload(0x40)
let aLength := mload(a)
// Copy `a` one word at a time, backwards.
for {
let o := and(add(mload(a), 32), w)
} 1 {
} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) {
break
}
}
let bLength := mload(b)
let output := add(result, mload(a))
// Copy `b` one word at a time, backwards.
for {
let o := and(add(bLength, 32), w)
} 1 {
} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) {
break
}
}
let totalLength := add(aLength, bLength)
let last := add(add(result, 0x20), totalLength)
// Zeroize the slot after the string.
mstore(last, 0)
// Stores the length.
mstore(result, totalLength)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 31), w))
}
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
function toCase(
string memory subject,
bool toUpper
) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(subject)
if length {
result := add(mload(0x40), 0x20)
subject := add(subject, 1)
let flags := shl(add(70, shl(5, toUpper)), 67108863)
let w := not(0)
for {
let o := length
} 1 {
} {
o := add(o, w)
let b := and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
if iszero(o) {
break
}
}
// Restore the result.
result := mload(0x40)
// Stores the string length.
mstore(result, length)
// Zeroize the slot after the string.
let last := add(add(result, 0x20), length)
mstore(last, 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 31), not(31)))
}
}
}
/// @dev Returns a lowercased copy of the string.
function lower(
string memory subject
) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
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 {
for {
let end := add(s, mload(s))
result := add(mload(0x40), 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)
)
} iszero(eq(s, end)) {
} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(result, c)
result := add(result, 1)
continue
}
let t := shr(248, mload(c))
mstore(result, mload(and(t, 31)))
result := add(result, shr(5, t))
}
let last := result
// Zeroize the slot after the string.
mstore(last, 0)
// Restore the result to the start of the free memory.
result := mload(0x40)
// Store the length of the result.
mstore(result, sub(last, add(result, 0x20)))
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 31), not(31)))
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(
string memory s
) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
for {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
// 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))
} 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(result, c)
result := add(result, 1)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), c)
result := add(result, 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(result, mload(0x19)) // "\\u00XX".
result := add(result, 6)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), mload(add(c, 8)))
result := add(result, 2)
}
let last := result
// Zeroize the slot after the string.
mstore(last, 0)
// Restore the result to the start of the free memory.
result := mload(0x40)
// Store the length of the result.
mstore(result, sub(last, add(result, 0x20)))
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 31), not(31)))
}
}
/// @dev Returns whether `a` equals `b`.
function eq(
string memory a,
string memory b
) internal pure returns (bool result) {
assembly {
result := eq(
keccak256(add(a, 0x20), mload(a)),
keccak256(add(b, 0x20), mload(b))
)
}
}
/// @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 behaviour is undefined.
function unpackOne(
bytes32 packed
) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
result := mload(0x40)
// Allocate 2 words (1 for the length, 1 for the bytes).
mstore(0x40, add(result, 0x40))
// Zeroize the length slot.
mstore(result, 0)
// Store the length and bytes.
mstore(add(result, 0x1f), packed)
// Right pad with zeroes.
mstore(add(add(result, 0x20), mload(result)), 0)
}
}
/// @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 aLength := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result := mul(
// Load the length and the bytes of `a` and `b`.
or(
shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
mload(sub(add(b, 0x1e), aLength))
),
// `totalLength != 0 && totalLength < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLength, 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 behaviour is undefined.
function unpackTwo(
bytes32 packed
) internal pure returns (string memory resultA, string memory resultB) {
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
resultA := mload(0x40)
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 retSize := 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, retSize), 0)
// Store the return offset.
mstore(retStart, 0x20)
// End the transaction, returning the string.
return(retStart, retSize)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BangerV3Token is ERC20 {
address public deployer;
uint256 public fid;
string public image;
string public animation;
string public extraStringData;
bytes public extraBytesData;
constructor(
string memory name_,
string memory symbol_,
uint256 maxSupply_,
address deployer_,
uint256 fid_,
string memory image_,
string memory animation_,
string memory extraStringData_,
bytes memory extraBytesData_
) ERC20(name_, symbol_) {
deployer = deployer_;
fid = fid_;
image = image_;
animation = animation_;
extraStringData = extraStringData_;
extraBytesData = extraBytesData_;
_mint(msg.sender, maxSupply_);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.25;
interface INonfungiblePositionManager {
struct MintParams {
address token0;
address token1;
uint24 fee;
int24 tickLower;
int24 tickUpper;
uint256 amount0Desired;
uint256 amount1Desired;
uint256 amount0Min;
uint256 amount1Min;
address recipient;
uint256 deadline;
}
struct CollectParams {
uint256 tokenId;
address recipient;
uint128 amount0Max;
uint128 amount1Max;
}
function mint(
MintParams calldata params
)
external
payable
returns (
uint256 tokenId,
uint128 liquidity,
uint256 amount0,
uint256 amount1
);
function createAndInitializePoolIfNecessary(
address token0,
address token1,
uint24 fee,
uint160 sqrtPriceX96
) external payable returns (address pool);
function collect(
CollectParams calldata params
) external payable returns (uint256 amount0, uint256 amount1);
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external;
}
interface IUniswapV3Factory {
function initialize(uint160 sqrtPriceX96) external;
function createPool(
address tokenA,
address tokenB,
uint24 fee
) external returns (address pool);
function feeAmountTickSpacing(uint24 fee) external view returns (int24);
}
interface ILockerFactory {
function deploy(
address token,
address beneficiary,
uint64 durationSeconds,
uint256 tokenId,
uint256 fees
) external payable returns (address);
}
interface ILocker {
function initializer(uint256 tokenId) external;
}
struct ExactInputSingleParams {
address tokenIn;
address tokenOut;
uint24 fee;
address recipient;
uint256 amountIn;
uint256 amountOutMinimum;
uint160 sqrtPriceLimitX96;
}
interface ISwapRouter {
function exactInputSingle(
ExactInputSingleParams calldata params
) external payable returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @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: GPL-2.0-or-later
pragma solidity >=0.5.0;
/// @title Math library for computing sqrt prices from ticks and vice versa
/// @notice Computes sqrt price for ticks of size 1.0001, i.e. sqrt(1.0001^tick) as fixed point Q64.96 numbers. Supports
/// prices between 2**-128 and 2**128
library TickMath {
/// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
int24 internal constant MIN_TICK = -887272;
/// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
int24 internal constant MAX_TICK = -MIN_TICK;
/// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
uint160 internal constant MIN_SQRT_RATIO = 4295128739;
/// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;
/// @notice Calculates sqrt(1.0001^tick) * 2^96
/// @dev Throws if |tick| > max tick
/// @param tick The input tick for the above formula
/// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
/// at the given tick
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
require(absTick <= uint256(int256(MAX_TICK)), 'T');
uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;
if (tick > 0) ratio = type(uint256).max / ratio;
// this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
// we then downcast because we know the result always fits within 160 bits due to our tick input constraint
// we round up in the division so getTickAtSqrtRatio of the output price is always consistent
sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
}
/// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
/// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
/// ever return.
/// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
/// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
// second inequality must be < because the price can never reach the price at the max tick
require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'R');
uint256 ratio = uint256(sqrtPriceX96) << 32;
uint256 r = ratio;
uint256 msb = 0;
assembly {
let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(5, gt(r, 0xFFFFFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(4, gt(r, 0xFFFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(3, gt(r, 0xFF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(2, gt(r, 0xF))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := shl(1, gt(r, 0x3))
msb := or(msb, f)
r := shr(f, r)
}
assembly {
let f := gt(r, 0x1)
msb := or(msb, f)
}
if (msb >= 128) r = ratio >> (msb - 127);
else r = ratio << (127 - msb);
int256 log_2 = (int256(msb) - 128) << 64;
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(63, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(62, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(61, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(60, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(59, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(58, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(57, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(56, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(55, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(54, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(53, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(52, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(51, f))
r := shr(f, r)
}
assembly {
r := shr(127, mul(r, r))
let f := shr(128, r)
log_2 := or(log_2, shl(50, f))
}
int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number
int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);
tick = tickLow == tickHi
? tickLow
: getSqrtRatioAtTick(tickHi) <= sqrtPriceX96
? tickHi
: tickLow;
}
}// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode( bytes memory data, bool fileSafe, bool noPadding ) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore( 0x3f, xor( "ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670) ) ) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) let dataEnd := add(add(0x20, data), dataLength) let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot. mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits. // Run over the input, 3 bytes at a time. for { } 1 { } { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`. mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode( bytes memory data ) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode( bytes memory data, bool fileSafe ) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode( string memory data ) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for { } 1 { } { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add( decodedLength, sub(and(dataLength, 3), 1) ) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore( 0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064 ) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for { } 1 { } { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore( ptr, or( and(m, mload(byte(28, input))), shr( 6, or( and(m, mload(byte(29, input))), shr( 6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) ) ) ) ) ) ) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC1155/IERC1155Receiver.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";
/**
* @dev Interface that must be implemented by smart contracts in order to receive
* ERC-1155 token transfers.
*/
interface IERC1155Receiver is IERC165 {
/**
* @dev Handles the receipt of a single ERC1155 token type. This function is
* called at the end of a `safeTransferFrom` after the balance has been updated.
*
* NOTE: To accept the transfer, this must return
* `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
* (i.e. 0xf23a6e61, or its own function selector).
*
* @param operator The address which initiated the transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param id The ID of the token being transferred
* @param value The amount of tokens being transferred
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
*/
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
) external returns (bytes4);
/**
* @dev Handles the receipt of a multiple ERC1155 token types. This function
* is called at the end of a `safeBatchTransferFrom` after the balances have
* been updated.
*
* NOTE: To accept the transfer(s), this must return
* `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
* (i.e. 0xbc197c81, or its own function selector).
*
* @param operator The address which initiated the batch transfer (i.e. msg.sender)
* @param from The address which previously owned the token
* @param ids An array containing ids of each token being transferred (order and length must match values array)
* @param values An array containing amounts of each token being transferred (order and length must match ids array)
* @param data Additional data with no specified format
* @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
*/
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*/
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
mapping(address account => uint256) private _balances;
mapping(address account => mapping(address spender => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `value`.
*/
function transfer(address to, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_transfer(owner, to, value);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `value` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 value) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `value`.
* - the caller must have allowance for ``from``'s tokens of at least
* `value`.
*/
function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, value);
_transfer(from, to, value);
return true;
}
/**
* @dev Moves a `value` amount of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _transfer(address from, address to, uint256 value) internal {
if (from == address(0)) {
revert ERC20InvalidSender(address(0));
}
if (to == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(from, to, value);
}
/**
* @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
* (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
* this function.
*
* Emits a {Transfer} event.
*/
function _update(address from, address to, uint256 value) internal virtual {
if (from == address(0)) {
// Overflow check required: The rest of the code assumes that totalSupply never overflows
_totalSupply += value;
} else {
uint256 fromBalance = _balances[from];
if (fromBalance < value) {
revert ERC20InsufficientBalance(from, fromBalance, value);
}
unchecked {
// Overflow not possible: value <= fromBalance <= totalSupply.
_balances[from] = fromBalance - value;
}
}
if (to == address(0)) {
unchecked {
// Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
_totalSupply -= value;
}
} else {
unchecked {
// Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
_balances[to] += value;
}
}
emit Transfer(from, to, value);
}
/**
* @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
* Relies on the `_update` mechanism
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead.
*/
function _mint(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidReceiver(address(0));
}
_update(address(0), account, value);
}
/**
* @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
* Relies on the `_update` mechanism.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* NOTE: This function is not virtual, {_update} should be overridden instead
*/
function _burn(address account, uint256 value) internal {
if (account == address(0)) {
revert ERC20InvalidSender(address(0));
}
_update(account, address(0), value);
}
/**
* @dev Sets `value` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address owner, address spender, uint256 value) internal {
_approve(owner, spender, value, true);
}
/**
* @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
*
* By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
* `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
* `Approval` event during `transferFrom` operations.
*
* Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
* true using the following override:
* ```
* function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
* super._approve(owner, spender, value, true);
* }
* ```
*
* Requirements are the same as {_approve}.
*/
function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
if (owner == address(0)) {
revert ERC20InvalidApprover(address(0));
}
if (spender == address(0)) {
revert ERC20InvalidSpender(address(0));
}
_allowances[owner][spender] = value;
if (emitEvent) {
emit Approval(owner, spender, value);
}
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `value`.
*
* Does not update the allowance value in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Does not emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
if (currentAllowance < value) {
revert ERC20InsufficientAllowance(spender, currentAllowance, value);
}
unchecked {
_approve(owner, spender, currentAllowance - value, false);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}{
"evmVersion": "paris",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"remappings": [
"forge-std/=lib/forge-std/src/",
"lib/v3-core/=lib/v3-core/",
"lib/openzeppelin-contracts/=lib/openzeppelin-contracts/",
"src/SocialDexDeployer.sol/=src/SocialDexDeployer.sol/",
"src/interface.sol/=src/interface.sol/",
"src/Bytes32AddressLib.sol/=src/Bytes32AddressLib.sol/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@uniswap/v3-core/=lib/v3-core/",
"@uniswap/v3-periphery/=lib/v3-periphery/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"v3-core/=lib/v3-core/",
"v3-periphery/=lib/v3-periphery/contracts/"
],
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Deprecated","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpNftId","type":"uint256"},{"indexed":false,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"uint256","name":"fid","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"address","name":"lockerAddress","type":"address"},{"indexed":false,"internalType":"string","name":"extraStringData","type":"string"},{"indexed":false,"internalType":"bool","name":"isMsgSenderOwner","type":"bool"}],"name":"TokenCreated","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"bundleFeeSwitch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"defaultLockingPeriod","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"int24","name":"_initialTick","type":"int24"},{"internalType":"bytes32","name":"_salt","type":"bytes32"},{"internalType":"address","name":"_deployer","type":"address"},{"internalType":"uint256","name":"_fid","type":"uint256"},{"internalType":"uint256","name":"mintPrice","type":"uint256"},{"internalType":"uint256","name":"mintEndTimestamp","type":"uint256"},{"internalType":"uint256","name":"maxMintSupply","type":"uint256"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_image","type":"string"},{"internalType":"string","name":"_animation","type":"string"},{"internalType":"string","name":"_extraStringData","type":"string"},{"internalType":"bytes","name":"_extraBytesData","type":"bytes"}],"name":"deployToken","outputs":[{"internalType":"contract BangerV3Token","name":"token","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"deprecated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fee","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"uint256","name":"fid","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"string","name":"animation","type":"string"},{"internalType":"string","name":"extraStringData","type":"string"},{"internalType":"bytes","name":"extraBytesData","type":"bytes"},{"internalType":"uint256","name":"supply","type":"uint256"}],"name":"generateSalt","outputs":[{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"address","name":"token","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint24","name":"_fee","type":"uint24"}],"name":"initialSwapTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"liquidityLocker","outputs":[{"internalType":"contract ILockerFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpFeesCut","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"deployer","type":"address"},{"internalType":"uint256","name":"fid","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"string","name":"image","type":"string"},{"internalType":"string","name":"animation","type":"string"},{"internalType":"string","name":"extraStringData","type":"string"},{"internalType":"bytes","name":"extraBytesData","type":"bytes"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"predictToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"protocolCut","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_deprecated","type":"bool"}],"name":"setDeprecated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxRate","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"toggleBundleFeeSwitch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV3Factory","outputs":[{"internalType":"contract IUniswapV3Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"newPeriod","type":"uint64"}],"name":"updateDefaultLockingPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newLocker","type":"address"}],"name":"updateLiquidityLocker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPositionManager","type":"address"}],"name":"updatePositionManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newFee","type":"uint8"}],"name":"updateProtocolFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRouter","type":"address"}],"name":"updateSwapRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCollector","type":"address"}],"name":"updateTaxCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"newRate","type":"uint8"}],"name":"updateTaxRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newFactory","type":"address"}],"name":"updateUniV3Factory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newWeth","type":"address"}],"name":"updateWeth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
6080806040523461016e576000805473cc4193b652fcb25347bb44a88d2b09b52585643f6001600160a01b0319821681178355916001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3600180547e1e321900000007bf59f7c52a67566660714afad6eb80a8a64eb7431b121f3c7fff00000000000000000000000000000000000000000000000000000000000000909116179055600280546001600160b81b03191672a4944d1e707f869356ff4b48e527370f002710179055600380546001600160a01b0319908116734200000000000000000000000000000000000006179091556004805482167333128a8fc17869897dce68ed026d694621f6fdfd179055600580549091167303a520b32c04bf3beef7beb72e919cf822ed34f117905560068054600161ff0160a01b0319167501002626664c2603336e57b271c5c0b26f421741e48117905561470990816101748239f35b600080fdfe61056080604052600436101561001b575b50361561001957005b005b600061012052610120513560e01c90816301ffc9a714612e2c575080630e136b1914612e0457806310f3577e14612d515780631962d94714612d0b5780631b5ad80114612cc55780632bdd20ef14612c7f57806337ad470114610f405780633aa10f1f14610ee25780633fc8cef314610eb757806340c10f1914610a6c5780634de2fae714610a2257806357aa0201146109fc5780635b549182146109d15780636881d8cb1461098b578063715018a614610929578063771a3a1d14610903578063791b98bc146108d85780637ebdf9ab146108b05780638da5cb5b146108835780639759164a146108545780639dbb8c9f14610803578063b0fad6f0146107b9578063b98b677f14610773578063bc197c81146106db578063bea1dcf8146106b0578063c31c9c0714610685578063cb1e82ee14610576578063d406d7511461054a578063d848dee714610500578063ddca3f43146104db578063de04f42e146104b5578063e42efd541461046b578063f23a6e6114610415578063f2fde38b1461037f5763f408ad2a146101b15738610010565b3461037857610120366003190112610378576101cb612e62565b610420526044356001600160401b038111610378576101ee903690600401612e8e565b61046052610480526064356001600160401b03811161037857610215903690600401612e8e565b6104a052610440526084356001600160401b0381116103785761023c903690600401612e8e565b6103205260a4356001600160401b0381116103785761025f903690600401612e8e565b610380526103605260c4356001600160401b03811161037857610286903690600401612e8e565b6103c0526103a05260e4356001600160401b038111610378576102ad903690600401612e8e565b610400526103e052610120516003546001600160a01b0316610340525b8061030c8261010435610400516103e0516103c0516103a0516103805161036051610320518c6104a0516104405161046051610480516024356104205161318b565b610340519091906001600160a01b038316108061036f575b610355575050600019811461033b576001016102ca565b634e487b7160e01b61012051526011600452602461012051fd5b604080519182526001600160a01b03929092166020820152f35b50813b15610324565b6101205180fd5b3461037857602036600319011261037857610398612e62565b6103a06132b3565b6001600160a01b031680156103f9576101205180546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36101205180f35b631e4fbdf760e01b610120515261012051600452602461012051fd5b346103785760a03660031901126103785761042e612e62565b50610437612e78565b506084356001600160401b03811161037857610457903690600401612e8e565b505060405163f23a6e6160e01b8152602090f35b346103785760203660031901126103785760043560ff81168103610378576104916132b3565b6001805460ff60e01b191660e09290921b60ff60e01b169190911790556101205180f35b34610378576101205136600319011261037857602060ff60015460f01c16604051908152f35b34610378576101205136600319011261037857602062ffffff60025416604051908152f35b3461037857602036600319011261037857600435801515809103610378576105266132b3565b6006805460ff60a01b191660a09290921b60ff60a01b169190911790556101205180f35b3461037857610120513660031901126103785760206001600160401b0360015460a01c16604051908152f35b346103785761014036600319011261037857610590612e62565b6044356001600160401b038111610378576105af903690600401612e8e565b906064356001600160401b038111610378576105cf903690600401612e8e565b93906084356001600160401b038111610378576105f0903690600401612e8e565b60a4959195356001600160401b03811161037857610612903690600401612e8e565b60c4929192356001600160401b03811161037857610634903690600401612e8e565b93909260e435996001600160401b038b116103785760209b61065d6106739c3690600401612e8e565b999098610124359c610104359c6024359061318b565b6040516001600160a01b039091168152f35b346103785761012051366003190112610378576006546040516001600160a01b039091168152602090f35b346103785761012051366003190112610378576001546040516001600160a01b039091168152602090f35b346103785760a0366003190112610378576106f4612e62565b506106fd612e78565b506044356001600160401b0381116103785761071d903690600401612ebb565b50506064356001600160401b0381116103785761073e903690600401612ebb565b50506084356001600160401b0381116103785761075f903690600401612e8e565b505060405163bc197c8160e01b8152602090f35b346103785760203660031901126103785761078c612e62565b6107946132b3565b60018060a01b03166001600160601b0360a01b60065416176006556101205161012051f35b3461037857602036600319011261037857600435801515809103610378576107df6132b3565b6006805460ff60a81b191660a89290921b60ff60a81b169190911790556101205180f35b346103785760203660031901126103785761081c612e62565b6108246132b3565b600280546301000000600160b81b03191660189290921b6301000000600160b81b03169190911790556101205180f35b3461037857610120513660031901126103785760025460405160189190911c6001600160a01b03168152602090f35b3461037857610120513660031901126103785761012051546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60065460a81c166040519015158152f35b346103785761012051366003190112610378576005546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60015460e01c16604051908152f35b346103785761012051366003190112610378576109446132b3565b6101205180546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36101205180f35b34610378576020366003190112610378576109a4612e62565b6109ac6132b3565b60018060a01b03166001600160601b0360a01b60055416176005556101205161012051f35b346103785761012051366003190112610378576004546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60015460e81c16604051908152f35b346103785760203660031901126103785760043560ff8116810361037857610a486132b3565b6001805460ff60e81b191660e89290921b60ff60e81b169190911790556101205180f35b604036600319011261037857610a80612e62565b60405163041804f760e31b8152610120516001600160a01b0383166004830181905230602480850191909152909392903591816044816fdb40fcb9f4466330982372e27fd7bbf55afa908115610d9b576101205191610e33575b5060c08180518101031261037857604081015192610afa60608301613177565b610b1260a0610b0b60808601613177565b9401613177565b506001600160a01b0316803b1561037857604051630d9778e560e11b8152856004820152846024820152610120518160448134865af18015610d9b57610e18575b50803b156103785760405190637921219560e11b825230600483015233602483015285604483015284606483015260a060848301526101205160a48301528160c481610120519361012051905af18015610d9b57610dfd575b50610bb6906132dc565b92604051926020840152604083015283606083015260018060a01b0316608082015260808152610be760a082612f1c565b6fb24d62781db359b07880a105cd0b64e63b1561037857610c49610c5f9260405193849283926308521f2760e21b84523360048501526080602485015260046084850152631b5a5b9d60e21b60a485015260c0604485015260c48401906130f6565b82810360031901606484015261012051946130f6565b0381610120516fb24d62781db359b07880a105cd0b64e65af18015610d9b57610de2575b5034610c91575b6101205180f35b6040516324a9d85360e01b81526020816004816f1c147e48f5aad3c69e8e4d2305523c625afa908115610d9b576101205191610da9575b50610d5c610ce6612710610cdf6020943490613082565b04346130ab565b600354600254604051929562ffffff909116916001600160a01b0316610d0b84612eeb565b83528483015260408201523360608201528360808201526101205160a08201526101205160c082015260018060a01b0360065416906040519485809481936304e45aaf60e01b835260048301612f4c565b03925af18015610d9b5715610c8a575b610d8d9060203d602011610d94575b610d858183612f1c565b810190612f3d565b5080610c8a565b503d610d7b565b6040513d61012051823e3d90fd5b90506020813d602011610dda575b81610dc460209383612f1c565b81010312610dd55751610d5c610cc8565b600080fd5b3d9150610db7565b61012051610def91612f1c565b610120516103785781610c83565b61012051610e0a91612f1c565b610120516103785785610bac565b61012051610e2591612f1c565b610120516103785786610b53565b90503d8061012051833e610e478183612f1c565b8101906040818303126103785780516001600160401b03811161037857810182601f820112156103785782816020610e8193519101613140565b506020810151906001600160401b03821161037857019080601f83011215610378578151610eb192602001613140565b84610ada565b346103785761012051366003190112610378576003546040516001600160a01b039091168152602090f35b34610378576020366003190112610378576004356001600160401b038116810361037857610f0e6132b3565b6001805467ffffffffffffffff60a01b191660a09290921b67ffffffffffffffff60a01b169190911790556101205180f35b6101c036600319011261037857602435610520526105205160020b6105205103610378576064356101408190526001600160a01b038116900361037857610104356001600160401b03811161037857610f9d903690600401612e8e565b6101605261018052610124356001600160401b03811161037857610fc5903690600401612e8e565b6102a0526102c052610144356001600160401b03811161037857610fed903690600401612e8e565b60e05261054052610164356001600160401b03811161037857611014903690600401612e8e565b60c052610184356001600160401b03811161037857611037903690600401612e8e565b6104e0526104c0526101a4356001600160401b0381116103785761105f903690600401612e8e565b906102205260ff60065460a01c16612c6a5760018060a01b0360045416602062ffffff600254166024604051809481936322afcccb60e01b835260048301525afa908115610d9b576101205191612c2e575b508060020b151580612c0f575b15612bdb5760408051610140516001600160a01b031660208201908152604435928201929092526110fc81606081015b03601f198101835282612f1c565b519020604051806112cc8101106001600160401b036112cc83011117612552576112cc61340882398061116785610220516104e0516104c05160c0518b60e05161054051608435610140516004356102a0518d6102c05190610160519061018051906112cc01612fcb565b039061012051f5610500526105005115610d9b57600354610500516001600160a01b039182169116811115612ba757610120516105205160020b1215612b9b576105205160020b600160ff1b1461033b576105205160020b61012051035b620d89e891828211612b72576001821615612b60576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116612b15575b60048116612aca575b60088116612a7f575b60108116612a34575b602081166129e9575b6040811661299e575b60808116612953575b6101008116612908575b61020081166128bd575b6104008116612872575b6108008116612827575b61100081166127dc575b6120008116612791575b6140008116612746575b61800081166126fb575b6201000081166126b0575b620200008116612668575b620400008116612623575b62080000166125e4575b610120516105205160020b136125d3575b602082901c9163ffffffff166125cb5761012051905b60ff82168301831161033b576004805460025460405163a167129560e01b8152610500516001600160a01b0390811694820194909452602481019490945262ffffff16604484015261012051602092849260649284929091165af18015610d9b576101205161010052612599575b50610100516001600160a01b03163b156103785760405163f637731d60e01b815260ff919091169091016001600160a01b03908116600483015261012051610100519091839160249183918591165af18015610d9b57612586575b506003546001600160a01b0316610300526002805462ffffff169083900b1561256c576040516102e08190526001600160401b036101608201908111911117612552576101606102e0510160405260018060a01b0361050051166102e051526103005160206102e051015260406102e05101526105205160020b60606102e05101528160020b90050260020b60806102e051015260043560a06102e05101526101205160c06102e05101526101205160e06102e0510152610120516101006102e0510152306101206102e0510152426101406102e051015260018060a01b03600554166040519063095ea7b360e01b8252600482015260043560248201526020816044816101205160018060a01b0361050051165af18015610d9b57612518575b5060018060a01b03600554166102805260405161026052634418b22b60e11b610260515260018060a01b036102e0515116600461026051015260018060a01b0360206102e051015116602461026051015262ffffff60406102e051015116604461026051015260606102e051015160020b606461026051015260806102e051015160020b608461026051015260a06102e051015160a461026051015260c06102e051015160c461026051015260e06102e051015160e46102605101526101006102e051015161010461026051015260018060a01b036101206102e0510151166101246102605101526101406102e05101516101446102605101526080610260516101646102605161012051610280515af1610240526102405115610d9b576101205161020052610240516124bb575b602060018060a01b0360025460181c1660ff60018060a01b0360055416600154906040516101e052634e54db0960e01b6101e0515260046101e051015260018060a01b03610140511660246101e05101526001600160401b038160a01c1660446101e05101526102005160646101e051015260e81c1660846101e051015260a46101e051916101e0519061012051905af16101c0526101c05115610d9b57610120516101a0526101c051612481575b6005546001600160a01b0316803b1561037857604051632142170760e11b81523060048201526101a0516001600160a01b031660248201526102005160448201526101205190918290606490829084905af18015610d9b57612466575b506101a0516001600160a01b03163b15610378576040516367a4d1c360e01b8152610200516004820152610120516101a0518290602490829084906001600160a01b03165af18015610d9b5761244b575b50346122c8575b60405163b8070c7360e01b8152906020826004816fb24d62781db359b07880a105cd0b64e65afa60a05260a05115610d9b57610120519160a051612294575b506118796001600860056117b0838060a01b0361050051166132dc565b60026117be610100516132dc565b916040516080526802232b83637bcb2b2160bd1b602060805101526101605161018051602960805101376029610160516080510161040560f31b828201526102a0516102c051602b8301376102a051010164014903a37960dd1b838201526118308251809360206007850191016130d3565b010167010143837b7b61d160c51b83820152611856825180936020600d850191016130d3565b0101602960f81b82820152608051900301601e1981016080515201608051612f1c565b610500516110ee9061192e90611897906001600160a01b03166132dc565b9260405192839186602084015260018060a01b036101005116604084015260018060a01b036105005116606084015260018060a01b036101a0511660808401526102005160a084015260018060a01b03610140511660c084015260843560e084015261012061010084015261191761014084016104e0516104c051612faa565b90601f198483030161012085015261022051612faa565b6fb24d62781db359b07880a105cd0b64e63b1561037857610c4961198c9260405193849283926308521f2760e21b84523360048501526080602485015261197a608485016080516130f6565b848103600319016044860152906130f6565b0381610120516fb24d62781db359b07880a105cd0b64e65af18015610d9b57612279575b50604051633ee60bcf60e01b8152916020836004816f1c147e48f5aad3c69e8e4d2305523c625afa928315610d9b576101205193612245575b5061050051611a00906001600160a01b03166132dc565b60e05115611f7657611a1360e0516130b8565b611a206040519182612f1c565b60e05181523660e051610540510111610378576013611bae92600b6002956004879560e05161054051602083013761012051602060e051830101525b6047604051998a96683d913730b6b2911d1160b91b6020890152610160516101805160298a0137602961016051890161040560f31b828201526102a0516102c051602b8301376102a0510101602960f81b838201527f222c226465736372697074696f6e223a224d656d65636f696e2d4e465420637260038201527f656174656420766961204e65742e204d656d65636f696e206973206c6f636174602382015265032b21030ba160d51b6043820152611b208251809360206049850191016130d3565b0101632e372e3760e11b828201526104e0516104c051604b8301376104e05101016a11161134b6b0b3b2911d1160a91b83820152611b68825180936020600f850191016130d3565b0101907211161130b734b6b0ba34b7b72fbab936111d1160691b8383015260c05190601e83013760c051010161227d60f01b838201520301601d19810184520182612f1c565b6f1c147e48f5aad3c69e8e4d2305523c623b156103785760405190630dd2f7a160e41b825260a435600483015260e435602483015260c435604483015261012051606483015260a060848301528180611c0f610120519360a48301906130f6565b0381610120516f1c147e48f5aad3c69e8e4d2305523c625af18015610d9b57611f5b575b506f1c147e48f5aad3c69e8e4d2305523c623b1561037857604051637921219560e11b8152306004820152610140516001600160a01b03166024820152604481018390526001606482015260a06084820152610120805160a4830152518160c481836f1c147e48f5aad3c69e8e4d2305523c625af18015610d9b57611f40575b5060408051602081019290925281018290526f1c147e48f5aad3c69e8e4d2305523c626060820152610100516001600160a01b0390811660808301526101a0511660a08201526102005160c0808301919091528152611d1360e082612f1c565b6fdb40fcb9f4466330982372e27fd7bbf53b15610378576040519063f9ed11d960e01b82528180611d57610120519360018060a01b0361050051166004840161311b565b0381610120516fdb40fcb9f4466330982372e27fd7bbf55af18015610d9b57611f25575b506040519080602083015260018060a01b036105005116604083015260018060a01b036101005116606083015260608252611db7608083612f1c565b6fdb40fcb9f4466330982372e27fd7bbf53b1561037857611df1916040518093819263f9ed11d960e01b835261012051946004840161311b565b0381610120516fdb40fcb9f4466330982372e27fd7bbf55af18015610d9b57611f0a575b7f7c8762543264172a17e130518fcc375c045781639d522d793332fc5c76a5ffe560018060a01b036101205154163314604051809160018060a01b036105005116825261020051602083015260018060a01b036101405116604083015260843560608301526101406080830152611ee2611eb2611e9d61014085016101605161018051612faa565b84810360a08601526102a0516102c051612faa565b60043560c08501526101a0516001600160a01b031660e08501528381036101008501526104e0516104c051612faa565b906101208301520390a160408051610500516001600160a01b03168152610200516020820152f35b61012051611f1791612f1c565b610120516103785780611e15565b61012051611f3291612f1c565b610120516103785781611d7b565b61012051611f4d91612f1c565b610120516103785782611cb3565b61012051611f6891612f1c565b610120516103785782611c33565b6040517f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208201527f30302f737667222077696474683d2235303022206865696768743d223530302260408201527f207374796c653d226261636b67726f756e642d636f6c6f723a23303030223e3c60608201527f7465787420783d223530252220793d223530252220746578742d616e63686f7260808201527f3d226d6964646c652220646f6d696e616e742d626173656c696e653d226d696460a08201527f646c6522207374796c653d22666f6e742d66616d696c793a6d6f6e6f7370616360c08201527f653b666f6e742d73697a653a323470783b66696c6c3a23306637223e0000000060e0820152610160516101805160fc8301376120c3600d60fc836101605181016c1e17ba32bc3a1f1e17b9bb339f60991b838201520301601219810184520182612f1c565b8051606091808261213a575b5050506013611bae92600b60029560048795612135603a60405180937f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000602083015261212481518092602086860191016130d3565b81010301601f198101835282612f1c565b611a5c565b9193909250604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f526020850160046003602084870101519661012051602086890101525b0191603f8351818160121c165161012051538181600c1c1651600153818160061c1651600253165160035361012051518152019060206003600285010460021b880101821015612200576004906003906121ab565b509281016020019390935260036002848101829004811b80870160409081019052613d3d60f01b9290950690048303526101205190915290825290601382600b6120cf565b9092506020813d602011612271575b8161226160209383612f1c565b81010312610dd5575191836119e9565b3d9150612254565b6101205161228691612f1c565b6101205161037857826119b0565b9091506020813d6020116122c0575b816122b060209383612f1c565b81010312610dd557519083611793565b3d91506122a3565b3460ff60065460a81c16612397575b6003546002546040516020926123639262ffffff16906001600160a01b03166122ff83612eeb565b8252610500516001600160a01b0390811685840152604080840192909252610140518116606084015260808301869052610120805160a08501525160c084015260065491516304e45aaf60e01b815295869492909116928492839160048301612f4c565b03925af18015610d9b57612378575b50611754565b6123909060203d602011610d9457610d858183612f1c565b5082612372565b506001546103e86123ae60ff8360e01c1634613082565b046123b981346130ab565b61012051909290918291829182916001600160a01b03165af13d15612446573d6123e2816130b8565b906123f06040519283612f1c565b8152610120513d916020013e5b6122d75760405162461bcd60e51b815260206004820152601c60248201527f4661696c656420746f2073656e642070726f746f636f6c2066656573000000006044820152606490fd5b6123fd565b6101205161245891612f1c565b61012051610378578261174d565b6101205161247391612f1c565b6101205161037857826116fc565b60203d6020116124b4575b8061249d6124ab926101e051612f1c565b6101e051016101e051613063565b6101a05261169f565b503d61248c565b60803d608011612511575b806124d660809261026051612f1c565b61026051908101031261037857610260515160206102605101516fffffffffffffffffffffffffffffffff81160361037857610200526115f0565b503d6124c6565b6020813d60201161254a575b8161253160209383612f1c565b81010312610378575180151581146114c1576101205180fd5b3d9150612524565b634e487b7160e01b61012051526041600452602461012051fd5b634e487b7160e01b61012051526012600452602461012051fd5b6101205161259391612f1c565b846113a0565b6125ba9060203d6020116125c4575b6125b28183612f1c565b810190613063565b6101005286611345565b503d6125a8565b6001906112d7565b90801561256c5760001904906112c1565b90806b048a170391f7dc42444e8fa28102046b048a170391f7dc42444e8fa2148115171561033b576b048a170391f7dc42444e8fa20260801c906112b0565b91806d2216e584f5fa1ea926041bedfe988102046d2216e584f5fa1ea926041bedfe98148115171561033b576d2216e584f5fa1ea926041bedfe980260801c916112a6565b91806e5d6af8dedb81196699c329225ee6048102046e5d6af8dedb81196699c329225ee604148115171561033b576e5d6af8dedb81196699c329225ee6040260801c9161129b565b91806f09aa508b5b7a84e1c677de54f3e99bc98102046f09aa508b5b7a84e1c677de54f3e99bc9148115171561033b576f09aa508b5b7a84e1c677de54f3e99bc90260801c91611290565b91806f31be135f97d08fd981231505542fcfa68102046f31be135f97d08fd981231505542fcfa6148115171561033b576f31be135f97d08fd981231505542fcfa60260801c91611285565b91806f70d869a156d2a1b890bb3df62baf32f78102046f70d869a156d2a1b890bb3df62baf32f7148115171561033b576f70d869a156d2a1b890bb3df62baf32f70260801c9161127b565b91806fa9f746462d870fdf8a65dc1f90e061e58102046fa9f746462d870fdf8a65dc1f90e061e5148115171561033b576fa9f746462d870fdf8a65dc1f90e061e50260801c91611271565b91806fd097f3bdfd2022b8845ad8f792aa58258102046fd097f3bdfd2022b8845ad8f792aa5825148115171561033b576fd097f3bdfd2022b8845ad8f792aa58250260801c91611267565b91806fe7159475a2c29b7443b29c7fa6e889d98102046fe7159475a2c29b7443b29c7fa6e889d9148115171561033b576fe7159475a2c29b7443b29c7fa6e889d90260801c9161125d565b91806ff3392b0822b70005940c7a398e4b70f38102046ff3392b0822b70005940c7a398e4b70f3148115171561033b576ff3392b0822b70005940c7a398e4b70f30260801c91611253565b91806ff987a7253ac413176f2b074cf7815e548102046ff987a7253ac413176f2b074cf7815e54148115171561033b576ff987a7253ac413176f2b074cf7815e540260801c91611249565b91806ffcbe86c7900a88aedcffc83b479aa3a48102046ffcbe86c7900a88aedcffc83b479aa3a4148115171561033b576ffcbe86c7900a88aedcffc83b479aa3a40260801c9161123f565b91806ffe5dee046a99a2a811c461f1969c30538102046ffe5dee046a99a2a811c461f1969c3053148115171561033b576ffe5dee046a99a2a811c461f1969c30530260801c91611235565b91806fff2ea16466c96a3843ec78b326b528618102046fff2ea16466c96a3843ec78b326b52861148115171561033b576fff2ea16466c96a3843ec78b326b528610260801c9161122c565b91806fff973b41fa98c081472e6896dfb254c08102046fff973b41fa98c081472e6896dfb254c0148115171561033b576fff973b41fa98c081472e6896dfb254c00260801c91611223565b91806fffcb9843d60f6159c9db58835c9266448102046fffcb9843d60f6159c9db58835c926644148115171561033b576fffcb9843d60f6159c9db58835c9266440260801c9161121a565b91806fffe5caca7e10e4e61c3624eaa0941cd08102046fffe5caca7e10e4e61c3624eaa0941cd0148115171561033b576fffe5caca7e10e4e61c3624eaa0941cd00260801c91611211565b91806ffff2e50f5f656932ef12357cf3c7fdcc8102046ffff2e50f5f656932ef12357cf3c7fdcc148115171561033b576ffff2e50f5f656932ef12357cf3c7fdcc0260801c91611208565b91806ffff97272373d413259a46990580e213a8102046ffff97272373d413259a46990580e213a148115171561033b576ffff97272373d413259a46990580e213a0260801c916111ff565b6001600160881b03600160801b6111f4565b60405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606490fd5b6105205160020b6111c5565b60405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a59081cd85b1d60a21b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964207469636b60a01b6044820152606490fd5b508060020b1561256c578060020b6105205160020b0760020b156110be565b90506020813d602011612c62575b81612c4960209383612f1c565b8101031261037857518060020b810361037857836110b1565b3d9150612c3c565b6331cee75f60e21b6101205152600461012051fd5b3461037857602036600319011261037857612c98612e62565b612ca06132b3565b60018060a01b03166001600160601b0360a01b60045416176004556101205161012051f35b3461037857602036600319011261037857612cde612e62565b612ce66132b3565b60018060a01b03166001600160601b0360a01b60035416176003556101205161012051f35b3461037857602036600319011261037857612d24612e62565b612d2c6132b3565b60018060a01b03166001600160601b0360a01b60015416176001556101205161012051f35b604036600319011261037857612d65612e62565b60243562ffffff811680910361037857600354604051612ded9360209391926001600160a01b0316612d9684612eeb565b835260018060a01b03168383015260408201523360608201523460808201526101205160a08201526101205160c082015260018060a01b036006541660405180809581946304e45aaf60e01b835260048301612f4c565b039134905af18015610d9b57610d6c576101205180f35b34610378576101205136600319011261037857602060ff60065460a01c166040519015158152f35b34610378576020366003190112610378576004359063ffffffff60e01b821680920361037857602091630271189760e51b148152f35b600435906001600160a01b0382168203610dd557565b602435906001600160a01b0382168203610dd557565b9181601f84011215610dd5578235916001600160401b038311610dd55760208381860195010111610dd557565b9181601f84011215610dd5578235916001600160401b038311610dd5576020808501948460051b010111610dd557565b60e081019081106001600160401b03821117612f0657604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117612f0657604052565b90816020910312610dd5575190565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0808401519083015260c092830151169181019190915260e00190565b908060209392818452848401376000828201840152601f01601f1916010190565b9d9b9996906130609f9d99938f90976130106130519e9961303599986130026080966130439f996101208852610120880191612faa565b918583036020870152612faa565b60408301979097526001600160a01b0316606082015201528c830360a08e0152612faa565b9189830360c08b0152612faa565b9186830360e0880152612faa565b92610100818503910152612faa565b90565b90816020910312610dd557516001600160a01b0381168103610dd55790565b8181029291811591840414171561309557565b634e487b7160e01b600052601160045260246000fd5b9190820391821161309557565b6001600160401b038111612f0657601f01601f191660200190565b60005b8381106130e65750506000910152565b81810151838201526020016130d6565b9060209161310f815180928185528580860191016130d3565b601f01601f1916010190565b60809061306093928152606060208201526000606082015281604082015201906130f6565b9092919261314d816130b8565b9161315b6040519384612f1c565b829482845282820111610dd55760206131759301906130d3565b565b51906001600160a01b0382168203610dd557565b90919a97949d9e9c9996939c9b9895929b6040518060208101926131c590858560209093929193604081019460018060a01b031681520152565b03601f19810182526131d79082612f1c565b5190209e6040519e8f6112cc6020016131f09082612f1c565b6112cc81526112cc9061340890602001396040519e8f9e8f6020019e6132159f612fcb565b03601f19810182526132279082612f1c565b60405180916020820193848151602081930191613243926130d3565b82018151918260208301916020019161325b926130d3565b010380825261326d9060200182612f1c565b5190209060405191602083019160ff60f81b83523060601b602185015260358401526055830152605582526132a3607583612f1c565b905190206001600160a01b031690565b6000546001600160a01b031633036132c757565b63118cdaa760e01b6000523360045260246000fd5b9060405191608083016040526f30313233343536373839616263646566600f526002830190602882526000604a85015260601b600160005b8080018601602284831a600f811651602384015360041c519101530190601482146133425790600190613314565b50506130786002825101915282528160228101907f88888888888888888888888888888888888888888888888888888888888888806028832016600160005b601160f31b83821a02818001520190601482146133a15790600190613381565b505060429180517f2020202020202020202020202020202020202020202020202020202020202020816000511660011c161890520180517f2020202020202020202020202020202020202020202020202020202020202020816020511660011c1618905256fe60806040523461085b576112cc8038038061001981610860565b9283398101906101208183031261085b5780516001600160401b03811161085b57826100469183016108df565b60208201516001600160401b03811161085b57836100659184016108df565b604083015160608401519091906001600160a01b0381169081900361085b57608085015160a08601519091906001600160401b03811161085b57876100ab9188016108df565b60c08701519093906001600160401b03811161085b57886100cd9189016108df565b60e08801519098906001600160401b03811161085b57816100ef918a016108df565b61010089015190986001600160401b03821161085b57019080601f8301121561085b57815161012092602001610885565b865190966001600160401b0382116104b15761013d6003546108fc565b601f811161080c575b50602090601f83116001146107a3576101789291600091836103e7575b50508160011b916000199060031b1c19161790565b6003555b8051906001600160401b0382116104b1576101986004546108fc565b601f8111610754575b50602090601f83116001146106eb576101d29291600091836103e75750508160011b916000199060031b1c19161790565b6004555b600580546001600160a01b0319169190911790556006558051906001600160401b0382116104b1576102096007546108fc565b601f811161069c575b50602090601f8311600114610633576102439291600091836103e75750508160011b916000199060031b1c19161790565b6007555b83516001600160401b0381116104b1576102626008546108fc565b601f81116105e4575b50602094601f821160011461057d5761029f9293949582916000926103e75750508160011b916000199060031b1c19161790565b6008555b82516001600160401b0381116104b1576102be6009546108fc565b601f811161052e575b506020601f82116001146104c75781906102f99394956000926103e75750508160011b916000199060031b1c19161790565b6009555b81516001600160401b0381116104b157610318600a546108fc565b601f8111610457575b50602092601f82116001146103f257610353929382916000926103e75750508160011b916000199060031b1c19161790565b600a555b33156103d1576002548181018091116103bb57600255600033815280602052604081208281540190556040519182527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203393a360405161097e908161094e8239f35b634e487b7160e01b600052601160045260246000fd5b63ec442f0560e01b600052600060045260246000fd5b015190503880610163565b601f19821693600a600052806000209160005b86811061043f5750836001959610610426575b505050811b01600a55610357565b015160001960f88460031b161c19169055388080610418565b91926020600181928685015181550194019201610405565b600a6000526104a1907fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601f840160051c810191602085106104a7575b601f0160051c0190610936565b38610321565b9091508190610494565b634e487b7160e01b600052604160045260246000fd5b601f198216906009600052806000209160005b818110610516575095836001959697106104fd575b505050811b016009556102fd565b015160001960f88460031b161c191690553880806104ef565b9192602060018192868b0151815501940192016104da565b6009600052610577907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c810191602085106104a757601f0160051c0190610936565b386102c7565b601f198216956008600052806000209160005b8881106105cc575083600195969798106105b3575b505050811b016008556102a3565b015160001960f88460031b161c191690553880806105a5565b91926020600181928685015181550194019201610590565b600860005261062d907ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3601f840160051c810191602085106104a757601f0160051c0190610936565b3861026b565b90601f198316916007600052816000209260005b818110610684575090846001959493921061066b575b505050811b01600755610247565b015160001960f88460031b161c1916905538808061065d565b92936020600181928786015181550195019301610647565b60076000526106e5907fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688601f850160051c810191602086106104a757601f0160051c0190610936565b38610212565b90601f198316916004600052816000209260005b81811061073c5750908460019594939210610723575b505050811b016004556101d6565b015160001960f88460031b161c19169055388080610715565b929360206001819287860151815501950193016106ff565b600460005261079d907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f850160051c810191602086106104a757601f0160051c0190610936565b386101a1565b90601f198316916003600052816000209260005b8181106107f457509084600195949392106107db575b505050811b0160035561017c565b015160001960f88460031b161c191690553880806107cd565b929360206001819287860151815501950193016107b7565b6003600052610855907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f850160051c810191602086106104a757601f0160051c0190610936565b38610146565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176104b157604052565b9192916001600160401b0382116104b1576108a9601f8301601f1916602001610860565b938285528282011161085b5760005b8281106108cc575050602060009184010152565b80602091830151828288010152016108b8565b9080601f8301121561085b5781516108f992602001610885565b90565b90600182811c9216801561092c575b602083101461091657565b634e487b7160e01b600052602260045260246000fd5b91607f169161090b565b818110610941575050565b6000815560010161093656fe6080604052600436101561001257600080fd5b60003560e01c806306fdde03146106fc578063095ea7b31461067657806318160ddd1461065857806323b872dd1461056b578063313ce5671461054f5780633257b4f31461053157806370a08231146104f75780638c662b7f1461044f57806395d89b41146103a7578063977fb1cc146102ff578063a9059cbb146102ce578063d5f39488146102a5578063dd62ed3e14610254578063e8a5edce146101ab5763f3ccaac0146100c157600080fd5b346101a65760003660031901126101a65760405160006007546100e381610811565b80845290600181169081156101825750600114610123575b61011f8361010b8185038261084b565b6040519182916020835260208301906107a4565b0390f35b600760009081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688939250905b8082106101685750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610150565b60ff191660208086019190915291151560051b8401909101915061010b90506100fb565b600080fd5b346101a65760003660031901126101a6576040516000600a546101cd81610811565b808452906001811690811561018257506001146101f45761011f8361010b8185038261084b565b919050600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8916000905b80821061023a5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610222565b346101a65760403660031901126101a65761026d6107e5565b6102756107fb565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b346101a65760003660031901126101a6576005546040516001600160a01b039091168152602090f35b346101a65760403660031901126101a6576102f46102ea6107e5565b6024359033610883565b602060405160018152f35b346101a65760003660031901126101a657604051600060085461032181610811565b808452906001811690811561018257506001146103485761011f8361010b8185038261084b565b600860009081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3939250905b80821061038d5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610375565b346101a65760003660031901126101a65760405160006004546103c981610811565b808452906001811690811561018257506001146103f05761011f8361010b8185038261084b565b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106104355750909150810160200161010b6100fb565b91926001816020925483858801015201910190929161041d565b346101a65760003660031901126101a657604051600060095461047181610811565b808452906001811690811561018257506001146104985761011f8361010b8185038261084b565b600960009081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106104dd5750909150810160200161010b6100fb565b9192600181602092548385880101520191019092916104c5565b346101a65760203660031901126101a6576001600160a01b036105186107e5565b1660005260006020526020604060002054604051908152f35b346101a65760003660031901126101a6576020600654604051908152f35b346101a65760003660031901126101a657602060405160128152f35b346101a65760603660031901126101a6576105846107e5565b61058c6107fb565b6001600160a01b03821660008181526001602081815260408084203385529091529091205491936044359392909181016105cc575b506102f49350610883565b83811061063b57841561062557331561060f576102f4946000526001602052604060002060018060a01b03331660005260205283604060002091039055846105c1565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b346101a65760003660031901126101a6576020600254604051908152f35b346101a65760403660031901126101a65761068f6107e5565b602435903315610625576001600160a01b031690811561060f57336000526001602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346101a65760003660031901126101a657604051600060035461071e81610811565b808452906001811690811561018257506001146107455761011f8361010b8185038261084b565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b80821061078a5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610772565b919082519283825260005b8481106107d0575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016107af565b600435906001600160a01b03821682036101a657565b602435906001600160a01b03821682036101a657565b90600182811c92168015610841575b602083101461082b57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610820565b90601f8019910116810190811067ffffffffffffffff82111761086d57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0316908115610932576001600160a01b031691821561091c5760008281528060205260408120548281106109025791604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b634b637e8f60e11b600052600060045260246000fdfea26469706673582212206c58257e9404c1e2494d4f719acb3b836cb49a49d92f4b5610d7074fbe24923364736f6c634300081a0033a264697066735822122041824f4abf3181b8b2a5453c96c8b2b4ad717e33543abb9ddf31ec180a02e07d64736f6c634300081a0033
Deployed Bytecode
0x61056080604052600436101561001b575b50361561001957005b005b600061012052610120513560e01c90816301ffc9a714612e2c575080630e136b1914612e0457806310f3577e14612d515780631962d94714612d0b5780631b5ad80114612cc55780632bdd20ef14612c7f57806337ad470114610f405780633aa10f1f14610ee25780633fc8cef314610eb757806340c10f1914610a6c5780634de2fae714610a2257806357aa0201146109fc5780635b549182146109d15780636881d8cb1461098b578063715018a614610929578063771a3a1d14610903578063791b98bc146108d85780637ebdf9ab146108b05780638da5cb5b146108835780639759164a146108545780639dbb8c9f14610803578063b0fad6f0146107b9578063b98b677f14610773578063bc197c81146106db578063bea1dcf8146106b0578063c31c9c0714610685578063cb1e82ee14610576578063d406d7511461054a578063d848dee714610500578063ddca3f43146104db578063de04f42e146104b5578063e42efd541461046b578063f23a6e6114610415578063f2fde38b1461037f5763f408ad2a146101b15738610010565b3461037857610120366003190112610378576101cb612e62565b610420526044356001600160401b038111610378576101ee903690600401612e8e565b61046052610480526064356001600160401b03811161037857610215903690600401612e8e565b6104a052610440526084356001600160401b0381116103785761023c903690600401612e8e565b6103205260a4356001600160401b0381116103785761025f903690600401612e8e565b610380526103605260c4356001600160401b03811161037857610286903690600401612e8e565b6103c0526103a05260e4356001600160401b038111610378576102ad903690600401612e8e565b610400526103e052610120516003546001600160a01b0316610340525b8061030c8261010435610400516103e0516103c0516103a0516103805161036051610320518c6104a0516104405161046051610480516024356104205161318b565b610340519091906001600160a01b038316108061036f575b610355575050600019811461033b576001016102ca565b634e487b7160e01b61012051526011600452602461012051fd5b604080519182526001600160a01b03929092166020820152f35b50813b15610324565b6101205180fd5b3461037857602036600319011261037857610398612e62565b6103a06132b3565b6001600160a01b031680156103f9576101205180546001600160a01b03198116831782556001600160a01b0316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a36101205180f35b631e4fbdf760e01b610120515261012051600452602461012051fd5b346103785760a03660031901126103785761042e612e62565b50610437612e78565b506084356001600160401b03811161037857610457903690600401612e8e565b505060405163f23a6e6160e01b8152602090f35b346103785760203660031901126103785760043560ff81168103610378576104916132b3565b6001805460ff60e01b191660e09290921b60ff60e01b169190911790556101205180f35b34610378576101205136600319011261037857602060ff60015460f01c16604051908152f35b34610378576101205136600319011261037857602062ffffff60025416604051908152f35b3461037857602036600319011261037857600435801515809103610378576105266132b3565b6006805460ff60a01b191660a09290921b60ff60a01b169190911790556101205180f35b3461037857610120513660031901126103785760206001600160401b0360015460a01c16604051908152f35b346103785761014036600319011261037857610590612e62565b6044356001600160401b038111610378576105af903690600401612e8e565b906064356001600160401b038111610378576105cf903690600401612e8e565b93906084356001600160401b038111610378576105f0903690600401612e8e565b60a4959195356001600160401b03811161037857610612903690600401612e8e565b60c4929192356001600160401b03811161037857610634903690600401612e8e565b93909260e435996001600160401b038b116103785760209b61065d6106739c3690600401612e8e565b999098610124359c610104359c6024359061318b565b6040516001600160a01b039091168152f35b346103785761012051366003190112610378576006546040516001600160a01b039091168152602090f35b346103785761012051366003190112610378576001546040516001600160a01b039091168152602090f35b346103785760a0366003190112610378576106f4612e62565b506106fd612e78565b506044356001600160401b0381116103785761071d903690600401612ebb565b50506064356001600160401b0381116103785761073e903690600401612ebb565b50506084356001600160401b0381116103785761075f903690600401612e8e565b505060405163bc197c8160e01b8152602090f35b346103785760203660031901126103785761078c612e62565b6107946132b3565b60018060a01b03166001600160601b0360a01b60065416176006556101205161012051f35b3461037857602036600319011261037857600435801515809103610378576107df6132b3565b6006805460ff60a81b191660a89290921b60ff60a81b169190911790556101205180f35b346103785760203660031901126103785761081c612e62565b6108246132b3565b600280546301000000600160b81b03191660189290921b6301000000600160b81b03169190911790556101205180f35b3461037857610120513660031901126103785760025460405160189190911c6001600160a01b03168152602090f35b3461037857610120513660031901126103785761012051546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60065460a81c166040519015158152f35b346103785761012051366003190112610378576005546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60015460e01c16604051908152f35b346103785761012051366003190112610378576109446132b3565b6101205180546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a36101205180f35b34610378576020366003190112610378576109a4612e62565b6109ac6132b3565b60018060a01b03166001600160601b0360a01b60055416176005556101205161012051f35b346103785761012051366003190112610378576004546040516001600160a01b039091168152602090f35b34610378576101205136600319011261037857602060ff60015460e81c16604051908152f35b346103785760203660031901126103785760043560ff8116810361037857610a486132b3565b6001805460ff60e81b191660e89290921b60ff60e81b169190911790556101205180f35b604036600319011261037857610a80612e62565b60405163041804f760e31b8152610120516001600160a01b0383166004830181905230602480850191909152909392903591816044816fdb40fcb9f4466330982372e27fd7bbf55afa908115610d9b576101205191610e33575b5060c08180518101031261037857604081015192610afa60608301613177565b610b1260a0610b0b60808601613177565b9401613177565b506001600160a01b0316803b1561037857604051630d9778e560e11b8152856004820152846024820152610120518160448134865af18015610d9b57610e18575b50803b156103785760405190637921219560e11b825230600483015233602483015285604483015284606483015260a060848301526101205160a48301528160c481610120519361012051905af18015610d9b57610dfd575b50610bb6906132dc565b92604051926020840152604083015283606083015260018060a01b0316608082015260808152610be760a082612f1c565b6fb24d62781db359b07880a105cd0b64e63b1561037857610c49610c5f9260405193849283926308521f2760e21b84523360048501526080602485015260046084850152631b5a5b9d60e21b60a485015260c0604485015260c48401906130f6565b82810360031901606484015261012051946130f6565b0381610120516fb24d62781db359b07880a105cd0b64e65af18015610d9b57610de2575b5034610c91575b6101205180f35b6040516324a9d85360e01b81526020816004816f1c147e48f5aad3c69e8e4d2305523c625afa908115610d9b576101205191610da9575b50610d5c610ce6612710610cdf6020943490613082565b04346130ab565b600354600254604051929562ffffff909116916001600160a01b0316610d0b84612eeb565b83528483015260408201523360608201528360808201526101205160a08201526101205160c082015260018060a01b0360065416906040519485809481936304e45aaf60e01b835260048301612f4c565b03925af18015610d9b5715610c8a575b610d8d9060203d602011610d94575b610d858183612f1c565b810190612f3d565b5080610c8a565b503d610d7b565b6040513d61012051823e3d90fd5b90506020813d602011610dda575b81610dc460209383612f1c565b81010312610dd55751610d5c610cc8565b600080fd5b3d9150610db7565b61012051610def91612f1c565b610120516103785781610c83565b61012051610e0a91612f1c565b610120516103785785610bac565b61012051610e2591612f1c565b610120516103785786610b53565b90503d8061012051833e610e478183612f1c565b8101906040818303126103785780516001600160401b03811161037857810182601f820112156103785782816020610e8193519101613140565b506020810151906001600160401b03821161037857019080601f83011215610378578151610eb192602001613140565b84610ada565b346103785761012051366003190112610378576003546040516001600160a01b039091168152602090f35b34610378576020366003190112610378576004356001600160401b038116810361037857610f0e6132b3565b6001805467ffffffffffffffff60a01b191660a09290921b67ffffffffffffffff60a01b169190911790556101205180f35b6101c036600319011261037857602435610520526105205160020b6105205103610378576064356101408190526001600160a01b038116900361037857610104356001600160401b03811161037857610f9d903690600401612e8e565b6101605261018052610124356001600160401b03811161037857610fc5903690600401612e8e565b6102a0526102c052610144356001600160401b03811161037857610fed903690600401612e8e565b60e05261054052610164356001600160401b03811161037857611014903690600401612e8e565b60c052610184356001600160401b03811161037857611037903690600401612e8e565b6104e0526104c0526101a4356001600160401b0381116103785761105f903690600401612e8e565b906102205260ff60065460a01c16612c6a5760018060a01b0360045416602062ffffff600254166024604051809481936322afcccb60e01b835260048301525afa908115610d9b576101205191612c2e575b508060020b151580612c0f575b15612bdb5760408051610140516001600160a01b031660208201908152604435928201929092526110fc81606081015b03601f198101835282612f1c565b519020604051806112cc8101106001600160401b036112cc83011117612552576112cc61340882398061116785610220516104e0516104c05160c0518b60e05161054051608435610140516004356102a0518d6102c05190610160519061018051906112cc01612fcb565b039061012051f5610500526105005115610d9b57600354610500516001600160a01b039182169116811115612ba757610120516105205160020b1215612b9b576105205160020b600160ff1b1461033b576105205160020b61012051035b620d89e891828211612b72576001821615612b60576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116612b15575b60048116612aca575b60088116612a7f575b60108116612a34575b602081166129e9575b6040811661299e575b60808116612953575b6101008116612908575b61020081166128bd575b6104008116612872575b6108008116612827575b61100081166127dc575b6120008116612791575b6140008116612746575b61800081166126fb575b6201000081166126b0575b620200008116612668575b620400008116612623575b62080000166125e4575b610120516105205160020b136125d3575b602082901c9163ffffffff166125cb5761012051905b60ff82168301831161033b576004805460025460405163a167129560e01b8152610500516001600160a01b0390811694820194909452602481019490945262ffffff16604484015261012051602092849260649284929091165af18015610d9b576101205161010052612599575b50610100516001600160a01b03163b156103785760405163f637731d60e01b815260ff919091169091016001600160a01b03908116600483015261012051610100519091839160249183918591165af18015610d9b57612586575b506003546001600160a01b0316610300526002805462ffffff169083900b1561256c576040516102e08190526001600160401b036101608201908111911117612552576101606102e0510160405260018060a01b0361050051166102e051526103005160206102e051015260406102e05101526105205160020b60606102e05101528160020b90050260020b60806102e051015260043560a06102e05101526101205160c06102e05101526101205160e06102e0510152610120516101006102e0510152306101206102e0510152426101406102e051015260018060a01b03600554166040519063095ea7b360e01b8252600482015260043560248201526020816044816101205160018060a01b0361050051165af18015610d9b57612518575b5060018060a01b03600554166102805260405161026052634418b22b60e11b610260515260018060a01b036102e0515116600461026051015260018060a01b0360206102e051015116602461026051015262ffffff60406102e051015116604461026051015260606102e051015160020b606461026051015260806102e051015160020b608461026051015260a06102e051015160a461026051015260c06102e051015160c461026051015260e06102e051015160e46102605101526101006102e051015161010461026051015260018060a01b036101206102e0510151166101246102605101526101406102e05101516101446102605101526080610260516101646102605161012051610280515af1610240526102405115610d9b576101205161020052610240516124bb575b602060018060a01b0360025460181c1660ff60018060a01b0360055416600154906040516101e052634e54db0960e01b6101e0515260046101e051015260018060a01b03610140511660246101e05101526001600160401b038160a01c1660446101e05101526102005160646101e051015260e81c1660846101e051015260a46101e051916101e0519061012051905af16101c0526101c05115610d9b57610120516101a0526101c051612481575b6005546001600160a01b0316803b1561037857604051632142170760e11b81523060048201526101a0516001600160a01b031660248201526102005160448201526101205190918290606490829084905af18015610d9b57612466575b506101a0516001600160a01b03163b15610378576040516367a4d1c360e01b8152610200516004820152610120516101a0518290602490829084906001600160a01b03165af18015610d9b5761244b575b50346122c8575b60405163b8070c7360e01b8152906020826004816fb24d62781db359b07880a105cd0b64e65afa60a05260a05115610d9b57610120519160a051612294575b506118796001600860056117b0838060a01b0361050051166132dc565b60026117be610100516132dc565b916040516080526802232b83637bcb2b2160bd1b602060805101526101605161018051602960805101376029610160516080510161040560f31b828201526102a0516102c051602b8301376102a051010164014903a37960dd1b838201526118308251809360206007850191016130d3565b010167010143837b7b61d160c51b83820152611856825180936020600d850191016130d3565b0101602960f81b82820152608051900301601e1981016080515201608051612f1c565b610500516110ee9061192e90611897906001600160a01b03166132dc565b9260405192839186602084015260018060a01b036101005116604084015260018060a01b036105005116606084015260018060a01b036101a0511660808401526102005160a084015260018060a01b03610140511660c084015260843560e084015261012061010084015261191761014084016104e0516104c051612faa565b90601f198483030161012085015261022051612faa565b6fb24d62781db359b07880a105cd0b64e63b1561037857610c4961198c9260405193849283926308521f2760e21b84523360048501526080602485015261197a608485016080516130f6565b848103600319016044860152906130f6565b0381610120516fb24d62781db359b07880a105cd0b64e65af18015610d9b57612279575b50604051633ee60bcf60e01b8152916020836004816f1c147e48f5aad3c69e8e4d2305523c625afa928315610d9b576101205193612245575b5061050051611a00906001600160a01b03166132dc565b60e05115611f7657611a1360e0516130b8565b611a206040519182612f1c565b60e05181523660e051610540510111610378576013611bae92600b6002956004879560e05161054051602083013761012051602060e051830101525b6047604051998a96683d913730b6b2911d1160b91b6020890152610160516101805160298a0137602961016051890161040560f31b828201526102a0516102c051602b8301376102a0510101602960f81b838201527f222c226465736372697074696f6e223a224d656d65636f696e2d4e465420637260038201527f656174656420766961204e65742e204d656d65636f696e206973206c6f636174602382015265032b21030ba160d51b6043820152611b208251809360206049850191016130d3565b0101632e372e3760e11b828201526104e0516104c051604b8301376104e05101016a11161134b6b0b3b2911d1160a91b83820152611b68825180936020600f850191016130d3565b0101907211161130b734b6b0ba34b7b72fbab936111d1160691b8383015260c05190601e83013760c051010161227d60f01b838201520301601d19810184520182612f1c565b6f1c147e48f5aad3c69e8e4d2305523c623b156103785760405190630dd2f7a160e41b825260a435600483015260e435602483015260c435604483015261012051606483015260a060848301528180611c0f610120519360a48301906130f6565b0381610120516f1c147e48f5aad3c69e8e4d2305523c625af18015610d9b57611f5b575b506f1c147e48f5aad3c69e8e4d2305523c623b1561037857604051637921219560e11b8152306004820152610140516001600160a01b03166024820152604481018390526001606482015260a06084820152610120805160a4830152518160c481836f1c147e48f5aad3c69e8e4d2305523c625af18015610d9b57611f40575b5060408051602081019290925281018290526f1c147e48f5aad3c69e8e4d2305523c626060820152610100516001600160a01b0390811660808301526101a0511660a08201526102005160c0808301919091528152611d1360e082612f1c565b6fdb40fcb9f4466330982372e27fd7bbf53b15610378576040519063f9ed11d960e01b82528180611d57610120519360018060a01b0361050051166004840161311b565b0381610120516fdb40fcb9f4466330982372e27fd7bbf55af18015610d9b57611f25575b506040519080602083015260018060a01b036105005116604083015260018060a01b036101005116606083015260608252611db7608083612f1c565b6fdb40fcb9f4466330982372e27fd7bbf53b1561037857611df1916040518093819263f9ed11d960e01b835261012051946004840161311b565b0381610120516fdb40fcb9f4466330982372e27fd7bbf55af18015610d9b57611f0a575b7f7c8762543264172a17e130518fcc375c045781639d522d793332fc5c76a5ffe560018060a01b036101205154163314604051809160018060a01b036105005116825261020051602083015260018060a01b036101405116604083015260843560608301526101406080830152611ee2611eb2611e9d61014085016101605161018051612faa565b84810360a08601526102a0516102c051612faa565b60043560c08501526101a0516001600160a01b031660e08501528381036101008501526104e0516104c051612faa565b906101208301520390a160408051610500516001600160a01b03168152610200516020820152f35b61012051611f1791612f1c565b610120516103785780611e15565b61012051611f3291612f1c565b610120516103785781611d7b565b61012051611f4d91612f1c565b610120516103785782611cb3565b61012051611f6891612f1c565b610120516103785782611c33565b6040517f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323060208201527f30302f737667222077696474683d2235303022206865696768743d223530302260408201527f207374796c653d226261636b67726f756e642d636f6c6f723a23303030223e3c60608201527f7465787420783d223530252220793d223530252220746578742d616e63686f7260808201527f3d226d6964646c652220646f6d696e616e742d626173656c696e653d226d696460a08201527f646c6522207374796c653d22666f6e742d66616d696c793a6d6f6e6f7370616360c08201527f653b666f6e742d73697a653a323470783b66696c6c3a23306637223e0000000060e0820152610160516101805160fc8301376120c3600d60fc836101605181016c1e17ba32bc3a1f1e17b9bb339f60991b838201520301601219810184520182612f1c565b8051606091808261213a575b5050506013611bae92600b60029560048795612135603a60405180937f646174613a696d6167652f7376672b786d6c3b6261736536342c000000000000602083015261212481518092602086860191016130d3565b81010301601f198101835282612f1c565b611a5c565b9193909250604051937f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106707f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f526020850160046003602084870101519661012051602086890101525b0191603f8351818160121c165161012051538181600c1c1651600153818160061c1651600253165160035361012051518152019060206003600285010460021b880101821015612200576004906003906121ab565b509281016020019390935260036002848101829004811b80870160409081019052613d3d60f01b9290950690048303526101205190915290825290601382600b6120cf565b9092506020813d602011612271575b8161226160209383612f1c565b81010312610dd5575191836119e9565b3d9150612254565b6101205161228691612f1c565b6101205161037857826119b0565b9091506020813d6020116122c0575b816122b060209383612f1c565b81010312610dd557519083611793565b3d91506122a3565b3460ff60065460a81c16612397575b6003546002546040516020926123639262ffffff16906001600160a01b03166122ff83612eeb565b8252610500516001600160a01b0390811685840152604080840192909252610140518116606084015260808301869052610120805160a08501525160c084015260065491516304e45aaf60e01b815295869492909116928492839160048301612f4c565b03925af18015610d9b57612378575b50611754565b6123909060203d602011610d9457610d858183612f1c565b5082612372565b506001546103e86123ae60ff8360e01c1634613082565b046123b981346130ab565b61012051909290918291829182916001600160a01b03165af13d15612446573d6123e2816130b8565b906123f06040519283612f1c565b8152610120513d916020013e5b6122d75760405162461bcd60e51b815260206004820152601c60248201527f4661696c656420746f2073656e642070726f746f636f6c2066656573000000006044820152606490fd5b6123fd565b6101205161245891612f1c565b61012051610378578261174d565b6101205161247391612f1c565b6101205161037857826116fc565b60203d6020116124b4575b8061249d6124ab926101e051612f1c565b6101e051016101e051613063565b6101a05261169f565b503d61248c565b60803d608011612511575b806124d660809261026051612f1c565b61026051908101031261037857610260515160206102605101516fffffffffffffffffffffffffffffffff81160361037857610200526115f0565b503d6124c6565b6020813d60201161254a575b8161253160209383612f1c565b81010312610378575180151581146114c1576101205180fd5b3d9150612524565b634e487b7160e01b61012051526041600452602461012051fd5b634e487b7160e01b61012051526012600452602461012051fd5b6101205161259391612f1c565b846113a0565b6125ba9060203d6020116125c4575b6125b28183612f1c565b810190613063565b6101005286611345565b503d6125a8565b6001906112d7565b90801561256c5760001904906112c1565b90806b048a170391f7dc42444e8fa28102046b048a170391f7dc42444e8fa2148115171561033b576b048a170391f7dc42444e8fa20260801c906112b0565b91806d2216e584f5fa1ea926041bedfe988102046d2216e584f5fa1ea926041bedfe98148115171561033b576d2216e584f5fa1ea926041bedfe980260801c916112a6565b91806e5d6af8dedb81196699c329225ee6048102046e5d6af8dedb81196699c329225ee604148115171561033b576e5d6af8dedb81196699c329225ee6040260801c9161129b565b91806f09aa508b5b7a84e1c677de54f3e99bc98102046f09aa508b5b7a84e1c677de54f3e99bc9148115171561033b576f09aa508b5b7a84e1c677de54f3e99bc90260801c91611290565b91806f31be135f97d08fd981231505542fcfa68102046f31be135f97d08fd981231505542fcfa6148115171561033b576f31be135f97d08fd981231505542fcfa60260801c91611285565b91806f70d869a156d2a1b890bb3df62baf32f78102046f70d869a156d2a1b890bb3df62baf32f7148115171561033b576f70d869a156d2a1b890bb3df62baf32f70260801c9161127b565b91806fa9f746462d870fdf8a65dc1f90e061e58102046fa9f746462d870fdf8a65dc1f90e061e5148115171561033b576fa9f746462d870fdf8a65dc1f90e061e50260801c91611271565b91806fd097f3bdfd2022b8845ad8f792aa58258102046fd097f3bdfd2022b8845ad8f792aa5825148115171561033b576fd097f3bdfd2022b8845ad8f792aa58250260801c91611267565b91806fe7159475a2c29b7443b29c7fa6e889d98102046fe7159475a2c29b7443b29c7fa6e889d9148115171561033b576fe7159475a2c29b7443b29c7fa6e889d90260801c9161125d565b91806ff3392b0822b70005940c7a398e4b70f38102046ff3392b0822b70005940c7a398e4b70f3148115171561033b576ff3392b0822b70005940c7a398e4b70f30260801c91611253565b91806ff987a7253ac413176f2b074cf7815e548102046ff987a7253ac413176f2b074cf7815e54148115171561033b576ff987a7253ac413176f2b074cf7815e540260801c91611249565b91806ffcbe86c7900a88aedcffc83b479aa3a48102046ffcbe86c7900a88aedcffc83b479aa3a4148115171561033b576ffcbe86c7900a88aedcffc83b479aa3a40260801c9161123f565b91806ffe5dee046a99a2a811c461f1969c30538102046ffe5dee046a99a2a811c461f1969c3053148115171561033b576ffe5dee046a99a2a811c461f1969c30530260801c91611235565b91806fff2ea16466c96a3843ec78b326b528618102046fff2ea16466c96a3843ec78b326b52861148115171561033b576fff2ea16466c96a3843ec78b326b528610260801c9161122c565b91806fff973b41fa98c081472e6896dfb254c08102046fff973b41fa98c081472e6896dfb254c0148115171561033b576fff973b41fa98c081472e6896dfb254c00260801c91611223565b91806fffcb9843d60f6159c9db58835c9266448102046fffcb9843d60f6159c9db58835c926644148115171561033b576fffcb9843d60f6159c9db58835c9266440260801c9161121a565b91806fffe5caca7e10e4e61c3624eaa0941cd08102046fffe5caca7e10e4e61c3624eaa0941cd0148115171561033b576fffe5caca7e10e4e61c3624eaa0941cd00260801c91611211565b91806ffff2e50f5f656932ef12357cf3c7fdcc8102046ffff2e50f5f656932ef12357cf3c7fdcc148115171561033b576ffff2e50f5f656932ef12357cf3c7fdcc0260801c91611208565b91806ffff97272373d413259a46990580e213a8102046ffff97272373d413259a46990580e213a148115171561033b576ffff97272373d413259a46990580e213a0260801c916111ff565b6001600160881b03600160801b6111f4565b60405162461bcd60e51b81526020600482015260016024820152601560fa1b6044820152606490fd5b6105205160020b6111c5565b60405162461bcd60e51b815260206004820152600c60248201526b125b9d985b1a59081cd85b1d60a21b6044820152606490fd5b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964207469636b60a01b6044820152606490fd5b508060020b1561256c578060020b6105205160020b0760020b156110be565b90506020813d602011612c62575b81612c4960209383612f1c565b8101031261037857518060020b810361037857836110b1565b3d9150612c3c565b6331cee75f60e21b6101205152600461012051fd5b3461037857602036600319011261037857612c98612e62565b612ca06132b3565b60018060a01b03166001600160601b0360a01b60045416176004556101205161012051f35b3461037857602036600319011261037857612cde612e62565b612ce66132b3565b60018060a01b03166001600160601b0360a01b60035416176003556101205161012051f35b3461037857602036600319011261037857612d24612e62565b612d2c6132b3565b60018060a01b03166001600160601b0360a01b60015416176001556101205161012051f35b604036600319011261037857612d65612e62565b60243562ffffff811680910361037857600354604051612ded9360209391926001600160a01b0316612d9684612eeb565b835260018060a01b03168383015260408201523360608201523460808201526101205160a08201526101205160c082015260018060a01b036006541660405180809581946304e45aaf60e01b835260048301612f4c565b039134905af18015610d9b57610d6c576101205180f35b34610378576101205136600319011261037857602060ff60065460a01c166040519015158152f35b34610378576020366003190112610378576004359063ffffffff60e01b821680920361037857602091630271189760e51b148152f35b600435906001600160a01b0382168203610dd557565b602435906001600160a01b0382168203610dd557565b9181601f84011215610dd5578235916001600160401b038311610dd55760208381860195010111610dd557565b9181601f84011215610dd5578235916001600160401b038311610dd5576020808501948460051b010111610dd557565b60e081019081106001600160401b03821117612f0657604052565b634e487b7160e01b600052604160045260246000fd5b90601f801991011681019081106001600160401b03821117612f0657604052565b90816020910312610dd5575190565b81516001600160a01b03908116825260208084015182169083015260408084015162ffffff16908301526060808401518216908301526080808401519083015260a0808401519083015260c092830151169181019190915260e00190565b908060209392818452848401376000828201840152601f01601f1916010190565b9d9b9996906130609f9d99938f90976130106130519e9961303599986130026080966130439f996101208852610120880191612faa565b918583036020870152612faa565b60408301979097526001600160a01b0316606082015201528c830360a08e0152612faa565b9189830360c08b0152612faa565b9186830360e0880152612faa565b92610100818503910152612faa565b90565b90816020910312610dd557516001600160a01b0381168103610dd55790565b8181029291811591840414171561309557565b634e487b7160e01b600052601160045260246000fd5b9190820391821161309557565b6001600160401b038111612f0657601f01601f191660200190565b60005b8381106130e65750506000910152565b81810151838201526020016130d6565b9060209161310f815180928185528580860191016130d3565b601f01601f1916010190565b60809061306093928152606060208201526000606082015281604082015201906130f6565b9092919261314d816130b8565b9161315b6040519384612f1c565b829482845282820111610dd55760206131759301906130d3565b565b51906001600160a01b0382168203610dd557565b90919a97949d9e9c9996939c9b9895929b6040518060208101926131c590858560209093929193604081019460018060a01b031681520152565b03601f19810182526131d79082612f1c565b5190209e6040519e8f6112cc6020016131f09082612f1c565b6112cc81526112cc9061340890602001396040519e8f9e8f6020019e6132159f612fcb565b03601f19810182526132279082612f1c565b60405180916020820193848151602081930191613243926130d3565b82018151918260208301916020019161325b926130d3565b010380825261326d9060200182612f1c565b5190209060405191602083019160ff60f81b83523060601b602185015260358401526055830152605582526132a3607583612f1c565b905190206001600160a01b031690565b6000546001600160a01b031633036132c757565b63118cdaa760e01b6000523360045260246000fd5b9060405191608083016040526f30313233343536373839616263646566600f526002830190602882526000604a85015260601b600160005b8080018601602284831a600f811651602384015360041c519101530190601482146133425790600190613314565b50506130786002825101915282528160228101907f88888888888888888888888888888888888888888888888888888888888888806028832016600160005b601160f31b83821a02818001520190601482146133a15790600190613381565b505060429180517f2020202020202020202020202020202020202020202020202020202020202020816000511660011c161890520180517f2020202020202020202020202020202020202020202020202020202020202020816020511660011c1618905256fe60806040523461085b576112cc8038038061001981610860565b9283398101906101208183031261085b5780516001600160401b03811161085b57826100469183016108df565b60208201516001600160401b03811161085b57836100659184016108df565b604083015160608401519091906001600160a01b0381169081900361085b57608085015160a08601519091906001600160401b03811161085b57876100ab9188016108df565b60c08701519093906001600160401b03811161085b57886100cd9189016108df565b60e08801519098906001600160401b03811161085b57816100ef918a016108df565b61010089015190986001600160401b03821161085b57019080601f8301121561085b57815161012092602001610885565b865190966001600160401b0382116104b15761013d6003546108fc565b601f811161080c575b50602090601f83116001146107a3576101789291600091836103e7575b50508160011b916000199060031b1c19161790565b6003555b8051906001600160401b0382116104b1576101986004546108fc565b601f8111610754575b50602090601f83116001146106eb576101d29291600091836103e75750508160011b916000199060031b1c19161790565b6004555b600580546001600160a01b0319169190911790556006558051906001600160401b0382116104b1576102096007546108fc565b601f811161069c575b50602090601f8311600114610633576102439291600091836103e75750508160011b916000199060031b1c19161790565b6007555b83516001600160401b0381116104b1576102626008546108fc565b601f81116105e4575b50602094601f821160011461057d5761029f9293949582916000926103e75750508160011b916000199060031b1c19161790565b6008555b82516001600160401b0381116104b1576102be6009546108fc565b601f811161052e575b506020601f82116001146104c75781906102f99394956000926103e75750508160011b916000199060031b1c19161790565b6009555b81516001600160401b0381116104b157610318600a546108fc565b601f8111610457575b50602092601f82116001146103f257610353929382916000926103e75750508160011b916000199060031b1c19161790565b600a555b33156103d1576002548181018091116103bb57600255600033815280602052604081208281540190556040519182527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203393a360405161097e908161094e8239f35b634e487b7160e01b600052601160045260246000fd5b63ec442f0560e01b600052600060045260246000fd5b015190503880610163565b601f19821693600a600052806000209160005b86811061043f5750836001959610610426575b505050811b01600a55610357565b015160001960f88460031b161c19169055388080610418565b91926020600181928685015181550194019201610405565b600a6000526104a1907fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601f840160051c810191602085106104a7575b601f0160051c0190610936565b38610321565b9091508190610494565b634e487b7160e01b600052604160045260246000fd5b601f198216906009600052806000209160005b818110610516575095836001959697106104fd575b505050811b016009556102fd565b015160001960f88460031b161c191690553880806104ef565b9192602060018192868b0151815501940192016104da565b6009600052610577907f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af601f840160051c810191602085106104a757601f0160051c0190610936565b386102c7565b601f198216956008600052806000209160005b8881106105cc575083600195969798106105b3575b505050811b016008556102a3565b015160001960f88460031b161c191690553880806105a5565b91926020600181928685015181550194019201610590565b600860005261062d907ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3601f840160051c810191602085106104a757601f0160051c0190610936565b3861026b565b90601f198316916007600052816000209260005b818110610684575090846001959493921061066b575b505050811b01600755610247565b015160001960f88460031b161c1916905538808061065d565b92936020600181928786015181550195019301610647565b60076000526106e5907fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688601f850160051c810191602086106104a757601f0160051c0190610936565b38610212565b90601f198316916004600052816000209260005b81811061073c5750908460019594939210610723575b505050811b016004556101d6565b015160001960f88460031b161c19169055388080610715565b929360206001819287860151815501950193016106ff565b600460005261079d907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f850160051c810191602086106104a757601f0160051c0190610936565b386101a1565b90601f198316916003600052816000209260005b8181106107f457509084600195949392106107db575b505050811b0160035561017c565b015160001960f88460031b161c191690553880806107cd565b929360206001819287860151815501950193016107b7565b6003600052610855907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f850160051c810191602086106104a757601f0160051c0190610936565b38610146565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176104b157604052565b9192916001600160401b0382116104b1576108a9601f8301601f1916602001610860565b938285528282011161085b5760005b8281106108cc575050602060009184010152565b80602091830151828288010152016108b8565b9080601f8301121561085b5781516108f992602001610885565b90565b90600182811c9216801561092c575b602083101461091657565b634e487b7160e01b600052602260045260246000fd5b91607f169161090b565b818110610941575050565b6000815560010161093656fe6080604052600436101561001257600080fd5b60003560e01c806306fdde03146106fc578063095ea7b31461067657806318160ddd1461065857806323b872dd1461056b578063313ce5671461054f5780633257b4f31461053157806370a08231146104f75780638c662b7f1461044f57806395d89b41146103a7578063977fb1cc146102ff578063a9059cbb146102ce578063d5f39488146102a5578063dd62ed3e14610254578063e8a5edce146101ab5763f3ccaac0146100c157600080fd5b346101a65760003660031901126101a65760405160006007546100e381610811565b80845290600181169081156101825750600114610123575b61011f8361010b8185038261084b565b6040519182916020835260208301906107a4565b0390f35b600760009081527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688939250905b8082106101685750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610150565b60ff191660208086019190915291151560051b8401909101915061010b90506100fb565b600080fd5b346101a65760003660031901126101a6576040516000600a546101cd81610811565b808452906001811690811561018257506001146101f45761011f8361010b8185038261084b565b919050600a6000527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8916000905b80821061023a5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610222565b346101a65760403660031901126101a65761026d6107e5565b6102756107fb565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b346101a65760003660031901126101a6576005546040516001600160a01b039091168152602090f35b346101a65760403660031901126101a6576102f46102ea6107e5565b6024359033610883565b602060405160018152f35b346101a65760003660031901126101a657604051600060085461032181610811565b808452906001811690811561018257506001146103485761011f8361010b8185038261084b565b600860009081527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3939250905b80821061038d5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610375565b346101a65760003660031901126101a65760405160006004546103c981610811565b808452906001811690811561018257506001146103f05761011f8361010b8185038261084b565b600460009081527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b939250905b8082106104355750909150810160200161010b6100fb565b91926001816020925483858801015201910190929161041d565b346101a65760003660031901126101a657604051600060095461047181610811565b808452906001811690811561018257506001146104985761011f8361010b8185038261084b565b600960009081527f6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af939250905b8082106104dd5750909150810160200161010b6100fb565b9192600181602092548385880101520191019092916104c5565b346101a65760203660031901126101a6576001600160a01b036105186107e5565b1660005260006020526020604060002054604051908152f35b346101a65760003660031901126101a6576020600654604051908152f35b346101a65760003660031901126101a657602060405160128152f35b346101a65760603660031901126101a6576105846107e5565b61058c6107fb565b6001600160a01b03821660008181526001602081815260408084203385529091529091205491936044359392909181016105cc575b506102f49350610883565b83811061063b57841561062557331561060f576102f4946000526001602052604060002060018060a01b03331660005260205283604060002091039055846105c1565b634a1406b160e11b600052600060045260246000fd5b63e602df0560e01b600052600060045260246000fd5b8390637dc7a0d960e11b6000523360045260245260445260646000fd5b346101a65760003660031901126101a6576020600254604051908152f35b346101a65760403660031901126101a65761068f6107e5565b602435903315610625576001600160a01b031690811561060f57336000526001602052604060002082600052602052806040600020556040519081527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560203392a3602060405160018152f35b346101a65760003660031901126101a657604051600060035461071e81610811565b808452906001811690811561018257506001146107455761011f8361010b8185038261084b565b600360009081527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b939250905b80821061078a5750909150810160200161010b6100fb565b919260018160209254838588010152019101909291610772565b919082519283825260005b8481106107d0575050826000602080949584010152601f8019910116010190565b806020809284010151828286010152016107af565b600435906001600160a01b03821682036101a657565b602435906001600160a01b03821682036101a657565b90600182811c92168015610841575b602083101461082b57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610820565b90601f8019910116810190811067ffffffffffffffff82111761086d57604052565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0316908115610932576001600160a01b031691821561091c5760008281528060205260408120548281106109025791604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815280845220818154019055604051908152a3565b916064928463391434e360e21b8452600452602452604452fd5b63ec442f0560e01b600052600060045260246000fd5b634b637e8f60e11b600052600060045260246000fdfea26469706673582212206c58257e9404c1e2494d4f719acb3b836cb49a49d92f4b5610d7074fbe24923364736f6c634300081a0033a264697066735822122041824f4abf3181b8b2a5453c96c8b2b4ad717e33543abb9ddf31ec180a02e07d64736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.