diff --git a/docs/antora.yml b/docs/antora.yml index 3c4ffb147..f13903da8 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -5,4 +5,4 @@ nav: - modules/ROOT/nav.adoc asciidoc: attributes: - page-sidebar-collapse-default: 'Access,Accounts,Introspection,Security,ERC20,ERC721,Upgrades' + page-sidebar-collapse-default: 'Access,Accounts,Introspection,Security,ERC20,ERC721,ERC1155,Upgrades' diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 880d9c88b..dce0c8550 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -30,7 +30,8 @@ **** xref:/api/erc20.adoc[API Reference] *** xref:erc721.adoc[ERC721] **** xref:/api/erc721.adoc[API Reference] -// *** xref:erc1155.adoc[ERC1155] +*** xref:erc1155.adoc[ERC1155] +**** xref:/api/erc1155.adoc[API Reference] ** xref:upgrades.adoc[Upgrades] *** xref:/api/upgrades.adoc[API Reference] diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 40b9b4593..62f8d9196 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -4,10 +4,11 @@ :src5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md[SRC5] :inner-src5: xref:api/introspection.adoc#ISRC5[SRC5 ID] :_set_role_admin: xref:#AccessControlComponent-_set_role_admin[_set_role_admin] -:mixin-impls: xref:components.adoc#mixins[Embeddable Mixin Implementations] = Access Control +include::../utils/_common.adoc[] + This directory provides ways to restrict who can access the functions of a contract or when they can do it. - {Ownable} is a simple mechanism with a single "owner" role that can be assigned to a single account. @@ -405,7 +406,6 @@ Emitted when `account` is revoked `role`. :assert_only_role: xref:#AccessControlComponent-assert_only_role :grant_role: xref:#AccessControlComponent-grant_role[grant_role] :revoke_role: xref:#AccessControlComponent-revoke_role[revoke_role] -:mixin-impl: xref:components.adoc#mixins[Embeddable Mixin Implementation] ```javascript use openzeppelin::access::accesscontrol::AccessControlComponent; @@ -446,7 +446,7 @@ grant and revoke this role. Extra precautions should be taken to secure accounts that have been granted it. [.contract-index#AccessControl-Mixin-Impl] -.{mixin-impl} +.{mixin-impls} -- .AccessControlMixinImpl diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index f1aaf0768..138cd77fd 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -1,7 +1,6 @@ :github-icon: pass:[] :snip6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md[SNIP-6] :inner-src5: xref:api/introspection.adoc#ISRC5[SRC5 ID] -:mixin-impl: xref:components.adoc#mixins[Embeddable Mixin Implementation] = Account @@ -9,6 +8,8 @@ Reference of interfaces, presets, and utilities related to account contracts. == Core +include::../utils/_common.adoc[] + [.contract] [[ISRC6]] === `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/account/interface.cairo[{github-icon},role=heading-link] @@ -75,10 +76,10 @@ use openzeppelin::account::AccountComponent; ``` Account component implementing xref:ISRC6[`ISRC6`] for signatures over the {starknet-curve}. -NOTE: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. +NOTE: {src5-component-required-note} [.contract-index#AccountComponent-Embeddable-Mixin-Impl] -.{mixin-impl} +.{mixin-impls} -- .AccountMixinImpl @@ -292,12 +293,12 @@ use openzeppelin::account::eth_account::EthAccountComponent; ``` Account component implementing xref:ISRC6[`ISRC6`] for signatures over the {secp256k1-curve}. -NOTE: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. +NOTE: {src5-component-required-note} NOTE: The `EthPublicKey` type is an alias for `starknet::secp256k1::Secp256k1Point`. [.contract-index#EthAccountComponent-Embeddable-Mixin-Impl] -.{mixin-impl} +.{mixin-impls} -- .EthAccountMixinImpl diff --git a/docs/modules/ROOT/pages/api/erc1155.adoc b/docs/modules/ROOT/pages/api/erc1155.adoc new file mode 100644 index 000000000..bd4afdda1 --- /dev/null +++ b/docs/modules/ROOT/pages/api/erc1155.adoc @@ -0,0 +1,670 @@ +:github-icon: pass:[] +:eip1155: https://eips.ethereum.org/EIPS/eip-1155[EIP1155] +:eip1155-metadata: https://eips.ethereum.org/EIPS/eip-1155#metadata +:receiving-tokens: xref:/erc1155.adoc#receiving_tokens[Receiving tokens] +:inner-src5: xref:api/introspection.adoc#ISRC5[SRC5 ID] + += ERC1155 + +include::../utils/_common.adoc[] + +Reference of interfaces, presets, and utilities related to ERC1155 contracts. + +TIP: For an overview of ERC1155, read our xref:erc1155.adoc[ERC1155 guide]. + +== Core + +[.contract] +[[IERC1155]] +=== `++IERC1155++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc1155/interface.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```javascript +use openzeppelin::token::erc1155::interface::IERC1155; +``` +Interface of the IERC1155 standard as defined in {eip1155}. + +[.contract-index] +.{inner-src5} +-- +0x6114a8f75559e1b39fcba08ce02961a1aa082d9256a158dd3e64964e4b1b52 +-- + +[.contract-index] +.Functions +-- +* xref:#IERC1155-balance_of[`++balance_of(account, token_id)++`] +* xref:#IERC1155-balance_of_batch[`++balance_of_batch(accounts, token_ids)++`] +* xref:#IERC1155-safe_transfer_from[`++safe_transfer_from(from, to, token_id, value, data)++`] +* xref:#IERC1155-safe_batch_transfer_from[`++safe_batch_transfer_from(from, to, token_ids, values, data)++`] +* xref:#IERC1155-set_approval_for_all[`++set_approval_for_all(operator, approved)++`] +* xref:#IERC1155-is_approved_for_all[`++is_approved_for_all(owner, operator)++`] +-- + +[.contract-index] +.Events +-- +* xref:#IERC1155-TransferSingle[`++TransferSingle(operator, from, to, id, value)++`] +* xref:#IERC1155-TransferBatch[`++TransferBatch(operator, from, to, ids, values)++`] +* xref:#IERC1155-ApprovalForAll[`++ApprovalForAll(owner, operator, approved)++`] +* xref:#IERC1155-URI[`++URI(value, id)++`] +-- + +==== Functions + +[.contract-item] +[[IERC1155-balance_of]] +==== `[.contract-item-name]#++balance_of++#++(account: ContractAddress, token_id: u256) → u256++` [.item-kind]#external# + +Returns the amount of `token_id` tokens owned by `account`. + +[.contract-item] +[[IERC1155-balance_of_batch]] +==== `[.contract-item-name]#++balance_of_batch++#++(accounts: Span, token_ids: Span) → Span++` [.item-kind]#external# + +Returns a list of balances derived from the `accounts` and `token_ids` pairs. + +[.contract-item] +[[IERC1155-safe_transfer_from]] +==== `[.contract-item-name]#++safe_transfer_from++#++(from: ContractAddress, to: ContractAddress, token_id: u256, value: u256, data: Span)++` [.item-kind]#external# + +Transfers ownership of `value` amount of `token_id` from `from` if `to` is either `IERC1155Receiver` or an account. + +`data` is additional data, it has no specified format and it is passed to `to`. + +Emits a <> event. + +[.contract-item] +[[IERC1155-safe_batch_transfer_from]] +==== `[.contract-item-name]#++safe_batch_transfer_from++#++(from: ContractAddress, to: ContractAddress, token_ids: Span, values: Span, data: Span)++` [.item-kind]#external# + +Transfers ownership of `token_ids` and `values` pairs from `from` if `to` is either `IERC1155Receiver` or an account. + +`data` is additional data, it has no specified format and it is passed to `to`. + +Emits a <> event. + +[.contract-item] +[[IERC1155-set_approval_for_all]] +==== `[.contract-item-name]#++set_approval_for_all++#++(operator: ContractAddress, approved: bool)++` [.item-kind]#external# + +Enables or disables approval for `operator` to manage all of the caller's assets. + +Emits an <> event. + +[.contract-item] +[[IERC1155-is_approved_for_all]] +==== `[.contract-item-name]#++is_approved_for_all++#++(owner: ContractAddress, operator: ContractAddress) -> bool++` [.item-kind]#external# + +Queries if `operator` is an authorized operator for `owner`. + +==== Events + +[.contract-item] +[[IERC1155-TransferSingle]] +==== `[.contract-item-name]#++TransferSingle++#++(operator: ContractAddress, from: ContractAddress, to: ContractAddress, id: u256, value: u256)++` [.item-kind]#event# + +Emitted when `value` amount of `id` token is transferred from `from` to `to` through `operator`. + +[.contract-item] +[[IERC1155-TransferBatch]] +==== `[.contract-item-name]#++TransferBatch++#++(operator: ContractAddress, from: ContractAddress, to: ContractAddress, ids: Span, values: Span)++` [.item-kind]#event# + +Emitted when a batch of `values` amount of `ids` tokens are transferred from `from` to `to` through `operator`. + +[.contract-item] +[[IERC1155-ApprovalForAll]] +==== `[.contract-item-name]#++ApprovalForAll++#++(owner: ContractAddress, operator: ContractAddress, approved: bool)++` [.item-kind]#event# + +Emitted when `owner` enables or disables `operator` to manage all of the owner's assets. + +[.contract-item] +[[IERC1155-URI]] +==== `[.contract-item-name]#++URI++#++(value: ByteArray, id: u256)++` [.item-kind]#event# + +Emitted when the token URI is updated to `value` for the `id` token. + +[.contract] +[[IERC1155MetadataURI]] +=== `++IERC1155MetadataURI++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc1155/interface.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```javascript +use openzeppelin::token::erc1155::interface::IERC1155MetadataURI; +``` +Interface for the optional metadata function in {eip1155-metadata}[EIP1155]. + +[.contract-index] +.{inner-src5} +-- +0xcabe2400d5fe509e1735ba9bad205ba5f3ca6e062da406f72f113feb889ef7 +-- + +[.contract-index] +.Functions +-- +* xref:#IERC1155MetadataURI-uri[`++uri(token_id)++`] +-- + +==== Functions + +[.contract-item] +[[IERC1155MetadataURI-uri]] +==== `[.contract-item-name]#++uri++#++(token_id: u256) -> ByteArray++` [.item-kind]#external# + +Returns the Uniform Resource Identifier (URI) for the `token_id` token. + +[.contract] +[[ERC1155Component]] +=== `++ERC1155Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc1155/erc1155.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```javascript +use openzeppelin::token::erc1155::ERC1155Component; +``` + +ERC1155 component implementing <> and <>. + +NOTE: {src5-component-required-note} + +[.contract-index#ERC1155Component-Embeddable-Impls] +.Embeddable Implementations +-- +[.sub-index#ERC1155Component-Embeddable-Impls-ERC1155Impl] +.ERC1155Impl +* xref:#ERC1155Component-balance_of[`++balance_of(self, account, token_id)++`] +* xref:#ERC1155Component-balance_of_batch[`++balance_of_batch(self, accounts, token_ids)++`] +* xref:#ERC1155Component-safe_transfer_from[`++safe_transfer_from(self, from, to, token_id, value, data)++`] +* xref:#ERC1155Component-safe_batch_transfer_from[`++safe_batch_transfer_from(self, from, to, token_ids, values, data)++`] +* xref:#ERC1155Component-set_approval_for_all[`++set_approval_for_all(self, operator, approved)++`] +* xref:#ERC1155Component-is_approved_for_all[`++is_approved_for_all(self, owner, operator)++`] + +[.sub-index#ERC1155Component-Embeddable-Impls-ERC1155MetadataURIImpl] +.ERC1155MetadataURIImpl +* xref:#ERC1155Component-uri[`++uri(self, token_id)++`] +-- + +[.contract-index#ERC1155Component-Embeddable-Impls-camelCase] +.Embeddable implementations (camelCase) +-- +[.sub-index#ERC1155Component-Embeddable-Impls-ER1155CamelImpl] +.ER1155CamelImpl +* xref:#ERC1155Component-balanceOf[`++balanceOf(self, account, tokenId)++`] +* xref:#ERC1155Component-balanceOfBatch[`++balanceOfBatch(self, accounts, tokenIds)++`] +* xref:#ERC1155Component-safeTransferFrom[`++safeTransferFrom(self, from, to, tokenId, value, data)++`] +* xref:#ERC1155Component-safeBatchTransferFrom[`++safeBatchTransferFrom(self, from, to, tokenIds, values, data)++`] +* xref:#ERC1155Component-setApprovalForAll[`++setApprovalForAll(self, operator, approved)++`] +* xref:#ERC1155Component-isApprovedForAll[`++isApprovedForAll(self, owner, operator)++`] +-- + +[.contract-index] +.Internal Functions +-- +.InternalImpl +* xref:#ERC1155Component-initializer[`++initializer(self, base_uri)++`] +* xref:#ERC1155Component-update[`++update(self, from, to, token_ids, values)++`] +* xref:#ERC1155Component-update_with_acceptance_check[`++update_with_acceptance_check(self, from, to, token_ids, values, data)++`] +* xref:#ERC1155Component-mint_with_acceptance_check[`++mint_with_acceptance_check(self, to, token_id, value, data)++`] +* xref:#ERC1155Component-batch_mint_with_acceptance_check[`++batch_mint_with_acceptance_check(self, to, token_ids, values, data)++`] +* xref:#ERC1155Component-burn[`++burn(self, from, token_id, value)++`] +* xref:#ERC1155Component-batch_burn[`++batch_burn(self, from, token_ids, values)++`] +* xref:#ERC1155Component-set_base_uri[`++set_base_uri(self, base_uri)++`] +-- + +[.contract-index] +.Events +-- +.IERC1155 +* xref:#ERC1155Component-TransferSingle[`++TransferSingle(operator, from, to, id, value)++`] +* xref:#ERC1155Component-TransferBatch[`++TransferBatch(operator, from, to, ids, values)++`] +* xref:#ERC1155Component-ApprovalForAll[`++ApprovalForAll(owner, operator, approved)++`] +* xref:#ERC1155Component-URI[`++URI(value, id)++`] +-- + +==== Embeddable functions + +[.contract-item] +[[ERC1155Component-balance_of]] +==== `[.contract-item-name]#++balance_of++#++(self: @ContractState, account: ContractAddress, token_id: u256) → u256++` [.item-kind]#external# + +Returns the amount of `token_id` tokens owned by `account`. + +[.contract-item] +[[ERC1155Component-balance_of_batch]] +==== `[.contract-item-name]#++balance_of_batch++#++(self: @ContractState, accounts: Span, token_ids: Span) → Span++` [.item-kind]#external# + +Returns a list of balances derived from the `accounts` and `token_ids` pairs. + +Requirements: + +- `token_ids` and `accounts` must have the same length. + +[.contract-item] +[[ERC1155Component-safe_transfer_from]] +==== `[.contract-item-name]#++safe_transfer_from++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, value: u256, data: Span)++` [.item-kind]#external# + +Transfers ownership of `value` amount of `token_id` from `from` if `to` is either an account or `IERC1155Receiver`. + +`data` is additional data, it has no specified format and it is passed to `to`. + +WARNING: This function can potentially allow a reentrancy attack when transferring tokens +to an untrusted contract, when invoking `on_ERC1155_received` on the receiver. +Ensure to follow the checks-effects-interactions pattern and consider employing +reentrancy guards when interacting with untrusted contracts. + +Requirements: + +- Caller is either approved or the `token_id` owner. +- `from` is not the zero address. +- `to` is not the zero address. +- If `to` refers to a non-account contract, it must implement `IERC1155Receiver::on_ERC1155_received` + and return the required magic value. + +Emits a <> event. + +[.contract-item] +[[ERC1155Component-safe_batch_transfer_from]] +==== `[.contract-item-name]#++safe_batch_transfer_from++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_ids: Span, values: Span, data: Span)++` [.item-kind]#external# + +Transfers ownership of `values` and `token_ids` pairs from `from` if `to` is either an account or `IERC1155Receiver`. + +`data` is additional data, it has no specified format and it is passed to `to`. + +WARNING: This function can potentially allow a reentrancy attack when transferring tokens +to an untrusted contract, when invoking `on_ERC1155_batch_received` on the receiver. +Ensure to follow the checks-effects-interactions pattern and consider employing +reentrancy guards when interacting with untrusted contracts. + +Requirements: + +- Caller is either approved or the `token_id` owner. +- `from` is not the zero address. +- `to` is not the zero address. +- `token_ids` and `values` must have the same length. +- If `to` refers to a non-account contract, it must implement `IERC1155Receiver::on_ERC1155_batch_received` + and return the acceptance magic value. + +Emits a <> event if the arrays contain one element, +and <> otherwise. + +[.contract-item] +[[ERC1155Component-set_approval_for_all]] +==== `[.contract-item-name]#++set_approval_for_all++#++(ref self: ContractState, operator: ContractAddress, approved: bool)++` [.item-kind]#external# + +Enables or disables approval for `operator` to manage all of the callers assets. + +Requirements: + +- `operator` cannot be the caller. + +Emits an <> event. + +[.contract-item] +[[ERC1155Component-is_approved_for_all]] +==== `[.contract-item-name]#++is_approved_for_all++#++(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool++` [.item-kind]#external# + +Queries if `operator` is an authorized operator for `owner`. + +[.contract-item] +[[ERC1155Component-uri]] +==== `[.contract-item-name]#++uri++#++(self: @ContractState, token_id: u256) -> ByteArray++` [.item-kind]#external# + +This implementation returns the same URI for *all* token types. It relies +on the token type ID substitution mechanism +{eip1155-metadata}[specified in the EIP]. + +Clients calling this function must replace the `\{id\}` substring with the +actual token type ID. + +==== camelCase Support + +[.contract-item] +[[ERC1155Component-balanceOf]] +==== `[.contract-item-name]#++balanceOf++#++(self: @ContractState, account: ContractAddress, tokenId: u256) → u256++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155Component-balanceOfBatch]] +==== `[.contract-item-name]#++balanceOfBatch++#++(self: @ContractState, accounts: Span, tokenIds: Span) → Span++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155Component-safeTransferFrom]] +==== `[.contract-item-name]#++safeTransferFrom++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenId: u256, value: u256, data: Span)++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155Component-safeBatchTransferFrom]] +==== `[.contract-item-name]#++safeBatchTransferFrom++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, tokenIds: Span, values: Span, data: Span)++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155Component-setApprovalForAll]] +==== `[.contract-item-name]#++setApprovalForAll++#++(ref self: ContractState, operator: ContractAddress, approved: bool)++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155Component-isApprovedForAll]] +==== `[.contract-item-name]#++isApprovedForAll++#++(self: @ContractState, owner: ContractAddress, operator: ContractAddress) -> bool++` [.item-kind]#external# + +See <>. + +==== Internal functions + +[.contract-item] +[[ERC1155Component-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, base_uri: ByteArray)++` [.item-kind]#internal# + +Initializes the contract by setting the token's base URI as `base_uri`, and registering the supported interfaces. +This should only be used inside the contract's constructor. + +[.contract-item] +[[ERC1155Component-update]] +==== `[.contract-item-name]#++update++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_ids: Span, values: Span)++` [.item-kind]#internal# + +Transfers a `value` amount of tokens of type `id` from `from` to `to`. +Will mint (or burn) if `from` (or `to`) is the zero address. + +Requirements: + +- `token_ids` and `values` must have the same length. + +Emits a <> event if the arrays contain one element, +and <> otherwise. + +NOTE: The ERC1155 acceptance check is not performed in this function. +See <> instead. + +[.contract-item] +[[ERC1155Component-update_with_acceptance_check]] +==== `[.contract-item-name]#++update_with_acceptance_check++#++(ref self: ContractState, from: ContractAddress, to: ContractAddress, token_ids: Span, values: Span, data: Span)++` [.item-kind]#internal# + +Version of `update` that performs the token acceptance check by calling +`onERC1155Received` or `onERC1155BatchReceived` in the receiver if +it implements `IERC1155Receiver`, otherwise by checking if it is an account. + +Requirements: + +- `to` is either an account contract or supports the `IERC1155Receiver` interface. +- `token_ids` and `values` must have the same length. + +Emits a <> event if the arrays contain one element, +and <> otherwise. + +[.contract-item] +[[ERC1155Component-mint_with_acceptance_check]] +==== `[.contract-item-name]#++mint_with_acceptance_check++#++(ref self: ContractState, to: ContractAddress, token_id: u256, value: u256, data: Span)++` [.item-kind]#internal# + +Creates a `value` amount of tokens of type `token_id`, and assigns them to `to`. + +Requirements: + +- `to` cannot be the zero address. +- If `to` refers to a smart contract, it must implement `IERC1155Receiver::on_ERC1155_received` +and return the acceptance magic value. + +Emits a <> event. + +[.contract-item] +[[ERC1155Component-batch_mint_with_acceptance_check]] +==== `[.contract-item-name]#++batch_mint_with_acceptance_check++#++(ref self: ContractState, to: ContractAddress, token_ids: Span, values: Span, data: Span)++` [.item-kind]#internal# + +Batched version of <>. + +Requirements: + +- `to` cannot be the zero address. +- `token_ids` and `values` must have the same length. +- If `to` refers to a smart contract, it must implement `IERC1155Receiver::on_ERC1155_batch_received` +and return the acceptance magic value. + +Emits a <> event. + +[.contract-item] +[[ERC1155Component-burn]] +==== `[.contract-item-name]#++burn++#++(ref self: ContractState, from: ContractAddress, token_id: u256, value: u256)++` [.item-kind]#internal# + +Destroys a `value` amount of tokens of type `token_id` from `from`. + +Requirements: + +- `from` cannot be the zero address. +- `from` must have at least `value` amount of tokens of type `token_id`. + +Emits a <> event. + +[.contract-item] +[[ERC1155Component-batch_burn]] +==== `[.contract-item-name]#++batch_burn++#++(ref self: ContractState, from: ContractAddress, token_ids: Span, values: Span)++` [.item-kind]#internal# + +Batched version of <>. + +Requirements: + +- `from` cannot be the zero address. +- `from` must have at least `value` amount of tokens of type `token_id`. +- `token_ids` and `values` must have the same length. + +Emits a <> event. + +[.contract-item] +[[ERC1155Component-set_base_uri]] +==== `[.contract-item-name]#++set_base_uri++#++(ref self: ContractState, base_uri: ByteArray)++` [.item-kind]#internal# + +Sets a new URI for all token types, by relying on the token type ID +substitution mechanism +{eip1155-metadata}[specified in the EIP]. + +By this mechanism, any occurrence of the `\{id\}` substring in either the +URI or any of the values in the JSON file at said URI will be replaced by +clients with the token type ID. + +For example, the pass:[https://token-cdn-domain/\{id\}.json] URI would be +interpreted by clients as +pass:[https://token-cdn-domain/000000000000...000000000000004cce0.json] +for token type ID `0x4cce0`. + +Because these URIs cannot be meaningfully represented by the `URI` event, +this function emits no events. + +==== Events + +[.contract-item] +[[ERC1155Component-TransferSingle]] +==== `[.contract-item-name]#++TransferSingle++#++(operator: ContractAddress, from: ContractAddress, to: ContractAddress, id: u256, value: u256)++` [.item-kind]#event# + +See <>. + +[.contract-item] +[[ERC1155Component-TransferBatch]] +==== `[.contract-item-name]#++TransferBatch++#++(operator: ContractAddress, from: ContractAddress, to: ContractAddress, ids: Span, values: Span)++` [.item-kind]#event# + +See <>. + +[.contract-item] +[[ERC1155Component-ApprovalForAll]] +==== `[.contract-item-name]#++ApprovalForAll++#++(owner: ContractAddress, operator: ContractAddress, approved: bool)++` [.item-kind]#event# + +See <>. + +[.contract-item] +[[ERC1155Component-URI]] +==== `[.contract-item-name]#++URI++#++(value: ByteArray, id: u256)++` [.item-kind]#event# + +See <>. + +== Receiver + +[.contract] +[[IERC1155Receiver]] +=== `++IERC1155Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc1155/interface.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```javascript +use openzeppelin::token::erc1155::interface::IERC1155Receiver; +``` + +Interface for contracts that support receiving token transfers from `ERC1155` contracts. + +[.contract-index] +.{inner-src5} +-- +0x15e8665b5af20040c3af1670509df02eb916375cdf7d8cbaf7bd553a257515e +-- + +[.contract-index] +.Functions +-- +* xref:#IERC1155Receiver-on_erc1155_received[`++on_erc1155_received(operator, from, token_id, value, data)++`] +* xref:#IERC1155Receiver-on_erc1155_batch_received[`++on_erc1155_batch_received(operator, from, token_ids, values, data)++`] +-- + +==== Functions + +[.contract-item] +[[IERC1155Receiver-on_erc1155_received]] +==== `[.contract-item-name]#++on_erc1155_received++#++(operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span) -> felt252++` [.item-kind]#external# + +This function is called whenever an ERC1155 `token_id` token is transferred to this `IERC1155Receiver` implementer +via <> by `operator` from `from`. + +[.contract-item] +[[IERC1155Receiver-on_erc1155_batch_received]] +==== `[.contract-item-name]#++on_erc1155_batch_received++#++(operator: ContractAddress, from: ContractAddress, token_ids: Span, values: Span, data Span) -> felt252++` [.item-kind]#external# + +This function is called whenever multiple ERC1155 `token_ids` tokens are transferred to this `IERC1155Receiver` implementer +via <> by `operator` from `from`. + +[.contract] +[[ERC1155ReceiverComponent]] +=== `++ERC1155ReceiverComponent++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc1155/erc1155_receiver.cairo[{github-icon},role=heading-link] + +[.hljs-theme-dark] +```javascript +use openzeppelin::token::erc1155::ERC1155ReceiverComponent; +``` + +ERC1155Receiver component implementing <>. + +NOTE: {src5-component-required-note} + +[.contract-index#ERC1155ReceiverComponent-Embeddable-Impls] +.Embeddable Implementations +-- +.ERC1155ReceiverImpl +* xref:#ERC1155ReceiverComponent-on_erc1155_received[`++on_erc1155_received(self, operator, from, token_id, value, data)++`] +* xref:#ERC1155ReceiverComponent-on_erc1155_batch_received[`++on_erc1155_batch_received(self, operator, from, token_ids, values, data)++`] +-- + +[.contract-index#ERC1155ReceiverComponent-Embeddable-Impls-camelCase] +.Embeddable implementations (camelCase) +-- +.ERC1155ReceiverCamelImpl +* xref:#ERC1155ReceiverComponent-onERC1155Received[`++onERC1155Received(self, operator, from, tokenId, value, data)++`] +* xref:#ERC1155ReceiverComponent-onERC1155BatchReceived[`++onERC1155BatchReceived(self, operator, from, tokenIds, values, data)++`] +-- + +[.contract-index] +.Internal Functions +-- +.InternalImpl +* xref:#ERC1155ReceiverComponent-initializer[`++initializer(self)++`] +-- + +==== Embeddable functions + +[.contract-item] +[[ERC1155ReceiverComponent-on_erc1155_received]] +==== `[.contract-item-name]#++on_erc1155_received++#++(operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span) -> 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, values: Span, data Span) -> felt252++` [.item-kind]#external# + +Returns the `IERC1155Receiver` interface ID. + +==== camelCase Support + + +[.contract-item] +[[ERC1155ReceiverComponent-onERC1155Received]] +==== `[.contract-item-name]#++onERC1155Received++#++(operator: ContractAddress, from: ContractAddress, token_id: u256, value: u256, data Span) -> felt252++` [.item-kind]#external# + +See <>. + +[.contract-item] +[[ERC1155ReceiverComponent-onERC1155BatchReceived]] +==== `[.contract-item-name]#++onERC1155BatchReceived++#++(operator: ContractAddress, from: ContractAddress, token_ids: Span, values: Span, data Span) -> felt252++` [.item-kind]#external# + +See <>. + +==== Internal functions + +[.contract-item] +[[ERC1155ReceiverComponent-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# + +Registers the `IERC1155Receiver` interface ID as supported through introspection. + +== Presets + +[.contract] +[[ERC1155]] +=== `++ERC1155++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/presets/erc1155.cairo[{github-icon},role=heading-link] + +```javascript +use openzeppelin::presets::ERC1155; +``` + +Basic ERC1155 contract leveraging xref:#ERC1155Component[ERC1155Component]. + +include::../utils/_class_hashes.adoc[] + +[.contract-index] +.{presets-page} +-- +{ERC1155-class-hash} +-- + +[.contract-index] +.Constructor +-- +* xref:#ERC1155-constructor[`++constructor(self, base_uri, recipient, token_ids, values)++`] +-- + +[.contract-index] +.Embedded Implementations +-- +.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++`] +-- + +[#ERC1155-constructor-section] +==== Constructor + +[.contract-item] +[[ERC1155-constructor]] +==== `[.contract-item-name]#++constructor++#++(ref self: ContractState, base_uri: ByteArray, recipient: ContractAddress, token_ids: Span, values: Span)++` [.item-kind]#constructor# + +Sets the `base_uri` for all tokens and registers the supported interfaces. +Mints the `values` for `token_ids` tokens to `recipient`. + +Requirements: + +- `to` is either an account contract (supporting ISRC6) or + supports the `IERC1155Receiver` interface. +- `token_ids` and `values` must have the same length. diff --git a/docs/modules/ROOT/pages/api/erc20.adoc b/docs/modules/ROOT/pages/api/erc20.adoc index 2cdd32622..9f18c1d16 100644 --- a/docs/modules/ROOT/pages/api/erc20.adoc +++ b/docs/modules/ROOT/pages/api/erc20.adoc @@ -3,10 +3,11 @@ :erc20-guide: xref:erc20.adoc[ERC20 guide] :casing-discussion: https://github.com/OpenZeppelin/cairo-contracts/discussions/34[here] :custom-decimals: xref:/erc20.adoc#customizing_decimals[Customizing decimals] -:mixin-impl: xref:components.adoc#mixins[Embeddable Mixin Implementation] = ERC20 +include::../utils/_common.adoc[] + Reference of interfaces and utilities related to ERC20 contracts. TIP: For an overview of ERC20, read our {erc20-guide}. @@ -170,7 +171,7 @@ use openzeppelin::token::erc20::ERC20Component; ERC20 component extending <> and <>. [.contract-index#ERC20Component-Embeddable-Mixin-Impl] -.{mixin-impl} +.{mixin-impls} -- .ERC20MixinImpl diff --git a/docs/modules/ROOT/pages/api/erc721.adoc b/docs/modules/ROOT/pages/api/erc721.adoc index dc9088402..321e1634d 100644 --- a/docs/modules/ROOT/pages/api/erc721.adoc +++ b/docs/modules/ROOT/pages/api/erc721.adoc @@ -3,10 +3,11 @@ :receiving-tokens: xref:/erc721.adoc#receiving_tokens[Receiving Tokens] :casing-discussion: https://github.com/OpenZeppelin/cairo-contracts/discussions/34[here] :inner-src5: xref:api/introspection.adoc#ISRC5[SRC5 ID] -:mixin-impl: xref:components.adoc#mixins[Embeddable Mixin Implementation] = ERC721 +include::../utils/_common.adoc[] + Reference of interfaces, presets, and utilities related to ERC721 contracts. TIP: For an overview of ERC721, read our xref:erc721.adoc[ERC721 guide]. @@ -15,7 +16,7 @@ TIP: For an overview of ERC721, read our xref:erc721.adoc[ERC721 guide]. [.contract] [[IERC721]] -=== `++IERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/token/erc721/interface.cairo#L13-L31[{github-icon},role=heading-link] +=== `++IERC721++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc721/interface.cairo#L13-L31[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -98,7 +99,7 @@ Emits an <> event. Enable or disable approval for `operator` to manage all of the caller's assets. -Emits an <> event. +Emits an <> event. [.contract-item] [[IERC721-get_approved]] @@ -124,7 +125,7 @@ Emitted when `owner` enables `approved` to manage the `token_id` token. [[IERC721-ApprovalForAll]] ==== `[.contract-item-name]#++ApprovalForAll++#++(owner: ContractAddress, operator: ContractAddress, approved: bool)++` [.item-kind]#event# -Emitted when `owner` enables `approved` to manage the `token_id` token. +Emitted when `owner` enables or disables `operator` to manage the `token_id` token. [.contract-item] [[IERC721-Transfer]] @@ -134,7 +135,7 @@ Emitted when `token_id` token is transferred from `from` to `to`. [.contract] [[IERC721Metadata]] -=== `++IERC721Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/token/erc721/interface.cairo#L54-L59[{github-icon},role=heading-link] +=== `++IERC721Metadata++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc721/interface.cairo#L54-L59[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -180,7 +181,7 @@ If the URI is not set for `token_id`, the return value will be an empty `ByteArr [.contract] [[ERC721Component]] -=== `++ERC721Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/token/erc721/erc721.cairo#L7[{github-icon},role=heading-link] +=== `++ERC721Component++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc721/erc721.cairo#L7[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript @@ -189,10 +190,10 @@ use openzeppelin::token::erc721::ERC721Component; ERC721 component implementing <> and <>. -NOTE: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. +NOTE: {src5-component-required-note} [.contract-index#ERC721Component-Embeddable-Mixin-Impl] -.{mixin-impl} +.{mixin-impls} -- .ERC721MixinImpl @@ -590,7 +591,7 @@ See <>. [.contract] [[IERC721Receiver]] -=== `++IERC721Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/token/erc721/interface.cairo#L70-L79[{github-icon},role=heading-link] +=== `++IERC721Receiver++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.9.0/src/token/erc721/interface.cairo#L70-L79[{github-icon},role=heading-link] [.hljs-theme-dark] ```javascript diff --git a/docs/modules/ROOT/pages/api/introspection.adoc b/docs/modules/ROOT/pages/api/introspection.adoc index f4742d94d..16dbdc193 100644 --- a/docs/modules/ROOT/pages/api/introspection.adoc +++ b/docs/modules/ROOT/pages/api/introspection.adoc @@ -55,6 +55,7 @@ SRC5 component extending xref:ISRC5[`ISRC5`]. [.contract-index#SRC5Component-Embeddable-Impls] .Embeddable Implementations -- +[.sub-index#SRC5Component-Embeddable-Impls-SRC5Impl] .SRC5Impl * xref:#SRC5Component-supports_interface[`++supports_interface(self, interface_id)++`] diff --git a/docs/modules/ROOT/pages/erc1155.adoc b/docs/modules/ROOT/pages/erc1155.adoc index 19e0b5566..3889c042f 100644 --- a/docs/modules/ROOT/pages/erc1155.adoc +++ b/docs/modules/ROOT/pages/erc1155.adoc @@ -1,548 +1,277 @@ -= ERC1155 - -The ERC1155 multi token standard is a specification for https://docs.openzeppelin.com/contracts/4.x/tokens#different-kinds-of-tokens[fungibility-agnostic] token contracts. -The ERC1155 library implements an approximation of https://eips.ethereum.org/EIPS/eip-1155[EIP-1155] in Cairo for StarkNet. - -== Table of Contents - -* <> -* <> -* <> - ** <> - ** <> - ** <> -* <> -* <> - ** <> -* <> - ** <> - ** <> - ** <> - ** <> - -== IERC1155 - -[,cairo] ----- -@contract_interface -namespace IERC1155 { - func balanceOf(account: felt, id: Uint256) -> (balance: Uint256) { - } - - func balanceOfBatch( - accounts_len: felt, - accounts: felt*, - ids_len: felt, - ids: Uint256* - ) -> ( - balances_len: felt, - balances: Uint256* - ) { - } - - func isApprovedForAll( - account: felt, - operator: felt - ) -> (approved: felt) { - } - - func setApprovalForAll(operator: felt, approved: felt) { - } +:eip-1155: https://eips.ethereum.org/EIPS/eip-1155[EIP-1155] +:fungibility-agnostic: https://docs.openzeppelin.com/contracts/5.x/tokens#different-kinds-of-tokens[fungibility-agnostic] - func safeTransferFrom( - from_: felt, - to: felt, - id: Uint256, - value: Uint256, - data_len: felt, - data: felt* - ) { - } - - func safeBatchTransferFrom( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, - ) { - } - - --------------- IERC165 --------------- += ERC1155 - func supportsInterface(interfaceId: felt) -> (success: felt) { - } +The ERC1155 multi token standard is a specification for {fungibility-agnostic} token contracts. +The ERC1155 library implements an approximation of {eip-1155} in Cairo for StarkNet. + +== Multi Token Standard + +:balance_of-api: xref:api/erc1155.adoc#IERC1155-balance_of[balance_of] +:erc721-balance_of-api: xref:api/erc721.adoc#IERC721-balance_of[balance_of] + +The distinctive feature of ERC1155 is that it uses a single smart contract to represent multiple tokens at once. This +is why its {balance_of-api} function differs from ERC20’s and ERC777’s: it has an additional ID argument for the +identifier of the token that you want to query the balance of. + +This is similar to how ERC721 does things, but in that standard a token ID has no concept of balance: each token is +non-fungible and exists or doesn’t. The ERC721 {erc721-balance_of-api} function refers to how many different tokens an account +has, not how many of each. On the other hand, in ERC1155 accounts have a distinct balance for each token ID, and +non-fungible tokens are implemented by simply minting a single one of them. + +This approach leads to massive gas savings for projects that require multiple tokens. Instead of deploying a new +contract for each token type, a single ERC1155 token contract can hold the entire system state, reducing deployment +costs and complexity. + +== Interface + +:compatibility: xref:/erc1155.adoc#erc1155_compatibility[ERC1155 Compatibility] +:isrc5-interface: xref:/api/introspection.adoc#ISRC5[ISRC5] +:ierc1155-interface: xref:/api/erc1155.adoc#IERC1155[IERC1155] +:ierc1155metadata-interface: xref:/api/erc1155.adoc#IERC1155MetadataURI[IERC1155MetadataURI] +:erc1155-component: xref:/api/erc1155.adoc#ERC1155Component[ERC1155Component] +:dual-interfaces: xref:interfaces.adoc#dual_interfaces[Dual interfaces] + +The following interface represents the full ABI of the Contracts for Cairo {erc1155-component}. +The interface includes the {ierc1155-interface} standard interface and the optional {ierc1155metadata-interface} interface together with {isrc5-interface}. + +To support older token deployments, as mentioned in {dual-interfaces}, the component also includes implementations of the interface written in camelCase. + +[,javascript] +---- +trait ERC1155ABI { + // IERC1155 + fn balance_of(account: ContractAddress, token_id: u256) -> u256; + fn balance_of_batch( + accounts: Span, token_ids: Span + ) -> Span; + fn safe_transfer_from( + from: ContractAddress, + to: ContractAddress, + token_id: u256, + value: u256, + data: Span + ); + fn safe_batch_transfer_from( + from: ContractAddress, + to: ContractAddress, + token_ids: Span, + values: Span, + data: Span + ); + fn is_approved_for_all( + owner: ContractAddress, operator: ContractAddress + ) -> bool; + fn set_approval_for_all(operator: ContractAddress, approved: bool); + + // IERC1155MetadataURI + fn uri(token_id: u256) -> ByteArray; + + // ISRC5 + fn supports_interface(interface_id: felt252) -> bool; + + // IERC1155Camel + fn balanceOf(account: ContractAddress, tokenId: u256) -> u256; + fn balanceOfBatch( + accounts: Span, tokenIds: Span + ) -> Span; + fn safeTransferFrom( + from: ContractAddress, + to: ContractAddress, + tokenId: u256, + value: u256, + data: Span + ); + fn safeBatchTransferFrom( + from: ContractAddress, + to: ContractAddress, + tokenIds: Span, + values: Span, + data: Span + ); + fn isApprovedForAll(owner: ContractAddress, operator: ContractAddress) -> bool; + fn setApprovalForAll(operator: ContractAddress, approved: bool); } ---- === ERC1155 Compatibility -Although StarkNet is not EVM compatible, this implementation aims to be as close as possible to the ERC1155 standard in the following ways: - -* It uses Cairo's `uint256` instead of `felt`. -* It returns `TRUE` as success. - -But some differences can still be found, such as: +Although Starknet is not EVM compatible, this implementation aims to be as close as possible to the ERC1155 standard but some differences can still be found, such as: -* It implements an `uri()` function that returns the same URI for *all* token types. It relies on the token type ID substitution mechanism https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. Clients calling this function must replace the `\{id\}` substring with the actual token type ID. -* `safeTransferFrom` and `safeBatchTransferFrom` are specified such that the optional `data` argument should be of type bytes. -In Solidity, this means a dynamically-sized array. -To be as close as possible to the standard, the `data` argument accepts a dynamic array of felts. -In Cairo, arrays are expressed with the array length preceding the actual array; -hence, the method accepts `data_len` and `data` respectively as types `felt` and `felt*`. -* `IERC1155Receiver` compliant contracts (`ERC1155Holder`) return a hardcoded selector id according to EVM selectors, since selectors are calculated differently in Cairo. -This is in line with the ERC165 interfaces design choice towards EVM compatibility. -See the xref:introspection.adoc[Introspection docs] for more info. -* `IERC1155Receiver` compliant contracts (`ERC1155Holder`) must support ERC165 by registering the `IERC1155Receiver` selector id in its constructor and exposing the `supportsInterface` method. -In doing so, recipient contracts (both accounts and non-accounts) can be verified that they support ERC1155 transfers. +* The optional `data` argument in both `safe_transfer_from` and `safe_batch_transfer_from` is implemented as `Span`. +* `IERC1155Receiver` compliant contracts must implement SRC5 and register the `IERC1155Receiver` interface ID. +* `IERC1155Receiver::on_erc1155_received` must return that interface ID on success. == Usage -To show a standard use case, we'll use the `ERC1155MintableBurnable` preset which allows for only the owner to `mint` tokens. -To create a token, you need to first deploy both Account and ERC1155 contracts respectively. +Using Contracts for Cairo, constructing an ERC1155 contract requires integrating both `ERC1155Component` and `SRC5Component`. +The contract should also set up the constructor to initialize the token's URI and interface support. +Here's an example of a basic contract: + +[,javascript] +---- +#[starknet::contract] +mod MyERC1155 { + use openzeppelin::introspection::src5::SRC5Component; + use openzeppelin::token::erc1155::ERC1155Component; + use starknet::ContractAddress; + + component!(path: ERC1155Component, storage: erc1155, event: ERC1155Event); + component!(path: SRC5Component, storage: src5, event: SRC5Event); + + // ERC1155 + #[abi(embed_v0)] + impl ERC1155Impl = ERC1155Component::ERC1155Impl; + #[abi(embed_v0)] + impl ERC1155MetadataURIImpl = + ERC1155Component::ERC1155MetadataURIImpl; + #[abi(embed_v0)] + impl ERC1155Camel = ERC1155Component::ERC1155CamelImpl; + impl ERC1155InternalImpl = ERC1155Component::InternalImpl; + + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; + + #[storage] + struct Storage { + #[substorage(v0)] + erc1155: ERC1155Component::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage + } -Considering that the ERC1155 constructor method looks like this: + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC1155Event: ERC1155Component::Event, + #[flat] + SRC5Event: SRC5Component::Event + } -[,cairo] ----- -func constructor( - uri: felt, // Token URI as Cairo short string - owner: felt // Address designated as the contract owner -) { + #[constructor] + fn constructor( + ref self: ContractState, + token_uri: ByteArray, + recipient: ContractAddress, + token_ids: Span, + values: Span + ) { + self.erc1155.initializer(token_uri); + self + .erc1155 + .batch_mint_with_acceptance_check(recipient, token_ids, values, array![].span()); + } } ---- -Deployment of both contracts looks like this: +=== Batch operations -[,python] ----- -account = await starknet.deploy( - "contracts/Account.cairo", - constructor_calldata=[signer.public_key] -) - -erc1155 = await starknet.deploy( - "contracts/token/erc1155/presets/ERC1155MintableBurnable.cairo", - constructor_calldata=[ - str_to_felt("http://my.uri/{id}"), # uri - account.contract_address # owner - ] -) ----- - -To mint tokens, send a transaction like this: - -[,python] ----- -signer = MockSigner(PRIVATE_KEY) -token_id = uint(1) -mint_value = uint(1000) - -await signer.send_transaction( - account, erc1155.contract_address, 'mint', [ - recipient_address, - *token_id, - *mint_value, - 0 # data - ] -) ----- +:safe_transfer_from: xref:/api/erc1155.adoc#IERC1155-safe_transfer_from[safe_transfer_from] +:balance_of_batch: xref:/api/erc1155.adoc#IERC1155-balance_of_batch[balance_of_batch] +:safe_batch_transfer_from: xref:/api/erc1155.adoc#IERC1155-safe_batch_transfer_from[safe_batch_transfer_from] +:batch_mint_with_acceptance_check: xref:/api/erc1155.adoc#ERC1155Component-batch_mint_with_acceptance_check[batch_mint_with_acceptance_check] -=== Token Transfers +Because all state is held in a single contract, it is possible to operate over multiple tokens in a single transaction very efficiently. The standard provides two functions, {balance_of_batch} and {safe_batch_transfer_from}, that make querying multiple balances and transferring multiple tokens simpler and less gas-intensive. We also have {safe_transfer_from} for non-batch operations. -This library includes `safeTransferFrom` and `safeBatchTransferFrom` to transfer assets. These methods incorporate the following conditional logic: +In the spirit of the standard, we’ve also included batch operations in the non-standard functions, such as +{batch_mint_with_acceptance_check}. -. If the receiving address xref:accounts.adoc#account_introspection_with_erc165[is identified as an account], the tokens will be transferred. -. If the receiving address is not an account contract, the function will check that the receiver supports ERC1155 tokens before sending them. +WARNING: While {safe_transfer_from} and {safe_batch_transfer_from} prevent loss by checking the receiver can handle the +tokens, this yields execution to the receiver which can result in a xref:security.adoc#reentrancy_guard[reentrant call]. -The current implementation requires recipient contracts to support ERC165 and expose the `supportsInterface` method. -See <>. +=== Receiving tokens -=== Interpreting ERC1155 URIs +:src5: xref:introspection.adoc#src5[SRC5] +:on_erc1155_received: xref:/api/erc1155.adoc#IERC1155Receiver-on_erc1155_received[on_erc1155_received] +:on_erc1155_batch_received: xref:/api/erc1155.adoc#IERC1155Receiver-on_erc1155_batch_received[on_erc1155_batch_received] +:computing-interface-id: xref:introspection.adoc#computing_the_interface_id[Computing the interface ID] -Token URIs in Cairo are stored as single field elements. -Each field element equates to 252-bits (or 31.5 bytes) which means that a token's URI can be no longer than 31 characters. +In order to be sure a non-account contract can safely accept ERC1155 tokens, said contract must implement the `IERC1155Receiver` interface. +The recipient contract must also implement the {src5} interface which supports interface introspection. -NOTE: Storing the URI as an array of felts was considered to accommodate larger strings. -While this approach is more flexible regarding URIs, a returned array further deviates from the standard. Therefore, this library's ERC1155 implementation sets URIs as a single field element. +==== IERC1155Receiver -The `utils.py` module includes utility methods for converting to/from Cairo field elements. -To properly interpret a URI from ERC1155, simply trim the null bytes and decode the remaining bits as an ASCII string. -For example: +:receiver-id: xref:/api/erc1155.adoc#IERC1155Receiver[IERC1155Receiver interface ID] -[,python] +[,javascript] ---- -# HELPER METHODS -def str_to_felt(text): - b_text = bytes(text, 'ascii') - return int.from_bytes(b_text, "big") - -def felt_to_str(felt): - b_felt = felt.to_bytes(31, "big") - return b_felt.decode() - -token_id = uint(1) -sample_uri = str_to_felt('mock://mytoken') - -await signer.send_transaction( - account, erc1155.contract_address, 'setTokenURI', [ - *token_id, sample_uri] -) - -felt_uri = await erc1155.tokenURI(first_token_id).call() -string_uri = felt_to_str(felt_uri) ----- - -=== ERC1155Received - -In order to be sure a contract can safely accept ERC1155 tokens, said contract must implement the <> interface (as expressed in the EIP1155 specification). -Methods such as `safeTransferFrom` and `safeBatchTransferFrom` call the recipient contract's `onERC1155Received` or `onERC1155BatchReceived` method. -If the contract fails to return the correct magic value, the transaction fails. - -StarkNet contracts that support safe transfers, however, must also support xref:introspection.adoc#erc165[ERC165] and include `supportsInterface` as proposed in https://github.com/OpenZeppelin/cairo-contracts/discussions/100[#100]. -Transfer functions require a means of differentiating between account and non-account contracts. -Currently, StarkNet does not support error handling from the contract level; -therefore, the current ERC1155 implementation requires that all contracts that support safe ERC1155 transfers (both accounts and non-accounts) include the `supportsInterface` method. -Further, `supportsInterface` should return `TRUE` if the recipient contract supports the `IERC1155Receiver` magic value `00x4e2312e0` (which invokes `onERC1155Received` and `onERC1155BatchReceived`). -If the recipient contract supports the `IAccount` magic value, `supportsInterface` should return `TRUE`. -Otherwise, transfer functions should fail. - -== Presets - -=== ERC1155MintableBurnable - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/token/erc1155/presets/ERC1155MintableBurnable.cairo[`ERC1155MintableBurnable`] preset offers a quick and easy setup for creating ERC1155 tokens. Its constructor takes three arguments: `name`, `symbol`, and an `owner` address which will be capable of minting tokens. - -== Utilities - -=== ERC1155Holder - -Implementation of the `IERC1155Receiver` interface. - -Accepts all token transfers. -Make sure the contract is able to use its token with `IERC1155.safeTransferFrom`, `IERC1155.approve` or `IERC1155.setApprovalForAll`. - -Also utilizes the ERC165 method `supportsInterface` to determine if the contract is an account. -See <>. - -== API Specification - -=== IERC1155 API - -[,cairo] ----- -func balanceOf(account: felt, id: Uint256) -> (balance: Uint256) { +trait IERC1155Receiver { + fn on_erc1155_received( + operator: ContractAddress, + from: ContractAddress, + token_id: u256, + value: u256, + data: Span + ) -> felt252; + fn on_erc1155_batch_received( + operator: ContractAddress, + from: ContractAddress, + token_ids: Span, + values: Span, + data: Span + ) -> felt252; } - -func balanceOfBatch( - accounts_len: felt, - accounts: felt*, - ids_len: felt, - ids: Uint256* -) -> ( - balances_len: felt, - balances: Uint256* -) { -} - -func isApprovedForAll(account: felt, operator: felt) -> (approved: felt) { -} - -func setApprovalForAll(operator: felt, approved: felt) { -} - -func safeTransferFrom( - from_: felt, - to: felt, - id: Uint256, - value: Uint256, - data_len: felt, - data: felt* -) { -} - -func safeBatchTransferFrom( - from_: felt, - to: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) { -} ----- - -==== `balanceOf` - -Returns the number of `id` tokens of ``account``. - -Parameters: - -[,cairo] ----- -account: felt -id: Uint256 ----- - -Returns: - -[,cairo] ----- -balance: Uint256 ----- - -==== `balanceOfBatch` - -Get the balance of multiple account/token pairs. - -Parameters: - -[,cairo] ----- -accounts_len: felt -accounts: felt* -ids_len: felt -ids: Uint156* ----- - -Returns: - -[,cairo] ----- -balances_len: felt -balances: Uint256* ----- - -==== `isApprovedForAll` - -Get whether `operator` is approved by `account` for all tokens. - -Parameters: - -[,cairo] ----- -account: felt -operator: felt ----- - -Returns: - -[,cairo] ----- -approved: felt ----- - -==== `setApprovalForAll` - -Enable or disable approval for a third party ("operator") to manage all of the caller's tokens. - -Parameters: - -[,cairo] ----- -operator: felt -approved: felt ----- - -Returns: None. - -==== `safeTransferFrom` - -Transfers `value` amount of token `id` from `from_` to `to`, checking first that contract recipients are aware and capable of handling ERC1155 tokens to prevent locking them forever. -For information regarding how contracts communicate their awareness of the ERC1155 protocol, see <>. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -from_: felt -to: felt -id: Uint256 -value: Uint256 -data_len: felt -data: felt* ---- -Returns: None. - -==== `safeBatchTransferFrom` +Implementing the `IERC1155Receiver` interface exposes the {on_erc1155_received} and {on_erc1155_batch_received} methods. +When {safe_transfer_from} and {safe_batch_transfer_from} are called, they invoke the recipient contract's `on_erc1155_received` or `on_erc1155_batch_received` methods respectively which *must* return the {receiver-id}. +Otherwise, the transaction will fail. -Batch version of <>. Emits a <> event. +TIP: For information on how to calculate interface IDs, see {computing-interface-id}. -Parameters: - -[,cairo] ----- -from_: felt -to: felt -ids_len: felt -ids: Uint256* -values_len: felt -values: Uint256* -data_len: felt -data: felt* ----- +==== Creating a token receiver contract -Returns: None. +:ERC1155ReceiverComponent: xref:/api/erc1155.adoc#ERC1155ReceiverComponent[ERC1155ReceiverComponent] -''' +The Contracts for Cairo {ERC1155ReceiverComponent} already returns the correct interface ID for safe token transfers. +To integrate the `IERC1155Receiver` interface into a contract, simply include the ABI embed directive to the implementations and add the `initializer` in the contract's constructor. +Here's an example of a simple token receiver contract: -=== Events - -==== `TransferSingle (Event)` - -Emitted when `operator` sends `value` amount of `id` token from `from_` to `to`. - -Parameters: - -[,cairo] ----- -operator: felt -from_: felt -to: felt -id: Uint256 -value: Uint256 +[,javascript] ---- +#[starknet::contract] +mod MyTokenReceiver { + use openzeppelin::introspection::src5::SRC5Component; + use openzeppelin::token::erc1155::ERC1155ReceiverComponent; + use starknet::ContractAddress; -==== `TransferBatch (Event)` + component!(path: ERC1155ReceiverComponent, storage: erc1155_receiver, event: ERC1155ReceiverEvent); + component!(path: SRC5Component, storage: src5, event: SRC5Event); -Emitted when `operator` sends multiple `values` of multiple token `ids` from `from_` to `to`. - -Parameters: - -[,cairo] ----- -operator: felt -from_: felt -to: felt -ids_len: felt -ids: Uint256* -values_len: felt -values: Uint256* ----- - -==== `ApprovalForAll (Event)` - -Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. - -Parameters: - -[,cairo] ----- -account: felt -operator: felt -approved: felt ----- + // ERC1155Receiver + #[abi(embed_v0)] + impl ERC1155ReceiverImpl = ERC1155ReceiverComponent::ERC1155ReceiverImpl; + #[abi(embed_v0)] + impl ERC1155ReceiverCamelImpl = ERC1155ReceiverComponent::ERC1155ReceiverCamelImpl; + impl ERC1155ReceiverInternalImpl = ERC1155ReceiverComponent::InternalImpl; -''' + // SRC5 + #[abi(embed_v0)] + impl SRC5Impl = SRC5Component::SRC5Impl; -=== IERC1155Metadata API - -[,cairo] ----- -func uri(id: Uint256) -> (uri: felt) { -} ----- - -==== `uri` - -Returns the Uniform Resource Identifier (URI) for a token `id`, although this implementation returns the same URI for *all* token types. It relies -on the token type ID substitution mechanism -https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP]. - -Parameters: - -[,cairo] ----- -id: Uint256 ----- - -Returns: - -[,cairo] ----- -uri: felt ----- - -''' - -=== IERC1155Receiver API + #[storage] + struct Storage { + #[substorage(v0)] + erc1155_receiver: ERC1155ReceiverComponent::Storage, + #[substorage(v0)] + src5: SRC5Component::Storage + } -[,cairo] ----- -func onERC1155Received( - operator: felt, - from_: felt, - tokenId: Uint256, - data_len: felt, - data: felt* -) -> (selector: felt) { -} + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + #[flat] + ERC1155ReceiverEvent: ERC1155ReceiverComponent::Event, + #[flat] + SRC5Event: SRC5Component::Event + } -func onERC1155BatchReceived( - operator: felt, - from_: felt, - ids_len: felt, - ids: Uint256*, - values_len: felt, - values: Uint256*, - data_len: felt, - data: felt*, -) -> (selector: felt) { + #[constructor] + fn constructor(ref self: ContractState) { + self.erc721_receiver.initializer(); + } } ---- - -==== `onERC1155Received` - -Whenever any IERC1155 token is transferred or minted to this non-account contract by `operator` from `from_`, this function is called. - -Parameters: - -[,cairo] ----- -operator: felt -from_: felt -id: Uint256 -value: Uint156 -data_len: felt -data: felt* ----- - -Returns: - -[,cairo] ----- -selector: felt ----- - -==== `onERC1155BatchReceived` - -Whenever any IERC1155 token is transferred to this non-account contract via `safeBatchTransferFrom` by `operator` from `from_`, this function is called. - -Parameters: - -[,cairo] ----- -operator: felt -from_: felt -ids_len: felt -ids: Uint256* -values_len: felt -values: Uint156* -data_len: felt -data: felt* ----- - -Returns: - -[,cairo] ----- -selector: felt ----- diff --git a/docs/modules/ROOT/pages/erc20.adoc b/docs/modules/ROOT/pages/erc20.adoc index afc26b452..7d260e47b 100644 --- a/docs/modules/ROOT/pages/erc20.adoc +++ b/docs/modules/ROOT/pages/erc20.adoc @@ -15,11 +15,15 @@ See the {custom-decimals} guide. == Interface :dual-interfaces: xref:/interfaces.adoc#dual_interfaces[Dual interfaces] +:ierc20-interface: xref:/api/erc20.adoc#IERC20[IERC20] +:ierc20metadata-interface: xref:/api/erc20.adoc#IERC20Metadata[IERC20Metadata] +:erc20-component: xref:/api/erc20.adoc#ERC20Component[ERC20Component] :erc20-supply: xref:/guides/erc20-supply.adoc[Creating ERC20 Supply] -The following interface represents the full ABI of the Contracts for Cairo `ERC20` component. -The interface includes the `IERC20` standard interface as well as `IERC20Camel` for backwards compatibility. -To support older token deployments, as mentioned in {dual-interfaces}, the `ERC20` component also includes an implementation of the interface written in camelCase. +The following interface represents the full ABI of the Contracts for Cairo {erc20-component}. +The interface includes the {ierc20-interface} standard interface as well as the optional {ierc20metadata-interface}. + +To support older token deployments, as mentioned in {dual-interfaces}, the component also includes an implementation of the interface written in camelCase. [,javascript] ---- diff --git a/docs/modules/ROOT/pages/erc721.adoc b/docs/modules/ROOT/pages/erc721.adoc index d59351c5c..3b63ce67f 100644 --- a/docs/modules/ROOT/pages/erc721.adoc +++ b/docs/modules/ROOT/pages/erc721.adoc @@ -9,17 +9,19 @@ The ERC721 token standard is a specification for {token-types}, or more colloqui == Interface :compatibility: xref:/erc721.adoc#erc721_compatibility[ERC721 Compatibility] -:ierc721-interface: xref:/erc721.adoc#ierc721[IERC721] -:ierc721metadata-interface: xref:/erc721.adoc#ierc721metadata[IERC721Metadata] +:ierc721-interface: xref:/api/erc721.adoc#IERC721[IERC721] +:ierc721metadata-interface: xref:/api/erc721.adoc#IERC721Metadata[IERC721Metadata] +:erc721-component: xref:/api/erc721.adoc#ERC721Component[ERC721Component] :dual-interfaces: xref:interfaces.adoc#dual_interfaces[Dual interfaces] -The following interface represents the full ABI of the Contracts for Cairo `ERC721Component`. -The interface includes the <> standard interface and the optional <> interface. +The following interface represents the full ABI of the Contracts for Cairo {erc721-component}. +The interface includes the {ierc721-interface} standard interface and the optional {ierc721metadata-interface} interface. + To support older token deployments, as mentioned in {dual-interfaces}, the component also includes implementations of the interface written in camelCase. [,javascript] ---- -trait IERC721ABI { +trait ERC721ABI { // IERC721 fn balance_of(account: ContractAddress) -> u256; fn owner_of(token_id: u256) -> ContractAddress; diff --git a/docs/modules/ROOT/pages/presets.adoc b/docs/modules/ROOT/pages/presets.adoc index b353ddc3b..d3a20c69d 100644 --- a/docs/modules/ROOT/pages/presets.adoc +++ b/docs/modules/ROOT/pages/presets.adoc @@ -1,6 +1,7 @@ :account: xref:/api/account.adoc#Account[Account] :erc20: xref:/api/erc20.adoc#ERC20[ERC20] :erc721: xref:/api/erc721.adoc#ERC721[ERC721] +:erc1155: xref:/api/erc1155.adoc#ERC1155[ERC1155] :eth-account-upgradeable: xref:/api/account.adoc#EthAccountUpgradeable[EthAccountUpgradeable] :sierra-class-hashes: https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/class-hash[Sierra class hashes] :starkli: https://book.starkli.rs/introduction[starkli] @@ -29,14 +30,17 @@ NOTE: Class hashes were computed using {class-hash-cairo-version}. | `{account}` | `{Account-class-hash}` -| `{eth-account-upgradeable}` -| `{EthAccountUpgradeable-class-hash}` - | `{erc20}` | `{ERC20-class-hash}` | `{erc721}` | `{ERC721-class-hash}` + +| `{erc1155}` +| `{ERC1155-class-hash}` + +| `{eth-account-upgradeable}` +| `{EthAccountUpgradeable-class-hash}` |=== TIP: {starkli} class-hash command can be used to compute the class hash from a Sierra artifact. diff --git a/docs/modules/ROOT/pages/utils/_class_hashes.adoc b/docs/modules/ROOT/pages/utils/_class_hashes.adoc index 58f5ed728..234e715a3 100644 --- a/docs/modules/ROOT/pages/utils/_class_hashes.adoc +++ b/docs/modules/ROOT/pages/utils/_class_hashes.adoc @@ -5,6 +5,7 @@ :Account-class-hash: 0x01148c31dfa5c4708a4e9cf1eb0fd3d4d8ad9ccf09d0232cd6b56bee64a7de9d :ERC20-class-hash: 0x07d94f28156c0dc3bfd9a07ca79b15b8da2b5b32093db79000fcd0f6f625d213 :ERC721-class-hash: 0x06b7c9efc5467c621f58d87995302d940a39b7217b5c5a7a55555c97cabf5cd8 +:ERC1155-class-hash: 0x518be7d9fa527c78d6929bf9e638e9c98b6077722e27e9546cc4342e830386e :EthAccountUpgradeable-class-hash: 0x0580fe510cf07255540abda6f9d29aa07cb8944db444bca59e1573904c269844 // Presets page diff --git a/docs/modules/ROOT/pages/utils/_common.adoc b/docs/modules/ROOT/pages/utils/_common.adoc new file mode 100644 index 000000000..b69272b96 --- /dev/null +++ b/docs/modules/ROOT/pages/utils/_common.adoc @@ -0,0 +1,5 @@ +// Notes +:src5-component-required-note: Implementing xref:api/introspection.adoc#SRC5Component[SRC5Component] is a requirement for this component to be implemented. + +// Links +:mixin-impls: xref:components.adoc#mixins[Embeddable Mixin Implementations] diff --git a/src/presets/erc1155.cairo b/src/presets/erc1155.cairo index cbefb3a3a..b1c111e5f 100644 --- a/src/presets/erc1155.cairo +++ b/src/presets/erc1155.cairo @@ -48,7 +48,7 @@ mod ERC1155 { SRC5Event: SRC5Component::Event } - /// Sets the `token_uri`. + /// Sets the `base_uri` for all tokens. /// Mints the `values` for `token_ids` tokens to `recipient`. /// /// Requirements: @@ -59,12 +59,12 @@ mod ERC1155 { #[constructor] fn constructor( ref self: ContractState, - token_uri: ByteArray, + base_uri: ByteArray, recipient: ContractAddress, token_ids: Span, values: Span ) { - self.erc1155.initializer(token_uri); + self.erc1155.initializer(base_uri); self .erc1155 .batch_mint_with_acceptance_check(recipient, token_ids, values, array![].span()); diff --git a/src/tests/mocks/erc1155_mocks.cairo b/src/tests/mocks/erc1155_mocks.cairo index 68da49228..976050426 100644 --- a/src/tests/mocks/erc1155_mocks.cairo +++ b/src/tests/mocks/erc1155_mocks.cairo @@ -41,12 +41,12 @@ mod DualCaseERC1155Mock { #[constructor] fn constructor( ref self: ContractState, + base_uri: ByteArray, recipient: ContractAddress, token_id: u256, - value: u256, - uri: ByteArray + value: u256 ) { - self.erc1155.initializer(uri); + self.erc1155.initializer(base_uri); self.erc1155.mint_with_acceptance_check(recipient, token_id, value, array![].span()); } } @@ -92,12 +92,12 @@ mod SnakeERC1155Mock { #[constructor] fn constructor( ref self: ContractState, + base_uri: ByteArray, recipient: ContractAddress, token_id: u256, - value: u256, - uri: ByteArray + value: u256 ) { - self.erc1155.initializer(uri); + self.erc1155.initializer(base_uri); self.erc1155.mint_with_acceptance_check(recipient, token_id, value, array![].span()); } } @@ -143,12 +143,12 @@ mod CamelERC1155Mock { #[constructor] fn constructor( ref self: ContractState, + base_uri: ByteArray, recipient: ContractAddress, token_id: u256, - value: u256, - uri: ByteArray + value: u256 ) { - self.erc1155.initializer(uri); + self.erc1155.initializer(base_uri); self.erc1155.mint_with_acceptance_check(recipient, token_id, value, array![].span()); } } diff --git a/src/tests/token/test_dual1155.cairo b/src/tests/token/test_dual1155.cairo index 272072fd7..32962595b 100644 --- a/src/tests/token/test_dual1155.cairo +++ b/src/tests/token/test_dual1155.cairo @@ -21,13 +21,13 @@ use starknet::testing; // fn setup_snake() -> (DualCaseERC1155, IERC1155Dispatcher, ContractAddress) { - let uri: ByteArray = "URI"; + let base_uri: ByteArray = "URI"; let owner = setup_account(); let mut calldata = array![]; + calldata.append_serde(base_uri); calldata.append_serde(owner); calldata.append_serde(TOKEN_ID); calldata.append_serde(TOKEN_VALUE); - calldata.append_serde(uri); let target = utils::deploy(SnakeERC1155Mock::TEST_CLASS_HASH, calldata); ( DualCaseERC1155 { contract_address: target }, @@ -37,13 +37,13 @@ fn setup_snake() -> (DualCaseERC1155, IERC1155Dispatcher, ContractAddress) { } fn setup_camel() -> (DualCaseERC1155, IERC1155CamelDispatcher, ContractAddress) { - let uri: ByteArray = "URI"; + let base_uri: ByteArray = "URI"; let owner = setup_account(); let mut calldata = array![]; + calldata.append_serde(base_uri); calldata.append_serde(owner); calldata.append_serde(TOKEN_ID); calldata.append_serde(TOKEN_VALUE); - calldata.append_serde(uri); let target = utils::deploy(CamelERC1155Mock::TEST_CLASS_HASH, calldata); ( DualCaseERC1155 { contract_address: target }, diff --git a/src/token/erc1155/erc1155.cairo b/src/token/erc1155/erc1155.cairo index b50079a20..138e3e58a 100644 --- a/src/token/erc1155/erc1155.cairo +++ b/src/token/erc1155/erc1155.cairo @@ -104,7 +104,7 @@ mod ERC1155Component { +SRC5Component::HasComponent, +Drop > of interface::IERC1155> { - /// Returns the number of NFTs owned by `account` for a specific `token_id`. + /// Returns the amount of `token_id` tokens owned by `account`. fn balance_of( self: @ComponentState, account: ContractAddress, token_id: u256 ) -> u256 { @@ -112,8 +112,7 @@ mod ERC1155Component { } - /// Returns a span of u256 values representing the batch balances of the - /// `accounts` for the specified `token_ids`. + /// Returns a list of balances derived from the `accounts` and `token_ids` pairs. /// /// Requirements: /// @@ -138,7 +137,7 @@ mod ERC1155Component { batch_balances.span() } - /// Transfers ownership of `token_id` from `from` if `to` is either an account or `IERC1155Receiver`. + /// Transfers ownership of `value` amount of `token_id` from `from` if `to` is either an account or `IERC1155Receiver`. /// /// `data` is additional data, it has no specified format and it is passed to `to`. /// @@ -169,7 +168,7 @@ mod ERC1155Component { self.safe_batch_transfer_from(from, to, token_ids, values, data) } - /// Batched version of `safeTransferFrom`. + /// Batched version of `safe_transfer_from`. /// /// WARNING: This function can potentially allow a reentrancy attack when transferring tokens /// to an untrusted contract, when invoking `on_ERC1155_batch_received` on the receiver. @@ -205,7 +204,7 @@ mod ERC1155Component { self.update_with_acceptance_check(from, to, token_ids, values, data); } - /// Enable or disable approval for `operator` to manage all of the + /// Enables or disables approval for `operator` to manage all of the /// callers assets. /// /// Requirements: @@ -223,7 +222,7 @@ mod ERC1155Component { self.emit(ApprovalForAll { owner, operator, approved }); } - /// Query if `operator` is an authorized operator for `owner`. + /// Queries if `operator` is an authorized operator for `owner`. fn is_approved_for_all( self: @ComponentState, owner: ContractAddress, operator: ContractAddress ) -> bool { @@ -317,10 +316,11 @@ mod ERC1155Component { impl SRC5: SRC5Component::HasComponent, +Drop > of InternalTrait { - /// Initializes the contract by setting the token uri. + /// Initializes the contract by setting the `base_uri` for all tokens, + /// and registering the supported interfaces. /// This should only be used inside the contract's constructor. - fn initializer(ref self: ComponentState, uri: ByteArray) { - self.set_uri(uri); + fn initializer(ref self: ComponentState, base_uri: ByteArray) { + self.set_base_uri(base_uri); let mut src5_component = get_dep_component_mut!(ref self, SRC5); src5_component.register_interface(interface::IERC1155_ID); @@ -379,13 +379,15 @@ mod ERC1155Component { } /// Version of `update` that performs the token acceptance check by calling - /// `IERC1155Receiver-onERC1155Received` or `IERC1155Receiver-onERC1155BatchReceived` if + /// `IERC1155Receiver::onERC1155Received` or `IERC1155Receiver::onERC1155BatchReceived` if /// the receiver is not recognized as an account. /// /// Requirements: /// /// - `to` is either an account contract or supports the `IERC1155Receiver` interface. /// - `token_ids` and `values` must have the same length. + /// + /// Emits a `TransferSingle` event if the arrays contain one element, and `TransferBatch` otherwise. fn update_with_acceptance_check( ref self: ComponentState, from: ContractAddress, @@ -502,8 +504,8 @@ mod ERC1155Component { /// /// Because these URIs cannot be meaningfully represented by the `URI` event, /// this function emits no events. - fn set_uri(ref self: ComponentState, uri: ByteArray) { - self.ERC1155_uri.write(uri); + fn set_base_uri(ref self: ComponentState, base_uri: ByteArray) { + self.ERC1155_uri.write(base_uri); } }