2

I'm trying to build a second layer to erc721 nft.

The problem is: I believe totalsupply is not in the proper format, but I'm not sure how to get totalSupply to be a uint passable into mint().

If I hardcode mint(_caller,1) it works. But mint(_caller,totalSupply) doesn't.

   pragma solidity ^0.4.18;


/**
 * Interface for required functionality in the ERC721 standard
 * for non-fungible tokens.
 *
 * Author: Nadav Hollander (nadav at dharma.io)
 */
contract ERC721 {
    // Function
    function totalSupply() public returns (uint256 _totalSupply);
    function balanceOf(address _owner) public view returns (uint256 _balance);
    function ownerOf(uint _tokenId) public view returns (address _owner);
    function approve(address _to, uint _tokenId) public;
    function getApproved(uint _tokenId) public view returns (address _approved);
    function transferFrom(address _from, address _to, uint _tokenId) public;
    function transfer(address _to, uint _tokenId) public;
    function implementsERC721() public view returns (bool _implementsERC721);

    // Events
    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);
    event Approval(address indexed _owner, address indexed _approved, uint256 _tokenId);
}

/**
 * Interface for optional functionality in the ERC721 standard
 * for non-fungible tokens.
 *
 * Author: Nadav Hollander (nadav at dharma.io)
 */
contract DetailedERC721 is ERC721 {
    function name() public view returns (string _name);
    function symbol() public view returns (string _symbol);
    function tokenMetadata(uint _tokenId) public view returns (string _infoUrl);
    function tokenOfOwnerByIndex(address _owner, uint _index) public view returns (uint _tokenId);
}


/**
 * @title NonFungibleToken
 *
 * Generic implementation for both required and optional functionality in
 * the ERC721 standard for non-fungible tokens.
 *
 * Heavily inspired by Decentraland's generic implementation:
 * https://github.com/decentraland/land/blob/master/contracts/BasicNFT.sol
 *
 * Standard Author: dete
 * Implementation Author: Nadav Hollander <nadav at dharma.io>
 */
contract NonFungibleToken is DetailedERC721 {
    string public name;
    string public symbol;
    address public owner;
    address public agServiceContract;
    uint256 public numTokensTotal;

    mapping(uint => address) internal tokenIdToOwner;
    mapping(uint => address) internal tokenIdToApprovedAddress;
    mapping(uint => string) internal tokenIdToMetadata;
    mapping(address => uint[]) internal ownerToTokensOwned;
    mapping(uint => uint) internal tokenIdToOwnerArrayIndex;

    event Transfer(address indexed _from, address indexed _to, uint256 _tokenId
    );

    event Approval( address indexed _owner, address indexed _approved, uint256 _tokenId
    );

    modifier onlyExtantToken(uint _tokenId) {
        require(ownerOf(_tokenId) != address(0));
        _;
    }
    function NonFungibleToken(){
        owner = msg.sender;
    }

    function name()
        public
        view
        returns (string _name)
    {
        return name;
    }

    function symbol()
        public
        view
        returns (string _symbol)
    {
        return symbol;
    }

    function totalSupply()
        public

        returns (uint256 _totalSupply)
    {
        return numTokensTotal;
    }

    function balanceOf(address _owner)
        public
        view
        returns (uint _balance)
    {
        return ownerToTokensOwned[_owner].length;
    }
    function setAgContract(address addr) {
        require(msg.sender == owner);
        agServiceContract = addr;
    }

    function ownerOf(uint _tokenId)
        public
        view
        returns (address _owner)
    {
        return _ownerOf(_tokenId);
    }

    function tokenMetadata(uint _tokenId)
        public
        view
        returns (string _infoUrl)
    {
        return tokenIdToMetadata[_tokenId];
    }

    function approve(address _to, uint _tokenId)
        public
        onlyExtantToken(_tokenId)
    {
        require(msg.sender == ownerOf(_tokenId)|| msg.sender == agServiceContract);
        require(msg.sender != _to);

        if (_getApproved(_tokenId) != address(0) ||
                _to != address(0)) {
            _approve(_to, _tokenId);
            Approval(msg.sender, _to, _tokenId);
        }
    }

    function transferFrom(address _from, address _to, uint _tokenId)
        public
        onlyExtantToken(_tokenId)
    {
        require(getApproved(_tokenId) == msg.sender || msg.sender == agServiceContract);
        require(ownerOf(_tokenId) == _from || msg.sender == agServiceContract);
        require(_to != address(0));

        _clearApprovalAndTransfer(_from, _to, _tokenId);

        Approval(_from, 0, _tokenId);
        Transfer(_from, _to, _tokenId);
    }

    function transfer(address _to, uint _tokenId)
        public
        onlyExtantToken(_tokenId)
    {
        require(ownerOf(_tokenId) == msg.sender || msg.sender == agServiceContract);
        require(_to != address(0));

        _clearApprovalAndTransfer(msg.sender, _to, _tokenId);

        Approval(msg.sender, 0, _tokenId);
        Transfer(msg.sender, _to, _tokenId);
    }

    function tokenOfOwnerByIndex(address _owner, uint _index)
        public
        view
        returns (uint _tokenId)
    {
        return _getOwnerTokenByIndex(_owner, _index);
    }

    function getOwnerTokens(address _owner)
        public
        view
        returns (uint[] _tokenIds)
    {
        return _getOwnerTokens(_owner);
    }

    function implementsERC721()
        public
        view
        returns (bool _implementsERC721)
    {
        return true;
    }

    function getApproved(uint _tokenId)
        public
        view
        returns (address _approved)
    {
        return _getApproved(_tokenId);
    }

    function _clearApprovalAndTransfer(address _from, address _to, uint _tokenId)
        internal
    {
        _clearTokenApproval(_tokenId);
        _removeTokenFromOwnersList(_from, _tokenId);
        _setTokenOwner(_tokenId, _to);
        _addTokenToOwnersList(_to, _tokenId);
    }

    function _ownerOf(uint _tokenId)
        internal
        view
        returns (address _owner)
    {
        return tokenIdToOwner[_tokenId];
    }

    function _approve(address _to, uint _tokenId)
        internal
    {
        tokenIdToApprovedAddress[_tokenId] = _to;
    }

    function _getApproved(uint _tokenId)
        internal
        view
        returns (address _approved)
    {
        return tokenIdToApprovedAddress[_tokenId];
    }

    function _getOwnerTokens(address _owner)
        internal
        view
        returns (uint[] _tokens)
    {
        return ownerToTokensOwned[_owner];
    }

    function _getOwnerTokenByIndex(address _owner, uint _index)
        internal
        view
        returns (uint _tokens)
    {
        return ownerToTokensOwned[_owner][_index];
    }

    function _clearTokenApproval(uint _tokenId)
        internal
    {
        tokenIdToApprovedAddress[_tokenId] = address(0);
    }

    function _setTokenOwner(uint _tokenId, address _owner)
        internal
    {
        tokenIdToOwner[_tokenId] = _owner;
    }

    function _addTokenToOwnersList(address _owner, uint _tokenId)
        internal
    {
        ownerToTokensOwned[_owner].push(_tokenId);
        tokenIdToOwnerArrayIndex[_tokenId] =
            ownerToTokensOwned[_owner].length - 1;
    }

    function _removeTokenFromOwnersList(address _owner, uint _tokenId)
        internal
    {
        uint length = ownerToTokensOwned[_owner].length;
        uint index = tokenIdToOwnerArrayIndex[_tokenId];
        uint swapToken = ownerToTokensOwned[_owner][length - 1];

        ownerToTokensOwned[_owner][index] = swapToken;
        tokenIdToOwnerArrayIndex[swapToken] = index;

        delete ownerToTokensOwned[_owner][length - 1];
        ownerToTokensOwned[_owner].length--;
    }

    function _insertTokenMetadata(uint _tokenId, string _metadata)
        internal
    {
        tokenIdToMetadata[_tokenId] = _metadata;
    }
}

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, throws on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }

  /**
  * @dev Integer division of two numbers, truncating the quotient.
  */
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  /**
  * @dev Substracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
  */
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }

  /**
  * @dev Adds two numbers, throws on overflow.
  */
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}

/**
 * @title MintableNonFungibleToken
 *
 * Superset of the ERC721 standard that allows for the minting
 * of non-fungible tokens.
 */
contract MintableNonFungibleToken is NonFungibleToken {
    using SafeMath for uint;

    event Mint(address indexed _to, uint256 indexed _tokenId);

    modifier onlyNonexistentToken(uint _tokenId) {
        require(tokenIdToOwner[_tokenId] == address(0));
        _;
    }

    function mint(address _owner, uint256 _tokenId) public onlyNonexistentToken(_tokenId){
        _setTokenOwner(_tokenId, _owner);
        _addTokenToOwnersList(_owner, _tokenId);

        numTokensTotal = numTokensTotal.add(1);


        Mint(_owner, _tokenId);
    }
}


        contract agService {
             using SafeMath for uint;
            address public owner;

            modifier onlyOwner(){
                require(msg.sender == owner);
                _;
            }
             modifier onlyFarmers(){
                require(msg.sender == owner);
                _;
            }
            MintableNonFungibleToken public nft;
            uint256 totalSupply;

            address[] approvedFarmers;
            function agService(){
                owner = msg.sender;

            }


            function setNFTAddress(address addr) onlyOwner{
                nft = MintableNonFungibleToken(addr);
            }

            function createNFT() onlyFarmers{

                address _caller;
                _caller = msg.sender;
        /*tried both ways totalSupply123(), and totalSupply = nft.totalSupply(); */
                totalSupply123();
        /* totalSupply = nft.totalupply(); */

                nft.mint(_caller, totalSupply); 

            }


         function totalSupply123
             ()



            { 
                totalSupply = nft.totalSupply();
            }
}

Once I create MintableNonFungibleToken and AgService, I set the mintable address setNFTaddress(). Then in createNFT() I type "0,0" in remix (for the date and weight) and press it. I get

transact to agService.createNFT errored: VM error: invalid opcode. invalid opcode
The execution might have thrown. Debug the transaction to get more information.

  • Can you fix your code? There are missing curly braces and no definition of DetailedERC721. It's hard to debug without code that compiles. – smarx Feb 13 '18 at 0:02
  • I didn't want to include all the extra, sorry about that. I've updated it in an edit. – Zach Feb 13 '18 at 0:36
  • I can't reproduce the issue. I pasted the code into Remix, deployed a new MintableNonFungibleToken, deployed a new agService, called setNFTAddress (passing the address of the MintableNonFungibleToken I deployed), and then called createNFT, and everything executed without error. – smarx Feb 13 '18 at 0:47
  • Please see my edit – Zach Feb 13 '18 at 1:33
  • Sorry for the bother. The 721 standard is quite different than what is currently in OpenZeppelin (it seems that's what you started from). Please see the updated #721/#841. – William Entriken Mar 7 '18 at 20:09
1

This line in createNFT is the problem:

farmersHistoryViewable[msg.sender].weightByBatch[0][farmersHistoryViewable[msg.sender].totalBatches] = _weight;

farmersHistoryViewable maps addresses to structs of type farmersHistory:

struct farmersHistory {
    uint totalBatches;
    uint256 totalWeight;
    uint[1][] weightByBatch;
}

weightByBatch is really strange... it's a dynamic array of 1-length arrays. (What's the purpose of a 1-length array?)

In any case, weightByBatch[0] is always going to fail, since the array always has length zero. (Nothing in the code ever adjusts its length.)

This replacement sort of works, but it's unclear to me what you're trying to do, so I don't know if it accomplishes your goals. (It seems likely that you want to get rid of the second dimension of the array altogether.)

farmersHistoryViewable[msg.sender].weightByBatch.push([_weight]);
farmersHistoryViewable[msg.sender].totalBatches = farmersHistoryViewable[msg.sender].totalBatches.add(1);

(The second line of code is because your existing code didn't actually add one to totalBatches. It computed the result of adding one but then discarded it.)

There are other issues here: notably, you create a token with the ID from nft.totalSupply(), but then everything else you store is keyed off of the new value of nft.totalSupply() (which has increased in the call to mint). So your IDs are going to be mismatched between the nft contract and the agService instance.

  • weightByBatch is supposed to be a two-dimensional array that tracks the weight of each Batch completed by the farmer. I wanted to keep it all within the struct, and a mapping wouldn't of worked (I'm not too sure) This is all just work in progress and I was simply testing as I go. Thank you, your code works. Also, good catch on totalSupply not updating properly. Thank you very much – Zach Feb 13 '18 at 2:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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