Skip to main content

Starstream WIT worlds

Each Starstream contract is described by its own bespoke WIT world, importing builtins, Utxos, and so on used by the contract and exporting Utxos and coordination scripts defined in the contract.

The shape of those imports and exports are described here and define the interface between the Starstream runtime (host) and Starstream contract (guest).

Imports from other contracts use @external-id nodes containing the digest of the other contract in a form similar to "sha256:$HEXDIGEST", followed by : and extra data if needed.

Global builtins

package starstream:std;

/// Core builtins that the Starstream compiler depends on and that (almost) all
/// Starstream programs require.
interface builtin {
/// A generic handle to any Utxo.
resource utxo {
has-method: func(hash: tuple<u64, u64, u64, u64>) -> bool;
}

/// A generic handle to any Token.
resource token {}
}

Exporting Utxos

Contracts which export Utxos use types from starstream:std/utxo-context:

package starstream:std;

/// Builtins needed by contracts which declare Utxos.
interface utxo-context {
/// A context through which a Utxo can tell the runtime information about
/// its own execution status.
resource utxo-context {
/// The `resume;` statement calls this to indicate the Utxo is resuming.
/// This resets the `implements-method` list. If the Utxo then returns
/// without calling `implements-method` again, the Utxo is considered
/// consumed.
resume: func();

/// The `yield(...);` statement in a Utxo `main fn` calls this to mark
/// a method hash as implemented at the current yield point.
implements-method: func(hash: tuple<u64, u64, u64, u64>);
}
}

Each Utxo declared in the contract is represented as a distinct exported interface with an arbitrary name. An exported interface represents a Utxo if it declares resource utxo. Each Utxo also has a record storage describing its memory and get-storage (save) and set-storage (load) functions.

main fns are static methods on the resource utxo, and also receive an owned utxo-context supplied by the runtime.

For example:

world root {
import starstream:std/utxo-context;

export my-utxo: interface {
resource utxo {
my-main-fn: static func(ctx: own<utxo-context>) -> utxo;
}

record storage {
my-field: s32,
}

get-storage: func(self: borrow<utxo>) -> storage;
set-storage: func(storage: storage) -> utxo;
}
}

Importing Utxos

Contracts which import Utxos do so by importing interfaces from starstream:utxo with the Utxo's name containing a resource utxo. If needed, the import may also include downcast and upcast methods, which the runtime will provide.

For example:

world root {
import starstream:utxo/my-utxo;
}

package starstream:utxo {
@external-id("0123456789abcdef")
interface my-utxo {
use starstream:std/builtin.{utxo as builtin-utxo};

resource utxo {
my-main-fn: static func() -> utxo;
}

downcast: func(self: borrow<builtin-utxo>) -> option<utxo>;
upcast: func(self: borrow<utxo>) -> builtin-utxo;
}
}

A contract which defines a Utxo and also uses it in its own coordination script will both export and import the Utxo interface.

Using a Utxo from a coordination script in the same contract imports starstream:self/<utxo-name>.

Importing a Utxo from another contract imports starstream:utxo/<utxo-name> and supplies @external-id on the interface with that contract's digest.

Importing ABIs

ABIs can contain events, effects, and methods.

Importing events

To emit events, import and call starstream:events/<abi-name>#<event-name>. For example:

interface starstream:events/my-abi {
my-event: func(number: s32);
}

world root {
import starstream:events/my-abi;
}

Importing effects

To raise effects, import and call starstream:effects/<abi-name>#<event-name>. For example:

interface starstream:effects/my-abi {
my-effect: func(number: s32);
}

world root {
import starstream:effects/my-abi;
}

ABI methods

To call methods on a Utxo without knowing its concrete type, import the methods from starstream:contract/dynamic-utxo:

interface starstream:contract/dynamic-utxo {
use starstream:std/builtin.utxo;

my-method: func(this: borrow<utxo>, parameter: s32);
}

world root {
import starstream:contract/dynamic-utxo;
}

ABI casting

To test whether methods exist before calling them, call has-method on the starstream:std/builtin#utxo resource.

Exporting coordination scripts

Coordination scripts are top-level function exports:

world root {
export my-coordination-script: func();
}

Importing coordination scripts

Cross-contract coordination scripts are imported from an interface named starstream:contract/scripts with all coordination script functions needed. Each function has an @external-id with the digest of the contract it belongs to. For example:

interface starstream:contract/scripts {
@external-id("0123456789abcdef")
foobar: func() -> s32;
}
world root {
import starstream:contract/scripts;
}

Cardano support

Starstream contracts may explicitly import the cardano interface to access Cardano-specific information. Such contracts become limited to the Cardano chain. For example:

import { blockHeight } from starstream:std/cardano;

script fn myCoordinationScript() -> s64 {
runtime blockHeight()
}

The functions available are:

package starstream:std;

/// Cardano blockchain context functions.
interface cardano {
block-height: func() -> s64;
current-slot: func() -> s64;
}

Arbitrary WIT

Starstream contracts may import an arbitrary namespace:package/interface if the WIT is available at compile time. Such contracts must be linked with an implementation in some way before being passed to a standard Starstream runtime, which will not have an implementation of those imports.