Files
xo-cash-utils/source/template/schemas.ts

896 lines
32 KiB
TypeScript

/* eslint-disable @stylistic/newline-per-chained-call */
import { z } from 'zod';
// ============================================================
// Enums
// ============================================================
/**
* Validation schema for a BCH VM version identifier. Defines the set of known BCH VM versions
* that XO templates declare support for.
*
* Zod's `z.enum` requires the exact values to be defined inline because it needs to know each
* specific value at compile time to validate against them. Defining the versions here directly
* satisfies that requirement and allows `z.array(bchVmVersionSchema)` to be used elsewhere
*
* ```
* {
* "supported": [ "BCH_2025_05" ] ← each value
* }
* ```
*/
export const bchVmVersionSchema = z.enum([ 'BCH_2020_05', 'BCH_2021_05', 'BCH_2022_05', 'BCH_2023_05', 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05' ]);
/**
* Validation schema for the capability of a non-fungible token. Defines the three capability
* types supported on BCH: minting tokens can create new NFTs, mutable tokens can update their
* commitment, and none tokens cannot be changed after creation.
*
* ```
* {
* "inputs|outputs": {
* "[id]": {
* "token": {
* "nft": {
* "capability": "minting" ← this schema
* }
* }
* }
* }
* }
* ```
*/
export const xoTemplateNftCapabilitySchema = z.enum([ 'minting', 'mutable', 'none' ]);
/**
* Validation schema for a BCH locking script type. Defines the standard locking script types
* supported on BCH.
*
* ```
* {
* "lockingScripts": {
* "[id]": {
* "lockingType": "p2pkh" ← this schema
* }
* }
* }
* ```
*/
export const xoTemplateLockingTypeSchema = z.enum([ 'p2s', 'p2pkh', 'p2sh' ]);
/**
* Validation schema for a primitive type identifier. Defines the set of primitive types
* that can be declared in an XO template. Used by constants, variables, and data fields.
*/
export const xoTemplatePrimitiveTypeSchema = z.enum([ 'boolean', 'bytes', 'integer', 'bigint', 'string', 'private_key', 'public_key' ]);
// ============================================================
// Primitives
// ============================================================
/**
* Validation schema for byte array fields i.e. Uint8Array instance.
*/
export const uint8ArraySchema = z.instanceof(Uint8Array).describe('A sequence of unsigned 8-bit integers expressed as a Uint8Array.');
/**
* Validation schema for the Satoshis type i.e. bigint.
*/
export const satoshisSchema = z.bigint().describe('A satoshi amount expressed as a bigint.');
// ============================================================
// Shared
// ============================================================
/** Maximum character length for name fields on view properties. */
export const VIEW_PROPERTIES_NAME_MAX_LENGTH = 200;
/** Maximum character length for description fields on view properties. */
export const VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH = 5000;
/** Maximum character length for icon fields on view properties. */
export const VIEW_PROPERTIES_ICON_MAX_LENGTH = 50;
/**
* Validation schema for view properties shared across many template elements i.e. name, description, icon.
* Extended by most other schemas in this file.
*/
export const xoTemplateViewPropertiesSchema = z
.object({
name: z.string().max(VIEW_PROPERTIES_NAME_MAX_LENGTH).describe('A short human-readable label for this element.'),
description: z
.string()
.max(VIEW_PROPERTIES_DESCRIPTION_MAX_LENGTH)
.describe('A human-readable explanation of what this element does and when it is relevant.'),
icon: z.string().max(VIEW_PROPERTIES_ICON_MAX_LENGTH).optional().describe('An optional icon identifier or URL for this element.'),
})
.strict();
// ============================================================
// Intents
// ============================================================
/**
* Validation schema for the base intent structure. Describes the common data parameters shared
* by all intent types regardless of what they target.
*
* An optional templateIdentifier allows the intent to reference a target defined in a different
* template, enabling cross-template interaction.
*
* Extended by: xoTemplateActionIntentSchema, xoTemplateOutputIntentSchema,
* xoTemplateLockingScriptIntentSchema.
*/
export const xoTemplateIntentSchema = z
.object({
templateIdentifier: z
.string()
.optional()
.describe('Optional identifier for the template used in this intent. If not provided, uses the current template.'),
role: z.string().optional().describe('Optional identifier for the role used in this intent.'),
generate: z.array(z.string()).optional().describe('Identifiers for items to generate when this intent is resolved, e.g. keys or secrets.'),
variables: z.array(z.record(z.string(), z.unknown())).optional().describe('Variable values to apply when this intent is resolved.'),
constants: z.array(z.record(z.string(), z.unknown())).optional().describe('Constant values to apply when this intent is resolved.'),
secrets: z.array(z.record(z.string(), z.unknown())).optional().describe('Secret values to apply when this intent is resolved.'),
})
.strict();
/**
* Validation schema for an action intent. Extends the base intent structure with an action
* identifier. Used in locking script action lists and in the template's start array.
*
* ```
* {
* "start": [
* { "action": "..." } ← this schema
* ],
* "lockingScripts": {
* "[id]": {
* "actions": [
* { "action": "..." } ← this schema
* ],
* "roles": {
* "[roleId]": {
* "actions": [
* { "action": "..." } ← this schema
* ]
* }
* }
* }
* }
* }
* ```
*/
export const xoTemplateActionIntentSchema = xoTemplateIntentSchema
.extend({
action: z.string().describe('The identifier for the intended action.'),
})
.strict();
/**
* Validation schema for an output intent. Extends the base intent structure with an output
* identifier. Used in the template's defaults block.
*
* ```
* {
* "defaults": {
* "change": { "output": "..." } ← this schema
* }
* }
* ```
*/
export const xoTemplateOutputIntentSchema = xoTemplateIntentSchema
.extend({
output: z.string().describe('The identifier for the intended output.'),
})
.strict();
/**
* Validation schema for a locking script intent. Extends the base intent structure with
* a locking script identifier.
*
* @todo The location of this schema in the template JSON is not yet determined.
*/
export const xoTemplateLockingScriptIntentSchema = xoTemplateIntentSchema
.extend({
lockingScript: z.string().describe('The identifier for the intended locking script.'),
})
.strict();
// ============================================================
// Actions
// ============================================================
/**
* Validation schema for the slot count configuration on a role requirement. Declares how many
* participants of a given role are needed. min sets the lower bound and max sets the upper bound.
* When max is absent, there is no upper limit.
*
* ```
* {
* "actions": {
* "[id]": {
* "requirements": {
* "participants": [
* { "slots": { "min": 1, "max": 1 } } ← this schema
* ]
* }
* }
* }
* }
* ```
*/
export const xoTemplateRoleSlotsRequirementsSchema = z
.object({
min: z.number().describe('Minimum number of participants required for this role.'),
max: z.number().optional().describe('Maximum number of participants allowed for this role. Undefined means unlimited.'),
})
.strict();
/**
* Validation schema for the capability requirements declared on a role within an action.
* Describes what data, secrets, or state the role is responsible for providing when participating in an action.
*
* ```
* {
* "actions": {
* "[id]": {
* "roles": {
* "[roleId]": {
* "requirements": { "variables": [], "secrets": [] } ← this schema
* }
* }
* }
* }
* }
* ```
*/
export const xoTemplateActionRoleRequirementsSchema = z
.object({
variables: z.array(z.string()).optional().describe('List of variable identifiers required for this role.'),
secrets: z.array(z.string()).optional().describe('List of secret identifiers required for this role.'),
})
.strict();
/**
* Validation schema for a role-specific definition within an action.
* All view properties are optional.
*
* ```
* {
* "actions": {
* "[id]": {
* "roles": {
* "[roleId]": { } ← this schema
* }
* }
* }
* }
* ```
*/
export const xoTemplateActionRoleSchema = xoTemplateViewPropertiesSchema
.partial()
.extend({
generate: z
.array(z.string())
.optional()
.describe('Identifiers for data items that should be generated for this role when participating in the action.'),
// Describes under what conditions this role can proceed with the action. All values listed
// under requirements must be populated for the action to work. This is a developer and
// author concern. It is not present on intents because intents are used to populate the
// action rather than to define it, and their fields are flattened accordingly.
requirements: xoTemplateActionRoleRequirementsSchema.optional().describe('The requirements for this role within this action.'),
})
.strict();
/**
* Validation schema for a role participation requirement in an action's requirements block.
*
* ```
* {
* "actions": {
* "[id]": {
* "requirements": {
* "participants": [
* { "role": "...", "slots": { } } ← this schema
* ]
* }
* }
* }
* }
* ```
*/
export const xoTemplateRoleSlotSchema = z
.object({
role: z.string().describe('The role identifier that this requirement applies to.'),
slots: xoTemplateRoleSlotsRequirementsSchema.describe('Slot configuration specifying how many participants of this role are required.'),
})
.strict();
/**
* Validation schema for the requirements of an action.
*
* ```
* {
* "actions": {
* "[id]": {
* "requirements": { "participants": [], "secrets": [] } ← this schema
* }
* }
* }
* ```
*/
export const xoTemplateActionRequirementsSchema = z
.object({
participants: z.array(xoTemplateRoleSlotSchema).optional().describe('The participants required for this action.'),
secrets: z.array(z.string()).optional().describe('The secrets required for this action.'),
})
.strict();
/**
* Validation schema for an action definition.
*
* ```
* {
* "actions": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateActionSchema = xoTemplateViewPropertiesSchema
.extend({
roles: z.record(z.string(), xoTemplateActionRoleSchema).optional().describe('Specific context for each role participating in this action.'),
requirements: xoTemplateActionRequirementsSchema.optional().describe('The requirements for this action.'),
// This is a list of conditions that can influence how the action behaves.
// This needs more work to be done.
conditions: z.array(z.string()).optional().describe('Conditions that must be met for this action to be available.'),
// A single transaction produced by the action.
// In future this might be moved to a results block that can have multiple transactions.
transaction: z
.string()
.optional()
.describe("The identifier of the transaction this action produces, referencing an entry in the template's transactions."),
// The data that is produced by the action.
// In future this might be moved to a results block that can have multiple data fields.
data: z.string().optional().describe("The identifier of the data field this action produces, referencing an entry in the template's data."),
})
.strict();
// ============================================================
// Tokens & Amounts
// ============================================================
/**
* Validation schema for the non-fungible token configuration within a token field.
*
* ```
* {
* "inputs|outputs": {
* "[id]": {
* "token": {
* "nft": { } ← this schema
* }
* }
* }
* }
* ```
*/
export const xoTemplateNonFungibleTokenDetailsSchema = z
.object({
capability: z
.union([ xoTemplateNftCapabilitySchema, z.string() ])
.optional()
.describe('The capability of the NFT. May be a known capability value or a CashASM expression resolving to a capability.'),
commitment: z.string().optional().describe('The commitment data for the NFT, as a string or CashASM expression resolving to a commitment.'),
})
.strict();
/**
* Validation schema for the token configuration on inputs and outputs.
*
* ```
* {
* "inputs|outputs": {
* "[id]": {
* "token": { } ← this schema
* }
* }
* }
* ```
*/
export const xoTemplateTokenSchema = z
.object({
category: z.string().optional().describe('The category of the token, as a string or CashASM expression resolving to a category.'),
amount: z
.union([ z.bigint(), z.string(), z.null() ])
.optional()
.describe('The amount of fungible tokens as a bigint, a CashASM expression resolving to a bigint, or null indicating no FT is present.'),
nft: xoTemplateNonFungibleTokenDetailsSchema
.nullable()
.optional()
.describe('Non-fungible token configuration. Null indicates no NFT is present.'),
})
.strict();
/**
* Validation schema for the asset amounts configuration. Used by omitChangeAmounts on inputs
* and by balance on locking scripts, outputs, and their roles.
*/
export const xoTemplateAssetAmountsSchema = z
.object({
/**
* The satoshi amount.
* - `Satoshis`: A specific bigint amount.
* - `string`: A CashASM expression that resolves to the amount.
* - `true`: all, i.e. the entire amount
*/
satoshis: z
.union([ satoshisSchema, z.string(), z.literal(true) ])
.optional()
.describe('The satoshi amount. Accepts a bigint for a specific value, a CashASM expression, or true for the entire amount.'),
/**
* The fungible token amount.
* - `FungibleTokenAmount`: A specific bigint amount.
* - `string`: A CashASM expression that resolves to the amount.
* - `true`: all, i.e. the entire amount
*/
fungibleTokens: z
.union([ z.bigint(), z.string(), z.literal(true) ])
.optional()
.describe('The fungible token amount. Accepts a bigint for a specific value, a CashASM expression, or true for the entire amount.'),
/**
* Whether a non-fungible token is present (0 for absent, 1 for present),
* or a CashASM expression that evaluates to 0 or 1.
* - `true`: resolves to 1 if an NFT is present, or 0 if none is present. Use this when
* the NFT is optional, to express that the NFT is estimated to be part of the balance
* if present, or absent from it if not.
* - `0`: None, i.e. nothing is expected to be included
* - `1`: present and complete, as value > 1 does not make sense for non-fungible tokens
* - `string`: A CashASM expression that evaluates to 0 or 1.
*/
nonfungibleTokens: z
.union([ z.literal(0), z.literal(1), z.string(), z.literal(true) ])
.optional()
.describe('Whether an NFT is present: 0 for absent, 1 for present, a CashASM expression evaluating to 0 or 1, or true to estimate the NFT as part of the balance if present, or absent from it if not.'),
})
.strict();
// ============================================================
// Locking Scripts
// ============================================================
/**
* Validation schema for the state configuration shared by a locking script and its individual roles.
* Declares which variables and secrets are tracked in the on-chain state for a given participant.
*
* ```
* {
* "lockingScripts": {
* "[id]": {
* "state": { "variables": [], "secrets": [] } ← this schema
* "roles": {
* "[roleId]": {
* "state": { "variables": [], "secrets": [] } ← this schema
* }
* }
* }
* }
* }
* ```
*/
export const xoTemplateStateSchema = z
.object({
variables: z.array(z.string()).optional().describe('List of variable identifiers to track in state.'),
secrets: z.array(z.string()).optional().describe('List of secret identifiers to track in state.'),
})
.strict();
/**
* Validation schema for a role definition for a locking script.
*
* ```
* {
* "lockingScripts": {
* "[id]": {
* "roles": {
* "[roleId]": { } ← this schema
* }
* }
* }
* }
* ```
*/
export const xoTemplateLockingScriptRoleSchema = xoTemplateViewPropertiesSchema
.partial()
.extend({
state: xoTemplateStateSchema.optional().describe('List of items to track as state for this role.'),
actions: z.array(xoTemplateActionIntentSchema).optional().describe('List of action references available to this role.'),
balance: xoTemplateAssetAmountsSchema.partial().optional().describe('Estimated ownership in the optional set of asset amounts specified.'),
selectable: z.boolean().optional().describe('Whether outputs locked to this script should be available for coin selection.'),
privacy: z
.union([ z.number(), z.string() ])
.optional()
.describe('Privacy level for outputs locked to this script. A numeric level or a CashASM expression that evaluates to a privacy level.'),
})
.strict();
/**
* Validation schema for a locking script definition.
*
* ```
* {
* "lockingScripts": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateLockingScriptSchema = xoTemplateViewPropertiesSchema
.extend({
lockingType: xoTemplateLockingTypeSchema.optional().describe('The type of locking mechanism. Defaults to p2s if not specified.'),
lockingBytecode: z.string().describe('The locking script bytecode.'),
unlockingBytecode: z.string().optional().describe('Optional default unlocking bytecode when used in automatic coin selection.'),
actions: z.array(xoTemplateActionIntentSchema).optional().describe('The actions available for this locking script.'),
state: xoTemplateStateSchema.optional().describe('List of items to track as state for all participants.'),
balance: xoTemplateAssetAmountsSchema.partial().optional().describe('Estimated ownership in the optional set of asset amounts specified.'),
selectable: z.boolean().optional().describe('Whether outputs locked to this script should be available for coin selection.'),
// Might be levels or tags
privacy: z
.union([ z.number(), z.string() ])
.optional()
.describe('Privacy level for outputs locked to this script. A numeric level or a CashASM expression that evaluates to a privacy level.'),
roles: z
.record(z.string(), xoTemplateLockingScriptRoleSchema)
.optional()
.describe('Specific context for each role participating in this locking script.'),
})
.strict();
// ============================================================
// Inputs
// ============================================================
/**
* Validation schema for an input definition in the template. Extends view properties with optional
* satoshi value, token configuration, and other transaction level fields.
*
* ```
* {
* "inputs": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateInputSchema = xoTemplateViewPropertiesSchema
.extend({
valueSatoshis: z
.union([ satoshisSchema, z.string() ])
.optional()
.describe('The amount of satoshis for this input as a bigint or a CashASM expression resolving to the amount.'),
token: xoTemplateTokenSchema.nullable().optional().describe('Token configuration for this input.'),
sequenceNumber: z
.union([ z.number(), z.string() ])
.optional()
.describe('The sequence number of this input as a specific number or a CashASM expression.'),
unlockingScript: z.string().optional().describe('Identifier of the unlocking script to use for the UTXO provided for this input.'),
omitChangeAmounts: xoTemplateAssetAmountsSchema
.optional()
.describe('Amount of change that should be omitted from the automatic change handling. WARNING: Setting this can result in loss of funds!'),
})
.strict();
// ============================================================
// Outputs
// ============================================================
/**
* Validation schema for an output definition. Extends the locking script schema so that
* every output inherits the same locking script fields and adds output-specific fields.
*
* ```
* {
* "outputs": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateOutputSchema = xoTemplateLockingScriptSchema
.omit({ lockingType: true, lockingBytecode: true, unlockingBytecode: true })
.extend({
lockingScript: z.string().describe('Identifier of the locking script to use for this output.'),
valueSatoshis: z
.union([ satoshisSchema, z.string() ])
.optional()
.describe('The amount of satoshis for this output as a bigint or a CashASM expression resolving to the amount.'),
token: xoTemplateTokenSchema.nullable().optional().describe('Token configuration for this output.'),
})
.strict();
// ============================================================
// Transactions
// ============================================================
/**
* Validation schema for a transaction input reference for a transaction definition.
*
* ```
* {
* "transactions": {
* "[id]": {
* "inputs": [
* { "input": "..." } ← this schema
* ]
* }
* }
* }
* ```
*/
export const xoTemplateTransactionInputSchema = z
.object({
input: z.string().describe('The input definition identifier.'),
inputIndex: z.number().optional().describe('Optional index of this input in the transaction.'),
})
.strict();
/**
* Validation schema for a transaction output reference for a transaction definition.
*
* ```
* {
* "transactions": {
* "[id]": {
* "outputs": [
* { "output": "..." } ← this schema
* ]
* }
* }
* }
* ```
*/
export const xoTemplateTransactionOutputSchema = z
.object({
output: z.string().describe('The output definition identifier.'),
outputIndex: z.number().optional().describe('Optional index of this output in the transaction.'),
})
.strict();
/**
* Validation schema for role-specific data for a transaction definition.
*
* ```
* {
* "transactions": {
* "[id]": {
* "roles": {
* "[roleId]": { } ← this schema
* }
* }
* }
* }
* ```
*/
export const xoTemplateTransactionRoleDataSchema = xoTemplateViewPropertiesSchema
.partial()
.extend({
inputs: z.array(xoTemplateTransactionInputSchema).optional().describe('The inputs required for this role.'),
outputs: z.array(xoTemplateTransactionOutputSchema).optional().describe('The outputs required for this role.'),
})
.strict();
/**
* Validation schema for a transaction template definition.
*
* ```
* {
* "transactions": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateTransactionSchema = xoTemplateViewPropertiesSchema
.extend({
version: z.number().optional().describe('The version of the transaction.'),
locktime: z.number().optional().describe('The locktime for this transaction.'),
inputs: z.array(xoTemplateTransactionInputSchema).describe('The inputs for this transaction.'),
outputs: z.array(xoTemplateTransactionOutputSchema).describe('The outputs for this transaction.'),
roles: z
.record(z.string(), xoTemplateTransactionRoleDataSchema)
.optional()
.describe('Specific context for each role participating in this transaction.'),
composable: z.boolean().optional().describe('Whether this transaction can be composed with other transactions.'),
})
.strict();
// ============================================================
// Template Data
// ============================================================
/**
* Validation schema for a constant value definition.
*
* ```
* {
* "constants": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateConstantSchema = xoTemplateViewPropertiesSchema
.extend({
type: xoTemplatePrimitiveTypeSchema.describe('The data type of this constant.'),
value: z.unknown().describe('The value of this constant.'),
hint: z.string().optional().describe('An optional hint to help apps and users understand what this constant represents.'),
})
.strict();
/**
* Validation schema for a data field definition.
*
* ```
* {
* "data": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateDataSchema = z
.object({
type: xoTemplatePrimitiveTypeSchema.describe('The data type of this data field.'),
value: z.unknown().describe('The value for this data field.'),
hint: z.string().optional().describe('An optional hint to help apps and users understand this data field.'),
})
.strict();
/**
* Validation schema for an import default value intent. Extends the base intent with optional
* view properties that the engine evaluates at runtime to produce human-readable output.
*
* ```
* {
* "variables": {
* "[id]": {
* "importDefaultValue": { } ← this schema
* }
* }
* }
* ```
*/
export const xoTemplateImportDefaultValueSchema = xoTemplateIntentSchema
// .shape unwraps the ZodObject to the raw field map { name, description, icon } with each field made optional
.extend(xoTemplateViewPropertiesSchema.partial().shape)
.strict();
/**
* Validation schema for a variable definition.
*
* ```
* {
* "variables": {
* "[id]": { } ← this schema
* }
* }
* ```
*/
export const xoTemplateVariableSchema = xoTemplateViewPropertiesSchema
.extend({
type: xoTemplatePrimitiveTypeSchema.optional().describe('The data type of this variable.'),
hint: z.string().optional().describe('A hint to help users understand what value to provide.'),
// A neutral intent that the engine uses to populate the default value for this variable.
// View properties (name, description, icon) may contain CashASM expressions that the
// engine evaluates at runtime to produce human-readable output. The engine overrides
// whatever values are set here when resolving the variable for a participant.
importDefaultValue: xoTemplateImportDefaultValueSchema
.optional()
.describe('A neutral intent that the engine uses to populate the default value for this variable.'),
})
.strict();
// ============================================================
// Template Resources
// ============================================================
/**
* Validation schema for a resource reference attached to a template element. Extends view
* properties with a URL pointing to external documentation or tooling.
*
* ```
* {
* "resources": [
* { "name": "...", "description": "...", "url": "..." } ← this schema
* ]
* }
* ```
*/
export const xoTemplateResourceSchema = xoTemplateViewPropertiesSchema
.extend({
url: z.string().describe('The URL for this resource.'),
})
.strict();
/**
* Validation schema for an icon reference.
*
* ```
* {
* "icons": [
* { "name": "...", "hash": "..." } ← this schema
* ]
* }
* ```
*/
export const xoTemplateIconSchema = xoTemplateViewPropertiesSchema
.pick({ name: true })
.extend({
hash: z.string().describe('The identifier of the icon.'),
})
.strict();
// ============================================================
// Defaults
// ============================================================
/**
* Validation schema for the defaults block of a template.
*
* ```
* {
* "defaults": { } ← this schema
* }
* ```
*/
export const xoTemplateDefaultsSchema = z
.object({
change: xoTemplateOutputIntentSchema.optional().describe('Instructions for how to construct automated change output.'),
})
.strict();
// ============================================================
// Template
// ============================================================
/**
* Validation schema for the full XOTemplate type.
*/
export const xoTemplateSchema = xoTemplateViewPropertiesSchema
.extend({
$schema: z
.string()
.describe('The URI that identifies the JSON Schema used by this template. This enables documentation, autocompletion, and validation in JSON documents.'),
version: z.string().optional().describe('A string identifying the version of this template.'),
supported: z.array(bchVmVersionSchema).min(1).describe('The BCH VM versions that this template supports. At least one version is required.'),
defaults: xoTemplateDefaultsSchema.optional().describe('Optional default settings used in this template.'),
roles: z.record(z.string(), xoTemplateViewPropertiesSchema).describe('The roles defined in this template.'),
start: z.array(xoTemplateActionIntentSchema).describe('A list of entry points defining which actions are available at the start.'),
actions: z.record(z.string(), xoTemplateActionSchema).describe('The actions defined in this template.'),
data: z.record(z.string(), xoTemplateDataSchema).optional().describe('The data fields defined in this template.'),
transactions: z.record(z.string(), xoTemplateTransactionSchema).optional().describe('The transaction templates defined in this template.'),
inputs: z.record(z.string(), xoTemplateInputSchema).describe('The inputs defined in this template.'),
outputs: z.record(z.string(), xoTemplateOutputSchema).describe('The outputs defined in this template.'),
lockingScripts: z.record(z.string(), xoTemplateLockingScriptSchema).describe('The locking script templates defined in this template.'),
scripts: z
.record(z.string(), z.string())
.describe('Scripts used in this template. Keys are script identifiers, values are bytecode or CashASM expressions.'),
constants: z.record(z.string(), xoTemplateConstantSchema).optional().describe('The constants defined in this template.'),
variables: z
.record(z.string(), xoTemplateVariableSchema)
.optional()
.describe("The variables that must be provided for use in the template's scripts."),
resources: z.array(xoTemplateResourceSchema).optional().describe('Resource references providing external documentation or tooling links.'),
icons: z.array(xoTemplateIconSchema).optional().describe('The icons available for use throughout the template.'),
scenarios: z.unknown().optional().describe('The scenarios defined in this template.'),
})
.strict();