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 }}
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) }); }}
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) }); }}
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) }); }}
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) }); }}
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(), }); }}
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()) }}