Skip to content

Commit

Permalink
Add ERC1155OperatorEnforced
Browse files Browse the repository at this point in the history
  • Loading branch information
ScreamingHawk committed Dec 5, 2024
1 parent 67e750f commit a447b5d
Show file tree
Hide file tree
Showing 7 changed files with 519 additions and 2 deletions.
2 changes: 2 additions & 0 deletions scripts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const DEPLOYABLE_CONTRACT_NAMES = [
'ERC1155ItemsFactory',
'ERC1155SaleFactory',
'ERC1155SoulboundFactory',
'ERC1155OperatorEnforcedFactory',
'PaymentCombiner',
'PaymentsFactory',
'Clawback',
Expand All @@ -22,5 +23,6 @@ export const PROXIED_TOKEN_CONTRACT_NAMES = [
'ERC1155Items',
'ERC1155Sale',
'ERC1155Soulbound',
'ERC1155OperatorEnforced',
'Payments',
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

import {ERC1155Items} from "@0xsequence/contracts-library/tokens/ERC1155/presets/items/ERC1155Items.sol";
import {OperatorAllowlistEnforced} from
"@0xsequence/contracts-library/tokens/common/immutable/OperatorAllowlistEnforced.sol";

/**
* An implementation of ERC-1155 that prevents transfers.
*/
contract ERC1155OperatorEnforced is ERC1155Items, OperatorAllowlistEnforced {
constructor() ERC1155Items() {}

/**
* Initialize the contract.
* @param owner Owner address
* @param tokenName Token name
* @param tokenBaseURI Base URI for token metadata
* @param tokenContractURI Contract URI for token metadata
* @param royaltyReceiver Address of who should be sent the royalty payment
* @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500)
* @param operatorAllowlist Address of the operator allowlist
* @dev This should be called immediately after deployment.
*/
function initialize(
address owner,
string memory tokenName,
string memory tokenBaseURI,
string memory tokenContractURI,
address royaltyReceiver,
uint96 royaltyFeeNumerator,
address operatorAllowlist
) public virtual {
_setOperatorAllowlistRegistry(operatorAllowlist);
ERC1155Items.initialize(owner, tokenName, tokenBaseURI, tokenContractURI, royaltyReceiver, royaltyFeeNumerator);
}

//
// Operator Allowlist
//

/**
* Set the operator allowlist registry.
* @param operatorAllowlist Address of the operator allowlist
*/
function setOperatorAllowlistRegistry(address operatorAllowlist) external onlyRole(DEFAULT_ADMIN_ROLE) {
_setOperatorAllowlistRegistry(operatorAllowlist);
}

function setApprovalForAll(address operator, bool approved) public override validateApproval(operator) {
super.setApprovalForAll(operator, approved);
}

function _safeTransferFrom(address from, address to, uint256 id, uint256 amount) internal virtual override {
if (from != address(0)) {
// Ignore validation on minting
_validateTransfer(from, to);
}
super._safeTransferFrom(from, to, id, amount);
}

function _safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
override
{
if (from != address(0)) {
// Ignore validation on minting
_validateTransfer(from, to);
}
super._safeBatchTransferFrom(from, to, ids, amounts);
}

function _burn(address from, uint256 id, uint256 amount)
internal
virtual
override
validateTransfer(from, address(0))
{
super._burn(from, id, amount);
}

function _batchBurn(address from, uint256[] memory ids, uint256[] memory amounts)
internal
virtual
override
validateTransfer(from, address(0))
{
super._batchBurn(from, ids, amounts);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

import {
IERC1155OperatorEnforcedFactory,
IERC1155OperatorEnforcedFactoryFunctions
} from "@0xsequence/contracts-library/tokens/ERC1155/presets/operator-enforced/IERC1155OperatorEnforcedFactory.sol";
import {ERC1155OperatorEnforced} from
"@0xsequence/contracts-library/tokens/ERC1155/presets/operator-enforced/ERC1155OperatorEnforced.sol";
import {SequenceProxyFactory} from "@0xsequence/contracts-library/proxies/SequenceProxyFactory.sol";

/**
* Deployer of ERC-1155 Operator Enforced proxies.
*/
contract ERC1155OperatorEnforcedFactory is IERC1155OperatorEnforcedFactory, SequenceProxyFactory {
/**
* Creates an ERC-1155 Operator Enforced Factory.
* @param factoryOwner The owner of the ERC-1155 Operator Enforced Factory
*/
constructor(address factoryOwner) {
ERC1155OperatorEnforced impl = new ERC1155OperatorEnforced();
SequenceProxyFactory._initialize(address(impl), factoryOwner);
}

/// @inheritdoc IERC1155OperatorEnforcedFactoryFunctions
function deploy(
address proxyOwner,
address tokenOwner,
string memory tokenName,
string memory tokenBaseURI,
string memory tokenContractURI,
address royaltyReceiver,
uint96 royaltyFeeNumerator,
address operatorAllowlist
) external returns (address proxyAddr) {
bytes32 salt = keccak256(
abi.encode(
tokenOwner,
tokenName,
tokenBaseURI,
tokenContractURI,
royaltyReceiver,
royaltyFeeNumerator,
operatorAllowlist
)
);
proxyAddr = _createProxy(salt, proxyOwner, "");
ERC1155OperatorEnforced(proxyAddr).initialize(
tokenOwner,
tokenName,
tokenBaseURI,
tokenContractURI,
royaltyReceiver,
royaltyFeeNumerator,
operatorAllowlist
);
emit ERC1155OperatorEnforcedDeployed(proxyAddr);
return proxyAddr;
}

/// @inheritdoc IERC1155OperatorEnforcedFactoryFunctions
function determineAddress(
address proxyOwner,
address tokenOwner,
string memory tokenName,
string memory tokenBaseURI,
string memory tokenContractURI,
address royaltyReceiver,
uint96 royaltyFeeNumerator,
address operatorAllowlist
) external view returns (address proxyAddr) {
bytes32 salt = keccak256(
abi.encode(
tokenOwner,
tokenName,
tokenBaseURI,
tokenContractURI,
royaltyReceiver,
royaltyFeeNumerator,
operatorAllowlist
)
);
return _computeProxyAddress(salt, proxyOwner, "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

interface IERC1155OperatorEnforcedFactoryFunctions {
/**
* Creates an ERC-1155 Operator Enforced proxy.
* @param proxyOwner The owner of the ERC-1155 Operator Enforced proxy
* @param tokenOwner The owner of the ERC-1155 Operator Enforced implementation
* @param tokenName Token name
* @param tokenBaseURI Base URI for token metadata
* @param tokenContractURI Contract URI for token metadata
* @param royaltyReceiver Address of who should be sent the royalty payment
* @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500)
* @param operatorAllowlist Address of the operator allowlist
* @return proxyAddr The address of the ERC-1155 Operator Enforced Proxy
*/
function deploy(
address proxyOwner,
address tokenOwner,
string memory tokenName,
string memory tokenBaseURI,
string memory tokenContractURI,
address royaltyReceiver,
uint96 royaltyFeeNumerator,
address operatorAllowlist
) external returns (address proxyAddr);

/**
* Computes the address of a proxy instance.
* @param proxyOwner The owner of the ERC-1155 Operator Enforced proxy
* @param tokenOwner The owner of the ERC-1155 Operator Enforced implementation
* @param tokenName Token name
* @param tokenBaseURI Base URI for token metadata
* @param tokenContractURI Contract URI for token metadata
* @param royaltyReceiver Address of who should be sent the royalty payment
* @param royaltyFeeNumerator The royalty fee numerator in basis points (e.g. 15% would be 1500)
* @param operatorAllowlist Address of the operator allowlist
* @return proxyAddr The address of the ERC-1155 Operator Enforced Proxy
*/
function determineAddress(
address proxyOwner,
address tokenOwner,
string memory tokenName,
string memory tokenBaseURI,
string memory tokenContractURI,
address royaltyReceiver,
uint96 royaltyFeeNumerator,
address operatorAllowlist
) external returns (address proxyAddr);
}

interface IERC1155OperatorEnforcedFactorySignals {
/**
* Event emitted when a new ERC-1155 Operator Enforced proxy contract is deployed.
* @param proxyAddr The address of the deployed proxy.
*/
event ERC1155OperatorEnforcedDeployed(address proxyAddr);
}

interface IERC1155OperatorEnforcedFactory is
IERC1155OperatorEnforcedFactoryFunctions,
IERC1155OperatorEnforcedFactorySignals
{}
19 changes: 18 additions & 1 deletion test/_mocks/WalletMock.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

import {IERC1155Receiver} from "openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sol";
import {IERC721Receiver} from "openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";

contract WalletMock is IERC721Receiver {
contract WalletMock is IERC1155Receiver, IERC721Receiver {
error CallFailed();

function call(address to, uint256 value, bytes memory data) external {
Expand All @@ -14,4 +15,20 @@ contract WalletMock is IERC721Receiver {
function onERC721Received(address, address, uint256, bytes memory) external pure returns (bytes4) {
return this.onERC721Received.selector;
}

function onERC1155Received(address, address, uint256, uint256, bytes memory) external pure returns (bytes4) {
return this.onERC1155Received.selector;
}

function onERC1155BatchReceived(address, address, uint256[] memory, uint256[] memory, bytes memory)
external
pure
returns (bytes4)
{
return this.onERC1155BatchReceived.selector;
}

function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
return interfaceId == this.onERC1155Received.selector || interfaceId == this.onERC1155BatchReceived.selector;
}
}
Loading

0 comments on commit a447b5d

Please sign in to comment.