-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
31 changed files
with
2,465 additions
and
783 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
mod attributes; | ||
mod collection; | ||
|
||
use traits::{Into, TryInto}; | ||
use option::OptionTrait; | ||
|
||
const COLLECTION_ID_MASK: felt252 = 0xffffffffffffffffffffffffffffffffffffffffffffffff; // 2**192 - 1; | ||
|
||
fn get_collection_id(attribute_id: felt252) -> felt252 { | ||
let collection_id = Into::<felt252, u256>::into(attribute_id) & COLLECTION_ID_MASK.into(); | ||
return collection_id.try_into().unwrap(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
use core::serde::Serde; | ||
use starknet::ContractAddress; | ||
use traits::Into; | ||
use traits::TryInto; | ||
use array::ArrayTrait; | ||
use array::SpanTrait; | ||
use option::OptionTrait; | ||
use zeroable::Zeroable; | ||
use clone::Clone; | ||
|
||
use briq_protocol::types::{FTSpec, ShapeItem}; | ||
use briq_protocol::felt_math::{feltBitAnd, feltOrd}; | ||
use briq_protocol::cumulative_balance::{CUM_BALANCE_TOKEN, CB_BRIQ, CB_ATTRIBUTES}; | ||
|
||
use dojo::world::{Context, IWorldDispatcherTrait}; | ||
use dojo_erc::erc1155::components::ERC1155Balance; | ||
use briq_protocol::world_config::{SYSTEM_CONFIG_ID, WorldConfig}; | ||
|
||
use briq_protocol::attributes::get_collection_id; | ||
use briq_protocol::attributes::collection::{Collection, CollectionTrait}; | ||
|
||
use briq_protocol::check_shape::{ShapeVerifier, CheckShapeTrait}; | ||
|
||
use debug::PrintTrait; | ||
|
||
|
||
#[derive(Drop, starknet::Event)] | ||
struct AttributeAssigned { | ||
set_token_id: u256, | ||
attribute_id: felt252 | ||
} | ||
|
||
#[derive(Drop, starknet::Event)] | ||
struct AttributeRemoved { | ||
set_token_id: u256, | ||
attribute_id: felt252 | ||
} | ||
|
||
fn assign_attributes( | ||
ctx: Context, | ||
set_owner: ContractAddress, | ||
set_token_id: felt252, | ||
mut attributes: Array<felt252>, | ||
shape: @Array<ShapeItem>, | ||
fts: @Array<FTSpec>, | ||
) { | ||
loop | ||
{ | ||
if (attributes.len() == 0) { | ||
break (); | ||
} | ||
assign_attribute(ctx, set_owner, set_token_id, attributes.pop_front().unwrap(), shape, fts); | ||
} | ||
} | ||
|
||
fn assign_attribute( | ||
ctx: Context, | ||
set_owner: ContractAddress, | ||
set_token_id: felt252, | ||
attribute_id: felt252, | ||
shape: @Array<ShapeItem>, | ||
fts: @Array<FTSpec>, | ||
) { | ||
assert(set_owner.is_non_zero(), 'Bad input'); | ||
assert(set_token_id != 0, 'Bad input'); | ||
assert(attribute_id != 0, 'Bad input'); | ||
|
||
let caller = ctx.origin; | ||
let set_addr = get!(ctx.world, (SYSTEM_CONFIG_ID), WorldConfig).set; | ||
// TODO: Set permissions on the collection (owner / set) ? | ||
assert (caller == set_addr, 'Bad caller'); | ||
|
||
let collection_id = get_collection_id(attribute_id); | ||
let (admin, system) = get!(ctx.world, (collection_id), Collection).get_admin_or_system(); | ||
if admin.is_some() { | ||
//library_erc1155::transferability::Transferability::_transfer_burnable(0, set_token_id, attribute_id, 1); | ||
assert(0 == 1, 'TODO'); | ||
} else { | ||
let shape_verifier = get!(ctx.world, (attribute_id), ShapeVerifier); | ||
shape_verifier.assign_attribute(ctx.world, set_owner, set_token_id, attribute_id, shape, fts); | ||
} | ||
emit!(ctx.world, AttributeAssigned { set_token_id: set_token_id.into(), attribute_id }); | ||
|
||
// Update the cumulative balance | ||
let balance = get!(ctx.world, (CUM_BALANCE_TOKEN(), CB_ATTRIBUTES, set_token_id), ERC1155Balance).amount; | ||
assert(balance < balance + 1, 'Balance overflow'); | ||
set!(ctx.world, ERC1155Balance { token: CUM_BALANCE_TOKEN(), token_id: CB_ATTRIBUTES, account: set_token_id.try_into().unwrap(), amount: balance + 1 }); | ||
} | ||
|
||
fn remove_attributes( | ||
ctx: Context, | ||
set_owner: ContractAddress, | ||
set_token_id: felt252, | ||
mut attributes: Array<felt252> | ||
) { | ||
loop | ||
{ | ||
if (attributes.len() == 0) { | ||
break (); | ||
} | ||
remove_attribute(ctx, set_owner, set_token_id, attributes.pop_front().unwrap()); | ||
} | ||
} | ||
|
||
fn remove_attribute( | ||
ctx: Context, | ||
set_owner: ContractAddress, | ||
set_token_id: felt252, | ||
attribute_id: felt252, | ||
) { | ||
assert(set_owner.is_non_zero(), 'Bad input'); | ||
assert(set_token_id != 0, 'Bad input'); | ||
assert(attribute_id != 0, 'Bad input'); | ||
|
||
let caller = ctx.origin; | ||
let set_addr = get!(ctx.world, (SYSTEM_CONFIG_ID), WorldConfig).set; | ||
// TODO: Set permissions on the collection (owner / set) ? | ||
assert (caller == set_addr, 'Bad caller'); | ||
|
||
let collection_id = get_collection_id(attribute_id); | ||
let (admin, system) = get!(ctx.world, (collection_id), Collection).get_admin_or_system(); | ||
if admin.is_some() { | ||
//library_erc1155::transferability::Transferability::_transfer_burnable(set_token_id, 0, attribute_id, 1); | ||
assert(0 == 1, 'TODO'); | ||
} else { | ||
let shape_verifier = get!(ctx.world, (attribute_id), ShapeVerifier); | ||
shape_verifier.remove_attribute(ctx.world, set_owner, set_token_id, attribute_id); | ||
} | ||
|
||
emit!(ctx.world, AttributeRemoved { set_token_id: set_token_id.into(), attribute_id }); | ||
|
||
// Update the cumulative balance | ||
let balance = get!(ctx.world, (CUM_BALANCE_TOKEN(), CB_ATTRIBUTES, set_token_id), ERC1155Balance).amount; | ||
assert(balance > balance - 1, 'Balance underflow'); | ||
set!(ctx.world, ERC1155Balance { token: CUM_BALANCE_TOKEN(), token_id: CB_ATTRIBUTES, account: set_token_id.try_into().unwrap(), amount: balance - 1 }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
use starknet::ContractAddress; | ||
|
||
const EXISTS_BIT: felt252 = 1; // This bit is always toggled for a collection that exists. | ||
const CONTRACT_BIT: felt252 = 2; | ||
|
||
use traits::{Into, TryInto}; | ||
use option::OptionTrait; | ||
use clone::Clone; | ||
use serde::Serde; | ||
|
||
use briq_protocol::felt_math::{feltBitAnd, feltOrd}; | ||
|
||
#[derive(Component, Copy, Drop, Serde, SerdeLen)] | ||
struct Collection { | ||
#[key] | ||
collection_id: u64, | ||
|
||
parameters: felt252, // bitfield | ||
admin_or_system: ContractAddress, | ||
} | ||
|
||
#[generate_trait] | ||
impl CollectionImpl of CollectionTrait { | ||
fn get_admin_or_system(self: @Collection) -> (Option<ContractAddress>, Option<ContractAddress>) { | ||
let a_o_c = self.admin_or_system; | ||
if *self.parameters & CONTRACT_BIT == 0 { | ||
return (Option::Some(*a_o_c), Option::None); | ||
} else { | ||
return (Option::None, Option::Some(*a_o_c)); | ||
} | ||
} | ||
} | ||
|
||
fn new_collection(collection_id: u64, params: felt252, admin_or_system: ContractAddress) -> Collection { | ||
let existence_bit_toggled = params & EXISTS_BIT; | ||
// Probably indicates an error, fail. | ||
assert(existence_bit_toggled == 0, 'Invalid bits'); | ||
assert(params < 0x400000000000000000000000000000000000000000000000000000000000000, 'Invalid bits'); | ||
|
||
Collection { | ||
collection_id: collection_id, | ||
parameters: params + EXISTS_BIT, | ||
admin_or_system: admin_or_system, | ||
} | ||
} | ||
|
||
#[derive(Clone, Drop, Serde)] | ||
struct CreateCollectionData | ||
{ | ||
collection_id: u64, | ||
params: felt252, | ||
admin_or_system: ContractAddress | ||
} | ||
|
||
#[system] | ||
mod create_collection { | ||
use starknet::ContractAddress; | ||
use traits::Into; | ||
use traits::TryInto; | ||
use array::ArrayTrait; | ||
use array::SpanTrait; | ||
use option::OptionTrait; | ||
use zeroable::Zeroable; | ||
use clone::Clone; | ||
use serde::Serde; | ||
|
||
use dojo::world::Context; | ||
use dojo_erc::erc1155::components::ERC1155Balance; | ||
use briq_protocol::world_config::AdminTrait; | ||
|
||
use briq_protocol::types::{FTSpec, ShapeItem}; | ||
|
||
use briq_protocol::attributes::get_collection_id; | ||
use briq_protocol::attributes::collection::{Collection, CollectionTrait, new_collection}; | ||
|
||
use debug::PrintTrait; | ||
|
||
use super::CreateCollectionData; | ||
|
||
#[derive(Drop, starknet::Event)] | ||
struct CollectionCreated { | ||
collection_id: u64, | ||
system: ContractAddress, | ||
admin: ContractAddress, | ||
parameters: felt252 | ||
} | ||
|
||
fn execute( | ||
ctx: Context, | ||
data: CreateCollectionData, | ||
) { | ||
let CreateCollectionData { collection_id, params, admin_or_system } = data; | ||
|
||
assert(admin_or_system.is_non_zero(), 'Must have admin'); | ||
|
||
// TODO: check ctx.origin is actually the origin | ||
ctx.world.only_admins(@ctx.origin); | ||
|
||
assert(get!(ctx.world, (collection_id), Collection).parameters == 0, 'Collec already exists'); | ||
|
||
let collec = new_collection(collection_id, params, admin_or_system); | ||
|
||
set!(ctx.world, (collec)); | ||
|
||
let (admin, system) = collec.get_admin_or_system(); | ||
if admin.is_some() { | ||
emit!(ctx.world, CollectionCreated { collection_id, system: Zeroable::zero(), admin: admin.unwrap(), parameters:params }); | ||
} else { | ||
emit!(ctx.world, CollectionCreated { collection_id, system: system.unwrap(), admin: Zeroable::zero(), parameters:params }); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
mod unboxing; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
use traits::Into; | ||
use traits::TryInto; | ||
use option::OptionTrait; | ||
|
||
use array::ArrayTrait; | ||
|
||
use starknet::ContractAddress; | ||
|
||
use dojo::world::IWorldDispatcher; | ||
|
||
use briq_protocol::world_config::{get_world_config, AdminTrait}; | ||
|
||
#[derive(Drop, Copy, Serde)] | ||
struct BoxData { | ||
briq_1: felt252, // nb of briqs of material 0x1 | ||
shape_class_hash: felt252, // Class hash of the matching shape contract | ||
} | ||
|
||
fn get_number_of_briqs_in_box(box_id: felt252) -> u128 | ||
{ | ||
// TODO: use match once that's supported | ||
if box_id == 1 { return 434; } | ||
if box_id == 2 { return 1252; } | ||
if box_id == 3 { return 2636; } | ||
if box_id == 4 { return 431; } | ||
if box_id == 5 { return 1246; } | ||
if box_id == 6 { return 2287; } | ||
if box_id == 7 { return 431; } | ||
if box_id == 8 { return 1286; } | ||
if box_id == 9 { return 2392; } | ||
if box_id == 10 { return 60; } // briqmas | ||
assert(false, 'bad box id'); | ||
0 | ||
} | ||
|
||
fn get_booklet_id_for_box(box_id: felt252) -> felt252 | ||
{ | ||
// TODO: use match once that's supported | ||
if box_id == 1 { return 0x1000000000000000000000000000000000000000000000001; } | ||
if box_id == 2 { return 0x2000000000000000000000000000000000000000000000001; } | ||
if box_id == 3 { return 0x3000000000000000000000000000000000000000000000001; } | ||
if box_id == 4 { return 0x4000000000000000000000000000000000000000000000001; } | ||
if box_id == 5 { return 0x5000000000000000000000000000000000000000000000001; } | ||
if box_id == 6 { return 0x6000000000000000000000000000000000000000000000001; } | ||
if box_id == 7 { return 0x7000000000000000000000000000000000000000000000001; } | ||
if box_id == 8 { return 0x8000000000000000000000000000000000000000000000001; } | ||
if box_id == 9 { return 0x9000000000000000000000000000000000000000000000001; } | ||
// TODO warning delta migration | ||
if box_id == 10 { return 0x1000000000000000000000000000000000000000000000002; } // briqmas | ||
assert(false, 'Invalid box id'); | ||
0 | ||
} | ||
|
||
fn unbox(world: IWorldDispatcher, owner: ContractAddress, box_id: felt252) | ||
{ | ||
// Burn the box | ||
// TODO: use event-emitting variant | ||
dojo_erc::erc1155::components::ERC1155BalanceTrait::transfer_tokens( | ||
world, | ||
get_world_config(world).box, | ||
owner, | ||
Zeroable::zero(), | ||
array![box_id].span(), | ||
array![1].span(), | ||
); | ||
|
||
// Mint a booklet | ||
// TODO: use event-emitting variant | ||
dojo_erc::erc1155::components::ERC1155BalanceTrait::transfer_tokens( | ||
world, | ||
get_world_config(world).booklet, | ||
Zeroable::zero(), | ||
owner, | ||
array![get_booklet_id_for_box(box_id)].span(), | ||
array![1].span(), | ||
); | ||
// TODO: register a specific shape verifier for this booklet ? | ||
// Or will that be handled directly by a different system maybe... | ||
|
||
// Mint briqs | ||
|
||
briq_protocol::briq_token::systems::update_nocheck( | ||
world, | ||
owner, | ||
get_world_config(world).briq, | ||
from: Zeroable::zero(), | ||
to: owner, | ||
ids: array![1], | ||
amounts: array![get_number_of_briqs_in_box(box_id)], | ||
data: array![] | ||
); | ||
} | ||
|
||
// Unbox burns the box NFT, and mints briqs & attributes_registry corresponding to the token URI. | ||
#[system] | ||
mod box_unboxing { | ||
use traits::{Into, TryInto}; | ||
use option::OptionTrait; | ||
use array::ArrayTrait; | ||
use dojo::world::Context; | ||
use zeroable::Zeroable; | ||
use starknet::ContractAddress; | ||
|
||
fn execute( | ||
ctx: Context, | ||
box_id: felt252, | ||
) { | ||
// Only the owner may unbox their box. | ||
super::unbox(ctx.world, ctx.origin, box_id); | ||
} | ||
} |
Oops, something went wrong.