Skip to main content

Motoko v0.11.0: Safety feature migration guide

Motoko
Migration guide

Overview

Motoko v0.11.0 and newer introduces a new safety feature that could cause breaking changes to existing code.

In previous Motoko versions, third-party library functions could make calls to sensitive functions such as ExperimentalCycles.add(...) and Timer.setTimer(...) without providing any indication to the caller that sensitive system functionality was being used.

In Motoko 0.11.0 and newer, the type system is used to detect and prevent this scenario while still allowing developers to grant access to sensitive functions.

Motoko v0.11.0 changes

Motoko uses a simple capability-based type system which selectively enables language constructs depending on their context. One example is only async expressions can contain await expressions, or only some asynchronous contexts can call shared functions.

In Motoko v0.11.0 and newer, this capability system is expanded to restrict calls to functions including Timer.setTimer and ExperimentalCycles.add. To accomplish this, Motoko introduces and uses the pseudo-type parameter system and corresponding pseudo-type argument (also system) for both functions and classes.

Another change in v0.11.0 and newer is a revision of ExperimentalCycles.add, whose type has been changed from Nat -> () to <system>Nat -> (). This change reflects the additional system capability requirement using the type parameter <system>.

The system type parameter must be the first parameter of any function, class constructor or function type, e.g. <system, T, U> is valid but <T, system, U> is not.

Migrations for existing workflows

User-defined functions must now declare an explicit system pseudo-type parameter if they require system capabilities. If a caller wants to grant system capabilities to a callee, the caller must already have system capabilities either (implicitly) by virtue of the callsite's program context or (explicitly) because the callsite resides within a function or class that itself declares the new system type parameter.

For example, in previous Motoko versions the following could be used:

  func splitCycles() {
let amount = ExperimentalCycles.balance() / 2;
ExperimentalCycles.add(amount); // new error
};

This code will now throw a compiler error such as:

`system` capability required, but not available
(need an enclosing async expression or function body or explicit `system` type parameter)(M0197)

For Motoko v0.11.0 and newer, the previous code should be rewritten to include the system type parameter:

 func splitCycles<system>() {
let amount = ExperimentalCycles.balance() / 2;
ExperimentalCycles.add(amount); // warning
};

This code will include a warning to reflect that ExperimentalCycles.add is implicitly using system capability:

this function call implicitly requires `system` capability and may perform undesired actions (please review the call and provide a type instantiation `<system>` to suppress this warning)(M0195)

This warning can be silenced by adding the pseudo-type argument system at the call-site:

  func splitCycles<system>() {
let amount = ExperimentalCycles.balance() / 2;
ExperimentalCycles.add<system>(amount); // no warning or error
}

Developers whose code has proper capability related errors that prevent compilation will need to refactor their code to explicitly pass down the system capabilities using additional type parameters and arguments.

System capability syntax limitations

System capability is available within the following contexts:

  • Within the body of an actor expression or actor class.
  • Within the body of a (non- query) shared function, asynchronous function, async expression or async* expression.
  • Within the body of a local (i.e. not shared) function or class that is declared with system pseudo-type parameter.
  • Within the system functions preupgrade and postupgrade.

No other context provides system capabilities, including the bodies of query and composite query methods.