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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use std::collections::BTreeSet;
use bitcoin::OutPoint;
use rgb::fungible::allocation::{AllocationMap, AllocationValueMap, AllocationValueVec};
use rgb::prelude::*;
use seals::txout::ExplicitSeal;
use super::schema::{OwnedRightType, TransitionType};
use super::Asset;
/// Errors happening during construction of RGB-121 asset state transitions
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error)]
#[display(doc_comments)]
pub enum Error {
/// input {0} is not related to the contract
UnrelatedInput(OutPoint),
/// sum of inputs and outputs is not equal
InputsNotEqualOutputs,
/// issue allowance {allowed} for the provided set of issue-controlling
/// rights is insufficient to issue the requested amount {requested}
InsufficientIssueAllowance {
/// Allowed issue value
allowed: AtomicValue,
/// Requested issue value
requested: AtomicValue,
},
/// the requested supply {requested} does not match the total supply
/// {assigned} allocated to the owned rights consumed by the operation
SupplyMismatch {
/// Assigned supply change rights
assigned: AtomicValue,
/// Requested supply change
requested: AtomicValue,
},
/// method was provided with a set of seals for owned rights which are not
/// a part of the asset data: {0:?}
UnknownSeals(BTreeSet<OutPoint>),
}
impl Asset {
/// Performs secondary issue closing an inflation-controlling seal over
/// inflation state transition, which is constructed and returned by this
/// function
pub fn inflate(
&self,
_closing: BTreeSet<OutPoint>,
_next_inflation: AllocationValueMap,
_allocations: AllocationValueVec,
) -> Result<Transition, Error> {
todo!()
}
/// Opens a new epoch by closing epoch-controlling seal over epoch opening
/// state transition, which is constructed and returned by this function
pub fn epoch(
&self,
_closing: OutPoint,
_next_epoch: Option<ExplicitSeal>,
_burning_seal: Option<ExplicitSeal>,
) -> Result<Transition, Error> {
todo!()
}
/// Burns certain amount of the asset by closing burn-controlling seal over
/// proof-of-burn state transition, which is constructed and returned by
/// this function
pub fn burn(
&self,
_closing: OutPoint,
_burned_value: AtomicValue,
_burned_utxos: BTreeSet<OutPoint>,
_next_burn: Option<ExplicitSeal>,
) -> Result<Transition, Error> {
todo!()
}
/// Burns and re-allocates certain amount of the asset by closing
/// burn-controlling seal over proof-of-burn state transition, which is
/// constructed and returned by this function
pub fn burn_replace(
&self,
_closing: OutPoint,
_burned_value: AtomicValue,
_burned_utxos: BTreeSet<OutPoint>,
_next_burn: Option<ExplicitSeal>,
_allocations: AllocationValueVec,
) -> Result<Transition, Error> {
todo!()
}
/// Creates a fungible asset-specific state transition (i.e. RGB-121
/// schema-based) given an asset information, inputs and desired outputs
pub fn transfer(
&self,
inputs: BTreeSet<OutPoint>,
payment: EndpointValueMap,
change: SealValueMap,
) -> Result<Transition, Error> {
// Collecting all input allocations
let mut input_usto = Vec::<OwnedValue>::new();
for outpoint in inputs {
let coins = self.outpoint_coins(outpoint);
if coins.is_empty() {
Err(Error::UnrelatedInput(outpoint))?
}
input_usto.extend(coins);
}
// Computing sum of inputs
let input_amounts: Vec<_> = input_usto.iter().map(|coin| coin.state).collect();
let total_inputs = input_amounts
.iter()
.fold(0u64, |acc, coin| acc + coin.value);
let total_outputs = change.sum() + payment.sum();
if total_inputs != total_outputs {
Err(Error::InputsNotEqualOutputs)?
}
let assignments = type_map! {
OwnedRightType::Assets =>
TypedAssignments::zero_balanced(input_amounts, change, payment)
};
let mut parent = ParentOwnedRights::default();
for coin in input_usto {
parent
.entry(coin.outpoint.node_id)
.or_insert_with(|| empty!())
.entry(OwnedRightType::Assets.into())
.or_insert_with(|| empty!())
.push(coin.outpoint.no);
}
let transition = Transition::with(
TransitionType::Transfer,
empty!(),
empty!(),
assignments.into(),
empty!(),
parent,
);
Ok(transition)
}
}