We are seeing a type mismatch with respect to ledger canister and the current invoice canister codebase (present here). So I believe we cannot directly plug in to the interface in the mainnet as the typings are completely different than what is used in the invoice implementation.
What do you folks at the community suggest about a way going forward?
For example, in the current invoice canister code, (As of 26/05/2022)
public type AccountIdentifier = Blob;
and in the current ledger canister types, ​public type AccountIdentifier = [Nat8];​
We are working on a transaction flow for an NFT project. We initially planned we will depend on the invoice canister for invoice generation and payment validation.
So now, is our only option is to go through the invoice canister code and update it to support newer typings line by line? Or is there any better way to do this? How would you suggest we go forward?
To be clear, both Motoko [Nat8] and Blob can be exported/imported as Candid vec nat8. Within Motoko itself, the type [Nat8] and Blob are distinct and require explicit conversion of values from one type to the other type.
One reason to sometimes import vec nat8 as Blob is that blobs have a much more compact in-memory representation than [Nat8] (which take 4x space over blobs), but the operations on Blobs are currently much more limited (just iteration, no map, fold, direct indexing etc)
To be honest, I don’t know enough about the invoice canister to recommend it or not. I think there must be a reason for that warning but don’t know what it is.
Perhaps someone else can chime in (@kpeacock perhaps).
If you can get away with it, I would just manually convert between the Blob and [Nat8] where required. If you can’t do this…
Regarding fixing the interface, one thing you could try is import the canister, extract the principal, get its textual form, and cast the textual form to the equivalent interface with the desired Motoko types.
(If I recall correctly, you can perform the cast on a computed text value, not just a literal as in the example above, provided you wrap the expression computing the text of the principal in parens, e.g.
actor ( Principal.toText(Principal.ofActor(Ledger)) ) : AltLedger
But that’s just a suggestion, I haven’t tried it and the actor interface (AltLedger) you need to specify in the cast might be quite large (but could be small if you only need a subset of it’s full functionality). All terribly unsafe, too.
Forking the invoice canister and rewriting it to match the Ledger interface might be a better option, tbh.
Thanks for the reply.
It seems there are many red flags in this approach. Would you suggest any other RECOMMENDED approach for ICP transactions in Dfinity apart from the Invoice Canister Method?
Sorry for the delay, I’ve been on vacation. Here’s the latest on the invoice canister.
Dfinity has decided that the invoice canister will be turned into an example of how to handle transactions in a canister, and will be moved to the examples repo. There is no official recommended approach today.
In the process of moving this to the examples repo, I will fix the type mismatch and get the project ready to self-deploy
The financial integrations team has indicated that their preferred approach will be to provide Motoko and Rust libraries for moving tokens, rather than a canister-based approach
Hi @kpeacock ,
I was going through invoice canister example readme ( nicely written ). And I found this line
" * There is some degree of risk in allowing the get_invoice, get_account_identifier, and get_balance queries to be left as queries"
Can you throw some more light on why “query” keyword is the reason for some degree of risk and what are those risk ?
Queries are served by a single replica and don’t go through consensus, so while they are faster and cheaper (currently free) they are less secure cause a node could modify the data.
Is the idea that within a single round of consensus a query can temporarily modify state on that single replica (not globally replicated) which could affect another call that is batch processed on that same replica within the same consensus round?
I think they’re talking about a rogue node operator being able (in theory) to modify a canister’s response when queried. Hence the “lack of security”.