Why does declaring returns type bytes memory give a compiler error? - solidity

If we have the following code:
pragma solidity >= 0.5;
contract stringsContract {
function takesTwo(string memory str, uint idx) public pure returns (bytes memory) {
bytes memory bytesStr = bytes(str);
return bytesStr[idx];
}
}
Why do we get TypeError return argument bytes1 is not explicitly convertible to expected type (type of first return variable bytes memory).
The fix was to change bytes memory to bytes:
contract stringsContract {
function takesTwo(string memory str, uint idx) public pure returns (byte) {
bytes memory bytesStr = bytes(str);
return bytesStr[idx];
}
}
Nevertheless, I'm still curious about the reason of the compilation error. Any thoughts?

Variable of type 'bytes' and 'string' are special arrays. In first code snippet you are returning an array which is not yet possible in Solidity yet.
You can find docs: https://solidity.readthedocs.io/en/develop/types.html#bytes-and-strings-as-arrays
When you return in solidity the syntax is like (value_type value_name: optional), what you tried returning bytes which is an array and with name memory, memory itself is spacial keyword in solidity

Related

String won't convert to bytes in solidity

I am converting this string to bytes
0 ICS 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 50000000000000000000 10 56500000000000000000 6500000000000000000
but it won't convert. I am using this code
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract helper {
function toStr(bytes memory byts) public pure returns (string memory) {
return string(byts);
}
function toBytes(string memory byts) public pure returns (bytes memory) {
return bytes(byts);
}
}
when ever i call the toBytes method this error pops up
call to helper.toStr errored: Error encoding arguments: Error: invalid arrayify value (argument="value", value="0 ICS 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 50000000000000000000 10 56500000000000000000 6500000000000000000", code=INVALID_ARGUMENT, version=bytes/5.5.0)

How to slice bytes memory in solidity?

Im trying to slice bytes such as
bytes memory bytesData = result[32:64];
and its throwing:
TypeError: Index range access is only supported for dynamic calldata arrays.
it works fine with calldata...
what about memory?
According to the Solidity docs, slicing memory arrays is not supported for now. As you've said, it does work on calldata bytes. This answer on EthereumSE seems to agree.
According to this question on EthSE, you can convert the memory to calldata with a workaround.
pragma solidity >=0.8.0 <0.9.0;
library BytesLib {
function slice(
bytes memory _bytes,
uint256 _start,
uint256 _length
)
internal
pure
returns (bytes memory)
{
require(_length + 31 >= _length, "slice_overflow");
require(_bytes.length >= _start + _length, "slice_outOfBounds");
bytes memory tempBytes;
// Check length is 0. `iszero` return 1 for `true` and 0 for `false`.
assembly {
switch iszero(_length)
case 0 {
// Get a location of some free memory and store it in tempBytes as
// Solidity does for memory variables.
tempBytes := mload(0x40)
// Calculate length mod 32 to handle slices that are not a multiple of 32 in size.
let lengthmod := and(_length, 31)
// tempBytes will have the following format in memory: <length><data>
// When copying data we will offset the start forward to avoid allocating additional memory
// Therefore part of the length area will be written, but this will be overwritten later anyways.
// In case no offset is require, the start is set to the data region (0x20 from the tempBytes)
// mc will be used to keep track where to copy the data to.
let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
let end := add(mc, _length)
for {
// Same logic as for mc is applied and additionally the start offset specified for the method is added
let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
} lt(mc, end) {
// increase `mc` and `cc` to read the next word from memory
mc := add(mc, 0x20)
cc := add(cc, 0x20)
} {
// Copy the data from source (cc location) to the slice data (mc location)
mstore(mc, mload(cc))
}
// Store the length of the slice. This will overwrite any partial data that
// was copied when having slices that are not a multiple of 32.
mstore(tempBytes, _length)
// update free-memory pointer
// allocating the array padded to 32 bytes like the compiler does now
// To set the used memory as a multiple of 32, add 31 to the actual memory usage (mc)
// and remove the modulo 32 (the `and` with `not(31)`)
mstore(0x40, and(add(mc, 31), not(31)))
}
// if we want a zero-length slice let's just return a zero-length array
default {
tempBytes := mload(0x40)
// zero out the 32 bytes slice we are about to return
// we need to do it because Solidity does not garbage collect
mstore(tempBytes, 0)
// update free-memory pointer
// tempBytes uses 32 bytes in memory (even when empty) for the length.
mstore(0x40, add(tempBytes, 0x20))
}
}
return tempBytes;
}
}
https://ethereum.stackexchange.com/questions/122029/how-does-bytes-utils-slice-function-work

solidity assert for several not nulls

I have the following function in solidity:
function registerStudentEvaluation(string memory _firstName, string memory _lastName, string memory _subject, uint _note) public returns(Note memory) {
bytes32 studentHash = keccak256(abi.encodePacked(_firstName, _lastName));
bytes32 subjectHash = keccak256(abi.encode(_subject));
address teacherAddress = msg.sender;
assert (students[studentHash] && subjects[subjectHash] && teachers[msg.sender]);
Note memory newNote = Note(studentHash, subjectHash, msg.sender, _note);
bytes32 noteHash = keccak256(abi.encodePacked(studentHash, subjectHash, msg.sender, _note));
notes[noteHash] = newNote;
emit student_evaluated(noteHash);
return newNote;
}
And I am getting these errors:
TypeError: Operator & not compatible with types struct Notes.Student storage ref and struct Notes.Subject storage ref
--> notes.sol:71:17:
|
71 | assert (students[studentHash] & subjects[subjectHash] & teachers[msg.sender])
TypeError: Operator && not compatible with types struct Notes.Student storage ref and struct Notes.Teacher storage ref
TypeError: Invalid type for argument in function call. Invalid implicit conversion from struct Notes.Student storage ref to bool requested.
How can I assert for several not nulls in Solidity?
Solidity uses two ampersands && as the logical AND operator.
assert(true && true);
One ampersand & is the bitwise AND operator.
uint8 three = 3; // 00000011
uint8 five = 5; // 00000101
uint8 result = three & five; // 00000001
Docs: https://docs.soliditylang.org/en/v0.8.12/cheatsheet.html
Solution: Use logical operators in the assert() condition.
assert (students[studentHash] && subjects[subjectHash] && teachers[msg.sender]);
Note: It's not defined in your question but I'm assuming that the students property is defined as mapping(bytes32 => bool) students;

Solidity unit type holding an array?

I am working through the solidity course cryptozombies and heres something im not understanding
struct Zombie {
string name;
uint dna;
uint32 level;
uint32 readyTime;
uint16 winCount;
uint16 lossCount;
}
Zombie[] public zombies;
mapping (uint => address) public zombieToOwner;
mapping (address => uint) ownerZombieCount;
function _createZombie(string memory _name, uint _dna) internal {
uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1;
zombieToOwner[id] = msg.sender;
ownerZombieCount[msg.sender]++;
emit NewZombie(id, _name, _dna);
}
Based on my understanding "zombies" is an array containing a string and different type of integers. If you look in the _createzombie function "id" is set as an uint. How can something of type uint store all these values?
Based on my understanding "zombies" is an array containing a string and different type of integers
This is only partially correct. zombies is in fact an array. But each of its items is of type Zombie.
A struct (docs) is kind of a "wrapper" type - it can contain multiple other datatypes on the inside, but from the outside it's seen as just one datatype (in this case you created a new datatype called Zombie).
You can see it for example in the push() function that accepts one new item of the array - type Zombie (wrapping the other variables).
zombies.push(
Zombie(...) // pushes 1 item of type `Zombie` to the array
)

How do I input the parameter with bytes4 type in Remix?

I created a simple contract as blow shows. When I deployed it and try to call get function, I found that I couldn't input the correct parameter with bytes4 type. No matter I used 0x01,11,"11"..., it always told that error encoding argument like this.
transact to Test.get errored: Error encoding arguments: Error: invalid arrayify value (argument="value" value="11" code=INVALID_ARGUMENT version=bytes/5.5.0)
transact to Test.get errored: Error encoding arguments: Error: invalid arrayify value (argument="value" value="0x6162" code=INVALID_ARGUMENT version=bytes/5.5.0)
What should I do ?
pragma solidity ^0.4.0;
contract Test {
mapping (bytes8 => string) public map;
function setMapping() public {
map["k1"] = "yes";
}
function get(bytes4 a) public {
}
}
You can enter the bytes in the hex form, undivided. Since bytes4 is a fixed-length array of four bytes, you always need to input exactly 4 bytes (8 hex characters).
0x12345678
12 is the first byte
34 is the second byte
etc...
Note: If you want to input empty bytes, you can use 00 in the location of the empty byte. Example: 0x00340078 (1st and 3rd byte are empty).