Getters are special contract functions that allow users to query information from the contract.
Contract methods starting with the prefix get fun
are all getters. You can define as many getters are you want. Each getter must also specify its return type - counter()
for example returns an Int
.
Calling getters is free and does not cost gas. The call is executed by a full node and doesn't go through consensus with all the validators nor is added to a new block.
Getters are read-only, they cannot change the contract persistent state.
If we were to omit the get
keyword from the function declaration of a getter, it will stop being a getter. External users would no longer be able call this function and it would essentially become a private method of the contract.
A contract cannot execute a getter of another contract.
Getters are only executable by end-users off-chain. Since contracts are running on-chain, they do not have access to each other's getters.
So, if you can't call a getter, how can two contracts communicate?
The only way for contracts to communicate on-chain is by sending messages to each other. Messages are handled in receivers.
import "@stdlib/deploy"; message CounterValue { value: Int as uint32; } //////////////////////////////////////////////////////////////////////////// // this is our famous Counter contract, we've seen it before // this contract is very annoying, it only allows to increment +1 at a time! contract Counter with Deployable { val: Int as uint32; init() { self.val = 0; } // step 6: this contract allows anyone to ask it to increment by 1 (ie. the other contract) receive("increment") { self.val = self.val + 1; self.reply(CounterValue{value: self.val}.toCell()); } // step 3: this contract replies with its current value to anyone asking (ie. the other contract) receive("query") { self.reply(CounterValue{value: self.val}.toCell()); } get fun value(): Int { return self.val; } } message Reach { counter: Address; target: Int as uint32; } //////////////////////////////////////////////////////////////////////////// // let's write a second helper contract to make our lives a little easier // it will keep incrementing the previous contract as many times as we need! contract BulkAdder with Deployable { target: Int as uint32; init() { self.target = 0; } // step 1: users will send this message to tell us what target value we need to reach receive(msg: Reach) { self.target = msg.target; // step 2: this contract will query the current counter value from the other contract send(SendParameters{ to: msg.counter, value: 0, /// TODO: https://github.com/tact-lang/tact/issues/31 mode: SendRemainingValue + SendIgnoreErrors, /// TODO: issues/31 body: "query".asComment() }); } // step 4: the other contract will tell us what is its current value by sending us this message receive(msg: CounterValue) { if (msg.value < self.target) { // step 5: if its value is too low, send it another message to increment it by +1 more send(SendParameters{ to: sender(), value: 0, /// TODO: same issue 31 mode: SendRemainingValue + SendIgnoreErrors, /// TODO: https://github.com/tact-lang/tact/issues/31 body: "increment".asComment() }); } } }