Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
502 changes: 269 additions & 233 deletions .gas-snapshot

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ pragma solidity ^0.8.18;

import { PaymentCombiner } from "../src/payments/PaymentCombiner.sol";
import { PaymentsFactory } from "../src/payments/PaymentsFactory.sol";
import { ERC1155ItemsFactory } from "../src/tokens/ERC1155/presets/items/ERC1155ItemsFactory.sol";

import { ERC1155ItemsFactory } from "../src/tokens/ERC1155/presets/items/ERC1155ItemsFactory.sol";
import { ERC1155PackFactory } from "../src/tokens/ERC1155/presets/pack/ERC1155PackFactory.sol";
import { ERC1155SoulboundFactory } from "../src/tokens/ERC1155/presets/soulbound/ERC1155SoulboundFactory.sol";
import { ERC1155Holder } from "../src/tokens/ERC1155/utility/holder/ERC1155Holder.sol";
import { ERC1155SaleFactory } from "../src/tokens/ERC1155/utility/sale/ERC1155SaleFactory.sol";

import { ERC20ItemsFactory } from "../src/tokens/ERC20/presets/items/ERC20ItemsFactory.sol";

import { ERC721ItemsFactory } from "../src/tokens/ERC721/presets/items/ERC721ItemsFactory.sol";
import { ERC721SoulboundFactory } from "../src/tokens/ERC721/presets/soulbound/ERC721SoulboundFactory.sol";
import { ERC721SaleFactory } from "../src/tokens/ERC721/utility/sale/ERC721SaleFactory.sol";
Expand Down Expand Up @@ -67,9 +70,11 @@ contract Deploy is SingletonDeployer {
salt,
pk
);
address holder =
_deployIfNotAlready("ERC1155Holder", abi.encodePacked(type(ERC1155Holder).creationCode), salt, pk);
_deployIfNotAlready(
"ERC1155PackFactory",
abi.encodePacked(type(ERC1155PackFactory).creationCode, abi.encode(factoryOwner)),
abi.encodePacked(type(ERC1155PackFactory).creationCode, abi.encode(factoryOwner, holder)),
salt,
pk
);
Expand Down
11 changes: 7 additions & 4 deletions src/tokens/ERC1155/ERC1155BaseToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ abstract contract ERC1155BaseToken is ERC1155Supply, ERC2981Controlled, SignalsI
string public baseURI;
string public contractURI;

/**
* Deploy contract.
*/
constructor() { }
bool private _initialized;

/**
* Initialize the contract.
Expand All @@ -43,6 +40,10 @@ abstract contract ERC1155BaseToken is ERC1155Supply, ERC2981Controlled, SignalsI
address implicitModeValidator,
bytes32 implicitModeProjectId
) internal {
if (_initialized) {
revert InvalidInitialization();
}

name = tokenName;
baseURI = tokenBaseURI;
contractURI = tokenContractURI;
Expand All @@ -52,6 +53,8 @@ abstract contract ERC1155BaseToken is ERC1155Supply, ERC2981Controlled, SignalsI
_grantRole(METADATA_ADMIN_ROLE, owner);

_initializeImplicitMode(owner, implicitModeValidator, implicitModeProjectId);

_initialized = true;
}

//
Expand Down
22 changes: 16 additions & 6 deletions src/tokens/ERC1155/extensions/supply/ERC1155Supply.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ abstract contract ERC1155Supply is ERC1155, IERC1155Supply {

uint256 nMint = _ids.length;
uint256 totalAmount = 0;
for (uint256 i = 0; i < nMint; i++) {
totalAmount += _amounts[i];
tokenSupply[_ids[i]] += _amounts[i];
for (uint256 i; i < nMint;) {
uint256 amount = _amounts[i];
totalAmount += amount;
tokenSupply[_ids[i]] += amount;
unchecked {
// Already checked in super._batchMint
++i;
}
}
totalSupply += totalAmount;
}
Expand Down Expand Up @@ -76,9 +81,14 @@ abstract contract ERC1155Supply is ERC1155, IERC1155Supply {

uint256 nBurn = _ids.length;
uint256 totalAmount = 0;
for (uint256 i = 0; i < nBurn; i++) {
tokenSupply[_ids[i]] -= _amounts[i];
totalAmount += _amounts[i];
for (uint256 i; i < nBurn;) {
uint256 amount = _amounts[i];
tokenSupply[_ids[i]] -= amount;
totalAmount += amount;
unchecked {
// Already checked in super._batchBurn
++i;
}
}
totalSupply -= totalAmount;
}
Expand Down
13 changes: 0 additions & 13 deletions src/tokens/ERC1155/presets/items/ERC1155Items.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ contract ERC1155Items is ERC1155BaseToken, IERC1155Items {

bytes32 internal constant MINTER_ROLE = keccak256("MINTER_ROLE");

address private immutable initializer;
bool private initialized;

constructor() {
initializer = msg.sender;
}

/**
* Initialize the contract.
* @param owner Owner address
Expand All @@ -40,18 +33,12 @@ contract ERC1155Items is ERC1155BaseToken, IERC1155Items {
address implicitModeValidator,
bytes32 implicitModeProjectId
) public virtual {
if (msg.sender != initializer || initialized) {
revert InvalidInitialization();
}

ERC1155BaseToken._initialize(
owner, tokenName, tokenBaseURI, tokenContractURI, implicitModeValidator, implicitModeProjectId
);
_setDefaultRoyalty(royaltyReceiver, royaltyFeeNumerator);

_grantRole(MINTER_ROLE, owner);

initialized = true;
}

//
Expand Down
49 changes: 33 additions & 16 deletions src/tokens/ERC1155/presets/pack/ERC1155Pack.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,20 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {

bytes32 internal constant PACK_ADMIN_ROLE = keccak256("PACK_ADMIN_ROLE");

address public immutable erc1155Holder;

mapping(uint256 => bytes32) public merkleRoot;
mapping(uint256 => uint256) public supply;
mapping(uint256 => uint256) public remainingSupply;

mapping(uint256 => mapping(address => uint256)) internal _commitments;
mapping(address => mapping(uint256 => uint256)) internal _commitments;
mapping(uint256 => mapping(uint256 => uint256)) internal _availableIndices;

constructor() ERC1155Items() { }
constructor(
address _erc1155Holder
) {
erc1155Holder = _erc1155Holder;
}

/// @inheritdoc ERC1155Items
function initialize(
Expand Down Expand Up @@ -56,12 +62,11 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {
function commit(
uint256 packId
) external {
if (_commitments[packId][msg.sender] != 0) {
if (_commitments[msg.sender][packId] != 0) {
revert PendingReveal();
}
_burn(msg.sender, packId, 1);
uint256 revealAfterBlock = block.number + 1;
_commitments[packId][msg.sender] = revealAfterBlock;
_commitments[msg.sender][packId] = block.number + 1;

emit Commit(msg.sender, packId);
}
Expand All @@ -80,21 +85,33 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {
revert InvalidProof();
}

delete _commitments[packId][user];
delete _commitments[user][packId];
remainingSupply[packId]--;

// Point this index to the last index's value
_availableIndices[packId][randomIndex] = _getIndexOrDefault(remainingSupply[packId], packId);

for (uint256 i = 0; i < packContent.tokenAddresses.length; i++) {
for (uint256 i; i < packContent.tokenAddresses.length;) {
address tokenAddr = packContent.tokenAddresses[i];
uint256[] memory tokenIds = packContent.tokenIds[i];
if (packContent.isERC721[i]) {
for (uint256 j = 0; j < packContent.tokenIds[i].length; j++) {
IERC721ItemsFunctions(packContent.tokenAddresses[i]).mint(user, packContent.tokenIds[i][j]);
for (uint256 j; j < tokenIds.length;) {
IERC721ItemsFunctions(tokenAddr).mint(user, tokenIds[j]);
unchecked {
++j;
}
}
} else {
IERC1155ItemsFunctions(packContent.tokenAddresses[i]).batchMint(
user, packContent.tokenIds[i], packContent.amounts[i], ""
);
// Send via the holder fallback if available
address to = user;
if (erc1155Holder != address(0) && msg.sender != user) {
to = erc1155Holder;
}
bytes memory packedData = abi.encode(user);
IERC1155ItemsFunctions(tokenAddr).batchMint(to, tokenIds, packContent.amounts[i], packedData);
}
unchecked {
++i;
}
}

Expand All @@ -103,14 +120,14 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {

/// @inheritdoc IERC1155Pack
function refundPack(address user, uint256 packId) external {
uint256 commitment = _commitments[packId][user];
uint256 commitment = _commitments[user][packId];
if (commitment == 0) {
revert NoCommit();
}
if (uint256(blockhash(commitment)) != 0 || block.number <= commitment) {
revert PendingReveal();
}
delete _commitments[packId][user];
delete _commitments[user][packId];
_mint(user, packId, 1, "");
}

Expand All @@ -125,7 +142,7 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {
revert AllPacksOpened();
}

uint256 commitment = _commitments[packId][user];
uint256 commitment = _commitments[user][packId];
if (commitment == 0) {
revert NoCommit();
}
Expand All @@ -147,7 +164,7 @@ contract ERC1155Pack is ERC1155Items, IERC1155Pack {
function supportsInterface(
bytes4 interfaceId
) public view override returns (bool) {
return type(IERC1155Pack).interfaceId == interfaceId || super.supportsInterface(interfaceId);
return interfaceId == type(IERC1155Pack).interfaceId || super.supportsInterface(interfaceId);
}

}
7 changes: 3 additions & 4 deletions src/tokens/ERC1155/presets/pack/ERC1155PackFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ contract ERC1155PackFactory is IERC1155PackFactory, SequenceProxyFactory {
/**
* Creates an ERC-1155 Pack Factory.
* @param factoryOwner The owner of the ERC-1155 Pack Factory
* @param holderFallback The address of the ERC1155Holder fallback
*/
constructor(
address factoryOwner
) {
ERC1155Pack impl = new ERC1155Pack();
constructor(address factoryOwner, address holderFallback) {
ERC1155Pack impl = new ERC1155Pack(holderFallback);
SequenceProxyFactory._initialize(address(impl), factoryOwner);
}

Expand Down
2 changes: 0 additions & 2 deletions src/tokens/ERC1155/presets/soulbound/ERC1155Soulbound.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ contract ERC1155Soulbound is ERC1155Items, IERC1155Soulbound {

bool internal _transferLocked;

constructor() ERC1155Items() { }

/// @inheritdoc ERC1155Items
function initialize(
address owner,
Expand Down
114 changes: 114 additions & 0 deletions src/tokens/ERC1155/utility/holder/ERC1155Holder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

import { IERC1155 } from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sol";
import { IERC1155Receiver, IERC165 } from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol";

/**
* An ERC-1155 contract that allows permissive minting.
*/
contract ERC1155Holder is IERC1155Receiver {

/// @dev Emitted when a claim is added.
event ClaimAdded(address claimant, address tokenAddress, uint256 tokenId, uint256 amount);
/// @dev Emitted when a batch of claims is added.
event ClaimAddedBatch(address claimant, address tokenAddress, uint256[] tokenIds, uint256[] amounts);

/// @dev Emitted when a claim is claimed.
event Claimed(address claimant, address tokenAddress, uint256 tokenId, uint256 amount);
/// @dev Emitted when a batch of claims is claimed.
event ClaimedBatch(address claimant, address tokenAddress, uint256[] tokenIds, uint256[] amounts);

/// @dev Error thrown when the claimant is invalid.
error InvalidClaimant();

/// @dev claimant -> tokenAddress -> tokenId -> amount
mapping(address => mapping(address => mapping(uint256 => uint256))) public claims;

/// @dev Claims a token.
/// @param claimant The claimant.
/// @param tokenAddress The token address.
/// @param tokenId The token id.
function claim(address claimant, address tokenAddress, uint256 tokenId) public {
uint256 amount = claims[claimant][tokenAddress][tokenId];
delete claims[claimant][tokenAddress][tokenId];
emit Claimed(claimant, tokenAddress, tokenId, amount);
IERC1155(tokenAddress).safeTransferFrom(address(this), claimant, tokenId, amount, "");
}

/// @dev Claims a batch of tokens.
/// @param claimant The claimant.
/// @param tokenAddress The token address.
/// @param tokenIds The token ids.
function claimBatch(address claimant, address tokenAddress, uint256[] memory tokenIds) public {
uint256[] memory amounts = new uint256[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
amounts[i] = claims[claimant][tokenAddress][tokenIds[i]];
delete claims[claimant][tokenAddress][tokenIds[i]];
}
emit ClaimedBatch(claimant, tokenAddress, tokenIds, amounts);
IERC1155(tokenAddress).safeBatchTransferFrom(address(this), claimant, tokenIds, amounts, "");
}

/// @inheritdoc IERC1155Receiver
/// @param claimData The encoded claimant.
function onERC1155Received(
address,
address,
uint256 tokenId,
uint256 amount,
bytes calldata claimData
) public virtual override returns (bytes4) {
address claimant = _decodeClaimant(claimData);
address tokenAddress = msg.sender;
claims[claimant][tokenAddress][tokenId] += amount;
emit ClaimAdded(claimant, tokenAddress, tokenId, amount);
return this.onERC1155Received.selector;
}

/// @inheritdoc IERC1155Receiver
/// @param claimData The encoded claimant.
function onERC1155BatchReceived(
address,
address,
uint256[] calldata tokenIds,
uint256[] calldata amounts,
bytes calldata claimData
) public virtual override returns (bytes4) {
address claimant = _decodeClaimant(claimData);
address tokenAddress = msg.sender;
for (uint256 i = 0; i < tokenIds.length; i++) {
claims[claimant][tokenAddress][tokenIds[i]] += amounts[i];
}
emit ClaimAddedBatch(claimant, tokenAddress, tokenIds, amounts);
return this.onERC1155BatchReceived.selector;
}

/// @dev Decodes the claimant from the claim data.
function _decodeClaimant(
bytes calldata claimData
) internal pure returns (address claimant) {
if (claimData.length == 20) {
// Packed address format
assembly {
calldatacopy(0, claimData.offset, 20)
claimant := shr(96, mload(0))
}
} else if (claimData.length == 32) {
// ABI encoded address format
(claimant) = abi.decode(claimData, (address));
}
if (claimant == address(0)) {
revert InvalidClaimant();
}
return claimant;
}

/// @inheritdoc IERC165
function supportsInterface(
bytes4 interfaceId
) public view virtual override(IERC165) returns (bool) {
return interfaceId == type(IERC1155Receiver).interfaceId || interfaceId == type(IERC165).interfaceId;
}

}
Loading
Loading