Skip to content

Commit

Permalink
Add examples back
Browse files Browse the repository at this point in the history
  • Loading branch information
Rigidity committed Jul 6, 2024
1 parent b8d9c4f commit 67fd481
Show file tree
Hide file tree
Showing 10 changed files with 369 additions and 0 deletions.
11 changes: 11 additions & 0 deletions examples/factorial.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fun main() -> Int {
factorial(15)
}

fun factorial(num: Int) -> Int {
if num > 1 {
num * factorial(num - 1)
} else {
1
}
}
11 changes: 11 additions & 0 deletions examples/fibonacci.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
fun main() -> Int {
fibonacci(10)
}

fun fibonacci(num: Int) -> Int {
if num > 1 {
fibonacci(num - 1) + fibonacci(num - 2)
} else {
num
}
}
3 changes: 3 additions & 0 deletions examples/hello_world.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fun main() -> Bytes {
"Hello, world!"
}
37 changes: 37 additions & 0 deletions examples/multisig.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// This puzzle has not been audited or tested, and is for example purposes only.

fun main(
public_keys: PublicKey[],
required: Int,
indices: Int[],
conditions: Condition[],
) -> Condition[] {
let message = tree_hash(conditions);
let agg_sigs = check_signatures(public_keys, required, indices, 0, message);
concat(agg_sigs, conditions)
}

fun check_signatures(
public_keys: PublicKey[],
required: Int,
indices: Int[],
pos: Int,
message: Bytes,
) -> Condition[] {
if required == 0 {
return nil;
}

assume !(public_keys is Nil) && !(indices is Nil);

if indices.first != pos {
return check_signatures(public_keys.rest, required, indices, pos + 1, message);
}

let agg_sig = Condition::AggSigMe {
public_key: public_keys.first,
message: message,
};

[agg_sig, ...check_signatures(public_keys.rest, required - 1, indices.rest, pos + 1, message)]
}
9 changes: 9 additions & 0 deletions examples/p2_conditions.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This puzzle has not been audited or tested, and is for example purposes only.

fun main(public_key: PublicKey, conditions: Condition[]) -> Condition[] {
let agg_sig = Condition::AggSigMe {
public_key: public_key,
message: tree_hash(conditions),
};
[agg_sig, ...conditions]
}
25 changes: 25 additions & 0 deletions examples/p2_delegated_or_hidden.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// This puzzle has not been audited or tested, and is for example purposes only.

fun main(
synthetic_pk: PublicKey,
original_pk: PublicKey?,
delegated_puzzle: fun(...solution: Any) -> Condition[],
delegated_solution: Any
) -> Condition[] {
let conditions = delegated_puzzle(...delegated_solution);
let delegated_puzzle_hash = tree_hash(delegated_puzzle);

if original_pk != nil {
let exponent = sha256(original_pk as Bytes + delegated_puzzle_hash);
let offset_pk = pubkey_for_exp(exponent);
assert synthetic_pk == original_pk + offset_pk;
return conditions;
}

let agg_sig_me = Condition::AggSigMe {
public_key: synthetic_pk,
message: delegated_puzzle_hash,
};

[agg_sig_me, ...conditions]
}
64 changes: 64 additions & 0 deletions examples/p2_fusion.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// This puzzle has not been audited or tested, and is for example purposes only.

// Also known as a "singleton struct".
struct SingletonInfo {
mod_hash: Bytes32,
launcher_id: Bytes32,
...launcher_puzzle_hash: Bytes32,
}

// Calculate the full puzzle hash for a singleton.
inline fun singleton_puzzle_hash(singleton_info: SingletonInfo, inner_puzzle_hash: Bytes32) -> Bytes32 {
curry_tree_hash(singleton_info.mod_hash, tree_hash(singleton_info), inner_puzzle_hash)
}

fun main(
fusion_singleton: SingletonInfo,
fusion_inner_puzzle_hash: Bytes32,
fusion_coin_id: Bytes32,
my_launcher_id: Bytes32,
my_inner_puzzle_hash: Bytes32,
my_amount: Int,
p2_puzzle_hash: Bytes32,
) -> Condition[] {
// The NFT singleton has the same mod hash and launcher puzzle hash as the fusion singleton.
let nft_singleton = SingletonInfo {
mod_hash: fusion_singleton.mod_hash,
launcher_id: my_launcher_id,
launcher_puzzle_hash: fusion_singleton.launcher_puzzle_hash,
};

// Calculate the full puzzle hashes for the NFT and fusion singletons.
let fusion_puzzle_hash = singleton_puzzle_hash(fusion_singleton, fusion_inner_puzzle_hash);
let nft_puzzle_hash = singleton_puzzle_hash(nft_singleton, my_inner_puzzle_hash);

// Calculate the announcement message.
let announcement_message = sha256(fusion_coin_id + my_launcher_id + p2_puzzle_hash);

[
// Make sure that the amount in the solution is correct.
Condition::AssertMyAmount { amount: my_amount },

// Prove supplied NFT coin matches the expected derived puzzle hash.
Condition::AssertMyPuzzleHash { puzzle_hash: nft_puzzle_hash },


// Assert that the fusion singleton announced this NFT spend.
Condition::AssertPuzzleAnnouncement {
announcement_id: sha256(fusion_puzzle_hash + announcement_message),
},

// Unlock the NFT to the new p2 puzzle hash, with a hint.
Condition::CreateCoin {
puzzle_hash: p2_puzzle_hash,
amount: my_amount,
memos: [p2_puzzle_hash],
},

// Announce that a specific singleton is being spent to
// help prevent ephemeral singleton spends from influencing.
Condition::CreateCoinAnnouncement {
message: announcement_message,
},
]
}
51 changes: 51 additions & 0 deletions examples/royalty_split.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// This puzzle has not been audited or tested, and is for example purposes only.

struct Payout {
puzzle_hash: Bytes32,
share: Int,
}

fun main(payouts: Payout[], total_shares: Int, my_amount: Int) -> Condition[] {
let announcement = Condition::CreateCoinAnnouncement { message: '$' };
let assert_amount = Condition::AssertMyAmount { amount: my_amount };

let conditions = calculate_amount_and_split(payouts, my_amount, total_shares, 0, my_amount);
[announcement, assert_amount, ...conditions]
}

fun calculate_amount_and_split(
payouts: Payout[],
total_amount: Int,
total_shares: Int,
shares_sum: Int,
remaining_amount: Int,
) -> Condition[] {
if payouts is (Payout, Payout[]) {
let amount = get_amount(payouts.first, total_amount, total_shares);
return split_amount_and_create_coins(payouts, amount, total_amount, total_shares, shares_sum, remaining_amount);
}
assert total_shares == shares_sum;
[]
}

fun split_amount_and_create_coins(
payouts: (Payout, Payout[]),
this_amount: Int,
total_amount: Int,
total_shares: Int,
shares_sum: Int,
remaining_amount: Int,
) -> Condition[] {
let payout = payouts.first;
let create_coin = Condition::CreateCoin {
puzzle_hash: payout.puzzle_hash,
amount: if payout.share > 0 { this_amount } else { remaining_amount },
memos: [payout.puzzle_hash],
};
let rest = calculate_amount_and_split(payouts.rest, total_amount, total_shares, shares_sum + payout.share, remaining_amount - this_amount);
[create_coin, ...rest]
}

fun get_amount(payout: Payout, total_amount: Int, total_shares: Int) -> Int {
(total_amount * payout.share) / total_shares
}
94 changes: 94 additions & 0 deletions examples/singleton.rue
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// This puzzle has not been audited or tested, and is for example purposes only.

struct Singleton {
mod_hash: Bytes32,
launcher_id: Bytes32,
launcher_puzzle_hash: Bytes32,
}

struct LineageProof {
parent_parent_coin_info: Bytes32,
parent_inner_puzzle_hash: Bytes32?,
parent_amount: Int,
}

fun singleton_puzzle_hash(singleton: Singleton, inner_puzzle_hash: Bytes32) -> Bytes32 {
curry_tree_hash(singleton.mod_hash, tree_hash(singleton), inner_puzzle_hash)
}

fun main(
singleton: Singleton,
inner_puzzle: fun(...solution: Any) -> Condition[],
lineage_proof: LineageProof,
my_amount: Int,
inner_solution: Any,
) -> Condition[] {
// Ensure that the amount is odd.
assert my_amount & 1 == 1;

// Verify the lineage proof.
let is_eve = lineage_proof.parent_inner_puzzle_hash == nil;

let parent_puzzle_hash = if is_eve {
singleton.launcher_puzzle_hash
} else {
singleton_puzzle_hash(singleton, lineage_proof.parent_inner_puzzle_hash)
};

let parent_coin_id = calculate_coin_id(
lineage_proof.parent_parent_coin_info,
parent_puzzle_hash,
lineage_proof.parent_amount,
);

assert is_eve || parent_coin_id == singleton.launcher_id;

// Run the inner puzzle.
let conditions = inner_puzzle(...inner_solution);

[
Condition::AssertMyAmount { amount: my_amount },
Condition::AssertMyParentId { parent_coin_id: parent_coin_id },
...morph_conditions(singleton, conditions, false),
]
}

fun morph_conditions(
singleton: Singleton,
conditions: Condition[],
found_singleton_output: Bool,
) -> Condition[] {
if conditions is Nil {
// We must have a singleton output.
assert found_singleton_output;
return nil;
}

let condition = conditions.first;
let rest = conditions.rest;

if !(condition is Condition::CreateCoin && condition.amount & 1 == 1) {
// We don't need to morph this condition.
return [
condition,
...morph_conditions(singleton, rest, found_singleton_output),
];
}

// We need to morph this odd output, but it must be the only one.
assert !found_singleton_output;

if condition.amount == -113 {
// We are melting the singleton, so we don't need to have an output.
return morph_conditions(singleton, rest, true);
}

// Wrap the puzzle hash in the singleton layer.
let output = Condition::CreateCoin {
puzzle_hash: singleton_puzzle_hash(singleton, condition.puzzle_hash),
amount: condition.amount,
memos: condition.memos,
};

[output, ...morph_conditions(singleton, rest, true)]
}
64 changes: 64 additions & 0 deletions tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,67 @@ compiler_errors = [
"Error: Unused enum variant `SameName`. (2:5)",
"Error: Unused enum variant `DuplicateDiscriminant`. (4:5)",
]

[p2_fusion]
bytes = 722
cost = 87151
input = "((0x4696e7a2b7682e2df01ab47e6e002d0dca895f99c6172e4a55a3e033499532b7 0x32ed6e4964102d7093ef350019dfd14c99a3ea9feac1f3502194384b8976f7c1 0x770bb2c0b2582924adf403e62374f8424a2ed510eef70b5f450eccab238a4911) 0x8d496dc7cdbc417db2132eda6894b29a91511f176e93a1ea943d210cd27822b2 0x3878fc2ed6b703c7c3d00f9f5d8f170ec252ca439be6e5b5b516e1dce1adc0d7 0x3fe4d62a7db919b25377cb207f16fa0fb6519e123366eaa23014dd5d7c967ca2 0x837525fb91b88dbf02d9ef5a0b322f6943f93424b6e8fe6d26dd1be6d3311871 1 0xc19110971a0cea01368f0c7599b8984f74e301b7cda20bd7f86eb2296bbf16c5)"
output = "((73 1) (72 0x6155f55414a5cd9193bef33744095a78d57852cf24241b25edeffad6e544c499) (63 0x9d6824bfdfb4c726334a210b657a5e4126c3fbb378598bb3a5b7a210bb75cdb8) (g1_negate 0xc19110971a0cea01368f0c7599b8984f74e301b7cda20bd7f86eb2296bbf16c5 1 (0xc19110971a0cea01368f0c7599b8984f74e301b7cda20bd7f86eb2296bbf16c5)) (60 0x81fdd3fbc407906bc0875522e7a2e77409ee5ef17d3eaa611b505b344588f6b6))"
hash = "1f6abfdd1000d9ed87740ca5a0a888a042d64a8a7b6d60f082aab5be1f0915b4"

[multisig]
bytes = 489
cost = 27062
input = "((0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000) 1 (()) ((51 0x0000000000000000000000000000000000000000000000000000000000000000 1000)))"
output = "((g1_multiply 0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0x502cea601814d49886e0713402860d6054f6947d811b3b93100c6b364626651a) (g1_negate 0x0000000000000000000000000000000000000000000000000000000000000000 1000))"
hash = "173385b87af5d8940767c328026fe5f8e76bc238d2a3aaddf4f55e844f400fca"

[hello_world]
bytes = 16
cost = 20
input = "()"
output = "\"Hello, world!\""
hash = "4d5ba80f14b464a42a862990c434225f0f297bec1fe146117cb5c8b96d01166b"

[fibonacci]
bytes = 121
cost = 414329
input = "()"
output = "55"
hash = "951ba85ff214a65c4d07814672544b6686e8f4a819550543473fb8eb26aae6a3"

[factorial]
bytes = 97
cost = 43743
input = "()"
output = "0x013077775800"
hash = "291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8"

[royalty_split]
bytes = 430
cost = 20303
input = "(((0x42840c6aebec47ce2e01629ce381b461c19695264281a7b1aab5d4ff54506775 1) (0x917b0e1ee2c8ad5755e1f97c4642ea653288acf816eee1b0d537dd8e01106711 2)) 3 100000)"
output = "((60 36) (73 0x0186a0) (g1_negate 0x42840c6aebec47ce2e01629ce381b461c19695264281a7b1aab5d4ff54506775 0x008235 (0x42840c6aebec47ce2e01629ce381b461c19695264281a7b1aab5d4ff54506775)) (g1_negate 0x917b0e1ee2c8ad5755e1f97c4642ea653288acf816eee1b0d537dd8e01106711 0x01046a (0x917b0e1ee2c8ad5755e1f97c4642ea653288acf816eee1b0d537dd8e01106711)))"
hash = "7eb7bdb24d4069d7dc9787e7727ef4f0feef354712b1963667d475065122b9de"

[p2_conditions]
bytes = 145
cost = 18933
input = "(0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ((51 0x291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8 1000)))"
output = "((g1_multiply 0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0xc239bbcfc69fb5abacdd8dc174c6b33170c6d902dec3bc1c87662020cf044313) (g1_negate 0x291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8 1000))"
hash = "e69958bce8b4294e16e9b54f6f6795228fbd6daa47ff27ab58a953c611367be2"

[p2_delegated_or_hidden]
bytes = 253
cost = 24446
input = "(0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 () (q . ((51 0x291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8 1000))) 1)"
output = "((g1_multiply 0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0x3d7e1145b5969c12f4889f4f1f66bde0e4d3ba54b91784cf604294d162b44b69) (g1_negate 0x291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8 1000))"
hash = "9b1c580707ca8282534c02c1a055427e0954818b6195a29f4442ac3e7ea8e8ee"

[singleton]
bytes = 1427
cost = 0
input = "((0x42840c6aebec47ce2e01629ce381b461c19695264281a7b1aab5d4ff54506775 0x4696e7a2b7682e2df01ab47e6e002d0dca895f99c6172e4a55a3e033499532b7 0x291e4594b43d58e833cab95e4b165c5fac6b4d8391c81ebfd20efdd8d58b92d8) 1 (0x9b1c580707ca8282534c02c1a055427e0954818b6195a29f4442ac3e7ea8e8ee () 1) 1 ((51 0x173385b87af5d8940767c328026fe5f8e76bc238d2a3aaddf4f55e844f400fca 1)))"
output = "()"
hash = "ca8bea1d975df6e382a60ef70f92d14de0eca974c548175adc6ee8c79597f91b"
error = "()"

0 comments on commit 67fd481

Please sign in to comment.