Logic


The logic module in js-moi-sdk is a powerful component that simplifies the interaction with MOI logic objects. It provides a user-friendly interface for deploying, interacting with, and querying logic objects on the MOI network.

With the logic module, the logic manifests can be easily deployed using logic factory. This includes the ability to encode and deploy logics with builder arguments.

Once deployed, the module handles routine calls, interaction sending, and state queries, abstracting away complexities like parameter encoding, fuel and interaction signing.

Integration with the wallet and signer modules ensures secure interaction signing and authorization. Users can choose from different signers, such as wallet-based signers, or custom signers.

Types

LogicIxRequest

The LogicIxRequest interface represents a request to deploy or execute a logic. It has the following properties:

  • call - function: A function that facilitates the execution of an logic interaction request, while maintaining the integrity of the current state. It returns a promise that resolves to an InteractionCallResponse.

  • send - function: A function that sends the logic interaction request and returns a promise that resolves to an InteractionResponse.

  • estimateFuel - function: A function that estimates the fuel required for the interaction request and returns a promise.

Routine

The Routine interface represents a routine function. It has the following properties:

  • A function that can be called with an optional array of arguments and returns a value.

  • isMutable - function: A function that returns a boolean indicating whether the routine is mutable.

  • accepts - function: A function that returns an array of TypeField representing the types of arguments accepted by the routine, or null if no arguments are accepted.

  • returns - function: A function that returns an array of TypeField representing the types of values returned by the routine, or null if no values are returned.

Routines

The Routines interface represents a collection of routines. It is an object with named properties where the property name is the routine name and the property value is a Routine.

CallSite

The CallSite interface represents a callsite. It has the following properties:

  • ptr - number: The pointer to the callsite.

  • kind - string: The kind of the callsite.

MethodDef

The MethodDef interface represents a method definition. It has the following properties:

  • ptr - number: The pointer to the method.

  • class - string: The name of the class.

Element Descriptor

The ElementDescriptor class represents a descriptor for elements in the logic manifest.

getStateMatrix()

Retrieves the state matrix associated with the ElementDescriptor.

Returns:

ContextStateMatrix – The state matrix.

getElements()

Retrieves the map of elements associated with the ElementDescriptor.

Returns:

Map.<number, LogicManifest.Element> – The elements map.

getCallsites()

Retrieves the map of call sites associated with the ElementDescriptor.

Returns:

Map.<string, CallSite> – The call sites map.

getClassDefs()

Retrieves the map of class definitions associated with the ElementDescriptor.

Returns:

Map.<string, number> – The class definitions map.

getMethodDefs()

Retrieves the map of method definitions associated with the ElementDescriptor.

Returns:

Map.<string, MethodDef> – The method definitions map.

getClassMethods(className)

Retrieves the methods of a class based on the given class name.

Arguments:
  • className (string) – The name of the class.

Throws:

Error – if the class name is invalid.

Returns:

Map.<string, LogicManifest.Method> – The methods of the class.

getRoutineElement(routineName)

Retrieves the element from the logic manifest based on the given routine name.

Arguments:
  • routineName (string) – The name of the routine.

Throws:

Error – if the routine name is invalid.

Returns:

LogicManifest.Element – The routine element.

getClassElement(className)

Retrieves the element from the logic manifest based on the given class name.

Throws:

Error – if the class name is invalid.

Returns:

LogicManifest.Element – The class element.

getMethodElement(methodName)

Retrieves the element from the logic manifest based on the given method name.

Arguments:
  • methodName (string) – The name of the method.

Throws:

Error – if the method name is invalid.

Returns:

LogicManifest.Element – The method element.

Logic Base

The LogicBase is a abstract class extends the ElementDescriptor class and serves as a base class for logic-related operations. It defines common properties and abstract methods that subclasses should implement.

LogicBase.connect(arg)

Updates the signer and provider instances for the LogicBase instance.

Arguments:
  • arg (Signer|AbstractProvider) – The signer or provider instance.

Logic Descriptor

The LogicDescriptor is a abstract class extends the LogicBase class and provides information about a logic.

Methods

LogicDescriptor.getLogicId()

Returns the logic id of the logic.

Returns:

string – The logic id.

LogicDescriptor.getEngine()

Returns the logic execution engine type.

Returns:

EngineKind – The engine type.

LogicDescriptor.getManifest()

Returns the logic manifest.

Returns:

LogicManifest.Manifest – The logic manifest.

LogicDescriptor.getEncodedManifest()

Returns the POLO encoded logic manifest.

Returns:

string – The POLO encoded logic manifest.

LogicDescriptor.isSealed()

Checks if the logic is sealed.

Returns:

boolean – True if the logic is sealed, false otherwise.

LogicDescriptor.isAssetLogic()

Checks if the logic represents an asset logic.

Returns:

boolean – True if the logic is an representation of asset logic, false otherwise.

LogicDescriptor.allowsInteractions()

Checks if the logic allows interactions.

Returns:

boolean – True if the logic allows interactions, false otherwise.

LogicDescriptor.isStateful()

Checks if the logic is stateful.

Returns:

boolean – True if the logic is stateful, false otherwise.

LogicDescriptor.hasPersistentState()

Checks if the logic has persistent state.

Returns:

A tuple containing the pointer to the persistent state and a flag indicating if it exists.

Examples:

const [ptr, exists] = logic.hasPersistentState();
LogicDescriptor.hasEphemeralState()

Checks if the logic has ephemeral state.

Returns:

A tuple containing the pointer to the ephemeral state and a flag indicating if it exists.

Examples:

const [ptr, exists] = logic.hasEphemeralState();

Logic Factory

The LogicFactory class provides a convenient way to deploy multiple instances of logic. This feature simplifies the deployment process, enhances code reusability, and supports the scalability and maintenance of decentralized applications on the MOI network.

// Example
const initWallet = async () => {
    const mnemonic = "mother clarify push liquid ordinary social track ...";
    const wallet = await Wallet.fromMnemonic(mnemonic);
    const provider = new JsonRpcProvider("http://localhost:1600/");
    wallet.connect(provider);

    return wallet;
}

const manifest = { ... }
const wallet = await initWallet(manifest);
const logicFactory = new LogicFactory(manifest, wallet);

Methods

LogicFactory.getEncodedManifest()

Returns the POLO encoded manifest in hexadecimal format.

Returns:

string – The encoded manifest.

const encodedManifest = logicFactory.getEncodedManifest();
console.log(encodedManifest);

>> 0x56b34f...
LogicFactory.deploy(builderName, ...args)

Deploys a logic.

Arguments:
  • builderName (string) – The name of the builder routine.

  • args (Array.<any>) – Optional arguments for the deployment.

Throws:

Error – If the builder routine is not found or if there are missing arguments.

Returns:

LogicIxRequest – The logic interaction request object.

import { LogicFactory } from "js-moi-sdk";
import { wallet } from "./wallet";

const factory = new LogicFactory(manifest, wallet);

const symbol = "MOI";
const supply = 1000000;

const ix = await factory.deploy("Seed!", symbol, supply);
const result = await ix.result();

console.log(result.logic_id); // 0x0800007d70c34ed6e...

If you wish to externally pass fuelLimit or fuelPrice, pass the options as the last argument in the deploy call.

import { LogicFactory } from "js-moi-sdk";
import { wallet } from "./wallet";

const factory = new LogicFactory(manifest, wallet);

const symbol = "MOI";
const supply = 1000000;
const option = {
    fuelPrice: 1,
    fuelLimit: 6420,
}

const ix = await factory.deploy("Seed!", symbol, supply, option);
const result = await ix.result();

console.log(result.logic_id); // 0x010000423d3233...

Logic Driver

The LogicDriver enables seamless interaction with MOI Logic by providing a user-friendly and intuitive interface. It allows developers to easily interact with deployed logics, execute their routines, and retrieve their states. The interface abstracts away the complexities of encoding parameters, decoding response and making logic interaction more straightforward.

Variables

routines - This variable represents the set of routines defined within the logic manifest. Developers can easily invoke and execute these routines, which encapsulate specific functionalities and operations provided by the logic.

persistentState - The persistent state variable provides access to enduring state associated with the logic. This state persists across different invocations and interactions, defining core attributes and long-term data.

It contains the following method:

  • get

    This method retrieves a value from persistent state using the storage key. A builder object is passed to a callback to generate the storage key. The builder object offers the following methods:

    • entity - This method used to select the member of the state persistent.

    • length - This method used to access length/size of Array, Varray and, Map.

    • property - This method used to access the property of map using the passed key.

    • at - This method used to access the element of Array and Varray using the passed index.

    • field - This method used to access the field of Class using the passed field name.

// Example
const logic = await getLogicDriver(logicId, wallet);

const symbol = await logic.persistentState.get(access => access.entity("symbol"));
console.log(symbol);

>> MOI
// Example: if you want to access size of the array/map
const logic = await getLogicDriver(logicId, wallet);

const length = await logic.persistentState.get(access => access.entity("persons").length());
console.log(length);

>> 10
// Example: if you want to access the balance of the address from the map
const logic = await getLogicDriver(logicId, wallet);
const address = "0x035dcdaa46f9b8984803b1105d8f327aef97de58481a5d3fea447735cee28fdc";

const balance = await logic.persistentState.get(access => access.entity("Balances").property(hexToBytes(address)));
console.log(balance);

>> 10000
// Example: if you want to field of the class
const logic = await getLogicDriver(logicId, wallet);

const name = await logic.persistentState.get(access => access.entity("persons").field("name"));
console.log(name);

>> Alice
// Example: if you want to access the element of the array
const logic = await getLogicDriver(logicId, wallet);

const product = await logic.persistentState.get(access => access.entity("Products").at(0));
console.log(name);

>> Chocolate

ephemeralState - The ephemeral state variable provides access to transient state associated directly with a participant. This state reflects the state of a participant and can change frequently as interactions occur.

It contains the following method:

  • get

    This method retrieves a value from ephemeral state using the storage key and participant address.

    Usage: Similar to persistent state, the get method takes a callback function. In addition to that, it also requires a participant address. The builder object within the callback defines how to access the state, similar to persistent state.

// Example
const address = "0x996ab2197faa069202f83d7993f174e7a3635f3278d3745d6a9fe89d75b854df"
const logic = await getLogicDriver(logicId, wallet);

const spendable = await logic.ephemeralState.get(address, (access) =>
    access.entity("Spendable")
);
console.log(spendable);

>> 10000

Functions

getLogicDriver(logicId, signerOrProvider, options)

Returns a logic driver instance based on the given logic id.

Arguments:
  • logicId (string) – The logic id of the logic.

  • signerOrProvider (Signer|AbstractProvider) – The instance of the Signer or AbstractProvider.

  • options (Options) – The custom tesseract options for retrieving

Returns:

Promise.<LogicDriver> – A promise that resolves to a LogicDriver instance.

// Example
const initWallet = async () => {
    const mnemonic = "mother clarify push liquid ordinary social track ...";
    const wallet = await Wallet.fromMnemonic(mnemonic);
    const provider = new JsonRpcProvider("http://localhost:1600/");

    wallet.connect(provider);

    return wallet;
}

const logicId = "0x0800007d70c34ed6ec4384c75d469894052647a078b33ac0f08db0d3751c1fce29a49a";
const wallet = await initWallet();
const logicDriver = await getLogicDriver(logicId, wallet);

Warning

When the logic driver is initialized with a provider, any attempt to execute a mutating routine will trigger the SDK to raise an exception. The error message associated with this exception will state: “Mutating routine calls require a signer to be initialized”. Developers should ensure they should pass signer instance while doing mutating routine calls to avoid encountering this exception.

Usage

Example 1: Calling a routine using the logic driver

import { getLogicDriver } from "js-moi-sdk";
import { wallet } from "./wallet";

const logicId = "0x0800007d70c34ed6ec4384c75d469894052647a078b33ac0f08db0d3751c1fce29a49a";
const address = "0x996ab2197faa069202f83d7993f174e7a3635f3278d3745d6a9fe89d75b854df";

// Get logic driver
const logic = await getLogicDriver(logicId, wallet);

// Call the logic routine
const { balance } = await logic.routines.BalanceOf(address);

console.log(balance); // 1000000

Example 2: Retrieving from the persistent state of a logic

import { getLogicDriver } from "js-moi-sdk";
import { wallet } from "./wallet";

const logicId = "0x0800007d70c34ed6ec4384c75d469894052647a078b33ac0f08db0d3751c1fce29a49a";
const address = "0x996ab2197faa069202f83d7993f174e7a3635f3278d3745d6a9fe89d75b854df";

// Get logic driver
const logic = await getLogicDriver(logicId, wallet);

// Get the persistent state
const symbol = await logic.persistentState.get(access => access.entity("symbol"));

console.log(symbol); // MOI

Example 3: Executing a mutating routine call

import { getLogicDriver } from "js-moi-sdk";
import { wallet } from "./wallet";

const logicId = "0x0800007d70c34ed6ec4384c75d469894052647a078b33ac0f08db0d3751c1fce29a49a";
const address = "0x996ab2197faa069202f83d7993f174e7a3635f3278d3745d6a9fe89d75b854df";

// Get logic driver
const logic = await getLogicDriver(logicId, wallet);

// Execute a mutating routine call
const ix = await logic.routines.Transfer(address, 1000);
console.log(ix.hash); //  0x010000423d3233...

const receipt = await ix.wait();
console.log(receipt); // { ... }

// if you want to view the result of the logic interaction
// you can use the result() method

// for example
// const result = await ix.result(); // { ... }

If you wish to externally pass fuelLimit or fuelPrice, pass the options as the last argument in the deploy call.

import { getLogicDriver } from "js-moi-sdk";
import { wallet } from "./wallet";

const logicId = "0x0800007d70c34ed6ec4384c75d469894052647a078b33ac0f08db0d3751c1fce29a49a";
const address = "0x996ab2197faa069202f83d7993f174e7a3635f3278d3745d6a9fe89d75b854df";

// Get logic driver
const logic = await getLogicDriver(logicId, wallet);

// Execute a mutating routine call
const option = {
    fuelPrice: 1,
    fuelLimit: 6420,
}
const ix = await logic.routines.Transfer(address, 1000, option);
console.log(ix.hash); //  0x010000423d3233...

const receipt = await ix.wait();
console.log(receipt); // { ... }