Creating and Calling Contracts
When you pass a contract to techelson using techelson --contract <file> ...
, the contract becomes
a named contract in the techelson environment. The name of the contract is the name of the file
- up to its first
.
character, - with the first letter capitalized.
So
techelson \
--contract my_contract.tz \
--contract myContract.tz \
--contract my.contract.tz \
...
defines three named contracts: My_contract
, MyContract
and My
.
Note that the naming convention is the same for testcases, based on the testcase file. The name of a testcase might be used in techelson's output to provide information, but it has no practical use currently.
Named Contract Creation
Techelson extends the CREATE_CONTRACT
michelson instruction with the following rule
instruction | parameter | stack |
---|---|---|
CREATE_CONTRACT | <string> | :: key_hash : option key_hash : bool : bool : mutez : 'g : 'S |
-> operation : address : 'S |
where <string>
is the name of a contract with storage type 'g
in the environment. The semantics
of the stack parameters is the same as in michelson: manager, optional delegate, the two spendable
and delegatable flags, and the balance and storage of the contract created.
NB: techelson also provides the
SPAWN_CONTRACT
extension which takes the name of the contract on the stack. See techelson's Extensions for more details.
Say we have the following contract in file simpleExample.tz.
storage nat;
parameter bool;
code {
UNPAIR; # Unpair parameter and storage.
IF { # Asked not to count: storage is unchanged, nothing to do.
} {
PUSH nat 1;
ADD
};
NIL operation; # We don't want to perform any operations.
PAIR # Aggregate the operation list and the new storage.
};
We can craft a creation operation in file create1.techel as follows
{
PUSH @storage nat 0 ;
PUSH @amount mutez 3 ;
PUSH @delegatable bool True ;
PUSH @spendable bool True ;
NONE @delegate key_hash ;
PUSH key "manager address" ;
SHA512 @manager ;
PRINT_STACK ;
STEP "before creation" ;
CREATE_CONTRACT "SimpleExample" ;
PRINT_STACK ;
STEP "after creation" ;
}
This produces the following output
$ techelson --contract rsc/simpleExample/contracts/simpleExample.tz -- rsc/simpleExample/okay/create1.techel
Running test `Create1`
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| @storage |
| 0p |
| nat |
|--------------------------------------------------------------------------------------------------|
| @amount |
| 3utz |
| mutez |
|--------------------------------------------------------------------------------------------------|
| @delegatable |
| True |
| bool |
|--------------------------------------------------------------------------------------------------|
| @spendable |
| True |
| bool |
|--------------------------------------------------------------------------------------------------|
| @delegate |
| None |
| (option key_hash) |
|--------------------------------------------------------------------------------------------------|
| @manager |
| "sha512:manager address" |
| key_hash |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stopping [before creation] press `return` to continue
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| address[1] |
| address |
|--------------------------------------------------------------------------------------------------|
| CREATE[uid:0] (@address[1], "sha512:manager address", None, true, true, 3utz) "SimpleExample" |
| operation |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stopping [after creation] press `return` to continue
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
Done running test `Create1`
Applying Operations
Michelson operations (contract/account creation, transfers) cannot be applied directly in a michelson contract. Instead, a contract produces a list of operation which the tezos runtime applies after the contract is done running.
A techelson test case needs to be able to apply operations however, which is why the
APPLY_OPERATIONS
extension exists. This instruction suspends the execution of the testcase to
apply the list of operations on the top of the stack. When all these operations are done running,
techelson resumes the execution of the testcase.
Warning: this instruction is only legal in testcases, not in contracts.
Consider testcase create2.techel:
{
PUSH @storage nat 0 ;
PUSH @amount mutez 3 ;
PUSH @delegatable bool True ;
PUSH @spendable bool True ;
NONE @delegate key_hash ;
PUSH key "manager address" ;
SHA512 @manager ;
CREATE_CONTRACT @main @main_op "SimpleExample" ;
DIP { NIL operation } ;
CONS ;
PRINT_STACK ;
STEP "operation is now in a list" ;
APPLY_OPERATIONS ;
PRINT_STACK ;
STEP "testing that contract exists" ;
# Takes the address on the top of the stack, retrieves a contract of parameter `bool`.
CONTRACT bool ;
IF_NONE { # There is no hope, failing.
PUSH @err_msg string "failed to retrieve contract" ;
FAILWITH
} {
PUSH string "success" ;
PRINT_STACK
}
}
Running it yields
$ techelson --contract rsc/simpleExample/contracts/simpleExample.tz -- rsc/simpleExample/okay/create2.techel
Running test `Create2`
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| @main |
| address[1]@main |
| address |
|--------------------------------------------------------------------------------------------------|
| [ CREATE[uid:0] (@address[1]@main, "sha512:manager address", None, true, true, 3utz) "SimpleExample" ] |
| (list operation) |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stopping [operation is now in a list] press `return` to continue
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
applying operation CREATE[uid:0] (@address[1]@main, "sha512:manager address", None, true, true, 3utz) "SimpleExample"
timestamp: 1970-01-01 00:00:00 +00:00
live contracts: none
=> live contracts: SimpleExample (3utz) address[1]@main
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| @main |
| address[1]@main |
| address |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stopping [testing that contract exists] press `return` to continue
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
stack:
|==================================================================================================|
| address[1]@main |
| (contract bool) |
|--------------------------------------------------------------------------------------------------|
| "success" |
| string |
|==================================================================================================|
running test script...
timestamp: 1970-01-01 00:00:00 +00:00
Done running test `Create2`
Notice the line Applying operations...
. We could increase techelson's verbosity to obtain more
information as to which contracts are deployed, but let's see how to inspect the state of a live
(deployed) contract instead.