In this article, we'll discuss a few more fundamental datatypes in Solidity programming, namely: strings, bytes, and address types.
This article is based on notes from this Blockchain Developer course and is organized as follows:
- Strings with Solidity
- Bytes with Solidity
- Address Types
- Understanding the Msg. Object
Stay up to date with AI
Strings with Solidity
Strings are actually arrays in Solidity and very similar to byte arrays.
Let's break down what that means in more detail.
Strings are quite unique in Solidity compared to other programming languages in that there are no string manipulation functions, except you can concatenate strings.
Other than concatenation, there are no string manipulation functions. The reason for this is that strings are very expensive to store on a blockchain.
Let's get started with an example with a new file in Remix called ExampleStrings.sol
.
We'll then add our pragma
line and start a new contract ExampleStrings
and define a public "Hello World" string as follows:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleStrings {
string public myString = "Hello World";
}
Next, we'll add a setter function for it, and place the _myString
parameter within a memory
location.
Memories are an ephemeral data location to work within functions, or during the transaction, meaning the memory location will be gone after the transaction is completed.
In order to make this permanent, we simply need to bring it to a storage location as follows:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleStrings {
string public myString = "Hello World";
function setMyString(string memory _myString) public {
myString = _myString;
}
}
Now if we deploy this contract we can now update our string with the setter function:
Comparing two strings
If we want to compare two strings we can create a function that will tell us if the string is the same as the string that was previously stored.
In this case, we will make this a public view
function, which means it's a reading function that can return something, in this case we will return a boolean.
If we try and use return myString == _myString;
we will get an error because their is no native comparison for strings in Solidity.
To resolve this we need to use the keccak256
hash of both strings, and we also have to use abi.encodePacked
since this hash function requires a single bytes argument:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleStrings {
string public myString = "Hello World";
function setMyString(string memory _myString) public {
myString = _myString;
}
function compareTwoStrings(string memory _myString) public view returns(bool) {
return keccak256(abi.encodePacked(myString)) == keccak256(abi.encodePacked(_myString));
}
}
If we redeploy this our initial string is "Hello World" and compare it to a different string we see the boolean returns false
:
In this case, we're not actually comparing the strings but comparing the hashes of the strings.
Bytes with Solidity
There is a difference between bytes and strings, although we can add a line of bytes public myBytes = "Hello World";
and it will return a byte representation of the string:
Aside from that, the main differences between bytes and strings are:
- Bytes have a length and can be converted into strings
- You cannot convert every string into bytes and get the length because strings are represented in UTF8 while bytes are not
This means that sometimes a character is represented by two bytes and other times by one byte.
This is why, in general, it is not very advisable to use strings in smart contracts, although we will still continue working with them for demonstration purposes.
Address Types
One datatype that is very specific to Solidity is the address type.
Address types store 20 bytes worth of an Ethereum address or an Ethereum account.
Let's see how address types work by creating new file in remix called ExampleAddress.sol
and a contract with the same name.
We'll then create an address type, make it public, and call it someAdress
:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleAddress {
address public someAddress;
}
If we deploy this, we see that by default the address is 0x...
followed by 40 0's, or 20 bytes worth of 0's.
If we want to set this to a different address we can create a function setSomeAddress
as follows:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleAddress {
address public someAddress;
function setSomeAddress(address _someAddress) public {
someAddress = _someAddress;
}
}
Now if we try and set the address to 0x01, we see we get an "incorrect address" error as we need the exact characters for an address.
Instead, we can get a correct address from Remix above, copy it to our clipboard, and then change the address without any errors:
Getting the balance of an address
Addresses also have a member property for the balance.
We can get the balance of an address by:
- Creating function called
getAddressBalance()
- We will make it a
public view
function because we will read something and will return an unsigned integer - We will then return
someAddress.balance
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleAddress {
address public someAddress;
function setSomeAddress(address _someAddress) public {
someAddress = _someAddress;
}
function getAddressBalance() public view returns(uint) {
return someAddress.balance;
}
}
Now if we deploy this contract and set the address to one of the test addresses provided by Remix we can then return the balance:
Understanding the Msg. Object
One more variable to discuss in this article is the messenger object, in particular, the property msg.sender
.
The messenger object is a key part of Ethereum blockchain programming as it highlights the difference between a classical, centralized database and a blockchain-based one where we have public and private keys.
To start, we'll create a new contract called ExampleMsgSender.sol
and start it off similar to our ExampleAddress
contract above with a public address.
We'll then add a function called updateSomeAddress()
without passing in any parameters and we'll set someAddress
to msg.sender
:
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
contract ExampleAddress {
address public someAddress;
function updateSomeAddress() public {
someAddress = msg.sender;
}
}
The msg
object is a public object that is available through all your contracts and contracts and contains several properties:
- The
sender
property contains the address of the person who is interacting with the smart contract - If an account is calling the contract, it will contain the address of the account
- This also means if one contract is interacting with another contract, the
msg.sender
will contain the address of the last point of contact
If we deploy this contract we see that someAdress
is 0x0...
initially, and if we hit updateSomeAddress
it will automatically change to the last address that interacted with the contract:
Summary: Strings, Bytes, and Address Types with Solidity
In this article, we discussed key data types in Solidty: strings, bytes, and address types. A few key points to remember are:
- Strings are actually arrays in Solidity and are very similar to byte arrays
- Memories are an ephemeral data location to work within functions, or during the transaction, meaning the memory location will be gone after the transaction is completed.
- The main difference between bytes and strings is that bytes have a length and can be converted into strings. You cannot convert every string into bytes and get the length because strings are represented in UTF8 while bytes are not.
- Address types store 20 bytes worth of an Ethereum address or an Ethereum account.
- The
msg
object is a public object that is available through all your contracts and contracts and contains the address of the person who is interacting with the smart contract