-
Notifications
You must be signed in to change notification settings - Fork 2
3 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:
- Pallet-level DSL (Rust macros) for your Substrate runtime.
- JSON Schema for client codegen (TS/C#/Python).
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,
}
}| 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 |
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.
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
-
Custom Types: Implement the
SageFieldTypetrait for your Rust struct or enum. The codegen will pick it up if you deriveSageField. -
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.
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.