Is it possible to return a dynamic array of strings ( string[] ) from a Solidity function?
Yes, you can serialize it to bytes and deserialize it back to string[].
In your smart contract:
function toBytes(string[] strArray)
private
pure
returns(bytes serialized) {
uint startindex = 0;
uint endindex = strArray.length - 1;
require(endindex >= startindex);
if (endindex > (strArray.length - 1)) {
endindex = strArray.length - 1;
}
//64 byte is needed for safe storage of a single string.
//((endindex - startindex) + 1) is the number of strings we want to pull out.
uint offset = 64 * ((endindex - startindex) + 1);
bytes memory buffer = new bytes(offset);
string memory out1 = new string(32);
for (uint i = startindex; i <= endindex; i++) {
out1 = strArray[i];
stringToBytes(offset, bytes(out1), buffer);
offset -= sizeOfString(out1);
}
return (buffer);
}
function stringToBytes(uint _offst, bytes memory _input, bytes memory _output)
private
pure {
uint256 stack_size = _input.length / 32;
if (_input.length % 32 > 0) stack_size++;
assembly {
stack_size: = add(stack_size, 1) //adding because of 32 first bytes memory as the length
for {
let index: = 0
}
lt(index, stack_size) {
index: = add(index, 1)
} {
mstore(add(_output, _offst), mload(add(_input, mul(index, 32))))
_offst: = sub(_offst, 32)
}
}
}
function sizeOfString(string memory _in)
private
pure
returns(uint _size) {
_size = bytes(_in).length / 32;
if (bytes(_in).length % 32 != 0)
_size++;
_size++; // first 32 bytes is reserved for the size of the string
_size *= 32;
}
}
Then to deserialize it back to string[] (using js) use the below function:
function hexBytesToStr(hex) {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
let v = parseInt(hex.substr(i, 2), 16);
if (v) str += String.fromCharCode(v);
}
let params = [];
let res = "";
for (let i = 0; i <= str.length; i++) {
if (str.charCodeAt(i) > 31) {
res = res + str[i];
}
else {
params.push(res);
res = "";
}
}
params.pop();
return params;
}