Skip to content

Commit

Permalink
Merge branch 'main' into add-remaining-events
Browse files Browse the repository at this point in the history
  • Loading branch information
julienbrs authored Jul 24, 2024
2 parents 6b3714a + 2f264a7 commit 9bb8233
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 69 deletions.
39 changes: 27 additions & 12 deletions src/components/metadata.cairo
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
use starknet::ClassHash;
use starknet::{ClassHash, ContractAddress};

#[starknet::interface]
trait IMetadataHandler<TContractState> {
fn uri(self: @TContractState, token_id: u256) -> ByteArray;
fn uri(self: @TContractState, token_id: u256) -> Span<felt252>;
fn get_provider(self: @TContractState) -> ContractAddress;
fn set_provider(ref self: TContractState, provider: ContractAddress);
fn get_uri(self: @TContractState) -> ClassHash;
fn set_uri(ref self: TContractState, class_hash: ClassHash);
}

#[starknet::interface]
trait IMetadataDescriptor<TContractState> {
fn construct_uri(self: @TContractState, token_id: u256) -> ByteArray;
fn construct_uri(self: @TContractState, token_id: u256) -> Span<felt252>;
}

#[starknet::component]
mod MetadataComponent {
use starknet::ClassHash;
use starknet::{ClassHash, ContractAddress};
use super::{IMetadataDescriptorLibraryDispatcher, IMetadataDescriptorDispatcherTrait};

#[storage]
struct Storage {
uri_implementation: ClassHash
MetadataHandler_uri_implementation: ClassHash,
MetadataHandler_provider: ContractAddress,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -37,17 +41,29 @@ mod MetadataComponent {
impl CarbonV3Metadata<
TContractState, +HasComponent<TContractState>
> of super::IMetadataHandler<ComponentState<TContractState>> {
fn uri(self: @ComponentState<TContractState>, token_id: u256) -> ByteArray {
let class_hash = self.uri_implementation.read();
fn uri(self: @ComponentState<TContractState>, token_id: u256) -> Span<felt252> {
let class_hash = self.MetadataHandler_uri_implementation.read();
let uri_lib = IMetadataDescriptorLibraryDispatcher { class_hash };
uri_lib.construct_uri(token_id)
}

fn set_uri(ref self: ComponentState<TContractState>, class_hash: ClassHash) {
fn get_provider(self: @ComponentState<TContractState>) -> ContractAddress {
self.MetadataHandler_provider.read()
}

fn set_provider(ref self: ComponentState<TContractState>, provider: ContractAddress) {
self.MetadataHandler_provider.write(provider);
}

fn get_uri(self: @ComponentState<TContractState>,) -> ClassHash {
self.MetadataHandler_uri_implementation.read()
}

fn set_uri(ref self: ComponentState<TContractState>, class_hash: ClassHash,) {
assert(!class_hash.is_zero(), 'URI class hash cannot be zero');
let old_class_hash = self.uri_implementation.read();
let old_class_hash = self.MetadataHandler_uri_implementation.read();
self.MetadataHandler_uri_implementation.write(class_hash);
self.emit(MetadataUpgraded { old_class_hash, class_hash });
self.uri_implementation.write(class_hash);
}
}
}
Expand All @@ -69,7 +85,6 @@ mod TestMetadataComponent {
let dispatcher = IMetadataHandlerDispatcher { contract_address };

dispatcher.set_uri(metadata_class.class_hash);
let uri = dispatcher.uri(1);
assert_eq!(uri, "bla bla bla");
assert_eq!(dispatcher.get_uri(), metadata_class.class_hash);
}
}
98 changes: 60 additions & 38 deletions src/contracts/project.cairo
Original file line number Diff line number Diff line change
@@ -1,48 +1,51 @@
use starknet::ContractAddress;
use starknet::{ContractAddress, ClassHash};

#[starknet::interface]
trait IExternal<ContractState> {
fn mint(ref self: ContractState, to: ContractAddress, token_id: u256, value: u256);
fn offset(ref self: ContractState, from: ContractAddress, token_id: u256, value: u256);
trait IExternal<TContractState> {
fn mint(ref self: TContractState, to: ContractAddress, token_id: u256, value: u256);
fn offset(ref self: TContractState, from: ContractAddress, token_id: u256, value: u256);
fn batch_mint(
ref self: ContractState, to: ContractAddress, token_ids: Span<u256>, values: Span<u256>
ref self: TContractState, to: ContractAddress, token_ids: Span<u256>, values: Span<u256>
);
fn batch_offset(
ref self: ContractState, from: ContractAddress, token_ids: Span<u256>, values: Span<u256>
ref self: TContractState, from: ContractAddress, token_ids: Span<u256>, values: Span<u256>
);
fn set_uri(ref self: ContractState, uri: ByteArray);
fn get_uri(self: @ContractState, token_id: u256) -> ByteArray;
fn decimals(self: @ContractState) -> u8;
fn only_owner(self: @ContractState, caller_address: ContractAddress) -> bool;
fn grant_minter_role(ref self: ContractState, minter: ContractAddress);
fn revoke_minter_role(ref self: ContractState, account: ContractAddress);
fn grant_offsetter_role(ref self: ContractState, offsetter: ContractAddress);
fn revoke_offsetter_role(ref self: ContractState, account: ContractAddress);
fn balance_of(self: @ContractState, account: ContractAddress, token_id: u256) -> u256;
fn uri(self: @TContractState, token_id: u256) -> Span<felt252>;
fn get_provider(self: @TContractState) -> ContractAddress;
fn set_provider(ref self: TContractState, provider: ContractAddress);
fn get_uri(self: @TContractState) -> ClassHash;
fn set_uri(ref self: TContractState, class_hash: ClassHash);
fn decimals(self: @TContractState) -> u8;
fn only_owner(self: @TContractState, caller_address: ContractAddress) -> bool;
fn grant_minter_role(ref self: TContractState, minter: ContractAddress);
fn revoke_minter_role(ref self: TContractState, account: ContractAddress);
fn grant_offsetter_role(ref self: TContractState, offsetter: ContractAddress);
fn revoke_offsetter_role(ref self: TContractState, account: ContractAddress);
fn balance_of(self: @TContractState, account: ContractAddress, token_id: u256) -> u256;
fn balance_of_batch(
self: @ContractState, accounts: Span<ContractAddress>, token_ids: Span<u256>
self: @TContractState, accounts: Span<ContractAddress>, token_ids: Span<u256>
) -> Span<u256>;
fn shares_of(self: @ContractState, account: ContractAddress, token_id: u256) -> u256;
fn shares_of(self: @TContractState, account: ContractAddress, token_id: u256) -> u256;
fn safe_transfer_from(
ref self: ContractState,
ref self: TContractState,
from: ContractAddress,
to: ContractAddress,
token_id: u256,
value: u256,
data: Span<felt252>
);
fn safe_batch_transfer_from(
ref self: ContractState,
ref self: TContractState,
from: ContractAddress,
to: ContractAddress,
token_ids: Span<u256>,
values: Span<u256>,
data: Span<felt252>
);
fn is_approved_for_all(
self: @ContractState, owner: ContractAddress, operator: ContractAddress
self: @TContractState, owner: ContractAddress, operator: ContractAddress
) -> bool;
fn set_approval_for_all(ref self: ContractState, operator: ContractAddress, approved: bool);
fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool);
}


Expand All @@ -59,8 +62,10 @@ mod Project {
use openzeppelin::introspection::src5::SRC5Component;
// ERC1155
use carbon_v3::components::erc1155::ERC1155Component;
// Absorber
// Vintage
use carbon_v3::components::vintage::VintageComponent;
// Metadata
use carbon_v3::components::metadata::MetadataComponent;
// Access Control - RBAC
use openzeppelin::access::accesscontrol::AccessControlComponent;
// ERC4906
Expand All @@ -73,12 +78,13 @@ mod Project {
component!(path: VintageComponent, storage: vintage, event: VintageEvent);
component!(path: AccessControlComponent, storage: accesscontrol, event: AccessControlEvent);
component!(path: ERC4906Component, storage: erc4906, event: ERC4906Event);
component!(path: MetadataComponent, storage: metadata, event: MetadataEvent);

// ERC1155
impl ERC1155Impl = ERC1155Component::ERC1155Impl<ContractState>;
#[abi(embed_v0)]
impl ERC1155MetadataURIImpl =
ERC1155Component::ERC1155MetadataURIImpl<ContractState>;
// #[abi(embed_v0)]
// impl ERC1155MetadataURIImpl =
// ERC1155Component::ERC1155MetadataURIImpl<ContractState>;
#[abi(embed_v0)]
impl ERC1155Camel = ERC1155Component::ERC1155CamelImpl<ContractState>;
#[abi(embed_v0)]
Expand All @@ -94,6 +100,8 @@ mod Project {
#[abi(embed_v0)]
impl AccessControlImpl =
AccessControlComponent::AccessControlImpl<ContractState>;
// Metadata
impl CarbonV3MetadataImpl = MetadataComponent::CarbonV3MetadataImpl<ContractState>;

impl ERC1155InternalImpl = ERC1155Component::InternalImpl<ContractState>;
impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;
Expand Down Expand Up @@ -127,6 +135,8 @@ mod Project {
accesscontrol: AccessControlComponent::Storage,
#[substorage(v0)]
erc4906: ERC4906Component::Storage,
#[substorage(v0)]
metadata: MetadataComponent::Storage,
}

#[event]
Expand All @@ -146,6 +156,8 @@ mod Project {
AccessControlEvent: AccessControlComponent::Event,
#[flat]
ERC4906Event: ERC4906Component::Event,
#[flat]
MetadataEvent: MetadataComponent::Event,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -166,19 +178,14 @@ mod Project {
// Constructor
#[constructor]
fn constructor(
ref self: ContractState,
base_uri: felt252,
owner: ContractAddress,
starting_year: u32,
number_of_years: u32
ref self: ContractState, owner: ContractAddress, starting_year: u32, number_of_years: u32
) {
self.accesscontrol.initializer();
self.accesscontrol._grant_role(OWNER_ROLE, owner);
self.accesscontrol._set_role_admin(MINTER_ROLE, OWNER_ROLE);
self.accesscontrol._set_role_admin(OFFSETTER_ROLE, OWNER_ROLE);
self.accesscontrol._set_role_admin(OWNER_ROLE, OWNER_ROLE);
let base_uri_bytearray: ByteArray = format!("{}", base_uri);
self.erc1155.initializer(base_uri_bytearray);
self.erc1155.initializer("");
self.ownable.initializer(owner);
self.vintage.initializer(starting_year, number_of_years);

Expand Down Expand Up @@ -227,9 +234,25 @@ mod Project {
self.erc1155.batch_burn(from, token_ids, values);
}

fn set_uri(ref self: ContractState, uri: ByteArray) {
// TODO: use own Metadata impl
self.erc1155.set_base_uri(uri);
fn uri(self: @ContractState, token_id: u256) -> Span<felt252> {
self.metadata.uri(token_id)
}

fn get_provider(self: @ContractState) -> ContractAddress {
self.metadata.get_provider()
}

fn set_provider(ref self: ContractState, provider: ContractAddress) {
let isOwner = self.accesscontrol.has_role(OWNER_ROLE, get_caller_address());
assert!(isOwner, "Caller is not owner");
self.metadata.set_provider(provider);
}

fn set_uri(ref self: ContractState, class_hash: ClassHash) {
let isOwner = self.accesscontrol.has_role(OWNER_ROLE, get_caller_address());
assert!(isOwner, "Caller is not owner");

self.metadata.set_uri(class_hash);

let num_vintages = self.vintage.get_num_vintages();

Expand All @@ -239,9 +262,8 @@ mod Project {
._emit_batch_metadata_update(fromTokenId: 0, toTokenId: num_vintages.into());
}

fn get_uri(self: @ContractState, token_id: u256) -> ByteArray {
let uri_result: ByteArray = self.erc1155.uri(token_id);
uri_result
fn get_uri(self: @ContractState) -> ClassHash {
self.metadata.get_uri()
}

fn decimals(self: @ContractState) -> u8 {
Expand Down
4 changes: 2 additions & 2 deletions src/mock/metadata.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ mod TestMetadata {

#[abi(embed_v0)]
impl MetadataProviderImpl of IMetadataDescriptor<ContractState> {
fn construct_uri(self: @ContractState, token_id: u256) -> ByteArray {
"bla bla bla"
fn construct_uri(self: @ContractState, token_id: u256) -> Span<felt252> {
array!['http://imgur.com/', 'o7a3j', '.png'].span()
}
}
}
1 change: 0 additions & 1 deletion tests/test_mint.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ use snforge_std::{
ContractClassTrait, test_address, spy_events, EventSpy, CheatSpan, start_cheat_caller_address,
stop_cheat_caller_address
};
use alexandria_storage::list::{List, ListTrait};

// Components

Expand Down
2 changes: 0 additions & 2 deletions tests/test_offsetter.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ use snforge_std::{
ContractClassTrait, test_address, spy_events, EventSpy, start_cheat_caller_address,
stop_cheat_caller_address
};
use alexandria_storage::list::{List, ListTrait};

// Components

use carbon_v3::components::vintage::interface::{IVintageDispatcher, IVintageDispatcherTrait};
Expand Down
13 changes: 5 additions & 8 deletions tests/test_project.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use snforge_std::cheatcodes::events::EventSpyAssertionsTrait;
// TODO: use token_ids instead of years as vintage
// Starknet deps

use starknet::{ContractAddress, contract_address_const, get_caller_address};
use starknet::{ContractAddress, contract_address_const, get_caller_address, ClassHash};

// External deps

Expand All @@ -14,7 +14,6 @@ use snforge_std as snf;
use snforge_std::{
ContractClassTrait, EventSpy, start_cheat_caller_address, stop_cheat_caller_address, spy_events
};
use alexandria_storage::list::{List, ListTrait};

// Models

Expand All @@ -27,9 +26,7 @@ use carbon_v3::components::vintage::interface::{
IVintage, IVintageDispatcher, IVintageDispatcherTrait
};
use carbon_v3::components::minter::interface::{IMint, IMintDispatcher, IMintDispatcherTrait};
use carbon_v3::components::erc1155::interface::{
IERC1155MetadataURI, IERC1155MetadataURIDispatcher, IERC1155MetadataURIDispatcherTrait
};
use carbon_v3::components::metadata::{IMetadataHandlerDispatcher, IMetadataHandlerDispatcherTrait};
use erc4906::erc4906_component::ERC4906Component::{Event, MetadataUpdate, BatchMetadataUpdate};

// Contracts
Expand Down Expand Up @@ -719,9 +716,9 @@ fn test_set_uri() {
let project_contract = IProjectDispatcher { contract_address: project_address };

start_cheat_caller_address(project_address, owner_address);
project_contract.set_uri("test_uri");
let uri = project_contract.get_uri(1);
assert_eq!(uri, "test_uri");
project_contract.set_uri('test_uri'.try_into().unwrap());
let uri = project_contract.get_uri();
assert_eq!(uri, 'test_uri'.try_into().unwrap());
}

#[test]
Expand Down
7 changes: 1 addition & 6 deletions tests/tests_lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use snforge_std::{
ContractClassTrait, EventSpy, spy_events, EventSpyTrait, EventSpyAssertionsTrait,
start_cheat_caller_address, stop_cheat_caller_address
};
use alexandria_storage::list::{List, ListTrait};

// Models

Expand Down Expand Up @@ -102,14 +101,10 @@ fn share_to_buy_amount(minter_address: ContractAddress, share: u256) -> u256 {

fn deploy_project() -> ContractAddress {
let contract = snf::declare("Project").expect('Declaration failed');
let uri = 'uri';
let starting_year: u64 = 2024;
let number_of_years: u64 = 20;
let mut calldata: Array<felt252> = array![
uri,
contract_address_const::<'OWNER'>().into(),
starting_year.into(),
number_of_years.into()
contract_address_const::<'OWNER'>().into(), starting_year.into(), number_of_years.into()
];
let (contract_address, _) = contract.deploy(@calldata).expect('Deployment failed');

Expand Down

0 comments on commit 9bb8233

Please sign in to comment.