Payments - Invoice Canister Design Review

I’ve been struggling with implementing this exact functionality. Has there been any updates on this @kpeacock? Also, your personal site has been super helpful in learning IC development, so thank you.

How exactly would that allow for atomic transactions, I’m not completely following on this? Are system services on each subnet and could work for each canister on that subnet atomically?

Generally, I don’t fully understand if or why not cross-canister transactions on the same subnet are not atomic?

Did you figure out a solution? Is a AWS lambda call not sufficient?

Well, we’ll go with the idiomatic, although highly limited solution. I don’t really understand why it even works. Because the dfx_notify call by the user is still an inter-canister call and according to my understanding, is just as insecure as directly calling from within the initial transfer call, but maybe I’m missing something here.
I have no idea about AWS lambda, but I’d rather not rely on AWS. I’ll just bite the bullet on this one.

It seems like everybody can call the create_invoice function including the anonymous principal.

Would it be an idea to:

  1. Let the actor have an optional parameter of an allowlist of principals who can create an invoices to prevent somebody malicious from filling up the canister with junk invoices.

  2. Have somebody explicitly confirm through a parameter in the create_invoice canister that they meant to pass the anonymous principal to prevent mistakes.

I’d be happy to help out with a pull request if you agree with these changes

Yes, that is one of the open issues here: [SEC-F21] Anonymous principal has an account · Issue #25 · dfinity/invoice-canister · GitHub

I haven’t been able to finish the project after it got deprioritized, but the allowlist was how I planned to resolve it

2 Likes

Ah apologies should have checked the issues.

Existing NFT projects (on other chains as well) usually employ a “whitelist” (for other purposes) that could provide a practical use case for creating an allowlist of principals known not to be malicious.

For instance, 1st time creation of an invoice for a new user could have a callback to register that principal to the allowlist, which then could be weighted depending on reputation should be a scalar.

Multiple invoice canisters could then also pipe their allowlists to an independent canister, to provide for a decentralized allowlist that all (legitimate) projects could benefit from. Removing from that list could be managed by a DAO (or a specific SNS implementation for this purpose on this decentralized allowlist canister) in case “someone goes bad” in a way that reflects the nature of decentralized governance. Theoretically this could be a good use case for an ecosystem benefiting black hole canister as well.

This seems to be critical infrastructure and I’d guess a lot of people are waiting for this (me included). Why was it deprioritized?

3 Likes

As far as I remember he said it was passed to another team, financial integration team or something like that.

Hello all - eng manager from the SDK team here. Here is the path forward for the invoice canister and IC based payments workflows in general:

  • the invoice canister authored by Kyle will be provided as sample code here. Ultimately, it’s a showcase of how invoices and payments can be facilitated on Internet Computer, but due to considerations raised by our security team at DFINITY, we as an organization, have decided not to officially endorse it as the defecto invoice solution on Internet Computer
  • instead, we will work on a set of tools that will help facilitate payments workflows and release this as a library at a later date. This work will be performed by the Financial Integrations team at DFINITY. I don’t have a timeline for this, but rough estimates would place it somewhere in '23.

If you have any questions about this, let me know, and I’d be happy to answer!

3 Likes

Would Quark help?

2 Likes

It may be because with the ledger canister you can verify how much an address holds, but not who made the transaction. This solutions gives you that option with: destination: AccountIdentifer and verify_invoice

I tried their testnet and it not only shows NNS balance but also allows you to transfer tokens from the NNS to their dApp with a single click, right now its faked so I wonder is that actully possible? I knew principals had no access to infos from the NNS or other dApps.

The Invoice Canister has officially landed in the examples repo! :tada:

We have some cleanup tasks, most importantly adding in access control for invoice creation, but feel free to use this as a reference for your canister logic.

8 Likes

hey is there not an atomicity issue at the responds with invoice state step? I.e. lets say you were making the invoice buy nft’s or something.
But after the invoice canister responds with a verified invoice state, if the dapp canister fails to mint, then you have a verified invoice without provision of service.

I.e.
func verify_invoice_and_provide_service(){
var txreceipt = await verify_invoice();
-------------------------------------------> potential atomicity hole
provide_synchronous_service()
more_synchronous_code()
}

Basically if provide_a_synchronous_service() is synchronous as named, is it garunteed to go through? Cause I can see issues occuring at that middle step. One being what if the canister ran out of cycles at exactly that step? Or am I wrong? If an intercanister call is able to run its code (i.e. verify the invoice internally), is the response a garuntee that the dapp canister will execute the rest of the synchronous code below (given theres no other async calls below)?

The verify step can be called idempotently - it updates to verified after the first call, and after that it returns an alreadyVerified variant. The dapp canister can use its own logic to handle errors, retries, and refunds

yea but what if i was dependent on that initial verified response and not the alreadyverified response. Is the only way to ensure that a synchronous service is ran in conjunction with the initial verified state is to inbuild the service into the invoice and not an external canister?

synchronicity was not a design goal - the Invoice Canister verification flow is based on a polling model that will be “eventually true”, while requiring minimal code to integrate with.

If your use case has a particular need to execute something at the time the verification takes place, it may very well be preferable to copy portions of the logic directly into your service logic, and skip the invoice canister entirely

2 Likes

I see, that makes sense.