I have double-checked that the ICP ledger principal is correctly configured, and I deployed the canisters on the “system” subnet. I make an ICP deposit to the canister’s default subaccount, and then pass the transaction receipt to the canister, which then calls verify(). It always fails with failed to query transaction and I have no idea why. I have worked through the weekend for this, because that’s the last part of a grant I’m working on, but I checked everything I could on my side, so I’m suspecting that something might be wrong with the ic_ledger_types crate. After all, the feature to query blocks was only added recently on my behalf, and I’m not sure whether it has actually been tested yet.
Ok I solved the problem it was NOT a problem with the crate, rather, my TransactionNotification constructor only listened for Transfer transactions, whereas I was testing it with a Mint transaction. Somehow, I had troubles setting up the test net to support transfers with large amounts of ICP tokens (but that’s a problem on how I used DFX, I guess, not a problem in my canister), so now I just used the minter account to deposit.
Thanks. I had the strange test setup because I couldn’t get the normal prefunded accounts to work for some reason. I think I might publish the component I wrote for receiving ICP with canisters in a separate crate, it allows paying ICP to the canister’s default subaccount and the payment context is in the transaction’s memo. The workflow is as follows:
Have a payment ID (some hash or nonce or whatever). Derive a unique u64 (the memo) from it, it should be reasonably collision resistant (no one should be able to come up with a differing payment ID that has the same memo within a few minutes). In my case, it was the first 8 bytes of the hash of the encoded action I wanted to take.
Send a transaction with that memo to the default subaccount of the canister you want to pay.
Send the transaction’s block height to the canister. The canister verifies the transaction, ignoring duplicates or transactions to the wrong recipient, etc., and accumulates the deposits made to each memo.
Redeem the deposits by sending the full payment ID (so, in my case, that was the payment channel ID I wanted to fund, as well as the address within the channel to credit the funds to) to the canister. It now calculates the associated memo from the ID, and drains the accumulated funds from the memo’s counter.
This process allows for partial payments, such as when crowdfunding, etc., to be accumulated. The logic for actually handling the purchase can be kept completely separate from that, simplifying the canister’s code complexity. This design can be expanded to also handle other token types that have different receipt mechanisms in a clean manner.
The component also allows simulation testing, which might otherwise be not so easy to incorporate into a canister that’s hard-coded to receive ICP.