Skip to main content
Version: Next

Contracts

The contract type represents a smart contract. There is no way to create a literal value of this type; you must create a contract type by passing the address of the account to a predefined function. Beware of failures if the address is invalid.

For information about the components of a contract and how to use them, see Contracts.

Creating contract types in contracts

The call Tezos.implicit_account(kh) casts the public key hash kh of an implicit account to a contract type that represents that user account. Contract types that represent implicit accounts always have the type contract<unit> because they accept no parameter.

The call Tezos.get_contract(address) casts the address of a smart contract (originated account) to a contract type that represents that contract. The type is parameterized based on the parameter that the contract accepts. For example, if the contract accepts an integer, the type is contract<int>.

type returnType = [list<operation>, int];
type contractParam =
| ["Reset", unit]
| ["Decrement", int]
| ["Increment", int];
@entry
const callContract = (_: unit, storage: int): returnType => {
const contractAddress: address = ("KT1FpuaoBHwXMXJ6zn3F4ZhpjpPZV28MAinz" as address);
const myContract: contract<contractParam> = Tezos.get_contract(contractAddress);
const contractArg: contractParam = Increment(4);
const operation = Tezos.transaction(contractArg, 0tez, myContract);
return [list([operation]), storage + 1]
}

Creating contract types in tests

To create a contract type in a test, use the contract_of function, which accepts a namespace and returns a contract type. See Testing.

Implicit types and functions

When declaring the entry points of a contract using @entry, LIGO generates two hidden values in the module:

  • An implicit main function, which can be obtained using the keyword contract_of(C) where C is the namespace or module containing the entry points
  • The input type for that main function, which can be obtained using the keyword parameter_of(C)

In the example below, contract_of(C) returns the implicitly-declared main function that calls the increment or decrement entry points depending on the argument given, and parameter_of(C) is the variant ["Increment", int] | ["Decrement", int].

type storage = int;
type @return = [list<operation>, storage];
namespace C {
@entry
const decrement = (param: int, storage: storage) : @return =>
[[], storage - param];
@entry
const increment = (param: int, storage: storage) : @return =>
[[], storage + param];
@entry
const reset = (_unit: unit, _storage: storage) : @return =>
[[], 0];
}
import Test = Test.Next;
const test_initial_storage = () : unit => {
const init_storage = 42;
const fee = 0mutez;
const contract = Test.Originate.contract(contract_of(C), init_storage, fee);
// Call contract through entrypoints
Test.Contract.transfer_exn(Test.Typed_address.get_entrypoint("increment", contract.taddr), 15, 0tez);
Test.Contract.transfer_exn(Test.Typed_address.get_entrypoint("decrement", contract.taddr), 14, 0tez);
// Call contract through `main` function
const increment_param: parameter_of C = Increment(8);
const decrement_param: parameter_of C = Decrement(3);
Test.transfer_exn(contract.taddr, increment_param, 0mutez);
Test.transfer_exn(contract.taddr, decrement_param, 0mutez);
const new_storage = Test.Typed_address.get_storage(contract.taddr);
Assert.assert(new_storage == init_storage + 15 - 14 + 8 - 3);
}