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

MetagameComponent

The MetagameComponent provides deeper integration between a platform and the EGS token system. It handles minter registration, callback routing, and optional context management.

When to Use It

Use MetagameComponent when your platform:

  • Needs to receive automatic callbacks on score updates and game completions
  • Wants to attach per-token context data (quest info, tournament metadata)
  • Benefits from automatic minter registration

For simple mint-and-read use cases, direct minting is sufficient.

IMetagame Interface

pub const IMETAGAME_ID: felt252 =
    0x7997c74299c045696726f0f7f0165f85817acbb0964e23ff77e11e34eff6f2;
 
#[starknet::interface]
pub trait IMetagame<TContractState> {
    /// Address of the optional context contract
    fn context_address(self: @TContractState) -> ContractAddress;
 
    /// Default MinigameToken address this metagame interacts with
    fn default_token_address(self: @TContractState) -> ContractAddress;
}

Composing the Component

#[starknet::contract]
mod MyPlatform {
    use game_components_metagame::metagame::MetagameComponent;
    use openzeppelin_introspection::src5::SRC5Component;
 
    component!(path: MetagameComponent, storage: metagame, event: MetagameEvent);
    component!(path: SRC5Component, storage: src5, event: SRC5Event);
 
    #[abi(embed_v0)]
    impl MetagameImpl = MetagameComponent::MetagameImpl<ContractState>;
    #[abi(embed_v0)]
    impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
 
    #[storage]
    struct Storage {
        #[substorage(v0)]
        metagame: MetagameComponent::Storage,
        #[substorage(v0)]
        src5: SRC5Component::Storage,
    }
 
    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        MetagameEvent: MetagameComponent::Event,
        #[flat]
        SRC5Event: SRC5Component::Event,
    }
 
    #[constructor]
    fn constructor(
        ref self: ContractState,
        token_address: ContractAddress,
        context_address: ContractAddress,
    ) {
        self.metagame.initializer(token_address, context_address);
    }
}

Initialization

The MetagameComponent's initializer sets up:

  1. The default MinigameToken address
  2. An optional context contract address
  3. Registers the IMETAGAME_ID interface via SRC5
self.metagame.initializer(
    token_address,    // MinigameToken contract
    context_address,  // Optional context contract (zero = none)
);

Context Extension

Metagames can attach per-token context data. This is useful for:

  • Tournament metadata (round number, bracket position)
  • Quest context (which quest, what reward tier)
  • Platform-specific data

GameContextDetails Struct

#[derive(Drop, Serde, Clone)]
pub struct GameContextDetails {
    pub name: ByteArray,               // "Season 2 Tournament"
    pub description: ByteArray,        // "Round of 16, Bracket A"
    pub id: Option<u32>,              // Optional context ID
    pub context: Span<GameContext>,   // Key-value pairs
}
 
#[derive(Drop, Serde, Clone)]
pub struct GameContext {
    pub name: ByteArray,   // "bracket"
    pub value: ByteArray,  // "A"
}

Pass context when minting:

let token_id = token.mint(MintParams {
    game_address,
    context: Option::Some(GameContextDetails {
        name: "Season 2 Tournament",
        description: "Round of 16",
        id: Option::Some(42),
        context: array![
            GameContext { name: "bracket", value: "A" },
            GameContext { name: "round", value: "16" },
        ].span(),
    }),
    // ... other params
});

IMetagameContext Interface

If your metagame implements context, register IMETAGAME_CONTEXT_ID:

pub const IMETAGAME_CONTEXT_ID: felt252 =
    0x1633419b5abcc4c0bbed8bd37a363fbe6de5bd25908761ab6dcda6a9b598ca9;
 
#[starknet::interface]
pub trait IMetagameContext<TState> {
    fn has_context(self: @TState, token_id: felt252) -> bool;
}
 
#[starknet::interface]
pub trait IMetagameContextDetails<TState> {
    fn context_details(self: @TState, token_id: felt252) -> GameContextDetails;
}

Minting via MetagameComponent

The component provides convenience methods for minting:

// Mint with context
let params = MintGameParams {
    player_name: Option::Some('Alice'),
    settings_id: Option::Some(2),
    start: Option::None,
    end: Option::None,
    objective_id: Option::None,
    context: Option::Some(my_context),
    client_url: Option::None,
    renderer_address: Option::None,
    skills_address: Option::None,
    to: player_address,
    soulbound: true,
    paymaster: false,
    salt: 0,
    metadata: 0,
};
 
let token_id = self.metagame.mint(game_address, params);