Mysten Incubation
Features

Actions

Declare one-shot on-chain effects (mint, create-singleton, seed-config) that run once after their dependencies are ready.

The action() plugin declares a one-shot on-chain effect — a mint, a singleton-object creation, a seed-config call — that runs after its declared upstream refs (typically a signer account plus one or more published packages) are ready. The result is an ActionReceipt carrying the real transaction digest and projected object changes.

Actions are role: 'task': the body runs once at acquire and reaches "done" after start resolves. They are not long-lived services.

devstack.config.ts
import { account, action, defineDevstack, localPackage, sui } from '@mysten-incubation/devstack';

const localnet = sui();
const alice = account('alice');
const connectFour = localPackage('connect-four', {
	sourcePath: './move/connect-four',
	publisher: alice,
});

const openLobby = action('connect-four.openLobby', {
	dependsOn: { signer: alice, pkg: connectFour },
	body: (ctx, { signer, pkg }) =>
		ctx.signAndExecute(signer, (tx) => {
			tx.moveCall({ target: `${pkg.packageId}::game::create_lobby` });
		}),
});

export default defineDevstack({
	members: [localnet, alice, connectFour, openLobby],
});

The body callback

action(name, opts) takes:

  • dependsOn — single ref, tuple, or object of plugin/refs. The resolved values arrive in the second argument of body in the same shape.
  • body: (ctx, deps) => Effect<ActionReceipt, ActionError> — the on-chain effect.
  • discriminator — optional caller-supplied material that influences the cache key (literal string or (ctx, deps) => Effect<string>).

ctx.signAndExecute(account, build) folds the full pipeline:

  1. Build the Transaction via the caller's build(tx) callback.
  2. Sign with the supplied account.
  3. Execute with {effects, objectTypes} includes.
  4. Wait for finality.
  5. Project the envelope into an ActionReceipt with digest + objectChanges.

The returned receipt's objectChanges array surfaces the SDK's changedObjects with kind: 'created' | 'mutated' and the fully-qualified objectType string when available.

Caching

Action results are cached by the substrate's artifact publisher under the action namespace. The cache key folds:

  • the chain id (so localnet and testnet cache independently);
  • a content hash of the action name and the resolved dependency resource ids;
  • a dynamic discriminator (literal or callback-supplied) when present.

This means re-running the same stack against the same chain reuses the recorded receipt unless the discriminator changes. Supplying a callback discriminator is how you force re-execution on mutable upstream state (e.g. a counter on a singleton object).

Failure surface

action(...) raises a single ActionError with a phase tag:

  • 'discriminator' — the dynamic discriminator failed.
  • 'build' — substrate dependency wiring failed before the body ran.
  • 'sign' — the body itself raised, or signing/submit transport failed (also covers a missing digest).
  • 'execute-failed' — the transaction was delivered and executed but the validator returned a FailedTransaction envelope.
  • 'verify' — substrate-side cache verify exhausted retries.

See Errors for the full catalog.

On this page