chia-sdk-driver 0.34.0

Driver code for interacting with standard puzzles on the Chia blockchain.
Documentation
use chia_protocol::Bytes32;
use chia_sdk_types::{
    Mod,
    puzzles::{SingletonMember, SingletonMemberSolution},
};
use clvm_utils::{ToTreeHash, TreeHash};
use clvmr::NodePtr;

use crate::{
    DriverError, InnerPuzzleSpend, MipsSpend, MofN, Spend, SpendContext, mips_puzzle_hash,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct P2ConditionsOrSingleton {
    pub launcher_id: Bytes32,
    pub nonce: usize,
    pub fixed_conditions_hash: Bytes32,
}

impl P2ConditionsOrSingleton {
    pub fn new(launcher_id: Bytes32, nonce: usize, fixed_conditions_hash: Bytes32) -> Self {
        Self {
            launcher_id,
            nonce,
            fixed_conditions_hash,
        }
    }

    pub fn fixed_conditions_hash(quoted_conditions_hash: Bytes32) -> Bytes32 {
        mips_puzzle_hash(0, vec![], quoted_conditions_hash.into(), false).into()
    }

    pub fn from_quoted_conditions_hash(
        launcher_id: Bytes32,
        nonce: usize,
        quoted_conditions_hash: Bytes32,
    ) -> Self {
        Self {
            launcher_id,
            nonce,
            fixed_conditions_hash: Self::fixed_conditions_hash(quoted_conditions_hash),
        }
    }

    pub fn fixed_path_hash(&self) -> TreeHash {
        self.fixed_conditions_hash.into()
    }

    pub fn p2_singleton_path_hash(&self) -> TreeHash {
        mips_puzzle_hash(
            self.nonce,
            vec![],
            SingletonMember::new(self.launcher_id).curry_tree_hash(),
            false,
        )
    }

    pub fn p2_singleton_spend(
        &self,
        ctx: &mut SpendContext,
        singleton_inner_puzzle_hash: Bytes32,
        singleton_amount: u64,
        delegated_spend: Spend,
    ) -> Result<Spend, DriverError> {
        let mut mips = MipsSpend::new(delegated_spend);

        let fixed_hash = self.fixed_path_hash();
        let p2_singleton_hash = self.p2_singleton_path_hash();
        let custody_hash = self.tree_hash();

        mips.members.insert(
            custody_hash,
            InnerPuzzleSpend::m_of_n(0, vec![], 1, vec![fixed_hash, p2_singleton_hash]),
        );

        let puzzle = ctx.curry(SingletonMember::new(self.launcher_id))?;
        let solution = ctx.alloc(&SingletonMemberSolution::new(
            singleton_inner_puzzle_hash,
            singleton_amount,
        ))?;

        mips.members.insert(
            p2_singleton_hash,
            InnerPuzzleSpend::new(self.nonce, vec![], Spend::new(puzzle, solution)),
        );

        mips.spend(ctx, custody_hash)
    }

    pub fn fixed_spend(
        &self,
        ctx: &mut SpendContext,
        delegated_spend: Spend,
    ) -> Result<Spend, DriverError> {
        let mut mips = MipsSpend::new(Spend::new(NodePtr::NIL, NodePtr::NIL));

        let fixed_hash = self.fixed_path_hash();
        let p2_singleton_hash = self.p2_singleton_path_hash();
        let custody_hash = self.tree_hash();

        mips.members.insert(
            custody_hash,
            InnerPuzzleSpend::m_of_n(0, vec![], 1, vec![fixed_hash, p2_singleton_hash]),
        );

        mips.members.insert(
            fixed_hash,
            InnerPuzzleSpend::new(0, vec![], delegated_spend),
        );

        mips.spend(ctx, custody_hash)
    }
}

impl ToTreeHash for P2ConditionsOrSingleton {
    fn tree_hash(&self) -> TreeHash {
        let fixed_hash = self.fixed_path_hash();

        let p2_singleton_hash = self.p2_singleton_path_hash();

        mips_puzzle_hash(
            0,
            vec![],
            MofN::new(1, vec![fixed_hash, p2_singleton_hash]).inner_puzzle_hash(),
            true,
        )
    }
}