curio-wrapper-truffle/contracts/CurioERC1155Wrapper.sol

242 lines
9.1 KiB
Solidity

// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.17;
import "./ERC1155.sol";
import "./IMastersFedi.sol";
import "./Address.sol";
import "./IERC1155Metadata.sol";
import "./ERC1155Metadata.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/Base64.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract CurioERC1155Wrapper is ERC1155, ERC1155Metadata_URI, ERC1155Metadata, ERC2981, Ownable, Pausable {
using Address for address;
mapping (uint256 => address) public contracts;
mapping (uint256 => string) public urls;
uint96 internal defaultRoyalty = 100;
/**
@notice Initialize an nft id's data
*/
function create(uint256 _id, address _contract, string memory _url) internal {
require(contracts[_id] == address(0), "id already exists");
contracts[_id] = _contract;
urls[_id] = _url;
// mint 0 just to let explorers know it exists
emit TransferSingle(msg.sender, address(0), msg.sender, _id, 0);
}
constructor() {
create(1, 0x2f873FCc3F4B84E9A62AFf28E9a897ce1BC8814B, "https://shitposter.club");
create(2, 0x13a9914Ad2e0be57eB2Abb3E159021Eab6D7a80E, "https://tuusin.misono-ya.info/users/hakui");
create(3, 0xdeCAa5B6901dc465FBf90f9C0c70c96132aF51Db, "https://shitposter.club/users/augustus");
create(4, 0xc1de7E95663FB3A0e8F8C6E6a64297d7AbcBF7f7, "https://mk.toast.cafe/@xjix");
create(5, 0xB70F9A809693B8c6a4c331342B96F15252521dC7, "https://varishangout.net/users/nepfag");
create(6, 0x3f2592136d90dE35615A409B4fe710B3764366F4, "https://shitposter.club/dokidoki@pl.smuglo.li");
create(7, 0x5e7318f75b177a0F27A31CB20bB26bd0C049620c, "https://twitter.com/sonyasupposedly");
create(8, 0x5539907D45a608828756765429f2B4e6311c295c, "https://shpposter.club/users/shpuld");
create(9, 0x0a0e64067B1F7aDfbF876Dde4322633Ff7Df9702, "https://bbs.kawa-kun.com/users/tk");
_setDefaultRoyalty(msg.sender, defaultRoyalty);
}
function transferOwnership(address newOwner) public override onlyOwner {
_setDefaultRoyalty(newOwner, defaultRoyalty);
super.transferOwnership(newOwner);
}
/**
@notice Returns URI of token metadata
@param _id NFT ID
@return URI data URI of metadata JSON
*/
function uri(uint256 _id) external override view returns (string memory) {
IMastersFedi curio = IMastersFedi(contracts[_id]);
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(abi.encodePacked(
'{',
'"name":"', curio.name(), '",',
'"description":"', curio.description(), '",',
'"image":"ipfs://', curio.ipfs_hash(), '",',
'"external_url":"', urls[_id], '",',
'"properties":{',
'"symbol":"', curio.symbol(), '",',
'"erc20_contract":"', Strings.toHexString(contracts[_id]), '"',
'}',
'}'
))));
}
/**
@notice Change the external URL for a token
@param _id NFT ID
@param _url URL pointing to user or site
*/
function setExternalUrl(uint256 _id, string memory _url) external onlyOwner {
require(contracts[_id] != address(0), "id must exist");
urls[_id] = _url;
}
/**
@notice Query if a contract implements an interface
@param _interfaceId The interface identifier, as specified in ERC-165
@return `true` if the contract implements `_interfaceId`
*/
function supportsInterface(bytes4 _interfaceId) public view override(ERC1155, ERC1155Metadata, ERC2981) returns (bool) {
return ERC1155.supportsInterface(_interfaceId)
|| ERC1155Metadata.supportsInterface(_interfaceId)
|| ERC2981.supportsInterface(_interfaceId)
;
}
/**
@notice If NFT ID exists
@dev Makes OpenSea happy
@param _id NFT ID
@return exists if NFT ID exists.
*/
function exists(uint256 _id) external view returns(bool) {
return contracts[_id] != address(0);
}
bool public destroyable = true;
/**
@notice Destroy the contract
@dev Only if it hasn't been disabled
*/
function destroy() public onlyOwner whenPaused {
require(destroyable, "destroy() has been disabled");
selfdestruct(payable(msg.sender));
}
function disableDestroy() public onlyOwner {
destroyable = false;
}
/**
@notice Converts old-style NFT to new-style
@dev For an NFT ID, queries and transfers tokens from the appropriate
curio contract to itself, and mints and transfers corresponding new
ERC-1155 tokens to caller
@param _id NFT ID
@param _quantity how many to wrap
*/
function wrap(uint256 _id, uint256 _quantity) external whenNotPaused {
address tokenContract = contracts[_id];
require(tokenContract != address(0), "invalid id");
IMastersFedi curio = IMastersFedi(tokenContract);
// these are here for convenience because curio contract doesn't throw meaningful exceptions
require(curio.balanceOf(msg.sender) >= _quantity, "insufficient curio balance");
require(curio.allowance(msg.sender, address(this)) >= _quantity, "insufficient curio allowance");
curio.transferFrom(msg.sender, address(this), _quantity);
balances[_id][msg.sender] += _quantity;
// mint
emit TransferSingle(msg.sender, address(0), msg.sender, _id, _quantity);
address _to = msg.sender;
if (_to.isContract()) {
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, msg.sender, _id, _quantity, '');
}
}
/**
@notice Batch version of wrap function
@param _ids array of NFT IDs
@param _quantities how many to wrap of each
*/
function wrapBatch(uint256[] calldata _ids, uint256[] calldata _quantities) external whenNotPaused {
require(_ids.length == _quantities.length, "ids and quantities must match");
address _to = msg.sender;
bool callerIsContract = _to.isContract();
for (uint256 i=0; i < _ids.length; ++i) {
uint256 _id = _ids[i];
uint256 _quantity = _quantities[i];
address tokenContract = contracts[_id];
require(tokenContract != address(0), "invalid id");
IMastersFedi curio = IMastersFedi(tokenContract);
require(curio.balanceOf(msg.sender) >= _quantity, "insufficient curio balance");
require(curio.allowance(msg.sender, address(this)) >= _quantity, "insufficient curio allowance");
curio.transferFrom(msg.sender, address(this), _quantity);
balances[_id][msg.sender] += _quantity;
if (callerIsContract) {
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, msg.sender, _id, _quantity, '');
}
}
// mint
emit TransferBatch(msg.sender, address(0), _to, _ids, _quantities);
}
/**
@notice Unwrap new-style NFTs back to old-style
@dev For an NFT ID, burns ERC-1155 quantity and transfers curio ERC-20
tokens to caller
@param _id NFT ID
@param _quantity how many to unwrap
*/
function unwrap(uint256 _id, uint256 _quantity) external whenNotPaused {
address tokenContract = contracts[_id];
require(tokenContract != address(0), "invalid id");
IMastersFedi curio = IMastersFedi(tokenContract);
require(balances[_id][msg.sender] >= _quantity, "insufficient balance");
balances[_id][msg.sender] -= _quantity;
// do it this way to make sure there's a transfer event
curio.approve(address(this), _quantity);
curio.transferFrom(address(this), msg.sender, _quantity);
// burn
emit TransferSingle(msg.sender, msg.sender, address(0), _id, _quantity);
}
/**
@notice Batch version of unwrap
@param _ids array of NFT IDs
@param _quantities how many to unwrap of each
*/
function unwrapBatch(uint256[] calldata _ids, uint256[] calldata _quantities) external whenNotPaused {
require(_ids.length == _quantities.length, "ids and quantities must match");
for (uint256 i=0; i < _ids.length; ++i) {
uint256 _id = _ids[i];
uint256 _quantity = _quantities[i];
address tokenContract = contracts[_id];
require(tokenContract != address(0), "invalid id");
IMastersFedi curio = IMastersFedi(tokenContract);
require(balances[_id][msg.sender] >= _quantity, "insufficient balance");
balances[_id][msg.sender] -= _quantity;
// do it this way to make sure there's a transfer event
curio.approve(address(this), _quantity);
curio.transferFrom(address(this), msg.sender, _quantity);
}
// burn
emit TransferBatch(msg.sender, msg.sender, address(0), _ids, _quantities);
}
}