| title | Chained NFTs to put Files and Code On-Chain | ||
|---|---|---|---|
| author | Marco Vasapollo (@marcovasapollo), Alessandro Mario Lagana Toschi (@alet89) | ||
| status | Draft | ||
| type | Standards Track | ||
| category | ERC | ||
| created | 2019-04-19 | ||
| requires |
|
A simple way to put files and code into chained NFTs to improve the decentralization of modern Dapps and DAOs
Put complex files On-Chain, surpassing the Ethereum Block's size limits via a combination of chained Non-Fungible Tokens, generated by splitting the hexadecimal code of a file different NFTs. Every Chained NFT is a part of a sequence based on the deployed file, saved by an array into the Smart Contract.
Modern Dapps are using centralized servers or distributed systems like IPFS to store Images and the Front-End part. This is a simple point of failure because with this setup a dapp still needs a well-known organization to rule it, at the end of the day this setup makes dapps not totally censorship-resistant especially if we focussed on non-financial applications. As well as ENS will remove the needs of a censurable DNS, this EIP is designed to put small files directly On-Chain removing as much as possible the censurable part of future Dapps.
Every NFT token is like a normal ERC-721 Token, with some methods to mint and finalize chained bunches of data:
pragma solidity ^0.5.0;
contract IRobe /* is IERC721 */ {
/// @dev Creates a new NFT Token with this specified payload of data.
/// @return a unique id representing this single NFT
function mint(bytes calldata payload) external returns(uint256);
/// @dev Creates a new NFT Token with this specified payload of data,
/// but it will be not possible to concatenate new NFTs to this one anymore.
/// @return a unique id representing this single NFT
function mintAndFinalize(bytes calldata payload) external returns(uint256);
/// @dev Attaches a new NFT to an already-existing one to expand it.
/// rootTokenId must represent the very first one id of the chain to be expanded
/// @return a unique id representing this single NFT
function mint(uint256 rootTokenId, bytes calldata payload) external returns(uint256);
/// @dev Attaches a new NFT to an already-existing one to expand it,
/// but it will be not possible to concatenate new NFTs to this one anymore.
/// rootTokenId must represent the very first one id of the chain to be expanded
/// @return a unique id representing this single NFT
function mintAndFinalize(uint256 rootTokenId, bytes calldata payload) external returns(uint256);
/// @dev Finalizing an NFT means that you cannot expand anymore the chain of concatenated
/// NFTs this id represents
function finalize(uint256 rootTokenId) external;
/// @dev Returns true if this tokenId belongs to a finalized chain.
/// False otherwise.
function isFinalized(uint256 tokenId) external view returns(bool);
/// @dev Returns all the tokenIds that composes the givend NFT
function getChain(uint256 tokenId) external view returns(uint256[] memory);
/// @dev Returns the root NFT of this tokenId
function getRoot(uint256 tokenId) external view returns(uint256);
///@dev Returns the content payload of the specified NFT
function getContent(uint256 tokenId) external view returns(bytes memory);
///@dev Returns the position this NFT has in the NFTs chain it belongs to
function getPositionOf(uint256 tokenId) external view returns(uint256);
///@dev Returns the Id of the NFT at the specific position in the chain represented by the given rootTokenId
function getTokenIdAt(uint256 rootTokenId, uint256 position) external view returns(uint256);
///@dev Syntactic sugar - Gives all the information of a specific NFT:
/// its position in the chain
/// the address of the wallet that minted it
/// its data payload
function getCompleteInfo(uint256 tokenId) external view returns(uint256, address, bytes memory);
///@dev event raised everytime a new NFT is minted,
/// with the root of the NFTs chain, the new id already created and the address of the wallet that submitted the transaction.
/// When the minted id is the root of the NFT chain, rootTokenId and newTokenId will have the same value
event Mint(uint256 indexed rootTokenId, uint256 indexed newTokenId, address indexed sender);
///@dev event raised when a NFT chain is finalized and it will be not possible anymore to expand it
event Finalize(uint256 indexed rootTokenId);
}
/// @title ERC-721 Non-Fungible Token Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x80ac58cd.
interface ERC721 /* is ERC165 */ {
/// @dev This emits when ownership of any NFT changes by any mechanism.
/// This event emits when NFTs are created (`from` == 0) and destroyed
/// (`to` == 0). Exception: during contract creation, any number of NFTs
/// may be created and assigned without emitting Transfer. At the time of
/// any transfer, the approved address for that NFT (if any) is reset to none.
event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
/// @dev This emits when the approved address for an NFT is changed or
/// reaffirmed. The zero address indicates there is no approved address.
/// When a Transfer event emits, this also indicates that the approved
/// address for that NFT (if any) is reset to none.
event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
/// @dev This emits when an operator is enabled or disabled for an owner.
/// The operator can manage all NFTs of the owner.
event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256);
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT. When transfer is complete, this function
/// checks if `_to` is a smart contract (code size > 0). If so, it calls
/// `onERC721Received` on `_to` and throws if the return value is not
/// `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
/// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
/// @notice Transfers the ownership of an NFT from one address to another address
/// @dev This works identically to the other function with an extra data parameter,
/// except this function just sets data to "".
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
/// @notice Change or reaffirm the approved address for an NFT
/// @dev The zero address indicates there is no approved address.
/// Throws unless `msg.sender` is the current NFT owner, or an authorized
/// operator of the current owner.
/// @param _approved The new approved NFT controller
/// @param _tokenId The NFT to approve
function approve(address _approved, uint256 _tokenId) external payable;
/// @notice Enable or disable approval for a third party ("operator") to manage
/// all of `msg.sender`'s assets
/// @dev Emits the ApprovalForAll event. The contract MUST allow
/// multiple operators per owner.
/// @param _operator Address to add to the set of authorized operators
/// @param _approved True if the operator is approved, false to revoke approval
function setApprovalForAll(address _operator, bool _approved) external;
/// @notice Get the approved address for a single NFT
/// @dev Throws if `_tokenId` is not a valid NFT.
/// @param _tokenId The NFT to find the approved address for
/// @return The approved address for this NFT, or the zero address if there is none
function getApproved(uint256 _tokenId) external view returns (address);
/// @notice Query if an address is an authorized operator for another address
/// @param _owner The address that owns the NFTs
/// @param _operator The address that acts on behalf of the owner
/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
interface ERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
The implications are massive, we're testing this EIP with the DFO project to create community-driven DAOs without need to a well know organization or a well-known team of developers to rule and developing it. DFOs are designed to be built by anonymous people without trust each other, using ENS, this EIP and a smart way to code Smart Contracts like microservices. DFO it's already working in its Alpha https://dfohub.com. Another interesting use of this EIP is about the ownership of art without trust entities, transacting every part of the history of the developing of digital goods, so trusting the history without known the creator. The most common use will be for the Front-End of Dapps, we're working on simplifying the usage of this EIP for every Dapp developer, you can test it here: https://robe.ninja.
Copyright and related rights waived via CC0.