In my previous post, I explained the basic concept of how one would get one contract to talk to another through function calls using minimal contract definitions. In this post I would like to explain how to send strings from one contract to another.

This will essentially be a continuation of the previous tutorial.

If you get lost or want to skip everything and just see the code along with the tests, you can find the code here.

Preface

This article was published a few days before solidity 0.4.22 came out. In the 0.4.22 release, which allows for dynamic returns from contracts. This means that strings can be returned! Essentially this means that this tutorial is now worthless. There are some neat things done with strings here if you want to dive deeper into that subject, otherwise just use strings. Unless you are trying to save on gas costs.

Prerequisites

Truffle Installed Basic Experience with Smart Contracts Basic Experience with Truffle Completion of Last Tutorial or at least an Understanding of the concepts

Getting Started

Clone the repo found here to start from where we left off in the previous tutorial.

The Problem that Needs Solving

The main issue is that strings are arrays in solidity. What’s the issue with that? Well… when sending data from one smart contract to another, it must be a fixed size! This means that dynamically sized arrays, such as strings, will not be able to be sent from one contract to another. This means that we are going to need to set this to a fixed size byte array.

Why Bytes?

Bytes are the lower level data type that is used to create strings. Perhaps you have seen the ascii table around before. Each character in the ascii table takes one byte. Characters used for other languages than english typically use two bytes. With bytes, we will be able to put them into a fixed size array which will allow us to send this data to another contract.

If you want to learn more about strings, characters, their relation to bytes, and how they are encoded, check out this great article which gives a pretty great explanation as well as history lesson regarding character encoding.

What are We Going to Do?

So essentially what we are going to be doing here is converting a string to an explicitly set fixed size array of bytes. Each byte will represent a character. There are two different ways of handling this depending on the situation. Strings are fun in solidity!

The First Way (Simple but Limited)

When your string is less than 32 characters, you can simply use the bytes32 type to transport your string from one contract to another. If your string is larger than 32 characters you will need to use the second way.

Why bytes32 ?

bytes32 is the largest bytes array type that has a static length. You can use this for, you guessed it, 32 characters. If you are sure that your strings will be of a certain length that is shorter than 32 characters you can also use something even smaller to save space: bytes8 for instance for an 8 character long string.

ExampleUser.sol

Open up ExampleUser.sol . We are going to need to convert a string to bytes32 . Lets start by making the function we need. Add this code to the bottom of our contract:

In the above code, we have created a pure function (does not access or up.date state) which uses some assembly to directly access the string at the memory pointer and load it into _stringBytes . We then return the bytes that we accessed by memory.

It is worth noting that when we are using mload and passing in _string we are getting access to the memory pointer. The add function is essentially giving us an offset of 32 in order to skip over non-essential data that isnt the actual bytes that we want.

Lets create our function that will send our string bytes over to ExampleContract . You can put this code just above the toBytes32 function:

Simple! All we are doing is making use of the toBytes32 function which we have already created and setting it on ExampleContract . This will not work yet because we need to create the setShortString function on our ExampleContract . Let’s jump over there and get things ready to receive the bytes32 we plan on sending.

ExampleContract.sol

Open up ExampleContract.sol .

For the sake of the tutorial we are going to convert the bytes32 we are getting from ExampleUser back to a string so that we can easily read it and see what is happening. It is worth mentioning though that it is possible and much more efficient to just keep everything on the smart contract side as bytes and not bother converting to a string . You can then do any string conversions you need on the client side in order to save gas.

Let’s go ahead and create our bytes32 to string conversion function. This is quite a bit more complicated than the toBytes32 function. Try reading through the comments to digest what is going on here. Put this code at the bottom of your ExampleContract file (inside the contract of course):

Let’s try and break this down in order of what is happening:

create new bytes with a length of 32 (line 9)

We know that we are loading in a bytes32 type due to our function argument. So we are going to create a new bytes type with the same length. We are doing this because bytes is readable/writeable. bytes32 is only readable.

initialize character counter (line 12)

We need this in order to get the actual length of our string that we are getting out of bytes32 . bytes32 is a fixed size (32 bytes), so there probably will be some padding in here that we will need to strip out. Keeping track of the length when looping will enable us to trim the string later on.

for loop (line 14)

We are just setting up a regular for loop here nothing too special. I changed the names in order to try to make things a bit more clear. But this is essentially the same as:

for(uint256 i = 0; i < 32; i++)

Normally you do not want to do loops in solidity due to gas limits, but we know that we are only going to be looping 32 times so everything should be fine.

convert byte to character (line 23)

TLDR: takes a single character from bytes based on counter

convert bytes32 data to uint in order to increase the number enough to

shift bytes further left while pushing out leftmost bytes

then convert uint256 data back to bytes32

then convert to bytes1 where everything but the leftmost hex value (byte)

is cutoff leaving only the leftmost byte

Oh boy, this one is a bit nested… but what it is doing is we are converting bytes32 to a uint in order to shift bytes further left and push out the leftmost bytes. We are then converting back into bytes32 and then bytes1 in order to cutoff to just the first byte which is the character we want at that point in the loop. This is mostly the same as what the comment says in the code.

The key things to learning this is that:

You can convert to a smaller bytes type which will cutoff any excess data. Example: converting bytes32 to bytes30 will result in a loss of 2 bytes .

type which will cutoff any excess data. Example: converting to will result in a loss of 2 . a single byte is 8 bits, this plays into the math involved.

If you are having trouble grappling with this, try playing with this EthFiddle in order to get comfortable with the concepts. First deploy via EthFiddle. Then try toBytes32 giving it an argument of test and 32 . You should get back

0x7465737400000000000000000000000000000000000000000000000000000000

This is ‘test’ padded to be bytes32 since test only takes 4 bytes it is padded for the rest of the bytes with 00 (remember each byte is a hex value: 74 = ‘t’, 65=’e’, etc.)

Use this result in testBytesToChar with an offset of 0 and you should get ‘t’.

Try it with 1 up to 31 (after 3 should be 00 if you are using ‘test’) to see the different results for each of the loops. You can also uncomment the different return statements in order to take a look at what the uint256 and converted bytes32 look like.

check for empty character (lines 25–30)

After we have gotten our character, we are going to check if it is empty. Remember that we have a bytes32 argument for this function, which means that if the string is less than 32 characters, we are going to have padding.

If the character is not empty, we assign the character to the _bytesContainer that we created earlier and increment the _charCount for trimming padding later.

create bytes for trimming (line 63)

Simple: as said above, we are just going to create a new bytes with a length that is the same as our _charCount .

copy over _bytesContainer to _bytesContainerTrimmed (lines 66 -69)

Here, we are doing another loop to loop over our 32 length bytes and copying over the non-empty bytes to our trimmed bytes instance.

convert to string and return (line 72)

Now that we have trimmed out the padding from our initial bytes32 argument we can now convert to a string and return. phew!

The last function that we are going to need will be an easy one!

First add: string public shortString; below uint256 public someNumber; near the top of the contract.

Then add the following above the toShortString function:

All we are doing here is making use of the toShortString function that we created a few minutes ago. We are setting the global shortString string to the value returned from our toShortString function. The function is public so this can be called from another contract, such as ExampleUser .

This should be all we need! Let’s create some tests to see it in action.

Testing (ExampleUser.js)

Open up ExampleUser.js in your tests directory and add in the following code at the bottom outside of any other describe blocks:

There is a testWillThrow function in there that we are going to need to define as well. Lets put that at the top under our require s.

What we are doing in these tests is just checking that our toBytes32 and toShortString functions are returning the correct values. We also test that toBytes32 only takes strings that are 32 characters long at most.

Lets make sure that we are actually getting the value we want from ExampleUser set in ExampleContract (put this after and outside of the last describe block):

In the above test, we are setting the string from ExampleUser and checking that it is set on ExampleContract . Let’s run the tests!

truffle test

You should get 7 passing tests (including the previous tutorial’s tests):

when using our beautiful example contract

Contract: ExampleContract

✓ should setNumber (69ms)

✓ should addNumbers when using our beautiful example user with example contract

Contract: ExampleContract/ExampleUser

✓ should addNumbers using ExampleContract (55ms) when testing our new utility functions

Contract: ExampleContract/ExampleUser

✓ should convert a short string to bytes32 on ExampleUser

✓ should NOT convert string more than 32 characters using toBytes32

✓ should convert bytes32 to a short string (87ms) when handling strings less than or equal to 32 characters

Contract: ExampleContract/ExampleUser

✓ should set a given string on ExampleContract from ExampleUser contract (97ms) 7 passing (787ms)

Looks good!

The Second Way (More Complex but Less Limited)

I originally wanted to cover both long strings and short strings in this tutorial, but the article turned out to run rather long. I will make another post about strings longer than 32 characters soon. A quick explanation is given below regardless: