编译器
0.8.26+commit.8a97fa7a
文件 1 的 19:ERC20.sol
pragma solidity ^0.8.4;
abstract contract ERC20 {
error TotalSupplyOverflow();
error AllowanceOverflow();
error AllowanceUnderflow();
error InsufficientBalance();
error InsufficientAllowance();
error InvalidPermit();
error PermitExpired();
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
uint256 private constant _TOTAL_SUPPLY_SLOT = 0x05345cdf77eb68f44c;
uint256 private constant _BALANCE_SLOT_SEED = 0x87a211a2;
uint256 private constant _ALLOWANCE_SLOT_SEED = 0x7f5e9f20;
uint256 private constant _NONCES_SLOT_SEED = 0x38377508;
uint256 private constant _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX = 0x383775081901;
bytes32 private constant _DOMAIN_TYPEHASH =
0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f;
bytes32 private constant _VERSION_HASH =
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6;
bytes32 private constant _PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
function name() public view virtual returns (string memory);
function symbol() public view virtual returns (string memory);
function decimals() public view virtual returns (uint8) {
return 18;
}
function totalSupply() public view virtual returns (uint256 result) {
assembly {
result := sload(_TOTAL_SUPPLY_SLOT)
}
}
function balanceOf(address owner) public view virtual returns (uint256 result) {
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
function allowance(address owner, address spender)
public
view
virtual
returns (uint256 result)
{
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x34))
}
}
function approve(address spender, uint256 amount) public virtual returns (bool) {
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x34), amount)
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, caller(), shr(96, mload(0x2c)))
}
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(msg.sender, to, amount);
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, caller())
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8)
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, caller(), shr(96, mload(0x0c)))
}
_afterTokenTransfer(msg.sender, to, amount);
return true;
}
function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
_beforeTokenTransfer(from, to, amount);
assembly {
let from_ := shl(96, from)
mstore(0x20, caller())
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED))
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
if add(allowance_, 1) {
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b)
revert(0x1c, 0x04)
}
sstore(allowanceSlot, sub(allowance_, amount))
}
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8)
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
return true;
}
function _constantNameHash() internal view virtual returns (bytes32 result) {}
function nonces(address owner) public view virtual returns (uint256 result) {
assembly {
mstore(0x0c, _NONCES_SLOT_SEED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x20))
}
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
bytes32 nameHash = _constantNameHash();
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
assembly {
if gt(timestamp(), deadline) {
mstore(0x00, 0x1a15a3cc)
revert(0x1c, 0x04)
}
let m := mload(0x40)
owner := shr(96, shl(96, owner))
spender := shr(96, shl(96, spender))
mstore(0x0e, _NONCES_SLOT_SEED_WITH_SIGNATURE_PREFIX)
mstore(0x00, owner)
let nonceSlot := keccak256(0x0c, 0x20)
let nonceValue := sload(nonceSlot)
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
mstore(0x2e, keccak256(m, 0xa0))
mstore(m, _PERMIT_TYPEHASH)
mstore(add(m, 0x20), owner)
mstore(add(m, 0x40), spender)
mstore(add(m, 0x60), value)
mstore(add(m, 0x80), nonceValue)
mstore(add(m, 0xa0), deadline)
mstore(0x4e, keccak256(m, 0xc0))
mstore(0x00, keccak256(0x2c, 0x42))
mstore(0x20, and(0xff, v))
mstore(0x40, r)
mstore(0x60, s)
let t := staticcall(gas(), 1, 0, 0x80, 0x20, 0x20)
if iszero(eq(mload(returndatasize()), owner)) {
mstore(0x00, 0xddafbaef)
revert(0x1c, 0x04)
}
sstore(nonceSlot, add(nonceValue, t))
mstore(0x40, or(shl(160, _ALLOWANCE_SLOT_SEED), spender))
sstore(keccak256(0x2c, 0x34), value)
log3(add(m, 0x60), 0x20, _APPROVAL_EVENT_SIGNATURE, owner, spender)
mstore(0x40, m)
mstore(0x60, 0)
}
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32 result) {
bytes32 nameHash = _constantNameHash();
if (nameHash == bytes32(0)) nameHash = keccak256(bytes(name()));
assembly {
let m := mload(0x40)
mstore(m, _DOMAIN_TYPEHASH)
mstore(add(m, 0x20), nameHash)
mstore(add(m, 0x40), _VERSION_HASH)
mstore(add(m, 0x60), chainid())
mstore(add(m, 0x80), address())
result := keccak256(m, 0xa0)
}
}
function _mint(address to, uint256 amount) internal virtual {
_beforeTokenTransfer(address(0), to, amount);
assembly {
let totalSupplyBefore := sload(_TOTAL_SUPPLY_SLOT)
let totalSupplyAfter := add(totalSupplyBefore, amount)
if lt(totalSupplyAfter, totalSupplyBefore) {
mstore(0x00, 0xe5cfe957)
revert(0x1c, 0x04)
}
sstore(_TOTAL_SUPPLY_SLOT, totalSupplyAfter)
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, 0, shr(96, mload(0x0c)))
}
_afterTokenTransfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
_beforeTokenTransfer(from, address(0), amount);
assembly {
mstore(0x0c, _BALANCE_SLOT_SEED)
mstore(0x00, from)
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8)
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
sstore(_TOTAL_SUPPLY_SLOT, sub(sload(_TOTAL_SUPPLY_SLOT), amount))
mstore(0x00, amount)
log3(0x00, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, shl(96, from)), 0)
}
_afterTokenTransfer(from, address(0), amount);
}
function _transfer(address from, address to, uint256 amount) internal virtual {
_beforeTokenTransfer(from, to, amount);
assembly {
let from_ := shl(96, from)
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
let fromBalanceSlot := keccak256(0x0c, 0x20)
let fromBalance := sload(fromBalanceSlot)
if gt(amount, fromBalance) {
mstore(0x00, 0xf4d678b8)
revert(0x1c, 0x04)
}
sstore(fromBalanceSlot, sub(fromBalance, amount))
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x20)
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
mstore(0x20, amount)
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))
}
_afterTokenTransfer(from, to, amount);
}
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
assembly {
mstore(0x20, spender)
mstore(0x0c, _ALLOWANCE_SLOT_SEED)
mstore(0x00, owner)
let allowanceSlot := keccak256(0x0c, 0x34)
let allowance_ := sload(allowanceSlot)
if add(allowance_, 1) {
if gt(amount, allowance_) {
mstore(0x00, 0x13be252b)
revert(0x1c, 0x04)
}
sstore(allowanceSlot, sub(allowance_, amount))
}
}
}
function _approve(address owner, address spender, uint256 amount) internal virtual {
assembly {
let owner_ := shl(96, owner)
mstore(0x20, spender)
mstore(0x0c, or(owner_, _ALLOWANCE_SLOT_SEED))
sstore(keccak256(0x0c, 0x34), amount)
mstore(0x00, amount)
log3(0x00, 0x20, _APPROVAL_EVENT_SIGNATURE, shr(96, owner_), shr(96, mload(0x2c)))
}
}
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}
文件 2 的 19:ERC721.sol
pragma solidity ^0.8.4;
abstract contract ERC721 {
uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;
error NotOwnerNorApproved();
error TokenDoesNotExist();
error TokenAlreadyExists();
error BalanceQueryForZeroAddress();
error TransferToZeroAddress();
error TransferFromIncorrectOwner();
error AccountBalanceOverflow();
error TransferToNonERC721ReceiverImplementer();
event Transfer(address indexed from, address indexed to, uint256 indexed id);
event Approval(address indexed owner, address indexed account, uint256 indexed id);
event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;
uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;
function name() public view virtual returns (string memory);
function symbol() public view virtual returns (string memory);
function tokenURI(uint256 id) public view virtual returns (string memory);
function ownerOf(uint256 id) public view virtual returns (address result) {
result = _ownerOf(id);
assembly {
if iszero(result) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
}
}
function balanceOf(address owner) public view virtual returns (uint256 result) {
assembly {
if iszero(owner) {
mstore(0x00, 0x8f4eb604)
revert(0x1c, 0x04)
}
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
}
}
function getApproved(uint256 id) public view virtual returns (address result) {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
if iszero(shl(96, sload(ownershipSlot))) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
result := sload(add(1, ownershipSlot))
}
}
function approve(address account, uint256 id) public payable virtual {
_approve(msg.sender, account, id);
}
function isApprovedForAll(address owner, address operator)
public
view
virtual
returns (bool result)
{
assembly {
mstore(0x1c, operator)
mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x30))
}
}
function setApprovalForAll(address operator, bool isApproved) public virtual {
assembly {
isApproved := iszero(iszero(isApproved))
mstore(0x1c, operator)
mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x30), isApproved)
mstore(0x00, isApproved)
log3(
0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))
)
}
}
function transferFrom(address from, address to, uint256 id) public payable virtual {
_beforeTokenTransfer(from, to, id);
assembly {
let bitmaskAddress := shr(96, not(0))
from := and(bitmaskAddress, from)
to := and(bitmaskAddress, to)
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
let owner := and(bitmaskAddress, ownershipPacked)
if iszero(mul(owner, eq(owner, from))) {
if iszero(owner) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
mstore(0x00, 0xa1148100)
revert(0x1c, 0x04)
}
if iszero(to) {
mstore(0x00, 0xea553b34)
revert(0x1c, 0x04)
}
{
mstore(0x00, from)
let approvedAddress := sload(add(1, ownershipSlot))
if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18)
revert(0x1c, 0x04)
}
}
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
{
let fromBalanceSlot := keccak256(0x0c, 0x1c)
sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
}
{
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x1c)
let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
mstore(0x00, 0x01336cea)
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceSlotPacked)
}
log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
}
_afterTokenTransfer(from, to, id);
}
function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
}
function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
public
payable
virtual
{
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
assembly {
let s := shr(224, interfaceId)
result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
}
}
function _exists(uint256 id) internal view virtual returns (bool result) {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))))
}
}
function _ownerOf(uint256 id) internal view virtual returns (address result) {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
}
}
function _getAux(address owner) internal view virtual returns (uint224 result) {
assembly {
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
result := shr(32, sload(keccak256(0x0c, 0x1c)))
}
}
function _setAux(address owner, uint224 value) internal virtual {
assembly {
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
let balanceSlot := keccak256(0x0c, 0x1c)
let packed := sload(balanceSlot)
sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
}
}
function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
}
}
function _setExtraData(uint256 id, uint96 value) internal virtual {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let packed := sload(ownershipSlot)
sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
}
}
function _mint(address to, uint256 id) internal virtual {
_beforeTokenTransfer(address(0), to, id);
assembly {
to := shr(96, shl(96, to))
if iszero(to) {
mstore(0x00, 0xea553b34)
revert(0x1c, 0x04)
}
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
if shl(96, ownershipPacked) {
mstore(0x00, 0xc991cbb1)
revert(0x1c, 0x04)
}
sstore(ownershipSlot, or(ownershipPacked, to))
{
mstore(0x00, to)
let balanceSlot := keccak256(0x0c, 0x1c)
let balanceSlotPacked := add(sload(balanceSlot), 1)
if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
mstore(0x00, 0x01336cea)
revert(0x1c, 0x04)
}
sstore(balanceSlot, balanceSlotPacked)
}
log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
}
_afterTokenTransfer(address(0), to, id);
}
function _safeMint(address to, uint256 id) internal virtual {
_safeMint(to, id, "");
}
function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
_mint(to, id);
if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
}
function _burn(uint256 id) internal virtual {
_burn(address(0), id);
}
function _burn(address by, uint256 id) internal virtual {
address owner = ownerOf(id);
_beforeTokenTransfer(owner, address(0), id);
assembly {
by := shr(96, shl(96, by))
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
owner := shr(96, shl(96, ownershipPacked))
if iszero(owner) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
{
mstore(0x00, owner)
let approvedAddress := sload(add(1, ownershipSlot))
if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18)
revert(0x1c, 0x04)
}
}
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
sstore(ownershipSlot, xor(ownershipPacked, owner))
{
let balanceSlot := keccak256(0x0c, 0x1c)
sstore(balanceSlot, sub(sload(balanceSlot), 1))
}
log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
}
_afterTokenTransfer(owner, address(0), id);
}
function _isApprovedOrOwner(address account, uint256 id)
internal
view
virtual
returns (bool result)
{
assembly {
result := 1
account := shr(96, shl(96, account))
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let owner := shr(96, shl(96, sload(ownershipSlot)))
if iszero(owner) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
if iszero(eq(account, owner)) {
mstore(0x00, owner)
if iszero(sload(keccak256(0x0c, 0x30))) {
result := eq(account, sload(add(1, ownershipSlot)))
}
}
}
}
function _getApproved(uint256 id) internal view virtual returns (address result) {
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
}
}
function _approve(address account, uint256 id) internal virtual {
_approve(address(0), account, id);
}
function _approve(address by, address account, uint256 id) internal virtual {
assembly {
let bitmaskAddress := shr(96, not(0))
account := and(bitmaskAddress, account)
by := and(bitmaskAddress, by)
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let owner := and(bitmaskAddress, sload(ownershipSlot))
if iszero(owner) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
if iszero(or(iszero(by), eq(by, owner))) {
mstore(0x00, owner)
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18)
revert(0x1c, 0x04)
}
}
sstore(add(1, ownershipSlot), account)
log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
}
}
function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
assembly {
by := shr(96, shl(96, by))
operator := shr(96, shl(96, operator))
isApproved := iszero(iszero(isApproved))
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
mstore(0x00, by)
sstore(keccak256(0x0c, 0x30), isApproved)
mstore(0x00, isApproved)
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator)
}
}
function _transfer(address from, address to, uint256 id) internal virtual {
_transfer(address(0), from, to, id);
}
function _transfer(address by, address from, address to, uint256 id) internal virtual {
_beforeTokenTransfer(from, to, id);
assembly {
let bitmaskAddress := shr(96, not(0))
from := and(bitmaskAddress, from)
to := and(bitmaskAddress, to)
by := and(bitmaskAddress, by)
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
let owner := and(bitmaskAddress, ownershipPacked)
if iszero(mul(owner, eq(owner, from))) {
if iszero(owner) {
mstore(0x00, 0xceea21b6)
revert(0x1c, 0x04)
}
mstore(0x00, 0xa1148100)
revert(0x1c, 0x04)
}
if iszero(to) {
mstore(0x00, 0xea553b34)
revert(0x1c, 0x04)
}
{
mstore(0x00, from)
let approvedAddress := sload(add(1, ownershipSlot))
if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18)
revert(0x1c, 0x04)
}
}
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
{
let fromBalanceSlot := keccak256(0x0c, 0x1c)
sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
}
{
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x1c)
let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
mstore(0x00, 0x01336cea)
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceSlotPacked)
}
log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
}
_afterTokenTransfer(from, to, id);
}
function _safeTransfer(address from, address to, uint256 id) internal virtual {
_safeTransfer(from, to, id, "");
}
function _safeTransfer(address from, address to, uint256 id, bytes memory data)
internal
virtual
{
_transfer(address(0), from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
function _safeTransfer(address by, address from, address to, uint256 id) internal virtual {
_safeTransfer(by, from, to, id, "");
}
function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data)
internal
virtual
{
_transfer(by, from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {}
function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {}
function _hasCode(address a) private view returns (bool result) {
assembly {
result := extcodesize(a)
}
}
function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
private
{
assembly {
let m := mload(0x40)
let onERC721ReceivedSelector := 0x150b7a02
mstore(m, onERC721ReceivedSelector)
mstore(add(m, 0x20), caller())
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), 0x80)
let n := mload(data)
mstore(add(m, 0xa0), n)
if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
if returndatasize() {
returndatacopy(0x00, 0x00, returndatasize())
revert(0x00, returndatasize())
}
}
if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
mstore(0x00, 0xd1a57ed6)
revert(0x1c, 0x04)
}
}
}
}
文件 3 的 19:ERC721Extended.sol
pragma solidity ^0.8.4;
import {ERC721} from "solady/src/tokens/ERC721.sol";
abstract contract ERC721Extended is ERC721 {
uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
function _getOwnershipSlot(uint256 id) internal view virtual returns (address owner, uint96 extra) {
assembly {
let m := mload(0x40)
mstore(add(m, 0x00), id)
mstore(add(m, 0x1c), _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(add(m, 0x00), 0x20)))
let packed := sload(ownershipSlot)
owner := shr(96, shl(96, packed))
extra := shr(160, packed)
}
}
function _setOwnershipSlot(uint256 id, address owner, uint96 extra) internal virtual {
assembly {
let m := mload(0x40)
mstore(add(m, 0x00), id)
mstore(add(m, 0x1c), _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(add(m, 0x00), 0x20)))
owner := shr(96, shl(96, owner))
sstore(ownershipSlot, or(owner, shl(160, extra)))
}
}
function _getBalanceSlot(address owner) internal view returns (uint256 slot) {
assembly {
let m := mload(0x40)
mstore(add(m, 0x1c), _ERC721_MASTER_SLOT_SEED)
mstore(add(m, 0x00), owner)
let balanceSlot := keccak256(add(m, 0x0c), 0x1c)
slot := sload(balanceSlot)
}
}
function _setBalanceSlot(address owner, uint32 ownerBalance, uint224 aux) internal {
}
function _changeBalance(address owner, bool decrement, uint256 amount) internal virtual {
assembly {
let m := mload(0x40)
mstore(add(m, 0x1c), _ERC721_MASTER_SLOT_SEED)
mstore(add(m, 0x00), owner)
let balanceSlot := keccak256(add(m, 0x0c), 0x1c)
let balanceSlotPacked := sload(balanceSlot)
switch decrement
case 0 { balanceSlotPacked := add(balanceSlotPacked, amount) }
default { balanceSlotPacked := sub(balanceSlotPacked, amount) }
if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) {
mstore(add(m, 0x00), 0x01336cea)
revert(add(m, 0x1c), 0x04)
}
sstore(balanceSlot, balanceSlotPacked)
}
}
function _incrementBalance(address owner, uint256 amount) internal virtual {
_changeBalance(owner, false, amount);
}
function _decrementBalance(address owner, uint256 amount) internal virtual {
_changeBalance(owner, true, amount);
}
function _isApprovedOrOwner(address account, uint256 id, address owner)
internal
view
virtual
returns (bool result)
{
assembly {
let m := mload(0x40)
result := 1
account := shr(96, shl(96, account))
if iszero(owner) {
mstore(add(m, 0x00), 0xceea21b6)
revert(add(m, 0x1c), 0x04)
}
if iszero(eq(account, owner)) {
mstore(add(m, 0x00), id)
mstore(add(m, 0x1c), or(_ERC721_MASTER_SLOT_SEED, account))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
mstore(add(m, 0x00), owner)
if iszero(sload(keccak256(add(m, 0x0c), 0x30))) {
result := eq(account, sload(add(1, ownershipSlot)))
}
}
}
}
function _burn(address by, uint256 id, address owner, bool decrementBalance) internal virtual {
assembly {
by := shr(96, shl(96, by))
let m := mload(0x40)
mstore(add(m, 0x00), id)
mstore(add(m, 0x1c), or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(add(m, 0x00), 0x20)))
if iszero(owner) {
mstore(add(m, 0x00), 0xceea21b6)
revert(add(m, 0x1c), 0x04)
}
{
mstore(add(m, 0x00), owner)
let approvedAddress := sload(add(1, ownershipSlot))
if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
if iszero(sload(keccak256(add(m, 0x0c), 0x30))) {
mstore(add(m, 0x00), 0x4b6e7f18)
revert(add(m, 0x1c), 0x04)
}
}
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
sstore(ownershipSlot, 0)
if decrementBalance {
let balanceSlot := keccak256(add(m, 0x0c), 0x1c)
sstore(balanceSlot, sub(sload(balanceSlot), 1))
}
log4(add(m, 0x00), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
}
}
}
文件 4 的 19:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 5 的 19:IERC20Extended.sol
pragma solidity ^0.8.17;
import {IERC20 as OZ_IERC20} from "openzeppelin/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "openzeppelin/token/ERC20/extensions/IERC20Metadata.sol";
import {IERC20Permit} from "openzeppelin/token/ERC20/extensions/IERC20Permit.sol";
interface IERC20 is OZ_IERC20, IERC20Metadata {
}
interface IPermitERC20 is IERC20, IERC20Permit {
}
文件 6 的 19:IERC20Metadata.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
interface IERC20Metadata is IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
}
文件 7 的 19:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 8 的 19:ILiquidityVault.sol
pragma solidity ^0.8.26;
import {Permit} from "shared/src/structs/Permit.sol";
interface ILiquidityVault {
struct MintParams {
address tokenA;
address tokenB;
Permit permitA;
Permit permitB;
uint256 amountA;
uint256 amountB;
uint32 lockDuration;
}
struct Snapshot {
address token0;
address token1;
uint256 amountIn0;
uint256 amountIn1;
uint256 liquidity;
}
struct IncreaseParams {
uint256 additional0;
uint256 additional1;
Permit permit0;
Permit permit1;
}
function WETH() external pure returns (address);
function ETH() external pure returns (address);
function fees() external view returns (uint256, uint256, uint256);
function unlockTime(uint256 id) external view returns (uint256);
function mint(address recipient, address referrer, MintParams calldata params) payable external returns (uint256 id, Snapshot memory snapshot);
function mint(MintParams calldata params) payable external returns (uint256 id, Snapshot memory snapshot);
function increase(uint256 id, IncreaseParams calldata params, Snapshot calldata snapshot) payable external returns (uint256 added0, uint256 added1);
function collect(uint256 id, Snapshot calldata snapshot) external returns (uint256 collectedFee0, uint256 collectedFee1);
function redeem(uint256 id, Snapshot calldata snapshot, bool removeLP) external;
function extend(uint256 id, uint32 additionalTime) external;
}
interface ILiquidityVaultReferral is ILiquidityVault {
function verifySnapshot(uint256 id, Snapshot calldata snapshot) external view returns (uint160 snapshotHash, uint96 referralHash);
function resetReferralHash(uint256 id, address referrer) external;
}
文件 9 的 19:IPayMaster.sol
pragma solidity ^0.8.26;
interface IPayMaster {
function OWNER() external returns (address);
function payFees(uint256 devFee) external payable;
}
文件 10 的 19:ISuccessor.sol
pragma solidity ^0.8.26;
interface ISuccessor {
function encodeParams(uint40 unlockTime, bytes memory params) pure external returns (bytes memory);
function mint(address recipient, bytes memory params) payable external;
}
文件 11 的 19:IUniswapV2Factory.sol
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
文件 12 的 19:IUniswapV2Pair.sol
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
文件 13 的 19:IWETH9.sol
pragma solidity ^0.8.4;
interface IWETH9 {
function deposit() external payable;
function withdraw(uint wad) external;
function totalSupply() external view returns (uint);
function approve(address guy, uint wad) external returns (bool);
function transfer(address dst, uint wad) external returns (bool);
function transferFrom(address src, address dst, uint wad) external returns (bool);
function balanceOf(address account) external view returns (uint256);
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
event Deposit(address indexed dst, uint wad);
event Withdrawal(address indexed src, uint wad);
}
文件 14 的 19:LiquidityVault.sol
pragma solidity ^0.8.26;
import {Ownable} from "solady/src/auth/Ownable.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
import {ERC721Extended} from "shared/src/tokens/ERC721Extended.sol";
import {Permit} from "shared/src/structs/Permit.sol";
import {Math} from "openzeppelin/utils/math/Math.sol";
import {IWETH9} from "shared/src/tokens/IWETH9.sol";
import {IPermitERC20, IERC20} from "shared/src/interfaces/IERC20Extended.sol";
import {IUniswapV2Factory} from "v2-core/interfaces/IUniswapV2Factory.sol";
import {IUniswapV2Pair} from "v2-core/interfaces/IUniswapV2Pair.sol";
import {IPayMaster} from "./interfaces/IPayMaster.sol";
import {ILiquidityVault} from "./interfaces/ILiquidityVault.sol";
import {Token} from "./MigrationToken.sol";
import {ISuccessor} from "./interfaces/ISuccessor.sol";
contract LiquidityVault is ILiquidityVault, ERC721Extended, Ownable {
event Minted(
uint256 indexed id,
address indexed referrer,
address token0,
address token1,
uint40 lockTime,
uint256 snapshotLiquidity,
uint256 snapshotAmountIn0,
uint256 snapshotAmountIn1,
bytes referralFee
);
event Increased(
uint256 indexed id,
uint256 snapshotLiquidity,
uint256 snapshotAmountIn0,
uint256 snapshotAmountIn1
);
event Collected(
uint256 indexed id,
uint256 fee0,
uint256 fee1,
uint256 snapshotLiquidity,
uint256 snapshotAmountIn0,
uint256 snapshotAmountIn1,
bytes referralFee0,
bytes referralFee1
);
event Redeemed(uint256 indexed id);
event Extended(uint256 indexed id, uint32 additionalTime);
IUniswapV2Factory public constant V2_FACTORY = IUniswapV2Factory(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f);
address public constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address public constant ETH = address(0);
uint32 public constant LOCK_FOREVER = type(uint32).max;
uint40 public constant LOCKED_FOREVER = type(uint40).max;
uint16 public constant FEE_DIVISOR = 10_000;
IPayMaster immutable payMaster;
error IdenticalTokens();
error ZeroTokenAmount();
error InvalidLiquiditySnapshot();
error NotUnlocked();
error InsufficientFunds();
error NotPayMaster();
error NotRegisteredRefferer();
error InvalidFee();
error InvalidLiquidityAdditionalAmounts();
error InsufficientLiquidityBurned();
function name() public pure override returns (string memory) { return "Liquidity Vault"; }
function symbol() public pure override returns (string memory) { return "LPVault"; }
function tokenURI(uint256 id) public pure override returns (string memory) {
return "";
}
uint256 private _idTracker;
uint256 _feeSlot = 0.1 ether << 16 | 2_000;
uint256 _collectFeePercent = 3_333;
ISuccessor _successor;
mapping(uint256 => bytes32) public hashInfoForCertificateID;
mapping(address => bool) public registeredReferrers;
constructor(IPayMaster pm) {
payMaster = pm;
_initializeOwner(msg.sender);
}
function _decodeFeeSlot(uint256 slot) internal pure returns (uint256 mintFee, uint256 referralMintFeePercent) {
referralMintFeePercent = slot & ((1 << 16) - 1);
mintFee = slot >> 16;
}
function _encodeFeeSlot(uint256 mintFee, uint256 referralMintFeePercent) internal pure returns (uint256 slot) {
slot = (referralMintFeePercent & ((1 << 16) - 1)) | (mintFee << 16);
}
function _encodeHashInfo(uint160 snapshotHash, uint96 referralHash) internal pure returns (bytes32) {
return bytes32((uint256(referralHash) << 160) | uint256(snapshotHash));
}
function _decodeHashInfo(bytes32 hashInfo) internal pure returns (uint160 snapshotHash, uint96 referralHash) {
referralHash = uint96(uint256(hashInfo) >> 160);
snapshotHash = uint160(uint256(hashInfo));
}
function _encodeSnapshotID(Snapshot memory snapshot) pure internal returns (uint160) {
return uint160(uint256(keccak256(
abi.encodePacked(
snapshot.token0,
snapshot.token1,
snapshot.amountIn0,
snapshot.amountIn1,
snapshot.liquidity
)
)));
}
function _convertToWETH(uint256 b, uint256 wethNeeded) internal returns (uint256 refundETH) {
uint wethB = IERC20(WETH).balanceOf(address(this));
uint ethToConvert = wethNeeded > wethB ? wethNeeded - wethB : 0;
if (wethB > wethNeeded) {
IWETH9(WETH).withdraw(wethB - wethNeeded);
refundETH += wethB - wethNeeded;
}
if (ethToConvert > 0) {
if (b < ethToConvert) revert InsufficientFunds();
IWETH9(WETH).deposit{value: ethToConvert}();
}
refundETH += b - ethToConvert;
}
function _resolveAndPermitIfNecessary(address token, Permit memory permit, uint256 amount) internal returns (address) {
if (permit.enable && token != WETH) IPermitERC20(token).permit(msg.sender, address(this), amount, permit.deadline, permit.v, permit.r, permit.s);
return token;
}
function _getAndValidateCertificateInfo(uint256 id) internal view returns (uint40 unlockTime, address owner) {
uint96 data;
(owner, data) = _getOwnershipSlot(id);
if (!_isApprovedOrOwner(msg.sender, id, owner)) revert NotOwnerNorApproved();
if (owner == address(0)) revert TokenDoesNotExist();
unlockTime = uint40(data);
}
function _getWETHNeeded(address tokenA, address tokenB, uint256 amountA, uint256 amountB) internal pure returns (uint256) {
if (tokenA == ETH || tokenA == WETH) return amountA;
if (tokenB == ETH || tokenB == WETH) return amountB;
return 0;
}
function _validateFunds(uint256 mintFee, uint256 wethNeeded) internal returns (uint256 remainingBal) {
remainingBal = msg.value;
if (msg.value < mintFee) revert InsufficientFunds();
remainingBal -= mintFee;
if (wethNeeded > 0) remainingBal = _convertToWETH(remainingBal, wethNeeded);
}
function _orderTokens(address tokenA, address tokenB) internal pure returns (address token0, address token1) {
(token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
}
function _pairFor(address tokenA, address tokenB) internal pure returns (address pair) {
(address token0, address token1) = _orderTokens(tokenA, tokenB);
pair = address(uint160(uint256(keccak256(abi.encodePacked(
hex'ff',
address(V2_FACTORY),
keccak256(abi.encodePacked(token0, token1)),
hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f'
)))));
}
function _removeLiquidity(address pool, uint liquidity, address to) internal returns (uint amount0, uint amount1) {
IUniswapV2Pair pair = IUniswapV2Pair(pool);
SafeTransferLib.safeTransfer(pool, pool, liquidity);
(amount0, amount1) = pair.burn(to);
}
function _addLiquidityV2(address pool, address token0, address token1, uint256 amount0, uint256 amount1, bool transferFrom0, bool transferFrom1) internal returns (uint256 liquidity, uint256 actualAmount0, uint256 actualAmount1, uint256 refundETH) {
IUniswapV2Pair pair = IUniswapV2Pair(pool);
(actualAmount0, actualAmount1) = (amount0, amount1);
(uint reserve0, uint reserve1, ) = pair.getReserves();
if (!(reserve0 == 0 && reserve1 == 0)) {
(actualAmount0, actualAmount1) = (amount0, amount0 * reserve1 / reserve0);
if (actualAmount1 == 0 || actualAmount1 > amount1)
(actualAmount0, actualAmount1) = (amount1 * reserve0 / reserve1, amount1);
if (actualAmount0 == 0 || actualAmount1 == 0 || actualAmount0 > amount0 || actualAmount1 > amount1)
revert InvalidLiquidityAdditionalAmounts();
}
if (transferFrom0) SafeTransferLib.safeTransferFrom(token0, msg.sender, pool, actualAmount0);
if (transferFrom1) SafeTransferLib.safeTransferFrom(token1, msg.sender, pool, actualAmount1);
if (!transferFrom0) {
SafeTransferLib.safeTransfer(token0, pool, actualAmount0);
if (token0 == WETH && amount0 > actualAmount0) refundETH = amount0 - actualAmount0;
}
if (!transferFrom1) {
SafeTransferLib.safeTransfer(token1, pool, actualAmount1);
if (token1 == WETH && amount1 > actualAmount1) refundETH = amount1 - actualAmount1;
}
if (refundETH > 0) IWETH9(WETH).withdraw(refundETH);
liquidity = pair.mint(address(this));
uint totalLiquidity = pair.totalSupply();
actualAmount0 = liquidity * (reserve0 + actualAmount0) / totalLiquidity;
actualAmount1 = liquidity * (reserve1 + actualAmount1) / totalLiquidity;
}
receive() external payable {
if (msg.sender != WETH) revert();
}
fallback() external payable {
if (msg.sender != WETH) revert();
}
function fees() external view returns (uint256 mintFee, uint256 referalMintFeePercent, uint256 collectFeePercent) {
(mintFee, referalMintFeePercent) = _decodeFeeSlot(_feeSlot);
collectFeePercent = _collectFeePercent;
}
function unlockTime(uint256 id) view external returns (uint256) {
return uint256(uint40(_getExtraData(id)));
}
function setFees(uint256 mintFee, uint256 referralMintFeePercent, uint256 collectFeePercent) external onlyOwner {
if (collectFeePercent > _collectFeePercent) revert InvalidFee();
if (referralMintFeePercent > FEE_DIVISOR) revert InvalidFee();
_feeSlot = _encodeFeeSlot(mintFee, referralMintFeePercent);
_collectFeePercent = collectFeePercent;
}
function setSuccessor(address successor) external onlyOwner {
_successor = ISuccessor(successor);
}
function setReferrer(address referrer, bool value) external onlyOwner {
registeredReferrers[referrer] = value;
}
function verifySnapshot(uint256 id, Snapshot calldata snapshot) public view returns (uint160 snapshotHash, uint96 referralHash) {
(snapshotHash, referralHash) = _decodeHashInfo(hashInfoForCertificateID[id]);
if (snapshotHash != _encodeSnapshotID(snapshot)) revert InvalidLiquiditySnapshot();
}
function resetReferralHash(uint256 id, address referrer) external {
if (msg.sender != address(payMaster)) revert NotPayMaster();
(uint160 snapshotHash, uint96 referralHash) = _decodeHashInfo(hashInfoForCertificateID[id]);
referralHash = uint96(uint256(keccak256(abi.encodePacked(referrer, uint256(0)))));
hashInfoForCertificateID[id] = _encodeHashInfo(
snapshotHash,
referralHash
);
}
function mint(address recipient, address referrer, MintParams calldata params) public payable returns (uint256 id, Snapshot memory snapshot) {
if (referrer != address(0) && !registeredReferrers[referrer]) revert NotRegisteredRefferer();
(uint256 mintFee, uint256 referralMintFeePercent) = _decodeFeeSlot(_feeSlot);
uint256 remainingBalance = _validateFunds(mintFee, _getWETHNeeded(params.tokenA, params.tokenB, params.amountA, params.amountB));
uint40 unlockTime = params.lockDuration == LOCK_FOREVER || (block.timestamp + params.lockDuration) > type(uint40).max ? LOCKED_FOREVER : uint40(block.timestamp + uint256(params.lockDuration));
uint256 devMintFee = referrer == address(0) ? mintFee : mintFee - mintFee * referralMintFeePercent / FEE_DIVISOR;
payMaster.payFees{ value: mintFee }(devMintFee);
if (params.tokenA == params.tokenB) revert IdenticalTokens();
if (params.tokenA == WETH && params.tokenB == ETH) revert IdenticalTokens();
if (params.tokenB == WETH && params.tokenA == ETH) revert IdenticalTokens();
if (params.amountA == 0 || params.amountB == 0) revert ZeroTokenAmount();
(address tokenA, address tokenB) = (
(params.tokenA == ETH || params.tokenA == WETH) ? WETH : _resolveAndPermitIfNecessary(params.tokenA, params.permitA, params.amountA),
(params.tokenB == ETH || params.tokenB == WETH) ? WETH : _resolveAndPermitIfNecessary(params.tokenB, params.permitB, params.amountB)
);
(snapshot.token0, snapshot.token1) = _orderTokens(tokenA, tokenB);
(uint256 desiredAmount0, uint256 desiredAmount1) = snapshot.token0 == tokenA ? (params.amountA, params.amountB) :
(params.amountB, params.amountA);
address pool = V2_FACTORY.getPair(tokenA, tokenB);
pool = pool == address(0) ? V2_FACTORY.createPair(tokenA, tokenB) : pool;
(bool isNativeETH0, bool isNativeETH1) = snapshot.token0 == tokenA ? (params.tokenA == ETH, params.tokenB == ETH) :
(params.tokenB == ETH, params.tokenA == ETH);
uint256 refundETH;
(snapshot.liquidity, snapshot.amountIn0, snapshot.amountIn1, refundETH) = _addLiquidityV2(
pool,
snapshot.token0,
snapshot.token1,
desiredAmount0,
desiredAmount1,
!isNativeETH0,
!isNativeETH1
);
if (remainingBalance + refundETH > 0) payable(msg.sender).transfer(remainingBalance + refundETH);
uint256 referralFee = mintFee * referralMintFeePercent / FEE_DIVISOR;
uint96 referrerHash = referrer != address(0) ? uint96(uint256(keccak256(abi.encodePacked(referrer, referralFee)))) : 0;
hashInfoForCertificateID[_idTracker] = _encodeHashInfo(
_encodeSnapshotID(snapshot),
referrerHash
);
id = _idTracker;
emit Transfer(address(0), recipient, _idTracker);
emit Minted(
_idTracker,
referrer,
snapshot.token0,
snapshot.token1,
params.lockDuration,
snapshot.liquidity,
snapshot.amountIn0,
snapshot.amountIn1,
referrer != address(0) ? abi.encode(uint256(referralFee)) : bytes("")
);
_setOwnershipSlot(_idTracker, recipient, uint96(unlockTime));
_incrementBalance(recipient, 1);
_idTracker++;
}
function mint(MintParams calldata params) payable external returns (uint256 id, Snapshot memory snapshot) {
return mint(msg.sender, address(0), params);
}
function collect(uint256 id, Snapshot calldata snapshot) external returns (uint256 fee0, uint256 fee1) {
(, uint96 referralHash) = verifySnapshot(id, snapshot);
(address owner, ) = _getOwnershipSlot(id);
address pool = _pairFor(snapshot.token0, snapshot.token1);
uint256 balance0 = IERC20(snapshot.token0).balanceOf(pool);
uint256 balance1 = IERC20(snapshot.token1).balanceOf(pool);
uint256 totalLiquidity = IERC20(pool).totalSupply();
uint256 wouldBeRemoved0 = snapshot.liquidity * balance0 / totalLiquidity;
uint256 wouldBeRemoved1 = snapshot.liquidity * balance1 / totalLiquidity;
uint256 feeLiquidity0 = totalLiquidity * wouldBeRemoved0 / balance0 - Math.mulDiv(totalLiquidity, Math.sqrt(Math.mulDiv(wouldBeRemoved0, snapshot.amountIn0 * snapshot.amountIn1, wouldBeRemoved1)), balance0);
uint256 feeLiquidity1 = totalLiquidity * wouldBeRemoved1 / balance1 - Math.mulDiv(totalLiquidity, Math.sqrt(Math.mulDiv(wouldBeRemoved1, snapshot.amountIn0 * snapshot.amountIn1, wouldBeRemoved0)), balance1);
uint256 feeLiquidity = feeLiquidity0 <= feeLiquidity1 ? feeLiquidity1 : feeLiquidity0;
if (feeLiquidity == 0) revert InsufficientLiquidityBurned();
(fee0, fee1) = _removeLiquidity(pool, feeLiquidity, address(this));
(uint256 referralFee0, uint256 referralFee1) = (fee0 * _collectFeePercent / FEE_DIVISOR, fee1 * _collectFeePercent / FEE_DIVISOR);
if (snapshot.token0 == WETH) IWETH9(WETH).withdraw(fee0);
if (snapshot.token1 == WETH) IWETH9(WETH).withdraw(fee1);
if (referralFee0 > 0) {
if (snapshot.token0 == WETH) {
payMaster.payFees{ value: referralFee0 }(referralHash == 0 ? referralFee0 : 0);
}
else SafeTransferLib.safeTransfer(snapshot.token0, referralHash == 0 ? payMaster.OWNER() : address(payMaster), referralFee0);
}
if (referralFee1 > 0) {
if (snapshot.token1 == WETH) {
payMaster.payFees{ value: referralFee1 }(referralHash == 0 ? referralFee1 : 0);
}
else SafeTransferLib.safeTransfer(snapshot.token1, referralHash == 0 ? payMaster.OWNER() : address(payMaster), referralFee1);
}
if (snapshot.token0 == WETH) payable(owner).transfer(fee0 - referralFee0);
else SafeTransferLib.safeTransfer(snapshot.token0, owner, fee0 - referralFee0);
if (snapshot.token1 == WETH) payable(owner).transfer(fee1 - referralFee1);
else SafeTransferLib.safeTransfer(snapshot.token1, owner, fee1 - referralFee1);
if (referralHash != 0) {
referralHash = uint96(uint256(keccak256(abi.encodePacked(
uint96(uint256(keccak256(abi.encodePacked(referralHash, referralFee0)))),
referralFee1
))));
}
uint256 liquidity = snapshot.liquidity - feeLiquidity;
totalLiquidity = IUniswapV2Pair(pool).totalSupply();
uint256 amountIn0 = liquidity * IERC20(snapshot.token0).balanceOf(pool) / totalLiquidity;
uint256 amountIn1 = liquidity * IERC20(snapshot.token1).balanceOf(pool) / totalLiquidity;
hashInfoForCertificateID[id] = _encodeHashInfo(
_encodeSnapshotID(Snapshot({
token0: snapshot.token0,
token1: snapshot.token1,
amountIn0: amountIn0,
amountIn1: amountIn1,
liquidity: liquidity
})),
referralHash
);
emit Collected(
id,
fee0,
fee1,
liquidity,
amountIn0,
amountIn1,
referralHash != 0 ? abi.encode(uint256(referralFee0)) : bytes(""),
referralHash != 0 ? abi.encode(uint256(referralFee1)) : bytes("")
);
}
function redeem(uint256 id, Snapshot calldata snapshot, bool removeLP) external {
verifySnapshot(id, snapshot);
(uint40 unlockTime, address owner) = _getAndValidateCertificateInfo(id);
if (unlockTime == LOCKED_FOREVER || block.timestamp <= unlockTime) revert NotUnlocked();
address pool = _pairFor(snapshot.token0, snapshot.token1);
if (removeLP) _removeLiquidity(pool, snapshot.liquidity, owner);
else IERC20(pool).transfer(owner, snapshot.liquidity);
hashInfoForCertificateID[id] = 0;
_burn(address(0), id, owner, true);
}
function extend(uint256 id, uint32 additionalTime) external {
(uint40 unlockTime, ) = _getAndValidateCertificateInfo(id);
if (unlockTime == LOCKED_FOREVER) return;
if (additionalTime == LOCK_FOREVER || LOCKED_FOREVER - unlockTime <= additionalTime) unlockTime = LOCKED_FOREVER;
else unlockTime += additionalTime;
_setExtraData(id, uint96(unlockTime));
}
function increase(uint256 id, IncreaseParams calldata params, Snapshot calldata snapshot) payable external returns (uint256 added0, uint256 added1) {
(, uint96 referralHash) = verifySnapshot(id, snapshot);
_getAndValidateCertificateInfo(id);
uint256 remainingBalance = _validateFunds(0, _getWETHNeeded(snapshot.token0, snapshot.token1, params.additional0, params.additional1));
address pair = _pairFor(snapshot.token0, snapshot.token1);
if (snapshot.token0 != WETH) _resolveAndPermitIfNecessary(snapshot.token0, params.permit0, params.additional0);
if (snapshot.token1 != WETH) _resolveAndPermitIfNecessary(snapshot.token1, params.permit1, params.additional1);
(bool isNativeETH0, bool isNativeETH1) = (snapshot.token0 == WETH, snapshot.token1 == WETH);
try this.collect(id, snapshot) {}
catch {}
(uint256 additionalLiquidity, uint256 refundETH) = (0, 0);
(additionalLiquidity, added0, added1, refundETH) = _addLiquidityV2(
pair,
snapshot.token0,
snapshot.token1,
params.additional0,
params.additional1,
!isNativeETH0,
!isNativeETH1
);
if (remainingBalance + refundETH > 0) payable(msg.sender).transfer(remainingBalance + refundETH);
uint256 snapshotLiquidity = snapshot.liquidity + additionalLiquidity;
uint256 totalLiquidity = IUniswapV2Pair(pair).totalSupply();
uint256 snapshotAmountIn0 = snapshotLiquidity * IERC20(snapshot.token0).balanceOf(pair) / totalLiquidity;
uint256 snapshotAmountIn1 = snapshotLiquidity * IERC20(snapshot.token1).balanceOf(pair) / totalLiquidity;
hashInfoForCertificateID[id] = _encodeHashInfo(
_encodeSnapshotID(Snapshot({
token0: snapshot.token0,
token1: snapshot.token1,
amountIn0: snapshotAmountIn0,
amountIn1: snapshotAmountIn1,
liquidity: snapshotLiquidity
})),
referralHash
);
emit Increased(
id,
snapshotLiquidity,
snapshotAmountIn0,
snapshotAmountIn1
);
}
mapping(address => bool) _migrated;
error MigrateNotAvailable();
error AlreadyMigrated();
error NotMajorityLiquidityHolder();
error NonETHPair();
function migrate(uint256 id, Snapshot calldata snapshot, bytes calldata successorParams) external returns (address token) {
if (address(_successor) == address(0)) revert MigrateNotAvailable();
verifySnapshot(id, snapshot);
(uint40 unlockTime, address owner) = _getAndValidateCertificateInfo(id);
address pool = _pairFor(snapshot.token0, snapshot.token1);
if (_migrated[pool]) revert AlreadyMigrated();
uint256 totalLiquidity = IERC20(pool).totalSupply();
if (snapshot.liquidity < totalLiquidity / 2) revert NotMajorityLiquidityHolder();
if (snapshot.token0 != WETH && snapshot.token1 != WETH) revert NonETHPair();
_migrated[pool] = true;
try this.collect(id, snapshot) {}
catch {}
(uint256 amount0, uint256 amount1) = _removeLiquidity(
pool,
snapshot.liquidity,
address(this)
);
address targetToken = snapshot.token0 != WETH ? snapshot.token0 : snapshot.token1;
(uint256 ethAmount, uint256 tokenAmount) = snapshot.token0 == WETH ? (amount0, amount1) : (amount1, amount0);
IWETH9(WETH).withdraw(ethAmount);
IERC20 oldToken = IERC20(targetToken);
Token newToken = new Token(targetToken);
token = address(newToken);
SafeTransferLib.safeTransfer(token, address(_successor), tokenAmount);
SafeTransferLib.safeTransfer(token, token, oldToken.totalSupply() - tokenAmount);
SafeTransferLib.safeTransfer(targetToken, address(0), tokenAmount);
_successor.mint{ value: ethAmount }(msg.sender, _successor.encodeParams(unlockTime, successorParams));
hashInfoForCertificateID[id] = 0;
_burn(address(0), id, owner, true);
}
}
文件 15 的 19:Math.sol
pragma solidity ^0.8.0;
library Math {
enum Rounding {
Down,
Up,
Zero
}
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a & b) + (a ^ b) / 2;
}
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
return a == 0 ? 0 : (a - 1) / b + 1;
}
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
uint256 prod0;
uint256 prod1;
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
if (prod1 == 0) {
return prod0 / denominator;
}
require(denominator > prod1, "Math: mulDiv overflow");
uint256 remainder;
assembly {
remainder := mulmod(x, y, denominator)
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
uint256 twos = denominator & (~denominator + 1);
assembly {
denominator := div(denominator, twos)
prod0 := div(prod0, twos)
twos := add(div(sub(0, twos), twos), 1)
}
prod0 |= prod1 * twos;
uint256 inverse = (3 * denominator) ^ 2;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
inverse *= 2 - denominator * inverse;
result = prod0 * inverse;
return result;
}
}
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
uint256 result = 1 << (log2(a) >> 1);
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
}
}
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
}
}
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
}
}
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
}
}
}
文件 16 的 19:MigrationToken.sol
pragma solidity ^0.8.26;
import {ERC20} from "solady/src/tokens/ERC20.sol";
import {IPermitERC20} from "shared/src/interfaces/IERC20Extended.sol";
import {Permit} from "shared/src/structs/Permit.sol";
import {SafeTransferLib} from "solady/src/utils/SafeTransferLib.sol";
contract Token is ERC20 {
address immutable OLD_TOKEN;
string NAME;
string SYMBOL;
function name() public view override returns (string memory) { return NAME; }
function symbol() public view override returns (string memory) { return SYMBOL; }
constructor(address token) {
OLD_TOKEN = token;
IPermitERC20 t = IPermitERC20(token);
NAME = t.name();
SYMBOL = t.symbol();
_mint(msg.sender, t.totalSupply());
}
function migrate(Permit calldata permit, uint256 amount) external {
IPermitERC20 oldToken = IPermitERC20(OLD_TOKEN);
uint256 curAmount = oldToken.balanceOf(address(this));
if (amount > 0) {
if (permit.enable) oldToken.permit(msg.sender, address(this), amount, permit.deadline, permit.v, permit.r, permit.s);
SafeTransferLib.safeTransferFrom(address(oldToken), msg.sender, address(0), amount);
}
_transfer(address(this), msg.sender, curAmount + amount);
SafeTransferLib.safeTransfer(address(oldToken), address(0), curAmount);
}
}
文件 17 的 19:Ownable.sol
pragma solidity ^0.8.4;
abstract contract Ownable {
error Unauthorized();
error NewOwnerIsZeroAddress();
error NoHandoverRequest();
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
event OwnershipHandoverRequested(address indexed pendingOwner);
event OwnershipHandoverCanceled(address indexed pendingOwner);
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8;
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
function _initializeOwner(address newOwner) internal virtual {
assembly {
newOwner := shr(96, shl(96, newOwner))
sstore(not(_OWNER_SLOT_NOT), newOwner)
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
function _setOwner(address newOwner) internal virtual {
assembly {
let ownerSlot := not(_OWNER_SLOT_NOT)
newOwner := shr(96, shl(96, newOwner))
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
sstore(ownerSlot, newOwner)
}
}
function _checkOwner() internal view virtual {
assembly {
if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) {
mstore(0x00, 0x82b42900)
revert(0x1c, 0x04)
}
}
}
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
function transferOwnership(address newOwner) public payable virtual onlyOwner {
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae)
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
function cancelOwnershipHandover() public payable virtual {
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818)
revert(0x1c, 0x04)
}
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
function owner() public view virtual returns (address result) {
assembly {
result := sload(not(_OWNER_SLOT_NOT))
}
}
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
assembly {
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
result := sload(keccak256(0x0c, 0x20))
}
}
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}
文件 18 的 19:Permit.sol
pragma solidity ^0.8.17;
struct Permit {
uint256 deadline;
bytes32 r;
bytes32 s;
uint8 v;
bool enable;
}
function NoPermit() pure returns (Permit memory) {
return Permit(0, 0, 0, 0, false);
}
文件 19 的 19:SafeTransferLib.sol
pragma solidity ^0.8.4;
library SafeTransferLib {
error ETHTransferFailed();
error TransferFromFailed();
error TransferFailed();
error ApproveFailed();
uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;
uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;
function safeTransferETH(address to, uint256 amount) internal {
assembly {
if iszero(call(gas(), to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function safeTransferAllETH(address to) internal {
assembly {
if iszero(call(gas(), to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
}
}
function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas()))
}
}
}
}
function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
assembly {
if iszero(call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas()))
}
}
}
}
function forceSafeTransferETH(address to, uint256 amount) internal {
assembly {
if lt(selfbalance(), amount) {
mstore(0x00, 0xb12d13eb)
revert(0x1c, 0x04)
}
if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(amount, 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas()))
}
}
}
}
function forceSafeTransferAllETH(address to) internal {
assembly {
if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), gas(), 0x00, gas(), 0x00)) {
mstore(0x00, to)
mstore8(0x0b, 0x73)
mstore8(0x20, 0xff)
if iszero(create(selfbalance(), 0x0b, 0x16)) {
returndatacopy(gas(), returndatasize(), shr(20, gas()))
}
}
}
}
function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, amount, gas(), 0x00, gas(), 0x00)
}
}
function trySafeTransferAllETH(address to, uint256 gasStipend)
internal
returns (bool success)
{
assembly {
success := call(gasStipend, to, selfbalance(), gas(), 0x00, gas(), 0x00)
}
}
function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
assembly {
let m := mload(0x40)
mstore(0x60, amount)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x23b872dd000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransferAllFrom(address token, address from, address to)
internal
returns (uint256 amount)
{
assembly {
let m := mload(0x40)
mstore(0x40, to)
mstore(0x2c, shl(96, from))
mstore(0x0c, 0x70a08231000000000000000000000000)
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x00, 0x23b872dd)
amount := mload(0x60)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
)
) {
mstore(0x00, 0x7939f424)
revert(0x1c, 0x04)
}
mstore(0x60, 0)
mstore(0x40, m)
}
}
function safeTransfer(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeTransferAll(address token, address to) internal returns (uint256 amount) {
assembly {
mstore(0x00, 0x70a08231)
mstore(0x20, address())
if iszero(
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x14, to)
amount := mload(0x34)
mstore(0x00, 0xa9059cbb000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x90b8ec18)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeApprove(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
mstore(0x34, 0)
}
}
function safeApproveWithRetry(address token, address to, uint256 amount) internal {
assembly {
mstore(0x14, to)
mstore(0x34, amount)
mstore(0x00, 0x095ea7b3000000000000000000000000)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x34, 0)
mstore(0x00, 0x095ea7b3000000000000000000000000)
pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00))
mstore(0x34, amount)
if iszero(
and(
or(eq(mload(0x00), 1), iszero(returndatasize())),
call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
)
) {
mstore(0x00, 0x3e3f8f73)
revert(0x1c, 0x04)
}
}
mstore(0x34, 0)
}
}
function balanceOf(address token, address account) internal view returns (uint256 amount) {
assembly {
mstore(0x14, account)
mstore(0x00, 0x70a08231000000000000000000000000)
amount :=
mul(
mload(0x20),
and(
gt(returndatasize(), 0x1f),
staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
)
)
}
}
}
{
"compilationTarget": {
"src/LiquidityVault.sol": "LiquidityVault"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 2000
},
"remappings": [
":@openzeppelin/=lib/shared/lib/openzeppelin-contracts/",
":@uniswap/v3-core/=lib/shared/lib/v3-core/",
":@uniswap/v3-periphery/=lib/shared/lib/v3-periphery/",
":ds-test/=lib/forge-std/lib/ds-test/src/",
":erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
":forge-std/=lib/forge-std/src/",
":openzeppelin-contracts/=lib/openzeppelin-contracts/",
":openzeppelin/=lib/openzeppelin-contracts/contracts/",
":shared/=lib/shared/",
":solady/=lib/solady/",
":swap-router-contracts/=lib/shared/lib/swap-router-contracts/contracts/",
":v2-core/=lib/shared/lib/v2-core/contracts/",
":v2-periphery/=lib/v2-periphery/contracts/",
":v3-core/=lib/shared/lib/v3-core/",
":v3-periphery/=lib/shared/lib/v3-periphery/contracts/"
],
"viaIR": true
}
[{"inputs":[{"internalType":"contract IPayMaster","name":"pm","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyMigrated","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"IdenticalTokens","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InsufficientLiquidityBurned","type":"error"},{"inputs":[],"name":"InvalidFee","type":"error"},{"inputs":[],"name":"InvalidLiquidityAdditionalAmounts","type":"error"},{"inputs":[],"name":"InvalidLiquiditySnapshot","type":"error"},{"inputs":[],"name":"MigrateNotAvailable","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonETHPair","type":"error"},{"inputs":[],"name":"NotMajorityLiquidityHolder","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NotPayMaster","type":"error"},{"inputs":[],"name":"NotRegisteredRefferer","type":"error"},{"inputs":[],"name":"NotUnlocked","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroTokenAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn1","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"referralFee0","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"referralFee1","type":"bytes"}],"name":"Collected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"additionalTime","type":"uint32"}],"name":"Extended","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn1","type":"uint256"}],"name":"Increased","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"referrer","type":"address"},{"indexed":false,"internalType":"address","name":"token0","type":"address"},{"indexed":false,"internalType":"address","name":"token1","type":"address"},{"indexed":false,"internalType":"uint40","name":"lockTime","type":"uint40"},{"indexed":false,"internalType":"uint256","name":"snapshotLiquidity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn0","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"snapshotAmountIn1","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"referralFee","type":"bytes"}],"name":"Minted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[],"name":"ETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEE_DIVISOR","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCKED_FOREVER","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LOCK_FOREVER","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"V2_FACTORY","outputs":[{"internalType":"contract IUniswapV2Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"}],"name":"collect","outputs":[{"internalType":"uint256","name":"fee0","type":"uint256"},{"internalType":"uint256","name":"fee1","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint32","name":"additionalTime","type":"uint32"}],"name":"extend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fees","outputs":[{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"referalMintFeePercent","type":"uint256"},{"internalType":"uint256","name":"collectFeePercent","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"hashInfoForCertificateID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"uint256","name":"additional0","type":"uint256"},{"internalType":"uint256","name":"additional1","type":"uint256"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permit0","type":"tuple"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permit1","type":"tuple"}],"internalType":"struct ILiquidityVault.IncreaseParams","name":"params","type":"tuple"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"}],"name":"increase","outputs":[{"internalType":"uint256","name":"added0","type":"uint256"},{"internalType":"uint256","name":"added1","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"},{"internalType":"bytes","name":"successorParams","type":"bytes"}],"name":"migrate","outputs":[{"internalType":"address","name":"token","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permitA","type":"tuple"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permitB","type":"tuple"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint32","name":"lockDuration","type":"uint32"}],"internalType":"struct ILiquidityVault.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"address","name":"referrer","type":"address"},{"components":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permitA","type":"tuple"},{"components":[{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bool","name":"enable","type":"bool"}],"internalType":"struct Permit","name":"permitB","type":"tuple"},{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint32","name":"lockDuration","type":"uint32"}],"internalType":"struct ILiquidityVault.MintParams","name":"params","type":"tuple"}],"name":"mint","outputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"},{"internalType":"bool","name":"removeLP","type":"bool"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"registeredReferrers","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"referrer","type":"address"}],"name":"resetReferralHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"mintFee","type":"uint256"},{"internalType":"uint256","name":"referralMintFeePercent","type":"uint256"},{"internalType":"uint256","name":"collectFeePercent","type":"uint256"}],"name":"setFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"referrer","type":"address"},{"internalType":"bool","name":"value","type":"bool"}],"name":"setReferrer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"successor","type":"address"}],"name":"setSuccessor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"unlockTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"components":[{"internalType":"address","name":"token0","type":"address"},{"internalType":"address","name":"token1","type":"address"},{"internalType":"uint256","name":"amountIn0","type":"uint256"},{"internalType":"uint256","name":"amountIn1","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"internalType":"struct ILiquidityVault.Snapshot","name":"snapshot","type":"tuple"}],"name":"verifySnapshot","outputs":[{"internalType":"uint160","name":"snapshotHash","type":"uint160"},{"internalType":"uint96","name":"referralHash","type":"uint96"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]