lnpbp-0021
1
LNPBP: 0021
2
Layer: Application (5)
3
Vertical: Smart contracts
4
Title: RGB non-fungible assets schema for collectibles (RGB-21)
5
Authors: Dr Maxim Orlovsky <[email protected]>,
6
Carlos Roldan,
7
Giacomo Zucco,
8
Olgsa Ukolova
9
Comments-URI: <https://github.com/LNP-BP/LNPBPs/issues/70>
10
Status: Proposal
11
Type: Standards Track
12
Created: 2020-09-10
13
License: CC0-1.0
Copied!
    Unique tokens & token-specfic data
    Issue control
    Generic token data, internal or external, in different formats
    Engravings (any why Schema subclassing is required)
    LockUTXOs and descriptors for proof of reserves
    Renominations
    Rights splits
1
Schema {
2
rgb_features: none!(),
3
root_id: none!(),
4
genesis: GenesisSchema {
5
metadata: type_map! {
6
FieldType::Name => Once,
7
FieldType::Description => NoneOrOnce,
8
FieldType::Data => NoneOrMore,
9
FieldType::DataFormat => NoneOrOnce,
10
// Proof of reserves UTXO
11
FieldType::LockUtxo => NoneOrMore,
12
// Proof of reserves scriptPubkey descriptor used for
13
// verification
14
FieldType::LockDescriptor => NoneOrUpTo(32),
15
FieldType::Timestamp => Once,
16
FieldType::NftSource => NoneOrMore,
17
FieldType::Salt => Once
18
},
19
owned_rights: type_map! {
20
OwnedRightsType::Inflation => NoneOrOnce,
21
OwnedRightsType::Renomination => NoneOrOnce,
22
OwnedRightsType::Ownership => OnceOrMore
23
},
24
public_rights: none!(),
25
abi: bmap! {
26
// Here we validate hash uniqueness of NftSource values and that
27
// there is always one ownership state per NftSource matching
28
// its hash
29
// and verification of proof of reserves
30
GenesisAction::Validate => Procedure::Embedded(StandardProcedure::NonfungibleInflation)
31
},
32
},
33
extensions: bmap! {},
34
transitions: type_map! {
35
TransitionType::Issue => TransitionSchema {
36
metadata: type_map! {
37
// Proof of reserves UTXO
38
FieldType::LockUtxo => NoneOrMore,
39
// Proof of reserves scriptPubkey descriptor used for
40
// verification
41
FieldType::LockDescriptor => NoneOrUpTo(32),
42
FieldType::NftSource => NoneOrMore,
43
FieldType::Salt => Once
44
},
45
closes: type_map! {
46
OwnedRightsType::Inflation => Once
47
},
48
owned_rights: type_map! {
49
OwnedRightsType::Inflation => NoneOrOnce,
50
OwnedRightsType::Ownership => OnceOrMore
51
},
52
public_rights: none!(),
53
abi: bmap! {
54
// Here we validate hash uniqueness of NftSource values and that
55
// there is always one ownership state per NftSource matching
56
// its hash, plus the fact that
57
// count(in(inflation)) >= count(out(inflation), out(nft_source))
58
// and verification of proof of reserves
59
TransitionAction::Validate => Procedure::Embedded(StandardProcedure::NonfungibleInflation)
60
}
61
},
62
TransitionType::Transfer => TransitionSchema {
63
metadata: type_map! {
64
// By default, use 0
65
FieldType::Salt => Once
66
},
67
closes: type_map! {
68
OwnedRightsType::Ownership => OnceOrMore
69
},
70
owned_rights: type_map! {
71
OwnedRightsType::Ownership => OnceOrMore
72
},
73
public_rights: none!(),
74
abi: none!()
75
},
76
// One engraving per set of tokens
77
TransitionType::Engraving => TransitionSchema {
78
metadata: type_map! {
79
FieldType::Data => NoneOrMore,
80
FieldType::DataFormat => NoneOrOnce,
81
// By default, use 0
82
FieldType::Salt => Once
83
},
84
closes: type_map! {
85
OwnedRightsType::Ownership => OnceOrMore
86
},
87
owned_rights: type_map! {
88
OwnedRightsType::Ownership => OnceOrMore
89
},
90
public_rights: none!(),
91
abi: none!()
92
},
93
TransitionType::Renomination => TransitionSchema {
94
metadata: type_map! {
95
FieldType::Name => NoneOrOnce,
96
FieldType::Description => NoneOrOnce,
97
FieldType::Data => NoneOrMore,
98
FieldType::DataFormat => NoneOrOnce
99
},
100
closes: type_map! {
101
OwnedRightsType::Renomination => Once
102
},
103
owned_rights: type_map! {
104
OwnedRightsType::Renomination => NoneOrOnce
105
},
106
public_rights: none!(),
107
abi: none!()
108
},
109
// Allows split of rights if they were occasionally allocated to the
110
// same UTXO, for instance both assets and issuance right. Without
111
// this type of transition either assets or inflation rights will be
112
// lost.
113
TransitionType::RightsSplit => TransitionSchema {
114
metadata: type_map! {
115
FieldType::Salt => Once
116
},
117
closes: type_map! {
118
OwnedRightsType::Inflation => NoneOrMore,
119
OwnedRightsType::Ownership => NoneOrMore,
120
OwnedRightsType::Renomination => NoneOrOnce
121
},
122
owned_rights: type_map! {
123
OwnedRightsType::Inflation => NoneOrMore,
124
OwnedRightsType::Ownership => NoneOrMore,
125
OwnedRightsType::Renomination => NoneOrOnce
126
},
127
public_rights: none!(),
128
abi: bmap! {
129
// We must allocate exactly one or none rights per each
130
// right used as input (i.e. closed seal); plus we need to
131
// control that sum of inputs is equal to the sum of outputs
132
// for each of state types having assigned confidential
133
// amounts
134
TransitionAction::Validate => Procedure::Embedded(StandardProcedure::RightsSplit)
135
}
136
}
137
},
138
field_types: type_map! {
139
FieldType::Name => DataFormat::String(256),
140
FieldType::Description => DataFormat::String(core::u16::MAX),
141
FieldType::Data => DataFormat::Bytes(core::u16::MAX),
142
FieldType::DataFormat => DataFormat::Unsigned(Bits::Bit16, 0, core::u16::MAX as u128),
143
// While UNIX timestamps allow negative numbers; in context of RGB
144
// Schema, assets can't be issued in the past before RGB or Bitcoin
145
// even existed; so we prohibit all the dates before RGB release
146
// This timestamp is equal to 10/10/2020 @ 2:37pm (UTC) - the same
147
// as for RGB-20 standard.
148
FieldType::Timestamp => DataFormat::Integer(Bits::Bit64, 1602340666, core::i64::MAX as i128),
149
FieldType::LockUtxo => DataFormat::TxOutPoint,
150
FieldType::LockDescriptor => DataFormat::String(core::u16::MAX),
151
FieldType::BurnUtxo => DataFormat::TxOutPoint,
152
// This type is used to "shift" unique tokens ids if there was a
153
// collision between them
154
FieldType::Salt => DataFormat::Unsigned(Bits::Bit32, 0, core::u32::MAX as u128),
155
// Hash of these data serves as a unique NFT identifier;
156
// if NFT contains no intrinsic data than simply put any unique
157
// value here (like counter value, increased with each token);
158
// it must be unique only within single issuance transition
159
FieldType::NftSource => DataFormat::Bytes(core::u16::MAX)
160
},
161
owned_right_types: type_map! {
162
OwnedRightsType::Inflation => StateSchema {
163
// How much issuer can issue tokens on this path
164
format: StateFormat::CustomData(DataFormat::Unsigned(Bits::Bit64, 0, core::u64::MAX as u128)),
165
abi: none!()
166
},
167
OwnedRightsType::Ownership => StateSchema {
168
// This is unique token identifier, which is
169
// SHA256(SHA256(nft_source_state), issue_transition_id)
170
// convoluted to 32-bits with XOR operation and then XORed with
171
// salt value from state transition metadata.
172
// NB: It is unique inside single state transition only, not
173
// globally. For global unique id use non-convoluted hash value.
174
format: StateFormat::CustomData(DataFormat::Unsigned(Bits::Bit32, 0, core::u32::MAX as u128)),
175
abi: bmap! {
176
// Here we ensure that each unique state value is
177
// transferred once and only once (using "salt" value for
178
// collision resoultion)
179
AssignmentAction::Validate => Procedure::Embedded(StandardProcedure::IdentityTransfer)
180
}
181
},
182
OwnedRightsType::Renomination => StateSchema {
183
format: StateFormat::Declarative,
184
abi: none!()
185
}
186
},
187
public_right_types: none!(),
188
}
Copied!
Last modified 3mo ago
Export as PDF
Copy link