[Ethereum] Finding the index of an array element

go-ethereumsolidity

I posted a question 1 day ago asking if it was possible to have multiple coin types in a single contract and I am trying to implement the answer I received.

Is it possible to have multiple coin types in one contract?

The answer said to use nested mappings which works perfect for me, but I can't have:

mapping string => mapping (address => uint)) coinBalanceOf; 

because it generates an error "Accessors for mapping with dynamically-sized keys not yet implemented"

So I am trying to find a way around this so that I can have multiple coin types in a single contract but allow the user to specify a string as the coin type when they use the transfer function in my contract instead of an integer.

For example here was the answer code from my last question:

contract token { 
  mapping (uint => mapping (address => uint)) coinBalanceOf;
  event CoinTransfer(uint coinType, address sender, address receiver, uint amount);

  /* Initializes contract with initial supply tokens to the creator of the contract */
  function token(uint numCoinTypes, uint supply) {
    for (uint k=0; k<numCoinTypes; ++k) {
    coinBalanceOf[k][msg.sender] = supply;
  }
}

/* Very simple trade function */
function sendCoin(uint coinType, address receiver, uint amount) returns(bool sufficient) {
  if (coinBalanceOf[coinType][msg.sender] < amount) return false;

  coinBalanceOf[coinType][msg.sender] -= amount;
  coinBalanceOf[coinType][receiver] += amount;

  CoinTransfer(coinType, msg.sender, receiver, amount);

  return true;

}

When creating this contract it takes the number of coin types and uses that to create a nested mapping of addresses so it contains "1, 2, and 3" and the user can specify which type they want to transfer and how much they want to transfer.

What I want is for the user to be able to say they want to transfer "Type 1" instead of just specifying "1" under the coin type. I want to do this because in example I used Coin Type 1, Coin Type 2, etc but in reality they aren't going to be named like that and the user won't know the index number associated with each coin type.

My initial thought was to have something like this:

contract token {
  string[] public assets = [
    'Coin 1',
    'Coin 2',
    'Coin 3'
  ];

  mapping (uint => mapping (address => uint)) public coinBalanceOf;
  event CoinTransfer(string coinType, address sender, address receiver, uint amount);

  function token(uint256 initialSupply) {
    if (initialSupply == 0) initialSupply = 1000000;

    uint length = assets.length;

    for (uint k=0; k<length; ++k) {
      coinBalanceOf[k][msg.sender] = initialSupply;
    }
  }

  function sendCoin(string coinType, address receiver, uint amount) returns(bool sufficient) {
    uint Index = getIndex(coinType);

    if (coinBalanceOf[Index][msg.sender] < amount) return false;

    coinBalanceOf[Index][msg.sender] -= amount;
    coinBalanceOf[Index][receiver] += amount;

    CoinTransfer(coinType, msg.sender, receiver, amount);

    return true;
  }

  function getIndex(string coinType) {
    for(uint i = 0; i<assets.length; i++){
      if(coinType == assets[i]) return i;
    }
  }
}

But I get an error when trying to call the getIndex function "Not enough components (0) in value to assign all variables (1)." and I'm not sure where to go from here.

Any help is greatly appreciated!

Best Answer

A popular alternative to index mapping with strings is to apply sha3 to the string. Instead of mapping (string => Document) documents; you have to use mapping (bytes32 => Document) documents;

Now to access each document instead of accessing with the string directly you apply the sha3 function. Chaging documents["Very Important Document.pdf"] to documents[sha3("Very Important Document.pdf")].

Related Topic