Skip to content

Commit c3fa368

Browse files
authored
Merge pull request #96 from hashed-io/develop
Updates to v114: ### Gated marketplaces - adds feedback field in Application Struct - adds reapply functionality - changes some errors and functions names within `gated_marketplaces` ### Fruniques - general adjustements - adds `create_with_attributes` extrinsic - adds `account_id_to_lookup_source`, `mint`, `freeze`, `burn`, `do_create` helper functions
2 parents 1416b5b + 34dd780 commit c3fa368

File tree

11 files changed

+514
-145
lines changed

11 files changed

+514
-145
lines changed

.vscode/tasks.json

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,55 @@
33
// for the documentation about the tasks.json format
44
"version": "2.0.0",
55
"tasks": [
6-
{
7-
"label": "Run ",
8-
"type": "shell",
9-
"command": "cargo",
10-
"args": ["run", "--release", "--", "--dev"],
11-
"group": {
12-
"kind": "build",
13-
"isDefault": true
14-
},
15-
"presentation": {
16-
"reveal": "always",
17-
"panel": "new"
18-
},
19-
"problemMatcher": [
20-
{
21-
"owner": "rust",
22-
"fileLocation": ["relative", "${workspaceRoot}"],
23-
"pattern": {
24-
"regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
25-
"file": 1,
26-
"line": 2,
27-
"column": 3,
28-
"endLine": 4,
29-
"endColumn": 5,
30-
"severity": 6,
31-
"message": 7
32-
}
6+
{
7+
"label": "Run ",
8+
"type": "shell",
9+
"command": "cargo",
10+
"args": [
11+
"run",
12+
"--release",
13+
"--",
14+
"--dev"
15+
],
16+
"group": {
17+
"kind": "build",
18+
"isDefault": true
19+
},
20+
"presentation": {
21+
"reveal": "always",
22+
"panel": "new"
23+
},
24+
"problemMatcher": [
25+
{
26+
"owner": "rust",
27+
"fileLocation": [
28+
"relative",
29+
"${workspaceRoot}"
30+
],
31+
"pattern": {
32+
"regexp": "^(.*):(\\d+):(\\d+):\\s+(\\d+):(\\d+)\\s+(warning|error):\\s+(.*)$",
33+
"file": 1,
34+
"line": 2,
35+
"column": 3,
36+
"endLine": 4,
37+
"endColumn": 5,
38+
"severity": 6,
39+
"message": 7
3340
}
34-
]
35-
}
41+
}
42+
]
43+
},
44+
{
45+
"type": "cargo",
46+
"command": "test",
47+
"problemMatcher": [
48+
"$rustc"
49+
],
50+
"group": {
51+
"kind": "test",
52+
"isDefault": true
53+
},
54+
"label": "rust: cargo test"
55+
}
3656
]
37-
}
57+
}

pallets/fruniques/src/functions.rs

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use frame_system::pallet_prelude::*;
55
use scale_info::prelude::string::String;
66
// use crate::types::*;
77
use frame_support::pallet_prelude::*;
8-
use sp_runtime::sp_std::vec::Vec;
8+
use sp_runtime::{sp_std::vec::Vec, Permill};
99

1010
impl<T: Config> Pallet<T> {
1111
pub fn u32_to_instance_id(input: u32) -> T::ItemId
@@ -27,6 +27,13 @@ impl<T: Config> Pallet<T> {
2727
}
2828
s
2929
}
30+
31+
pub fn account_id_to_lookup_source(
32+
account_id: &T::AccountId,
33+
) -> <T::Lookup as sp_runtime::traits::StaticLookup>::Source {
34+
<T::Lookup as sp_runtime::traits::StaticLookup>::unlookup(account_id.clone())
35+
}
36+
3037
/// Helper function for printing purposes
3138
pub fn get_nft_attribute(
3239
class_id: &T::CollectionId,
@@ -60,4 +67,75 @@ impl<T: Config> Pallet<T> {
6067
)?;
6168
Ok(())
6269
}
70+
71+
pub fn mint(
72+
origin: OriginFor<T>,
73+
class_id: &T::CollectionId,
74+
instance_id: T::ItemId,
75+
owner: <T::Lookup as sp_runtime::traits::StaticLookup>::Source,
76+
) -> DispatchResult {
77+
pallet_uniques::Pallet::<T>::mint(origin, *class_id, instance_id, owner)?;
78+
Ok(())
79+
}
80+
81+
pub fn freeze(
82+
origin: OriginFor<T>,
83+
class_id: &T::CollectionId,
84+
instance_id: T::ItemId,
85+
) -> DispatchResult {
86+
pallet_uniques::Pallet::<T>::freeze(origin, *class_id, instance_id)?;
87+
Ok(())
88+
}
89+
90+
// TODO: add a function to get the owner of an instance
91+
// TODO: add a function to burn an instance
92+
pub fn burn(
93+
origin: OriginFor<T>,
94+
class_id: &T::CollectionId,
95+
instance_id: T::ItemId,
96+
) -> DispatchResult {
97+
let admin = Self::admin_of(class_id, &instance_id);
98+
ensure!(admin.is_some(), "Instance is not owned by anyone");
99+
100+
pallet_uniques::Pallet::<T>::burn(
101+
origin,
102+
*class_id,
103+
instance_id,
104+
Some(Self::account_id_to_lookup_source(&admin.unwrap())),
105+
)?;
106+
Ok(())
107+
}
108+
109+
// TODO: add a function to transfer an instance
110+
pub fn do_create(
111+
origin: OriginFor<T>,
112+
class_id: T::CollectionId,
113+
instance_id: T::ItemId,
114+
numeric_value: Option<Permill>,
115+
admin: <T::Lookup as sp_runtime::traits::StaticLookup>::Source,
116+
) -> DispatchResult {
117+
pallet_uniques::Pallet::<T>::create(origin.clone(), class_id.clone(), admin.clone())?;
118+
119+
Self::mint(origin.clone(), &class_id, instance_id.clone(), admin.clone())?;
120+
121+
if let Some(n) = numeric_value {
122+
let num_value_key = BoundedVec::<u8, T::KeyLimit>::try_from(r#"num_value"#.encode())
123+
.expect("Error on encoding the numeric value key to BoundedVec");
124+
let num_value = BoundedVec::<u8, T::ValueLimit>::try_from(n.encode())
125+
.expect("Error on encoding the numeric value to BoundedVec");
126+
pallet_uniques::Pallet::<T>::set_attribute(
127+
origin.clone(),
128+
class_id,
129+
Some(instance_id),
130+
num_value_key,
131+
num_value,
132+
)?;
133+
}
134+
135+
Ok(())
136+
}
137+
138+
pub fn do_spawn() -> DispatchResult {
139+
Ok(())
140+
}
63141
}

pallets/fruniques/src/lib.rs

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -100,31 +100,9 @@ pub mod pallet {
100100
) -> DispatchResult {
101101
let owner = ensure_signed(origin.clone())?;
102102

103-
let new_cnt =
104-
Self::frunique_cnt().checked_add(1).ok_or(<Error<T>>::FruniqueCntOverflow)?;
105103
// create an NFT in the uniques pallet
106-
pallet_uniques::Pallet::<T>::create(origin.clone(), class_id.clone(), admin.clone())?;
107-
pallet_uniques::Pallet::<T>::mint(
108-
origin.clone(),
109-
class_id.clone(),
110-
instance_id.clone(),
111-
admin.clone(),
112-
)?;
113-
<FruniqueCnt<T>>::put(new_cnt);
114-
if let Some(n) = numeric_value {
115-
let num_value_key =
116-
BoundedVec::<u8, T::KeyLimit>::try_from(r#"num_value"#.encode())
117-
.expect("Error on encoding the numeric value key to BoundedVec");
118-
let num_value = BoundedVec::<u8, T::ValueLimit>::try_from(n.encode())
119-
.expect("Error on encoding the numeric value to BoundedVec");
120-
pallet_uniques::Pallet::<T>::set_attribute(
121-
origin.clone(),
122-
class_id,
123-
Some(instance_id),
124-
num_value_key,
125-
num_value,
126-
)?;
127-
}
104+
Self::do_create(origin.clone(), class_id, instance_id, numeric_value, admin.clone())?;
105+
128106
let admin = T::Lookup::lookup(admin)?;
129107
Self::deposit_event(Event::FruniqueCreated(owner, admin, class_id, instance_id));
130108

@@ -182,6 +160,49 @@ pub mod pallet {
182160
Ok(())
183161
}
184162

163+
/// ## Create a frunique with given attributes.
164+
/// `origin` must be signed by the owner of the frunique.
165+
/// - `attributes` must be a list of pairs of `key` and `value`.
166+
/// `key` must be a valid key for the asset class.
167+
/// `value` must be a valid value for the asset class.
168+
/// `attributes` must not be empty.
169+
/// - `instance_id` must be a valid instance of the asset class.
170+
/// - `class_id` must be a valid class of the asset class.
171+
/// - `numeric_value` must be a valid value for the asset class.
172+
/// - `admin` must be a valid admin of the asset class.
173+
/// - `instance_id` must not be already in use.
174+
/// - `class_id` must not be already in use.
175+
/// - `numeric_value` must not be already in use.
176+
#[pallet::weight(10_000 + T::DbWeight::get().writes(1))]
177+
pub fn create_with_attributes(
178+
origin: OriginFor<T>,
179+
class_id: T::CollectionId,
180+
instance_id: T::ItemId,
181+
numeric_value: Option<Permill>,
182+
admin: <T::Lookup as sp_runtime::traits::StaticLookup>::Source,
183+
attributes: Vec<(BoundedVec<u8, T::KeyLimit>, BoundedVec<u8, T::ValueLimit>)>,
184+
) -> DispatchResult {
185+
// ! Ensure the admin is the one who can add attributes to the frunique.
186+
ensure!(!attributes.is_empty(), Error::<T>::AttributesEmpty);
187+
188+
let owner = ensure_signed(origin.clone())?;
189+
// create an NFT in the uniques pallet
190+
Self::do_create(origin.clone(), class_id, instance_id, numeric_value, admin.clone())?;
191+
for attribute in &attributes {
192+
Self::set_attribute(
193+
origin.clone(),
194+
&class_id.clone(),
195+
Self::u32_to_instance_id(instance_id.clone()),
196+
attribute.0.clone(),
197+
attribute.1.clone(),
198+
)?;
199+
}
200+
201+
let admin = T::Lookup::lookup(admin)?;
202+
Self::deposit_event(Event::FruniqueCreated(owner, admin, class_id, instance_id));
203+
Ok(())
204+
}
205+
185206
/// ## NFT Division
186207
///
187208
/// PD: the Key/value length limits are inherited from the uniques pallet,
@@ -213,21 +234,14 @@ pub mod pallet {
213234
// Boilerplate (setup, conversions, ensure_signed)
214235
let owner = ensure_signed(origin.clone())?;
215236
let encoded_id = instance_id.encode();
216-
let new_cnt =
217-
Self::frunique_cnt().checked_add(1).ok_or(<Error<T>>::FruniqueCntOverflow)?;
218237
// TODO: Check if the instance_id exists?
219238
let parent_id_key = BoundedVec::<u8, T::KeyLimit>::try_from(r#"parent_id"#.encode())
220239
.expect("Error on encoding the parent_id key to BoundedVec");
221240
let mut parent_id_val: BoundedVec<u8, T::ValueLimit>;
222241
// Instance n number of nfts (with the respective parentId)
223242
let new_instance_id = Self::frunique_cnt().try_into().unwrap();
224243
// Mint a unique
225-
pallet_uniques::Pallet::<T>::mint(
226-
origin.clone(),
227-
class_id,
228-
new_instance_id,
229-
admin.clone(),
230-
)?;
244+
Self::mint(origin.clone(), &class_id, new_instance_id, admin.clone())?;
231245
// Set the respective attributtes
232246
if inherit_attrs {
233247
// TODO: Check all the parent's instance attributes
@@ -253,10 +267,10 @@ pub mod pallet {
253267
BoundedVec::<u8, T::KeyLimit>::try_from(r#"num_value"#.encode())
254268
.expect("Error on encoding the num_value key to BoundedVec");
255269
// TODO: Call bytes_to_u32 & divide the numeric value before setting it
256-
pallet_uniques::Pallet::<T>::set_attribute(
270+
Self::set_attribute(
257271
origin.clone(),
258-
class_id,
259-
Some(Self::u32_to_instance_id(new_instance_id)),
272+
&class_id,
273+
Self::u32_to_instance_id(new_instance_id),
260274
num_value_key,
261275
num_value,
262276
)?;
@@ -279,21 +293,31 @@ pub mod pallet {
279293
.expect("Error on converting the parent_id to BoundedVec");
280294
}
281295
// (for encoding reasons the parentId is stored on hex format as a secondary side-effect, I hope it's not too much of a problem).
282-
pallet_uniques::Pallet::<T>::set_attribute(
296+
Self::set_attribute(
283297
origin.clone(),
284-
class_id,
285-
Some(Self::u32_to_instance_id(new_instance_id)),
298+
&class_id,
299+
Self::u32_to_instance_id(new_instance_id),
286300
parent_id_key,
287301
parent_id_val,
288302
)?;
289303
let _e = Self::instance_exists(origin, class_id, instance_id);
290304
//let final_test = pallet_uniques::Pallet::<T>::attribute(&class_id, &Self::u16_to_instance_id(new_instance_id ), &r#"parent_id"#.encode() );
291305
//println!("The parent_id of {} is now {:?}",new_instance_id, Self::bytes_to_u32(final_test.unwrap()) );
292-
<FruniqueCnt<T>>::put(new_cnt);
293306
// TODO: set the divided value attribute. Numbers, divisions and floating points are giving a lot of problems
294307
let admin = T::Lookup::lookup(admin)?;
295308
Self::deposit_event(Event::FruniqueDivided(owner, admin, class_id, instance_id));
296309
// Freeze the nft to prevent trading it? Burn it? Not clear, so nothing at the moment
310+
// Freeze parent
311+
312+
// unique -> n parts of parent
313+
// unique is freezed
314+
// 1, 2, 3, 4, ..., n
315+
// alice 1 & bob 1 & carol 1 & ... & n
316+
// (n - 5) -> m parts of parent
317+
// m parts of the new frunique
318+
// n
319+
320+
297321
Ok(())
298322
}
299323
}

pallets/fruniques/src/tests.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,33 @@ fn create_frunique_works() {
4141
});
4242
}
4343

44+
#[test]
45+
fn create_frunique_with_attributes_should_work() {
46+
// Create a frunique with attributes
47+
ExtBuilder::default().build().execute_with(|| {
48+
assert_noop!(
49+
Fruniques::create_with_attributes(
50+
Origin::signed(1),
51+
1,
52+
0,
53+
Some(Permill::from_percent(50)),
54+
1,
55+
vec![]
56+
),
57+
Error::<Test>::AttributesEmpty
58+
);
59+
60+
assert_ok!(Fruniques::create_with_attributes(
61+
Origin::signed(1),
62+
1,
63+
0,
64+
Some(Permill::from_percent(50)),
65+
1,
66+
vec![(bvec![0], bvec![0])],
67+
));
68+
});
69+
}
70+
4471
// this test is failing for some reason...
4572
/*---- tests::spawn_extrinsic_works stdout ----
4673
thread 'tests::spawn_extrinsic_works' panicked at 'Expected Ok(_). Got Err(
@@ -65,7 +92,14 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
6592
fn spawn_extrinsic_works() {
6693
ExtBuilder::default().build().execute_with(|| {
6794
assert_ok!(Fruniques::create(Origin::signed(1), 1, 0, Some(Permill::from_percent(50)), 1));
68-
assert_ok!(Fruniques::spawn(Origin::signed(1), 1, 255, true, Permill::from_float(20.525), 1));
95+
assert_ok!(Fruniques::spawn(
96+
Origin::signed(1),
97+
1,
98+
255,
99+
true,
100+
Permill::from_float(20.525),
101+
1
102+
));
69103
//Fruniques::spawn(Origin::signed(1),1,255,true,Permill::from_float(20.525),1 );
70104
assert_ok!(Fruniques::spawn(Origin::signed(1), 1, 1, true, Permill::from_float(20.525), 1));
71105
assert_ok!(Fruniques::instance_exists(Origin::signed(1), 1, 1));

0 commit comments

Comments
 (0)