Getting array of struct from another contract - ethereum

I have 2 contracts.
contract Contract1{
struct Data {
uint data1;
string data2;
}
Data [] newData;
}
Let's assume that I have datas in newData
import "./Contract1.sol";
contract Contract2{
Data storage newOne = newData[0];
}
I want to reach array of struct which is in Contract1 as above.
How can I access to Contract1 from Contract2?

You can extend a contract with the is keyword.
Child contracts (in your case Contract2) can access all non-private parent (in your case Contract1) properties.
pragma solidity ^0.8;
import "./Contract1.sol";
contract Contract2 is Contract1 {
function foo() external {
Data storage newOne = newData[0];
// newOne.data1 = 1;
// newOne.data2 = 'hello';
}
}
Edit: Mind that newData[0] is trying to access index 0 of the array, but when the contract is deployed, the array is empty (does not have index 0). You can create the first item (with index 0 and dummy data) by executing this function:
function add() external {
newData.push(Data(1, 'a'));
}

Related

In Solidity, can you declare a mapping variable inside function?

I have only seen that the mapping variables are declared as storage variables.
I'd like to know if I can declare a mapping variable inside the function in Solidity.
No, its not possible because mappings cannot be created dynamically, you have to assign them from a state variable. Yet you can create a reference to a mapping, and assign a storage variable to it.
Yet, you can encapsulate the mapping in a contract, and use it in another by instantiating a new contract containing that mapping, this is the most approximated way of "declaring" a mapping inside a function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.0 <0.9.0;
contract MappingExample {
mapping(address => uint) public balances;
function update(uint newBalance) public {
balances[msg.sender] = newBalance;
}
}
contract MappingUser {
function f() public returns (uint) {
MappingExample m = new MappingExample();
m.update(100);
return m.balances(address(this));
}
}
Taken form the docs:
Mappings in solidity are always stored in the storage and declared top-level as docs say.
But you declare a mapping inside a function if it refers to a top-level mapping inside a function.
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract MappingInFunction {
mapping (uint => string) public Names;
uint public counter;
function addToMappingInsideFunction(string memory name) public returns (string memory localName) {
mapping (uint => string) storage localNames = Names;
counter+=1;
localNames[counter] = name;
return localNames[counter];
// we cannot return mapping in solidity
// return localNames;
}
}
Even though I am not sure what would be the use case but referring to top-level mapping inside addToMappingInsideFunction is a valid syntax.

How to create a function that returns me my selection between more structs in Solidity?

I am trying to create a function that would return me the struct I select from multiple structs.
Here is my code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Structing {
struct DataOne {
uint indexOne;
address toOne;
}
struct DataTwo {
uint indexTwo;
address toTwo;
}
function selectingStruct(string name_struct) public view returns(struct) {
return _name_struct public final_selection;
}
}
This is the error I get:
Parser error, expecting type name.
How to create a function that returns me my selection between more structs in Solidity?
Your snippet only contains struct definitions, but not storage properties storing any data.
You'll need to define the exact datatype that you want to return. There's no magic typing that would allow returning a "1 of N" type in Solidity.
pragma solidity ^0.8;
contract Structing {
// type definition
struct DataOne {
uint indexOne;
address toOne;
}
// type definition
struct DataTwo {
uint indexTwo;
address toTwo;
}
// typed properties
DataOne dataOne;
DataTwo dataTwo;
// TODO implement setters of `dataOne` and `dataTwo` properties
function getDataOne() public view returns (DataOne memory) { // returns type
return dataOne; // property name
}
function getDataTwo() public view returns (DataTwo memory) { // returns type
return dataTwo; // property name
}
}

Solidity: Data location must be "memory" or "calldata" for return parameter in function

I am learning Ethereum dev in Solidity and trying to run a simple HelloWorld program but ran into the following error:
Data location must be "memory" or "calldata" for return parameter in function, but none was given.
My code:
pragma solidity ^0.8.5;
contract HelloWorld {
string private helloMessage = "Hello world";
function getHelloMessage() public view returns (string){
return helloMessage;
}
}
You need to return string memory instead of string.
Example:
function getHelloMessage() public view returns (string memory) {
return helloMessage;
}
The memory keyword is the variable data location.
For those reading this who have similar code, 'memory' may not necessarily be the correct word to use for you. You may need to use the words 'calldata' or 'storage' instead. Here is an explanation:
Memory, calldata (and storage) refer to how Solidity variables store values.
For example:
1. Memory: here is an example using the word 'memory':
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import 'hardhat/console.sol'; // to use console.log
contract MemoryExample {
uint[] public values;
function doSomething() public
{
values.push(5);
values.push(10);
console.log(values[0]); // logged as: 5
modifyArray(values);
}
function modifyArray(uint[] memory arrayToModify) pure private {
arrayToModify[0] = 8888;
console.log(arrayToModify[0]) // logged as: 8888
console.log(values[0]) // logged as: 5 (unchanged)
}
}
Notice how the 'values' array was not changed in the private function because 'arrayToModify' is a copy of the array and does not reference (or point to the array that was passed in to the private function.
2. Calldata is different and can be used to pass a variable as read-only:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract CallDataExample {
uint[] public values;
function doSomething() public
{
values.push(5);
values.push(10);
modifyArray(values);
}
function modifyArray(uint[] calldata arrayToModify) pure private {
arrayToModify[0] = 8888; // you will get an error saying the array is read only
}
}
3. Storage: a third option here is to use the 'storage' keyword:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import 'hardhat/console.sol'; // to use console.log
contract MemoryExample {
uint[] public values;
function doSomething() public
{
values.push(5);
values.push(10);
console.log(values[0]); // logged as: 5
modifyArray(values);
}
function modifyArray(uint[] storage arrayToModify) private {
arrayToModify[0] = 8888;
console.log(arrayToModify[0]) // logged as: 8888
console.log(values[0]) // logged as: 8888 (modifed)
}
}
Notice how by using the memory keyword, the arrayToModify variable references the array that was passed in and modifies it.
use string memory instead of string.
storage - variable is a state variable (store on blockchain)
memory - variable
List item - is in memory and it exists while a function is being called
calldata - special data location that contains function arguments, only available for external functions
example code : Data Locations

I get a declaration error in solidity when I create a variable with "var"

I'm trying to create a variable "project" to store data from a mapping but I get "Decalration error, undefined identifier" on project = projects[addr]
function getProjectInfo(address addr) public view returns (string memory name, string memory url, uint funds){
var project = projects[addr];
}```
Use explicit variable type definition:
pragma solidity ^0.5.8;
contract Test
{
struct Project
{
bytes32 name ;
}
mapping (address => Project) projects ;
constructor () public {
}
function getProjectInfo(address addr) public view returns (string memory name, string memory url, uint funds)
{
Project memory project = projects[addr];
// ...
}
}

String array in solidity

I came across quite a common problem that it seems I can't solve elegantly and efficiently in solidity.
I've to pass an arbitrary long array of arbitrary long strings to a solidity contract.
In my mind it should be something like
function setStrings(string [] row)
but it seems it can't be done.
How can I solve this problem?
This is a limitation of Solidity, and the reason is that string is basically an arbitrary-length byte array (i.e. byte[]), and so string[] is a two-dimensional byte array (i.e. byte[][]). According to Solidity references, two-dimensional arrays as parameters are not yet supported.
Can a contract function accept a two-dimensional array?
This is not yet implemented for external calls and dynamic arrays - you can only use one level of dynamic arrays.
One way you can solve this problem is if you know in advanced the max length of all of your strings (which in most cases are possible), then you can do this:
function setStrings(byte[MAX_LENGTH][] row) {...}
December 2021 Update
As of Solidity 0.8.0, ABIEncoderV2, which provides native support for dynamic string arrays, is used by default.
pragma solidity ^0.8.0;
contract Test {
string[] public row;
function getRow() public view returns (string[] memory) {
return row;
}
function pushToRow(string memory newValue) public {
row.push(newValue);
}
}
String arrays as parameters aren't supported yet in solidity.
You can convert the array elements to a byte string and then deserialize that byte string back to the array inside the function. Although this can prove to be quite expensive you can try it if you don't have a choice. You can follow this short article to serialize/deserialize any datatype in solidity.
all solutions you need:-
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.1;
contract HelloWorld {
string[] strings;
// push one string to array
function pushToStrings(string memory _data) public{
strings.push(_data);
}
//get all the strings in array form
function GetAllStrings() view public returns(string[] memory){
return strings;
}
//get nth string of strings array
function GetNthStrings(uint x) view public returns(string memory){
return strings[x];
}
//push array of strings in strings
function pushStringsArray(string[] memory someData) public{
for (uint i=0; i < someData.length; i++) {
strings.push(someData[i]);
}
}
//change whole strings, take array of strings as input
function changeWholeString(string[] memory someData) public{
strings=someData;
}
}
string array is not available in Solidity
because String is basically array of character
Nested dynamic arrays not implemented
There are two types arrays in solidity: static array and dynamic array.
declaration of array
static array: These has fixed size.
int[5] list_of_students;
list_of_students = ["Faisal","Asad","Naeem"];
we access the values using index number
Dynamic arrays: The size of these arrays dynamically increases or decreases.
int[] list_of_students;
list_of_students.push("Faisal");
list_of_students.push("Asad");
list_of_students.push("Smith");
we can access the value using index number.
push and pop function is used to insert and delete the values. length function is used to measure the length of the array.
It can be done by using
pragma experimental ABIEncoderV2;
at the top of your contract you may then use dynamic arrays of strings. Ex.
string[] memory myStrings;
This is an example contract to manage the array push, get, getAll,
and remove
pragma solidity ^0.8.4;
contract Array {
string[] private fruits = ["banana", "apple", "avocado", "pineapple", "grapes"];
function push(string memory item) public {
fruits.push(item);
}
function get(uint256 index) public view returns (string memory) {
return fruits[index];
}
function remove(uint256 index) public returns (bool) {
if (index >= 0 && index < fruits.length) {
fruits[index] = fruits[fruits.length - 1];
fruits.pop();
return true;
}
revert("index out of bounds");
}
function getAll() public view returns (string[] memory) {
return fruits;
}
}