Skip to main content

Interactions

An Interaction is the unit of state change in MOI — the equivalent of a transaction in a global-state network, but built around participants rather than a shared global tree.

This page covers the execution model behind Interactions, the structure of an Interaction payload, the full set of protocol-native operations, and the receipt the network produces once an Interaction executes.

Prerequisites: This guide assumes familiarity with MOI's core state primitives — specifically accounts, assets, and logics. If these concepts are new, start with the Accounts, Assets, and Logics documentation first.

Execution Models

An execution model defines how state changes are triggered, grouped, and executed. MOI's model is easiest to understand against the model it replaces.

Legacy Transactions (Application-Centric)

Networks with a single global state, such as Ethereum, treat a transaction as a generic trigger: an instruction to run a function in a shared smart contract. The protocol has no idea what that function actually does — minting, swapping, or nothing at all. All meaning lives in the application layer, which creates three structural problems:

  • Redundant boilerplate. Basic capabilities like issuing a token require deploying and auditing a contract (ERC-20 and friends) before any value can move.

  • A wider attack surface. Routine network operations are reimplemented as custom code, so a single flaw in a widely reused contract can compromise thousands of users.

  • Sequential bottlenecks. Any transaction can touch any part of global state, so the network must order transactions conservatively to avoid collisions. That rules out parallelism.

The root problem: legacy transactions push standard protocol mechanics into custom smart contracts, paying for it in security, scalability, and developer overhead.

MOI Interactions (Participant-Centric)

MOI anchors state to individual participants. An Interaction tells the protocol exactly whose state it touches and what it intends to do, which is enough context to execute the state transition inside an isolated, ephemeral cluster.

  • Protocol-Native Logic: creating an asset, transferring it, staking to a validator, are implemented inside the protocol as domain-specific operations (IxOps) and triggered directly through the SDKs. No boilerplate contract to deploy or audit.

  • Parallel Execution: Interactions explicitly declare the participant states they need to access. The network forms localized consensus clusters by locking only these specific states. Since interactions involving disjoint participants do not compete for the same state locks, they execute concurrently.

  • Cost-Efficient Batching: Users can pack multiple operations (IxOps) into a single interaction. Executing a batch of operations under a single localized state lock minimizes consensus overhead and consumes significantly less fuel than submitting each operation independently.

Example

Alice wants to deploy a new application logic and simultaneously transfer an existing digital asset to Bob.

  • Legacy model: Alice deploys the smart contract (transaction 1), waits for the network to confirm it, and then submits a separate token transfer (transaction 2). Two triggers, two full rounds of overhead, and a confirmation wait in between.

  • MOI: Alice submits one Interaction carrying two IxOps: LogicDeploy (to spin up the application) and AssetAction (to transfer the asset). The protocol executes both natively in a single batch. One round of overhead, two state transitions.

Anatomy of an Interaction

ParameterTypeRequiredDescription
senderSenderYesThe entity initiating and authorizing the Interaction.
ix_operationsArray<IxOperation>YesThe protocol-native operations to execute.
participantsArray<Participant>YesThe accounts whose state the runtime is allowed to see. Anything not listed here is invisible to execution.
fuel_priceHEXYesKMOI the sender will pay per unit of execution fuel.
fuel_limitHEXYesCeiling on the fuel this Interaction may consume. Must be non-zero.
payerHEX (32 bytes)NoA different participant who covers the fuel cost, enabling sponsored Interactions. Defaults to the sender.
preferencesIxPreferencesNoOverrides the default compute and consensus configuration for this Interaction.
perceptionBytesNoEncodes the perceived value of assets at execution time (for example, 1 KMOI = 1 USD).

Sender

Identifies who initiated the Interaction and ensures ordered execution to prevent replay attacks.

FieldTypeDescription
idHEX (32 bytes)Unique identifier of the sender account
sequence_idNumberA strictly incrementing nonce. The protocol rejects any sequenceID it has already processed, preventing replays.
key_idNumberIndex of the sender's public key used to sign the payload.
info

There is an optional field, payer which allows other participants to sponser the Interaction, by paying the Interaction cost for the sender.

Execution Fuel

Every Interaction pays for the compute it consumes, in KMOI.

  • fuel_price is the rate the sender offers per unit of fuel. It must meet or exceed the network's minimum (1 on Public Devnet).
  • fuel_limit caps total consumption, which is what stops a runaway loop from draining an account.
  • The account charged is the payer if one is declared, and the sender otherwise.

Fuel is charged for work performed, so a failed Interaction still costs KMOI. How much depends on how it failed — see Operation Status Codes.

Participants and State Isolation

This is the critical distinction in MOI. On a global-state network, a transaction can read anyone's state. MOI does not allow this. The runtime executes in a strict sandbox: an account's state cannot be read or modified unless that account is declared in participants.

The sender is included implicitly. Which additional participants are required depends on the operation - an AssetAction transfer needs the beneficiary and the asset account, a LogicInvoke needs the logic account, and so on. Each operation section below shows a worked example.

Participant

FieldTypeDescription
idHEX (32 bytes)Unique identifier of the participant.
lock_typeLockTypeThe access the runtime is granted over this participant's state.
notaryBooleanWhether this participant's signature is required to finalize the Interaction.

LockType

ValueNameDescription
0MutateLockState may change — deducting funds, updating stored data.
1ReadLockState is visible to the runtime but cannot be altered.
2NoLockNo lock is taken. The account is referenced but its state is unaffected.

Network Preferences

preferences is optional. When present, it lets the initiator dictate how the ephemeral cluster should process and validate the state transition.

IxPreferences

FieldTypeDescription
computeBytesEncoded parameters defining the execution environment requirements.
consensusIxConsensusPreferenceLocalized trust and validation thresholds for the cluster.

IxConsensusPreference

FieldTypeDescription
TrustNodesArray<KramaID>Node identities the initiator explicitly trusts to participate in consensus.
MTQuintModulated Trust Quotient — how many nodes beyond TrustNodes must also participate before the Interaction finalizes.

Operation Reference

Each IxOperation carries a type identifier and a matching payload. MOI groups its protocol-native operations into five categories.

TypeNameCategoryPurposeStatus
1ParticipantCreateAccountRegisters a new participant identity and assigns its signing keys.Active
2AccountConfigureAccountAdds or revokes keys on an existing account.Active
3AccountInheritAccountCreates an application-specific sub-account of a primary account.Active
4AssetCreateAssetMints a new native digital asset.Active
5AssetActionAssetInvokes a routine on an existing asset -- transfer, mint, burn, custom.Active
6GuardianRegisterGuardianRegisters a node as a network validator and locks its initial stake.Not yet active
7GuardianStakeGuardianAdds stake to a registered guardian.Not yet active
8GuardianUnstakeGuardianBegins the unbonding process for staked tokens.Not yet active
9GuardianWithdrawGuardianReleases tokens once the unbonding period has elapsed.Not yet active
10GuardianClaimGuardianClaims accumulated validator rewards.Not yet active
11LogicDeployLogicDeploys new application logic to the network.Active
12LogicInvokeLogicExecutes a routine on a deployed logic account.Active
13LogicEnlistLogicSubscribes an account to a deployed logic.Reserved
16LogicInteractLogicCross-logic interaction.Reserved
17LogicUpgradeLogicUpgrading deployed logic instances.Reserved
14StorageDepositStorageConverts KMOI into a prepaid storage allowance.Active
15StorageWithdrawStorageReclaims unused storage allowance as KMOI.Active
18AccessCreateAccessWrites a new Access Policy onto the sender's account.Active
19AccessUpdateAccessReplaces an existing Access Policy.Active
20AccessDeleteAccessRemoves an Access Policy.Active

Operations for native fuel management, governance, and voting are planned for future rollouts.


ParticipantCreate

Creates a new participant account on the network. In a single atomic step, this operation adds the new account to the network's registry of accounts (Sarga account), binds its initial signing keys, and transfers a starting KMOI balance from the sender, ensuring the participant is fully operational the moment the Interaction executes.

note

The sender must hold enough KMOI to cover both the execution fuel and the initial funding transfer. If it cannot cover both, the entire Interaction fails.

ParticipantCreateOperation

ParameterTypeDescription
typeNumberSet to 1.
payloadPayloadConfiguration for the new account.
resultResultThe data returned upon execution in the receipt.

ParticipantCreatePayload

ParameterTypeDescription
idHEX (32 bytes)Globally unique identifier for the new participant.
keys_payloadArray<KeyAddPayload>Initial public keys granting signing authority. Weights must total ≥ 1000.
valueAssetActionPayloadThe KMOI transfer that funds the new account.

ParticipantCreateResult

FieldTypeDescription
account_idHEX (32 Bytes)Identifier of the newly registered account.
errorHEXSerialised error data if execution failed.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 0,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 1,
"payload": {
"id": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"keys_payload": [
{
"public_key": "0x00000000513b40a069905a1b05bd28d8338ad4a2eff419d7972be75900000000",
"weight": 1000,
"signature_algorithm": 0
}
],
"value": {
"asset_id": "0x108000004cd973c4eb83cdb8870c0de209736270491b7acc99873da100000000",
"callsite": "Transfer",
"calldata": "0x0d6f06659601c502616d6f756e7403138862656e65666963696172790600000000513b40a069905a1b05bd28d8338ad4a2eff419d7972be75900000000"
}
}
}
],
"participants": [
{
"id": "0x108000004cd973c4eb83cdb8870c0de209736270491b7acc99873da100000000",
"lock_type": 2
}
]
}

AccountConfigure

Updates the collection of signing keys for an existing participant account - appending new public keys, or revoking compromised and obsolete ones.

This keeps an identity secure without migrating its assets to a new account.

note

A single AccountConfigure operation performs either an add or a revoke, never both. Leave the unused array empty.

AccountConfigureOperation

ParameterTypeDescription
typeNumberSet to 2.
payloadPayloadThe keys to add or revoke.

AccountConfigurePayload

ParameterTypeDescription
addArray<KeyAddPayload>New public keys to append to the authorized signers.
revokeArray<KeyRevokePayload>Existing key indices to revoke immediately.

KeyAddPayload

ParameterTypeDescription
public_keyBytesRaw byte representation of the public key.
weightNumberAuthority weight assigned to this key, used in multisig threshold calculations (0–1000).
signature_algorithmNumberIdentifier for the signature scheme the key uses (ECDSA, BLS, Schnorr).

KeyRevokePayload

ParameterTypeDescription
key_idNumberIndex of the key to revoke in the account's key list.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 1,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 2,
"payload": {
"add": [
{
"public_key": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"weight": 1000,
"signature_algorithm": 0
}
],
"revoke": []
}
}
],
"participants": []
}

AccountInherit

Creates a dedicated sub-account linked to a primary participant. This sub-account inherits the execution context of a specific target application while retaining the signing credentials of the primary account.

Instead of forcing a user's primary account to carry the data of every application they interact with, MOI provisions a separate sub-account for each application to keep state localized and manageable.

info

Inherited accounts are covered in detail in a dedicated document, coming soon.

AccountInheritOperation

ParameterTypeDescription
typeNumberSet to 3.
payloadPayloadTarget account and funding for the sub-account.
resultResultThe data returned upon execution in the receipt.

AccountInheritPayload

ParameterTypeDescription
target_accountHEX (32 bytes)The account whose execution context the sub-account inherits.
valueAssetActionPayloadThe KMOI transfer that funds the new sub-account.
sub_account_indexNumberThe sub-account's index in the primary account's sub-account list.

AccountInheritResult

FieldTypeDescription
sub_accountHEX (32 Bytes)Identifier of the newly created sub-account.
errorHEXSerialised error data if execution failed
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 2,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 3,
"payload": {
"target_account": "0x20800000a6ba9853f131679d00da0f033516a2efe9cd53c3d54e1f9a00000000",
"value": {
"asset_id": "0x108000004cd973c4eb83cdb8870c0de209736270491b7acc99873da100000000",
"callsite": "Transfer",
"calldata": "0x0d6f06659601c502616d6f756e7403138862656e65666963696172790600000000513b40a069905a1b05bd28d8338ad4a2eff419d7972be75900000000"
},
"sub_account_index": 0
}
}
],
"participants": [
{
"id": "0x108000004cd973c4eb83cdb8870c0de209736270491b7acc99873da100000000",
"lock_type": 2
}
]
}

AssetCreate

Deploys a new digital asset natively on the network. The operation creates a dedicated asset account, deploys the asset's execution logic, registers the asset to the creator's account, and credits the initial supply to their balance.

AssetCreateOperation

ParameterTypeDescription
typeNumberSet to 4.
payloadPayloadConfiguration, logic, and metadata for the asset.
resultResultThe data returned upon execution in the receipt.

AssetCreatePayload

ParameterTypeDescription
symbolStringIdentifying symbol for the asset, e.g. KOI.
max_supplyBigIntMaximum supply the asset can ever reach.
standardAssetStandardThe standard to follow: MAS0, MAS1, or MASX. MASX requires logic.
dimensionUint8Type classification of the asset, e.g. fungible or non-fungible behavior.
decimalsUint8Decimal precision, e.g. 18 for a typical fungible token.
enable_eventsBooleanIf true, the asset emits events on state changes such as transfers and mints.
managerStringThe participant authorized to manage supply and dynamic metadata.
logicLogicDeployPayloadRequired for MASX. The compiled manifest and initialization data.
metadataMapInitial static and dynamic metadata.

AssetCreateResult

FieldTypeDescription
asset_idHEX (32 Bytes)Identifier of the newly created asset.
errorHEXSerialised error data if execution failed
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 4,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 4,
"payload": {
"symbol": "KOI",
"max_supply": 20000,
"standard": 0,
"dimension": 0,
"enable_events": true,
"manager": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000"
}
}
],
"participants": []
}

AssetAction

Executes a routine defined in an asset's compiled logic - standard transfers, mints, and burns, as well as any custom state transition the asset defines.

AssetActionOperation

ParameterTypeDescription
typeNumberSet to 5.
payloadPayloadThe routine to invoke and its arguments.
resultResultThe data returned upon execution in the receipt.

AssetActionPayload

ParameterTypeDescription
asset_idHEX (32 bytes)Identifier of the target asset.
callsiteStringMethod to invoke - Transfer, Mint, or a custom routine such as IssueBadge.
calldataHEXPOLO-encoded arguments for the method.
fundsMapOptional. Asset IDs mapped to amounts, when the call needs to carry value with it.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 7,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 5,
"payload": {
"asset_id": "0x10030000d9f12d13c0347a737430cdbcca174164f0823ccc39bedbe800000000",
"callsite": "Transfer",
"calldata": "0x0d6f06659601c502616d6f756e7403138862656e65666963696172790600000000ed434a2ab138e69295e134686d57d80a9aa3325dbbde9bbf00000000"
}
}
],
"participants": [
{
"id": "0x00000000ed434a2ab138e69295e134686d57d80a9aa3325dbbde9bbf00000000",
"lock_type": 0
},
{
"id": "0x10030000d9f12d13c0347a737430cdbcca174164f0823ccc39bedbe800000000",
"lock_type": 2
}
]
}

GuardianRegister

Guardians are the nodes that participate in consensus and secure the network. This operation onboards one: it adds the node to the validator registry and locks an initial stake.

Registration binds three things together - the node's krama_id (its network identity), the participant account that owns it, and the consensus key it signs consensus messages with. The staked KMOI is locked from the sender's balance rather than spent: it still belongs to the owner, but cannot move while the guardian is registered.

GuardianRegisterOperation

ParameterTypeDescription
typeNumberSet to 6.
payloadPayloadNode identity, credentials, and initial stake.

GuardianRegisterPayload

ParameterTypeDescription
krama_idStringNetwork identity of the guardian node being registered.
wallet_idHEX (32 bytes)The account that owns the guardian and receives its stake and rewards.
consensus_keyBytesPublic key the node uses to sign consensus messages.
kyc_proofBytesCompliance proof submitted for the guardian.
amountHEXInitial KMOI to lock as stake. Must be greater than zero.

GuardianStake

Increases the stake backing an already-registered guardian. The KMOI is locked from the sender's balance and recorded as a pending addition.

Stake does not take effect immediately. Pending additions are promoted to active stake at an epoch boundary. A guardian's active stake is what determines whether it is eligible for consensus and how much influence it carries.

ParameterTypeDescription
typeNumberSet to 7.
payloadPayloadTarget guardian and amount to stake.

GuardianUnstake

Begins stake removal. The requested amount is marked pending, and at the next epoch boundary it shifts from active to inactive stake - but stays locked. This waiting period is what keeps a guardian accountable for the period it was active, rather than letting a misbehaving node exit with its funds instantly.

ParameterTypeDescription
typeNumberSet to 8.
payloadPayloadTarget guardian and amount to unstake.

GuardianWithdraw

Completes the exit. Once the waiting period has elapsed and the tokens are marked inactive, this operation releases the lock and credits the KMOI back to the sender's spendable balance.

Only inactive tokens can be withdrawn. If the stake is still active or still pending, the withdrawal fails.

ParameterTypeDescription
typeNumberSet to 9.
payloadPayloadTarget guardian and amount to withdraw.

GuardianClaim

Transfers accrued consensus rewards into the owner's spendable KMOI balance. Rewards are held separately from stake, so claiming them has no effect on the guardian's staked position or its participation in consensus.

ParameterTypeDescription
typeNumberSet to 10.
payloadPayloadTarget guardian and reward amount to claim.

GuardianActionPayload

Shared by GuardianStake, GuardianUnstake, GuardianWithdraw, and GuardianClaim.

ParameterTypeDescription
krama_idKramaIDIdentity of the guardian the action applies to.
amountHEXKMOI amount for the action. Must be greater than zero.

Guardian examples will be provided in a future update.


LogicDeploy

Deploys a new logic instance. The operation verifies and compiles the logic manifest, registers a new logic account, and optionally runs an initialization routine to establish starting state.

note

If a callsite is provided, the runtime invokes it immediately after deployment - the equivalent of a constructor.

LogicDeployOperation

ParameterTypeDescription
typeNumberSet to 11.
payloadPayloadManifest and initialization data.
resultResultThe data returned upon execution in the receipt.

LogicDeployPayload

ParameterTypeDescription
manifestBytesSerialized representation of the logic manifest.
callsiteStringInitialization routine to invoke after successful deployment.
calldataHEXPOLO-encoded arguments for that routine.

LogicDeployResult

FieldTypeDescription
logic_idHEX (32 bytes)Identifier of the deployed logic. Omitted if deployment failed.
errorHEXSerialized error data if deployment or callsite execution failed.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 8,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 11,
"payload": {
"manifest": "0x0e6f031ef601ce02...",
"callsite": "Seed",
"calldata": "0x0def0106458601e501f605d506a60785..."
}
}
],
"participants": []
}

LogicInvoke

Executes a routine within a deployed logic instance. This is the primary way participants interact with logic modules.

LogicInvokeOperation

ParameterTypeDescription
typeNumberSet to 12.
payloadPayloadTarget logic and execution context.
resultResultThe data returned upon execution in the receipt.

LogicInvokePayload

ParameterTypeDescription
logic_idHEX (32 bytes)Identifier of the logic instance being invoked.
callsiteStringFunction to execute within the logic module.
calldataHEXPOLO-encoded arguments for the callsite.

LogicInvokeResult

FieldTypeDescription
outputsHEXPOLO-encoded return values. Empty if the callsite returns nothing.
errorHEXSerialized error data if execution failed.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 9,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 12,
"payload": {
"logic_id": "0x0800008d898ef91ebd8a208855d6d1c98939202cfcb6a067530845993fe6975de1eb84",
"callsite": "BalanceOf",
"calldata": "0x0d2f0645616464720652fdfc072182654f163f5f0f9a621d729566c74d10037c4d7bbb0407d1e2c649"
}
}
],
"participants": [
{
"id": "0x0800008d898ef91ebd8a208855d6d1c98939202cfcb6a067530845993fe6975de1eb84",
"lock_type": 1
}
]
}

LogicEnlist

Subscribes a participant to a deployed logic module. Under the hood it allocates a dedicated logic storage tree inside the invoker's account state and runs a setup routine defined by the target logic. An account must enlist before it can store data tied to that logic.

info

This operation is currently Reserved by the protocol. The details below represent its conceptual design and are subject to change before activation.

LogicEnlistOperation

ParameterTypeDescription
typeNumberSet to 13.
payloadPayloadTarget logic and enlistment parameters.

LogicEnlistPayload

ParameterTypeDescription
logic_idHEX (32 bytes)Identifier of the deployed logic to enlist with.
callsiteStringRegistration routine defined in the logic.
calldataHEXPOLO-encoded arguments passed to the enlistment routine.

StorageDeposit

When a participant invokes a logic, any state that logic writes on their behalf occupies storage on the network, and storage has to be paid for. This operation converts KMOI into a storage allowance - a prepaid quota of bytes, reserved on a target account and attributed to a specific participant.

The amount is converted at the network's storage_price_per_byte rate. Allowances are granted in whole bytes, so any remainder too small to buy a full byte is refunded to the sender immediately.

StorageDepositOperation

ParameterTypeDescription
typeNumberSet to 14.
payloadPayloadTarget account, beneficiary, and amount.

StorageDepositPayload

ParameterTypeDescription
target_accountHEX (32 bytes)The logic or asset account the allowance is reserved on.
deposit_forHEX (32 bytes)The participant the allowance is credited to.
amountNumberKMOI to convert into storage.
note

deposit_for does not have to be the sender. This lets an application sponsor storage for its users, so they can interact with a logic without holding an allowance of their own.

{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 1,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 14,
"payload": {
"target_account": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"deposit_for": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"amount": 1000
}
}
],
"participants": [
{
"id": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"lock_type": 0
},
{
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"lock_type": 0
}
]
}

StorageWithdraw

The inverse of StorageDeposit. It releases bytes from a participant's allowance on a target account and returns the corresponding KMOI to the sender.

Only unused bytes can be reclaimed. An allowance is made up of bytes currently holding state and bytes still free; the operation fails if the requested amount exceeds what is free. Deleting state on the target account frees bytes back into the allowance, making them withdrawable.

note

Setting bytes_to_release to 0 withdraws the entire unused allowance. Once an allowance is fully drained, its record on the target account is cleared.

StorageWithdrawOperation

ParameterTypeDescription
typeNumberSet to 15.
payloadPayloadTarget account and bytes to reclaim.

StorageWithdrawPayload

ParameterTypeDescription
target_accountHEX (32 bytes)The logic or asset account holding the allowance.
bytes_to_releaseNumberUnused bytes to reclaim. Set to 0 to withdraw the full unused allowance.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 1,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 15,
"payload": {
"target_account": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"bytes_to_release": 2000
}
}
],
"participants": [
{
"id": "0x000000004678e9f5bf2f66362ef5367fbc72efe7b419a5e7d851f57b00000000",
"lock_type": 0
},
{
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"lock_type": 0
}
]
}

AccessCreate

Writes a new Access Policy onto the sender's account, granting other accounts and logics a constrained path into state the sender owns.

The operation fails if a policy already exists for the same policy key — the pair (resource_type, resource_id). Use AccessUpdate to replace one.

AccessCreateOperation

ParameterTypeDescription
typeNumberSet to 18.
payloadPayloadThe account to write the policy to, and the policy.

AccessPayload

ParameterTypeDescription
target_accountHEX (32 bytes)The account the policy is written to. Must be the sender.
access_policyAccessPolicyThe policy record.

AccessPolicy

ParameterTypeDescription
resource_typeStringThe class of resource governed. Only "storage" is currently accepted.
resource_idHEX (32 bytes)The specific resource. For storage, the Logic ID of the logic that performs the write.
action_typeArray of StringPermitted actions. Currently ["storage_mutate"]. Must be non-empty.
caller_constraintCallerConstraintConstrains the immediate caller of the storing logic.
origin_constraintCallerConstraintConstrains the interaction sender.

The record also carries a scope field, which would narrow a policy to part of a resource. It is reserved: leave it empty, which means the whole resource. It is not yet enforced and is not returned by the read RPCs.

CallerConstraint

The same type is used for both caller_constraint and origin_constraint, despite the name.

ParameterTypeDescription
kindNumber0 — any identifier matches. 1 — only identifiers in set match.
setArray of HEXThe admitted identifiers. Required and non-empty when kind is 1; null when kind is 0.
{
"sender": {
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"sequence": 12,
"key_id": 0
},
"fuel_price": 1,
"fuel_limit": 10000,
"ix_operations": [
{
"type": 18,
"payload": {
"target_account": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"access_policy": {
"resource_type": "storage",
"resource_id": "0x20000000ff572431a4f52ad972f54fee061847c682eb22ffa51c97a900000000",
"action_type": ["storage_mutate"],
"caller_constraint": {
"kind": 1,
"set": [
"0x20000000784cf54a25a23390e71563a37d7d2c0d203746876e04992b00000000"
]
},
"origin_constraint": { "kind": 0, "set": null }
}
}
}
],
"participants": [
{
"id": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"lock_type": 0
}
]
}

AccessUpdate

Replaces an existing Access Policy. The policy key (resource_type, resource_id) identifies which policy is replaced; every other field is overwritten wholesale, not merged.

The operation fails if no policy exists for that key.

AccessUpdateOperation

ParameterTypeDescription
typeNumberSet to 19.
payloadPayloadThe account holding the policy, and the new policy.

The payload and the surrounding Ix object are identical in shape to AccessCreate; only type differs. Widening a constraint set charges additional storage bytes, and narrowing one credits bytes back.

{
"payload": {
"target_account": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"access_policy": {
"resource_type": "storage",
"resource_id": "0x20000000ff572431a4f52ad972f54fee061847c682eb22ffa51c97a900000000",
"action_type": ["storage_mutate"],
"caller_constraint": {
"kind": 1,
"set": [
"0x20000000784cf54a25a23390e71563a37d7d2c0d203746876e04992b00000000"
]
},
"origin_constraint": {
"kind": 1,
"set": [
"0x00000000ed434a2ab138e69295e134686d57d80a9aa3325dbbde9bbf00000000"
]
}
}
}
}

This narrows the policy above from any origin to a single origin.


AccessDelete

Removes an Access Policy. The resource returns to being reachable only by its owner. Deletion is complete rather than a tombstone, so the same key may be created again afterwards with AccessCreate.

The operation fails if no policy exists for the given key.

AccessDeleteOperation

ParameterTypeDescription
typeNumberSet to 20.
payloadPayloadIdentifies the policy to remove.

AccessDeletePayload

ParameterTypeDescription
target_accountHEX (32 bytes)The account holding the policy. Must be the sender.
resource_typeStringThe resource class of the policy being removed.
resource_idHEX (32 bytes)The resource ID of the policy being removed.
{
"payload": {
"target_account": "0x000000001ec28dabfc3e4ac4dfc2084b45785b5e9cf1287b63a4f46900000000",
"resource_type": "storage",
"resource_id": "0x20000000ff572431a4f52ad972f54fee061847c682eb22ffa51c97a900000000"
}
}

Interaction Receipt

Once an Interaction is included in a Tesseract and executed, the network records a receipt - the authoritative account of what happened: whether it succeeded, how much fuel it burned, and what each operation produced. Fetch it by interaction hash with the moi.InteractionReceipt API.

Only execution produces a receipt. An Interaction rejected during validation never enters a Tesseract, so it has none.

Receipt Structure

FieldTypeDescription
ix_hashHEX (32 bytes)Hash of the Interaction this receipt belongs to.
statusReceiptStatusOverall outcome.
fuel_usedHEXFuel actually charged.
ix_operationsArray<IxOpResult>One result per operation, in submission order.
fromHEX (32 bytes)The sender.
ix_indexHEXPosition of the Interaction within its Tesseract.
ts_hashHEX (32 bytes)Hash of the Tesseract that included it.
participantsArray<ParticipantState>State of each participant account after execution.

Receipt Status Codes

ValueNameDescription
0ReceiptOkAll operations succeeded and their state changes were applied.
1ReceiptStateRevertedExecution failed and no state changes were applied.
2ReceiptInsufficientFuelThe Interaction ran out of fuel mid-execution.
note

An Interaction is all-or-nothing. Execution stops at the first operation that fails, and every state change it made - including changes from operations that had already succeeded - is discarded. Fuel is still charged, because the work was performed.

Operation Result

Each operation produces a result at the index it was submitted at.

FieldTypeDescription
ix_typeHEXThe operation type that produced this result.
statusIxOpStatusOutcome of this specific operation.
dataJSONOperation-specific output, e.g. AccountCreationResult.

If execution halted early, only the operations that actually ran appear in ix_operations. An array shorter than the Interaction's operation list is itself a signal of where the failure occurred.

Operation Status Codes

ValueNameDescription
0ResultOkThe operation completed successfully.
1ResultExceptionRaisedThe operation failed a check - insufficient balance, invalid target, failed validation.
2ResultDefectRaisedThe operation failed irrecoverably during logic execution.

The two failure modes differ in cost. An exception charges only the fuel consumed up to the point of failure. A defect charges the Interaction's entire fuel_limit.

Participant State

One entry per account touched by the Interaction, as of after execution.

FieldTypeDescription
idHEX (32 bytes)Identifier of the participant account.
heightHEXThe account's state height after the Interaction.
state_hashHEX (32 bytes)Hash of the account's state.
transitive_linkHEX (32 bytes)Hash of the latest tesseract that mutated the account state.
locked_contextHEX (32 bytes)The context the account was locked under during execution.
context_deltaJSONChanges made to the account's context.

Validation Constraints

These are checked before an Interaction is accepted. Failing any of them means rejection at submission: no receipt is produced and no fuel is charged.

Interaction-level

ConstraintRequirement
AssetCreate per InteractionAt most 1
LogicDeploy per InteractionAt most 1
Interaction sizeAt most 128 KB
FuelBoth fuel_price and a non-zero fuel_limit must be specified
Fuel priceAt least the network's minimum (1 on Public Devnet)
SenderMust not be nil
SequenceAt least the sender's next expected sequence
Sender balanceMust cover the Interaction's total cost
ParticipantsAll non-genesis participants must be registered on the network
SignaturesMust be valid and include one from the sender's own key
Combined signature weightAt least 1000
Key weight (ParticipantCreate)Each registered key must weigh at most 1000

Access operations

ConstraintRequirement
target_accountMust equal the sender
resource_typeMust be "storage"; asset, logic, and key are defined but rejected
resource_idMust not be null
action_typeMust be non-empty
Constraint setsA constraint with kind: 1 must carry a non-empty set

Packages & SDKs

  • JS MOI SDK - JavaScript/TypeScript library for the MOI Protocol: submit Interactions, deploy and invoke logics, manage participants and assets.
  • JS POLO - JavaScript/TypeScript implementation of the POLO serialization scheme.
  • GO POLO - Go implementation of POLO.
  • Cocolang - Language and toolchain for writing, compiling, and testing Coco modules (logics).