#soroban-kit: State Machine module | Commitment scheme | Type Safe Storage

9 messages · Page 1 of 1 (latest)

storm shell
#

Hi everyone!

I just published the state-machine module I developed for several game-related Soroban smart contracts to crates.io and GitHub to make it available to the wider community (open source MIT License). The module itself is a generic state machine implementation, not specific to games, and can be used for modeling concurrent state executions and complex runtime interactions for a wide range of use cases (see below).

FEATURES

  • Easy setup via procedural attribute macros and traits (declarative macro available too).
  • Flexible state concurrency via regions.
  • Runtime behavior modeling via extended state variables.
  • Transition control with guards and effects.
  • State persistence with Soroban storage.

SIMPLE USAGE

Using the #[state_machine] attribute macro you can quickly configure a function for state transition within your finite state machine.

#[state_machine( state = "State:Ready:app", region = "Region:Specific:address", transition = true, storage = "instance" )] fn app_login(&self, env: &Env, address: &Address, app: &App) { }

TRANSITIONS

The attribute macro forces the function to panics if the state is invalid preventing any code execution inside the function body.

You can implement the TransitionHandler trait to apply guards and effects to control state transition. For example, this allows you to implement a time based / ledger based state transition just before state validation occurs.

EXAMPLE USE CASES

The state machine allows you to model complex state machine behaviors for concurrent users and also define extended states at runtime. Check out the Coffee Machine and Game Lobby examples in the repo.

Here are some more use case examples:

  • Independent NFT minting windows for users based on variable attributes.
  • Markets with concurrent auctions and bidders.
  • Multiplayer game lobby with teams and individual access.
  • Online app with concurrent users, variable access rights...

LINKS

soroban-kit: https://crates.io/crates/soroban-kit
code repo: https://github.com/FredericRezeau/soroban-kit

Note that all modules in crates are feature flagged (with feature forwarding), so you can compile just what you need and nothing more!
e.g., To configure the crate with state-machine module only:
[dependencies.soroban-macros] version = "0.1.2" default-features = false features = ["state-machine"]

Hope you find it useful.

storm shell
#

SOROBAN-KIT UPDATE

Just updated soroban-kit to version 0.1.4.

https://github.com/FredericRezeau/soroban-kit

The update features the commitment scheme (commit-reveal) attribute macros, allowing easy implementation of the scheme in soroban smart contracts (use cases: voting systems, zero-knowledge proofs, pseudo-random number generation seeding and more...).

The new commit and reveal attributes can be paired with the state-machine attribute to manage the commit and reveal phases for multiple parties.

#[commit]
#[state_machine(state = "Phase:Committing")]
    fn vote(&self, env: &Env, hash: &BytesN<32>) {
}

#[reveal]
#[state_machine(state = "Phase:Revealing")]
    fn reveal(&self, env: &Env, data: &Bytes) {
}

A comprehensive polling station demo is also provided to showcase the pairing of state-machine and commit-reveal to allow multiple voters to cast concurrently (and in any order) while controlling the global phases and transitions. An implementation of the Rock-Paper-Scissors game is also provided in the hello-soroban-kit contract demo (tests).

Enjoy!

#

soroban-kit: State Machine module | Commitment scheme | Type Safe Storage

bold wedge
#

Really cool. I like the commit reveal mechanism but I wonder what is the application of such a mechanism? It seems that it would allow to prove ownership of a secret without using the account authentication, but this can only be used once.

storm shell
# bold wedge Really cool. I like the commit reveal mechanism but I wonder what is the applica...

Thanks!

Basically the commit-reveal scheme covers more general use cases, few examples:

Vote confidentiality, sealed bids auctions... voters/bidders can have a phase for X ledgers during which they commit without revealing their choice/bid.

Activities requiring simultaneous action (like the game rock-paper-scissors) where participants can commit to their choices in advance, and once all commitments are made, their moves/action is revealed and verified against the previously committed hashes.

Another use case is PRNG seeding where commit-reveal can be used to generate an unpredictable seed between parties.

Here are a few implementation examples:

polling station: https://github.com/FredericRezeau/soroban-kit/blob/main/crates/soroban-macros/tests/commit-reveal-tests.rs
Rock-Paper-Scissors: https://github.com/FredericRezeau/soroban-kit/blob/main/crates/hello-soroban-kit/src/examples/example_rock_paper_scissors.rs

bold wedge
#

I see, this is then a voluntary reveal since the image is only known by the user (except if some central platform would act as a proxy).
This kind of mechanic bring several questions🤣 I mean for a sealed auction I suppose you will need to provide a fee only redeemed on the reveal or something like that.

storm shell
# bold wedge I see, this is then a voluntary reveal since the image is only known by the us...

Yes, 💯 each use case needs to adopt strategies for participant punishment e.g. like you said, sealed bid auctions could ask for a commit deposit, random winner use case (PRNG seeding) may just exclude any non revealer from the draw, for a game it could be a deposit + loss after x time (the state-machine allows the implementation of guards for example to force state transitions based on time-based conditions).

storm shell
#

soroban-kit update 0.1.6

Streamlined circuit breaker pattern implementation in Soroban smart contracts.

This pattern is commonly used in Solidity smart contracts, for example through the popular Pausable contract module from OpenZeppelin (USDC...) to safeguard stakeholders in the event of unexpected contract behavior or external attacks.

Simple usage via 2 attribute macros when_opened and when_closed (full documentation and examples here: https://github.com/FredericRezeau/soroban-kit?tab=readme-ov-file#circuit-breaker):

`
#[derive(CircuitBreaker)]
struct Circuit;

impl Circuit {
    // bid() is usable when the circuit is closed (operational).
    #[when_closed]
    fn bid(&self, env: &Env) {
    }

    // emergency_stop() triggers a state change.
    #[when_closed(trigger = true)]
    fn emergency_stop(&self, env: &Env) {
    }

    // upgrade() also restores bid() operation.
    #[when_opened(trigger = true)]
    fn upgrade(&self, env: &Env) {
      // e.g., upgrade contract.
    }
}

`

The macros also support regions for the creation of composite circuits i.e., grouping operations in sub circuits so for example you can choose which functionality to pause.

storm shell
#

soroban-kit update 0.1.8
https://github.com/FredericRezeau/soroban-kit?tab=readme-ov-file#oracle

Walkthrough here: https://dev.to/kyung_jin/oracles-with-soroban-smart-contracts-a-practical-and-flexible-on-chain-framework-f3g

Oracle feature with oracle_broker and oracle_subscriber attribute macros.

The macros can be used to automatically generate the interface and implementation for synchronous and asynchronous communication (pub-sub pattern) via cross-contract calls. The system allows subscriber contracts to establish multiple connections to broker contracts and vice-versa. Types for topic and data are customizable via macro arguments.

Implement the oracle broker interface for your contract.```
#[contract]
#[oracle_broker(Bytes, MyDataType)]
pub struct OracleContract;

Implement the oracle subscriber interface for your contract.```
    #[contract]
    #[oracle_subscriber(Bytes, MyDataType)]
    pub struct TestContract;

The oracle_subscriber and oracle_broker are now set for synchronous and asynchronous communication. You can handle events/hooks by implementing the soroban_kit::oracle::Events trait```
impl oracle::Events<Bytes, MyDataType> for HelloContract {
fn on_request(env: &Env, _topic: &Bytes, envelope: &oracle::Envelope) {
}

fn on_sync_receive(env: &Env, topic: &Bytes, envelope: &oracle::Envelope, data: &MyDataType) {
}

fn on_async_receive(env: &Env, topic: &Bytes, envelope: &oracle::Envelope, data: &MyDataType) {
}

}

Check out the `oracle-soroban-kit` contract for a basic oracle broker implementation showcasing fee collection from subscribers, with the ability to serve data both synchronously and asynchronously based on availability.