Skip to content

Commit

Permalink
Add ERC1155 mixin (#941)
Browse files Browse the repository at this point in the history
* add erc1155 mixin

* update changelog

* add missing semicolon

* Apply suggestions from code review

Co-authored-by: Eric Nordelo <eric.nordelo39@gmail.com>

* fix constructor in code block

* fix name, consolidate snake and camel blocks

* fix param name

* add mixin block

* embed mixin in mock

* add erc1155receiver mixin

* add changelog entry

* fix formatting

* remove i from mixin interface

* add self to receiver API fns

* remove src5 camel

* fix interface imports

* fix formatting

---------

Co-authored-by: Eric Nordelo <eric.nordelo39@gmail.com>
  • Loading branch information
andrew-fleming and ericnordelo committed Mar 22, 2024
1 parent 9f14829 commit e039e86
Show file tree
Hide file tree
Showing 8 changed files with 274 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- ERC1155Component and ERC1155ReceiverComponent mixins (#941)
- ERC721ReceiverComponent documentation (#945)

### Changed
Expand Down
36 changes: 25 additions & 11 deletions docs/modules/ROOT/pages/api/erc1155.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,17 @@ ERC1155 component implementing <<IERC1155,IERC1155>> and <<IERC1155MetadataURI,I

NOTE: {src5-component-required-note}

[.contract-index#ERC1155Component-Embeddable-Mixin-Impl]
.{mixin-impls}

--
.ERC1155MixinImpl
* xref:#ERC1155Component-Embeddable-Impls-ERC1155Impl[`++ERC1155Impl++`]
* xref:#ERC1155Component-Embeddable-Impls-ERC1155MetadataURIImpl[`++ERC1155MetadataURIImpl++`]
* xref:#ERC1155Component-Embeddable-Impls-ER1155CamelImpl[`++ER1155CamelImpl++`]
* xref:api/introspection.adoc#SRC5Component-Embeddable-Impls-SRC5Impl[`++SRC5Impl++`]
--

[.contract-index#ERC1155Component-Embeddable-Impls]
.Embeddable Implementations
--
Expand Down Expand Up @@ -547,6 +558,15 @@ ERC1155Receiver component implementing <<IERC1155Receiver,IERC1155Receiver>>.

NOTE: {src5-component-required-note}

[.contract-index#ERC1155ReceiverComponent-Embeddable-Mixin-Impl]
.{mixin-impls}
--
.ERC1155MixinImpl
* xref:#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverImpl[`++ERC1155ReceiverImpl++`]
* xref:#ERC1155ReceiverComponent-Embeddable-Impls-ERC1155ReceiverCamelImpl[`++ERC1155ReceiverCamelImpl++`]
* xref:api/introspection.adoc#SRC5Component-Embeddable-Impls-SRC5Impl[`++SRC5Impl++`]
--

[.contract-index#ERC1155ReceiverComponent-Embeddable-Impls]
.Embeddable Implementations
--
Expand All @@ -570,25 +590,25 @@ NOTE: {src5-component-required-note}

[.contract-item]
[[ERC1155ReceiverComponent-on_erc1155_received]]
==== `[.contract-item-name]#++on_erc1155_received++#++(operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span<felt252>) -> felt252++` [.item-kind]#external#
==== `[.contract-item-name]#++on_erc1155_received++#++(self: @ContractState, operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span<felt252>) -> felt252++` [.item-kind]#external#

Returns the `IERC1155Receiver` interface ID.

[.contract-item]
[[ERC1155ReceiverComponent-on_erc1155_batch_received]]
==== `[.contract-item-name]#++on_erc1155_batch_received++#++(operator: ContractAddress, from: ContractAddress, token_ids: Span<u256>, values: Span<u256>, data Span<felt252>) -> felt252++` [.item-kind]#external#
==== `[.contract-item-name]#++on_erc1155_batch_received++#++(self: @ContractState, operator: ContractAddress, from: ContractAddress, token_ids: Span<u256>, values: Span<u256>, data Span<felt252>) -> felt252++` [.item-kind]#external#

Returns the `IERC1155Receiver` interface ID.

[.contract-item]
[[ERC1155ReceiverComponent-onERC1155Received]]
==== `[.contract-item-name]#++onERC1155Received++#++(operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span<felt252>) -> felt252++` [.item-kind]#external#
==== `[.contract-item-name]#++onERC1155Received++#++(self: @ContractState, operator: ContractAddress, from: ContractAddress, tokenId: u256, value: u256, data Span<felt252>) -> felt252++` [.item-kind]#external#

See <<ERC1155ReceiverComponent-on_erc1155_received,ERC1155ReceiverComponent::on_erc1155_received>>.

[.contract-item]
[[ERC1155ReceiverComponent-onERC1155BatchReceived]]
==== `[.contract-item-name]#++onERC1155BatchReceived++#++(operator: ContractAddress, from: ContractAddress, token_ids: Span<u256>, values: Span<u256>, data Span<felt252>) -> felt252++` [.item-kind]#external#
==== `[.contract-item-name]#++onERC1155BatchReceived++#++(self: @ContractState, operator: ContractAddress, from: ContractAddress, tokenIds: Span<u256>, values: Span<u256>, data Span<felt252>) -> felt252++` [.item-kind]#external#

See <<ERC1155ReceiverComponent-on_erc1155_batch_received,ERC1155ReceiverComponent::on_erc1155_batch_received>>.

Expand Down Expand Up @@ -631,13 +651,7 @@ include::../utils/_class_hashes.adoc[]
--
.ERC1155Component

* xref:#ERC1155Component-Embeddable-Impls-ERC1155Impl[`++ERC1155Impl++`]
* xref:#ERC1155Component-Embeddable-Impls-ERC1155MetadataURIImpl[`++ERC1155MetadataURIImpl++`]
* xref:#ERC1155Component-Embeddable-Impls-ER1155CamelImpl[`++ERC1155CamelImpl++`]

.SRC5Component

* xref:api/introspection.adoc#SRC5Component-Embeddable-Impls-SRC5Impl[`++SRC5Impl++`]
* xref:#ERC1155Component-Embeddable-Mixin-Impl[`++ERC1155MixinImpl++`]
--

[#ERC1155-constructor-section]
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/erc1155.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ mod MyTokenReceiver {
#[constructor]
fn constructor(ref self: ContractState) {
self.erc721_receiver.initializer();
self.erc1155_receiver.initializer();
}
}
----
13 changes: 2 additions & 11 deletions src/presets/erc1155.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,11 @@ mod ERC1155 {
component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event);
component!(path: SRC5Component, storage: src5, event: SRC5Event);

// ERC1155
// ERC1155 Mixin
#[abi(embed_v0)]
impl ERC1155Impl = ERC1155Component::ERC1155Impl<ContractState>;
#[abi(embed_v0)]
impl ERC1155MetadataURIImpl =
ERC1155Component::ERC1155MetadataURIImpl<ContractState>;
#[abi(embed_v0)]
impl ERC1155Camel = ERC1155Component::ERC1155CamelImpl<ContractState>;
impl ERC1155MixinImpl = ERC1155Component::ERC1155MixinImpl<ContractState>;
impl ERC1155InternalImpl = ERC1155Component::InternalImpl<ContractState>;

// SRC5
#[abi(embed_v0)]
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
Expand Down
13 changes: 3 additions & 10 deletions src/tests/mocks/erc1155_receiver_mocks.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,12 @@ mod DualCaseERC1155ReceiverMock {
path: ERC1155ReceiverComponent, storage: erc1155_receiver, event: ERC1155ReceiverEvent
);

// ERC1155Receiver
// ERC1155Receiver Mixin
#[abi(embed_v0)]
impl ERC1155ReceiverImpl =
ERC1155ReceiverComponent::ERC1155ReceiverImpl<ContractState>;
#[abi(embed_v0)]
impl ERC1155ReceiverCamelImpl =
ERC1155ReceiverComponent::ERC1155ReceiverCamelImpl<ContractState>;
impl ERC1155ReceiverMixinImpl =
ERC1155ReceiverComponent::ERC1155ReceiverMixinImpl<ContractState>;
impl ERC1155ReceiverInternalImpl = ERC1155ReceiverComponent::InternalImpl<ContractState>;

// SRC5
#[abi(embed_v0)]
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;

#[storage]
struct Storage {
#[substorage(v0)]
Expand Down
139 changes: 130 additions & 9 deletions src/token/erc1155/erc1155.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ mod ERC1155Component {
use openzeppelin::account;
use openzeppelin::introspection::interface::{ISRC5Dispatcher, ISRC5DispatcherTrait};
use openzeppelin::introspection::src5::SRC5Component::InternalTrait as SRC5InternalTrait;
use openzeppelin::introspection::src5::SRC5Component::SRC5;
use openzeppelin::introspection::src5::SRC5Component;
use openzeppelin::token::erc1155::dual1155_receiver::{
DualCaseERC1155Receiver, DualCaseERC1155ReceiverTrait
Expand Down Expand Up @@ -130,7 +131,8 @@ mod ERC1155Component {
if index == token_ids.len() {
break;
}
batch_balances.append(self.balance_of(*accounts.at(index), *token_ids.at(index)));
batch_balances
.append(ERC1155::balance_of(self, *accounts.at(index), *token_ids.at(index)));
index += 1;
};

Expand Down Expand Up @@ -165,7 +167,7 @@ mod ERC1155Component {
) {
let token_ids = array![token_id].span();
let values = array![value].span();
self.safe_batch_transfer_from(from, to, token_ids, values, data)
ERC1155::safe_batch_transfer_from(ref self, from, to, token_ids, values, data)
}

/// Batched version of `safe_transfer_from`.
Expand Down Expand Up @@ -198,7 +200,7 @@ mod ERC1155Component {

let operator = get_caller_address();
if from != operator {
assert(self.is_approved_for_all(from, operator), Errors::UNAUTHORIZED);
assert(ERC1155::is_approved_for_all(@self, from, operator), Errors::UNAUTHORIZED);
}

self.update_with_acceptance_check(from, to, token_ids, values, data);
Expand Down Expand Up @@ -259,15 +261,15 @@ mod ERC1155Component {
fn balanceOf(
self: @ComponentState<TContractState>, account: ContractAddress, tokenId: u256
) -> u256 {
self.balance_of(account, tokenId)
ERC1155::balance_of(self, account, tokenId)
}

fn balanceOfBatch(
self: @ComponentState<TContractState>,
accounts: Span<ContractAddress>,
tokenIds: Span<u256>
) -> Span<u256> {
self.balance_of_batch(accounts, tokenIds)
ERC1155::balance_of_batch(self, accounts, tokenIds)
}

fn safeTransferFrom(
Expand All @@ -278,7 +280,7 @@ mod ERC1155Component {
value: u256,
data: Span<felt252>
) {
self.safe_transfer_from(from, to, tokenId, value, data)
ERC1155::safe_transfer_from(ref self, from, to, tokenId, value, data)
}

fn safeBatchTransferFrom(
Expand All @@ -289,19 +291,19 @@ mod ERC1155Component {
values: Span<u256>,
data: Span<felt252>
) {
self.safe_batch_transfer_from(from, to, tokenIds, values, data)
ERC1155::safe_batch_transfer_from(ref self, from, to, tokenIds, values, data)
}

fn setApprovalForAll(
ref self: ComponentState<TContractState>, operator: ContractAddress, approved: bool
) {
self.set_approval_for_all(operator, approved)
ERC1155::set_approval_for_all(ref self, operator, approved)
}

fn isApprovedForAll(
self: @ComponentState<TContractState>, owner: ContractAddress, operator: ContractAddress
) -> bool {
self.is_approved_for_all(owner, operator)
ERC1155::is_approved_for_all(self, owner, operator)
}
}

Expand Down Expand Up @@ -546,4 +548,123 @@ mod ERC1155Component {
src5_dispatcher.supports_interface(account::interface::ISRC6_ID)
}
}

#[embeddable_as(ERC1155MixinImpl)]
impl ERC1155Mixin<
TContractState,
+HasComponent<TContractState>,
impl SRC5: SRC5Component::HasComponent<TContractState>,
+Drop<TContractState>
> of interface::ERC1155ABI<ComponentState<TContractState>> {
// IERC1155
fn balance_of(
self: @ComponentState<TContractState>, account: ContractAddress, token_id: u256
) -> u256 {
ERC1155::balance_of(self, account, token_id)
}

fn balance_of_batch(
self: @ComponentState<TContractState>,
accounts: Span<ContractAddress>,
token_ids: Span<u256>
) -> Span<u256> {
ERC1155::balance_of_batch(self, accounts, token_ids)
}

fn safe_transfer_from(
ref self: ComponentState<TContractState>,
from: ContractAddress,
to: ContractAddress,
token_id: u256,
value: u256,
data: Span<felt252>
) {
ERC1155::safe_transfer_from(ref self, from, to, token_id, value, data);
}

fn safe_batch_transfer_from(
ref self: ComponentState<TContractState>,
from: ContractAddress,
to: ContractAddress,
token_ids: Span<u256>,
values: Span<u256>,
data: Span<felt252>
) {
ERC1155::safe_batch_transfer_from(ref self, from, to, token_ids, values, data);
}

fn is_approved_for_all(
self: @ComponentState<TContractState>, owner: ContractAddress, operator: ContractAddress
) -> bool {
ERC1155::is_approved_for_all(self, owner, operator)
}

fn set_approval_for_all(
ref self: ComponentState<TContractState>, operator: ContractAddress, approved: bool
) {
ERC1155::set_approval_for_all(ref self, operator, approved);
}

// ISRC5
fn supports_interface(
self: @ComponentState<TContractState>, interface_id: felt252
) -> bool {
let src5 = get_dep_component!(self, SRC5);
src5.supports_interface(interface_id)
}

// IERC1155MetadataURI
fn uri(self: @ComponentState<TContractState>, token_id: u256) -> ByteArray {
ERC1155MetadataURI::uri(self, token_id)
}

// IERC1155Camel
fn balanceOf(
self: @ComponentState<TContractState>, account: ContractAddress, tokenId: u256
) -> u256 {
ERC1155Camel::balanceOf(self, account, tokenId)
}

fn balanceOfBatch(
self: @ComponentState<TContractState>,
accounts: Span<ContractAddress>,
tokenIds: Span<u256>
) -> Span<u256> {
ERC1155Camel::balanceOfBatch(self, accounts, tokenIds)
}

fn safeTransferFrom(
ref self: ComponentState<TContractState>,
from: ContractAddress,
to: ContractAddress,
tokenId: u256,
value: u256,
data: Span<felt252>
) {
ERC1155Camel::safeTransferFrom(ref self, from, to, tokenId, value, data);
}

fn safeBatchTransferFrom(
ref self: ComponentState<TContractState>,
from: ContractAddress,
to: ContractAddress,
tokenIds: Span<u256>,
values: Span<u256>,
data: Span<felt252>
) {
ERC1155Camel::safeBatchTransferFrom(ref self, from, to, tokenIds, values, data);
}

fn isApprovedForAll(
self: @ComponentState<TContractState>, owner: ContractAddress, operator: ContractAddress
) -> bool {
ERC1155Camel::isApprovedForAll(self, owner, operator)
}

fn setApprovalForAll(
ref self: ComponentState<TContractState>, operator: ContractAddress, approved: bool
) {
ERC1155Camel::setApprovalForAll(ref self, operator, approved);
}
}
}

0 comments on commit e039e86

Please sign in to comment.