ree-exchange-sdk 0.7.0

REE exchange rust SDK.
Documentation

The REE Exchange SDK provides a set of types and interfaces for building REE exchanges.

Example

use candid::{CandidType, Deserialize};
use ic_cdk::{query, update};
use ic_stable_structures::{Storable, storable::Bound};
use ree_exchange_sdk::{
    prelude::*,
    {CoinBalance, Txid, Utxo},
};
use serde::Serialize;

/// The state stored in the pool.
#[derive(CandidType, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct DummyPoolState {
    pub txid: Txid,
    pub nonce: u64,
    pub coin_reserved: Vec<CoinBalance>,
    pub btc_reserved: u64,
    pub utxos: Vec<Utxo>,
    pub attributes: String,
}

/// The state must implement the `Storable` trait
impl Storable for DummyPoolState {
    const BOUND: Bound = Bound::Unbounded;

    fn to_bytes(&self) -> std::borrow::Cow<[u8]> {
        let bytes = bincode::serialize(&self).unwrap();
        std::borrow::Cow::Owned(bytes)
    }

    fn into_bytes(self) -> Vec<u8> {
        bincode::serialize(&self).unwrap();
    }

    fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self {
        bincode::deserialize(bytes.as_ref()).unwrap()
    }
}

/// The state view must implement the `StateView` trait
impl StateView for DummyPoolState {
    fn inspect_state(&self) -> StateInfo {
        StateInfo {
            txid: self.txid,
            nonce: self.nonce,
            coin_reserved: self.coin_reserved.clone(),
            btc_reserved: self.btc_reserved,
            utxos: self.utxos.clone(),
            attributes: "{}".to_string(),
        }
    }
}

/// Entry point for the exchange.
#[exchange]
pub mod exchange {
    use super::*;

    #[pools]
    pub struct DummyPools;

    impl Pools for DummyPools {
        type State = DummyPoolState;

        const POOL_MEMORY: u8 = 102;

        const BLOCK_MEMORY: u8 = 100;

        const TRANSACTION_MEMORY: u8 = 101;

        fn network() -> Network {
            Network::Testnet4
        }

        // This is optional
        fn finalize_threshold() -> u32 {
            60
        }
    }

    /// This is optional
    #[hook]
    impl Hook for DummyPools {
        /// This function is called when a new block is received, before any processing.
        fn on_block_received(_args: NewBlockInfo) {}

        /// This function is called when a transaction is dropped from the mempool.
        fn on_state_reverted(_address: String, _txid: Txid) {}

        /// This function is called when a transaction is confirmed in a block.
        fn on_state_confirmed(_address: String, _txid: Txid, _block: Block) {}

        /// This function is called when a transaction reaches the finalize threshold.
        fn on_state_finalized(_address: String, _txid: Txid, _block: Block) {}

        /// This function is called after a new block is processed.
        fn on_block_processed(_args: NewBlockInfo) {}
    }

    #[update]
    pub fn new_pool(args: Metadata) {
        let pool = Pool::new(args.clone());
        DummyPools::insert(pool.clone());
        let loaded = DummyPools::get(&args.address);
        assert_eq!(loaded, Some(pool), "Pool not loaded correctly");
        let (addr, p) = DummyPools::iter().next().unwrap();
        assert_eq!(addr, args.address, "Pool address mismatch");
        assert_eq!(Some(p), loaded, "Pool data mismatch");
        DummyPools::remove(&args.address);
        let loaded = DummyPools::get(&args.address);
        assert!(loaded.is_none(), "Pool not removed correctly");
    }

    // returns essential pool information so the client could construct a PSBT
    #[query]
    pub fn pre_swap(addr: String) -> Option<StateInfo> {
        DummyPools::get(&addr).and_then(|pool| {
            pool.states()
                .iter()
                .map(|s| s.inspect_state())
                .last()
                .clone()
        })
    }

    #[action(name = "swap")]
    pub async fn execute_swap(_args: ExecuteTxArgs) -> ExecuteTxResponse {
        // do check and sign the PSBT
        Ok("Transaction executed successfully".to_string())
    }
}