Skip to content

Single-contract communication

This page lists examples of communication between a single deployed contract and other contracts on blockchain.

For examples of communication between multiple deployed contracts, see: Multi-contract communication.

How to make a basic reply

contract Example {
receive() {
self.reply("Hello, World!".asComment()); // asComment converts a String to a Cell with a comment
}
}
▶️ Open in Web IDE

How to send a simple message

contract Example {
receive() {
send(SendParameters {
bounce: true, // default
to: sender(), // or another destination address
value: ton("0.01"), // attached amount of TON to send
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
▶️ Open in Web IDE

How to send a message with the entire balance

If we need to send the whole balance of the smart contract, we should use the SendRemainingBalance send mode. Alternatively, we can use mode: 128, which has the same meaning.

contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingBalance, // or mode: 128
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
▶️ Open in Web IDE

How to send a message with the remaining value

If we want to send a reply to the same sender, we can use the mode SendRemainingValue (i.e. mode: 64), which carries all the remaining value of the inbound message in addition to the value initially indicated in the new message.

contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingValue,
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
▶️ Open in Web IDE

It’s often useful to add the SendIgnoreErrors flag too, in order to ignore any errors arising while processing this message during the action phase:

contract Example {
receive() {
send(SendParameters {
// bounce = true by default
to: sender(), // send the message back to the original sender
value: 0,
mode: SendRemainingValue | SendIgnoreErrors, // prefer using | over + for the mode
body: "Hello from Tact!".asComment(), // comment (optional)
});
}
}
▶️ Open in Web IDE

The latter example is identical to using the self.reply() function.

How to send a message with a long text comment

If we need to send a message with a lengthy text comment, we should create a String consisting of more than 127 characters. To do this, we can utilize the StringBuilder primitive type and its methods beginComment() and append(). Prior to sending, we should convert this string into a cell using the toCell() method.

contract Example {
receive() {
let comment: StringBuilder = beginComment();
let longString = "..."; // Some string with more than 127 characters.
comment.append(longString);
send(SendParameters {
// bounce = true by default
to: sender(),
value: 0,
mode: SendIgnoreErrors,
body: comment.toCell(),
});
}
}
▶️ Open in Web IDE

How to commit the state for the sequence number

To prevent the possibility of replay attacks, you can use unique identifiers, such as seqno. Yet, the changes made to it must persist. To do so, the commit() function is used.

message MsgWithSignedData {
bundle: SignedBundle;
seqno: Int as uint64;
someExtraData: Cell;
}
contract Sample(
publicKey: Int as uint256,
seqno: Int as uint64,
) {
external(msg: MsgWithSignedData) {
// Various checks with accepting the external message processing afterwards
require(msg.bundle.verifySignature(self.publicKey), "Invalid signature");
require(msg.seqno == self.seqno, "Invalid seqno");
acceptMessage();
// Since we have done all the checks we can now safely increase the number,
// then commit the state of persistent data and output actions,
// and, finally, save that state early, before any further actions take place.
self.seqno += 1;
commit();
setData(self.toCell());
// And now you can safely do something with the rest of the message,
// knowing that the `self.seqno` change will not be reverted in case of errors
throw(42); // this will prevent subsequent code from executing,
// but will not fail the transaction!
}
// Empty receiver for the deployment,
// which forwards the remaining value back to the sender
receive() { cashback(sender()) }
}
▶️ Open in Web IDE