Motoko v0.11.0: Safety feature migration guide
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 oractor
class. - Within the body of a (non-
query
)shared
function, asynchronous function,async
expression orasync*
expression. - Within the body of a local (i.e. not
shared
) function or class that is declared withsystem
pseudo-type parameter. - Within the system functions
preupgrade
andpostupgrade
.
No other context provides system capabilities, including the bodies of query and composite query methods.