How to push onto a dynamic sized Array within a function with Solidity? - solidity

How can I push a value into an dynamic sized array within a function?
I have a function which builds an array dynamically to use this as a function argument afterwards:
function autoMintBatch(...) {
uint32[] xList;
uint32[] yList;
// ... y is declared properly ...
yList.push(y);
for (uint256 i = 0; i < idList.length; i++) {
xList.push(x++);
}
}
I get the following compilation error:
TypeError: Member "push" is not available in uint32[] memory outside
of storage.
But when I change the variable declaration to storage like:
uint32[] storage xList;
another error appears:
TypeError: This variable is of storage pointer type and can be
accessed without prior assignment, which would lead to undefined
behaviour.
Is there any way to build an array dynamically within a function?

Assign the result of "x++" in a variable inside the function and then try to push the variable inside the array. Remember to create a state variable for the array. This worked for me
Item[] public items;
event MarketItem(
bytes32 title,
uint8 price,
bool sold,
bool published,
address owner
);
mapping(address => Item) public itemToOwner;
function addItem(bytes32 _title, uint8 _price) public {
Item memory newItem = Item({
title: _title,
price: _price,
sold: false,
published: true,
owner: msg.sender
});
items.push(newItem);
}

Only dynamic storage arrays can be resized (push/pop).
In your case better implementation could rely on static memory array with fixed size, such as:
function autoMintBatch(...) public virtual returns (uint256[] memory)
{
...
uint256[] memory xList = new uint[](idList.length);
for(uint256 i = 0; i< amount ; i++)
{
xList[i] = y++;
}
return xList;
}

Related

How do I call diamondCut (EIP-2535) from another contract?

I'm trying to call execute the diamondCut function using another contract, but it keeps getting reverted, even though all the facet addresses and respective function selectors exist and are included in the call. I'm trying to do the following:
Remove 3 functions, each function is in a separate facet, using the cutSomeDiamonds function in this contract
The interfaces used are in https://github.com/mudgen/diamond-1-hardhat/tree/main/contracts/interfaces
contract ExecuteDiamondCuts {
address CONTRACT_ADDRESS = 0xblahblah; // dummy address
string[] functionsToRemove;
constructor() {
functionsToRemove.push("exampleFunctionA(address)");
functionsToRemove.push("exampleFunctionB(uint)");
functionsToRemove.push("exampleFunctionC()");
}
function cutSomeDiamonds() external {
IDiamondLoupe _loupe = IDiamondLoupe(CONTRACT_ADDRESS);
IDiamondCut.FacetCut[] memory _facetCuts = new IDiamondCut.FacetCut[](functionsToRemove.length);
for (uint i=0; i<functionsToRemove.length; i++) {
address facetWithFn = _loupe.facetAddress(bytes4(keccak256(bytes((functionsToRemove[i])))));
bytes4[] memory _fnSelectors = new bytes4[](1);
_fnSelectors[0] = bytes4(keccak256(bytes((functionsToRemove[i]))));
IDiamondCut.FacetCut memory _facetCut = IDiamondCut.FacetCut({
facetAddress: facetWithFn, // facet address
action: IDiamondCut.FacetCutAction.Remove, // action
functionSelectors: _fnSelectors // array of fn selectors
});
_facetCuts[i] = _facetCut;
}
(bool success,) = CONTRACT_ADDRESS.delegatecall(
abi.encodeWithSignature(
"diamondCut(FacetCut[],address,bytes)",
_facetCuts,
address(0),
"0x"
)
);
require(success);
}
}
Everything seems to work until require(success); which got reverted.

I keep on getting ParseError: Expected type name // when I want to return a struct I have just created

I am new in Solidity and I have been trying to create and get STRUCT without adding it to an Array. I alway see Structs with arrays and the method .push and I wanted to try it without it.
I have created a single Contract with one Struct and one function to create and get it.
If I create a single public function to create, but not return, the struct it doesn´t give me any error... Like the following:
struct Todo {
string name;
uint age;
}
function createTodo(string memory _name, uint _age) public pure{
Todo memory myTodo = Todo(_name, _age);
}
With the above code I would also like to know why it wouldn´t let me set the pointer "Todo" as storage like: Todo storage myTodo = Todo(_name, _age); It gives an TypeError: Todo memory is not implicity convertible to expect type struct storage pointer.
Next, I tried to modify the function to create and RETURN but then is when I start getting the ParseError.
The code is the following:
function getTodo(string memory _name, uint _age) public returns(struct myTodo) {
Todo memory myTodo = Todo(_name, _age);
return myTodo;
}
With the aobve code I also tried in "returns(struct), returns(struct memory)"....
I would really appreciate any type of help here.
Thank you very much
You received this error because you're wrong to set a returns keyword on getTodo() function. In your case, you must change your function in this way:
function getTodo(string memory _name, uint _age) external pure returns(Todo memory) {
Todo memory myTodo = Todo(_name, _age);
return myTodo;
}
If you want to handle storage structs, see this smart contract code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
struct Todo {
string name;
uint age;
}
// Declare state variable
Todo[] todoArray;
// Push into array new struct
function createTodo(string memory _name, uint _age) public {
todoArray.push(Todo(_name, _age));
}
// Retrieve ToDo struct from specific index about struct array
function getTodo(uint _index) external view returns(Todo memory) {
return todoArray[_index];
}
}

Getting accurate gas cost after each function call

I implemented a dynamic array in solidity for my own use. The following is my implementation. I can get the accurate gas cost of each function call by clicking the debug message in the console of remix. However, manually getting gas costs is tedious and I'm thinking if I can write another solidity script to get the gas cost of my function call. For example, I want to get the gas cost of consecutively calling push API for 10000 times. The x-axis should be the number of API calls, and the y axis should be the cumulative gas cost up to i API calls. Is there any built-in function in solidity to help me do that?
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract Array {
// Several ways to initialize an array
uint[] public arr;
uint[] public arr2 = [1, 2, 3];
// Fixed sized array, all elements initialize to 0
uint[10] public myFixedSizeArr;
function get(uint i) public view returns (uint) {
return arr[i];
}
// Solidity can return the entire array.
// But this function should be avoided for
// arrays that can grow indefinitely in length.
function getArr() public view returns (uint[] memory) {
return arr;
}
function push(uint i) public {
// Append to array
// This will increase the array length by 1.
arr.push(i);
}
function pop() public {
// Remove last element from array
// This will decrease the array length by 1
arr.pop();
}
function getLength() public view returns (uint) {
return arr.length;
}
function remove(uint index) public {
// Delete does not change the array length.
// It resets the value at index to it's default value,
// in this case 0
delete arr[index];
}
function examples() external {
// create array in memory, only fixed size can be created
uint[] memory a = new uint[](5);
}
}
You can use msg.gas and store the value to a variable, when the contract is executed the gas amount will be stored.

Array returns "Undeclared identifier. Did you mean "Candidate" or "candidate"?"

when trying to set up an array of structs i get an error that says "Undeclared identifier. Did you mean "Candidate" or "candidate"?"
Ive tried to create an empty array by writing
uint[] memory candidate;
and
bytes[] memory candidate
above the function in which i'm getting errors to instantiate it. However, this doesn't work either and gives errors. It does not compile.
pragma solidity 0.5.0;
contract Election {
string public candidate;
struct Candidate {
uint id;
string name;
uint voteCount;
}
mapping(uint => Candidate) candidate;
uint public candidatesCount;
function createCandidate(string storage name ) private {
candidatesCount ++;
candidates[candidatesCount] = Candidate(candidatesCount, name, 0);
}
function addCandidates () public {
createCandidate("Candidate1");
createCandidate("Candidate2");
}
}
change
mapping(uint => Candidate) candidate;
to
mapping(uint => Candidate) candidates;
and
function createCandidate(string storage name ) private
to
function createCandidate(string memory name ) private

Solidity - Filling and using array of array

I have a contract with the following data structures:
struct Answer
{
bytes32 name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
struct Question
{
bytes32 name; // short name (up to 32 bytes);
Answer[] answers;
}
Question[] public questions;
How can I fill the arrays?
The following lines are not functional:
function addQuestion(bytes32 _name, bytes32[] _answers) onlyOwner { // perhabs it should be possible that others as the owner can add
Answer[] memory answersLocal = new Answer[](_answers.length);
//Question memory question = Question(_name);
for (uint i = 0; i < _answers.length; i++) {
answersLocal[i] = Answer({
name: _answers[i],
voteCount: 0
});
}
questions.push(Question({
name: _name,
answers: answersLocal
}));
}
I get here the error:
Copying of type struct Roadshow.Answer memory[] memory to storage not yet supported.
if you are trying to access contract via web3 or something bridge like this.
the bridge still not support array of arrays, but solidity supports!
i guess if the error was in solidity you will see a different type of error.
Hope this helps.
Use push() method instead of Solidity assigning.