I have created struct with nested mapping. Consider the following piece of code written inside the contract in solidity:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract TestContract {
struct Item {
uint itemId;
uint itemValue;
}
struct OverlayingItemStruct {
mapping(uint => Item) items;
uint overlayingId;
uint itemsCount;
}
mapping(uint => OverlayingItemStruct) public overlayingItems;
uint public overlayCount;
function addOverlayingItemsStruct(uint _value) external {
overlayCount ++;
mapping(uint => Item) memory items;
items[1] = Item(1, _value);
overlayingItems[overlayCount] = OverlayingItemStruct(items, 1, 1);
}
function addItem(uint _value, uint _overlayId) external {
OverlayingItemStruct storage overlay = overlayingItems[_overlayId];
overlay.itemsCount ++;
overlay.items[overlay.itemsCount] = Item(overlay.itemsCount, _value);
}
}
When compiling the above code, I am getting the error:
TypeError: Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable.
--> TestC.sol:21:5:
|
21 | mapping(uint => Item) memory items;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Not sure, how to handle this error.
Secondly, needed to confirm if the method to add new values in the nested mapping dictionary is correct?
A mapping cannot be declare inside a function and in memory state. This type has only storage state.
Said this, to pass a mapping into a struct, you can set the key of nested mapping and pass relative struct inside it.
I tried to adjust your smart contract like this:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
contract TestContract {
struct Item {
uint itemId;
uint itemValue;
}
struct OverlayingItemStruct {
mapping(uint => Item) items;
uint overlayingId;
uint itemsCount;
}
mapping(uint => OverlayingItemStruct) public overlayingItems;
uint public overlayCount;
function addOverlayingItemsStruct(uint _value) external {
overlayCount ++;
// NOTE: I declared a new Item struct
Item memory item = Item(1, _value);
// NOTE: I set into items mapping key value 1, Item struct created in row above this
overlayingItems[overlayCount].items[1] = item;
}
function addItem(uint _value, uint _overlayId) external {
OverlayingItemStruct storage overlay = overlayingItems[_overlayId];
overlay.itemsCount ++;
overlay.items[overlay.itemsCount] = Item(overlay.itemsCount, _value);
}
}
Related
I want to create a new function based on these codes below, that it can just fill in the ordinal number (first student is started by 1) to track out the struct student info in this case.
That's mean after I give the data of this first student to the struct by addInfo function:["Simon", 20, "CA USA", 10] Then my expected new function is that I just fill in this unit: 1, then it will appear this student detail
\`
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ReferenceTypes {
address public owner;
struct student {
string Name;
uint Age;
string BirthPlace;
uint8 Marks;
}
constructor() {
owner = msg.sender;
}
mapping (address => student) public Info;
address[] public student_Info;
function addInfo(student memory _student, address _address) public {
require(owner == msg.sender, "Only admin can add Info!!!");
Info[_address] = _student;
student_Info.push(_address);
}
function count() public view returns(uint) {
return student_Info.length;
}
}
\`
Thanks so much guys
I tried a new mapping but failed
You can make another mapping that leads to your mapping Info.
uint public studentsCounter;
mapping (uint => mapping (address => student)) public Info;
function addInfo(student memory _student, address _address) public returns(uint){
require(owner == msg.sender, "Only admin can add Info!!!");
Info[studentsCounter][_address] = _student;
studentsCounter++;
student_Info.push(_address);
return studentsCounter-1;
}
Thus you can reach your struct by passing studentId(studentCounter) which addInfo returns and students address.
Another approach is to remake you array of addresses.
student[] public student_Info;
And push struct in this array.
function addInfo(student memory _student, address _address) public {
require(owner == msg.sender, "Only admin can add Info!!!");
Info[_address] = _student;
student_Info.push(_student);
}
So now you can display studentsInfo buy passing index in student_Info array.
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
}
}
I get the following errors when trying to type cast string memory to address and uint type.
TypeError: Explicit type conversion not allowed from "string memory" to "address".
TypeError: Explicit type conversion not allowed from "string memory" to "uint256".
Below is the solidity code.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
struct allowedTokenDetails {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
uint256 timestampAdded;
uint256 timestampLastUpdated;
}
mapping(address => allowedTokenDetails) public allowedTokensData;
function setAllowedTokensData(address _token, string[][] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
string memory dataKey = _data[dataIndex][0];
string memory dataValue = _data[dataIndex][1];
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("admin"))) allowedTokensData[_token].admin = address(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("price"))) allowedTokensData[_token].price = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("balance"))) allowedTokensData[_token].balance = uint256(dataValue);
if (keccak256(abi.encodePacked(dataKey)) == keccak256(abi.encodePacked("rewardToken"))) allowedTokensData[_token].rewardToken = address(dataValue);
allowedTokensData[_token].timestampLastUpdated = block.timestamp;
}
}
}
Is there a solution to this?
Instead of validating the input with a set of if statements and typecasting each value based on the function logic, you can already pass the input data in expected types in a prepared struct:
struct inputData {
address admin;
uint256 price;
uint256 balance;
address rewardToken;
}
function setAllowedTokensData(address _token, inputData[] memory _data) public {
for (uint256 dataIndex = 0; dataIndex < _data.length; dataIndex++) {
allowedTokensData[_token] = allowedTokenDetails(
_data[dataIndex].admin,
_data[dataIndex].price,
_data[dataIndex].balance,
_data[dataIndex].rewardToken,
0, // `timestampAdded` not set in your snippet
block.timestamp
);
}
}
I have created a solidity that record data CRUD like where I can create read update delete but I want to create a readAll function wondering how can I write in solidity since I write like below it does not work. For calling with id it return the correct but not readAll. Looking forward for your help <3
example
function readAllTask() public view returns (uint, uint256, uint256) {
return (tasks.id, tasks.stackAddress, tasks.nftId); <============= return everything
}
pragma solidity ^0.8.6;
contract RecordData {
struct Task {
uint id;
uint256 stackAddress;
uint256 nftId;
}
Task[] tasks;
uint nextId; // default value 0, add public to see the value
function createTask(uint256 _stackAddress, uint256 _nftId) public {
tasks.push(Task(nextId, _stackAddress, _nftId));
nextId++;
}
function findIndex(uint _id) internal view returns (uint) {
for (uint i = 0; i < tasks.length; i++) {
if (tasks[i].id == _id) {
return i;
}
}
revert("Task not found");
}
function updateTask(uint _id, uint256 _stackAddress, uint256 _nftId) public {
uint index = findIndex(_id);
tasks[index].stackAddress = _stackAddress;
tasks[index].nftId = _nftId;
}
function readTask(uint _id) public view returns (uint, uint256, uint256) {
uint index = findIndex(_id);
return (tasks[index].id, tasks[index].stackAddress, tasks[index].nftId);
}
function deleteTask(uint _id) public {
uint index = findIndex(_id);
delete tasks[index];
}
}
You can return an array of structs:
function readAllTask() public view returns (Task[] memory) {
return tasks;
}
I think you have reason to do it, but just a remind that saving the data into blockchain is not a good deal, due to the high cost.
If you would like to return all the task, then simply make the tasks public. Solidity automatically assign a get function for it.
If you would like to get some specific content of task struct, then consider something like this:
function readAllTask() public view returns (uint, uint256, uint256 [] memory) {
// something
}
I have this solidity mapping
mapping (string => Ticket) public myMapping;
I want to check if myMapping[key] exists or not. How can I check?
The entire storage space is virtually initialized to 0 (there is no undefined).
So you have to compare the value to the 0 value for your type.
For example, mapping[key] == address(0x0) or mapping[key] = bytes4(0x0).
There is no direct method to check whether the mapping has particular key. But you can check if mapping property has value or not. The following example considered that the Ticket is the struct with some property.
pragma solidity >=0.4.21 <0.6.0;
contract Test {
struct Ticket {
uint seatNumber;
}
mapping (string => Ticket) myMapping;
function isExists(string memory key) public view returns (bool) {
if(myMapping[key].seatNumber != 0){
return true;
}
return false;
}
function add(string memory key, uint seatNumber) public returns (bool){
myMapping[key].seatNumber = seatNumber;
return true;
}
}
pragma solidity ^0.8.0;
contract BookLibNew{
address public owner;
constructor() public{
owner = msg.sender;
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
struct bookDet{
uint bookId;
string bookTitle;
string bookAuthor;
}
mapping (uint8 => bookDet) public bookLib;
function addBookLib(uint8 _bookId, string memory _bookTitle, string memory _bookAuthor)
public onlyOwner {
require(bookLib(_bookId) == false, "Error: Book already exists");
bookLib[_bookId].bookTitle = _bookTitle;
bookLib[_bookId].bookAuthor = _bookAuthor;
}
function readBookDetails(uint8 _bookId) public view returns(string memory, string memory){
return(bookLib[_bookId].bookTitle, bookLib[_bookId].bookAuthor);
}
}