Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vault members restrictions #142

Merged
merged 3 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ workspace = true

[features]
chip-0035 = ["chia-sdk-driver/chip-0035", "chia-sdk-types/chip-0035"]
vault = ["chia-sdk-driver/vault", "chia-sdk-types/vault"]
experimental-vaults = [
"chia-sdk-driver/experimental-vaults",
"chia-sdk-types/experimental-vaults",
]
offers = ["chia-sdk-driver/offers"]
native-tls = ["chia-sdk-client/native-tls"]
rustls = ["chia-sdk-client/rustls"]
Expand Down
3 changes: 2 additions & 1 deletion crates/chia-sdk-driver/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ workspace = true

[features]
chip-0035 = ["chia-sdk-types/chip-0035"]
vault = ["chia-sdk-types/vault"]
experimental-vaults = ["chia-sdk-types/experimental-vaults"]
offers = [
"dep:bech32",
"dep:chia-traits",
Expand All @@ -30,6 +30,7 @@ offers = [

[dependencies]
chia-bls = { workspace = true }
chia-secp = { workspace = true }
chia-protocol = { workspace = true }
chia-puzzles = { workspace = true }
clvm-traits = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-sdk-driver/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ mod datalayer;
#[cfg(feature = "chip-0035")]
pub use datalayer::*;

#[cfg(feature = "vault")]
#[cfg(feature = "experimental-vaults")]
mod vault;

#[cfg(feature = "vault")]
#[cfg(feature = "experimental-vaults")]
pub use vault::*;
116 changes: 114 additions & 2 deletions crates/chia-sdk-driver/src/primitives/vault/member.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use chia_bls::PublicKey;
use chia_sdk_types::{BlsMember, Mod};
use chia_protocol::Bytes32;
use chia_sdk_types::{
BlsMember, BlsTaprootMember, FixedPuzzleMember, Mod, PasskeyMember, PasskeyMemberPuzzleAssert,
Secp256k1Member, Secp256k1MemberPuzzleAssert, Secp256r1Member, Secp256r1MemberPuzzleAssert,
SingletonMember,
};
use chia_secp::{K1PublicKey, R1PublicKey};
use clvm_utils::TreeHash;
use clvmr::NodePtr;

Expand All @@ -16,6 +22,15 @@
#[derive(Debug, Clone)]
pub enum MemberKind {
Bls(BlsMember),
BlsTaproot(BlsTaprootMember),
FixedPuzzle(FixedPuzzleMember),
Passkey(PasskeyMember),
PasskeyPuzzleAssert(PasskeyMemberPuzzleAssert),
Secp256k1(Secp256k1Member),
Secp256k1PuzzleAssert(Secp256k1MemberPuzzleAssert),
Secp256r1(Secp256r1Member),
Secp256r1PuzzleAssert(Secp256r1MemberPuzzleAssert),
Singleton(SingletonMember),
MofN(MofN),
Unknown,
}
Expand All @@ -29,6 +44,78 @@
}
}

pub fn bls_taproot(synthetic_key: PublicKey) -> Self {
let member = BlsTaprootMember::new(synthetic_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::BlsTaproot(member),
}
}

pub fn fixed_puzzle(fixed_puzzle_hash: Bytes32) -> Self {
let member = FixedPuzzleMember::new(fixed_puzzle_hash);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::FixedPuzzle(member),
}
}

pub fn passkey(genesis_challenge: Bytes32, public_key: R1PublicKey) -> Self {
let member = PasskeyMember::new(genesis_challenge, public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Passkey(member),
}
}

pub fn passkey_puzzle_assert(genesis_challenge: Bytes32, public_key: R1PublicKey) -> Self {
let member = PasskeyMemberPuzzleAssert::new(genesis_challenge, public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::PasskeyPuzzleAssert(member),
}
}

pub fn secp256k1(public_key: K1PublicKey) -> Self {
let member = Secp256k1Member::new(public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Secp256k1(member),
}
}

pub fn secp256k1_puzzle_assert(public_key: K1PublicKey) -> Self {
let member = Secp256k1MemberPuzzleAssert::new(public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Secp256k1PuzzleAssert(member),
}
}

pub fn secp256r1(public_key: R1PublicKey) -> Self {
let member = Secp256r1Member::new(public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Secp256r1(member),
}
}

pub fn secp256r1_puzzle_assert(public_key: R1PublicKey) -> Self {
let member = Secp256r1MemberPuzzleAssert::new(public_key);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Secp256r1PuzzleAssert(member),
}
}

pub fn singleton(launcher_id: Bytes32) -> Self {
let member = SingletonMember::new(launcher_id);
Self {
puzzle_hash: member.curry_tree_hash(),
kind: MemberKind::Singleton(member),
}
}

pub fn m_of_n(required: usize, members: Vec<PuzzleWithRestrictions<Member>>) -> Self {
let m_of_n = MofN::new(required, members).expect("invalid m_of_n");
Self {
Expand Down Expand Up @@ -57,6 +144,21 @@
fn puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
match &self.kind {
MemberKind::Bls(bls) => ctx.curry(bls),
MemberKind::BlsTaproot(bls_taproot) => ctx.curry(bls_taproot),
MemberKind::FixedPuzzle(fixed_puzzle) => ctx.curry(fixed_puzzle),

Check warning on line 148 in crates/chia-sdk-driver/src/primitives/vault/member.rs

View check run for this annotation

Codecov / codecov/patch

crates/chia-sdk-driver/src/primitives/vault/member.rs#L148

Added line #L148 was not covered by tests
MemberKind::Passkey(passkey) => ctx.curry(passkey),
MemberKind::PasskeyPuzzleAssert(passkey_puzzle_assert) => {
ctx.curry(passkey_puzzle_assert)
}
MemberKind::Secp256k1(secp256k1) => ctx.curry(secp256k1),

Check warning on line 153 in crates/chia-sdk-driver/src/primitives/vault/member.rs

View check run for this annotation

Codecov / codecov/patch

crates/chia-sdk-driver/src/primitives/vault/member.rs#L153

Added line #L153 was not covered by tests
MemberKind::Secp256k1PuzzleAssert(secp256k1_puzzle_assert) => {
ctx.curry(secp256k1_puzzle_assert)
}
MemberKind::Secp256r1(secp256r1) => ctx.curry(secp256r1),
MemberKind::Secp256r1PuzzleAssert(secp256r1_puzzle_assert) => {
ctx.curry(secp256r1_puzzle_assert)
}
MemberKind::Singleton(singleton) => ctx.curry(singleton),

Check warning on line 161 in crates/chia-sdk-driver/src/primitives/vault/member.rs

View check run for this annotation

Codecov / codecov/patch

crates/chia-sdk-driver/src/primitives/vault/member.rs#L161

Added line #L161 was not covered by tests
MemberKind::MofN(m_of_n) => m_of_n.puzzle(ctx),
MemberKind::Unknown => Err(DriverError::UnknownPuzzle),
}
Expand All @@ -70,7 +172,17 @@
.unwrap_or(self.kind);

let kind = match kind {
MemberKind::Bls(..) | MemberKind::Unknown => kind,
MemberKind::Bls(..)
| MemberKind::BlsTaproot(..)
| MemberKind::FixedPuzzle(..)
| MemberKind::Passkey(..)
| MemberKind::PasskeyPuzzleAssert(..)
| MemberKind::Secp256k1(..)
| MemberKind::Secp256k1PuzzleAssert(..)
| MemberKind::Secp256r1(..)
| MemberKind::Secp256r1PuzzleAssert(..)
| MemberKind::Singleton(..)
| MemberKind::Unknown => kind,
MemberKind::MofN(m_of_n) => MemberKind::MofN(m_of_n.replace(known_puzzles)),
};

Expand Down
10 changes: 9 additions & 1 deletion crates/chia-sdk-driver/src/primitives/vault/restriction.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use chia_sdk_types::Timelock;
use chia_sdk_types::{Force1of2RestrictedVariable, Timelock};
use clvm_utils::TreeHash;
use clvmr::NodePtr;

Expand All @@ -16,6 +16,9 @@ pub struct Restriction {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RestrictionKind {
Timelock(Timelock),
ForceCoinMessage,
ForceAssertCoinAnnouncement,
Force1of2RestrictedVariable(Force1of2RestrictedVariable),
Unknown,
}

Expand Down Expand Up @@ -49,6 +52,11 @@ impl VaultLayer for Restriction {
fn puzzle(&self, ctx: &mut SpendContext) -> Result<NodePtr, DriverError> {
match &self.kind {
RestrictionKind::Timelock(timelock) => ctx.curry(timelock),
RestrictionKind::ForceCoinMessage => ctx.force_coin_message_puzzle(),
RestrictionKind::ForceAssertCoinAnnouncement => {
ctx.force_assert_coin_announcement_puzzle()
}
RestrictionKind::Force1of2RestrictedVariable(restriction) => ctx.curry(restriction),
RestrictionKind::Unknown => Err(DriverError::UnknownPuzzle),
}
}
Expand Down
19 changes: 19 additions & 0 deletions crates/chia-sdk-driver/src/spend_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::{tree_hash, CurriedProgram, TreeHash};
use clvmr::{serde::node_from_bytes, Allocator, NodePtr};

#[cfg(feature = "experimental-vaults")]
use chia_sdk_types::{
FORCE_ASSERT_COIN_ANNOUNCEMENT_PUZZLE, FORCE_ASSERT_COIN_ANNOUNCEMENT_PUZZLE_HASH,
FORCE_COIN_MESSAGE_PUZZLE, FORCE_COIN_MESSAGE_PUZZLE_HASH,
};

use crate::{DriverError, Spend};

/// A wrapper around [`Allocator`] that caches puzzles and keeps track of a list of [`CoinSpend`].
Expand Down Expand Up @@ -128,6 +134,19 @@ impl SpendContext {
self.puzzle(SETTLEMENT_PAYMENTS_PUZZLE_HASH, &SETTLEMENT_PAYMENTS_PUZZLE)
}

#[cfg(feature = "experimental-vaults")]
pub fn force_coin_message_puzzle(&mut self) -> Result<NodePtr, DriverError> {
self.puzzle(FORCE_COIN_MESSAGE_PUZZLE_HASH, &FORCE_COIN_MESSAGE_PUZZLE)
}

#[cfg(feature = "experimental-vaults")]
pub fn force_assert_coin_announcement_puzzle(&mut self) -> Result<NodePtr, DriverError> {
self.puzzle(
FORCE_ASSERT_COIN_ANNOUNCEMENT_PUZZLE_HASH,
&FORCE_ASSERT_COIN_ANNOUNCEMENT_PUZZLE,
)
}

/// Preload a puzzle into the cache.
pub fn preload(&mut self, puzzle_hash: TreeHash, ptr: NodePtr) {
self.puzzles.insert(puzzle_hash, ptr);
Expand Down
3 changes: 2 additions & 1 deletion crates/chia-sdk-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ workspace = true

[features]
chip-0035 = []
vault = []
experimental-vaults = []

[dependencies]
chia-sdk-derive = { workspace = true }
chia-bls = { workspace = true }
chia-secp = { workspace = true }
chia-protocol = { workspace = true }
chia-consensus = { workspace = true }
chia-puzzles = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions crates/chia-sdk-types/src/puzzles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ mod datalayer;
#[cfg(feature = "chip-0035")]
pub use datalayer::*;

#[cfg(feature = "vault")]
#[cfg(feature = "experimental-vaults")]
mod vault;

#[cfg(feature = "vault")]
#[cfg(feature = "experimental-vaults")]
pub use vault::*;

#[cfg(test)]
Expand Down
18 changes: 18 additions & 0 deletions crates/chia-sdk-types/src/puzzles/vault/members.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
mod bls_member;
mod bls_taproot_member;
mod fixed_puzzle_member;
mod passkey_member;
mod passkey_member_puzzle_assert;
mod secp256k1_member;
mod secp256k1_member_puzzle_assert;
mod secp256r1_member;
mod secp256r1_member_puzzle_assert;
mod singleton_member;

pub use bls_member::*;
pub use bls_taproot_member::*;
pub use fixed_puzzle_member::*;
pub use passkey_member::*;
pub use passkey_member_puzzle_assert::*;
pub use secp256k1_member::*;
pub use secp256k1_member_puzzle_assert::*;
pub use secp256r1_member::*;
pub use secp256r1_member_puzzle_assert::*;
pub use singleton_member::*;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use chia_bls::PublicKey;
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::TreeHash;
use hex_literal::hex;

use crate::Mod;

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(curry)]
pub struct BlsTaprootMember {
pub synthetic_key: PublicKey,
}

impl BlsTaprootMember {
pub fn new(synthetic_key: PublicKey) -> Self {
Self { synthetic_key }
}
}

impl Mod for BlsTaprootMember {
const MOD_REVEAL: &[u8] = &BLS_TAPROOT_MEMBER;
const MOD_HASH: TreeHash = BLS_TAPROOT_MEMBER_HASH;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(solution)]
pub struct BlsTaprootMemberSolution {
pub original_public_key: Option<PublicKey>,
}

impl BlsTaprootMemberSolution {
pub fn new(original_public_key: Option<PublicKey>) -> Self {
Self {
original_public_key,
}
}
}

pub const BLS_TAPROOT_MEMBER: [u8; 99] = hex!(
"
ff02ffff01ff02ffff03ff17ffff01ff02ffff03ffff09ff05ffff1dff17ffff
1effff0bff17ff0b80808080ff80ffff01ff088080ff0180ffff01ff04ffff04
ff02ffff04ff05ffff04ff0bff80808080ff808080ff0180ffff04ffff0132ff
018080
"
);

pub const BLS_TAPROOT_MEMBER_HASH: TreeHash = TreeHash::new(hex!(
"35d2ad31aaf0df91c965909e5112294c57a18354ee4a5aae80572080ec3b6842"
));
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use chia_protocol::Bytes32;
use clvm_traits::{FromClvm, ToClvm};
use clvm_utils::TreeHash;
use hex_literal::hex;

use crate::Mod;

#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)]
#[clvm(curry)]
pub struct FixedPuzzleMember {
pub fixed_puzzle_hash: Bytes32,
}

impl FixedPuzzleMember {
pub fn new(fixed_puzzle_hash: Bytes32) -> Self {
Self { fixed_puzzle_hash }
}
}

impl Mod for FixedPuzzleMember {
const MOD_REVEAL: &[u8] = &FIXED_PUZZLE_MEMBER;
const MOD_HASH: TreeHash = FIXED_PUZZLE_MEMBER_HASH;
}

pub const FIXED_PUZZLE_MEMBER: [u8; 25] =
hex!("ff02ffff03ffff09ff02ff0580ff80ffff01ff088080ff0180");

pub const FIXED_PUZZLE_MEMBER_HASH: TreeHash = TreeHash::new(hex!(
"34ede3eadc52ed750e405f2b9dea9891506547f651290bb606356d997c64f219"
));
Loading
Loading