Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Msg

The msg module provides type inference and validated message building from JSON Schema — the core of schemos.

import { createMsgBuilder, createMsgValidator } from 'schemos'
import type {
  InferMsg, MessageNames, MessageArgs, InferResponse,
  MsgBuilder, MsgValidator,
} from 'schemos'

Why Msg?

createTypedContract binds msg building to a specific client and contract address. The msg module gives you just the typed message envelope or validated data — useful when you want to:

  • Build messages without a client (e.g., for batch transactions)
  • Use protobuf encoding from your own chain SDK
  • Validate instantiate messages before deploying
  • Compose messages for executeMultiple or multi-message transactions

createMsgBuilder

Creates a reusable typed message builder from a JSON Schema. The schema type is resolved once at factory level — subsequent calls have zero type overhead.

function createMsgBuilder<TSchema extends JSONSchema>(
  schema: TSchema,
): MsgBuilder<FromSchema<TSchema>>

Parameters

ParameterTypeDescription
schemaJSONSchemaA cargo schema JSON object imported as as const

Returns

A callable MsgBuilder that builds validated { [msgName]: args } envelopes.

Example

 
import { createMsgBuilder } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
const cw20Msg = createMsgBuilder(cw20.execute)
 
// Typed envelopeautocomplete on msg names and args
const envelope = cw20Msg('transfer', { amount: '1000', recipient: 'osmo1...' })
// envelope: { transfer: { amount: string; recipient: string } }

Batch usage

The schema is compiled once at factory creation. Safe for repeated calls:

const cw20Msg = createMsgBuilder(cw20.execute)
 
const msgs = [
  cw20Msg('transfer', { amount: '100', recipient: addr1 }),
  cw20Msg('transfer', { amount: '200', recipient: addr2 }),
]

With telescope protobuf encoding

 
import { createMsgBuilder, Json } from 'schemos'
import { cw20 } from 'schemos/schemas'
import { MsgExecuteContract } from 'osmojs/cosmwasm/wasm/v1/tx'
 
const cw20Msg = createMsgBuilder(cw20.execute)
const envelope = cw20Msg('transfer', { amount: '1000', recipient: 'osmo1...' })
 
// Use with telescope's protobuf encoding
MsgExecuteContract.fromPartial({
  sender,
  contract,
  msg: Json.toBytes(envelope),
  funds: [],
})

createMsgValidator

Creates a typed validator from a JSON Schema. Useful for validating instantiate messages and other flat struct schemas where the envelope pattern ({ [msgName]: args }) doesn't apply.

function createMsgValidator<TSchema extends JSONSchema>(
  schema: TSchema,
): MsgValidator<FromSchema<TSchema>>

Parameters

ParameterTypeDescription
schemaJSONSchemaA cargo schema JSON object imported as as const

Returns

A callable MsgValidator that type-checks the input at compile time and validates it at runtime.

Example

import { createMsgValidator } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
const validateInit = createMsgValidator(cw20.instantiate)
 
// initMsg type is inferred from cw20.instantiate schema
const initMsg = validateInit({
  name: 'Token',
  symbol: 'TKN',
  decimals: 6,
  initial_balances: [{ address: 'osmo1...', amount: '1000000' }],
})
 
await client.instantiate(sender, codeId, initMsg, 'label', 'auto')

Error handling

// Compile errormissing required fields (symbol, decimals, initial_balances)
const validateInit = createMsgValidator(cw20.instantiate)
 
validateInit({
  name: 'Token',
  symbol: 'TKN',
  decimal: 6,
Object literal may only specify known properties, but 'decimal' does not exist in type '{ marketing?: { description?: string | null | undefined; marketing?: string | null | undefined; logo?: { url: string; } | { embedded: { svg: string; } | { png: string; }; } | null | undefined; project?: string | ... 1 more ... | undefined; } | null | undefined; ... 4 more ...; name: string; }'. Did you mean to write 'decimals'?
initial_balances: [{ address: 'osmo1...', amount: '1000000' }], }) validateInit({ name: 'Token', symbol: 'TKN', decimals: 6, initial_balances: [{ address: 'osmo1...', amount: 1000000 }],
Type 'number' is not assignable to type 'string'.
}) // Runtime errorif invalid data bypasses type checking (e.g., from external source) // throws: Validation failed: data must have required property 'symbol', ...

Validation

createMsgBuilder and createMsgValidator both validate data against the schema at runtime. Validation errors are thrown immediately — before gas is spent.

Validators are cached in a module-level WeakMap keyed by schema reference — out-of-scope schemas are garbage collected.

CosmWasm Format Validators

Ajv is configured with custom format validators for CosmWasm-specific integer formats emitted by cosmwasm-schema:

FormatRangeDescription
uint80 - 2558-bit unsigned integer
uint320 - 4,294,967,29532-bit unsigned integer
uint640 - Number.MAX_SAFE_INTEGER64-bit unsigned integer (limited by JS number precision)

These are registered automatically when any schema is compiled. Values above Number.MAX_SAFE_INTEGER for uint64 must be handled via BigInt at the application layer.

Type Utilities

InferMsg

Infer the full TypeScript union type from a JSON Schema:

type InferMsg<TSchema extends JSONSchema> = FromSchema<TSchema>
import type { InferMsg } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
type Cw20ExecuteMsg = InferMsg<typeof cw20.execute>
// { transfer: { recipient: string; amount: string } }
// | { burn: { amount: string } }
// | { send: { contract: string; amount: string; msg: string } }
// | ...

MessageNames

Extract all top-level message names from a message union:

type MessageNames<T> = T extends Record<string, unknown> ? keyof T & string : never
import type { InferMsg, MessageNames } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
type Names = MessageNames<InferMsg<typeof cw20.execute>>
// 'transfer' | 'burn' | 'send' | 'mint' | 'increase_allowance' | ...

MessageArgs

Extract the args type for a specific message name:

type MessageArgs<T, K extends string> = T extends Record<K, infer V> ? V : never
import type { InferMsg, MessageArgs } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
type TransferArgs = MessageArgs<InferMsg<typeof cw20.execute>, 'transfer'>
// { recipient: string; amount: string }

InferResponse

Infer a specific response type from a responses schema map:

type InferResponse<
  TResponses extends Record<string, JSONSchema>,
  K extends keyof TResponses & string,
> = FromSchema<TResponses[K]>
import type { InferResponse } from 'schemos'
import { cw20 } from 'schemos/schemas'
 
type BalanceResponse = InferResponse<typeof cw20.responses, 'balance'>
// { balance: string }

MsgBuilder

The callable type returned by createMsgBuilder:

type MsgBuilder<TMsg> = <K extends MessageNames<TMsg>>(
  msg: K,
  args: MessageArgs<TMsg, K>,
  options?: { context?: string },
) => { [P in K]: MessageArgs<TMsg, K> }

MsgValidator

The callable type returned by createMsgValidator:

type MsgValidator<TMsg> = (
  data: TMsg,
  options?: { context?: string },
) => TMsg