2023-01-29 18:29:54 +00:00
|
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
pragma solidity ^0.8.17;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
import "./ERC1155.sol";
|
2023-01-29 19:46:02 +00:00
|
|
|
import "./IMastersFedi.sol";
|
2022-02-11 04:17:00 +00:00
|
|
|
import "./Address.sol";
|
|
|
|
import "./IERC1155Metadata.sol";
|
2023-01-29 22:22:15 +00:00
|
|
|
import "./ERC1155Metadata.sol";
|
2023-01-29 19:46:02 +00:00
|
|
|
import "@openzeppelin/contracts/utils/Strings.sol";
|
|
|
|
import "@openzeppelin/contracts/utils/Base64.sol";
|
2023-01-29 21:15:20 +00:00
|
|
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
2023-01-29 22:50:26 +00:00
|
|
|
import "@openzeppelin/contracts/security/Pausable.sol";
|
2023-01-30 06:09:51 +00:00
|
|
|
import "@openzeppelin/contracts/token/common/ERC2981.sol";
|
2022-02-11 04:17:00 +00:00
|
|
|
|
2023-01-30 06:09:51 +00:00
|
|
|
contract CurioERC1155Wrapper is ERC1155, ERC1155Metadata_URI, ERC1155Metadata, ERC2981, Ownable, Pausable {
|
2022-02-11 04:17:00 +00:00
|
|
|
using Address for address;
|
|
|
|
|
|
|
|
mapping (uint256 => address) public contracts;
|
2023-01-29 21:15:20 +00:00
|
|
|
mapping (uint256 => string) public urls;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
2023-01-30 06:09:51 +00:00
|
|
|
uint96 internal defaultRoyalty = 100;
|
|
|
|
|
2022-02-11 04:17:00 +00:00
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice Initialize an nft id's data
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 21:15:20 +00:00
|
|
|
function create(uint256 _id, address _contract, string memory _url) internal {
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
require(contracts[_id] == address(0), "id already exists");
|
|
|
|
contracts[_id] = _contract;
|
|
|
|
|
2023-01-29 21:15:20 +00:00
|
|
|
urls[_id] = _url;
|
|
|
|
|
2022-02-11 04:17:00 +00:00
|
|
|
// mint 0 just to let explorers know it exists
|
|
|
|
emit TransferSingle(msg.sender, address(0), msg.sender, _id, 0);
|
|
|
|
}
|
|
|
|
|
2023-01-29 18:29:54 +00:00
|
|
|
constructor() {
|
2023-01-29 21:15:20 +00:00
|
|
|
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");
|
2023-01-30 06:09:51 +00:00
|
|
|
|
|
|
|
_setDefaultRoyalty(msg.sender, defaultRoyalty);
|
|
|
|
}
|
|
|
|
|
|
|
|
function transferOwnership(address newOwner) public override onlyOwner {
|
|
|
|
_setDefaultRoyalty(newOwner, defaultRoyalty);
|
|
|
|
super.transferOwnership(newOwner);
|
2022-02-11 04:17:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice Returns URI of token metadata
|
2022-02-11 04:17:00 +00:00
|
|
|
@param _id NFT ID
|
2023-01-29 21:44:25 +00:00
|
|
|
@return URI data URI of metadata JSON
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 21:44:25 +00:00
|
|
|
function uri(uint256 _id) external override view returns (string memory) {
|
2023-01-29 21:15:20 +00:00
|
|
|
IMastersFedi curio = IMastersFedi(contracts[_id]);
|
|
|
|
|
|
|
|
return string(abi.encodePacked("data:application/json;base64,", Base64.encode(abi.encodePacked(
|
|
|
|
'{',
|
2023-01-30 03:21:09 +00:00
|
|
|
'"name":"', curio.name(), '",',
|
|
|
|
'"description":"', curio.description(), '",',
|
|
|
|
'"image":"ipfs://', curio.ipfs_hash(), '",',
|
2023-01-29 21:15:20 +00:00
|
|
|
'"external_url":"', urls[_id], '",',
|
|
|
|
'"properties":{',
|
2023-01-30 05:25:36 +00:00
|
|
|
'"symbol":"', curio.symbol(), '",',
|
|
|
|
'"erc20_contract":"', Strings.toHexString(contracts[_id]), '"',
|
2023-01-29 21:15:20 +00:00
|
|
|
'}',
|
|
|
|
'}'
|
|
|
|
))));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice Change the external URL for a token
|
2023-01-29 21:15:20 +00:00
|
|
|
@param _id NFT ID
|
2023-01-29 21:44:25 +00:00
|
|
|
@param _url URL pointing to user or site
|
2023-01-29 21:15:20 +00:00
|
|
|
*/
|
|
|
|
function setExternalUrl(uint256 _id, string memory _url) external onlyOwner {
|
|
|
|
require(contracts[_id] != address(0), "id must exist");
|
|
|
|
|
|
|
|
urls[_id] = _url;
|
2022-02-11 04:17:00 +00:00
|
|
|
}
|
|
|
|
|
2023-01-29 22:22:15 +00:00
|
|
|
/**
|
|
|
|
@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`
|
|
|
|
*/
|
2023-01-30 06:09:51 +00:00
|
|
|
function supportsInterface(bytes4 _interfaceId) public view override(ERC1155, ERC1155Metadata, ERC2981) returns (bool) {
|
2023-01-29 22:22:15 +00:00
|
|
|
return ERC1155.supportsInterface(_interfaceId)
|
2023-01-30 06:09:51 +00:00
|
|
|
|| ERC1155Metadata.supportsInterface(_interfaceId)
|
|
|
|
|| ERC2981.supportsInterface(_interfaceId)
|
|
|
|
;
|
2023-01-29 22:22:15 +00:00
|
|
|
}
|
|
|
|
|
2022-02-11 04:17:00 +00:00
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice If NFT ID exists
|
|
|
|
@dev Makes OpenSea happy
|
2022-02-11 04:17:00 +00:00
|
|
|
@param _id NFT ID
|
2023-01-29 21:44:25 +00:00
|
|
|
@return exists if NFT ID exists.
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
|
|
|
function exists(uint256 _id) external view returns(bool) {
|
|
|
|
return contracts[_id] != address(0);
|
|
|
|
}
|
|
|
|
|
2023-01-29 22:50:26 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2022-02-11 04:17:00 +00:00
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@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
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 22:50:26 +00:00
|
|
|
function wrap(uint256 _id, uint256 _quantity) external whenNotPaused {
|
2022-02-11 04:17:00 +00:00
|
|
|
address tokenContract = contracts[_id];
|
|
|
|
require(tokenContract != address(0), "invalid id");
|
2023-01-29 19:46:02 +00:00
|
|
|
IMastersFedi curio = IMastersFedi(tokenContract);
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
2023-01-29 21:55:26 +00:00
|
|
|
balances[_id][msg.sender] += _quantity;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
// 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, '');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice Batch version of wrap function
|
|
|
|
@param _ids array of NFT IDs
|
|
|
|
@param _quantities how many to wrap of each
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 22:50:26 +00:00
|
|
|
function wrapBatch(uint256[] calldata _ids, uint256[] calldata _quantities) external whenNotPaused {
|
2022-02-11 04:17:00 +00:00
|
|
|
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");
|
2023-01-29 19:46:02 +00:00
|
|
|
IMastersFedi curio = IMastersFedi(tokenContract);
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2023-01-29 21:55:26 +00:00
|
|
|
balances[_id][msg.sender] += _quantity;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
if (callerIsContract) {
|
|
|
|
_doSafeTransferAcceptanceCheck(msg.sender, msg.sender, msg.sender, _id, _quantity, '');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// mint
|
|
|
|
emit TransferBatch(msg.sender, address(0), _to, _ids, _quantities);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@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
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 22:50:26 +00:00
|
|
|
function unwrap(uint256 _id, uint256 _quantity) external whenNotPaused {
|
2022-02-11 04:17:00 +00:00
|
|
|
address tokenContract = contracts[_id];
|
|
|
|
require(tokenContract != address(0), "invalid id");
|
2023-01-29 19:46:02 +00:00
|
|
|
IMastersFedi curio = IMastersFedi(tokenContract);
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
require(balances[_id][msg.sender] >= _quantity, "insufficient balance");
|
2023-01-29 22:22:15 +00:00
|
|
|
balances[_id][msg.sender] -= _quantity;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
curio.transfer(msg.sender, _quantity);
|
|
|
|
|
|
|
|
// burn
|
2023-01-29 18:00:39 +00:00
|
|
|
emit TransferSingle(msg.sender, msg.sender, address(0), _id, _quantity);
|
2022-02-11 04:17:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-01-29 21:44:25 +00:00
|
|
|
@notice Batch version of unwrap
|
|
|
|
@param _ids array of NFT IDs
|
|
|
|
@param _quantities how many to unwrap of each
|
2022-02-11 04:17:00 +00:00
|
|
|
*/
|
2023-01-29 22:50:26 +00:00
|
|
|
function unwrapBatch(uint256[] calldata _ids, uint256[] calldata _quantities) external whenNotPaused {
|
2022-02-11 04:17:00 +00:00
|
|
|
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");
|
2023-01-29 19:46:02 +00:00
|
|
|
IMastersFedi curio = IMastersFedi(tokenContract);
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
require(balances[_id][msg.sender] >= _quantity, "insufficient balance");
|
2023-01-29 21:55:26 +00:00
|
|
|
balances[_id][msg.sender] -= _quantity;
|
2022-02-11 04:17:00 +00:00
|
|
|
|
|
|
|
curio.transfer(msg.sender, _quantity);
|
|
|
|
}
|
|
|
|
|
|
|
|
// burn
|
2023-01-29 18:00:39 +00:00
|
|
|
emit TransferBatch(msg.sender, msg.sender, address(0), _ids, _quantities);
|
2022-02-11 04:17:00 +00:00
|
|
|
}
|
|
|
|
}
|