Tact doesn't support classical class inheritance and instead introduces the concept of traits. Traits are similar to simplified base classes that potentially add state variables, receivers, getters or contract methods.
Contracts can rely on multiple traits. Extract logic into a trait if you have multiple contracts that share this logic.
This example shows how to write a new trait that adds simple analytics behavior to any contract.
This trait also makes use of the virtual
keyword which lets the contract relying on the trait override some of the trait's behaviors. In the example, the default filter behavior ignores messages from owner in the analytics.
The contract relying on the trait can change this default behavior by specifying the override
keyword and providing a new implementation to this method. In our case, the custom filter is to have no filters.
import "@stdlib/deploy"; message HiFromParent { greeting: String; } message HiFromChild { fromSeqno: Int as uint64; greeting: String; } // we have multiple instances of the children contract TodoChild { parent: Address; // we added this variable so a child always knows who the parent is seqno: Int as uint64; // when deploying an instance, we must specify its index (sequence number) init(parent: Address, seqno: Int) { require(sender() == parent, "not the parent"); self.parent = parent; self.seqno = seqno; } receive(msg: HiFromParent) { require(sender() == self.parent, "Access denied"); // only the real parent can get here dump(self.seqno); dump("😃 handling hi from parent"); self.reply(HiFromChild{fromSeqno: self.seqno, greeting: "sup"}.toCell()); } } // we have one instance of the parent contract TodoParent with Deployable { init() {} receive("greet 3") { let i: Int = 0; repeat (3) { i = i + 1; let init: StateInit = initOf TodoChild(myAddress(), i); send(SendParameters{ to: contractAddress(init), body: HiFromParent{ greeting: "darling" }.toCell(), value: ton("0.1"), // pay for message and potential deployment mode: SendIgnoreErrors, code: init.code, // if child is not deployed, also deploy it data: init.data }); } } receive(msg: HiFromChild) { let expectedAddress: Address = contractAddress(initOf TodoChild(myAddress(), msg.fromSeqno)); require(sender() == expectedAddress, "Access denied"); // only the real children can get here dump(msg.fromSeqno); dump("😑 handling hi from child"); } }