文件 1 的 22:Context.sol
pragma solidity ^0.7.0;
contract Context {
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _txOrigin() internal view returns (address payable) {
return tx.origin;
}
function _msgData() internal view returns (bytes memory) {
this;
return msg.data;
}
}
文件 2 的 22:ERC1155.sol
pragma solidity ^0.7.0;
import "./library/LibSafeMath.sol";
import "./library/LibAddress.sol";
import "./interface/IERC1155.sol";
import "./interface/IERC1155Receiver.sol";
import "./mixin/MixinNonFungibleToken.sol";
import "./mixin/MixinOwnable.sol";
import "./WhitelistExchangesProxy.sol";
contract ERC1155 is
IERC1155,
MixinNonFungibleToken,
Ownable
{
using LibAddress for address;
using LibSafeMath for uint256;
bytes4 constant public ERC1155_RECEIVED = 0xf23a6e61;
bytes4 constant public ERC1155_BATCH_RECEIVED = 0xbc197c81;
mapping (uint256 => mapping(address => uint256)) internal balances;
mapping (address => mapping(address => bool)) internal operatorApproval;
address public exchangesRegistry;
function setExchangesRegistry(address newExchangesRegistry) external onlyOwner() {
exchangesRegistry = newExchangesRegistry;
}
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
override
external
{
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"INSUFFICIENT_ALLOWANCE"
);
if (isNonFungible(id)) {
require(
value == 1,
"AMOUNT_EQUAL_TO_ONE_REQUIRED"
);
require(
nfOwners[id] == from,
"NFT_NOT_OWNED_BY_FROM_ADDRESS"
);
nfOwners[id] = to;
} else {
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
}
emit TransferSingle(msg.sender, from, to, id, value);
if (to.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155Received(
msg.sender,
from,
id,
value,
data
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
override
external
{
require(
to != address(0x0),
"CANNOT_TRANSFER_TO_ADDRESS_ZERO"
);
require(
ids.length == values.length,
"TOKEN_AND_VALUES_LENGTH_MISMATCH"
);
require(
from == msg.sender || isApprovedForAll(from, msg.sender),
"INSUFFICIENT_ALLOWANCE"
);
for (uint256 i = 0; i < ids.length; ++i) {
uint256 id = ids[i];
uint256 value = values[i];
if (isNonFungible(id)) {
require(
value == 1,
"AMOUNT_EQUAL_TO_ONE_REQUIRED"
);
require(
nfOwners[id] == from,
"NFT_NOT_OWNED_BY_FROM_ADDRESS"
);
nfOwners[id] = to;
} else {
balances[id][from] = balances[id][from].safeSub(value);
balances[id][to] = balances[id][to].safeAdd(value);
}
}
emit TransferBatch(msg.sender, from, to, ids, values);
if (to.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(to).onERC1155BatchReceived(
msg.sender,
from,
ids,
values,
data
);
require(
callbackReturnValue == ERC1155_BATCH_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
function setApprovalForAll(address operator, bool approved) external override {
operatorApproval[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator) public override view returns (bool) {
bool approved = operatorApproval[owner][operator];
if (!approved && exchangesRegistry != address(0)) {
return WhitelistExchangesProxy(exchangesRegistry).isAddressWhitelisted(operator) == true;
}
return approved;
}
function balanceOf(address owner, uint256 id) external override view returns (uint256) {
if (isNonFungibleItem(id)) {
return nfOwners[id] == owner ? 1 : 0;
}
return balances[id][owner];
}
function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external override view returns (uint256[] memory balances_) {
require(
owners.length == ids.length,
"OWNERS_AND_IDS_MUST_HAVE_SAME_LENGTH"
);
balances_ = new uint256[](owners.length);
for (uint256 i = 0; i < owners.length; ++i) {
uint256 id = ids[i];
if (isNonFungibleItem(id)) {
balances_[i] = nfOwners[id] == owners[i] ? 1 : 0;
} else {
balances_[i] = balances[id][owners[i]];
}
}
return balances_;
}
bytes4 constant private INTERFACE_SIGNATURE_ERC165 = 0x01ffc9a7;
bytes4 constant private INTERFACE_SIGNATURE_ERC1155 = 0xd9b67a26;
function supportsInterface(bytes4 _interfaceID) external view returns (bool) {
if (_interfaceID == INTERFACE_SIGNATURE_ERC165 ||
_interfaceID == INTERFACE_SIGNATURE_ERC1155) {
return true;
}
return false;
}
}
文件 3 的 22:ERC1155Mintable.sol
pragma solidity ^0.7.0;
import "./library/LibSafeMath.sol";
import "./library/LibAddress.sol";
import "./ERC1155.sol";
import "./interface/IERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
import "./mixin/MixinContractURI.sol";
import "./mixin/MixinTokenURI.sol";
contract ERC1155Mintable is
IERC1155Mintable,
ERC1155,
MixinContractURI,
MixinTokenURI
{
using LibSafeMath for uint256;
using LibAddress for address;
uint256 internal nonce;
mapping (uint256 => uint256) public maxIndex;
mapping (uint256 => mapping(address => bool)) internal creatorApproval;
modifier onlyCreator(uint256 _id) {
require(creatorApproval[_id][msg.sender], "not an approved creator of id");
_;
}
function setCreatorApproval(uint256 id, address creator, bool status) external onlyCreator(id) {
creatorApproval[id][creator] = status;
}
function create(
bool isNF
)
external
override
onlyOwner()
returns (uint256 type_)
{
type_ = (++nonce << 128);
if (isNF) {
type_ = type_ | TYPE_NF_BIT;
}
creatorApproval[type_][msg.sender] = true;
emit TransferSingle(
msg.sender,
address(0x0),
address(0x0),
type_,
0
);
emit URI(uri(type_), type_);
}
function createWithType(
uint256 type_
)
external
onlyOwner()
{
creatorApproval[type_][msg.sender] = true;
emit TransferSingle(
msg.sender,
address(0x0),
address(0x0),
type_,
0
);
emit URI(uri(type_), type_);
}
function mintFungible(
uint256 id,
address[] calldata to,
uint256[] calldata quantities
)
external
override
onlyCreator(id)
{
require(
isFungible(id),
"TRIED_TO_MINT_FUNGIBLE_FOR_NON_FUNGIBLE_TOKEN"
);
for (uint256 i = 0; i < to.length; ++i) {
address dst = to[i];
uint256 quantity = quantities[i];
balances[id][dst] = quantity.safeAdd(balances[id][dst]);
emit TransferSingle(
msg.sender,
address(0x0),
dst,
id,
quantity
);
if (dst.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received(
msg.sender,
msg.sender,
id,
quantity,
""
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
}
function mintNonFungible(
uint256 type_,
address[] calldata to
)
external
override
onlyCreator(type_)
{
require(
isNonFungible(type_),
"TRIED_TO_MINT_NON_FUNGIBLE_FOR_FUNGIBLE_TOKEN"
);
uint256 index = maxIndex[type_] + 1;
for (uint256 i = 0; i < to.length; ++i) {
address dst = to[i];
uint256 id = type_ | index + i;
nfOwners[id] = dst;
balances[type_][dst] = balances[type_][dst].safeAdd(1);
emit TransferSingle(msg.sender, address(0x0), dst, id, 1);
if (dst.isContract()) {
bytes4 callbackReturnValue = IERC1155Receiver(dst).onERC1155Received(
msg.sender,
msg.sender,
id,
1,
""
);
require(
callbackReturnValue == ERC1155_RECEIVED,
"BAD_RECEIVER_RETURN_VALUE"
);
}
}
maxIndex[type_] = to.length.safeAdd(maxIndex[type_]);
}
}
文件 4 的 22:HashRegistry.sol
pragma solidity ^0.7.0;
import "./library/LibSafeMath.sol";
import "./ERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
contract HashRegistry is Ownable {
using LibSafeMath for uint256;
ERC1155Mintable public mintableErc1155;
mapping(uint256 => uint256) public tokenIdToTxHash;
mapping(uint256 => uint256) public txHashToTokenId;
mapping(address => bool) public permissedWriters;
constructor(
address _mintableErc1155
) {
permissedWriters[msg.sender] = true;
mintableErc1155 = ERC1155Mintable(_mintableErc1155);
}
event UpdatedRegistry(
uint256 tokenId,
uint256 txHash
);
modifier onlyIfPermissed(address writer) {
require(permissedWriters[writer] == true, "writer can't write to registry");
_;
}
function updatePermissedWriterStatus(address _writer, bool status) public onlyIfPermissed(msg.sender) {
permissedWriters[_writer] = status;
}
function writeToRegistry(uint256[] memory tokenIds, uint256[] memory txHashes) public onlyIfPermissed(msg.sender) {
require(tokenIds.length == txHashes.length, "tokenIds and txHashes size mismatch");
for (uint256 i = 0; i < tokenIds.length; ++i) {
uint256 tokenId = tokenIds[i];
uint256 txHash = txHashes[i];
require(mintableErc1155.ownerOf(tokenId) != address(0), 'token does not exist');
require(txHashToTokenId[txHash] == 0, 'txHash already exists');
require(tokenIdToTxHash[tokenId] == 0, 'tokenId already exists');
tokenIdToTxHash[tokenId] = txHash;
txHashToTokenId[txHash] = tokenId;
emit UpdatedRegistry(tokenId, txHash);
}
}
}
文件 5 的 22:IERC1155.sol
pragma solidity ^0.7.0;
interface IERC1155 {
event TransferSingle(
address indexed _operator,
address indexed _from,
address indexed _to,
uint256 _id,
uint256 _value
);
event TransferBatch(
address indexed _operator,
address indexed _from,
address indexed _to,
uint256[] _ids,
uint256[] _values
);
event ApprovalForAll(
address indexed _owner,
address indexed _operator,
bool _approved
);
event URI(
string _value,
uint256 indexed _id
);
function safeTransferFrom(
address from,
address to,
uint256 id,
uint256 value,
bytes calldata data
)
external;
function safeBatchTransferFrom(
address from,
address to,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external;
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function balanceOf(address owner, uint256 id) external view returns (uint256);
function balanceOfBatch(
address[] calldata owners,
uint256[] calldata ids
)
external
view
returns (uint256[] memory balances_);
}
文件 6 的 22:IERC1155Mintable.sol
pragma solidity ^0.7.0;
import "./IERC1155.sol";
interface IERC1155Mintable is
IERC1155
{
function create(
bool isNF
)
external
returns (uint256 type_);
function mintFungible(
uint256 id,
address[] calldata to,
uint256[] calldata quantities
)
external;
function mintNonFungible(
uint256 type_,
address[] calldata to
)
external;
}
文件 7 的 22:IERC1155Receiver.sol
pragma solidity ^0.7.0;
interface IERC1155Receiver {
function onERC1155Received(
address operator,
address from,
uint256 id,
uint256 value,
bytes calldata data
)
external
returns(bytes4);
function onERC1155BatchReceived(
address operator,
address from,
uint256[] calldata ids,
uint256[] calldata values,
bytes calldata data
)
external
returns(bytes4);
}
文件 8 的 22:LibAddress.sol
pragma solidity ^0.7.0;
library LibAddress {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
}
文件 9 的 22:LibRichErrors.sol
pragma solidity ^0.7.0;
library LibRichErrors {
bytes4 internal constant STANDARD_ERROR_SELECTOR =
0x08c379a0;
function StandardError(
string memory message
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
STANDARD_ERROR_SELECTOR,
bytes(message)
);
}
function rrevert(bytes memory errorData)
internal
pure
{
assembly {
revert(add(errorData, 0x20), mload(errorData))
}
}
}
文件 10 的 22:LibSafeMath.sol
pragma solidity ^0.7.0;
import "./LibRichErrors.sol";
import "./LibSafeMathRichErrors.sol";
library LibSafeMath {
function safeMul(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (a == 0) {
return 0;
}
uint256 c = a * b;
if (c / a != b) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.MULTIPLICATION_OVERFLOW,
a,
b
));
}
return c;
}
function safeDiv(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b == 0) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.DIVISION_BY_ZERO,
a,
b
));
}
uint256 c = a / b;
return c;
}
function safeSub(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
if (b > a) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.SUBTRACTION_UNDERFLOW,
a,
b
));
}
return a - b;
}
function safeAdd(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
uint256 c = a + b;
if (c < a) {
LibRichErrors.rrevert(LibSafeMathRichErrors.Uint256BinOpError(
LibSafeMathRichErrors.BinOpErrorCodes.ADDITION_OVERFLOW,
a,
b
));
}
return c;
}
function max256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a >= b ? a : b;
}
function min256(uint256 a, uint256 b)
internal
pure
returns (uint256)
{
return a < b ? a : b;
}
}
文件 11 的 22:LibSafeMathRichErrors.sol
pragma solidity ^0.7.0;
library LibSafeMathRichErrors {
bytes4 internal constant UINT256_BINOP_ERROR_SELECTOR =
0xe946c1bb;
bytes4 internal constant UINT256_DOWNCAST_ERROR_SELECTOR =
0xc996af7b;
enum BinOpErrorCodes {
ADDITION_OVERFLOW,
MULTIPLICATION_OVERFLOW,
SUBTRACTION_UNDERFLOW,
DIVISION_BY_ZERO
}
enum DowncastErrorCodes {
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT32,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT64,
VALUE_TOO_LARGE_TO_DOWNCAST_TO_UINT96
}
function Uint256BinOpError(
BinOpErrorCodes errorCode,
uint256 a,
uint256 b
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_BINOP_ERROR_SELECTOR,
errorCode,
a,
b
);
}
function Uint256DowncastError(
DowncastErrorCodes errorCode,
uint256 a
)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
UINT256_DOWNCAST_ERROR_SELECTOR,
errorCode,
a
);
}
}
文件 12 的 22:LibString.sol
pragma solidity ^0.7.0;
library LibString {
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory) {
bytes memory _ba = bytes(_a);
bytes memory _bb = bytes(_b);
bytes memory _bc = bytes(_c);
bytes memory _bd = bytes(_d);
bytes memory _be = bytes(_e);
string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
bytes memory babcde = bytes(abcde);
uint k = 0;
for (uint i = 0; i < _ba.length; i++) babcde[k++] = _ba[i];
for (uint i = 0; i < _bb.length; i++) babcde[k++] = _bb[i];
for (uint i = 0; i < _bc.length; i++) babcde[k++] = _bc[i];
for (uint i = 0; i < _bd.length; i++) babcde[k++] = _bd[i];
for (uint i = 0; i < _be.length; i++) babcde[k++] = _be[i];
return string(babcde);
}
function strConcat(string memory _a, string memory _b, string memory _c, string memory _d) internal pure returns (string memory) {
return strConcat(_a, _b, _c, _d, "");
}
function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
return strConcat(_a, _b, _c, "", "");
}
function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
return strConcat(_a, _b, "", "", "");
}
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
function uint2hexstr(uint i) internal pure returns (string memory) {
if (i == 0) {
return "0";
}
uint j = i;
uint len;
while (j != 0) {
len++;
j = j >> 4;
}
uint mask = 15;
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (i != 0){
uint curr = (i & mask);
bstr[k--] = curr > 9 ? byte(uint8(55 + curr)) : byte(uint8(48 + curr));
i = i >> 4;
}
return string(bstr);
}
}
文件 13 的 22:MetadataRegistry.sol
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import "./library/LibSafeMath.sol";
import "./ERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
contract MetadataRegistry is Ownable {
using LibSafeMath for uint256;
mapping(uint256 => mapping(string => Document)) public tokenIdToDocumentMap;
mapping(address => bool) public permissedWriters;
struct Document {
address writer;
string text;
uint256 creationTime;
}
constructor(
) {
}
event UpdatedDocument(
uint256 indexed tokenId,
address indexed writer,
string indexed key,
string text
);
function updatePermissedWriterStatus(address _writer, bool status) public onlyOwner {
permissedWriters[_writer] = status;
}
modifier onlyIfPermissed(address writer) {
require(permissedWriters[writer] == true, "writer can't write to registry");
_;
}
function writeDocuments(uint256 tokenId, string[] memory keys, string[] memory texts, address[] memory writers) public onlyIfPermissed(msg.sender) {
require(keys.length == texts.length, "keys and txHashes size mismatch");
require(writers.length == texts.length, "writers and texts size mismatch");
for (uint256 i = 0; i < keys.length; ++i) {
string memory key = keys[i];
string memory text = texts[i];
address writer = writers[i];
tokenIdToDocumentMap[tokenId][key] = Document(writer, text, block.timestamp);
emit UpdatedDocument(tokenId, writer, key, text);
}
}
}
文件 14 的 22:MixinContractURI.sol
pragma solidity ^0.7.0;
import "./MixinOwnable.sol";
contract MixinContractURI is Ownable {
string public contractURI;
function setContractURI(string calldata newContractURI) external onlyOwner() {
contractURI = newContractURI;
}
}
文件 15 的 22:MixinNonFungibleToken.sol
pragma solidity ^0.7.0;
contract MixinNonFungibleToken {
uint256 constant internal TYPE_MASK = uint256(uint128(~0)) << 128;
uint256 constant internal NF_INDEX_MASK = uint128(~0);
uint256 constant internal TYPE_NF_BIT = 1 << 255;
mapping (uint256 => address) internal nfOwners;
function isNonFungible(uint256 id) public pure returns(bool) {
return id & TYPE_NF_BIT == TYPE_NF_BIT;
}
function isFungible(uint256 id) public pure returns(bool) {
return id & TYPE_NF_BIT == 0;
}
function getNonFungibleIndex(uint256 id) public pure returns(uint256) {
return id & NF_INDEX_MASK;
}
function getNonFungibleBaseType(uint256 id) public pure returns(uint256) {
return id & TYPE_MASK;
}
function isNonFungibleBaseType(uint256 id) public pure returns(bool) {
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK == 0);
}
function isNonFungibleItem(uint256 id) public pure returns(bool) {
return (id & TYPE_NF_BIT == TYPE_NF_BIT) && (id & NF_INDEX_MASK != 0);
}
function ownerOf(uint256 id) public view returns (address) {
return nfOwners[id];
}
}
文件 16 的 22:MixinOwnable.sol
pragma solidity ^0.7.0;
import "./Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 17 的 22:MixinPausable.sol
pragma solidity ^0.7.0;
import "./Context.sol";
abstract contract MixinPausable is Context {
event Paused(address account);
event Unpaused(address account);
bool private _paused;
constructor () {
_paused = false;
}
function paused() public view virtual returns (bool) {
return _paused;
}
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}
文件 18 的 22:MixinSignature.sol
pragma solidity ^0.7.0;
contract MixinSignature {
function splitSignature(bytes memory sig)
public pure returns (bytes32 r, bytes32 s, uint8 v)
{
require(sig.length == 65, "invalid signature length");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
if (v < 27) v += 27;
}
function isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (bool) {
return _isSigned(_address, messageHash, v, r, s) || _isSignedPrefixed(_address, messageHash, v, r, s);
}
function _isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
internal pure returns (bool)
{
return ecrecover(messageHash, v, r, s) == _address;
}
function _isSignedPrefixed(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
internal pure returns (bool)
{
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
return _isSigned(_address, keccak256(abi.encodePacked(prefix, messageHash)), v, r, s);
}
}
文件 19 的 22:MixinTokenURI.sol
pragma solidity ^0.7.0;
import "./MixinOwnable.sol";
import "../library/LibString.sol";
contract MixinTokenURI is Ownable {
using LibString for string;
string public baseMetadataURI = "";
function setBaseMetadataURI(string memory newBaseMetadataURI) public onlyOwner() {
baseMetadataURI = newBaseMetadataURI;
}
function uri(uint256 _id) public view returns (string memory) {
return LibString.strConcat(
baseMetadataURI,
LibString.uint2hexstr(_id)
);
}
}
文件 20 的 22:ReentrancyGuard.sol
pragma solidity ^0.7.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
文件 21 的 22:SignedTextMetadataWriter.sol
pragma solidity ^0.7.0;
pragma experimental ABIEncoderV2;
import "./library/LibString.sol";
import "./MetadataRegistry.sol";
import "./HashRegistry.sol";
import "./ERC1155Mintable.sol";
import "./mixin/MixinOwnable.sol";
import "./mixin/MixinSignature.sol";
import "./mixin/MixinPausable.sol";
import "./library/ReentrancyGuard.sol";
contract SignedTextMetadataWriter is MixinSignature, ReentrancyGuard {
MetadataRegistry public metadataRegistry;
ERC1155Mintable public mintableErc1155;
HashRegistry public hashRegistry;
constructor(
address _mintableErc1155,
address _metadataRegistry,
address _hashRegistry
) {
mintableErc1155 = ERC1155Mintable(_mintableErc1155);
metadataRegistry = MetadataRegistry(_metadataRegistry);
hashRegistry = HashRegistry(_hashRegistry);
}
struct SignedText {
address writer;
string text;
uint256 txHash;
uint256 fee;
bytes signature;
uint256 createdAt;
}
event WroteSignedText(
uint256 indexed tokenId,
address indexed writer,
string indexed key,
string text,
uint256 txHash,
uint256 fee,
bytes signature
);
modifier onlyTokenOwner(uint256 tokenId, address owner) {
require(mintableErc1155.ownerOf(tokenId) == owner, 'do not have permission to write docs');
_;
}
function getSignedTextHash(SignedText memory signedText) public pure returns(bytes32) {
return keccak256(abi.encodePacked(signedText.writer, signedText.text, signedText.txHash, signedText.fee, signedText.createdAt)) ;
}
function verifySignedDocument(SignedText memory signedText) public pure returns(bool) {
bytes32 signedHash = getSignedTextHash(signedText);
(bytes32 r, bytes32 s, uint8 v) = splitSignature(signedText.signature);
return isSigned(signedText.writer, signedHash, v, r, s);
}
function writeDocuments(uint256 tokenId, string[] memory keys, SignedText[] memory signedTexts) public payable nonReentrant() onlyTokenOwner(tokenId, msg.sender) {
require(keys.length == signedTexts.length, "keys and signedTexts size mismatch");
address[] memory writers = new address[](keys.length);
string[] memory texts = new string[](keys.length);
for (uint256 i = 0; i < keys.length; ++i) {
string memory key = keys[i];
SignedText memory signedText = signedTexts[i];
require(verifySignedDocument(signedText) == true, 'invalid signature');
require(hashRegistry.tokenIdToTxHash(tokenId) == signedText.txHash, 'invalid signedText for hash');
writers[i] = signedText.writer;
texts[i] = signedText.text;
signedText.writer.call{value: signedText.fee }("");
emit WroteSignedText(tokenId, signedText.writer, key, signedText.text, signedText.txHash, signedText.fee, signedText.signature );
}
metadataRegistry.writeDocuments(tokenId, keys, texts, writers);
msg.sender.call{value: address(this).balance }("");
}
}
文件 22 的 22:WhitelistExchangesProxy.sol
pragma solidity ^0.7.0;
import "./mixin/MixinOwnable.sol";
contract WhitelistExchangesProxy is Ownable {
mapping(address => bool) internal proxies;
bool public paused = true;
function setPaused(bool newPaused) external onlyOwner() {
paused = newPaused;
}
function updateProxyAddress(address proxy, bool status) external onlyOwner() {
proxies[proxy] = status;
}
function isAddressWhitelisted(address proxy) external view returns (bool) {
if (paused) {
return false;
} else {
return proxies[proxy];
}
}
}
{
"compilationTarget": {
"contracts/SignedTextMetadataWriter.sol": "SignedTextMetadataWriter"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_mintableErc1155","type":"address"},{"internalType":"address","name":"_metadataRegistry","type":"address"},{"internalType":"address","name":"_hashRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"writer","type":"address"},{"indexed":true,"internalType":"string","name":"key","type":"string"},{"indexed":false,"internalType":"string","name":"text","type":"string"},{"indexed":false,"internalType":"uint256","name":"txHash","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"signature","type":"bytes"}],"name":"WroteSignedText","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"writer","type":"address"},{"internalType":"string","name":"text","type":"string"},{"internalType":"uint256","name":"txHash","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"internalType":"struct SignedTextMetadataWriter.SignedText","name":"signedText","type":"tuple"}],"name":"getSignedTextHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"hashRegistry","outputs":[{"internalType":"contract HashRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"isSigned","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"metadataRegistry","outputs":[{"internalType":"contract MetadataRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintableErc1155","outputs":[{"internalType":"contract ERC1155Mintable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitSignature","outputs":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"writer","type":"address"},{"internalType":"string","name":"text","type":"string"},{"internalType":"uint256","name":"txHash","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"internalType":"struct SignedTextMetadataWriter.SignedText","name":"signedText","type":"tuple"}],"name":"verifySignedDocument","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string[]","name":"keys","type":"string[]"},{"components":[{"internalType":"address","name":"writer","type":"address"},{"internalType":"string","name":"text","type":"string"},{"internalType":"uint256","name":"txHash","type":"uint256"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"internalType":"struct SignedTextMetadataWriter.SignedText[]","name":"signedTexts","type":"tuple[]"}],"name":"writeDocuments","outputs":[],"stateMutability":"payable","type":"function"}]