Docs
Linting rules

E007: no-bounce-handler

Reports `createMessage({ bounce: BounceMode.<...> })` calls reachable from `onInternalMessage` when the contract file does not declare `onBouncedMessage`.

Metadata

  • Code: E007
  • Rule: no-bounce-handler
  • Status: Stable since v0.0.1
  • Quick fix: not available

What it does

Reports createMessage({ bounce: BounceMode.<...> }) calls reachable from onInternalMessage when the contract file does not declare onBouncedMessage.

Why is this bad?

If an outgoing internal message can bounce, the bounced transaction returns to onBouncedMessage. Without that handler, the contract cannot restore state, refund accounting, or observe the failure.

Example

fun onInternalMessage(in: InMessage) {
    sendRefund(in.senderAddress);
}

fun sendRefund(dest: address) {
    val refundMessage = createMessage({
        bounce: BounceMode.Only256BitsOfBody,
        //      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E007: contract sends a message that may bounce but `onBouncedMessage` handler doesn't exist
        value: ton("0.1"),
        dest,
    });
    refundMessage.send(SEND_MODE_REGULAR);
}

Use instead:

fun onBouncedMessage(in: InMessageBounced) {
    // handle bounced refund message
}

Or send explicitly without bounce handling:

val refundMessage = createMessage({
    bounce: BounceMode.NoBounce,
    value: ton("0.1"),
    dest,
    body: beginCell().endCell(),
});

Behavior notes

  • BounceMode.NoBounce is ignored by this rule.
  • Legacy boolean bounce values are not currently matched; the check looks for BounceMode field access.
  • The handler must be declared as onBouncedMessage in the same file as the onInternalMessage entrypoint.
Source code

Last updated on

On this page