Skip to content

3 Asset Specification DSL

Cedric Decoster edited this page Jun 19, 2025 · 1 revision

Asset Specification DSL

The Asset Specification DSL is a core part of SAGE, enabling you to declaratively define your on-chain asset types without writing boiler‑plate Rust storage code. It consists of two complementary representations:

  1. Pallet-level DSL (Rust macros) for your Substrate runtime.
  2. JSON Schema for client codegen (TS/C#/Python).

1. Pallet-level DSL (Rust)

Use the #[asset_schema!] macro in your runtime pallet-sage configuration to define one or more assets:

// In your runtime's lib.rs
use pallet_sage::asset_schema;
use frame_support::sp_std::vec::Vec;

asset_schema! {
    /// A player character with health and experience.
    pub struct Player {
        /// Current health points (0..=100)
        health: u8,
        /// Experience points earned
        xp: u128,
    }

    /// A consumable item that restores health.
    pub struct Consumable {
        /// Amount of health restored
        healing_power: u8,
        /// One-time use flag (always true)
        single_use: bool,
    }

    /// On-chain currency token
    pub struct Currency {
        /// Balance in smallest units
        amount: u128,
    }
}

1.1 Field Types

Type Rust Definition Description
u8, u16 u8, u16 Unsigned integer fields
u32, u64 u32, u64 Larger counters or IDs
u128 u128 High‑precision balances
bool bool Flags
Vec<T> Vec<T> Variable‑length lists
BTreeMap<K, V> BTreeMap<K, V> Mappings (requires feature in runtime)
Custom Enums enum MyEnum { ... } Finite choice fields

1.2 Indices & Ownership

By default, every asset gains an owner: AccountId index. For custom indices:

asset_schema! {
    pub struct LandPlot {
        area: u32,
        geojson: Vec<u8>,
        #[index(by = "geohash")] location_hash: u64,
    }
}

Generates a secondary index locations: map u64 => Vec<AssetId> keyed by location_hash.


2. JSON Schema

To power client code generation, SAGE emits a JSON schema of your assets:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "Player": {
      "type": "object",
      "properties": {
        "health": { "type": "integer", "minimum": 0, "maximum": 100 },
        "xp": { "type": "string", "pattern": "^[0-9]+$" }
      },
      "required": ["health","xp"]
    }
  }
}

Clients (TS/C#/Python) consume this schema to generate:

  • TypeScript interfaces for asset payloads
  • C# classes with attributes for Unity
  • Python dataclasses for analytics scripts

3. Extending the DSL

  • Custom Types: Implement the SageFieldType trait for your Rust struct or enum. The codegen will pick it up if you derive SageField.
  • Validation Hooks: Attach Rust functions for complex validation beyond simple range checks using #[validate(func = "my_custom_validator")] on fields.
  • Metadata: Add arbitrary JSON metadata via #[metadata] on any field; this is stored off‑chain in the indexer.

4. Example Usage in Transitions

Define a transition that consumes a Consumable and updates Player:

transition! {
    name: "eat",
    inputs: [Player, Consumable],
    outputs: [Player],
    pre_conditions: [caller_owns(Input0), type_is(Input0, "Player"), type_is(Input1, "Consumable")],
    post_logic: "Input0.health = min(Input0.health + Input1.healing_power, 100);"
}

The Asset Specification DSL seamlessly integrates with the Transition & Rule Language, sharing the same field names and types.


5. References

Clone this wiki locally