chia-sdk-bindings 0.34.0

Underlying implementation of chia-wallet-sdk bindings.
Documentation
use std::sync::{Arc, Mutex};

use bindy::Result;
use chia_bls::PublicKey;
use chia_protocol::{Bytes, Bytes32};
use chia_sdk_driver::SpendContext;
use chia_sdk_types::conditions::{self, Memos, TradePrice};
use clvm_traits::{FromClvm, ToClvm};
use clvmr::NodePtr;
use paste::paste;

use crate::{Clvm, Program};

trait Convert<T> {
    fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<T>;
}

impl Convert<Program> for NodePtr {
    fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Program> {
        Ok(Program(clvm.clone(), self))
    }
}

impl Convert<NodePtr> for Program {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<NodePtr> {
        Ok(self.1)
    }
}

impl Convert<PublicKey> for PublicKey {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<PublicKey> {
        Ok(self)
    }
}

impl Convert<Bytes> for Bytes {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Bytes> {
        Ok(self)
    }
}

impl Convert<Bytes32> for Bytes32 {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Bytes32> {
        Ok(self)
    }
}

impl Convert<u64> for u64 {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u64> {
        Ok(self)
    }
}

impl Convert<u32> for u32 {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u32> {
        Ok(self)
    }
}

impl Convert<u8> for u8 {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<u8> {
        Ok(self)
    }
}

impl Convert<TradePrice> for TradePrice {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<TradePrice> {
        Ok(self)
    }
}

impl Convert<Memos<NodePtr>> for Option<Program> {
    fn convert(self, _clvm: &Arc<Mutex<SpendContext>>) -> Result<Memos<NodePtr>> {
        Ok(self.map_or(Memos::None, |program| Memos::Some(program.1)))
    }
}

impl Convert<Option<Program>> for Memos<NodePtr> {
    fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Option<Program>> {
        Ok(match self {
            Memos::None => None,
            Memos::Some(value) => Some(Program(clvm.clone(), value)),
        })
    }
}

impl<T, U> Convert<Vec<U>> for Vec<T>
where
    T: Convert<U>,
{
    fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Vec<U>> {
        self.into_iter()
            .map(|value| T::convert(value, clvm))
            .collect()
    }
}

impl<T, U> Convert<Option<U>> for Option<T>
where
    T: Convert<U>,
{
    fn convert(self, clvm: &Arc<Mutex<SpendContext>>) -> Result<Option<U>> {
        self.map(|value| T::convert(value, clvm)).transpose()
    }
}

macro_rules! conditions {
    ( $( $condition:ident $( < $( $generic:ty ),* > )? { $function:ident( $( $name:ident: $ty:ty ),* ) }, )* ) => {
        $( #[derive(Clone)]
        pub struct $condition {
            $( pub $name: $ty, )*
        } )*

        $( paste! {
            impl Clvm {
                pub fn $function( &self, $( $name: $ty ),* ) -> Result<Program> {
                    let mut ctx = self.0.lock().unwrap();
                    $( let $name = Convert::convert($name, &self.0)?; )*
                    let ptr = conditions::$condition $( ::< $( $generic ),* > )? ::new( $( $name ),* )
                    .to_clvm(&mut **ctx)?;
                    Ok(Program(self.0.clone(), ptr))
                }
            }

            impl Program {
                #[allow(unused)]
                pub fn [< parse_ $function >]( &self ) -> Result<Option<$condition>> {
                    let ctx = self.0.lock().unwrap();

                    let Some(condition) = conditions::$condition $( ::< $( $generic ),* > )? ::from_clvm(&**ctx, self.1).ok() else {
                        return Ok(None);
                    };

                    Ok(Some($condition {
                        $( $name: Convert::convert(condition.$name, &self.0.clone())?, )*
                    }))
                }
            }
        } )*
    };
}

conditions!(
    Remark<NodePtr> {
        remark(rest: Program)
    },
    AggSigParent {
        agg_sig_parent(public_key: PublicKey, message: Bytes)
    },
    AggSigPuzzle {
        agg_sig_puzzle(public_key: PublicKey, message: Bytes)
    },
    AggSigAmount {
        agg_sig_amount(public_key: PublicKey, message: Bytes)
    },
    AggSigPuzzleAmount {
        agg_sig_puzzle_amount(public_key: PublicKey, message: Bytes)
    },
    AggSigParentAmount {
        agg_sig_parent_amount(public_key: PublicKey, message: Bytes)
    },
    AggSigParentPuzzle {
        agg_sig_parent_puzzle(public_key: PublicKey, message: Bytes)
    },
    AggSigUnsafe {
        agg_sig_unsafe(public_key: PublicKey, message: Bytes)
    },
    AggSigMe {
        agg_sig_me(public_key: PublicKey, message: Bytes)
    },
    CreateCoin {
        create_coin(puzzle_hash: Bytes32, amount: u64, memos: Option<Program>)
    },
    ReserveFee {
        reserve_fee(amount: u64)
    },
    CreateCoinAnnouncement {
        create_coin_announcement(message: Bytes)
    },
    CreatePuzzleAnnouncement {
        create_puzzle_announcement(message: Bytes)
    },
    AssertCoinAnnouncement {
        assert_coin_announcement(announcement_id: Bytes32)
    },
    AssertPuzzleAnnouncement {
        assert_puzzle_announcement(announcement_id: Bytes32)
    },
    AssertConcurrentSpend {
        assert_concurrent_spend(coin_id: Bytes32)
    },
    AssertConcurrentPuzzle {
        assert_concurrent_puzzle(puzzle_hash: Bytes32)
    },
    AssertSecondsRelative {
        assert_seconds_relative(seconds: u64)
    },
    AssertSecondsAbsolute {
        assert_seconds_absolute(seconds: u64)
    },
    AssertHeightRelative {
        assert_height_relative(height: u32)
    },
    AssertHeightAbsolute {
        assert_height_absolute(height: u32)
    },
    AssertBeforeSecondsRelative {
        assert_before_seconds_relative(seconds: u64)
    },
    AssertBeforeSecondsAbsolute {
        assert_before_seconds_absolute(seconds: u64)
    },
    AssertBeforeHeightRelative {
        assert_before_height_relative(height: u32)
    },
    AssertBeforeHeightAbsolute {
        assert_before_height_absolute(height: u32)
    },
    AssertMyCoinId {
        assert_my_coin_id(coin_id: Bytes32)
    },
    AssertMyParentId {
        assert_my_parent_id(parent_id: Bytes32)
    },
    AssertMyPuzzleHash {
        assert_my_puzzle_hash(puzzle_hash: Bytes32)
    },
    AssertMyAmount {
        assert_my_amount(amount: u64)
    },
    AssertMyBirthSeconds {
        assert_my_birth_seconds(seconds: u64)
    },
    AssertMyBirthHeight {
        assert_my_birth_height(height: u32)
    },
    AssertEphemeral {
        assert_ephemeral()
    },
    SendMessage<NodePtr> {
        send_message(mode: u8, message: Bytes, data: Vec<Program>)
    },
    ReceiveMessage<NodePtr> {
        receive_message(mode: u8, message: Bytes, data: Vec<Program>)
    },
    Softfork<NodePtr> {
        softfork(cost: u64, rest: Program)
    },
    MeltSingleton {
        melt_singleton()
    },
    TransferNft {
        transfer_nft(launcher_id: Option<Bytes32>, trade_prices: Vec<TradePrice>, singleton_inner_puzzle_hash: Option<Bytes32>)
    },
    RunCatTail<NodePtr, NodePtr> {
        run_cat_tail(program: Program, solution: Program)
    },
    UpdateNftMetadata<NodePtr, NodePtr> {
        update_nft_metadata(updater_puzzle_reveal: Program, updater_solution: Program)
    },
    UpdateDataStoreMerkleRoot {
        update_data_store_merkle_root(new_merkle_root: Bytes32, memos: Vec<Bytes>)
    },
);