Loading Animation

0%

Intento Logo

Intento Tutorial

Welcome to Intento

What is Intento?

Intento is a protocol that revolutionizes on-chain orchestration of actions through a novel Cosmos SDK module. It is designed to process and execute user intentions across IBC-connected chains, making on-chain processes more intuitive, accessible, and efficient. Intento covers a broad range of use cases, from simple scheduled payments to complex interchain operations.

Processing of Intent-Based Actions via Flows

Intents contain actions and predefined conditions, which determine how actions are processed. With Intento, you can specify your intent to perform any action, anywhere, at any moment, given any conditions. This eliminates counterparty risk and enables permissionless, decentralized execution.

Key Features

  • Self-Custodial Execution: Completely sovereign processing of your actions and conditions.
  • Permissionless: Open for everyone to use.
  • TriggerPortal: An easy-to-use frontend UI to submit flows.
  • Orchestration: Specify complex interchain operations.
  • Scalable and VM Agnostic: Compatibility with executing actions on various VMs.
  • IBC-Native: Coordinated actions across blockchains using Interchain Accounts and IBC-hooks.
  • Modular and Secure: Utilizes Cosmos SDK and Interchain Security (ICS) on the Cosmos Hub for security.
  • Privileged Execution: Execute actions on your account by granting permissions to a fixed and unique trigger address.

Why Intento?

Intento is a comprehensive solution designed to make blockchain operations effortless, secure, and efficient. With a focus on user intent, scalability, and interchain capabilities, Intento stands out as the most efficient and effective processing of intents solution in the Web3 ecosystem. Whether you're looking to manage portfolios, streamline payments, or coordinate across blockchains, Intento has you covered.

Intento leverages a combination of the Cosmos stack and IBC to provide a seamless experience for workflows. Users, developers, and organizations can orchestrate complex sets of actions, ranging from simple automated payments to sophisticated interchain operations, all composed and executed from the Intento processing chain.

Pillars of Intento

Self-Custodial

By utilizing programmed accounts on a flow level, Intento enables fully self-custodial execution in a secure manner. This ensures a completely sovereign processing of your actions and conditions. With Intento, your blockchain experience is not just about participation—it's about freedom and sovereignty.

Secure On-Chain

On-chain submission, triggering, and processing highlight our dedication to enabling seamless and secure execution of actions across multiple blockchain networks. By leveraging the Inter-Blockchain Communication (IBC) protocol, Intento empowers users to trigger actions effortlessly with any chain, ensuring every transaction is executed securely and reliably.

Scalable

At Intento, scalability is a cornerstone of our design. Our platform ensures that as your needs grow, it can effortlessly adapt, empowering you to execute transactions and manage assets with confidence and efficiency, no matter the blockchain landscape. Intento sets a new standard for efficiency in the blockchain space, outperforming existing off-chain solutions with significantly lower gas costs.

Explore Use Cases

Discover how Intento can transform your blockchain workflows. Check out the use cases section to learn more.

Intento Kit

Installation

Introduction

Now we will learn about IntentoJS, a powerful library for interacting with the Intento ecosystem.

Installation

To install IntentoJS, run the following command:

npm install intentojs

Connecting with Wallets and Signing Messages

To initialize the Stargate client, we recommend manually creating the SigningStargateClient instance using getTrstSigningClientOptions:

import { getTrstSigningClientOptions, trstAccountParser } from "@intentojs";

const { registry, aminoTypes } = getTrstSigningClientOptions();

const client = await SigningStargateClient.connectWithSigner(
  rpc,
  offlineSigner,
  {
    registry,
    aminoTypes,
    accountParser: trstAccountParser,
  }
);

Usage

We strongly recommend checking the generated files in src/codegen/trst and using them as the source of truth for available functions.

RPC Client

Here's how to create an RPC client:

import { trst } from "intentojs";

const client = await trst.ClientFactory.createRPCQueryClient({
  rpcEndpoint: RPC_ENDPOINT,
});

const balance = await client.cosmos.bank.v1beta1.allBalances({
  address: "trst1addresshere",
});

Composing & Broadcasting Trst Messages

Here's an example of composing and broadcasting a Trst message:

import { trst } from "intentojs";

const msgClaimFreeAmount =
  trst.claim.MessageComposer.withTypeUrl.claimFreeAmount({
    user: "trst1addresshere",
  });

const fee = {
  amount: [
    {
      amount: "0",
      denom: "utrst",
    },
  ],
  gas: 250_000,
};

const tx = await trstAccount.client.signAndBroadcast(
  "trst1addresshere",
  [msgClaimFreeAmount],
  fee,
  ""
);

assertIsDeliverTxSuccess(tx);

If you're unfamiliar with Stargate, you can read their guide here.

Composing IBC Messages

Here's an example of composing an IBC message:

import { ibc } from "intentojs";

const { transfer } =
  ibc.applications.transfer.v1.MessageComposer.withTypeUrl.transfer({
    // Redacted (check internal types for the message parameters)
  });

Testing with IntentoJS

1️⃣ Setup Steps

Follow these steps to set up a project with IntentoJS:

mkdir intentojs-test && cd intentojs-test

2️⃣ package.json

Create a package.json file with the following content:

{
  "name": "intentojs-test",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "@cosmjs/proto-signing": "^0.33.1",
    "@cosmjs/stargate": "^0.33.1",
    "dotenv": "^16.4.7",
    "intentojs": "^0.9.0-beta.3"
  }
}

Install dependencies by running:

npm install

Create Required Files

Create the necessary files:

touch rpc-client-test.js account-client-test.js all-object.js

3️⃣ rpc-client-test.js

Check the RPC URL to ensure it is correct and accessible. You can test the server at https://rpc-testnet-itento.zixine.com.

const { Tendermint37Client } = require("@cosmjs/tendermint-rpc");

const RPC_ENDPOINT = "https://rpc-testnet-itento.zixine.com";

async function main() {
  const client = await Tendermint37Client.connect(RPC_ENDPOINT);
  const status = await client.status();
  console.log("Node Status:", status);
}

main().catch(console.error);

Run the script with:

node rpc-client-test.js

Example output:

Node Status: Node Status: {
  nodeInfo: {
    id: Uint8Array(20) [
       67, 123,  50,  67,  48, 140,
       71, 223, 233, 232, 219,  82,
      216,  75,  45, 161, 218,  93,
      127, 214
    ],
    listenAddr: 'tcp://0.0.0.0:25556',
    network: 'intento-ics-test-1',
    version: '0.38.17',
    channels: '40202122233038606100',
    moniker: 'zixine',
    other: Map(2) {
      'tx_index' => 'on',
      'rpc_address' => 'tcp://0.0.0.0:25557'
    },
    protocolVersion: { app: 0, block: 11, p2p: 8 }
  },
  syncInfo: {
    earliestAppHash: Uint8Array(32) [
      227, 176, 196,  66, 152, 252,  28,
       20, 154, 251, 244, 200, 153, 111,
      185,  36,  39, 174,  65, 228, 100,
      155, 147,  76, 164, 149, 153,  27,
      120,  82, 184,  85
    ],
    earliestBlockHash: Uint8Array(32) [
       7, 153, 195,  95,  77, 157, 202, 146,
      95, 117,  91,  29, 228, 184, 185,  39,
      24, 135,   9, 104, 157, 153,  17,  26,
      14, 129, 198,  94, 233, 211,  99, 102
    ],
    earliestBlockHeight: 1,
    earliestBlockTime: 2025-03-17T13:51:56.592Z { nanoseconds: 979166 },
    latestBlockHash: Uint8Array(32) [
        5,  68, 232, 140,   5,  74,  35, 114,
      252, 163,  71, 229, 125, 234, 104, 143,
      111,  44,  43,  70, 187,  89, 132, 207,
       11, 153, 109,  96, 218, 114, 171, 215
    ],
    latestAppHash: Uint8Array(32) [
       74,  48, 238,  87, 220,   0, 100,  33,
      165, 108, 110, 160, 107, 239, 110, 118,
       45, 235, 184, 203, 125,  12,  54, 219,
      110, 185, 161,  11,  63,  45, 189, 120
    ],
    latestBlockTime: 2025-03-18T17:11:13.524Z { nanoseconds: 824934 },
    latestBlockHeight: 34161,
    catchingUp: false
  },
  validatorInfo: {
    pubkey: { algorithm: 'ed25519', data: [Uint8Array] },
    votingPower: 0n,
    address: Uint8Array(20) [
      165, 241, 198, 126, 130, 89,
       83, 140, 243, 180,  77, 12,
      251, 121, 240, 230, 237, 83,
       61, 165
    ],
    proposerPriority: undefined
  }
}

4️⃣ account-client-test.js

Check the account balance:

const { StargateClient } = require("@cosmjs/stargate");

const RPC_ENDPOINT = "https://rpc-testnet-itento.zixine.com";
const ADDRESS = "into142sleww92d7hvww0gk2502kevr2rrc7ve4jn2d"; // Replace with your TRST address

async function main() {
  const client = await StargateClient.connect(RPC_ENDPOINT);
  const balance = await client.getAllBalances(ADDRESS);
  console.log("Balances:", balance);
}

main().catch(console.error);

Run the script with:

node account-client-test.js

Example output:

Balances: []

5️⃣ all-object.js

Inspect the objects in IntentoJS:

import pkg from 'intentojs';

const { intento, trst } = pkg;

console.log(intento);
console.log(pkg);
console.log(trst);

Run the script with:

node all-object.js

Example output:

{
  alloc: {
    v1beta1: {
      GenesisState: [Object],
      WeightedAddress: [Object],
      DistributionProportions: [Object],
      Params: [Object],
      QueryParamsRequest: [Object],
      QueryParamsResponse: [Object],
      MsgFundFairburnPool: [Object],
      MsgFundFairburnPoolResponse: [Object],
      MsgUpdateParams: [Object],
      MsgUpdateParamsResponse: [Object],
      AminoConverter: [Object],
      registry: [Array],
      load: [Function: load],
      MessageComposer: [Object],
      QueryClientImpl: [class QueryClientImpl],
      createRpcQueryExtension: [Function: createRpcQueryExtension],
      MsgClientImpl: [class MsgClientImpl]
    }
  },
  claim: {
    v1beta1: {
      Action: [Object],
      ActionSDKType: [Object],
      ActionAmino: [Object],
      actionFromJSON: [Function: actionFromJSON],
      actionToJSON: [Function: actionToJSON],
      ClaimRecord: [Object],
      Status: [Object],
      MsgClaimClaimable: [Object],
      MsgClaimClaimableResponse: [Object],
      GenesisState: [Object],
      Params: [Object],
      QueryModuleAccountBalanceRequest: [Object],
      QueryModuleAccountBalanceResponse: [Object],
      QueryParamsRequest: [Object],
      QueryParamsResponse: [Object],
      QueryClaimRecordRequest: [Object],
      QueryClaimRecordResponse: [Object],
      QueryClaimableForActionRequest: [Object],
      QueryClaimableForActionResponse: [Object],
      QueryTotalClaimableRequest: [Object],
      QueryTotalClaimableResponse: [Object],
      AminoConverter: [Object],
      registry: [Array],
      load: [Function: load],
      MessageComposer: [Object],
      QueryClientImpl: [class QueryClientImpl],
      createRpcQueryExtension: [Function: createRpcQueryExtension],
      MsgClientImpl: [class MsgClientImpl]
    }
  },
  intent: {
    v1beta1: {
      ComparisonOperator: [Object],
      ComparisonOperatorSDKType: [Object],
      ComparisonOperatorAmino: [Object],
      comparisonOperatorFromJSON: [Function: comparisonOperatorFromJSON],
      comparisonOperatorToJSON: [Function: comparisonOperatorToJSON],
      FlowInfo: [Object],
      ICAConfig: [Object],
      HostedICAConfig: [Object],
      ExecutionConfiguration: [Object],
      FlowHistory: [Object],
      FlowHistoryEntry: [Object],
      ExecutionConditions: [Object],
      FeedbackLoop: [Object],
      Comparison: [Object],
      ICQConfig: [Object],
      GenesisState: [Object],
      Sequence: [Object],
      HostedAccount: [Object],
      HostFeeConfig: [Object],
      Params: [Object],
      QueryInterchainAccountFromAddressRequest: [Object],
      QueryInterchainAccountFromAddressResponse: [Object],
      QueryFlowRequest: [Object],
      QueryFlowResponse: [Object],
      QueryFlowHistoryRequest: [Object],
      QueryFlowHistoryResponse: [Object],
      QueryFlowsRequest: [Object],
      QueryFlowsResponse: [Object],
      QueryFlowsForOwnerRequest: [Object],
      QueryFlowsForOwnerResponse: [Object],
      QueryParamsRequest: [Object],
      QueryParamsResponse: [Object],
      QueryHostedAccountRequest: [Object],
      QueryHostedAccountResponse: [Object],
      QueryHostedAccountsRequest: [Object],
      QueryHostedAccountsResponse: [Object],
      QueryHostedAccountsByAdminRequest: [Object],
      QueryHostedAccountsByAdminResponse: [Object],
      MsgRegisterAccount: [Object],
      MsgRegisterAccountResponse: [Object],
      MsgSubmitTx: [Object],
      MsgSubmitTxResponse: [Object],
      MsgSubmitFlow: [Object],
      MsgSubmitFlowResponse: [Object],
      MsgRegisterAccountAndSubmitFlow: [Object],
      MsgRegisterAccountAndSubmitFlowResponse: [Object],
      MsgUpdateFlow: [Object],
      MsgUpdateFlowResponse: [Object],
      MsgCreateHostedAccount: [Object],
      MsgCreateHostedAccountResponse: [Object],
      MsgUpdateHostedAccount: [Object],
      MsgUpdateHostedAccountResponse: [Object],
      AminoConverter: [Object],
      registry: [Array],
      load: [Function: load],
      MessageComposer: [Object],
      QueryClientImpl: [class QueryClientImpl],
      createRpcQueryExtension: [Function: createRpcQueryExtension],
      MsgClientImpl: [class MsgClientImpl]
    }
  },
  mint: {
    v1beta1: {
      GenesisState: [Object],
      Minter: [Object],
      Params: [Object],
      QueryParamsRequest: [Object],
      QueryParamsResponse: [Object],
      QueryAnnualProvisionsRequest: [Object],
      QueryAnnualProvisionsResponse: [Object],
      MsgUpdateParams: [Object],
      MsgUpdateParamsResponse: [Object],
      AminoConverter: [Object],
      registry: [Array],
      load: [Function: load],
      MessageComposer: [Object],
      QueryClientImpl: [class QueryClientImpl],
      createRpcQueryExtension: [Function: createRpcQueryExtension],
      MsgClientImpl: [class MsgClientImpl]
    }
  },
  ClientFactory: {
    createRPCQueryClient: [AsyncFunction: createRPCQueryClient],
    createRPCMsgClient: [AsyncFunction: createRPCMsgClient]
  }
}
{
  amino: [Getter],
  ics23: [Getter],
  cosmos_proto: [Getter],
  cosmos: [Getter],
  cosmosAminoConverters: [Getter],
  cosmosProtoRegistry: [Getter],
  getSigningCosmosClientOptions: [Getter],
  getSigningCosmosClient: [Getter],
  cosmwasm: [Getter],
  cosmwasmAminoConverters: [Getter],
  cosmwasmProtoRegistry: [Getter],
  getSigningCosmwasmClientOptions: [Getter],
  getSigningCosmwasmClient: [Getter],
  gogoproto: [Getter],
  google: [Getter],
  ibc: [Getter],
  ibcAminoConverters: [Getter],
  ibcProtoRegistry: [Getter],
  getSigningIbcClientOptions: [Getter],
  getSigningIbcClient: [Getter],
  tendermint: [Getter],
  intento: [Getter],
  intentoAminoConverters: [Getter],
  intentoProtoRegistry: [Getter],
  getSigningIntentoClientOptions: [Getter],
  getSigningIntentoClient: [Getter],
  osmosis: [Getter],
  stride: [Getter],
  strideAminoConverters: [Getter],
  strideProtoRegistry: [Getter],
  getSigningStrideClientOptions: [Getter],
  getSigningStrideClient: [Getter],
  varint64read: [Getter],
  varint64write: [Getter],
  int64FromString: [Getter],
  int64ToString: [Getter],
  uInt64ToString: [Getter],
  varint32write: [Getter],
  varint32read: [Getter],
  zzEncode: [Getter],
  zzDecode: [Getter],
  readUInt32: [Getter],
  readInt32: [Getter],
  writeVarint32: [Getter],
  writeVarint64: [Getter],
  int64Length: [Getter],
  writeFixed32: [Getter],
  writeByte: [Getter],
  utf8Length: [Getter],
  utf8Read: [Getter],
  utf8Write: [Getter],
  WireType: [Getter],
  BinaryReader: [Getter],
  BinaryWriter: [Getter],
  GlobalDecoderRegistry: [Getter],
  getIntentoSigningClientOptions: [Getter],
  getIntentoSigningClient: [Getter],
  customMsgRegistry: [Getter]
}

TRST Labs & Intento Documentation

TRST Labs

TRST Labs develops blockchain infrastructure for Intents using Cosmos SDK and IBC.

Flow Governance Proposal Parameters

The Flow Governance Proposal Parameters define the rules and constraints governing the execution of Flows within the network. These parameters are unique as they are set through on-chain governance, ensuring transparency and adaptability over time.

ParameterTypeDescriptionExample Value
flow_funds_commissionint64Commission rate to return remaining funds in flow fee account after final execution2 (2%)
flow_flex_fee_mulint64Multiplier to the flexible flow gas fee250 (2.5X)
burn_fee_per_msgint64Fixed burn fee per message execution to burn native denom10_000 (0.01uinto)
gas_fee_coinsrepeated CoinArray of denoms that can be used for fee payment together with an amount[1uinto, 0.05ibc/chain_channel_hash]
max_flow_durationgoogle.protobuf.DurationMaximum period for self-executing Flow263520h (a little over 3 years)
min_flow_durationgoogle.protobuf.DurationMinimum period for self-executing Flow1m (1 minute)
min_flow_intervalgoogle.protobuf.DurationMinimum interval for self-executing Flow1m (1 minute)
relayer_rewardsrepeated int64Relayer rewards in uinto for each message type[0, 1, 2]

Authentication Overview

The module processes three primary message types:

  • Local Messages
  • Authz MsgExec Messages
  • ICA (Interchain Account) Messages

Each message type has specific authentication logic to ensure security and correctness.

Example Code: validateMessage

func (k Keeper) validateMessage(ctx sdk.Context, codec codec.Codec, flowInfo types.FlowInfo, message *codectypes.Any) error {
    var sdkMsg sdk.Msg
    if err := codec.UnpackAny(message, &sdkMsg); err != nil {
        return errorsmod.Wrap(err, "failed to unpack message")
    }

    switch {
    case isAuthzMsgExec(message):
        return k.validateAuthzMsg(ctx, codec, flowInfo, message)
    case isLocalMessage(flowInfo):
        return k.validateSigners(ctx, codec, flowInfo, message)
    case isHostedICAMessage(flowInfo):
        if message.TypeUrl != sdk.MsgTypeURL(&authztypes.MsgExec{}) {
            return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "only MsgExec is allowed for Hosted ICA messages")
        }
        return nil
    case isSelfHostedICAMessage(flowInfo):
        return nil
    default:
        return errorsmod.Wrap(sdkerrors.ErrUnauthorized, "unsupported message type")
    }
}

Supported Types

The Intent module supports various types from Cosmos SDK, Osmosis, CosmWasm, and Ethermint. Below are some examples:

  • Cosmos SDK: Account Balances, Validator Information, Delegations
  • Osmosis: Pool Information, Liquidity Incentives, Superfluid Staking
  • CosmWasm: Smart Contract Code, Smart Contract Instance, Smart Contract State
  • Ethermint: EVM Code, EVM Storage, EVM Module Parameters
Go Back Home