Skip to content

Commit

Permalink
added metadata hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
rsodre committed Jun 30, 2024
1 parent fdc28c1 commit 286d785
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 1 deletion.
3 changes: 3 additions & 0 deletions token/src/components/tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod mocks {
mod erc721_balance_mock;
mod erc721_enumerable_mock;
mod erc721_metadata_mock;
mod erc721_metadata_hooks_mock;
mod erc721_mintable_burnable_mock;
mod erc721_receiver_mock;
}
Expand Down Expand Up @@ -55,6 +56,8 @@ mod token {
#[cfg(test)]
mod test_erc721_metadata;
#[cfg(test)]
mod test_erc721_metadata_hooks;
#[cfg(test)]
mod test_erc721_mintable_burnable;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use dojo::world::IWorldDispatcher;

#[starknet::interface]
// trait IERC721EnumMintBurnPreset {
trait IERC721MetadataHooksMock<TContractState> {
// IWorldProvider
fn world(self: @TContractState,) -> IWorldDispatcher;
}

#[dojo::contract]
mod erc721_metadata_hooks_mock {

use starknet::{get_contract_address};
use token::components::token::erc721::erc721_approval::erc721_approval_component;
use token::components::token::erc721::erc721_balance::erc721_balance_component;
use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
use token::components::token::erc721::erc721_mintable::erc721_mintable_component;
use token::components::token::erc721::erc721_owner::erc721_owner_component;

component!(
path: erc721_approval_component, storage: erc721_approval, event: ERC721ApprovalEvent
);
component!(path: erc721_balance_component, storage: erc721_balance, event: ERC721BalanceEvent);
component!(
path: erc721_metadata_component, storage: erc721_metadata, event: ERC721MetadataEvent
);
component!(
path: erc721_mintable_component, storage: erc721_mintable, event: ERC721MintableEvent
);
component!(path: erc721_owner_component, storage: erc721_owner, event: ERC721OwnerEvent);

#[abi(embed_v0)]
impl ERC721MetadataImpl =
erc721_metadata_component::ERC721MetadataImpl<ContractState>;

impl ERC721ApprovalInternalImpl = erc721_approval_component::InternalImpl<ContractState>;
impl ERC721BalanceInternalImpl = erc721_balance_component::InternalImpl<ContractState>;
impl ERC721MetadataInternalImpl = erc721_metadata_component::InternalImpl<ContractState>;
impl ERC721MintableInternalImpl = erc721_mintable_component::InternalImpl<ContractState>;
impl ERC721OwnerInternalImpl = erc721_owner_component::InternalImpl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
erc721_approval: erc721_approval_component::Storage,
#[substorage(v0)]
erc721_balance: erc721_balance_component::Storage,
#[substorage(v0)]
erc721_metadata: erc721_metadata_component::Storage,
#[substorage(v0)]
erc721_mintable: erc721_mintable_component::Storage,
#[substorage(v0)]
erc721_owner: erc721_owner_component::Storage,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
ERC721ApprovalEvent: erc721_approval_component::Event,
ERC721BalanceEvent: erc721_balance_component::Event,
ERC721MetadataEvent: erc721_metadata_component::Event,
ERC721MintableEvent: erc721_mintable_component::Event,
ERC721OwnerEvent: erc721_owner_component::Event
}


//
// Metadata Hooks
//
use super::{IERC721MetadataHooksMockDispatcher, IERC721MetadataHooksMockDispatcherTrait};
impl ERC721MetadataHooksImpl<TContractState> of erc721_metadata_component::ERC721MetadataHooksTrait<TContractState> {
fn custom_uri(
self: @erc721_metadata_component::ComponentState<TContractState>,
base_uri: @ByteArray,
token_id: u256,
) -> ByteArray {
//
// example on how to access the world
// (does not work for testing, throws 'CONTRACT_NOT_DEPLOYED')
//
// let contract_address = get_contract_address();
// let selfie = IERC721MetadataHooksMockDispatcher{ contract_address };
// let _world = selfie.world();

format!("CUSTOM{}{}", base_uri, token_id)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod erc721_metadata_mock {
use token::components::token::erc721::erc721_approval::erc721_approval_component;
use token::components::token::erc721::erc721_balance::erc721_balance_component;
use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
use token::components::token::erc721::erc721_metadata_hooks::ERC721MetadataHooksEmptyImpl;
use token::components::token::erc721::erc721_mintable::erc721_mintable_component;
use token::components::token::erc721::erc721_owner::erc721_owner_component;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod erc721_mintable_burnable_mock {
use token::components::token::erc721::erc721_approval::erc721_approval_component;
use token::components::token::erc721::erc721_balance::erc721_balance_component;
use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
use token::components::token::erc721::erc721_metadata_hooks::ERC721MetadataHooksEmptyImpl;
use token::components::token::erc721::erc721_mintable::erc721_mintable_component;
use token::components::token::erc721::erc721_burnable::erc721_burnable_component;
use token::components::token::erc721::erc721_owner::erc721_owner_component;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use integer::BoundedInt;
use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};
use dojo::test_utils::spawn_test_world;
use token::tests::constants::{OWNER};

use token::components::token::erc721::erc721_metadata::{erc_721_meta_model, ERC721MetaModel,};
use token::components::token::erc721::erc721_metadata::erc721_metadata_component::{
ERC721MetadataImpl, ERC721MetadataCamelImpl, InternalImpl
};
use token::components::token::erc721::erc721_mintable::erc721_mintable_component::InternalImpl as ERC721MintableInternalImpl;

use token::components::tests::mocks::erc721::erc721_metadata_hooks_mock::erc721_metadata_hooks_mock;
use starknet::storage::{StorageMemberAccessTrait};


fn STATE() -> (IWorldDispatcher, erc721_metadata_hooks_mock::ContractState) {
let world = spawn_test_world(array![erc_721_meta_model::TEST_CLASS_HASH,]);

let mut state = erc721_metadata_hooks_mock::contract_state_for_testing();
state.world_dispatcher.write(world);

(world, state)
}

#[test]
fn test_erc721_metadata_hooks_initialize() {
let (_world, mut state) = STATE();

let NAME: ByteArray = "NAME";
let SYMBOL: ByteArray = "SYMBOL";
let URI: ByteArray = "URI";

state.erc721_metadata.initialize(NAME, SYMBOL, URI);

assert(state.erc721_metadata.name() == "NAME", 'Should be NAME');
assert(state.erc721_metadata.symbol() == "SYMBOL", 'Should be SYMBOL');

state.erc721_mintable.mint(OWNER(), 1);
assert(state.erc721_metadata.token_uri(1) == "CUSTOMURI1", 'Should be CUSTOMURI1');
assert(state.erc721_metadata.tokenURI(1) == "CUSTOMURI1", 'Should be CUSTOMURI1');
}
19 changes: 18 additions & 1 deletion token/src/components/token/erc721/erc721_metadata.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,24 @@ mod erc721_metadata_component {
const INVALID_TOKEN_ID: felt252 = 'ERC721: invalid token ID';
}

///
/// Hooks
///
trait ERC721MetadataHooksTrait<TContractState> {
fn custom_uri(
self: @ComponentState<TContractState>,
base_uri: @ByteArray,
token_id: u256,
) -> ByteArray;
}

#[embeddable_as(ERC721MetadataImpl)]
impl ERC721Metadata<
TContractState,
+HasComponent<TContractState>,
+IWorldProvider<TContractState>,
impl ERC721Owner: erc721_owner_comp::HasComponent<TContractState>,
+ERC721MetadataHooksTrait<TContractState>,
+Drop<TContractState>,
> of IERC721Metadata<ComponentState<TContractState>> {
fn name(self: @ComponentState<TContractState>) -> ByteArray {
Expand All @@ -79,6 +91,7 @@ mod erc721_metadata_component {
+HasComponent<TContractState>,
+IWorldProvider<TContractState>,
impl ERC721Owner: erc721_owner_comp::HasComponent<TContractState>,
+ERC721MetadataHooksTrait<TContractState>,
+Drop<TContractState>,
> of IERC721MetadataCamel<ComponentState<TContractState>> {
fn tokenURI(self: @ComponentState<TContractState>, tokenId: u256) -> ByteArray {
Expand All @@ -93,6 +106,7 @@ mod erc721_metadata_component {
+HasComponent<TContractState>,
+IWorldProvider<TContractState>,
impl ERC721Owner: erc721_owner_comp::HasComponent<TContractState>,
impl Hooks: ERC721MetadataHooksTrait<TContractState>,
+Drop<TContractState>,
> of InternalTrait<TContractState> {
fn get_meta(self: @ComponentState<TContractState>) -> ERC721MetaModel {
Expand All @@ -103,7 +117,10 @@ mod erc721_metadata_component {
let mut erc721_owner = get_dep_component!(self, ERC721Owner);
assert(erc721_owner.exists(token_id), Errors::INVALID_TOKEN_ID);
let base_uri = self.get_meta().base_uri;
if base_uri.len() == 0 {
let custom_uri = Hooks::custom_uri(self, @base_uri, token_id);
if custom_uri.len() > 0 {
return custom_uri;
} else if base_uri.len() == 0 {
return "";
} else {
return format!("{}{}", base_uri, token_id);
Expand Down
20 changes: 20 additions & 0 deletions token/src/components/token/erc721/erc721_metadata_hooks.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

///
/// An empty implementation of the ERC721MetadataHooksTrait
///
/// When the hook is not required, import together with the component:
/// use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
/// use token::components::token::erc721::erc721_metadata_hooks::ERC721MetadataHooksEmptyImpl;
///
/// Or implement your own (example on erc721_metadata_hooks_mock.cairo)
///

use token::components::token::erc721::erc721_metadata::erc721_metadata_component;

impl ERC721MetadataHooksEmptyImpl<TContractState> of erc721_metadata_component::ERC721MetadataHooksTrait<TContractState> {
fn custom_uri(
self: @erc721_metadata_component::ComponentState<TContractState>,
base_uri: @ByteArray,
token_id: u256,
) -> ByteArray { "" }
}
1 change: 1 addition & 0 deletions token/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod components {
mod erc721_burnable;
mod erc721_enumerable;
mod erc721_metadata;
mod erc721_metadata_hooks;
mod erc721_mintable;
mod erc721_owner;
mod erc721_receiver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ mod ERC721EnumMintBurn {
use token::components::token::erc721::erc721_burnable::erc721_burnable_component;
use token::components::token::erc721::erc721_enumerable::erc721_enumerable_component;
use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
use token::components::token::erc721::erc721_metadata_hooks::ERC721MetadataHooksEmptyImpl;
use token::components::token::erc721::erc721_mintable::erc721_mintable_component;
use token::components::token::erc721::erc721_owner::erc721_owner_component;

Expand Down
1 change: 1 addition & 0 deletions token/src/presets/erc721/mintable_burnable.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ mod ERC721MintableBurnable {
use token::components::token::erc721::erc721_balance::erc721_balance_component;
use token::components::token::erc721::erc721_burnable::erc721_burnable_component;
use token::components::token::erc721::erc721_metadata::erc721_metadata_component;
use token::components::token::erc721::erc721_metadata_hooks::ERC721MetadataHooksEmptyImpl;
use token::components::token::erc721::erc721_mintable::erc721_mintable_component;
use token::components::token::erc721::erc721_owner::erc721_owner_component;

Expand Down

0 comments on commit 286d785

Please sign in to comment.