The best way to enable payments to canisters from users?


I’ve been thinking about this for some time now and have come to some conclusion (which I yet need to test out and see if it works the way I imagined it to), but I am not sure if it’s the only and / or best way to do so and would like your opinion on it.

I would like to have an app that is able to allow users to purchase whatever (let’s say NFT’s) that are listed for sale. But I did not find any other way of possibly doing so right now than using a combination of the following (this is my current plan):

  1. Through javascript, there would be a call made to ledger canister (i have one deployed locally for testing) by importing a ledger canister, then calling it’s send_dfx method to transfer funds to my smart contract canister (ie: user sends ICP to my smart contract canister by calling ledger canister directly)
  2. If that call was a success (this would need to be checked in JS I guess after the async method is completed) I can then make another call to the ledger canister to notify it of the transfer so that it invokes the transaction_notification method in my canister (to which the user has sent the payment in step 1). In that method in my SC i would then do checks to see if the address matches the user’s address, price matches token price etc… Then, I would send him the item he bought

Is this the way to do this (the only / best way currently) ? Are there any drawbacks to this method (other than if a user leaves the page before the second when the call to ledger notify method is made) ?

Or is there something a lot more simple that would allow me to do what I want?

I think @kpeacock was working on something related to this.


Thank you :slight_smile: I hope he gets to see this eventually and posts his own thoughts or solution :slight_smile: In the meantime, there must be a way people are currently doing this, as there are services like Entrepot for example which already have this implemented

bump to see if anyone has anything more to add.

Send_dfx to the canister, then have a deposit function that takes a block and processes the payment. Add the block to a tracker so it can’t be used again, Check the block, make sure it matches the deposit, then credit the user for the payment and take action. If it didn’t match, remove the block from the tracker.

1 Like

Alright, so pretty much what I had in plan already then? Is there a need to send a second tx to ledger from the client to trigger the transaction_notification in my canister where I would handle fulfillment logic (ie sending NFT to the user), or would just a callback once a successful async call to ledger for send_dfx was made do? Is it safe to assume a tx was successful if a call to send_dfx was made, so we could go straight to a method in the canister that assigns whatever has been bought to the user, or is that vulnerable if not checked in transaction_notification hook callback?

Thank you very much for this, I really appreciate it ! :slight_smile: Needed to get a confirmation from someone who has done it or tested it like yourself to be sure it’s the way to go!

The issue with notify was that a malicious canister could hang your ledger by never returning a value. Thus it is being deprecated. get_block has a similar ddos vector, but at least the attacker has to pay cycles for it. I would not assume that your send_dfx works perfectly. Check the block and make sure.

Some of the checking logic can be found at aramakme_nft_auction/ at f0ca7fb629814dc24a90ad84c7d024a49390e38b · aramakme/aramakme_nft_auction · GitHub. ← uses a proxy canister to check blocks because it used to(maybe still is) only available to protobuff

1 Like

My solution is mostly done - we haven’t announced it yet as I resolve some final security / scaling considerations, but that’s what I’ll be working on this sprint! News should be coming before much longer


Thank you both for providing help on this matter :slight_smile: It gives me something to work with until @kpeacock is done with his solution (which I hope would perhaps provide a more streamlined approach and ease up this kind of app flow).