I am trying to save an invoice to contract storage (see function addNewInvoice(..)
) but I seem to be tripping over the data locations.
// SPDX-License-Identifier: private
pragma solidity >=0.7.0;
pragma experimental ABIEncoderV2;
contract InvoiceValidator {
mapping(uint => Invoice) private idToInvoiceMap;
uint[] private invoicesToValidate;
struct Treatment {
string description;
uint cost;
}
struct Invoice {
address recipient;
address sender;
string patient;
uint date;
Treatment[] treatment;
}
constructor() {}
function addNewInvoice(address recipient, address sender, string memory patient, uint date, Treatment[] memory treatments)
external
{
uint invoiceId = 1;
Invoice memory invoice = Invoice(recipient, sender, patient, date, treatments);
idToInvoiceMap[invoiceId] = invoice;
invoicesToValidate.push(invoiceId);
}
}
throws
UnimplementedFeatureError: Copying of type struct InvoiceValidator.Treatment memory[] memory to storage not yet supported.
I think this is because of the line
idToInvoiceMap[invoiceId] = invoice;
which would save the invoice to contract state, which is what I am trying to do.
Is there a way to achieve this?
Also, I couldn't find a whole lot of good ressources about data location (storage
, memory
, calldata
[, stack
]), so I'm not sure if memory
is even the right location for the local invoice variable. But if I change the line
Invoice memory invoice = Invoice(recipient, sender, patient, date, treatments);
to
Invoice storage invoice = Invoice(recipient, sender, patient, date, treatments);
the compiler throws
[...].sol:30:9: TypeError: Type struct InvoiceValidator.Invoice memory is not implicitly convertible to expected type struct InvoiceValidator.Invoice storage pointer. Invoice storage invoice = Invoice(recipient, sender, patient, date, treatments); ^-----------------------------------------------------------------------------^
And what I do not understand either is that when I change the Invoice
struct treatment
property to a single Treatment
(instead of an array of them) like this:
struct Invoice {
address recipient;
address sender;
string patient;
uint date;
Treatment treatment;
}
and try to assign it like this:
Invoice memory invoice = Invoice(recipient, sender, patient, date, treatments[0]);
it seems to work, but changing to storage
Invoice storage invoice = Invoice(recipient, sender, patient, date, treatments[0]);
throws
[...].sol:30:9: TypeError: Type struct InvoiceValidator.Invoice memory is not implicitly convertible to expected type struct InvoiceValidator.Invoice storage pointer. Invoice storage invoice = Invoice(recipient, sender, patient, date, treatments[0]); ^--------------------------------------------------------------------------------^
So there seems to be another problem with arrays of reference types vs reference type only?
I would much appreciate if somebody could help me solve how to save this invoice containing a list of treatments to contract storage or shine some light on my confusion in general.
(Also: I couldn't find much information about this either but am I correct in assuming that it would be more appropriate to emit events and create an outside-the-blockchain storage to keep track of data instead of storing a lot of invoices inside the contract?)