Transfers, contract calls

Transfer

The transfer instruction is used to transfer Tezis to an account.
1
effect {
2
transfer 1tz to coder;
3
}
Copied!
where coder is a role variable.

Calling a contract

It is possible to call a smart contract with the transfer instruction. Say for example you want to call the add_value entry point of the following contract:
1
archetype contract_called
2
3
variable v : nat = 0
4
5
entry add_value(x : nat) { v += x }
Copied!
The contract may then be called with the transfer ... to ... call ... instruction:
1
effect {
2
var c = @KT1RNB9PXsnp7KMkiMrWNMRzPjuefSWojBAm;
3
transfer 0tz to c call add_value<nat>(3);
4
}
Copied!
Note that it fails if the contract at address c does not provide an entry point annotated %add_value

Self

It is possible to call the current contract itself. Say the current contract has the my_add_value entry point; it is possible to call it from another entry point with the following instruction:
1
entry my_add_value(a : nat, b : nat) {
2
sum := a + b;
3
}
4
5
entry add_1_3 () {
6
transfer 0tz to entry self.my_add_value(1,3)
7
}
Copied!

Getter & contract

A common pattern for contracts to exchange values is to call an entry point with a callback.
This pattern is presented in the two-way-inter-contract invocation article below:
Enabling Smart Contract Interaction in Tezos with LIGO Functions and CPS
Medium
The archetype version of the sender contract (see article above):
1
archetype sender
2
3
variable bar : nat = 0
4
5
getter getBar () { return bar }
6
7
entry setBar (b : nat) { bar := b }
Copied!
It uses the getter keyword used to declare an entry point to the contract called "getBar"; the Michelson version of this entry actually takes a callback function (a setter) used to set/use the bar value in another contract. It is syntactic sugar equivalent to the following entry declaration:
1
entry getBar (cb : contract<nat>) { transfer 0tz to entry cb(bar) }
Copied!
The contract type is used to declare the callback type; it is parametrized by the signature of the callback, represented as the tuple of argument types.
The difference between the getter and entry versions of the getBar entry above is that the callback argument is anonymous in the getter version.
The archetype version of the inspector contract (see article above):
1
archetype inspector
2
3
variable foo : int = 0
4
5
entry setFoo(v : int) { foo := v }
6
7
entry getFoo(asender : address) {
8
transfer 0tz to asender call getBar<contract<int>>(self.setFoo)
9
}
Copied!

Entrypoint

The entrypoint function may be used to build a contract value from the name and the address. It returns an option value of contract type, so that it is possible to handle the case when the entry point does not exist.
The require_entrypoint function builds a contract and fails with error message if contract is invalid. The above inspector contract may be rewritten as:
1
archetype inspector
2
3
variable foo : int = 0
4
5
entry setFoo(v : int) { foo := v }
6
7
entry getFoo(asender : address) {
8
var e = require_entrypoint<int>("%getBar", asender, "invalid address");
9
transfer 0tz to entry e(self.setFoo))
10
}
Copied!

View

Since Hangzhou protocol, it is possible for a contract to read the storage of another contract by declaring a view in the contract to read data from, and by calling this view.
Use the view keyword to declare such a view; as for entry points, views may have arguments. Use the return keyword to return any value to the calling contract.
In the example below, the view returns the natural value stored in the storage, multiplied by 2:
1
archetype with_view
2
3
variable v : nat = 0
4
5
entry setValue(a : nat) { v := a }
6
7
view getValueMby2 () : nat {
8
return (2 * v)
9
}
Copied!
Use the callview operator to call a contract view; parameters are:
  • the expected return type between chevrons < ... >
  • the address of the contract to call
  • the parameter of the view (potentially a tuple)
The example below illustrates how to call the view getValueMby2 defined above:
1
archetype call_view(
2
with_view : address
3
)
4
5
variable v : nat = 0
6
7
entry getValue() {
8
match callview<nat>(with_view, "getValueMby2", Unit) with
9
| some(res) -> v := res
10
| none -> fail("FAILED_TO_CALL_VIEW")
11
end
12
}
13
Copied!
Note that callview returns an option of value that requires to be handled. It returns none when:
  • the contract at the specified address does not contain the view with the specified name
  • the view fails

Events

Archetype provides a seamless way to work with contract events. Please refer to these articles for a presentation.
Archetype defines events with the event keyword declaration. An event may possess several fields, like a record.
For example the following declares the HighestBidIncreased event with two fields bidder and amount:
1
event HighestBidIncreased { bidder : address; amount : tez }
Copied!
Event fields may be of any type except:
  • event
  • operation
  • big_map
  • asset
  • contract
  • ticket
  • sapling_state
Use emit instruction to emit an event:
1
entry bid() {
2
(* ... *)
3
if transferred > highestbid then begin
4
highestbid := transferred;
5
emit<HighestBidIncreased>({ source; transferred })
6
end
7
}
Copied!