2

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?)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.