What's the typical pattern of error handling and reporting to frontend in a multi-contract interaction?

Let’s say I have a contract A that’s supposed to be called from the frontend (DApp/TWA), and the full interaction involves several contracts: A calls B, C, D, and C again. It’s desirable to report on frontend whether the whole “saga” was successful. Is this feasible in TON without extra means (like backend/indexing APIs)?

 A –––> B     C     D
 |      *     |     |
 | <––– |     |     |
 *      |     |     |
 | –––––––––> |     |
 |      |     *     |
 | <––––––––– |     |  // this may be missing if C is third-party
 *      |     |     |
 | ---------------> |
 |      |     |     *
 | <--------------- |
 *      |     |     |
 | –––––––––> |     |
 |      |     *     |
 | <––––––––– |     |  // this may be missing if C is third-party
 *      |     |     |

The complication I see is that once A calls B, the initial tx from the user’s wallet is finished, and the rest of the process is done in new txs (tx 2: B recieves msg from A, computes, and sends another msg to A), which can’t bounce “back to wallet”, while in each compute point (* on the diagram) errors may take place. I’m aware that one can send and resend the same query_id for all the messages of this “saga”, but what’s the typical approach to error handling, especially when, say, contract C is a third-party one?

I’ve checked the article by Tal Kol that explains contract sharding and followed “User story 1” (sending Jetton), but the code is not self-explanatory: (ok, let’s skip the external messages stuff) what does the “revert on errors” comment mean? In my tests, if send_raw_message fails on the action phase, the code after it still computes (and that’s understandable, as it’s executed during the compute phase).

Basically my question is: how can I “collect” the results and “report” them on frontend (i.e. distinguish “pending”, “success”, and “failure” states)? In sandbox (Blueprint autotests), it’s simple: each send_ method of a SandboxContract returns a full log containing all the txs and events in the chain of interactions, but is there something similar available for frontend?

More specifically, it seems that saga is not needed (in Jetton), so how the possible errors are handled and reported instead?

PS Another related question is: if C doesn’t send specific responses on success, but I need to send message to D after the message to C is successfully processed, can I still somehow do that?

1 Like

Alright, looks like I’ve found the answer to the first part of the question.

For frontend we have at least 2 APIs: toncenter (/transactions and /transactionsByMessage) and tonconsole (/v2/blockchain/transactions/{tx_id} and /v2/blockchain/messages/{msg_id}/transaction) which allow to see messages of a tx, and then find next txs by those messages, and get the whole chain using those. Note: I haven’t used this in production yet, only checked that the APIs allow to get the chain of messages and txs on a live mainnet example.

===

But I still don’t understand how to handle the case when I need a “saga”, i.e. call D after C, but only if tx to C succeeds (and given that C doesn’t send any specific response). What I do understand is that I can set the bounce flag to the A → C message, but that only allows (I’m not sure if it works in 100% cases) to get a message with the bounced flag (and hopefully the same query_id) if the tx fails. However, I need a way to send to D only if and after the tx on C succeeds. Is there any way to do that?

1 Like