i'm new with solidity and i'm currently struggling iterating through a mapping index to get the values from a Struct
struct Stakes {
uint256 stakeDate;
uint256 stakeAmount;
}
mapping (address => Stakes[]) public addressToStaked;
function stake (uint256 _amount) public {
require(_amount > 0, "You must stake more than 0");
addressToStaked[msg.sender].push(Stakes(block.timestamp, _amount));
}
function returnStaked () public view returns (uint256[][] memory) {
uint256[][] memory result;
for (uint256 i = 0; i < 2; i++){
result[i] = [addressToStaked[msg.sender][i].stakeDate, addressToStaked[msg.sender][i].stakeAmount];
}
return result;
}
As shown on the code, i'm able to push the Struct Values into the mapping, but when i try to read the values as in the returnStaked function i get the error:
TypeError: Type uint256[2] memory is not implicitly convertible to expected type uint256[] memory.
I am not sure but i think you can't iterate through mapping to get values.. if you want to get the stake for the particular address .. below code will work..
function returnStaked (address addressStaked) public view returns (Stakes[] memory) {
return addressToStaked[addressStaked];
}
I will list some links for your references and if i found the way to do it.. i will update here...
https://solidity-by-example.org/app/iterable-mapping/
https://ethereum.stackexchange.com/questions/15337/can-we-get-all-elements-stored-in-a-mapping-in-the-contract
https://programtheblockchain.com/posts/2018/03/09/understanding-ethereum-smart-contract-storage/
Related
This my code ..if someone can help ..thanks in advance
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2 ;
contract Users {
struct Drug { // Vehicle = Drug
string name;
uint Qt;
uint Qs;
uint Qr;
}
event DrugAdded(
string name,
uint Qt,
uint Qs,
uint Qr
);
Drug[] public drugs;
uint counter=0;
function addDrug(string memory _name, uint _Qt, uint _Qs, uint _Qr) public {
drugs.push(
Drug(_name, _Qt,_Qs,_Qr)
);
emit DrugAdded(_name, _Qt,_Qs,_Qr);
counter++;
}
function getdrugs(string memory _name) public view returns (Drug[] memory) {
for(uint i=0;i<counter;i++){
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
return drugs[i];
}
}
}
}
i get error in last line:
TypeError: Return argument type struct Users.Drug storage ref is not implicitly convertible to expected type (type of first return variable) struct Users.Drug memory[] memory.
return drugs[i];
^------^
Because of how arrays are stored in memory, Solidity is not able to resize memory arrays. So when you're returning a dynamic-length array with an unknown length, you need to find out and declare its length first (see _getCount() in the example below) - and then fill each of its items.
You can find another example of a very similar thing in this answer.
function getdrugs(string memory _name) public view returns (Drug[] memory) {
Drug[] memory drugsToReturn = new Drug[](_getCount(_name));
uint256 index = 0;
for(uint i=0;i<counter;i++) {
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
drugsToReturn[index] = drugs[i];
index++;
}
}
return drugsToReturn;
}
function _getCount(string memory _name) private view returns (uint256) {
uint256 count = 0;
for(uint i=0;i<counter;i++) {
if (keccak256(abi.encodePacked((drugs[i].name))) == keccak256(abi.encodePacked((_name)))){
count++;
}
}
return count;
}
I try to get a loop run through all structs associated with the caller address, but I can't get my head around this warning. I think I understand the problem, but can't get my head around what should I do differently to achieve this result the other way.
The error I am getting:
TypeError: Integer constant expected.
--> minitest.sol:30:31:
|
30 | balance += Wallet[walletNumbers[msg.sender][i]].balance;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
My code simplified just for the error part:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^ 0.8 .0;
contract MiniTest {
uint nextWalletNumber = 0;
struct Wallet {
address owner;
uint balance;
uint debt;
}
Wallet[] public walletInfo;
mapping(address => uint[]) public walletNumbers;
function createWallet() public {
Wallet memory newWallet = Wallet(msg.sender, 1000, 0);
walletInfo.push(newWallet);
walletNumbers[msg.sender].push(nextWalletNumber);
nextWalletNumber++;
}
function allWalletsBalance() public view returns(uint) {
uint balance;
for (uint i; i < walletNumbers[msg.sender].length; i++) {
balance += Wallet[walletNumbers[msg.sender][i]].balance;
}
return balance;
}
}
Is there another way to achieve this for loop and take out uint from all structs associated with that address?
although I could not figure out the relationship between your state variables, this line of code is
balance += Wallet[walletNumbers[msg.sender][i]].balance;
Wallet is a struct. instead you should be using walletInfo the name of the array.
balance += walletInfo[walletNumbers[msg.sender][i]].balance;
I want to return an array of structs because i want to output all my data.
//SPDX-License-Identifier:MIT
pragma solidity ^0.8.0;
contract MyContract
{
mapping(uint256 => People) dataList;
uint256[] countArr;
struct People{
string name;
uint256 favNum;
}
In this function, i set the data of my struct object and then include it in my mapping.
function setPerson(string memory _name,uint256 _id, uint256 _favNum) public {
dataList[_id]= People(_name,_favNum);
countArr.push(_id);
}
This function here gets me the data of my specified struct object.
function getPerson(uint _id) public view returns(string memory,uint256){
return (dataList[_id].name, dataList[_id].favNum);
}
Now here is the function i think that is causing me trouble because in this function i want to return not the data of a single People object but all of my data and whenever i run this function on my REMIX IDE console it shows me the error: call to MyContract.getAllData errored: VM error: revert. revert
The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
function getAllData()public view returns(People[] memory){
uint256 count = countArr.length;
uint256 i = 0;
People[] memory outputL= new People[](count);
while(count >= 0){
(string memory nam,uint256 num) = getPerson(count-1);
People memory temp = People(nam,num);
outputL[i]=temp;
count--;
i++;
}
return outputL;
}
}
Can anyone help and explain what is wrong and how can i get it running?
This version of the getAllData function works as you expect:
function getAllData() public view returns (People[] memory) {
uint256 count = countArr.length;
People[] memory outputL = new People[](count);
while(count > 0) {
count--;
(string memory nam, uint256 num) = getPerson(countArr[count]);
People memory temp = People(nam, num);
outputL[count] = temp;
}
return outputL;
}
Feel free to ask if you have any questions about the changes.
Here is a sample Solidity contract where I have a function which returns an empty struct.
I want to test from a function inside the contract for the empty struct, but I am having trouble figuring out the correct syntax ...
contract MyNFTShop is ERC721 {
struct NFTCardAttributes {
uint256 cardIndex;
string name;
string imageURI;
}
NFTCardAttributes[] defaultCards;
constructor(
string[] memory cardNames,
string[] memory cardImageURIs,
) ERC721("NFT", "NFTC") {
for (uint256 i = 0; i < cardNames.length; i += 1) {
defaultCards.push(
NFTCardAttributes({
cardIndex: i,
name: cardNames[i],
imageURI: cardImageURIs[i],
})
);
NFTCardAttributes memory c = defaultCards[i];
}
}
function checkIfUserHasNFTCard() public view returns (NFTCardAttributes memory) {
uint256 userNFTCardNftTokenId = nftCardHolders[msg.sender];
if(userNFTCardNftTokenId > 0 ) {
return nftCardHolderAttributes[userNFTCardNftTokenId];
} else {
NFTCardAttributes memory emptyStruct;
return emptyStruct;
}
}
function do_something() public () {
if (getAllDefaultCards() == EMPTY) { <---- NEED HELP HERE
// sendMoney to whatever
}
}
}
Help with this Solidity function. I know it returns (0,0,0) when called from brownie/python but I don't know how to test for it. [ the struct returned is indeed empty aka (0,0,0) using Solidity. ]
function do_something() public () {
if (getAllDefaultCards() == EMPTY) { <---- NEED HELP HERE
// sendMoney to whatever
}
}
A WORKAROUND
I basically split the function into two separate functions to get the desired affect:
function checkIfUserHasNFTCard() public view returns (bool)
function getUserHasNFTCard() public view returns (NFTCardAttributes)
Although, the primary question still stands and will update once I figure out the answer!
In Ethereum private network (geth) I do have very simple contract (in Solidity).
version 1:
contract T {
string log;
function getLastLog() constant returns (string lastLog) { return log; }
function T() { log = "[call end]: T()\n"; }
struct TData {
uint amount;
}
mapping (address => uint) balance;
mapping (address => TData) mystructmap;
function setBalance(address _user, uint _balance) {
log = "[call start]: setBalance()\n";
balance[_user] = _balance;
mystructmap[_user] = TData({amount: 42});
log = "[call end]: setBalance()\n";
}
function getBalance(address _user) constant returns (uint _balance) {
return balance[_user];
}
function get42(address _user) constant returns (uint _fourtytwo) {
return mystructmap[_user].amount;
}
}
I do deploy contract and then call it like this (from web3.js):
contract.getLog()
contract.setBalance(valid_address, 55)
contract.getLog()
contract.getBalance(address)
contract.get42(address)
And I get as output result:
[call end]: T()
[call end]: setBalance()
55
42
Now I just add one new field to TData structure:
version 2:
contract T {
string log;
function getLastLog() constant returns (string lastLog) { return log; }
function T() { log = "[call end]: T()\n"; }
struct TData {
uint somedata;
uint amount;
}
mapping (address => uint) balance;
mapping (address => TData) mystructmap;
function setBalance(address _user, uint _balance) {
log = "[call start]: setBalance()\n";
balance[_user] = _balance;
mystructmap[_user] = TData({somedata: 11, amount: 42});
log = "[call end]: setBalance()\n";
}
function getBalance(address _user) external constant returns (uint _balance) {
return balance[_user];
}
function get42(address _user) external constant returns (uint _fourtytwo) {
return mystructmap[_user].amount;
}
}
I do the same calls as above:
contract.getLog()
contract.setBalance(valid_address, 55)
contract.getLog()
contract.getBalance(address)
contract.get42(address)
But now I get:
[call end]: T()
[call end]: T()
0
0
Seems like 'setBalance()' function is not executed (or exited somewhere) and state in storage is not changed.
Please help!
Thanks.
I had the same problem earlier. I'm pretty sure that it has to do with the amount of gas that you are sending with your requests. Web3 will guess but this has failed me before. Try manually sending different amounts of gas along with your request.
Here's something I'm doing:
store
.changeProduct(d.id, d.name, d.price, d.description, d.quantity,d.enabled, {from: account, gas:1000000})
Hardcoding Gas for any operation is a bad idea. You will keep getting into this kind of errors if you do that. You should check for Gas before firing the method
Use the estimate Gas API -
https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethestimategas
As and when you take your DApp public, you have to be cognizant of the fact that miners can adjust Gas prices in the geth console.
miner.setGasPrice(gasPrice);
Hope that helps!