Description:
Multi-signature wallet contract requiring multiple confirmations for transaction execution.
Blockchain: Ethereum
Source Code: View Code On The Blockchain
Solidity Source Code:
{{
"language": "Solidity",
"sources": {
"contracts/MidnightBreezeV2.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "@limitbreak/creator-token-standards/src/erc721c/ERC721C.sol";
import "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
/*
██████████ █████ █████ █████ ███ █████
▒███▒▒▒▒███ ▒▒███ ▒▒███ ▒▒███ ▒▒▒ ▒▒███
▒███ ▒▒███ █████ ████ ███████ ██████ ▒███████ ███████ ████ ███████ ██████
▒███ ▒███▒▒███ ▒███ ▒▒▒███▒ ███▒▒███ ▒███▒▒███ ▒▒▒███▒ ▒▒███ ███▒▒███ ███▒▒███
▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒▒▒ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███████
▒███ ███ ▒███ ▒███ ▒███ ███▒███ ███ ▒███ ▒███ ▒███ ███ ▒███ ▒███ ▒███ ▒███▒▒▒
██████████ ▒▒████████ ▒▒█████ ▒▒██████ ████ █████ ▒▒█████ █████▒▒████████▒▒██████
▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒
█████ █████
▒▒███ ▒▒███
▒▒███ ███
▒▒█████
███▒███
███ ▒▒███
█████ █████
▒▒▒▒▒ ▒▒▒▒▒
███████████ █████ ████ █████
▒███▒▒▒▒▒███ ▒▒███ ▒▒███ ▒▒███
▒███ ▒███ ██████ ▒███████ ▒███ ██████ ███████ ██████ █████ █████
▒██████████ ▒▒▒▒▒███ ▒███▒▒███ ▒███ ███▒▒███ ███▒▒███ ███▒▒███▒▒███ ▒▒███
▒███▒▒▒▒▒▒ ███████ ▒███ ▒███ ▒███ ▒███ ▒███▒███ ▒███ ▒███████ ▒███ ▒███
▒███ ███▒▒███ ▒███ ▒███ ▒███ ▒███ ▒███▒███ ▒███ ▒███▒▒▒ ▒▒███ ███
█████ ▒▒████████ ████████ █████▒▒██████ ▒▒████████▒▒██████ ▒▒█████
▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒
██████ ██████ ███ █████ ███ █████ █████ ███████████ ████████
▒▒██████ ██████ ▒▒▒ ▒▒███ ▒▒▒ ▒▒███ ▒▒███ ▒▒███▒▒▒▒▒███ ███▒▒▒▒███
▒███▒█████▒███ ████ ███████ ████████ ████ ███████ ▒███████ ███████ ▒███ ▒███ ████████ ██████ ██████ █████████ ██████ ▒▒▒ ▒███
▒███▒▒███ ▒███ ▒▒███ ███▒▒███ ▒▒███▒▒███ ▒▒███ ███▒▒███ ▒███▒▒███ ▒▒▒███▒ ▒██████████ ▒▒███▒▒███ ███▒▒███ ███▒▒███ ▒█▒▒▒▒███ ███▒▒███ ███████
▒███ ▒▒▒ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███▒▒▒▒▒███ ▒███ ▒▒▒ ▒███████ ▒███████ ▒ ███▒ ▒███████ ███▒▒▒▒
▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ███ ▒███ ▒███ ▒███ ▒███▒▒▒ ▒███▒▒▒ ███▒ █▒███▒▒▒ ███ █
█████ █████ █████▒▒████████ ████ █████ █████▒▒███████ ████ █████ ▒▒█████ ███████████ █████ ▒▒██████ ▒▒██████ █████████▒▒██████ ▒██████████
▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒███▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒▒▒
███ ▒███
▒▒██████
▒▒▒▒▒▒
*/
contract MidnightBreezeV2 is
ERC721C,
BasicRoyalties,
OwnableBasic,
ReentrancyGuard
{
struct Auction {
uint256 startBlock;
uint256 endBlock;
uint256 discountRate;
uint256 startingPrice;
uint256 minPrice;
uint256 lastPrice;
uint256 amountPurchased;
uint256 totalPaid;
bool active;
}
string public upgradableTokensURI;
string public publicMintTokensURI;
address private devpablo = 0x7e41cb2eCA64793532d6730b38d10575fD62B37F;
address private devasto = 0x0B884DfbadE931b8eA5DB16Cc28434EC23f4054E;
address private dutchtide = 0x11c6AFEB38B7B31a0E997AaaC9A16538b86CDE63;
address private derak = 0x5D8F48b84937aeEEe870E4376821956303F79903;
address private V1Address;
address private burnAddress = 0x0000000000000000000000000000000000000001;
bool public oneForOneBurnStarted = false;
bool public oneForOneClaimStarted = false;
bool public travelersWhitelistStarted = false;
bool public dedicatedWhitelistStarted = false;
bool public twoForOneMintStarted = false;
bytes32 public travelersMerkleRoot = bytes32(0);
bytes32 public dedicatedMerkleRoot = bytes32(0);
uint256 public constant MAX_SUPPLY = 10000;
uint256 public constant UPGRADABLE_SUPPLY = 6969;
uint256 public constant PUBLIC_START_ID = UPGRADABLE_SUPPLY + 1;
uint256 public travelersReserve = 400;
uint256 public dedicatedReserve = 100;
uint256 public constant MAX_PER_MINT = 69;
uint256 public nextPublicId = PUBLIC_START_ID;
uint256 public totalMintedPublic = 0;
uint256 public totalMintedTravelers = 0;
uint256 public dedicatedPrice = 0;
uint256 public travelerPrice = 0;
mapping(address => uint256) public travelersWhitelistMinted;
mapping(uint256 => Auction) public auctions;
mapping(address => mapping(uint256 => uint256)) public auctionParticipation;
mapping(address => mapping(uint256 => uint256)) public auctionAmountPaid;
mapping(address => uint256[]) private V1BreezesBurned;
uint256 private auctionCount = 0;
bool public transfersBlocked = true;
constructor(
string memory baseURI,
address _V1Address
)
ERC721OpenZeppelin("MidnightBreezeV2", "MBV2")
BasicRoyalties(msg.sender, 0) // every 100 is 1%
{
upgradableTokensURI = baseURI;
publicMintTokensURI = baseURI;
V1Address = _V1Address;
}
function setURI(
string memory _upgradableTokensURI,
string memory _publicMintTokensURI
) external {
_requireCallerIsContractOwner();
upgradableTokensURI = _upgradableTokensURI;
publicMintTokensURI = _publicMintTokensURI;
}
function tokenURI(
uint256 _tokenId
) public view override returns (string memory) {
require(_exists(_tokenId), "Token does not exist.");
if (_tokenId <= UPGRADABLE_SUPPLY) {
return
string(
abi.encodePacked(
upgradableTokensURI,
Strings.toString(_tokenId)
)
);
} else {
return
string(
abi.encodePacked(
publicMintTokensURI,
Strings.toString(_tokenId)
)
);
}
}
function createAuction(
uint256 startBlock,
uint256 endBlock,
uint256 discountRate,
uint256 startingPrice,
uint256 minPrice
) external {
_requireCallerIsContractOwner();
require(minPrice > 0, "Min price can't reach zero");
require(
startingPrice > minPrice,
"Start price must be higher than min price"
);
require(
startBlock >= block.number,
"Can't start an auction in the past"
);
require(startBlock < endBlock, "Start block must be before end block");
auctions[auctionCount] = Auction({
startBlock: startBlock,
endBlock: endBlock,
discountRate: discountRate,
startingPrice: startingPrice,
minPrice: minPrice,
lastPrice: startingPrice,
amountPurchased: 0,
totalPaid: 0,
active: true
});
auctionCount++;
}
function stopAuction(uint256 auctionId) external {
_requireCallerIsContractOwner();
auctions[auctionId].active = false;
}
function getAuctionPrice(uint256 auctionId) public view returns (uint256) {
Auction storage auction = auctions[auctionId];
require(block.number >= auction.startBlock, "Auction not started");
require(block.number <= auction.endBlock, "Auction ended");
require(auction.active, "Auction disabled");
uint256 elapsedBlocks = block.number - auction.startBlock;
uint256 discount = auction.discountRate * elapsedBlocks;
uint256 price = auction.startingPrice > discount
? auction.startingPrice - discount
: auction.minPrice; //uint can't deal with negative values...
return price >= auction.minPrice ? price : auction.minPrice;
}
function _mintPublicTo(address to) internal {
require(nextPublicId <= MAX_SUPPLY, "No public supply left");
_safeMint(to, nextPublicId);
nextPublicId++;
}
function auctionMint(
uint256 auctionId,
uint256 mintAmount
) external payable nonReentrant {
Auction storage auction = auctions[auctionId];
require(auction.active, "Auction not active");
require(
mintAmount > 0 && mintAmount <= MAX_PER_MINT,
"Invalid mint amount"
);
require(
block.number >= auction.startBlock &&
block.number <= auction.endBlock,
"Invalid auction period"
);
require(
nextPublicId + mintAmount - 1 <=
MAX_SUPPLY - travelersReserve - dedicatedReserve,
"Auctionable supply depleted"
);
uint256 price = getAuctionPrice(auctionId);
uint256 totalCost = price * mintAmount;
require(msg.value >= totalCost, "Insufficient payment");
for (uint256 i = 0; i < mintAmount; i++) {
_mintPublicTo(msg.sender);
}
// track participation and payments
auctionParticipation[msg.sender][auctionId] += mintAmount;
auctionAmountPaid[msg.sender][auctionId] += totalCost;
auction.lastPrice = price;
auction.amountPurchased += mintAmount;
auction.totalPaid += totalCost;
// refund any overpayment
uint256 over = msg.value - totalCost;
if (over > 0) {
(bool ok, ) = msg.sender.call{value: over}("");
require(ok, "Refund failed");
}
}
function claimAuctionRefund(uint256 auctionId) external nonReentrant {
uint256 paid = auctionAmountPaid[msg.sender][auctionId];
require(paid > 0, "No refund due");
uint256 purchased = auctionParticipation[msg.sender][auctionId];
require(purchased > 0, "No auction purchase recorded");
uint256 last = auctions[auctionId].lastPrice;
uint256 owed = last * purchased;
require(paid > owed, "No refund due");
uint256 refundable = paid - owed;
auctionAmountPaid[msg.sender][auctionId] = owed;
auctions[auctionId].totalPaid -= refundable;
(bool sent, ) = msg.sender.call{value: refundable}("");
require(sent, "Refund transfer failed");
}
event OneForOneBurn(address from, uint256[] burned);
event OneForOneClaim(address from, uint256[] upgraded);
event TwoForOneMint(address from, uint256[] upgraded, uint256[] burned);
function oneForOneBurn(uint[] memory toBurn) external nonReentrant {
require(oneForOneBurnStarted, "One for one burn has not started");
require(!twoForOneMintStarted, "Two for one mint has started");
require(toBurn.length > 0, "Empty burn array");
for (uint i = 0; i < toBurn.length; i++) {
IERC721(V1Address).safeTransferFrom(
_msgSender(),
burnAddress,
toBurn[i]
);
V1BreezesBurned[msg.sender].push(toBurn[i]);
}
emit OneForOneBurn(msg.sender, toBurn);
}
function claimBurnedBreezes(uint256 count) external nonReentrant {
require(oneForOneClaimStarted, "One for one claim has not started");
uint256 len = V1BreezesBurned[msg.sender].length;
require(len > 0, "Nothing to claim");
require(count > 0 && count <= len, "Invalid count");
uint256[] memory claimed = new uint256[](count);
for (uint256 i = 0; i < count; i++) {
uint256 tokenId = V1BreezesBurned[msg.sender][i];
_safeMint(_msgSender(), tokenId);
claimed[i] = tokenId;
}
emit OneForOneClaim(msg.sender, claimed);
for (uint256 i = count; i < len; i++) {
V1BreezesBurned[msg.sender][i - count] = V1BreezesBurned[
msg.sender
][i];
}
for (uint256 i = 0; i < count; i++) {
V1BreezesBurned[msg.sender].pop();
}
}
function twoForOneMint(
uint[] memory toUpgrade,
uint[] memory toBurn
) external nonReentrant {
require(twoForOneMintStarted, "Two for one mint has not started");
require(toUpgrade.length == toBurn.length, "Arrays must match");
require(toUpgrade.length > 0, "Empty upgrade array");
for (uint i = 0; i < toUpgrade.length; i++) {
IERC721(V1Address).safeTransferFrom(
_msgSender(),
burnAddress,
toBurn[i]
);
IERC721(V1Address).safeTransferFrom(
_msgSender(),
burnAddress,
toUpgrade[i]
);
_safeMint(_msgSender(), toUpgrade[i]);
}
emit TwoForOneMint(msg.sender, toUpgrade, toBurn);
}
function travelersWhitelistMint(
bytes32[] calldata proof
) external payable nonReentrant {
require(
travelersWhitelistStarted,
"Travelers whitelist mint not started"
);
require(travelerPrice > 0, "Travelers price not set");
require(
travelersWhitelistMinted[msg.sender] == 0,
"Traveler already minted"
);
require(
totalMintedTravelers + 1 <= travelersReserve,
"Travelers supply depleted"
);
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(
MerkleProof.verify(proof, travelersMerkleRoot, leaf),
"Invalid whitelist proof"
);
require(msg.value == travelerPrice, "Incorrect payment");
// ensure there's at least one public token available
_mintPublicTo(msg.sender);
travelersWhitelistMinted[msg.sender] += 1;
totalMintedTravelers += 1;
}
function dedicatedWhitelistMint(
uint256 mintAmount,
bytes32[] calldata proof
) external payable nonReentrant {
require(
dedicatedWhitelistStarted,
"Dedicated whitelist mint not started"
);
require(
!travelersWhitelistStarted,
"Traveler whitelist mint still ongoing"
);
require(dedicatedPrice > 0, "Dedicated price not set");
require(
nextPublicId + mintAmount - 1 <= MAX_SUPPLY,
"Dedicated supply exceeded"
);
bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
require(
MerkleProof.verify(proof, dedicatedMerkleRoot, leaf),
"Invalid whitelist proof"
);
require(msg.value == mintAmount * dedicatedPrice, "Incorrect payment");
for (uint256 i = 0; i < mintAmount; i++) {
_mintPublicTo(msg.sender);
}
}
function batchTransferFrom(
address _from,
address _to,
uint256[] memory _tokenIds
) public {
for (uint256 i = 0; i < _tokenIds.length; i++) {
transferFrom(_from, _to, _tokenIds[i]);
}
}
function batchSafeTransferFrom(
address _from,
address _to,
uint256[] memory _tokenIds,
bytes memory data_
) public {
for (uint256 i = 0; i < _tokenIds.length; i++) {
safeTransferFrom(_from, _to, _tokenIds[i], data_);
}
}
function getBurned(address user) external view returns (uint256[] memory) {
return V1BreezesBurned[user];
}
function setTravelersMerkleRoot(bytes32 root) external {
_requireCallerIsContractOwner();
require(root != bytes32(0), "Invalid root");
travelersMerkleRoot = root;
}
function setDedicatedMerkleRoot(bytes32 root) external {
_requireCallerIsContractOwner();
require(root != bytes32(0), "Invalid root");
dedicatedMerkleRoot = root;
}
function setTravelersPrice(uint price) external {
_requireCallerIsContractOwner();
require(price > 0, "Price can't be zero");
travelerPrice = price;
}
function setDedicatedPrice(uint price) external {
_requireCallerIsContractOwner();
require(price > 0, "Price can't be zero");
dedicatedPrice = price;
}
function setTravelersReserve(uint amount) external {
_requireCallerIsContractOwner();
travelersReserve = amount;
}
function setDedicatedReserve(uint amount) external {
_requireCallerIsContractOwner();
dedicatedReserve = amount;
}
function startTravelersMint() external {
_requireCallerIsContractOwner();
require(travelerPrice > 0, "Set price first!");
require(travelersMerkleRoot != bytes32(0), "Set root first!");
travelersWhitelistStarted = true;
}
function stopTravelersMint() external {
_requireCallerIsContractOwner();
travelersWhitelistStarted = false;
}
function startDedicatedMint() external {
_requireCallerIsContractOwner();
require(dedicatedPrice > 0, "Set price first!");
require(dedicatedMerkleRoot != bytes32(0), "Set root first!");
require(!travelersWhitelistStarted, "Stop traveler mint first");
dedicatedWhitelistStarted = true;
}
function stopDedicatedMint() external {
_requireCallerIsContractOwner();
dedicatedWhitelistStarted = false;
}
function startOneForOneBurning() external {
_requireCallerIsContractOwner();
oneForOneBurnStarted = true;
}
function stopOneForOneBurning() external {
_requireCallerIsContractOwner();
oneForOneBurnStarted = false;
}
function startTwoForOneMint() external {
_requireCallerIsContractOwner();
twoForOneMintStarted = true;
}
function stopTwoForOneMint() external {
_requireCallerIsContractOwner();
twoForOneMintStarted = false;
}
function startOneForOneClaiming() external {
_requireCallerIsContractOwner();
oneForOneClaimStarted = true;
}
function stopOneForOneClaiming() external {
_requireCallerIsContractOwner();
oneForOneClaimStarted = false;
}
// Returns the maximum refund liability for a single auction.
// - Active auction: conservatively assume lastPrice may drop to minPrice (worst-case).
// - Ended auction: lastPrice is final.
function auctionMaxRefundLiability(
uint256 auctionId
) public view returns (uint256) {
Auction storage a = auctions[auctionId];
// Determine which price to use for refund liability
uint256 priceForLiability;
if (
a.active &&
block.number <= a.endBlock &&
block.number >= a.startBlock
) {
// Active auction: future buyers may lower lastPrice, use minPrice conservatively
priceForLiability = a.minPrice;
} else {
// Ended auction: lastPrice is final
priceForLiability = a.lastPrice;
}
// Refundable amount = totalPaid - priceForLiability * total minted in this auction
if (a.totalPaid > priceForLiability * a.amountPurchased) {
return a.totalPaid - priceForLiability * a.amountPurchased;
}
return 0;
}
//Returns sum of all auction refund liabilities (conservative)
function totalAuctionLiabilities() public view returns (uint256) {
uint256 sum = 0;
for (uint256 i = 0; i < auctionCount; i++) {
sum += auctionMaxRefundLiability(i);
}
return sum;
}
//Maximum safe withdrawable amount from contract
function withdrawable() public view returns (uint256) {
uint256 bal = address(this).balance;
uint256 liabilities = totalAuctionLiabilities();
if (bal > liabilities) {
return bal - liabilities;
}
return 0;
}
//Withdraw funds safely, leaving enough ETH to cover refunds
function withdrawSafe() external nonReentrant {
_requireCallerIsContractOwner();
uint256 available = withdrawable();
require(available > 0, "No withdrawable funds");
uint256 devpablo_fee = (available * 75) / 1000;
uint256 devasto_fee = (available * 75) / 1000;
uint256 derak_fee = (available * 5) / 1000;
uint256 remaining = available - devpablo_fee - devasto_fee - derak_fee;
(bool ok1, ) = payable(dutchtide).call{value: remaining}("");
require(ok1, "Transfer failed");
(bool ok2, ) = payable(devpablo).call{value: devpablo_fee}("");
require(ok2, "Transfer failed");
(bool ok3, ) = payable(devasto).call{value: devasto_fee}("");
require(ok3, "Transfer failed");
(bool ok4, ) = payable(derak).call{value: derak_fee}("");
require(ok4, "Transfer failed");
}
function supportsInterface(
bytes4 interfaceId
) public view virtual override(ERC721C, ERC2981) returns (bool) {
return super.supportsInterface(interfaceId);
}
function setDefaultRoyalty(address receiver, uint96 feeNumerator) public {
_requireCallerIsContractOwner();
_setDefaultRoyalty(receiver, feeNumerator);
}
function setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) public {
_requireCallerIsContractOwner();
_setTokenRoyalty(tokenId, receiver, feeNumerator);
}
function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId,
uint256 batchSize
) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId, batchSize);
// Allow minting (from 0 address) and burning (to 0 address)
if (from != address(0) && to != address(0)) {
require(!transfersBlocked, "Transfers are currently disabled");
}
}
function approve(address to, uint256 tokenId) public virtual override {
require(!transfersBlocked, "Approvals are currently disabled");
super.approve(to, tokenId);
}
function setApprovalForAll(
address operator,
bool approved
) public virtual override {
require(!transfersBlocked, "Approvals are currently disabled");
super.setApprovalForAll(operator, approved);
}
function startTransfers() external {
_requireCallerIsContractOwner();
transfersBlocked = false;
}
function stopTransfers() external {
_requireCallerIsContractOwner();
transfersBlocked = true;
}
}
"
},
"@limitbreak/creator-token-standards/src/access/OwnableBasic.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./OwnablePermissions.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract OwnableBasic is OwnablePermissions, Ownable {
function _requireCallerIsContractOwner() internal view virtual override {
_checkOwner();
}
}
"
},
"@openzeppelin/contracts/security/ReentrancyGuard.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be _NOT_ENTERED
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
}
"
},
"@openzeppelin/contracts/utils/cryptography/MerkleProof.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
library MerkleProof {
/**
* @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
* defined by `root`. For this, a `proof` must be provided, containing
* sibling hashes on the branch from the leaf to the root of the tree. Each
* pair of leaves and each pair of pre-images are assumed to be sorted.
*/
function verify(
bytes32[] memory proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(
bytes32[] calldata proof,
bytes32 root,
bytes32 leaf
) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuild the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proof.length - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value for the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i] ? leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++] : proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
return hashes[totalHashes - 1];
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
"
},
"@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
/**
* @title BasicRoyaltiesBase
* @author Limit Break, Inc.
* @dev Base functionality of an NFT mix-in contract implementing the most basic form of programmable royalties.
*/
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
/**
* @title BasicRoyalties
* @author Limit Break, Inc.
* @notice Constructable BasicRoyalties Contract implementation.
*/
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}
/**
* @title BasicRoyaltiesInitializable
* @author Limit Break, Inc.
* @notice Initializable BasicRoyalties Contract implementation to allow for EIP-1167 clones.
*/
abstract contract BasicRoyaltiesInitializable is BasicRoyaltiesBase {}"
},
"@limitbreak/creator-token-standards/src/erc721c/ERC721C.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/AutomaticValidatorTransferApproval.sol";
import "../utils/CreatorTokenBase.sol";
import "../token/erc721/ERC721OpenZeppelin.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
import {TOKEN_TYPE_ERC721} from "@limitbreak/permit-c/src/Constants.sol";
/**
* @title ERC721C
* @author Limit Break, Inc.
* @notice Extends OpenZeppelin's ERC721 implementation with Creator Token functionality, which
* allows the contract owner to update the transfer validation logic by managing a security policy in
* an external transfer validation security policy registry. See {CreatorTokenTransferValidator}.
*/
abstract contract ERC721C is ERC721OpenZeppelin, CreatorTokenBase, AutomaticValidatorTransferApproval {
/**
* @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved
* for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
/**
* @notice Indicates whether the contract implements the specified interface.
* @dev Overrides supportsInterface in ERC165.
* @param interfaceId The interface id
* @return true if the contract implements the specified interface, false otherwise
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateBeforeTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateAfterTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC721);
}
}
/**
* @title ERC721CInitializable
* @author Limit Break, Inc.
* @notice Initializable implementation of ERC721C to allow for EIP-1167 proxy clones.
*/
abstract contract ERC721CInitializable is ERC721OpenZeppelinInitializable, CreatorTokenBase, AutomaticValidatorTransferApproval {
function initializeERC721(string memory name_, string memory symbol_) public override {
super.initializeERC721(name_, symbol_);
_emitDefaultTransferValidator();
_registerTokenType(getTransferValidator());
}
/**
* @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved
* for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
/**
* @notice Indicates whether the contract implements the specified interface.
* @dev Overrides supportsInterface in ERC165.
* @param interfaceId The interface id
* @return true if the contract implements the specified interface, false otherwise
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
/// @dev Ties the open-zeppelin _beforeTokenTransfer hook to more granular transfer validation logic
function _beforeTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateBeforeTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
/// @dev Ties the open-zeppelin _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfer(
address from,
address to,
uint256 firstTokenId,
uint256 batchSize) internal virtual override {
for (uint256 i = 0; i < batchSize;) {
_validateAfterTransfer(from, to, firstTokenId + i);
unchecked {
++i;
}
}
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC721);
}
}"
},
"@openzeppelin/contracts/token/common/ERC2981.sol": {
"content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}
"
},
"@limitbreak/permit-c/src/Constants.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Constant bytes32 value of 0x000...000
bytes32 constant ZERO_BYTES32 = bytes32(0);
/// @dev Constant value of 0
uint256 constant ZERO = 0;
/// @dev Constant value of 1
uint256 constant ONE = 1;
/// @dev Constant value representing an open order in storage
uint8 constant ORDER_STATE_OPEN = 0;
/// @dev Constant value representing a filled order in storage
uint8 constant ORDER_STATE_FILLED = 1;
/// @dev Constant value representing a cancelled order in storage
uint8 constant ORDER_STATE_CANCELLED = 2;
/// @dev Constant value representing the ERC721 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC721 = 721;
/// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC1155 = 1155;
/// @dev Constant value representing the ERC20 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC20 = 20;
/// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s`
bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @dev EIP-712 typehash used for validating signature based stored approvals
bytes32 constant UPDATE_APPROVAL_TYPEHASH =
keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit without additional data
bytes32 constant SINGLE_USE_PERMIT_TYPEHASH =
keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit with additional data
string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB =
"PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills
string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB =
"PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev Pausable flag for stored approval transfers of ERC721 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0;
/// @dev Pausable flag for stored approval transfers of ERC1155 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1;
/// @dev Pausable flag for stored approval transfers of ERC20 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2;
/// @dev Pausable flag for single use permit transfers of ERC721 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3;
/// @dev Pausable flag for single use permit transfers of ERC1155 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4;
/// @dev Pausable flag for single use permit transfers of ERC20 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5;
/// @dev Pausable flag for order fill transfers of ERC1155 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6;
/// @dev Pausable flag for order fill transfers of ERC20 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;"
},
"@limitbreak/creator-token-standards/src/interfaces/ITransferValidatorSetTokenType.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidatorSetTokenType {
function setTokenTypeOfCollection(address collection, uint16 tokenType) external;
}"
},
"@limitbreak/creator-token-standards/src/token/erc721/ERC721OpenZeppelin.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../../access/OwnablePermissions.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
abstract contract ERC721OpenZeppelinBase is ERC721 {
// Token name
string internal _contractName;
// Token symbol
string internal _contractSymbol;
function name() public view virtual override returns (string memory) {
return _contractName;
}
function symbol() public view virtual override returns (string memory) {
return _contractSymbol;
}
function _setNameAndSymbol(string memory name_, string memory symbol_) internal {
_contractName = name_;
_contractSymbol = symbol_;
}
}
abstract contract ERC721OpenZeppelin is ERC721OpenZeppelinBase {
constructor(string memory name_, string memory symbol_) ERC721("", "") {
_setNameAndSymbol(name_, symbol_);
}
}
abstract contract ERC721OpenZeppelinInitializable is OwnablePermissions, ERC721OpenZeppelinBase {
error ERC721OpenZeppelinInitializable__AlreadyInitializedERC721();
/// @notice Specifies whether or not the contract is initialized
bool private _erc721Initialized;
/// @dev Initializes parameters of ERC721 tokens.
/// These cannot be set in the constructor because this contract is optionally compatible with EIP-1167.
function initializeERC721(string memory name_, string memory symbol_) public virtual {
_requireCallerIsContractOwner();
if(_erc721Initialized) {
revert ERC721OpenZeppelinInitializable__AlreadyInitializedERC721();
}
_erc721Initialized = true;
_setNameAndSymbol(name_, symbol_);
}
}
"
},
"@limitbreak/creator-token-standards/src/utils/CreatorTokenBase.sol": {
"content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
import "../interfaces/ICreatorToken.sol";
import "../interfaces/ICreatorTokenLegacy.sol";
import "../interfaces/ITransferValidator.sol";
import "./TransferValidation.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
/**
* @title CreatorTokenBase
* @author Limit Break, Inc.
* @notice CreatorTokenBaseV3 is an abstract contract that provides basic functionality for managing token
* transfer policies through an implementation of ICreatorTokenTransferValidator/ICreatorTokenTransferValidatorV2/ICreatorTokenTransferValidatorV3.
* This contract is intended to be used as a base for creator-specific token contracts, enabling customizable transfer
* restrictions and security policies.
*
* <h4>Features:</h4>
* <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul>
* <ul>TransferValidation: Implements the basic token transfer validation interface.</ul>
*
* <h4>Benefits:</h4>
* <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul>
* <ul>Allows creators to enforce policies such as account and codehash blacklists, whitelists, and graylists.</ul>
* <ul>Can be easily integrated into other token contracts as a base contract.</ul>
*
* <h4>Intended Usage:</h4>
* <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and
* security policies.</ul>
* <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the
* creator token.</ul>
*
* <h4>Compatibility:</h4>
* <ul>Backward and Forward Compatible - V1/V2/V3 Creator Token Base will work with V1/V2/V3 Transfer Validators.</ul>
*/
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
/// @dev Thrown when setting a transfer validator address that has no deployed code.
error CreatorTokenBase__InvalidTransferValidatorContract();
/// @dev The default transfer validator that will be used if no transfer validator has been set by the creator.
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x721C008fdff27BF06E7E123956E2Fe03B63342e3);
/// @dev Used to determine if the default transfer validator is applied.
/// @dev Set to true when the creator sets a transfer validator address.
bool private isValidatorInitialized;
/// @dev Address of the transfer validator to apply to transactions.
address private transferValidator;
constructor() {
_emitDefaultTransferValidator();
_registerTokenType(DEFAULT_TRANSFER_VALIDATOR);
}
/**
* @notice Sets the transfer validator for the token contract.
*
* @dev Throws when provided validator contract is not the zero address and does not have code.
* @dev Throws when the caller is not the contract owner.
*
* @dev <h4>Postconditions:</h4>
* 1. The transferValidator address is updated.
* 2. The `TransferValidatorUpdated` event is emitted.
*
* @param transferValidator_ The address of the transfer validator contract.
*/
function setTransferValidator(address transferValidator_) public {
_requireCallerIsContractOwner();
bool isValidTransferValidator = transferValidator_.code.length > 0;
if(transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(getTransferValidator()), transferValidator_);
isValidatorInitialized = true;
transferValidator = transferValidator_;
_registerTokenType(transferValidator_);
}
/**
* @notice Returns the transfer validator contract address for this token contract.
*/
function getTransferValidator() public view override returns (address validator) {
validator = transferValidator;
if (validator =
Submitted on: 2025-09-30 17:09:28
Comments
Log in to comment.
No comments yet.