Solidity - initialize string array in struct - arrays

I am currently working on my first smart contract. After already reading a few topics out there I still don't have a clue on how to initialize the string array inside my struct.
The idea is that the customer can always choose from a variety of energysources on a homepage which then gets deployed on the smart contract if he's done choosing.
So what would be the best/efficient way to implement this idea onto the blockchain?
pragma solidity ^0.4.23; /* solhint-disable */
contract EnergyContract {
struct EnContract {
uint price;
uint amount;
string[] energysource;
address creator;
}
EnContract[] aContract;
function createContract(uint _price, uint _amount, address _creator) public {
aContract.length += 1;
EnContract storage _EnContract = aContract[aContract.length - 1];
_EnContract.price = _price;
_EnContract.amount = _amount;
_EnContract.creator = _creator;
}
}

The way you declare your array is correct. You don't need to do anything else. You can just start pushing data into the array.

Related

Solidity inserting array as map value after _setTokenURI on ERC721

I want to assign an array as a value type of a map named dictBasic after function _mint and _setTokenURI from erc721. something like this:
contract Implement721 is ERC721URIStorage{
uint256 public tokenCounter;
mapping(address => uint[]) public dictBasic;
constructor() ERC721("alvinChris", "ACH") {
tokenCounter = 100;
}
function saveData(address _address_sender, string memory _tokenURI)
public returns(address, uint256){
uint256 newItemId = tokenCounter;
_mint(_address_sender, newItemId); //mint function
_setTokenURI(newItemId, _tokenURI); //setTokenURI
//inserting to map
dictBasic[_address_sender].push(tokenCounter);
tokenCounter = tokenCounter + 1;
return (_address_sender, newItemId);
}
I can assign successfully, but the question is can I make sure that the _mint and _setTokenURI is done before inserting array to Map. can someone give me the example on handling this case.
The idea that come in my mind is like IF logic, when _mint and _setTokenURI is not done, then pending assigning value to Map until its done.
Thankyou for the help

Solidity: Return a mapping from inside a struct

here is my code:
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;
mapping(uint => ProductWithBids) public internalProducts;
struct SecretBids {
uint values;
bool fake;
string secret;
}
struct ProductWithBids {
uint id;
string name;
uint price;
address payable owner;
address payable beneficiary;
bool purchased;
mapping(address => Bid[]) bids;
mapping(address => SecretBids[]) nakedBids;
// Allowed withdrawals of previous bids
mapping(address => uint) pendingReturns;
uint bidsCount;
bool ended;
uint biddingEnd;
uint revealEnd;
address highestBidder;
uint highestBid;
}
function getNakedBids(uint _id)
public
view
returns(SecretBids[] memory product) {
ProductWithBids storage selectedProduct = internalProducts[_id];
return selectedProduct.nakedBids;
}
i need to return the nakedBids but i get the following error :
TypeError: Return argument type mapping(address => struct eShop.SecretBids storage ref[] storage ref) is not implicitly convertible to expected type (type of first return variable) struct eShop.SecretBids memory[] memory.
return selectedProduct.nakedBids;
I get what the error means, i think i have tried everything and looked everywhere. From what i have found is that solidity doesn't support at all this action .Does anyone has any idea what i can try next? If i missed any other important code parts let me know. Thanks in advance.
I also tried :
returns(mapping(address => SecretBids[]) memory nakedBids)
but then i get the following error:
Types containing (nested) mappings can only be parameters or return variables of internal or library functions.
returns(mapping(address => SecretBids[]) memory nakedBids) {
^-----------------------------------------------^
,TypeError: Type mapping(address => struct eShop.SecretBids[]) is only valid in storage because it contains a (nested) mapping.
returns(mapping(address => SecretBids[]) memory nakedBids)
ps: if i change it to storage it complains that Data location must be memory.
By the way, you should move mapping(address => SecretBids[]) nakedBids; out of the struct, and let it be a storage variable on its own.
nakedBids is an array of SecretBids struct.
My answer is based on solidity v0.5.x (hopefully similar to 0.7.4). Return array of struct is not supported in solidity yet. Instead you can return tuple.
returns (uint[] memory, bool[] memory, string[] memory)
I pretty much gave up on the idea of creating a getter. So i got the data i needed in a more direct way. Probably is not the best way but it worked for me. Feel free to share any other solutions.
Here is the code:
function reveal(
uint _id
)
public
payable
{
ProductWithBids storage selectedProduct = internalProducts[_id];
//onlyAfter biddingEnd && onlyBefore revealEnd
require(block.timestamp > selectedProduct.biddingEnd);
require(block.timestamp < selectedProduct.revealEnd);
uint count = selectedProduct.bidsCount;
uint[] memory values = new uint[](count);
bool[] memory fake = new bool[](count);
string[] memory secret = new string[](count);
for (uint i = 0; i < count; i++) {
values[i] = selectedProduct.nakedBids[msg.sender][i].values;
fake[i] = selectedProduct.nakedBids[msg.sender][i].fake;
secret[i] = selectedProduct.nakedBids[msg.sender][i].secret;
}
revealInternal(
values,
fake,
secret,
_id
);
}
I did not go from the start with this solution because i needed the react-js to do it from the front-end and then just pass it in revealInternal(...);

Make ArduinoJSON Array globally available

I am wrapping my head around this problem quite a long time now.
I am opening a websocket Connection from my ESP32 to my NodeJS Backend. When receiving a message, the content gets parsed with ArduinoJSON.
I store the parsed content in global Variables so I can access them in my void loop(). Everytime a new message comes in they are overwritten. Thats how it should be.
The Variable Declaration:
uint8_t brightness = 10;
uint8_t lastMillis = 0;
int ArrayPointer = 0;
int interval = 2000;
bool immediate = true;
const size_t capacity = JSON_ARRAY_SIZE(32) + JSON_OBJECT_SIZE(1) + 290;
After the void Setup()
void onMessageCallback(WebsocketsMessage message) {
Serial.print("Got Message: ");
DynamicJsonBuffer jsonBuffer(capacity);
JsonObject & JSONResponse = jsonBuffer.parseObject(message);
JsonArray & PixelArray = JSONResponse["frame"];
brightness = JSONResponse["brightness"];
ArrayPointer = 0;
immediate = true;
}
void loop() {
client.poll();
if(millis() - lastMillis >= interval || immediate == true) {
// Here I would like to access the Variable PixelArray
lastMillis = millis();
}
}
Of course I cant access PixelArray in the void loop because its a different scope.
Now i Need a way to make PixelArray globally accessible.
What I tried:
Declared a global JsonArray before void Setup() but this threw an error ;(.
Assigning it to another (global) array didnt work properly because the size of the PixelArray varies.
Hopefully somebody can help me ;)
Thanks in advance ;)
PS: Currently I am using ArduinoJson 5 but an upgrade would be no problem.
Don't do it that way.
You should use ArduinoJson just to serialize and deserialize JSON objects, not to store program state. Its documentation makes that very clear.
The correct way to do this (the way that the ArduinoJSON package is designed to be used) is to maintain an internal data structure and serialize and deserialize your JSON objects to it.
So you'd have a global variable that would be your internal representation of PixelArray and then copy values from the JsonArray to it when you receive a JSON message. You're using brightness correctly here; you should do the same thing with PixelArray.

Solidity: UnimplementedFeatureError: Nested dynamic arrays not implemented here

When I try to do this in Solidity, it gives me
UnimplementedFeatureError: Nested dynamic arrays not implemented here.
I see this in code examples. Does Solidity not support this?
Edit - posted complete code below. So I figured out the problem is only in the last function. It doesn't like that I am returning a dynamic array. How could I implement the same functionality (I want to return a string array of data)?
pragma solidity ^0.4.6;
contract EmailIntegrity {
// Map an array of EmailIntegrityStructs for each email address.
// The first element will be used for the integrity record.
// The rest will be used for audit records.
enum ItemType { Integrity, Audit }
struct EmailIntegrityStruct {
ItemType itemType;
uint timestamp;
string data;
}
mapping(address => EmailIntegrityStruct[]) emailIntegrityStructs;
function hasEmailIntegrityData(address emailAddress) public constant returns(bool isEmail) {
return emailIntegrityStructs[emailAddress][0].timestamp == 0;
}
function insertIntegrityData(address emailAddress, uint timestamp, string data) public returns(bool success) {
if (hasEmailIntegrityData(emailAddress)) {
revert();
}
EmailIntegrityStruct memory integrityData;
integrityData.itemType = ItemType.Integrity;
integrityData.timestamp = timestamp;
integrityData.data = data;
emailIntegrityStructs[emailAddress].push(integrityData);
return emailIntegrityStructs[emailAddress].length == 1;
}
function insertAuditData(address emailAddress, uint timestamp, string data) public returns(bool success) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
EmailIntegrityStruct memory auditData;
auditData.itemType = ItemType.Audit;
auditData.timestamp = timestamp;
auditData.data = data;
emailIntegrityStructs[emailAddress].push(auditData);
return emailIntegrityStructs[emailAddress].length > 1;
}
function getIntegrityData(address emailAddress) public constant returns(string data) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
return emailIntegrityStructs[emailAddress][0].data;
}
function getAuditData(address emailAddress) public constant returns(string[] data) {
if (!hasEmailIntegrityData(emailAddress)) {
revert();
}
var length = emailIntegrityStructs[emailAddress].length;
string[] memory auditData = new string[](length - 1);
for (uint i = 1; i < length ; i++) {
auditData[i] = emailIntegrityStructs[emailAddress][i].data;
}
return auditData;
}
}
Solidity and Javascript allow nested arrays but we do not have the ability to pull a nested dynamic array from the solidity over to javascript world.
it is the limitation of the bridge between solidity and javascript. Since strings inside of solidity are represented as dynamic arrays, we cannot transfer array of strings.
UPDATE
Since then, solidity has evolved, you can return dynamic array including structs. A test contract:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.0;
contract Test {
struct User{
string name;
string LastName;
}
User[] public store;
function addToStorage() external returns (User[] memory ) {
User memory newUser=User(
"yilmads","bin"
);
store.push(newUser);
return store;
}
}
This compiled fine for me.
I added a definition of MyStruct and upped the Solidity version to the current one (though it compiled fine with the old pragma too). Here's the code I compiled via Remix:
pragma solidity ^0.4.19;
contract MyContract{
struct MyStruct {
uint256 foo;
}
mapping(address => MyStruct[]) myStruct;
}
Could it be that you're using an older version of the Solidity compiler? (The ^0.4.6 made me think that perhaps you are.)
What's your MyStruct? Perhaps a more interesting structure there would fail. In general, please try to provide full code samples that reproduce the problem you're seeing.

How do I initialize an array in a struct

I have a struct Purchase in which I'm putting an array of payments. However, when I try to add the new payments array in my makePayment method I get an error back from the solidity compiler: "Internal compiler error: Copying of type struct Payment memory[] memory to storage not yet supported." When I change the mayment array to be storage or memory, I get the same error. I've added the relevant code below.
Is it possible to do what I'm trying to do in solidity? I don't see anything explicitly saying it's not possible in the documentation but I also don't see any examples doing what I'm trying to do. :|
struct Payment {
address maker;
uint amount;
}
struct Purchase {
uint product_id;
bool complete;
Payment[] payments;
}
Purchase[] purchases;
function makePayment(uint product_id, uint amt, uint purchase_id) returns (bool) {
Payment[] payments;
payments[0] = Payment(address, amt);
purchases[purchase_id] = Purchase(product_id, false, payments);
}
You need to manually change the length of the payments array when setting it.
Either use:
Payment[] payments;
payments[payments.length++] = Payment(address, amt);
Or:
Payment[] payments;
payments.push(Payment(address, amt));
For setting the payments array in Purchase, instead of creating an array and trying to set it to the Purchase.payments you can do the following:
uint purchase_id = purchases.length++;
purchases[purchase_id].product_id = product_id;
purchases[purchase_id].complete = false;
purchases[purchase_id].payments.push(Payment(msg.sender, amt));
Extending the purchases length will automatically create the new attributes. Then you can set them manually.
I found this as best solution.
event OnCreateRoom(address indexed _from, uint256 _value);
struct Room {
address[] players;
uint256 whosTurnId;
uint256 roomState;
}
Room[] rooms;
function createRoom() public{
address[] adr;
adr.push(msg.sender);
Room memory room = Room(adr, 0, 0);
rooms.push(room);
OnCreateRoom(msg.sender, 0);
}

Resources