Repository navigation
Expand file tree
/
Copy pathsingleton.rue
More file actions
131 lines (107 loc) · 3.87 KB
/
Copy pathsingleton.rue
File metadata and controls
131 lines (107 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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,
}
struct EveProof {
parent_parent_coin_info: Bytes32,
parent_amount: Int,
}
type Proof = LineageProof | EveProof;
fn main(
singleton: Singleton,
inner_puzzle: fn(...inner_solution: Any) -> List<Condition>,
proof: Proof,
my_amount: Int,
inner_solution: Any,
) -> List<Condition> {
// Verify the amount and parent coin id
// TODO: proof is LineageProof is hand optimized here, it should be done by the compiler
let (is_lineage, parent_coin_id) = if unchecked_cast::<Bool>(
(proof as (Any, (Any, Any))).rest.rest,
) {
inline let proof = unchecked_cast::<LineageProof>(proof);
(
true,
coinid(
proof.parent_parent_coin_info,
singleton_puzzle_hash(singleton, proof.parent_inner_puzzle_hash),
proof.parent_amount,
),
)
} else {
inline let proof = unchecked_cast::<EveProof>(proof);
(
false,
coinid(
proof.parent_parent_coin_info,
singleton.launcher_puzzle_hash,
proof.parent_amount,
),
)
};
let valid_amount = my_amount % 2 == 1;
let valid_lineage = is_lineage | (parent_coin_id == singleton.launcher_id);
assert valid_amount & valid_lineage;
// Assert the amount and parent coin id
let assert_amount = AssertMyAmount { amount: my_amount };
let assert_parent = AssertMyParentId { parent_id: parent_coin_id };
let conditions = morph_conditions(singleton, inner_puzzle(...inner_solution), false);
[assert_amount, assert_parent, ...conditions]
}
inline fn singleton_puzzle_hash(singleton: Singleton, inner_puzzle_hash: Bytes32) -> Bytes32 {
curry_tree_hash(singleton.mod_hash, [tree_hash(singleton), inner_puzzle_hash])
}
fn morph_conditions(
singleton: Singleton,
conditions: List<Condition>,
has_odd_output: Bool,
) -> List<Condition> {
if conditions is nil {
assert has_odd_output;
return;
}
inline let (condition, rest) = conditions;
if condition is CreateCoin && condition.amount % 2 == 1 {
assert !has_odd_output;
let rest_odd_output = morph_conditions(singleton, rest, true);
return if condition.amount == -113 {
rest_odd_output
} else {
let morphed = CreateCoin {
puzzle_hash: singleton_puzzle_hash(singleton, condition.puzzle_hash),
amount: condition.amount,
memos: condition.memos,
};
[morphed, ...rest_odd_output]
};
}
[condition, ...morph_conditions(singleton, rest, false)]
}
test fn tests() {
let parent_parent_coin_info = sha256("parent_parent_coin_info");
let launcher_puzzle_hash = sha256("launcher_puzzle");
let launcher_id = coinid(parent_parent_coin_info, launcher_puzzle_hash, 0);
let singleton = Singleton { mod_hash: tree_hash(main), launcher_id, launcher_puzzle_hash };
let inner_puzzle = fn(...solution: Any) => unchecked_cast::<List<Condition>>(solution);
let proof = EveProof { parent_parent_coin_info, parent_amount: 0 };
let p2_puzzle_hash = sha256("p2_puzzle_hash");
let conditions = main(
singleton,
inner_puzzle,
proof,
1,
[CreateCoin { puzzle_hash: p2_puzzle_hash, amount: 1 }],
);
assert tree_hash(conditions) == tree_hash([
AssertMyAmount { amount: 1 },
AssertMyParentId { parent_id: launcher_id },
CreateCoin { puzzle_hash: singleton_puzzle_hash(singleton, p2_puzzle_hash), amount: 1 },
]);
}