@niftory/niftory-solidity
v0.0.5
Published
Niftory Solidity Contracts
Downloads
6
Keywords
Readme
Niftory Smart Contracts for EVM Compatible Blockchains
This repository hosts all smart contracts (and related scripts, tests, etc.) for Niftory, an NFT management platform. Niftory NFTs are ERC1155 compatible.
Note: This README is autogenerated. Please modify docs from within the docs
folder and run yarn build
to regenerate.
Usage
In order to use the contract, just extend one of the contracts from the impl
folder. Currently, there is only NiftoryStandardERC1155
.
Typed APIs, generated with typechain, can be accessed via src/bindings
. NiftoryStandardERC1155Interface
from here is the best place to see the full accessible API in one place.
Overview
Each uniquely identifiable ERC1155 token maps to a unique set
(via setId
) and template
(via templateId
) pair. The IERC1155 token id
(e.g. for the uri
function) can be expressed as (setId << 64) + templateId
, as setId
and templateId
are both 64 bits each.
A contract can have multiple set
s, and each set
can have multiple templates
. Indexing for both starts at 1
(so there is no set
with setId=0
or template
with templateId=0
in any set).
Each template
maps to exactly one uri
, which can be modified by an Admin or SetAdmin (see next section). template
s also keep track of how many NFTs have been minted for that template and how many are allowed to minted (maxMint
). A template
with a maxMint
of 0 allows unlimited minting. A maxMint
may be set later, however.
set
s can be locked to prevent more templates from being added, and templates
can have metadata modification and minting locked separately.
set
s allow Admins to delegate control to a collection of template
s to a SetAdmin, allowing the SetAdmin to lock and mint from set
s it owns.
Roles and Actions
This contract uses a very simple RBAC style management with three different roles, as below.
Admin
An Admin is the superuser of the contract. An Admin can
- Assign (or revoke) more Admins
- Assign (or revoke) SetAdmins
- Create & lock sets
- Add templates to any set
- Mint from any mintable template
- Change the metadata for any template
- Modify the maximum mint amount for any template
- Lock metadata and minting for any template
- Modify the global default URI
Set Admin
A SetAdmin is an adminstrator of set
s it has been given power over, either from an Admin or another previous SetAdmin. A SetAdmin can
- Assign (or revoke) SetAdmins from the sets it owns
- Lock sets it owns
- Add templates to sets it owns
- Mint from mintable templates of sets it owns
- Change the metadata of templates of sets it owns
- Modify the maximum mint amount for templates of sets it owns
- Lock metadata and minting for templates of sets it owns
Collector
Collector
is another way of saying "no role" and can be anyone with an account on the blockchain. A Collector
can
- Hold and transfer tokens
- Approve another account to manage tokens
- Burn tokens
All the above functionality is provided by OpenZeppelin's ERC1155 implementation.
Architecture
There are three extensions that can be used to power this token, which all assume that an ERC1155 token uses the set
/template
scheme mentioned above.
The main NiftoryStandardERC1155
uses OpenZeppelin's ERC1155Burnable.sol
as a base. There are three custom extensions used, which can be found in contracts/extensions
UriManager
manages URI's for templates and allows modification. If the URI is blank, it will use the default_defaultUri
.RoleManager
manages the Admin and SetAdmin based ownership.RoleManager
maps an(address, setId)
pair to a boolean value indicating whetheraddress
is a SetAdmin of setsetId
. The 0-th bit is used to indicate an Admin. This extension uses a custom library (lib/AddressIndexedBitmap.sol
) in order to tightly pack the boolean role indicatorTemplateManager
is broken into two parts - theSetManager
and the derivingTemplateManager
. TheSetManager
storesSet
s in asetId => Set
map. ASet
needs to keep track of how many templates it contains, and also allows locking to stop more templates from being added.TemplateManager
manages eachTemplate
, keeping track of what the max mint is, how many NFTs have been minted from it, whether metadata can still be modified, and whether minting is still unlocked.
There are also two libraries in the lib
folder - AddressedIndexedBitmap.sol
and TemplateBasedId.sol
. AddressedIndexedBitmap
was already mentioned above, but TemplateBasedId
provides a 1-1 mapping from (uint64 setId, uint64 templateId) <=> uint256 id
), in order to adhere to IERC1155
.
Development
yarn
- install all node dependenciesyarn clean
- remove all hardhat generated filesyarn compile
- compile Solidity files and generate docsyarn build
- clean and compileyarn test
- build and run tests (and show gas usage information)yarn coverage
- generate coverage reports
Solidity API
MetadataManager
State
struct State {
string _contractUri;
string tokenUri;
mapping(uint256 => string) tokenUriOverrides;
struct LockManager.State locks;
}
contractUri
function contractUri(struct MetadataManager.State self) internal view returns (string)
uri
function uri(struct MetadataManager.State self, uint64 setId, uint64 templateId, uint64 serialNumber) internal view returns (string)
modifyContractUri
function modifyContractUri(struct MetadataManager.State self, string newContractUri) internal
modifyTokenUri
function modifyTokenUri(struct MetadataManager.State self, string newTokenUri) internal
modifySetOverrides
function modifySetOverrides(struct MetadataManager.State self, uint64[] setIds, string[] newTokenUris) internal
modifyTemplateOverrides
function modifyTemplateOverrides(struct MetadataManager.State self, uint64 setId, uint64[] templateIds, string[] newTokenUris) internal
modifySerialOverrides
function modifySerialOverrides(struct MetadataManager.State self, uint64 setId, uint64 templateId, uint64[] serialNumbers, string[] newTokenUris) internal
lockContract
function lockContract(struct MetadataManager.State self) internal
lockSets
function lockSets(struct MetadataManager.State self, uint64[] setIds) internal
lockSetRange
function lockSetRange(struct MetadataManager.State self, uint64 setIdStart, uint64 setIdEnd) internal
lockTemplates
function lockTemplates(struct MetadataManager.State self, uint64 setId, uint64[] templateIds) internal
lockTemplateRange
function lockTemplateRange(struct MetadataManager.State self, uint64 setId, uint64 templateIdStart, uint64 templateIdEnd) internal
_getBestUri
function _getBestUri(struct MetadataManager.State self, uint64 setId, uint64 templateId, uint64 serialNumber) private view returns (string)
MintManager
Template
struct Template {
mapping(uint256 => uint256) balances;
uint64 minted;
uint64 maxMint;
}
Set
struct Set {
uint64 numTemplates;
}
State
struct State {
mapping(uint256 => struct MintManager.Set) sets;
mapping(uint256 => struct MintManager.Template) templates;
struct LockManager.State locks;
uint64 numSets;
}
addressHasToken
function addressHasToken(struct MintManager.State self, address addr, uint64 setId, uint64 templateId, uint64 serialNumber) internal view returns (bool)
doesSetExist
function doesSetExist(struct MintManager.State self, uint64 setId) internal view returns (bool)
doesTemplateExist
function doesTemplateExist(struct MintManager.State self, uint64 setId, uint64 templateId) internal view returns (bool)
checkSetExists
function checkSetExists(struct MintManager.State self, uint64 setId) internal view
checkTemplateExists
function checkTemplateExists(struct MintManager.State self, uint64 setId, uint64 templateId) internal view
numberOfSets
function numberOfSets(struct MintManager.State self) internal view returns (uint64)
numberOfTemplates
function numberOfTemplates(struct MintManager.State self, uint64 setId) internal view returns (uint64)
numberMinted
function numberMinted(struct MintManager.State self, uint64 setId, uint64 templateId) internal view returns (uint64)
addSets
function addSets(struct MintManager.State self, uint64 numSets) internal
addTemplates
function addTemplates(struct MintManager.State self, uint64 setId, uint64 numTemplates) internal
mint
function mint(struct MintManager.State self, address[] to, uint64 setId, uint64[] templateIds, uint64[] amounts) internal
lockContract
function lockContract(struct MintManager.State self) internal
lockSets
function lockSets(struct MintManager.State self, uint64[] setIds) internal
lockTemplates
function lockTemplates(struct MintManager.State self, uint64 setId, uint64[] templateIds) internal
setMaxMints
function setMaxMints(struct MintManager.State self, uint64 setId, uint64[] templateIds, uint64[] maxMints) internal
transfer
function transfer(struct MintManager.State self, address from, address to, uint256[] tokenIds) internal
burn
function burn(struct MintManager.State self, address from, uint256[] tokenIds) internal
OperatorManager
State
struct State {
mapping(uint256 => bool) operators;
}
isApproved
function isApproved(struct OperatorManager.State self, address account, address operator) internal view returns (bool)
checkApproved
function checkApproved(struct OperatorManager.State self, address account, address operator) internal view
modifyApproval
function modifyApproval(struct OperatorManager.State self, address account, address operator, bool approved) internal
_operatorKey
function _operatorKey(address account, address operator) private pure returns (uint256)
RoleManager
_CONTRACT_ADMIN_BIT
uint64 _CONTRACT_ADMIN_BIT
State
struct State {
mapping(uint256 => uint256) roles;
}
isContractAdmin
function isContractAdmin(struct RoleManager.State self, address addr) internal view returns (bool)
isSetAdmin
function isSetAdmin(struct RoleManager.State self, address addr, uint64 setId) internal view returns (bool)
checkContractAdmin
function checkContractAdmin(struct RoleManager.State self, address addr) internal view
checkSetAdmin
function checkSetAdmin(struct RoleManager.State self, address addr, uint64 setId) internal view
grantContractAdmin
function grantContractAdmin(struct RoleManager.State self, address[] addrs) internal
grantSetAdmin
function grantSetAdmin(struct RoleManager.State self, uint64[] setIds, address[] addrs) internal
grantSetRangeAdmin
function grantSetRangeAdmin(struct RoleManager.State self, uint64 fromSetId, uint64 toSetId, address[] addrs) internal
revokeContractAdmin
function revokeContractAdmin(struct RoleManager.State self, address[] addrs) internal
revokeSetRangeAdmin
function revokeSetRangeAdmin(struct RoleManager.State self, uint64 fromSetId, uint64 toSetId, address[] addrs) internal
UpgradeManager
State
struct State {
mapping(address => bool) admins;
}
isAdmin
function isAdmin(struct UpgradeManager.State self, address account) internal view returns (bool)
checkAdmin
function checkAdmin(struct UpgradeManager.State self, address account) internal view
grantAdmin
function grantAdmin(struct UpgradeManager.State self, address account) internal
revokeAdmin
function revokeAdmin(struct UpgradeManager.State self, address account) internal
NiftoryOptimizedERC1155
AdminsAssigned
event AdminsAssigned(uint64 setId, address[] admins)
AdminsRevoked
event AdminsRevoked(uint64 setId, address[] admins)
SetsAdded
event SetsAdded(uint64[] setIds)
SetsLocked
event SetsLocked(uint64[] setIds)
TemplatesAdded
event TemplatesAdded(uint64 setId, uint64[] templateIds)
TemplatesMetadataLocked
event TemplatesMetadataLocked(uint64 setId, uint64[] templateIds)
SetMetadataLocked
event SetMetadataLocked(uint64 setId)
TemplatesMaxMintModified
event TemplatesMaxMintModified(uint64 setId, uint64[] templateIds, uint64[] newMaxes)
TemplatesMintingLocked
event TemplatesMintingLocked(uint64 setId, uint64[] templateIds)
SetMintingLocked
event SetMintingLocked(uint64 setId)
_roleManager
struct RoleManager.State _roleManager
_operatorManager
struct OperatorManager.State _operatorManager
_mintManager
struct MintManager.State _mintManager
_metadataManager
struct MetadataManager.State _metadataManager
constructor
constructor() public
initialize
function initialize(address owner, string contractUri, string tokenUri) public
supportsInterface
function supportsInterface(bytes4 interfaceId) public pure returns (bool)
_Returns true if this contract implements the interface defined by
interfaceId
. See the corresponding
https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
to learn more about how these ids are created.
This function call must use less than 30 000 gas._
balanceOf
function balanceOf(address account, uint256 id) public view returns (uint256)
_Returns the amount of tokens of token type id
owned by account
.
Requirements:
account
cannot be the zero address._
balanceOfBatch
function balanceOfBatch(address[] accounts, uint256[] ids) public view returns (uint256[])
_xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
Requirements:
accounts
andids
must have the same length._
setApprovalForAll
function setApprovalForAll(address operator, bool approved) public
_Grants or revokes permission to operator
to transfer the caller's tokens, according to approved
,
Emits an {ApprovalForAll} event.
Requirements:
operator
cannot be the caller._
isApprovedForAll
function isApprovedForAll(address account, address operator) public view returns (bool)
_Returns true if operator
is approved to transfer account
's tokens.
See {setApprovalForAll}._
safeTransferFrom
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes) public
safeBatchTransferFrom
function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes) public
uri
function uri(uint256 id) public view returns (string)
_Returns the URI for token type id
.
If the \{id\}
substring is present in the URI, it must be replaced by
clients with the actual token type ID._
contractURI
function contractURI() public view returns (string)
_checkOwner
function _checkOwner() internal view
Throws if the sender is not the owner.
burn
function burn(uint256[] ids) public
addSets
function addSets(uint64 numSets) public
addTemplates
function addTemplates(uint64 setId, uint64 numTemplates) public
mint
function mint(address[] to, uint64 setId, uint64[] templateIds, uint64[] amounts) public
lockMintingForContract
function lockMintingForContract() public
lockMintingForSets
function lockMintingForSets(uint64[] setIds) public
lockMintingForTemplates
function lockMintingForTemplates(uint64 setId, uint64[] templateIds) public
setMaxMints
function setMaxMints(uint64 setId, uint64[] templateIds, uint64[] maxMints) public
modifyContractMetadataUri
function modifyContractMetadataUri(string newUri) public
modifyTokenMetadataUri
function modifyTokenMetadataUri(string newUri) public
modifySetMetadataOverrides
function modifySetMetadataOverrides(uint64[] setIds, string[] newUris) public
modifyTemplateMetadataOverrides
function modifyTemplateMetadataOverrides(uint64 setId, uint64[] templateIds, string[] newUris) public
modifySerialMetadataOverrides
function modifySerialMetadataOverrides(uint64 setId, uint64 templateId, uint64[] serialNumbers, string[] newUris) public
lockMetadataForContract
function lockMetadataForContract() public
lockMetadataForSets
function lockMetadataForSets(uint64[] setIds) public
lockMetadataForTemplates
function lockMetadataForTemplates(uint64 setId, uint64[] templateIds) public
grantContractAdmin
function grantContractAdmin(address[] admins) public
grantSetAdmin
function grantSetAdmin(uint64[] setIds, address[] admins) public
grantSetRangeAdmin
function grantSetRangeAdmin(uint64 fromSetId, uint64 toSetId, address[] admins) public
Beacon
_upgradeManager
struct UpgradeManager.State _upgradeManager
constructor
constructor(address implementation) public
_checkOwner
function _checkOwner() internal view
Throws if the sender is not the owner.
grantAdmin
function grantAdmin(address account) public
revokeAdmin
function revokeAdmin(address account) public
deployProxy
function deployProxy(bytes data, bool forceCall) public returns (address proxy)
BeaconProxy
_BEACON_SLOT
bytes32 _BEACON_SLOT
BeaconUpgraded
event BeaconUpgraded(address beacon)
_roleManager
struct RoleManager.State _roleManager
constructor
constructor(address beacon, bytes data, bool forceCall) public payable
_implementation
function _implementation() internal view returns (address)
_This is a virtual function that should be overridden so it returns the address to which the fallback function and {fallback} should delegate.
redirectBeaconProxy
function redirectBeaconProxy(address newBeacon, bytes data, bool forceCall) public
_setBeacon
function _setBeacon(address newBeacon, bytes data, bool forceCall) private
AddressIndexedBitmap
A bitmap that can be efficiently indexed by an (address, uint64) pair.
Best if used as a decorator for a mapping of (uint256 => uint256)
_ADDRESS_SHIFT
uint256 _ADDRESS_SHIFT
getBit
function getBit(mapping(uint256 => uint256) bitmap, address addr, uint64 index) internal view returns (bool)
setBit
function setBit(mapping(uint256 => uint256) bitmap, address addr, uint64 index) internal
set the bit at position index
for addr
in bitmap
Parameters
| Name | Type | Description | | ---- | ---- | ----------- | | bitmap | mapping(uint256 => uint256) | the underlying bitmap - target of decorator | | addr | address | the address to index into the bitmap | | index | uint64 | the bit to set |
setBitRange
function setBitRange(mapping(uint256 => uint256) bitmap, address addr, uint64 start, uint64 end) internal
clearBit
function clearBit(mapping(uint256 => uint256) bitmap, address addr, uint64 index) internal
clear the bit at position index
for addr
in bitmap
Parameters
| Name | Type | Description | | ---- | ---- | ----------- | | bitmap | mapping(uint256 => uint256) | the underlying bitmap - target of decorator | | addr | address | the address to index into the bitmap | | index | uint64 | the bit to clear |
clearBitRange
function clearBitRange(mapping(uint256 => uint256) bitmap, address addr, uint64 start, uint64 end) internal
_addressKey
function _addressKey(address addr) private pure returns (uint256)
ArrayOps
singleton
function singleton(address a) internal pure returns (address[])
singleton
function singleton(uint256 a) internal pure returns (uint256[])
singleton
function singleton(uint64 a) internal pure returns (uint64[])
singleton
function singleton(bool a) internal pure returns (bool[])
fill
function fill(address[] arr, address a) internal pure
BitmapOps
Library for manipulating bitmaps. A bitmap is a uint256 -> uint256 mapping. It is assumed that the "word selector" is actually 64 bits, but we use 256 bits for the mapping key because we can do more with it. However, this means that we always need to provide the full key separately.
getBit
function getBit(mapping(uint256 => uint256) bitmap, uint256 key, uint64 index, uint256 subWordIndexShift) internal view returns (bool)
getBitRangeForWord
function getBitRangeForWord(mapping(uint256 => uint256) bitmap, uint256 key, uint64 start, uint64 end, uint256 subWordIndexShift) internal view returns (uint256)
setBit
function setBit(mapping(uint256 => uint256) bitmap, uint256 key, uint64 index, uint256 subWordIndexShift) internal
setBitRange
function setBitRange(mapping(uint256 => uint256) bitmap, uint256 key, uint64 start, uint64 end, uint256 subWordIndexShift) internal
clearBit
function clearBit(mapping(uint256 => uint256) bitmap, uint256 key, uint64 index, uint256 subWordIndexShift) internal
clearBitRange
function clearBitRange(mapping(uint256 => uint256) bitmap, uint256 key, uint64 start, uint64 end, uint256 subWordIndexShift) internal
_wordIndex
function _wordIndex(uint256 key, uint64 index, uint256 subWordIndexShift) private pure returns (uint256)
BytesOps
toAsciiBytes
function toAsciiBytes(uint64 value) internal pure returns (bytes)
bytesMatchAtOffset
function bytesMatchAtOffset(bytes input, bytes target, uint256 offset) internal pure returns (bool)
slice
function slice(bytes input, uint256 start, uint256 end) internal pure returns (bytes)
flatten
function flatten(bytes[] input, uint256 numSegments) internal pure returns (bytes)
IdCodec
_TEMPLATE_SHIFT
uint256 _TEMPLATE_SHIFT
_SET_SHIFT
uint256 _SET_SHIFT
Decoded
struct Decoded {
uint64 setId;
uint64 templateId;
uint64 serialNumber;
}
encodeAsSetMask
function encodeAsSetMask(uint64 setId) internal pure returns (uint256)
encodeAsTemplateMask
function encodeAsTemplateMask(uint64 setId, uint64 templateId) internal pure returns (uint256)
encodeAsTokenId
function encodeAsTokenId(uint64 setId, uint64 templateId, uint64 serialNumber) internal pure returns (uint256)
decodeSetId
function decodeSetId(uint256 tokenId) internal pure returns (uint64)
decodeTemplateId
function decodeTemplateId(uint256 tokenId) internal pure returns (uint64)
decodeSerialNumber
function decodeSerialNumber(uint256 tokenId) internal pure returns (uint64)
decode
function decode(uint256 tokenId) internal pure returns (struct IdCodec.Decoded decoded)
LockManager
This library provides arbitrary bitmap-based locking facilities for Contracts - 0 | 0 | 0 | 0 Sets - 0 | setIdWordIndex | 0 | 0 Templates - 0 | setId | templateIdWordIndex | 0 Serials - 0 | setId | templateId | serialNumberWordIndex In the above table,
- 0 represents a 64 bit word
- setId, templateId, serialNumber are 64 bit numbers
- each value in the mapping
- a 'word' is a 256 bit segment of the bitmap, LSB aligned
- *WordIndex is the 64-bit index of the word in the bitmap (i / 256)
_SET_SHIFT
uint256 _SET_SHIFT
_TEMPLATE_SHIFT
uint256 _TEMPLATE_SHIFT
_CONTRACT_KEY
uint256 _CONTRACT_KEY
_SET_BLANK_KEY
uint256 _SET_BLANK_KEY
State
struct State {
mapping(uint256 => uint256) locks;
}
isContractLocked
function isContractLocked(struct LockManager.State self) internal view returns (bool)
isSetLocked
function isSetLocked(struct LockManager.State self, uint64 setId) internal view returns (bool)
isTemplateLocked
function isTemplateLocked(struct LockManager.State self, uint64 setId, uint64 templateId) internal view returns (bool)
isSerialLocked
function isSerialLocked(struct LockManager.State self, uint64 setId, uint64 templateId, uint64 serialNumber) internal view returns (bool)
checkContractUnlocked
function checkContractUnlocked(struct LockManager.State self) internal view
checkSetUnlocked
function checkSetUnlocked(struct LockManager.State self, uint64 setId) internal view
checkTemplateUnlocked
function checkTemplateUnlocked(struct LockManager.State self, uint64 setId, uint64 templateId) internal view
lockContract
function lockContract(struct LockManager.State self) internal
lockSets
function lockSets(struct LockManager.State self, uint64[] setIds) internal
checkSerialUnlocked
function checkSerialUnlocked(struct LockManager.State self, uint64 setId, uint64 templateId, uint64 serialNumber) internal view
lockSetRange
function lockSetRange(struct LockManager.State self, uint64 start, uint64 end) internal
lockTemplates
function lockTemplates(struct LockManager.State self, uint64 setId, uint64[] templateIds) internal
lockTemplateRange
function lockTemplateRange(struct LockManager.State self, uint64 setId, uint64 start, uint64 end) internal
lockSerials
function lockSerials(struct LockManager.State self, uint64 setId, uint64 templateId, uint64[] serialNumbers) internal
lockSerialRange
function lockSerialRange(struct LockManager.State self, uint64 setId, uint64 templateId, uint64 start, uint64 end) internal
_templateBlankKey
function _templateBlankKey(uint64 setId) private pure returns (uint256)
_serialBlankKey
function _serialBlankKey(uint64 setId, uint64 templateId) private pure returns (uint256)
_indexToWordIndex
function _indexToWordIndex(uint64 index) private pure returns (uint256)
_setIdWordIndex
function _setIdWordIndex(uint64 setId) private pure returns (uint256)
_templateIdWordIndex
function _templateIdWordIndex(uint64 setId, uint64 templateId) private pure returns (uint256)
_serialNumberWordIndex
function _serialNumberWordIndex(uint64 setId, uint64 templateId, uint64 serialNumber) private pure returns (uint256)
UriEncoder
_SET_TAG
bytes _SET_TAG
_TEMPLATE_TAG
bytes _TEMPLATE_TAG
_SERIAL_TAG
bytes _SERIAL_TAG
_MAX_SEGMENTS
uint256 _MAX_SEGMENTS
encode
function encode(string uri, uint64 setId, uint64 templateId, uint64 serialNumber) internal pure returns (string)