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);
}
Related
I've initialized a votes array and two functions to store the votes in our array as :
uint[2] votes = [0,0];
function vote_a() public{
votes[0] += 1;
}
function vote_b() public{
votes[1] += 1;
}
Now, I've created a "results" function which should return a string "tie", "a wins" or "b wins" on the basis of number of votes while also reassigning the number of votes to 0
function results() public returns(string memory){
uint a = votes[0];
uint b = votes[1];
votes[0]=0;
votes[1]=0;
if (a==b)
return "tie";
else if (a>b)
return "a wins";
else
return "b wins";
}
but it does not show the returned result in remix ide like a view function. And I cannot modify the state of the function to view as it'd throw an error for changing value of votes array elements. Is there any way to achieve both conditions.
This happen when you'alterating state variables defined in view functions.
Thus, view functions can only reads data from your smart contract.
To solve your issue, I tried to split the content about results() function in two functions. The first function that I called setResults() is a similar to setter functions (in other programming languages), so allows only for contract owner to handle the array values.
Second function, allows you to view the result about the comparison between a and b elements.
In the following lines, I put your smart contract adjusted where I inserted some notes:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Test {
uint[2] votes = [0,0];
address owner;
// NOTE: I set a 'owner' variable with the address value who have deployed for the first time the smart contract
constructor() {
owner = msg.sender;
}
// NOTE: Modifier that allow only for smart contract owner the access to specific function
modifier onlyOwner() {
require(msg.sender == owner, "You're not the owner!");
_;
}
function vote_a() public{
votes[0] += 1;
}
function vote_b() public{
votes[1] += 1;
}
function results() public view returns(string memory){
uint a = votes[0];
uint b = votes[1];
if (a==b)
return "tie";
else if (a>b)
return "a wins";
else
return "b wins";
}
// NOTE: I created a new function that allows you to handle the data inside array
function setResults() public onlyOwner {
votes[0] = 0;
votes[1] = 0;
}
}
IMPORTANT: Before call results() function, remember you to call setResults() for change the array values.
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
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(...);
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.
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.