When a contract is deployed to the chain, it receives an address by which users can refer to it and send it transactions.
In this example, we have two different contracts: Todo1
and Todo2
. They are deployed separately and each gets its own unique address. As we've seen before, a contract can always know its own address by running myAddress()
.
The special bit in this example is that each contract can also get the address of the other contract by running contractAddress(stateInit)
.
Contract addresses on TON are derived from the initial code of the contract (the compiled bytecode) and the initial data of the contract (the arguments of init).
Both contracts don't have any constructor arguments, so their initial data is the identical. Their addresses are different because their code is different.
The combination of the inital code and the initial data is called the stateInit of the contract. Tact gives easy access to the stateInit using the initOf
statement.
import "@stdlib/deploy"; message HiFromParent { greeting: String; } message HiFromChild { fromSeqno: Int as uint64; greeting: String; } // we have multiple instances of the children contract TodoChild { seqno: Int as uint64; // when deploying an instance, we must specify its index (sequence number) init(seqno: Int) { self.seqno = seqno; } receive(msg: HiFromParent) { 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(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) { dump("😑 handling hi from child"); dump(msg.fromSeqno); } }