I am trying to understand how to trace a manufacturing process using token compositions, but unsure if it is a good approach.

Basic example:

  • Entity A produces flour
  • Entity B produces bread

Within a smart contract we tokenize the goods, so this means that we will produce some ERC-20 BreadToken(s) if the input is valid (in this case, it must be FlourToken)

This means that any flour batch can be used as a input to satisfy the contract.

In the real world, I might prefer to use a specific batch of flour before it expires, and I want to make sure this is tracked. This means that input needs to be a non fungible token (it still rapresents flour but have additional information like expiration date attached off-chain).

By looking at ERC-721 https://eips.ethereum.org/EIPS/eip-721 what I understood is that the smart contract should output nfts that share the same ERC721Metadata. In this case each Flour batch is identified by an nft having the same ERC721Metadata as the others, and the smart contract will output individual bread nfts.

Are there better options out there? I understand this doesn't scale well due to the cost related to number of nfts to be minted

1 Answer 1


Check out ERC1155. It allows you to batch mint tokens and assign them an ID, but keeping them fungible among each other implicitly. In your implementation you can explicitly code IDs to be fungible among batches as the ERC-1155 safeBatchTransferFrom method and onERC1155BatchReceived method don't place any constraints on the IDs other than that they must map one-to-one to the values array passed to the method:

    @param _ids     IDs of each token type (order and length must match _values array)
function safeBatchTransferFrom(address _from, address _to, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external;
    @param _ids       An array containing ids of each token being transferred (order and length must match _values array)
function onERC1155BatchReceived(address _operator, address _from, uint256[] calldata _ids, uint256[] calldata _values, bytes calldata _data) external returns(bytes4);

Code snippet from Enjin Coin's implementation of ERC-1155:

// Creates a new token type and assings _initialSupply to minter
function create(uint256 _initialSupply, string calldata _uri) external returns(uint256 _id) {

    _id = ++nonce;
    creators[_id] = msg.sender;
    balances[_id][msg.sender] = _initialSupply;

    // Transfer event with mint semantic
    emit TransferSingle(msg.sender, address(0x0), msg.sender, _id, _initialSupply);

     if (bytes(_uri).length > 0)
        emit URI(_uri, _id);

// Batch mint tokens. Assign directly to _to[].
function mint(uint256 _id, address[] calldata _to, uint256[] calldata _quantities) external creatorOnly(_id) {

    for (uint256 i = 0; i < _to.length; ++i) {

        address to = _to[i];
        uint256 quantity = _quantities[i];

        // Grant the items to the caller
        balances[_id][to] = quantity.add(balances[_id][to]);

        // Emit the Transfer/Mint event.
        // the 0x0 source address implies a mint
        // It will also provide the circulating supply info.
        emit TransferSingle(msg.sender, address(0x0), to, _id, quantity);

        if (to.isContract()) {
            _doSafeTransferAcceptanceCheck(msg.sender, msg.sender, to, _id, quantity, '');

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.