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

Add functions for parsing conditions #107

Merged
merged 2 commits into from
Nov 1, 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
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ convert_case = "0.6.0"
fastrand = "2.1.1"
napi-derive = "2.12.2"
napi = { version = "2.12.2", default-features = false }
paste = "1.0.15"

[profile.release]
lto = true
Expand Down
1 change: 1 addition & 0 deletions napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ chia = { workspace = true }
clvmr = { workspace = true }
num-bigint = { workspace = true }
hex = { workspace = true }
paste = { workspace = true }

[build-dependencies]
napi-build = "2.0.1"
15 changes: 15 additions & 0 deletions napi/__test__/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,3 +281,18 @@ test("mint and spend nft", (t) => {
)
);
});

test("create and parse condition", (t) => {
const clvm = new ClvmAllocator();

const puzzleHash = fromHex("ff".repeat(32));

const condition = clvm.createCoin(puzzleHash, 1n, [puzzleHash]);
const parsed = clvm.parseCreateCoin(condition);

t.deepEqual(parsed, {
puzzleHash,
amount: 1n,
memos: [puzzleHash],
});
});
161 changes: 158 additions & 3 deletions napi/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,126 @@ export interface Output {
export declare function curryTreeHash(treeHash: Uint8Array, args: Array<Uint8Array>): Uint8Array
export declare function intToSignedBytes(bigInt: bigint): Uint8Array
export declare function signedBytesToInt(bytes: Uint8Array): bigint
export interface Remark {
rest: Program
}
export interface AggSigParent {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigPuzzle {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigAmount {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigPuzzleAmount {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigParentAmount {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigParentPuzzle {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigUnsafe {
publicKey: Uint8Array
message: Uint8Array
}
export interface AggSigMe {
publicKey: Uint8Array
message: Uint8Array
}
export interface CreateCoin {
puzzleHash: Uint8Array
amount: bigint
memos: Array<Uint8Array>
}
export interface ReserveFee {
amount: bigint
}
export interface CreateCoinAnnouncement {
message: Uint8Array
}
export interface CreatePuzzleAnnouncement {
message: Uint8Array
}
export interface AssertCoinAnnouncement {
announcementId: Uint8Array
}
export interface AssertPuzzleAnnouncement {
announcementId: Uint8Array
}
export interface AssertConcurrentSpend {
coinId: Uint8Array
}
export interface AssertConcurrentPuzzle {
puzzleHash: Uint8Array
}
export interface AssertSecondsRelative {
seconds: bigint
}
export interface AssertSecondsAbsolute {
seconds: bigint
}
export interface AssertHeightRelative {
height: number
}
export interface AssertHeightAbsolute {
height: number
}
export interface AssertBeforeSecondsRelative {
seconds: bigint
}
export interface AssertBeforeSecondsAbsolute {
seconds: bigint
}
export interface AssertBeforeHeightRelative {
height: number
}
export interface AssertBeforeHeightAbsolute {
height: number
}
export interface AssertMyCoinId {
coinId: Uint8Array
}
export interface AssertMyParentId {
parentId: Uint8Array
}
export interface AssertMyPuzzleHash {
puzzleHash: Uint8Array
}
export interface AssertMyAmount {
amount: bigint
}
export interface AssertMyBirthSeconds {
seconds: bigint
}
export interface AssertMyBirthHeight {
height: number
}
export interface AssertEphemeral {

}
export interface SendMessage {
mode: number
message: Uint8Array
data: Array<Program>
}
export interface ReceiveMessage {
mode: number
message: Uint8Array
data: Array<Program>
}
export interface Softfork {
cost: bigint
rest: Program
}
export interface Coin {
parentCoinInfo: Uint8Array
puzzleHash: Uint8Array
Expand Down Expand Up @@ -103,41 +223,76 @@ export declare class ClvmAllocator {
parseNftInfo(puzzle: Program): ParsedNft | null
parseChildNft(parentCoin: Coin, parentPuzzle: Program, parentSolution: Program): Nft | null
spendNft(nft: Nft, innerSpend: Spend): Array<CoinSpend>
remark(value: Program): Program
remark(rest: Program): Program
parseRemark(program: Program): Remark | null
aggSigParent(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigParent(program: Program): AggSigParent | null
aggSigPuzzle(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigPuzzle(program: Program): AggSigPuzzle | null
aggSigAmount(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigAmount(program: Program): AggSigAmount | null
aggSigPuzzleAmount(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigPuzzleAmount(program: Program): AggSigPuzzleAmount | null
aggSigParentAmount(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigParentAmount(program: Program): AggSigParentAmount | null
aggSigParentPuzzle(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigParentPuzzle(program: Program): AggSigParentPuzzle | null
aggSigUnsafe(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigUnsafe(program: Program): AggSigUnsafe | null
aggSigMe(publicKey: Uint8Array, message: Uint8Array): Program
parseAggSigMe(program: Program): AggSigMe | null
createCoin(puzzleHash: Uint8Array, amount: bigint, memos: Array<Uint8Array>): Program
reserveFee(fee: bigint): Program
parseCreateCoin(program: Program): CreateCoin | null
reserveFee(amount: bigint): Program
parseReserveFee(program: Program): ReserveFee | null
createCoinAnnouncement(message: Uint8Array): Program
parseCreateCoinAnnouncement(program: Program): CreateCoinAnnouncement | null
createPuzzleAnnouncement(message: Uint8Array): Program
parseCreatePuzzleAnnouncement(program: Program): CreatePuzzleAnnouncement | null
assertCoinAnnouncement(announcementId: Uint8Array): Program
parseAssertCoinAnnouncement(program: Program): AssertCoinAnnouncement | null
assertPuzzleAnnouncement(announcementId: Uint8Array): Program
parseAssertPuzzleAnnouncement(program: Program): AssertPuzzleAnnouncement | null
assertConcurrentSpend(coinId: Uint8Array): Program
parseAssertConcurrentSpend(program: Program): AssertConcurrentSpend | null
assertConcurrentPuzzle(puzzleHash: Uint8Array): Program
parseAssertConcurrentPuzzle(program: Program): AssertConcurrentPuzzle | null
assertSecondsRelative(seconds: bigint): Program
parseAssertSecondsRelative(program: Program): AssertSecondsRelative | null
assertSecondsAbsolute(seconds: bigint): Program
parseAssertSecondsAbsolute(program: Program): AssertSecondsAbsolute | null
assertHeightRelative(height: number): Program
parseAssertHeightRelative(program: Program): AssertHeightRelative | null
assertHeightAbsolute(height: number): Program
parseAssertHeightAbsolute(program: Program): AssertHeightAbsolute | null
assertBeforeSecondsRelative(seconds: bigint): Program
parseAssertBeforeSecondsRelative(program: Program): AssertBeforeSecondsRelative | null
assertBeforeSecondsAbsolute(seconds: bigint): Program
parseAssertBeforeSecondsAbsolute(program: Program): AssertBeforeSecondsAbsolute | null
assertBeforeHeightRelative(height: number): Program
parseAssertBeforeHeightRelative(program: Program): AssertBeforeHeightRelative | null
assertBeforeHeightAbsolute(height: number): Program
parseAssertBeforeHeightAbsolute(program: Program): AssertBeforeHeightAbsolute | null
assertMyCoinId(coinId: Uint8Array): Program
parseAssertMyCoinId(program: Program): AssertMyCoinId | null
assertMyParentId(parentId: Uint8Array): Program
parseAssertMyParentId(program: Program): AssertMyParentId | null
assertMyPuzzleHash(puzzleHash: Uint8Array): Program
parseAssertMyPuzzleHash(program: Program): AssertMyPuzzleHash | null
assertMyAmount(amount: bigint): Program
parseAssertMyAmount(program: Program): AssertMyAmount | null
assertMyBirthSeconds(seconds: bigint): Program
parseAssertMyBirthSeconds(program: Program): AssertMyBirthSeconds | null
assertMyBirthHeight(height: number): Program
parseAssertMyBirthHeight(program: Program): AssertMyBirthHeight | null
assertEphemeral(): Program
parseAssertEphemeral(program: Program): AssertEphemeral | null
sendMessage(mode: number, message: Uint8Array, data: Array<Program>): Program
parseSendMessage(program: Program): SendMessage | null
receiveMessage(mode: number, message: Uint8Array, data: Array<Program>): Program
softfork(cost: bigint, value: Program): Program
parseReceiveMessage(program: Program): ReceiveMessage | null
softfork(cost: bigint, rest: Program): Program
parseSoftfork(program: Program): Softfork | null
}
export declare class Program {
isAtom(): boolean
Expand Down
74 changes: 42 additions & 32 deletions napi/src/clvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,18 @@ use chia::{
protocol::{self, Bytes32},
puzzles::nft::{self, NFT_METADATA_UPDATER_PUZZLE_HASH},
};
use chia_wallet_sdk::{
self as sdk, AggSigAmount, AggSigMe, AggSigParent, AggSigParentAmount, AggSigParentPuzzle,
AggSigPuzzle, AggSigPuzzleAmount, AggSigUnsafe, AssertBeforeHeightAbsolute,
AssertBeforeHeightRelative, AssertBeforeSecondsAbsolute, AssertBeforeSecondsRelative,
AssertCoinAnnouncement, AssertConcurrentPuzzle, AssertConcurrentSpend, AssertEphemeral,
AssertHeightAbsolute, AssertHeightRelative, AssertMyAmount, AssertMyBirthHeight,
AssertMyBirthSeconds, AssertMyCoinId, AssertMyParentId, AssertMyPuzzleHash,
AssertPuzzleAnnouncement, AssertSecondsAbsolute, AssertSecondsRelative, CreateCoin,
CreateCoinAnnouncement, CreatePuzzleAnnouncement, HashedPtr, ReceiveMessage, Remark,
ReserveFee, SendMessage, Softfork, SpendContext,
};
use chia_wallet_sdk::{self as sdk, HashedPtr, SpendContext};
use clvmr::{
run_program,
serde::{node_from_bytes, node_from_bytes_backrefs},
ChiaDialect, NodePtr, MEMPOOL_MODE,
};
use napi::bindgen_prelude::*;
use paste::paste;

use crate::{
clvm_value::{Allocate, ClvmValue},
traits::{FromJs, IntoJs, IntoRust},
traits::{FromJs, IntoJs, IntoProgramOrJs, IntoRust},
Coin, CoinSpend, MintedNfts, Nft, NftMetadata, NftMint, ParsedNft, Program, Spend,
};

Expand Down Expand Up @@ -399,26 +390,45 @@ pub fn signed_bytes_to_int(bytes: Uint8Array) -> Result<BigInt> {
}

macro_rules! conditions {
( $( $condition:ident { $hint:literal $function:ident( $( $name:ident: $ty:ty $( => $remap:ty )? ),* ) }, )* ) => {
$( #[napi]
impl ClvmAllocator {
#[napi(ts_args_type = $hint)]
pub fn $function( &mut self, this: This<Clvm>, $( $name: $ty ),* ) -> Result<Program> {
$( let $name $( : $remap )? = FromJs::from_js($name)?; )*
let ptr = $condition::new( $( $name ),* )
.to_clvm(&mut self.0.allocator)
.map_err(|error| Error::from_reason(error.to_string()))?;
( $( $condition:ident $( < $( $generic:ty ),* > )? { $hint:literal $function:ident( $( $name:ident: $ty:ty $( => $remap:ty )? ),* ) }, )* ) => {
$( #[napi(object)]
pub struct $condition {
$( pub $name: $ty, )*
} )*

Ok(Program::new(this, ptr))
$( paste! {
#[napi]
impl ClvmAllocator {
#[napi(ts_args_type = $hint)]
pub fn $function( &mut self, this: This<Clvm>, $( $name: $ty ),* ) -> Result<Program> {
$( let $name $( : $remap )? = FromJs::from_js($name)?; )*
let ptr = sdk::$condition::new( $( $name ),* )
.to_clvm(&mut self.0.allocator)
.map_err(|error| Error::from_reason(error.to_string()))?;

Ok(Program::new(this, ptr))
}

#[napi(ts_args_type = "program: Program")]
#[allow(unused)]
pub fn [< parse_ $function >]( &mut self, env: Env, this: This<Clvm>, program: Reference<Program> ) -> Result<Option<$condition>> {
let Some(condition) = sdk::$condition $( ::< $( $generic ),* > )? ::from_clvm(&self.0.allocator, program.ptr).ok() else {
return Ok(None);
};

Ok(Some($condition {
$( $name: condition.$name.into_program_or_js(env, this.clone(env)?)?, )*
}))
}
}
} )*
};
}

conditions!(
Remark {
"value: Program"
remark(value: ClassInstance<Program> => NodePtr)
Remark<NodePtr> {
"rest: Program"
remark(rest: ClassInstance<Program> => NodePtr)
},
AggSigParent {
"publicKey: Uint8Array, message: Uint8Array"
Expand Down Expand Up @@ -457,8 +467,8 @@ conditions!(
create_coin(puzzle_hash: Uint8Array, amount: BigInt, memos: Vec<Uint8Array>)
},
ReserveFee {
"fee: bigint"
reserve_fee(fee: BigInt)
"amount: bigint"
reserve_fee(amount: BigInt)
},
CreateCoinAnnouncement {
"message: Uint8Array"
Expand Down Expand Up @@ -544,16 +554,16 @@ conditions!(
""
assert_ephemeral()
},
SendMessage {
SendMessage<NodePtr> {
"mode: number, message: Uint8Array, data: Array<Program>"
send_message(mode: u8, message: Uint8Array, data: Vec<ClassInstance<Program>> => Vec<NodePtr>)
},
ReceiveMessage {
ReceiveMessage<NodePtr> {
"mode: number, message: Uint8Array, data: Array<Program>"
receive_message(mode: u8, message: Uint8Array, data: Vec<ClassInstance<Program>> => Vec<NodePtr>)
},
Softfork {
"cost: bigint, value: Program"
softfork(cost: BigInt, value: ClassInstance<Program> => NodePtr)
Softfork<NodePtr> {
"cost: bigint, rest: Program"
softfork(cost: BigInt, rest: ClassInstance<Program> => NodePtr)
},
);
Loading