Why can't you pass strings from contract to contract? - solidity

When calling trying to pass a string from contract to contract, I get an error. in getName with error. I'm aware you cannot pass strings but what is the reason?
Return argument type inaccessible dynamic type is not implicitly
convertible to expected type (type of first return variable) string
memory. return toBeCalled.getName();
pragma solidity ^0.1.0;
contract ToContract{
FromContract fromContract = new FromContract();
function getName() constant returns (string) {
return fromContract.getName();
}
}
contract FromContract{
string name = 'dapp';
function getName() constant return(string){
return name;
}
}

In solidity a string "Hey" is internally stored as ["H","e","y"] which is a dynamic array. As of now it has no support to pass dynamic arrays. you can try to work around this by passing the string as a part of an object.

Related

Semantic operator of dot in Kotlin

I'd like to understand a bit better the 2 functions below. I know it is very compact and understand more or less what it does: it converts each characters of a string into string of '0' and '1'. But...
How does the dot(in front of encodeToByteArray) connect the 's' to encodeToByteArray()?
Where can I find more info about what dot represents?
Also, how and why the code { byte -> binaryStringOf(byte) } can do the job in that place?
How does it "know" that there is a byte with which it calls the function binaryStringOf(byte)
Where can I find more info about it, too?
fun binaryStringOf(message: String): String {
var s: String
s = (message)
.encodeToByteArray()
.joinToString("") { byte -> binaryStringOf(byte) }
return s
}
fun binaryStringOf(b: Byte): String {
return b.toString(2).padStart(8, '0')
}
The formatting above makes things a little bit more confusing, but let me try to explain what is going on.
The = is an assignment operator. It says "assign the variable s to the result of the expression on the right side".
Now we see that message is a parameter in the binaryStringOf function of type String. String is a class which contains a function (also called a method when it is a member of a class) called encodeToByteArray which returns a ByteArray.
ByteArray in turn has a function called joinToString which we're giving two parameters: one of type String, and one of type ((Byte) -> CharSequence) (ie, the function is itself being passed in as a variable, using lambda syntax). Kotlin has some syntactic sugar to make this look nicer when the lambda is the last argument.
So, the statement
s = (message)
.encodeToByteArray()
.joinToString("") { byte -> binaryStringOf(byte) }
means "the variable s is assigned the value that results from calling joinToString on the result of calling encodeToByteArray on message.
Then return s says that the return value from the binaryStringOf should be whatever value was assigned to s.
.encodeToByteArray()
works on the incoming string (message in this case). It returns a ByteArray; so something that represents an array of Byte values.
And on that array object, it invokes the joinToString() method. That method receives various arguments, but only the separator string ("") is provided, and the transform parameter.
Now: transform is a function. It is something that can be invoked, with parameters, and that has to return a specific result.
The key part to understand is that { byte -> ... } is that transform function parameter.

Memory in solidity with different types of data

When creating a function that accepts an arguments like int, uint, string and so on why does it needs to specify that string is a memory but when passing a uint it doesn't needs to specify that its a memory
example:
contract SompleContract{
string favWord;
uint favNum;
// in here we have 2 arguments _favNum and _favWord but passing _favWord needs to be memory
function simpleFunction(uint _favNum, string memory _favWord) public {
favNum = _favNum;
favWord = _favWord;
}
}
why does it has to be memory when its a string (_favWord in this case) and not when its a uint (_favNum) and also what kind of data types has to be specified that it's memory when passing it into a function
Data location (memory, calldata or storage) needs to be specified for all reference types. In Solidity, string is treated as dynamic-size array of bytes - and array is a reference type.

Using interface name as Variable type

In solidity, see below code ..... How is that the interface name is being used as variable type ?
See the comments in below code
pragma solidity 0.8.11;
import "../interfaces/ISpool.sol";
// ... other imports
abstract contract VaultBase is IVaultBase, VaultImmutable, SpoolOwnable, SpoolPausable, BaseConstants {
using Bitwise for uint256;
using SafeERC20 for IERC20;
/* ========== STATE VARIABLES ========== */
/// #notice The central Spool contract
ISpool internal immutable spool; // ISpool is interface name and it is
// being used as variable type. What this means ?
}
ISpool interface:
interface ISpool is ISpoolExternal, ISpoolReallocation, ISpoolDoHardWork, ISpoolStrategy, ISpoolBase {}
How is that the interface name is being used as variable type ?
Interface type variables work the same way as Contract type variables.
They serve as as pointer to the specified address, assuming that there is a contract deployed on this address that implements this interface.
Example: If the ISpool interface declares a function foo(uint256) external returns (bool), your contract can call this function and assign the return value directly:
spool = ISpool(address(0x123));
bool result = spool.foo(1);
If the specified address doesn't implement this specific function that you're trying to call, the call fails with an exception.

Send array of structs to a different contract

It is mentioned here that ABIEncoderV2 should make it possible to pass structs from contract to contract. Solidity latest ABI spec mentions that it is possible to have tuple array as a input. Can you please say how array of structs / tuple[] should be sent in below example code from TupleArrayFactory to TupleArray?
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract TupleArrayFactory {
TupleArray newTuple;
function createTuple() public {
newTuple = new TupleArray("trait0", "display0", 0);
// newTuple.pushAttribute([["trait1","display2",2]]);
newTuple.pushAttribute(["trait1","display2",2]);
// TypeError: Unable to deduce common type for array elements.
}
}
contract TupleArray {
struct Attribute {
string trait_type;
string display_type;
uint8 value;
}
Attribute[] public attributes;
Attribute[] public tempAttributeArr;
constructor(string memory trait_type, string memory display_type, uint8 value) payable {
Attribute memory Attribute0 = Attribute(trait_type, display_type, value);
tempAttributeArr.push(Attribute0);
pushAttribute(tempAttributeArr);
//pushAttribute([trait_type, display_type, value]);
// TypeError: Unable to deduce common type for array elements.
}
function pushAttribute(Attribute[] memory _attr) public payable {
attributes.push(_attr[0]);
}
}
Here's a working version of your example:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract TupleArrayFactory {
TupleArray newTuple;
function createTuple() public {
newTuple = new TupleArray("trait0", "display0", 0);
TupleArray.Attribute[] memory attributes = new TupleArray.Attribute[](1);
attributes[0] = TupleArray.Attribute("trait1", "display2", 2);
newTuple.pushAttribute(attributes);
}
}
contract TupleArray {
struct Attribute {
string trait_type;
string display_type;
uint8 value;
}
Attribute[] public attributes;
constructor(string memory trait_type, string memory display_type, uint8 value) payable {
Attribute[] memory tempAttributeArr = new Attribute[](1);
tempAttributeArr[0] = Attribute(trait_type, display_type, value);
pushAttribute(tempAttributeArr);
}
function pushAttribute(Attribute[] memory _attr) public payable {
attributes.push(_attr[0]);
}
}
Some remarks:
pushAttribute([["trait1","display2",2]]) won't work because an array is not implicitly convertible to a struct. You have to invoke the struct constructor.
Even then pushAttribute([TupleArray.Attribute("trait1","display2",2)]) won't work because Solidity currently does not have dynamic array literals. If you want to pass a dynamic array into a function you have to create a variable for it.
Your pushAttribute() takes an array but ignores all but the first element. So why make it an array at all? I'm assuming it's for the sake of the example but if not, you should make the function just accept a single struct.
Putting tempAttributeArr in storage works but is not necessary. You can put it in memory, which is cheaper.
Solidity latest ABI spec mentions that it is possible to have tuple array as a input.
The docs you are linking to only describe how tuples (used for example to return named function arguments or return values) are formatted in the JSON describing the ABI.
Maybe you're referring to some other section on that page? In general, structs are encoded as tuples the ABI, which might be the source of confusion there. But this simply means that if you are encoding the parameters yourself (e.g. when you use off-chain code to issue a transaction), you should encode structs as tuples. If you are just calling external functions on chain, you do not have to do that. In fact you can't because structs and tuples are not convertible to each other. You have to use an actual struct when a function expects a struct and the struct type must be the exact one specified in function signature.

TypeError: Data location must be "memory" for parameter in function, but none was given

I tried to compile my code, but I got the following error:
TypeError: Data location must be "memory" for parameter in function,
but none was given
my code:
pragma solidity ^0.5.0;
contract memeRegistry {
string url;
string name;
uint timestamp;
function setmeme(string _url,string _name, uint _timestamp) public{
url = _url;
name = _name;
timestamp = _timestamp;
}
}
Explicit data location for all variables of struct, array or mapping types is now mandatory. This is also applied to function parameters and return variables.
Add memory after string
function setmeme(string memory _url, string memory _name, uint _timestamp) public{
check here for Solidity 0.5.0. changes https://solidity.readthedocs.io/en/v0.5.0/050-breaking-changes.html
//The version I have used is 0.5.2
pragma solidity ^0.5.2;
contract Inbox{
string public message;
//**Constructor** must be defined using “constructor” keyword
//**In version 0.5.0 or above** it is **mandatory to use “memory” keyword** so as to
//**explicitly mention the data location**
//you are free to remove the keyword and try for yourself
constructor (string memory initialMessage) public{
message=initialMessage;
}
function setMessage(string memory newMessage)public{
message=newMessage;
}
function getMessage()public view returns(string memory){
return message;
}
}
It's working for me.
string memory firstname
Select a different version of the solidity compiler. ^0.4.25 works for me.
The version of the solidity compiler has to be set both on the file and in the compile tab on remix(it is a drop-down menu).
You need to make the return parameters explicitly memory:
Thus,
function setmeme(string _url,string _name, uint _timestamp) public
Becomes
function setmeme(string memory _url, string memory _name, uint _timestamp) public{