From d883c80f54c44e21838d6c42e85122494fe4f360 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Mon, 20 Mar 2023 20:27:16 +0100 Subject: [PATCH 01/20] Create eip-4365.md --- EIPS/eip-4365.md | 360 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 EIPS/eip-4365.md diff --git a/EIPS/eip-4365.md b/EIPS/eip-4365.md new file mode 100644 index 0000000000000..0dece23e9d532 --- /dev/null +++ b/EIPS/eip-4365.md @@ -0,0 +1,360 @@ +--- +eip: 4365 +title: Redeemable Tokens +description: A proposition for redeemable tokens +author: Lucaz Lindgren (@LucazFFz) +discussions-to: https://ethereum-magicians.org/t/eip-4365-redeemable-tokens/13441 +status: Draft +type: Standards Track +category: ERC +created: 2023-03-20 +requires: 165, 1238 +--- + +## Abstract + +[ERC-4365: Redeemable Tokens](https://github.com/ethereum/EIPs/pull/6731) outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. + +Contrary to the ERC-1155 standard, ERC-4365 does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, this report introduces several extensions used to expand the functionality of ERC-4365. One of which is the **Badge extension** which allows implementers to easily add access control limiting certain actions to addresses possessing pre-specified ERC-1238 badges. + +## Motivation + +The core idea of ERC-4365: Redeemable Token is to standardize and simplify the development of redeemable tokens (tickets) on the Ethereum blockchain. The tokens can be redeemed in exchange for currency or access (the reward for redeeming is left to implementers). The tokens can be exchanged for real-world or digital rewards. + +Example of use-cases for redeemable tokens: + +- General admission tickets - Tickets allowing attendees entry to the event together with access to the regular event activities. This type of ticket could be fungible meaning they are interchangeable. The event can be held either physically or digitally. +- VIP tickets - All-access tickets that include everything the event offers with activities excluded from the general admission tickets to give the attendees a premium experience. These tickets can be non-fungible making every ticket unique and allowing each ticket to be connected to an individual artwork or likewise to incentivize purchasing VIP tickets instead. + +Additionally, this standard can be used to create, among others, vouchers, gift cards, and scratchcards. + +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. + +**Every ERC-4365 compliant smart contract MUST implement the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** + +```solidity +interface IERC4365 is IERC165 { + /** + * @dev Emitted when `amount` tokens of token type `id` are minted to `to` by `minter`. + */ + event MintSingle(address indexed minter, address indexed to, uint256 indexed id, uint256 amount); + + /** + * @dev Equivalent to multiple {MintSingle} events, where `minter` and `to` is the same for all token types. + */ + event MintBatch(address indexed minter, address indexed to, uint256[] ids, uint256[] amounts); + + /** + * @dev Emitted when `amount` tokens of token type `id` owned by `owner` are burned by `burner`. + */ + event BurnSingle(address indexed burner, address indexed owner, uint256 indexed id, uint256 amount); + + /** + * @dev Equivalent to multiple {BurnSingle} events, where `owner` and `burner` is the same for all token types. + */ + event BurnBatch(address indexed burner, address indexed owner, uint256[] ids, uint256[] amounts); + + /** + * @dev Emitted when `amount` of tokens of token type `id` are redeemed by `account`. + */ + event Redeem(address indexed account, uint256 indexed id, uint256 amount); + + /** + * @dev Returns the balance of tokens of token type `id` owned by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev Returns the balance of `account` for a batch of token `ids`. + */ + function balanceOfBatch(address account, uint256[] calldata ids) external view returns (uint256[] memory); + + /** + * @dev Returns the balance of multiple `accounts` for a batch of token `ids`. + * This is equivalent to calling {balanceOfBatch} for several accounts in just one call. + * + * Requirements: + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view + returns (uint256[][] memory); + + /** + * @dev Returns the balance of tokens of token type `id` redeemed by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + */ + function balanceOfRedeemed(address account, uint256 id) external view returns (uint256); + + /** + * @dev Returns the balance of `account` for a batch of redeemed token `ids`. + */ + function balanceOfRedeemedBatch(address account, uint256[] calldata ids) external view returns (uint256[] memory); + + /** + * @dev Returns the balance of multiple `accounts` for a batch of redeemed token `ids`. + * This is equivalent to calling {balanceOfRedeemedBatch} for several accounts in just one call. + * + * Requirements: + * - `accounts` and `ids` must have the same length. + */ + function balanceOfRedeemedBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view + returns (uint256[][] memory); + + /** + * Redeem `amount` of token type `id` owned by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + * - `amount` together with `account` balance of redeemed token of token type `id` + * cannot exceed `account` balance of token type `id`. + */ + function redeem (address account, uint256 id, uint256 amount, bytes memory data) external; +} +``` + +In addition, in order for a contract to be compliant with ERC-4365, it MUST abide by the following: + +- Implementers MAY enable token transfers to support functionality such as ticket reselling. +- Implementers MUST NOT allow tokens to be transferred between addresses after they have been redeemed. +- Implementers MUST allow token holders to redeem their tokens. +- Implementers MUST NOT allow token issuers to redeem the tokens they have issued. +- Implementers SHOULD allow token recipients to burn any token they receive. +- Implementers MAY enable token issuers to burn the tokens they issued. + +**Smart contracts MUST implement all of the functions in the `ERC4365Receiver` interface to accept tokens being minted to them.** + +The **URI Storage extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique URI for each token ID. + +```solidity +interface IERC4365URIStorage is IERC4365 { + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + */ + event URI(uint256 indexed id, string value); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `id` token. + */ + function tokenURI(uint256 id) external view returns (string memory); +} +``` + +The **Expirable extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: + +- Implementers MUST NOT allow tokens to be minted or redeemed if expired. + +```solidity +interface IERC4365Expirable is IERC4365 { + /** + * @dev Sets the expiry date for the token of token type `id`. + */ + function setExpiryDate(uint256 id, uint256 date) external; + + /** + * @dev [Batched] version of {setExpiryDate}. + */ + function setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) external; + + /** + * @dev Returns the expiry date for the token of token type `id`. + */ + function expiryDate(uint256 id) external view returns (uint256); + + /** + * @dev Returns `true` or `false` depending on if the token of token type `id` has expired + * by comparing the expiry date with `block.timestamp`. + */ + function isExpired(uint256 id) external view returns (bool); +} +``` + +The **Supply extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: + +- Implementers SHOULD NOT allow tokens to be minted if total supply exceeds max supply. +- Implementers SHOULD increment total supply upon minting and decrement upon burning. +- Implementers are RECOMMENDED to override the `_beforeMint` hook to increment total supply upon minting and decrement upon burning. + +```solidity +interface IERC4365Payable is IERC4365 { + /** + * @dev Sets the price `amount` for the token of token type `id`. + */ + function setPrice(uint256 id, uint256 amount) external; + + /** + * @dev [Batched] version of {setPrice}. + */ + function setBatchPrices(uint256[] memory ids, uint256[] memory amounts) external; + + /** + * @dev Returns the price for the token type `id`. + */ + function price(uint256 id) external view returns (uint256); +} +``` + +The **Payable extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: + +- Implementers SHOULD require recipients to provide funding equal to the token price. + +```solidity +interface IERC4365Supply is IERC4365 { + /** + * @dev Sets the max supply for the token of token type `id`. + */ + function setMaxSupply(uint256 id, uint256 amount) external; + + /** + * @dev [Batched] version of {setMaxSupply}. + */ + function setBatchMaxSupplies(uint256[] memory ids, uint256[] memory amounts) external; + + /** + * @dev Returns the total supply for token of token type `id`. + */ + function totalSupply(uint256 id) external view returns (uint256); + + /** + * @dev Returns the max supply for token of token type `id`. + */ + function maxSupply(uint256 id) external view returns (uint256); + + /** + * @dev Indicates whether any token of token type `id` exists, or not. + */ + function exists(uint256 id) external view returns (bool); +} +``` + +The **Badge extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate multiple different unique ERC-1238 Badges for each token ID. Smart contracts implementing the `ERC4365adge` extension MUST abide by the following: + +- Implementers are RECOMMENDED to implement a `data` field of data type `bytes` in the Badge struct as a general-purpose field with no specified format. + +```solidity +interface IERC4365Badge is IERC4365 { + /** + * @dev Adds an ERC-1238 token reference `badge_` with id `badgeId` for the token of token type `id`. + * + * Requirements: + * - `badge_.contract_` must implement the IERC1238 interface. + */ + function addBadge(uint256 tokenId, uint256 badgeId, Badge memory badge_) external; + + /** + * @dev [Batched] version of {addBadge}. + */ + function addBadgesBatch(uint256 tokenId, uint256[] memory badgeIds, Badge[] memory badges) external; + + /** + * @dev Returns the ERC-1238 token reference data with id `badgeId` for token of token type `tokenId`. + */ + function badge(uint256 tokenId, uint256 badgeId) external view returns (Badge memory); + + /** + * @dev Returns all ERC-1238 token reference data set for token of token type `id`. + */ + function allBadges(uint256 id) external view returns (Badge[] memory); + + /** + * @dev Returns the balance of ERC-1238 tokens owned by `account` added to token type `tokenId` + * by using the reference data in `badgeId`. + * + * Requirements: + * - `account` cannot be the zero address. + */ + function balanceOfBadge(address account, uint256 tokenId, uint256 badgeId) external view returns (uint256); + + /** + * @dev Returns the balance of all ERC-1238 tokens owned by `account` added to token type `tokenId`. + */ + function balanceOfAllBadges(address account, uint256 id) external view returns (uint256[] memory); + + /** + * @dev [Batched] version of {balanceOfAllbadges}. + */ + function balanceOfAllBadgesBatch(address account, uint256[] memory ids) external view returns (uint256[][] memory); +} +``` + +## Rationale + +### Overview + +The proposed interface and implementation draw heavy inspiration from the ERC-1155 Multi-Token Standard which paved the way for managing multiple token types in the same smart contract reducing gas costs. It draws from the lessons and prior discussions which emerged from the standard and therefore inherits from its design and structure. + +ERC-1155 presents multiple interesting features also applicable to ERC-4365 tokens: + +- Because one contract is able to hold multiple different token types, there is no need to deploy multiple contracts for each collection as with previous standards. This saves on deployment gas costs as well as reduces redundant bytecode on the Ethereum blockchain. +- ERC-1155 is fungibility-agnostic which means the same contract can manage both fungible and non-fungible token types. +- Batch operations are supported making it possible to mint or query the balance for multiple token ids within the same call. +- Eliminates the possibility to lock tokens in smart contracts due to the requirement for smart contracts to implement the `ERC1155TokenReceiver` interface. +- Smart contracts implementing the `ERC1155TokenReceiver` interface may reject an increase in balance. + +This standard does not assume who has the power to mint/burn tokens nor under what condition the actions can occur. However, it requires that the token holders have the ability to redeem their tokens. + +### Fungibility + +This standard, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. + +One way to achieve non-fungible tokens is to utilize split ID bits reserving the top 128 bits of the 256 bits `id` parameter to represent the base token ID while using the bottom 128 bits to represent the index of the non-fungible to make it unique. For more information, reference the [EIP-1155 documentation](https://eips.ethereum.org/EIPS/eip-1155). + +Alternatively, a more intuitive approach to represent non-fungible tokens is to allow a maximum value of 1 for each. This would reflect the real world, where unique items have a quantity of 1 and fungible items have a quantity greater than 1. + +### Batch Operations + +ERC-1155, likewise ERC-4365, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. + +However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this standard support, introduced by the ERC-1238 standard, bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. + +### Transfer + +This standard does not enforce transferability between addresses except for minting and burning. However, it recognizes the possible need for it when for example implementing resell functionality and, therefore, does not prevent it. + +### Badge + +This extension enables the possibility to associate redeemable tokens with ERC-1238 tokens (badges) by storing one or more references to contracts implementing the `ERC1238` interface. + +The `balanceOfBadge`, `balanceOfAllBadges`, and `balanceOfAllBadgesBatch` functions simply query the specified ERC-1238 contract for the balance of tokens with the given ID. + +This allows implementers to easily add access control limiting certain actions to addresses possessing pre-specified ERC-1238 badges. One use-case is to limit which addresses are able to mint (purchase) redeemable tokens. Additionally, addresses holding a particular badge may receive discounts when minting tokens. + +On top of this, implementers are RECOMMENDED to implement a `bytes` field in the Badge struct called `data`. This is to, optionally, associate data with each separate non-transferable token. For example, the balance of a badge required to mint a redeemable token. It could also be used to specify badges with different use cases within the contract, such as required (badges required to mint) and discount (badges that give a discount when minting). + +The `data` field can be split reserving the first 2 bits to store the required value/discount amount and the following two bits to specify one of four different types. Note that these numbers and use cases are examples and implementers MAY store whichever data they see useful for their needs. + +### Redeem + +The core addition to redeemable tokens is the possibility to redeem tokens in exchange for currency, access, etc. As tokens only can be redeemed by their holders a possible `redeemBatch` function has been excluded as it is not expected that a holder would want to redeem multiple token types simultaneously. + +### Safe Mint Only + +This standard takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. + +## Backwards Compatibility + +Because of the heavy inspiration from the ERC-1155 standard many concepts and methods remain identical, namely the concept of a batch, the `balanceOf` and `balanceOfBatch` functions, and to some extent the extensions for URI storage and supply. + +ERC-4365 also takes inspiration from ERC-1238 and implements the idea of a bundle, specifically is the `balanceOfBundle` function identical. The `ERC4365Expirable` extension together with the `MintSingle` and `MintBatch` events are identical to their ERC-1238 counterparts. + +## Reference Implementation + +- https://github.com/LucazFFz/ERC4365-token + +## Security Considerations + +Needs discussion. + +## Copyright + +Copyright and related rights waived via [CC0](../LICENSE.md). From 9eff3ff1357085600be0dd9e752cd7011d5fd2ed Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Tue, 21 Mar 2023 13:54:05 +0100 Subject: [PATCH 02/20] Remove ERC4365Badge extension and add reference implementation --- EIPS/eip-4365.md | 110 +---- assets/eip-4365/.gitignore | 2 + assets/eip-4365/README.md | 95 ++++ assets/eip-4365/contracts/.gitkeep | 0 assets/eip-4365/contracts/Migrations.sol | 25 ++ assets/eip-4365/contracts/examples/Ticket.sol | 57 +++ .../contracts/token/ERC4365/ERC4365.sol | 412 ++++++++++++++++++ .../contracts/token/ERC4365/IERC4365.sol | 95 ++++ .../token/ERC4365/IERC4365Receiver.sol | 50 +++ .../ERC4365/extensions/ERC4365Expirable.sol | 73 ++++ .../ERC4365/extensions/ERC4365Payable.sol | 55 +++ .../ERC4365/extensions/ERC4365Supply.sol | 104 +++++ .../ERC4365/extensions/ERC4365URIStorage.sol | 84 ++++ .../ERC4365/extensions/IERC4365Expirable.sol | 31 ++ .../ERC4365/extensions/IERC4365Payable.sol | 24 + .../ERC4365/extensions/IERC4365Supply.sol | 34 ++ .../ERC4365/extensions/IERC4365URIStorage.sol | 20 + assets/eip-4365/contracts/utils/Address.sol | 244 +++++++++++ assets/eip-4365/contracts/utils/Context.sol | 24 + assets/eip-4365/contracts/utils/Strings.sol | 70 +++ .../contracts/utils/introspection/ERC165.sol | 29 ++ .../contracts/utils/introspection/IERC165.sol | 25 ++ assets/eip-4365/contracts/utils/math/Math.sol | 345 +++++++++++++++ assets/eip-4365/migrations/.gitkeep | 0 .../migrations/1_initial_migration.js | 5 + .../eip-4365/migrations/2_deploy_contracts.js | 5 + assets/eip-4365/test/.gitkeep | 0 assets/eip-4365/truffle-config.js | 141 ++++++ 28 files changed, 2072 insertions(+), 87 deletions(-) create mode 100644 assets/eip-4365/.gitignore create mode 100644 assets/eip-4365/README.md create mode 100644 assets/eip-4365/contracts/.gitkeep create mode 100644 assets/eip-4365/contracts/Migrations.sol create mode 100644 assets/eip-4365/contracts/examples/Ticket.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/ERC4365.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/IERC4365.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol create mode 100644 assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol create mode 100644 assets/eip-4365/contracts/utils/Address.sol create mode 100644 assets/eip-4365/contracts/utils/Context.sol create mode 100644 assets/eip-4365/contracts/utils/Strings.sol create mode 100644 assets/eip-4365/contracts/utils/introspection/ERC165.sol create mode 100644 assets/eip-4365/contracts/utils/introspection/IERC165.sol create mode 100644 assets/eip-4365/contracts/utils/math/Math.sol create mode 100644 assets/eip-4365/migrations/.gitkeep create mode 100644 assets/eip-4365/migrations/1_initial_migration.js create mode 100644 assets/eip-4365/migrations/2_deploy_contracts.js create mode 100644 assets/eip-4365/test/.gitkeep create mode 100644 assets/eip-4365/truffle-config.js diff --git a/EIPS/eip-4365.md b/EIPS/eip-4365.md index 0dece23e9d532..c96e1ded82ee4 100644 --- a/EIPS/eip-4365.md +++ b/EIPS/eip-4365.md @@ -13,26 +13,26 @@ requires: 165, 1238 ## Abstract -[ERC-4365: Redeemable Tokens](https://github.com/ethereum/EIPs/pull/6731) outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +This ERC outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. -Contrary to the ERC-1155 standard, ERC-4365 does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, this report introduces several extensions used to expand the functionality of ERC-4365. One of which is the **Badge extension** which allows implementers to easily add access control limiting certain actions to addresses possessing pre-specified ERC-1238 badges. +Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. ## Motivation -The core idea of ERC-4365: Redeemable Token is to standardize and simplify the development of redeemable tokens (tickets) on the Ethereum blockchain. The tokens can be redeemed in exchange for currency or access (the reward for redeeming is left to implementers). The tokens can be exchanged for real-world or digital rewards. +The core idea of this ERC is to standardize and simplify the development of redeemable tokens (tickets) on the Ethereum blockchain. The tokens can be redeemed in exchange for currency or access (the reward for redeeming is left to implementers). The tokens can be exchanged for real-world or digital rewards. Example of use-cases for redeemable tokens: -- General admission tickets - Tickets allowing attendees entry to the event together with access to the regular event activities. This type of ticket could be fungible meaning they are interchangeable. The event can be held either physically or digitally. -- VIP tickets - All-access tickets that include everything the event offers with activities excluded from the general admission tickets to give the attendees a premium experience. These tickets can be non-fungible making every ticket unique and allowing each ticket to be connected to an individual artwork or likewise to incentivize purchasing VIP tickets instead. +- **General admission tickets** - Tickets allowing attendees entry to the event together with access to the regular event activities. This type of ticket could be fungible meaning they are interchangeable. The event can be held either physically or digitally. +- **VIP tickets** - All-access tickets that include everything the event offers with activities excluded from the general admission tickets to give the attendees a premium experience. These tickets can be non-fungible making every ticket unique and allowing each ticket to be connected to an individual artwork or likewise to incentivize purchasing VIP tickets instead. -Additionally, this standard can be used to create, among others, vouchers, gift cards, and scratchcards. +Additionally, these tokens can be used to create, among others, vouchers, gift cards, and scratchcards. ## Specification The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -**Every ERC-4365 compliant smart contract MUST implement the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** +**Every smart contract compliant with this ERC MUST implement the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity interface IERC4365 is IERC165 { @@ -123,7 +123,7 @@ interface IERC4365 is IERC165 { } ``` -In addition, in order for a contract to be compliant with ERC-4365, it MUST abide by the following: +In addition, in order for a contract to be compliant with this ERC, it MUST abide by the following: - Implementers MAY enable token transfers to support functionality such as ticket reselling. - Implementers MUST NOT allow tokens to be transferred between addresses after they have been redeemed. @@ -134,7 +134,7 @@ In addition, in order for a contract to be compliant with ERC-4365, it MUST abid **Smart contracts MUST implement all of the functions in the `ERC4365Receiver` interface to accept tokens being minted to them.** -The **URI Storage extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique URI for each token ID. +The **URI Storage extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique URI for each token ID. ```solidity interface IERC4365URIStorage is IERC4365 { @@ -150,7 +150,7 @@ interface IERC4365URIStorage is IERC4365 { } ``` -The **Expirable extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: +The **Expirable extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: - Implementers MUST NOT allow tokens to be minted or redeemed if expired. @@ -179,7 +179,7 @@ interface IERC4365Expirable is IERC4365 { } ``` -The **Supply extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: +The **Supply extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: - Implementers SHOULD NOT allow tokens to be minted if total supply exceeds max supply. - Implementers SHOULD increment total supply upon minting and decrement upon burning. @@ -204,7 +204,7 @@ interface IERC4365Payable is IERC4365 { } ``` -The **Payable extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: +The **Payable extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: - Implementers SHOULD require recipients to provide funding equal to the token price. @@ -237,63 +237,13 @@ interface IERC4365Supply is IERC4365 { } ``` -The **Badge extension** is OPTIONAL for ERC-4365 smart contracts. This allows contracts to associate multiple different unique ERC-1238 Badges for each token ID. Smart contracts implementing the `ERC4365adge` extension MUST abide by the following: - -- Implementers are RECOMMENDED to implement a `data` field of data type `bytes` in the Badge struct as a general-purpose field with no specified format. - -```solidity -interface IERC4365Badge is IERC4365 { - /** - * @dev Adds an ERC-1238 token reference `badge_` with id `badgeId` for the token of token type `id`. - * - * Requirements: - * - `badge_.contract_` must implement the IERC1238 interface. - */ - function addBadge(uint256 tokenId, uint256 badgeId, Badge memory badge_) external; - - /** - * @dev [Batched] version of {addBadge}. - */ - function addBadgesBatch(uint256 tokenId, uint256[] memory badgeIds, Badge[] memory badges) external; - - /** - * @dev Returns the ERC-1238 token reference data with id `badgeId` for token of token type `tokenId`. - */ - function badge(uint256 tokenId, uint256 badgeId) external view returns (Badge memory); - - /** - * @dev Returns all ERC-1238 token reference data set for token of token type `id`. - */ - function allBadges(uint256 id) external view returns (Badge[] memory); - - /** - * @dev Returns the balance of ERC-1238 tokens owned by `account` added to token type `tokenId` - * by using the reference data in `badgeId`. - * - * Requirements: - * - `account` cannot be the zero address. - */ - function balanceOfBadge(address account, uint256 tokenId, uint256 badgeId) external view returns (uint256); - - /** - * @dev Returns the balance of all ERC-1238 tokens owned by `account` added to token type `tokenId`. - */ - function balanceOfAllBadges(address account, uint256 id) external view returns (uint256[] memory); - - /** - * @dev [Batched] version of {balanceOfAllbadges}. - */ - function balanceOfAllBadgesBatch(address account, uint256[] memory ids) external view returns (uint256[][] memory); -} -``` - ## Rationale ### Overview -The proposed interface and implementation draw heavy inspiration from the ERC-1155 Multi-Token Standard which paved the way for managing multiple token types in the same smart contract reducing gas costs. It draws from the lessons and prior discussions which emerged from the standard and therefore inherits from its design and structure. +The proposed interface and implementation draw heavy inspiration from ERC-1155 which paved the way for managing multiple token types in the same smart contract reducing gas costs. It draws from the lessons and prior discussions which emerged from the standard and therefore inherits from its design and structure. -ERC-1155 presents multiple interesting features also applicable to ERC-4365 tokens: +ERC-1155 presents multiple interesting features also applicable to redeemable tokens: - Because one contract is able to hold multiple different token types, there is no need to deploy multiple contracts for each collection as with previous standards. This saves on deployment gas costs as well as reduces redundant bytecode on the Ethereum blockchain. - ERC-1155 is fungibility-agnostic which means the same contract can manage both fungible and non-fungible token types. @@ -305,33 +255,21 @@ This standard does not assume who has the power to mint/burn tokens nor under wh ### Fungibility -This standard, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. +This ERC, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. -One way to achieve non-fungible tokens is to utilize split ID bits reserving the top 128 bits of the 256 bits `id` parameter to represent the base token ID while using the bottom 128 bits to represent the index of the non-fungible to make it unique. For more information, reference the [EIP-1155 documentation](https://eips.ethereum.org/EIPS/eip-1155). +One way to achieve non-fungible tokens is to utilize split ID bits reserving the top 128 bits of the 256 bits `id` parameter to represent the base token ID while using the bottom 128 bits to represent the index of the non-fungible to make it unique. Alternatively, a more intuitive approach to represent non-fungible tokens is to allow a maximum value of 1 for each. This would reflect the real world, where unique items have a quantity of 1 and fungible items have a quantity greater than 1. ### Batch Operations -ERC-1155, likewise ERC-4365, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. +ERC-1155, likewise this ERC, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. -However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this standard support, introduced by the ERC-1238 standard, bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. +However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this ERC support bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. ### Transfer -This standard does not enforce transferability between addresses except for minting and burning. However, it recognizes the possible need for it when for example implementing resell functionality and, therefore, does not prevent it. - -### Badge - -This extension enables the possibility to associate redeemable tokens with ERC-1238 tokens (badges) by storing one or more references to contracts implementing the `ERC1238` interface. - -The `balanceOfBadge`, `balanceOfAllBadges`, and `balanceOfAllBadgesBatch` functions simply query the specified ERC-1238 contract for the balance of tokens with the given ID. - -This allows implementers to easily add access control limiting certain actions to addresses possessing pre-specified ERC-1238 badges. One use-case is to limit which addresses are able to mint (purchase) redeemable tokens. Additionally, addresses holding a particular badge may receive discounts when minting tokens. - -On top of this, implementers are RECOMMENDED to implement a `bytes` field in the Badge struct called `data`. This is to, optionally, associate data with each separate non-transferable token. For example, the balance of a badge required to mint a redeemable token. It could also be used to specify badges with different use cases within the contract, such as required (badges required to mint) and discount (badges that give a discount when minting). - -The `data` field can be split reserving the first 2 bits to store the required value/discount amount and the following two bits to specify one of four different types. Note that these numbers and use cases are examples and implementers MAY store whichever data they see useful for their needs. +This ERC does not enforce transferability between addresses except for minting and burning. However, it recognizes the possible need for it when for example implementing resell functionality and, therefore, does not prevent it. ### Redeem @@ -339,17 +277,15 @@ The core addition to redeemable tokens is the possibility to redeem tokens in ex ### Safe Mint Only -This standard takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. +This ERC takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. ## Backwards Compatibility -Because of the heavy inspiration from the ERC-1155 standard many concepts and methods remain identical, namely the concept of a batch, the `balanceOf` and `balanceOfBatch` functions, and to some extent the extensions for URI storage and supply. - -ERC-4365 also takes inspiration from ERC-1238 and implements the idea of a bundle, specifically is the `balanceOfBundle` function identical. The `ERC4365Expirable` extension together with the `MintSingle` and `MintBatch` events are identical to their ERC-1238 counterparts. +Because of the heavy inspiration from the ERC-1155 standard many concepts and methods remain identical, namely the concept of a batch, the `balanceOf` and `balanceOfBatch` functions, and to some extent the URI Storage and Supply extensions. ## Reference Implementation -- https://github.com/LucazFFz/ERC4365-token +* [Reference implementation](../assets/eip-4365/) ## Security Considerations @@ -357,4 +293,4 @@ Needs discussion. ## Copyright -Copyright and related rights waived via [CC0](../LICENSE.md). +Copyright and related rights waived via [CC0](../LICENSE.md). \ No newline at end of file diff --git a/assets/eip-4365/.gitignore b/assets/eip-4365/.gitignore new file mode 100644 index 0000000000000..e0f3d0b9ceb50 --- /dev/null +++ b/assets/eip-4365/.gitignore @@ -0,0 +1,2 @@ +# directories +build/* \ No newline at end of file diff --git a/assets/eip-4365/README.md b/assets/eip-4365/README.md new file mode 100644 index 0000000000000..d5cbddf175f49 --- /dev/null +++ b/assets/eip-4365/README.md @@ -0,0 +1,95 @@ +# [ERC4365] Redeemable Tokens (Tickets) Reference Implementation + +## Core + +{{IERC4365}} +{{ERC4365}} +{{IERC4365Receiver}} + +## Extensions + +{{ERC4365Expirable}} +{{ERC4365Payable}} +{{ERC4365Supply}} +{{ERC4365URIStorage}} +{{IERC4365Expirable}} +{{IERC4365Payable}} +{{IERC4365Supply}} + +## Usage + +### Prerequisites + +To run this code you first need to install Truffle via npm (node package manager). If you do not already have npm installed, +you can install it [here](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm). + +To install Truffle, run: + +```sh +npm install -g truffle +``` + +If you want to use Ganache to host a personal blockchain, download it [here](https://trufflesuite.com/ganache/). + +### Compile + +If you want to compile, simply run: + +```sh +truffle compile +``` + +### Test + +To run all tests, simply run: + +```sh +truffle test +``` + +You can also run each test individually by calling: + +```sh +truffle test {test-location} +``` + +### Deploy + +To deploy the `Ticket.sol` example smart contract, you need to connect to a blockchain. Truffle has a built-in personal blockchain used for testing. Altertently, if you installed +Ganache, you can use that. + +If you want to use Truffles built-in blockchain, run: + +```sh +truffle develop +``` + +If you want to use Ganache, run: + +```sh +truffle deploy +``` + +However, dont forget to link Ganache to the project (tutorial [here](https://trufflesuite.com/docs/ganache/how-to/link-a-truffle-project/)), alternatively create a Ganache quickstart workspace and match the server host and port in `truffle-config.js`. + +## Syntax Highlighting + +If you use VSCode, you can enjoy syntax highlighting for your Solidity code ia the [vscode-solidity](https://github.com/juanfranblanco/vscode-solidity) extension. It is also +available via the VSCode extensions marketplace. The recommended approach to set the compiler version is to add the following fields to your VSCode user settings: + +```json +{ + "solidity.compileUsingRemoteVersion": "v0.8.4+commit.c7e474f2", + "solidity.defaultCompiler": "remote" +} +``` + +Where `v0.8.4+commit.c7e474f2` can be replaced by any other version. + +## Todo + +- [ ] Add tests + +## Credits + +- EIP inspirations: [EIP-1155: Multi Token Standard](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) diff --git a/assets/eip-4365/contracts/.gitkeep b/assets/eip-4365/contracts/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/assets/eip-4365/contracts/Migrations.sol b/assets/eip-4365/contracts/Migrations.sol new file mode 100644 index 0000000000000..cd412571085ab --- /dev/null +++ b/assets/eip-4365/contracts/Migrations.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract Migrations { + address public owner; + uint256 public last_completed_migration; + + modifier restricted() { + if (msg.sender == owner) _; + } + + constructor() { + owner = msg.sender; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } + + function upgrade(address new_address) public restricted { + Migrations upgraded = Migrations(new_address); + upgraded.setCompleted(last_completed_migration); + } +} diff --git a/assets/eip-4365/contracts/examples/Ticket.sol b/assets/eip-4365/contracts/examples/Ticket.sol new file mode 100644 index 0000000000000..bc574d906eda5 --- /dev/null +++ b/assets/eip-4365/contracts/examples/Ticket.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../token/ERC4365/IERC4365.sol"; +import "../token/ERC4365/extensions/ERC4365Expirable.sol"; + +contract Ticket is ERC4365, ERC4365Expirable { + using Address for address; + + address public owner; + + constructor(address owner_, string memory baseURI_) ERC4365(baseURI_) { + owner = owner_; + } + + modifier onlyOwner() { + require(msg.sender == owner, "Unauthorized: sender is not the owner"); + _; + } + + function transferOwnership(address newOwner) external onlyOwner { + require(newOwner != address(0), "Invalid address for new owner"); + owner = newOwner; + } + + function setBaseURI(string calldata newBaseURI) external onlyOwner { + _setBaseURI(newBaseURI); + } + + function mint(address to, uint256 id, uint256 amount, bytes calldata data) external onlyOwner { + _mint(to, id, amount, data); + } + + function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes calldata data) + external + onlyOwner + { + _mintBatch(to, ids, amounts, data); + } + + function burn(address from, uint256 id, uint256 amount) external { + require(msg.sender == from || msg.sender == owner, "Sender is not token holder or contract owner"); + + _burn(from, id, amount); + } + + function burnBatch(address from, uint256[] memory ids, uint256[] memory amounts) external { + require(msg.sender == from || msg.sender == owner, "Sender is not token holder or contract owner"); + + _burnBatch(from, ids, amounts); + } + + function _setExpiryDate(uint256 id, uint256 date) internal override onlyOwner { + super._setExpiryDate(id, date); + } +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol b/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol new file mode 100644 index 0000000000000..bd21e9c3c0311 --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/Address.sol"; +import "../../utils/Context.sol"; +import "./IERC4365Receiver.sol"; +import "../../utils/introspection/ERC165.sol"; +import "./IERC4365.sol"; + +/** + * @dev Implementation proposal for redeemable tokens (tickets). + */ +contract ERC4365 is Context, ERC165, IERC4365 { + using Address for address; + + // Mapping from token ID to account balances. id => (account => balance) + mapping(uint256 => mapping(address => uint256)) private _balances; + + // Mapping from token ID to account balance of redeemed tokens. id => (account => redeemed) + mapping(uint256 => mapping(address => uint256)) private _redeemed; + + // Used as the URI for all token types by relying on ID substitution, + // e.g. https://token-cdn-domain/{id}.json. + string private _baseURI; + + /** + * @dev See {_setBaseURI}. + */ + constructor(string memory baseURI_) { + _setBaseURI(baseURI_); + } + + /** + * @dev See {IERC4365-redeem}. + */ + function redeem( + address account, + uint256 id, + uint256 amount, + bytes memory data + ) external virtual { + require(_balances[id][account] >= _redeemed[id][account] + amount, + "ERC4365: redeem amount exceeds balance"); + + _beforeRedeem(account, id, amount, data); + + _redeemed[id][account] += amount; + emit Redeem(account, id, amount); + } + + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { + return interfaceId == type(IERC4365).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev This implementation retuns the same URI for *all* token types. It relies + * on the token type ID substitution mechanism as in EIP-1155: + * https://eips.ethereum.org/EIPS/eip-1155#metadata + * + * Clients calling this function must replace the `\{id\}` substring with the + * actual token type ID. + */ + function baseURI() public view virtual returns (string memory) { + return _baseURI; + } + + /** + * @dev See {IERC-4365-balanceOf}. + */ + function balanceOf(address account, uint256 id) public view virtual returns (uint256) { + require(account != address(0), "ERC4365: address zero is not a valid owner"); + return _balances[id][account]; + } + + /** + * @dev See {IERC4365-balanceOfBatch}. + */ + function balanceOfBatch(address account, uint256[] memory ids) + public + view + virtual + returns (uint256[] memory) + { + uint256 idsLength = ids.length; + uint256[] memory batchBalances = new uint256[](idsLength); + + for (uint256 i = 0; i < idsLength; ++i) { + batchBalances[i] = balanceOf(account, ids[i]); + } + + return batchBalances; + } + + /** + * @dev See {IERC4365-balanceOfBundle}. + */ + function balanceOfBundle(address[] memory accounts, uint256[][] memory ids) + public + view + virtual + returns (uint256[][] memory) + { + uint256 accountsLength = accounts.length; + uint256[][] memory bundleBalances = new uint256[][](accountsLength); + + for (uint256 i = 0; i < accountsLength; ++i) { + bundleBalances[i] = balanceOfBatch(accounts[i], ids[i]); + } + + return bundleBalances; + } + + /** + * @dev See {IERC4365-balanceOfRedeemed}. + */ + function balanceOfRedeemed(address account, uint256 id) public view virtual returns (uint256) { + require(account != address(0), "ERC4365: address zero is not a valid owner"); + return _redeemed[id][account]; + } + + /** + * @dev See {IERC4365-balanceOfRedeemedBatch}. + */ + function balanceOfRedeemedBatch(address account, uint256[] memory ids) + public + view + virtual + returns(uint256[] memory) + { + uint256 idsLength = ids.length; + uint256[] memory batchRedeemed = new uint256[](idsLength); + + for (uint256 i = 0; i < idsLength; ++i) { + batchRedeemed[i] = balanceOfRedeemed(account, ids[i]); + } + + return batchRedeemed; + } + + /** + * @dev See {IERC4365-balanceOfRedeemedBundle}. + */ + function balanceOfRedeemedBundle(address[] memory accounts, uint256[][] memory ids) + public + view + virtual + returns (uint256[][] memory) + { + uint256 accountsLength = accounts.length; + uint256[][] memory bundleRedeemed = new uint256[][](accountsLength); + + for (uint256 i = 0; i < accountsLength; ++i) { + bundleRedeemed[i] = balanceOfRedeemedBatch(accounts[i], ids[i]); + } + + return bundleRedeemed; + } + + /** + * @dev Sets a new URI for all token types, by relying on the token type ID + * substitution mechanism as in EIP-1155 + * https://eips.ethereum.org/EIPS/eip-1155#metadata + * + * By this mechanism, any occurrence of the `\{id\}` substring in either the + * URI or any of the amounts in the JSON file at said URI will be replaced by + * clients with the token type ID. + * + * For example, the `https://token-cdn-domain/\{id\}.json` URI would be + * interpreted by clients as + * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json` + * for token type ID 0x4cce0. + * + * + * Because these URIs cannot be meaningfully represented by the {URI} event, + * this function emits no events. + */ + function _setBaseURI(string memory newBaseURI) internal virtual { + _baseURI = newBaseURI; + } + + /** + * @dev Creates `amount` tokens of token type `id` and assigns them to `to`. + * + * Emits a {MintSingle} event. + * + * Requirements: + * - `to` cannot be the zero address. + * - If `to` refers to a smart contract, it must implement [IERC4365REceiver-onERC4365Received] and + * return the acceptance magic value. + */ + function _mint( + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + + address minter = _msgSender(); + + _beforeMint(minter, to, id, amount, data); + + _balances[id][to] += amount; + emit MintSingle(minter, to, id, amount); + + _doSafeMintAcceptanceCheck(minter, to, id, amount, data); + } + + /** + * @dev [Batched] version of {_mint}. A batch specifies an array of token `id` and + * the amount of token for each. + * + * Emits a {MintBatch} event. + * + * Requirements: + * - `ids` and `amounts` must have the same length. + * - If `to` refers to a smart contract, it must implement [IERC4365REceiver-onERC4365BatchReceived] and + * return the acceptance magic value. + */ + function _mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) internal virtual { + require(to != address(0), "ERC1155: mint to the zero address"); + require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); + + address minter = _msgSender(); + + for (uint256 i = 0; i < ids.length; i++) { + _beforeMint(minter, to, ids[i], amounts[i], data); + + _balances[ids[i]][to] += amounts[i]; + } + + emit MintBatch(minter, to, ids, amounts); + + _doSafeBatchMintAcceptanceCheck(minter, to, ids, amounts, data); + } + + /** + * @dev [Bundled] version of {_mint}. A bundle can be views as minting several batches + * to an array of addresses in one transaction. + * + * Emits multiple {MintBatch} events. + */ + function _mintBundle( + address[] calldata to, + uint256[][] calldata ids, + uint256[][] calldata amounts, + bytes[] calldata data + ) internal virtual { + uint256 toLength = to.length; + for (uint256 i = 0; i < toLength; i++) { + _mintBatch(to[i], ids[i], amounts[i], data[i]); + } + } + + /** + * @dev Destroys `amount` tokens of token type `id` from `from`. + * + * Emits a {BurnSingle} event. + * + * Requirements: + * - `from` cannot be the zero address. + * - `from` must have at least `amount` tokens of token type `id`. + */ + function _burn( + address from, + uint256 id, + uint256 amount + ) internal virtual { + require(from != address(0), "ERC4365: burn from the zero address"); + + address burner = _msgSender(); + + _beforeBurn(burner, from, id, amount); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC4365: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + + emit BurnSingle(burner, from, id, amount); + } + + /** + * [Batched] version of {_burn}. + * + * Emits a {BurnBatch} event. + * + * Requirements: + * - `ids` and `amouts` ust have the same length. + */ + function _burnBatch( + address from, + uint256[] memory ids, + uint256[] memory amounts + ) internal virtual { + require(from != address(0), "ERC4365: burn from the zero address"); + require(ids.length == amounts.length, "ERC4365: ids and amounts length mismatch"); + + address burner = _msgSender(); + + for (uint256 i = 0; i < ids.length; i++) { + uint256 id = ids[i]; + uint256 amount = amounts[i]; + + _beforeBurn(burner, from, ids[i], amounts[i]); + + uint256 fromBalance = _balances[id][from]; + require(fromBalance >= amount, "ERC4365: burn amount exceeds balance"); + unchecked { + _balances[id][from] = fromBalance - amount; + } + } + + emit BurnBatch(burner, from, ids, amounts); + } + + /** + * @dev Hook that is called before an `amount` of tokens are minted. + * + * The same hook is called on both sinle + * + * Calling conditions: + * - `minter` and `to` cannot be the zero address. + */ + function _beforeMint( + address minter, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual {} + + /** + * @dev Hook that is called before an `amount` of tokens are burned. + * + * Calling conditions: + * - `minter` and `from` cannot be the zero address. + */ + function _beforeBurn( + address burner, + address from, + uint256 id, + uint256 amount + ) internal virtual {} + + /** + * @dev Hook that is called before an `amount` of tokens are redeemed. + * + * Calling conditions: + * - `account` cannot be the zero address. + */ + function _beforeRedeem( + address account, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual {} + + + function _doSafeMintAcceptanceCheck( + address minter, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) private { + if (to.isContract()) { + try IERC4365Receiver(to).onERC4365Mint(minter, id, amount, data) returns (bytes4 response) { + if (response != IERC4365Receiver.onERC4365Mint.selector) { + revert("ERC4365: ERC4365Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC4365: mint to non-ERC4365Receiver implementer"); + } + } + } + + function _doSafeBatchMintAcceptanceCheck( + address minter, + address to, + uint256[] memory ids, + uint256[] memory amounts, + bytes memory data + ) private { + if (to.isContract()) { + try IERC4365Receiver(to).onERC4365BatchMint(minter, ids, amounts, data) returns ( + bytes4 response + ) { + if (response != IERC4365Receiver.onERC4365BatchMint.selector) { + + revert("ERC4365: ERC4365Receiver rejected tokens"); + } + } catch Error(string memory reason) { + revert(reason); + } catch { + revert("ERC4365: mint to non-ERC4365Receiver implementer"); + } + } + } +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol b/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol new file mode 100644 index 0000000000000..5ecbb18a580c3 --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * @dev Interface proposal for Redeemable tokens. + * Note: The ERC-165 identifier for this interface is 0x9d1da9d1. + */ +interface IERC4365 is IERC165 { + /** + * @dev Emitted when `amount` tokens of token type `id` are minted to `to` by `minter`. + */ + event MintSingle(address indexed minter, address indexed to, uint256 indexed id, uint256 amount); + + /** + * @dev Equivalent to multiple {MintSingle} events, where `minter` and `to` is the same for all token types. + */ + event MintBatch(address indexed minter, address indexed to, uint256[] ids, uint256[] amounts); + + /** + * @dev Emitted when `amount` tokens of token type `id` owned by `owner` are burned by `burner`. + */ + event BurnSingle(address indexed burner, address indexed owner, uint256 indexed id, uint256 amount); + + /** + * @dev Equivalent to multiple {BurnSingle} events, where `owner` and `burner` is the same for all token types. + */ + event BurnBatch(address indexed burner, address indexed owner, uint256[] ids, uint256[] amounts); + + /** + * @dev Emitted when `amount` of tokens of token type `id` are redeemed in `account`. + */ + event Redeem(address indexed account, uint256 indexed id, uint256 amount); + + /** + * @dev Returns the balance of tokens of token type `id` owned by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + */ + function balanceOf(address account, uint256 id) external view returns (uint256); + + /** + * @dev Returns the balance of `account` for a batch of token `ids`. + */ + function balanceOfBatch(address account, uint256[] calldata ids) external view returns (uint256[] memory); + + /** + * @dev Returns the balance of multiple `accounts` for a batch of token `ids`. + * This is equivalent to calling {balanceOfBatch} for several accounts in just one call. + * + * Requirements: + * - `accounts` and `ids` must have the same length. + */ + function balanceOfBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view + returns (uint256[][] memory); + + /** + * @dev Returns the balance of tokens of token type `id` redeemed by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + */ + function balanceOfRedeemed(address account, uint256 id) external view returns (uint256); + + /** + * @dev Returns the balance of `account` for a batch of redeemed token `ids`. + */ + function balanceOfRedeemedBatch(address account, uint256[] calldata ids) external view returns (uint256[] memory); + + /** + * @dev Returns the balance of multiple `accounts` for a batch of redeemed token `ids`. + * This is equivalent to calling {balanceOfRedeemedBatch} for several accounts in just one call. + * + * Requirements: + * - `accounts` and `ids` must have the same length. + */ + function balanceOfRedeemedBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view + returns (uint256[][] memory); + + /** + * Redeem `amount` of token type `id` owned by `account`. + * + * Requirements: + * - `account` cannot be the zero address. + * - `amount` together with `account` balance of redeemed token of token type `id` + * cannot exceed `account` balance of token type `id`. + */ + function redeem (address account, uint256 id, uint256 amount, bytes memory data) external; +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol b/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol new file mode 100644 index 0000000000000..0ee3ebd32ab6e --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../../utils/introspection/IERC165.sol"; + +/** + * Interface for smart contracts wishing to receive ownership of ERC4365 tokens. + */ +interface IERC4365Receiver is IERC165 { + /** + * @dev Handles the receipt of a single ERC4365 token type. + * + * NOTE: To accept the transfer, this must return + * `bytes4(keccak256("onERC4365Mint(address,address,uint256,uint256,bytes)"))`. + * + * @param minter The address which initiated minting (i.e. msg.sender). + * @param id The ID of the token being transferred. + * @param amount The amount of tokens being transferred. + * @param data Additional data with no specified format. + * @return `bytes4(keccak256("onERC4365Mint(address,uint256,uint256,bytes)"))` if minting is allowed. + */ + function onERC4365Mint( + address minter, + uint256 id, + uint256 amount, + bytes calldata data + ) external returns (bytes4); + + /** + * @dev Handles the receipt of multiple ERC4365 token types. + * + * NOTE: To accept the transfer(s), this must return + * `bytes4(keccak256("onERC4365BatchMint(address,address,uint256[],uint256[],bytes)"))`. + * + * @param minter The address which initiated minting (i.e. msg.sender). + * @param ids An array containing ids of each token being transferred (order and length must match values array). + * @param amounts An array containing amounts of each token being transferred (order and length must match ids array). + * @param data Additional data with no specified format. + * @return `bytes4(keccak256("onERC4365BatchMint(address,uint256[],uint256[],bytes)"))` if minting is allowed. + */ + function onERC4365BatchMint( + address minter, + uint256[] calldata ids, + uint256[] calldata amounts, + bytes calldata data + ) external returns (bytes4); +} + + diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol new file mode 100644 index 0000000000000..c5a42a3dcb80d --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "./IERC4365Expirable.sol"; +import "../ERC4365.sol"; + +/** + * @dev See {IERC1238Expirable}. + */ +abstract contract ERC4365Expirable is ERC4365 { + // Optional mapping for token expiry date. + mapping(uint256 => uint256) private _expiryDate; + + /** + * @dev Publicly expose {_setExpiryDate}. + */ + function setExpiryDate(uint256 id, uint256 date) external { + _setExpiryDate(id, date); + } + + /** + * @dev Publicly expose {_setBatchExpiryDates}. + */ + function setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) external { + _setBatchExpiryDates(ids, dates); + } + + /** + * @dev See {IERC1238Expirable-expiryDate}. + */ + function expiryDate(uint256 id) public view virtual returns (uint256) { + uint256 date = _expiryDate[id]; + + require(date != 0, "ERC4365Expirable: no expiry date set"); + + return date; + } + + /** + * @dev See {IERC1238Expirable-isExpired}. + */ + function isExpired(uint256 id) public view virtual returns (bool) { + uint256 date = _expiryDate[id]; + + require(date != 0, "ERC4365Expirable: no expiry date set"); + + return date < block.timestamp; + } + + /** + * @dev Sets the expiry date for the tokens with id `id`. + * + * Requirements: + * - The new date must be after the current expiry date. + */ + function _setExpiryDate(uint256 id, uint256 date) internal virtual { + require(date > block.timestamp, "ERC4365Expirable: expiry date cannot be in the past"); + require(date > _expiryDate[id], "ERC4365Expirable: expiry date can only be extended"); + + _expiryDate[id] = date; + } + + /** + * @dev [Batched] version of {_setExpiryDate}. + */ + function _setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) internal { + require(ids.length == dates.length, "ERC4365Expirable: ids and token URIs length mismatch"); + + for (uint256 i = 0; i < ids.length; i++) { + _setExpiryDate(ids[i], dates[i]); + } + } +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol new file mode 100644 index 0000000000000..c76c06b8cf51c --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC4365Payable.sol"; +import "../ERC4365.sol"; + +/** + * @dev See {IERC4365Payable}. + */ +abstract contract ERC4365Payable is ERC4365 { + // Optional mapping for token price. + mapping(uint256 => uint256) private _price; + + /** + * @dev Pubicly Exposes {_setPrice}. + */ + function setPrice(uint256 id, uint256 amount) external { + _setPrice(id, amount); + } + + /** + * @dev Pubicly Exposes {_setBatchPrices}. + */ + function setBatchPrices(uint256[] memory ids, uint256[] memory amounts) external { + _setBatchPrices(ids, amounts); + } + + /** + * @dev See {IERC4365Payable-price}. + */ + function price(uint256 id) public view virtual returns (uint256) { + uint256 amount = _price[id]; + require(amount != 0, "ERC4365Pay: no price set"); + return amount; + } + + /** + * @dev Sets the price for the tokens of token type `id`. + */ + function _setPrice(uint256 id, uint256 amount) internal virtual { + _price[id] = amount; + } + + /** + * @dev [Batched] version of {_setPrice}. + */ + function _setBatchPrices(uint256[] memory ids, uint256[] memory amounts) internal { + require(ids.length == amounts.length, "ERC4365Supply: ids and amounts length mismatch"); + + for (uint256 i = 0; i < ids.length; i++) { + _setPrice(ids[i], amounts[i]); + } + } +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol new file mode 100644 index 0000000000000..efda6c87dda8b --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "./IERC4365Supply.sol"; +import "../ERC4365.sol"; + +/** + * @dev See {IERC4365Supply}. + */ +abstract contract ERC4365Supply is ERC4365 { + // Mapping from token ID to total supply. + mapping(uint256 => uint256) private _totalSupply; + + // Mapping from token ID to max supply. + mapping(uint256 => uint256) private _maxSupply; + + /** + * @dev Pubicly exposes {_setMaxSupply}. + */ + function setMaxSupply(uint256 id, uint256 amount) external { + _setMaxSupply(id, amount); + } + + /** + * @dev Pubicly exposes {_setBatchMaxSupplies}. + */ + function setBatchMaxSupplies(uint256[] memory ids, uint256[] memory amounts) external { + _setBatchMaxSupplies(ids, amounts); + } + + /** + * @dev See {IERC4365Supply-totalSupply}. + */ + function totalSupply(uint256 id) public view virtual returns (uint256) { + return _totalSupply[id]; + } + + /** + * @dev See {IERC4365Supply-maxSupply}. + */ + function maxSupply(uint256 id) public view virtual returns (uint256) { + uint256 max = _maxSupply[id]; + require(max != 0, "ERC4365Supply: no maxSupply set"); + return max; + } + + /** + * @dev See {IERC4365Supply-exists}. + */ + function exists(uint256 id) public view virtual returns (bool) { + return ERC4365Supply.totalSupply(id) > 0; + } + + /** + * @dev Sets the max supply for the token of token type `id`. + */ + function _setMaxSupply(uint256 id, uint256 amount) internal virtual { + _maxSupply[id] = amount; + } + + /** + * @dev [Batched] version of {setMaxSupply}. + */ + function _setBatchMaxSupplies(uint256[] memory ids, uint256[] memory amounts) internal { + require(ids.length == amounts.length, "ERC4365Supply: ids and amounts length mismatch"); + + for (uint256 i = 0; i < ids.length; i++) { + _setMaxSupply(ids[i], amounts[i]); + } + } + + /** + * @dev See {ERC4365-_beforeMint}. + */ + function _beforeMint( + address minter, + address to, + uint256 id, + uint256 amount, + bytes memory data + ) internal virtual override { + super._beforeMint(minter, to, id, amount, data); + + _totalSupply[id] += amount; + } + + /** + * @dev See {ERC4365-_beforeBurn. + */ + function _beforeBurn( + address burner, + address from, + uint256 id, + uint256 amount + ) internal virtual override { + super._beforeBurn(burner, from, id, amount); + + require(_totalSupply[id] >= amount, "ERC4365: burn amount exceeds totalSupply"); + unchecked { + _totalSupply[id] -= amount; + } + } +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol new file mode 100644 index 0000000000000..c6804032a6a0f --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import "../ERC4365.sol"; +import "../../../utils/introspection/ERC165.sol"; +import "./IERC4365URIStorage.sol"; + +/** + * @dev See {IERC4365URIStorage}. + */ +abstract contract ERC4365URIStorage is ERC165, IERC4365URIStorage, ERC4365 { + // Optional mapping for token URIs. + mapping(uint256 => string) private _tokenURIs; + + function supportsInterface(bytes4 interfaceId) + public + view + virtual + override(ERC4365, ERC165, IERC165) + returns (bool) + { + return interfaceId == type(IERC4365URIStorage).interfaceId || super.supportsInterface(interfaceId); + } + + /** + * @dev See {IERC4365URIStorage-tokenURI}. + */ + function tokenURI(uint256 id) public view virtual override returns (string memory) { + string memory _tokenURI = _tokenURIs[id]; + + // Returns the token URI if there is a specific one set that overrides the base URI + if (_isTokenURISet(id)) { + return _tokenURI; + } + + string memory base = baseURI(); + + return base; + } + + /** + * @dev Sets `_tokenURI` as the token URI for the tokens of type `id`. + */ + function _setTokenURI(uint256 id, string memory _tokenURI) internal virtual { + _tokenURIs[id] = _tokenURI; + + emit URI(id, _tokenURI); + } + + /** + * @dev [Batched] version of {_setTokenURI}. + */ + function _setBatchTokenURI(uint256[] memory ids, string[] memory tokenURIs) internal { + uint256 idsLength = ids.length; + require(idsLength == tokenURIs.length, "ERC1238Storage: ids and token URIs length mismatch"); + + for (uint256 i = 0; i < idsLength; i++) { + _setTokenURI(ids[i], tokenURIs[i]); + } + } + + /** + * @dev Deletes the tokenURI for the tokens of type `id`. + * + * Requirements: + * - A token URI must be set. + * + * Possible improvement: + * - The URI can only be deleted if all tokens of type `id` have been burned. + */ + function _deleteTokenURI(uint256 id) internal virtual { + if (_isTokenURISet(id)) { + delete _tokenURIs[id]; + } + } + + /** + * @dev Returns whether a tokenURI is set or not for a specific `id` token type. + */ + function _isTokenURISet(uint256 id) private view returns (bool) { + return bytes(_tokenURIs[id]).length > 0; + } +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol new file mode 100644 index 0000000000000..0f034e0a6bc5e --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../IERC4365.sol"; + +/** + * @dev Proposal of an interface for ERC-4365 tokens with an expiry date. + * NOTE: The dates are stored as unix timestamps in seconds. + */ +interface IERC4365Expirable is IERC4365 { + /** + * @dev Sets the expiry date for the token of token type `id`. + */ + function setExpiryDate(uint256 id, uint256 date) external; + + /** + * @dev [Batched] version of {setExpiryDate}. + */ + function setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) external; + + /** + * @dev Returns the expiry date for the token of token type `id`. + */ + function expiryDate(uint256 id) external view returns (uint256); + + /** + * @dev Returns `true` or `false` depending on if the token of token type `id` has expired + * by comparing the expiry date with `block.timestamp`. + */ + function isExpired(uint256 id) external view returns (bool); +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol new file mode 100644 index 0000000000000..ed223b0d9ae8f --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../IERC4365.sol"; + +/** + * @dev Proposal of an interface for ERC-4365 tokens with a price. + */ +interface IERC4365Payable is IERC4365 { + /** + * @dev Sets the price `amount` for the token of token type `id`. + */ + function setPrice(uint256 id, uint256 amount) external; + + /** + * @dev [Batched] version of {setPrice}. + */ + function setBatchPrices(uint256[] memory ids, uint256[] memory amounts) external; + + /** + * @dev Returns the price for the token type `id`. + */ + function price(uint256 id) external view returns (uint256); +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol new file mode 100644 index 0000000000000..bdf1e80f2ba94 --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../IERC4365.sol"; + +/** + * @dev Proposal of an interface for ERC-4365 tokens with a max supply. + */ +interface IERC4365Supply is IERC4365 { + /** + * @dev Sets the max supply for the token of token type `id`. + */ + function setMaxSupply(uint256 id, uint256 amount) external; + + /** + * @dev [Batched] version of {setMaxSupply}. + */ + function setBatchMaxSupplies(uint256[] memory ids, uint256[] memory amounts) external; + + /** + * @dev Returns the total supply for token of token type `id`. + */ + function totalSupply(uint256 id) external view returns (uint256); + + /** + * @dev Returns the max supply for token of token type `id`. + */ + function maxSupply(uint256 id) external view returns (uint256); + + /** + * @dev Indicates whether any token of token type `id` exists, or not. + */ + function exists(uint256 id) external view returns (bool); +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol new file mode 100644 index 0000000000000..466292afaba46 --- /dev/null +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "../IERC4365.sol"; +import "../../../utils/introspection/IERC165.sol"; + +/** + * @dev Proposal of an interface for ERC-4365 token with storage based token URI management. + */ +interface IERC4365URIStorage is IERC4365 { + /** + * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. + */ + event URI(uint256 indexed id, string value); + + /** + * @dev Returns the Uniform Resource Identifier (URI) for `id` token. + */ + function tokenURI(uint256 id) external view returns (string memory); +} \ No newline at end of file diff --git a/assets/eip-4365/contracts/utils/Address.sol b/assets/eip-4365/contracts/utils/Address.sol new file mode 100644 index 0000000000000..d440b259eef23 --- /dev/null +++ b/assets/eip-4365/contracts/utils/Address.sol @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) + +pragma solidity ^0.8.1; + +/** + * @dev Collection of functions related to the address type + */ +library Address { + /** + * @dev Returns true if `account` is a contract. + * + * [IMPORTANT] + * ==== + * It is unsafe to assume that an address for which this function returns + * false is an externally-owned account (EOA) and not a contract. + * + * Among others, `isContract` will return false for the following + * types of addresses: + * + * - an externally-owned account + * - a contract in construction + * - an address where a contract will be created + * - an address where a contract lived, but was destroyed + * ==== + * + * [IMPORTANT] + * ==== + * You shouldn't rely on `isContract` to protect against flash loan attacks! + * + * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets + * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract + * constructor. + * ==== + */ + function isContract(address account) internal view returns (bool) { + // This method relies on extcodesize/address.code.length, which returns 0 + // for contracts in construction, since the code is only stored at the end + // of the constructor execution. + + return account.code.length > 0; + } + + /** + * @dev Replacement for Solidity's `transfer`: sends `amount` wei to + * `recipient`, forwarding all available gas and reverting on errors. + * + * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost + * of certain opcodes, possibly making contracts go over the 2300 gas limit + * imposed by `transfer`, making them unable to receive funds via + * `transfer`. {sendValue} removes this limitation. + * + * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. + * + * IMPORTANT: because control is transferred to `recipient`, care must be + * taken to not create reentrancy vulnerabilities. Consider using + * {ReentrancyGuard} or the + * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. + */ + function sendValue(address payable recipient, uint256 amount) internal { + require(address(this).balance >= amount, "Address: insufficient balance"); + + (bool success, ) = recipient.call{value: amount}(""); + require(success, "Address: unable to send value, recipient may have reverted"); + } + + /** + * @dev Performs a Solidity function call using a low level `call`. A + * plain `call` is an unsafe replacement for a function call: use this + * function instead. + * + * If `target` reverts with a revert reason, it is bubbled up by this + * function (like regular Solidity function calls). + * + * Returns the raw returned data. To convert to the expected return value, + * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. + * + * Requirements: + * + * - `target` must be a contract. + * - calling `target` with `data` must not revert. + * + * _Available since v3.1._ + */ + function functionCall(address target, bytes memory data) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, "Address: low-level call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with + * `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, 0, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but also transferring `value` wei to `target`. + * + * Requirements: + * + * - the calling contract must have an ETH balance of at least `value`. + * - the called Solidity function must be `payable`. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value + ) internal returns (bytes memory) { + return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); + } + + /** + * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but + * with `errorMessage` as a fallback revert reason when `target` reverts. + * + * _Available since v3.1._ + */ + function functionCallWithValue( + address target, + bytes memory data, + uint256 value, + string memory errorMessage + ) internal returns (bytes memory) { + require(address(this).balance >= value, "Address: insufficient balance for call"); + (bool success, bytes memory returndata) = target.call{value: value}(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { + return functionStaticCall(target, data, "Address: low-level static call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a static call. + * + * _Available since v3.3._ + */ + function functionStaticCall( + address target, + bytes memory data, + string memory errorMessage + ) internal view returns (bytes memory) { + (bool success, bytes memory returndata) = target.staticcall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { + return functionDelegateCall(target, data, "Address: low-level delegate call failed"); + } + + /** + * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], + * but performing a delegate call. + * + * _Available since v3.4._ + */ + function functionDelegateCall( + address target, + bytes memory data, + string memory errorMessage + ) internal returns (bytes memory) { + (bool success, bytes memory returndata) = target.delegatecall(data); + return verifyCallResultFromTarget(target, success, returndata, errorMessage); + } + + /** + * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling + * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. + * + * _Available since v4.8._ + */ + function verifyCallResultFromTarget( + address target, + bool success, + bytes memory returndata, + string memory errorMessage + ) internal view returns (bytes memory) { + if (success) { + if (returndata.length == 0) { + // only check isContract if the call was successful and the return data is empty + // otherwise we already know that it was a contract + require(isContract(target), "Address: call to non-contract"); + } + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + /** + * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the + * revert reason or using the provided one. + * + * _Available since v4.3._ + */ + function verifyCallResult( + bool success, + bytes memory returndata, + string memory errorMessage + ) internal pure returns (bytes memory) { + if (success) { + return returndata; + } else { + _revert(returndata, errorMessage); + } + } + + function _revert(bytes memory returndata, string memory errorMessage) private pure { + // Look for revert reason and bubble it up if present + if (returndata.length > 0) { + // The easiest way to bubble the revert reason is using memory via assembly + /// @solidity memory-safe-assembly + assembly { + let returndata_size := mload(returndata) + revert(add(32, returndata), returndata_size) + } + } else { + revert(errorMessage); + } + } +} diff --git a/assets/eip-4365/contracts/utils/Context.sol b/assets/eip-4365/contracts/utils/Context.sol new file mode 100644 index 0000000000000..f304065b46068 --- /dev/null +++ b/assets/eip-4365/contracts/utils/Context.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/Context.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Provides information about the current execution context, including the + * sender of the transaction and its data. While these are generally available + * via msg.sender and msg.data, they should not be accessed in such a direct + * manner, since when dealing with meta-transactions the account sending and + * paying for execution may not be the actual sender (as far as an application + * is concerned). + * + * This contract is only required for intermediate, library-like contracts. + */ +abstract contract Context { + function _msgSender() internal view virtual returns (address) { + return msg.sender; + } + + function _msgData() internal view virtual returns (bytes calldata) { + return msg.data; + } +} diff --git a/assets/eip-4365/contracts/utils/Strings.sol b/assets/eip-4365/contracts/utils/Strings.sol new file mode 100644 index 0000000000000..76aa3640af320 --- /dev/null +++ b/assets/eip-4365/contracts/utils/Strings.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol) + +pragma solidity ^0.8.0; + +import "./math/Math.sol"; + +/** + * @dev String operations. + */ +library Strings { + bytes16 private constant _SYMBOLS = "0123456789abcdef"; + uint8 private constant _ADDRESS_LENGTH = 20; + + /** + * @dev Converts a `uint256` to its ASCII `string` decimal representation. + */ + function toString(uint256 value) internal pure returns (string memory) { + unchecked { + uint256 length = Math.log10(value) + 1; + string memory buffer = new string(length); + uint256 ptr; + /// @solidity memory-safe-assembly + assembly { + ptr := add(buffer, add(32, length)) + } + while (true) { + ptr--; + /// @solidity memory-safe-assembly + assembly { + mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) + } + value /= 10; + if (value == 0) break; + } + return buffer; + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. + */ + function toHexString(uint256 value) internal pure returns (string memory) { + unchecked { + return toHexString(value, Math.log256(value) + 1); + } + } + + /** + * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length. + */ + function toHexString(uint256 value, uint256 length) internal pure returns (string memory) { + bytes memory buffer = new bytes(2 * length + 2); + buffer[0] = "0"; + buffer[1] = "x"; + for (uint256 i = 2 * length + 1; i > 1; --i) { + buffer[i] = _SYMBOLS[value & 0xf]; + value >>= 4; + } + require(value == 0, "Strings: hex length insufficient"); + return string(buffer); + } + + /** + * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. + */ + function toHexString(address addr) internal pure returns (string memory) { + return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); + } +} diff --git a/assets/eip-4365/contracts/utils/introspection/ERC165.sol b/assets/eip-4365/contracts/utils/introspection/ERC165.sol new file mode 100644 index 0000000000000..3bf5613a6ccf0 --- /dev/null +++ b/assets/eip-4365/contracts/utils/introspection/ERC165.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) + +pragma solidity ^0.8.0; + +import "./IERC165.sol"; + +/** + * @dev Implementation of the {IERC165} interface. + * + * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check + * for the additional interface id that will be supported. For example: + * + * ```solidity + * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); + * } + * ``` + * + * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. + */ +abstract contract ERC165 is IERC165 { + /** + * @dev See {IERC165-supportsInterface}. + */ + function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { + return interfaceId == type(IERC165).interfaceId; + } +} diff --git a/assets/eip-4365/contracts/utils/introspection/IERC165.sol b/assets/eip-4365/contracts/utils/introspection/IERC165.sol new file mode 100644 index 0000000000000..e8cdbdbf6099b --- /dev/null +++ b/assets/eip-4365/contracts/utils/introspection/IERC165.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/assets/eip-4365/contracts/utils/math/Math.sol b/assets/eip-4365/contracts/utils/math/Math.sol new file mode 100644 index 0000000000000..7848c9203887d --- /dev/null +++ b/assets/eip-4365/contracts/utils/math/Math.sol @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) + +pragma solidity ^0.8.0; + +/** + * @dev Standard math utilities missing in the Solidity language. + */ +library Math { + enum Rounding { + Down, // Toward negative infinity + Up, // Toward infinity + Zero // Toward zero + } + + /** + * @dev Returns the largest of two numbers. + */ + function max(uint256 a, uint256 b) internal pure returns (uint256) { + return a > b ? a : b; + } + + /** + * @dev Returns the smallest of two numbers. + */ + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + /** + * @dev Returns the average of two numbers. The result is rounded towards + * zero. + */ + function average(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b) / 2 can overflow. + return (a & b) + (a ^ b) / 2; + } + + /** + * @dev Returns the ceiling of the division of two numbers. + * + * This differs from standard division with `/` in that it rounds up instead + * of rounding down. + */ + function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { + // (a + b - 1) / b can overflow on addition, so we distribute. + return a == 0 ? 0 : (a - 1) / b + 1; + } + + /** + * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 + * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) + * with further edits by Uniswap Labs also under MIT license. + */ + function mulDiv( + uint256 x, + uint256 y, + uint256 denominator + ) internal pure returns (uint256 result) { + unchecked { + // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use + // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 + // variables such that product = prod1 * 2^256 + prod0. + uint256 prod0; // Least significant 256 bits of the product + uint256 prod1; // Most significant 256 bits of the product + assembly { + let mm := mulmod(x, y, not(0)) + prod0 := mul(x, y) + prod1 := sub(sub(mm, prod0), lt(mm, prod0)) + } + + // Handle non-overflow cases, 256 by 256 division. + if (prod1 == 0) { + return prod0 / denominator; + } + + // Make sure the result is less than 2^256. Also prevents denominator == 0. + require(denominator > prod1); + + /////////////////////////////////////////////// + // 512 by 256 division. + /////////////////////////////////////////////// + + // Make division exact by subtracting the remainder from [prod1 prod0]. + uint256 remainder; + assembly { + // Compute remainder using mulmod. + remainder := mulmod(x, y, denominator) + + // Subtract 256 bit number from 512 bit number. + prod1 := sub(prod1, gt(remainder, prod0)) + prod0 := sub(prod0, remainder) + } + + // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. + // See https://cs.stackexchange.com/q/138556/92363. + + // Does not overflow because the denominator cannot be zero at this stage in the function. + uint256 twos = denominator & (~denominator + 1); + assembly { + // Divide denominator by twos. + denominator := div(denominator, twos) + + // Divide [prod1 prod0] by twos. + prod0 := div(prod0, twos) + + // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. + twos := add(div(sub(0, twos), twos), 1) + } + + // Shift in bits from prod1 into prod0. + prod0 |= prod1 * twos; + + // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such + // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for + // four bits. That is, denominator * inv = 1 mod 2^4. + uint256 inverse = (3 * denominator) ^ 2; + + // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works + // in modular arithmetic, doubling the correct bits in each step. + inverse *= 2 - denominator * inverse; // inverse mod 2^8 + inverse *= 2 - denominator * inverse; // inverse mod 2^16 + inverse *= 2 - denominator * inverse; // inverse mod 2^32 + inverse *= 2 - denominator * inverse; // inverse mod 2^64 + inverse *= 2 - denominator * inverse; // inverse mod 2^128 + inverse *= 2 - denominator * inverse; // inverse mod 2^256 + + // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. + // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is + // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 + // is no longer required. + result = prod0 * inverse; + return result; + } + } + + /** + * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. + */ + function mulDiv( + uint256 x, + uint256 y, + uint256 denominator, + Rounding rounding + ) internal pure returns (uint256) { + uint256 result = mulDiv(x, y, denominator); + if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { + result += 1; + } + return result; + } + + /** + * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. + * + * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). + */ + function sqrt(uint256 a) internal pure returns (uint256) { + if (a == 0) { + return 0; + } + + // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. + // + // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have + // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. + // + // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` + // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` + // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` + // + // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. + uint256 result = 1 << (log2(a) >> 1); + + // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, + // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at + // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision + // into the expected uint128 result. + unchecked { + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + result = (result + a / result) >> 1; + return min(result, a / result); + } + } + + /** + * @notice Calculates sqrt(a), following the selected rounding direction. + */ + function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = sqrt(a); + return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); + } + } + + /** + * @dev Return the log in base 2, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 128; + } + if (value >> 64 > 0) { + value >>= 64; + result += 64; + } + if (value >> 32 > 0) { + value >>= 32; + result += 32; + } + if (value >> 16 > 0) { + value >>= 16; + result += 16; + } + if (value >> 8 > 0) { + value >>= 8; + result += 8; + } + if (value >> 4 > 0) { + value >>= 4; + result += 4; + } + if (value >> 2 > 0) { + value >>= 2; + result += 2; + } + if (value >> 1 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 2, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log2(value); + return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 10, rounded down, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >= 10**64) { + value /= 10**64; + result += 64; + } + if (value >= 10**32) { + value /= 10**32; + result += 32; + } + if (value >= 10**16) { + value /= 10**16; + result += 16; + } + if (value >= 10**8) { + value /= 10**8; + result += 8; + } + if (value >= 10**4) { + value /= 10**4; + result += 4; + } + if (value >= 10**2) { + value /= 10**2; + result += 2; + } + if (value >= 10**1) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log10(value); + return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0); + } + } + + /** + * @dev Return the log in base 256, rounded down, of a positive value. + * Returns 0 if given 0. + * + * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. + */ + function log256(uint256 value) internal pure returns (uint256) { + uint256 result = 0; + unchecked { + if (value >> 128 > 0) { + value >>= 128; + result += 16; + } + if (value >> 64 > 0) { + value >>= 64; + result += 8; + } + if (value >> 32 > 0) { + value >>= 32; + result += 4; + } + if (value >> 16 > 0) { + value >>= 16; + result += 2; + } + if (value >> 8 > 0) { + result += 1; + } + } + return result; + } + + /** + * @dev Return the log in base 10, following the selected rounding direction, of a positive value. + * Returns 0 if given 0. + */ + function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { + unchecked { + uint256 result = log256(value); + return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0); + } + } +} diff --git a/assets/eip-4365/migrations/.gitkeep b/assets/eip-4365/migrations/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/assets/eip-4365/migrations/1_initial_migration.js b/assets/eip-4365/migrations/1_initial_migration.js new file mode 100644 index 0000000000000..ee2135d2952ea --- /dev/null +++ b/assets/eip-4365/migrations/1_initial_migration.js @@ -0,0 +1,5 @@ +const Migrations = artifacts.require("Migrations"); + +module.exports = function(deployer) { + deployer.deploy(Migrations); +}; diff --git a/assets/eip-4365/migrations/2_deploy_contracts.js b/assets/eip-4365/migrations/2_deploy_contracts.js new file mode 100644 index 0000000000000..313adfb0b14a1 --- /dev/null +++ b/assets/eip-4365/migrations/2_deploy_contracts.js @@ -0,0 +1,5 @@ +const Ticket = artifacts.require("Ticket"); + +module.exports = function(deployer, network, accounts) { + deployer.deploy(Ticket, accounts[0], ""); +}; diff --git a/assets/eip-4365/test/.gitkeep b/assets/eip-4365/test/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/assets/eip-4365/truffle-config.js b/assets/eip-4365/truffle-config.js new file mode 100644 index 0000000000000..4a09bad4350dc --- /dev/null +++ b/assets/eip-4365/truffle-config.js @@ -0,0 +1,141 @@ +/** + * Use this file to configure your truffle project. It's seeded with some + * common settings for different networks and features like migrations, + * compilation, and testing. Uncomment the ones you need or modify + * them to suit your project as necessary. + * + * More information about configuration can be found at: + * + * https://trufflesuite.com/docs/truffle/reference/configuration + * + * Hands-off deployment with Infura + * -------------------------------- + * + * Do you have a complex application that requires lots of transactions to deploy? + * Use this approach to make deployment a breeze 🏖️: + * + * Infura deployment needs a wallet provider (like @truffle/hdwallet-provider) + * to sign transactions before they're sent to a remote public node. + * Infura accounts are available for free at 🔍: https://infura.io/register + * + * You'll need a mnemonic - the twelve word phrase the wallet uses to generate + * public/private key pairs. You can store your secrets 🤐 in a .env file. + * In your project root, run `$ npm install dotenv`. + * Create .env (which should be .gitignored) and declare your MNEMONIC + * and Infura PROJECT_ID variables inside. + * For example, your .env file will have the following structure: + * + * MNEMONIC = + * PROJECT_ID = + * + * Deployment with Truffle Dashboard (Recommended for best security practice) + * -------------------------------------------------------------------------- + * + * Are you concerned about security and minimizing rekt status 🤔? + * Use this method for best security: + * + * Truffle Dashboard lets you review transactions in detail, and leverages + * MetaMask for signing, so there's no need to copy-paste your mnemonic. + * More details can be found at 🔎: + * + * https://trufflesuite.com/docs/truffle/getting-started/using-the-truffle-dashboard/ + */ + +// require('dotenv').config(); +// const { MNEMONIC, PROJECT_ID } = process.env; + +// const HDWalletProvider = require('@truffle/hdwallet-provider'); + +module.exports = { + /** + * Networks define how you connect to your ethereum client and let you set the + * defaults web3 uses to send transactions. If you don't specify one truffle + * will spin up a managed Ganache instance for you on port 9545 when you + * run `develop` or `test`. You can ask a truffle command to use a specific + * network from the command line, e.g + * + * $ truffle test --network + */ + + networks: { + // Useful for testing. The `development` name is special - truffle uses it by default + // if it's defined here and no other network is specified at the command line. + // You should run a client (like ganache, geth, or parity) in a separate terminal + // tab if you use this network and you must also set the `host`, `port` and `network_id` + // options below to some value. + // + development: { + host: "127.0.0.1", // Localhost (default: none) + port: 7545, // Standard Ethereum port (default: none) + network_id: "*", // Any network (default: none) + }, + // + // An additional network, but with some advanced options… + // advanced: { + // port: 8777, // Custom port + // network_id: 1342, // Custom network + // gas: 8500000, // Gas sent with each transaction (default: ~6700000) + // gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei) + // from:
, // Account to send transactions from (default: accounts[0]) + // websocket: true // Enable EventEmitter interface for web3 (default: false) + // }, + // + // Useful for deploying to a public network. + // Note: It's important to wrap the provider as a function to ensure truffle uses a new provider every time. + // goerli: { + // provider: () => new HDWalletProvider(MNEMONIC, `https://goerli.infura.io/v3/${PROJECT_ID}`), + // network_id: 5, // Goerli's id + // confirmations: 2, // # of confirmations to wait between deployments. (default: 0) + // timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50) + // skipDryRun: true // Skip dry run before migrations? (default: false for public nets ) + // }, + // + // Useful for private networks + // private: { + // provider: () => new HDWalletProvider(MNEMONIC, `https://network.io`), + // network_id: 2111, // This network is yours, in the cloud. + // production: true // Treats this network as if it was a public net. (default: false) + // } + }, + + // Set default mocha options here, use special reporters, etc. + mocha: { + // timeout: 100000 + }, + + // Configure your compilers + compilers: { + solc: { + version: "0.8.17" // Fetch exact version from solc-bin (default: truffle's version) + // docker: true, // Use "0.5.1" you've installed locally with docker (default: false) + // settings: { // See the solidity docs for advice about optimization and evmVersion + // optimizer: { + // enabled: false, + // runs: 200 + // }, + // evmVersion: "byzantium" + // } + } + } + + // Truffle DB is currently disabled by default; to enable it, change enabled: + // false to enabled: true. The default storage location can also be + // overridden by specifying the adapter settings, as shown in the commented code below. + // + // NOTE: It is not possible to migrate your contracts to truffle DB and you should + // make a backup of your artifacts to a safe location before enabling this feature. + // + // After you backed up your artifacts you can utilize db by running migrate as follows: + // $ truffle migrate --reset --compile-all + // + // db: { + // enabled: false, + // host: "127.0.0.1", + // adapter: { + // name: "indexeddb", + // settings: { + // directory: ".db" + // } + // } + // } +}; From 3a099678c8eaa868662834fe581c80d56738a186 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Tue, 21 Mar 2023 14:15:47 +0100 Subject: [PATCH 03/20] Update eip-4365.md --- EIPS/eip-4365.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-4365.md b/EIPS/eip-4365.md index c96e1ded82ee4..c51f47704ccab 100644 --- a/EIPS/eip-4365.md +++ b/EIPS/eip-4365.md @@ -1,5 +1,5 @@ --- -eip: 4365 +eip: X title: Redeemable Tokens description: A proposition for redeemable tokens author: Lucaz Lindgren (@LucazFFz) @@ -8,12 +8,12 @@ status: Draft type: Standards Track category: ERC created: 2023-03-20 -requires: 165, 1238 +requires: 165 --- ## Abstract -This ERC outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +This ERC outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. @@ -285,7 +285,7 @@ Because of the heavy inspiration from the ERC-1155 standard many concepts and me ## Reference Implementation -* [Reference implementation](../assets/eip-4365/) +- [Reference implementation](../assets/eip-4365/) ## Security Considerations From b8f41f60b4d7d11378128a2e616661069149d687 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Tue, 21 Mar 2023 15:02:16 +0100 Subject: [PATCH 04/20] Fix EIP errors --- EIPS/eip-4365.md | 132 +++++++++--------- assets/eip-4365/contracts/examples/Ticket.sol | 2 +- .../contracts/token/ERC4365/ERC4365.sol | 2 +- .../contracts/token/ERC4365/IERC4365.sol | 2 +- .../token/ERC4365/IERC4365Receiver.sol | 2 - .../ERC4365/extensions/ERC4365Expirable.sol | 2 +- .../ERC4365/extensions/ERC4365Payable.sol | 2 +- .../ERC4365/extensions/ERC4365URIStorage.sol | 2 +- .../ERC4365/extensions/IERC4365Expirable.sol | 2 +- .../ERC4365/extensions/IERC4365Payable.sol | 2 +- .../ERC4365/extensions/IERC4365Supply.sol | 2 +- .../ERC4365/extensions/IERC4365URIStorage.sol | 2 +- 12 files changed, 76 insertions(+), 78 deletions(-) diff --git a/EIPS/eip-4365.md b/EIPS/eip-4365.md index c51f47704ccab..28a8816d9e442 100644 --- a/EIPS/eip-4365.md +++ b/EIPS/eip-4365.md @@ -1,5 +1,5 @@ --- -eip: X +eip: title: Redeemable Tokens description: A proposition for redeemable tokens author: Lucaz Lindgren (@LucazFFz) @@ -11,29 +11,29 @@ created: 2023-03-20 requires: 165 --- -## Abstract +## Abstract -This ERC outlines a smart contract interface that can represent any number of fungible and non-funible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +This ERC outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. -Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. +Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. -## Motivation +## Motivation The core idea of this ERC is to standardize and simplify the development of redeemable tokens (tickets) on the Ethereum blockchain. The tokens can be redeemed in exchange for currency or access (the reward for redeeming is left to implementers). The tokens can be exchanged for real-world or digital rewards. - -Example of use-cases for redeemable tokens: -- **General admission tickets** - Tickets allowing attendees entry to the event together with access to the regular event activities. This type of ticket could be fungible meaning they are interchangeable. The event can be held either physically or digitally. -- **VIP tickets** - All-access tickets that include everything the event offers with activities excluded from the general admission tickets to give the attendees a premium experience. These tickets can be non-fungible making every ticket unique and allowing each ticket to be connected to an individual artwork or likewise to incentivize purchasing VIP tickets instead. - +Example of use-cases for redeemable tokens: + +- **General admission tickets** - Tickets allowing attendees entry to the event together with access to the regular event activities. This type of ticket could be fungible meaning they are interchangeable. The event can be held either physically or digitally. +- **VIP tickets** - All-access tickets that include everything the event offers with activities excluded from the general admission tickets to give the attendees a premium experience. These tickets can be non-fungible making every ticket unique and allowing each ticket to be connected to an individual artwork or likewise to incentivize purchasing VIP tickets instead. + Additionally, these tokens can be used to create, among others, vouchers, gift cards, and scratchcards. -## Specification +## Specification + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. +**Every smart contract implementing this ERC MUST implement the all of the functions in the `ERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** -**Every smart contract compliant with this ERC MUST implement the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** - ```solidity interface IERC4365 is IERC165 { /** @@ -81,9 +81,9 @@ interface IERC4365 is IERC165 { * Requirements: * - `accounts` and `ids` must have the same length. */ - function balanceOfBundle(address[] calldata accounts, uint256[][] calldata ids) - external - view + function balanceOfBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view returns (uint256[][] memory); /** @@ -106,9 +106,9 @@ interface IERC4365 is IERC165 { * Requirements: * - `accounts` and `ids` must have the same length. */ - function balanceOfRedeemedBundle(address[] calldata accounts, uint256[][] calldata ids) - external - view + function balanceOfRedeemedBundle(address[] calldata accounts, uint256[][] calldata ids) + external + view returns (uint256[][] memory); /** @@ -116,25 +116,25 @@ interface IERC4365 is IERC165 { * * Requirements: * - `account` cannot be the zero address. - * - `amount` together with `account` balance of redeemed token of token type `id` - * cannot exceed `account` balance of token type `id`. + * - `amount` together with `account` balance of redeemed token of token type `id` + * cannot exceed `account` balance of token type `id`. */ function redeem (address account, uint256 id, uint256 amount, bytes memory data) external; } ``` - -In addition, in order for a contract to be compliant with this ERC, it MUST abide by the following: -- Implementers MAY enable token transfers to support functionality such as ticket reselling. -- Implementers MUST NOT allow tokens to be transferred between addresses after they have been redeemed. -- Implementers MUST allow token holders to redeem their tokens. -- Implementers MUST NOT allow token issuers to redeem the tokens they have issued. -- Implementers SHOULD allow token recipients to burn any token they receive. -- Implementers MAY enable token issuers to burn the tokens they issued. +In addition, in order for a contract to be compliant with this ERC, it MUST abide by the following: + +- Implementers MAY enable token transfers to support functionality such as ticket reselling. +- Implementers MUST NOT allow tokens to be transferred between addresses after they have been redeemed. +- Implementers MUST allow token holders to redeem their tokens. +- Implementers MUST NOT allow token issuers to redeem the tokens they have issued. +- Implementers SHOULD allow token recipients to burn any token they receive. +- Implementers MAY enable token issuers to burn the tokens they issued. **Smart contracts MUST implement all of the functions in the `ERC4365Receiver` interface to accept tokens being minted to them.** -The **URI Storage extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique URI for each token ID. +The **URI Storage extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique URI for each token ID. ```solidity interface IERC4365URIStorage is IERC4365 { @@ -150,9 +150,9 @@ interface IERC4365URIStorage is IERC4365 { } ``` -The **Expirable extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: +The **Expirable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: -- Implementers MUST NOT allow tokens to be minted or redeemed if expired. +- Implementers MUST NOT allow tokens to be minted or redeemed if expired. ```solidity interface IERC4365Expirable is IERC4365 { @@ -165,25 +165,25 @@ interface IERC4365Expirable is IERC4365 { * @dev [Batched] version of {setExpiryDate}. */ function setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) external; - + /** * @dev Returns the expiry date for the token of token type `id`. */ function expiryDate(uint256 id) external view returns (uint256); /** - * @dev Returns `true` or `false` depending on if the token of token type `id` has expired + * @dev Returns `true` or `false` depending on if the token of token type `id` has expired * by comparing the expiry date with `block.timestamp`. */ function isExpired(uint256 id) external view returns (bool); } ``` -The **Supply extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: +The **Supply extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: -- Implementers SHOULD NOT allow tokens to be minted if total supply exceeds max supply. -- Implementers SHOULD increment total supply upon minting and decrement upon burning. -- Implementers are RECOMMENDED to override the `_beforeMint` hook to increment total supply upon minting and decrement upon burning. +- Implementers SHOULD NOT allow tokens to be minted if total supply exceeds max supply. +- Implementers SHOULD increment total supply upon minting and decrement upon burning. +- Implementers are RECOMMENDED to override the `_beforeMint` hook to increment total supply upon minting and decrement upon burning. ```solidity interface IERC4365Payable is IERC4365 { @@ -204,9 +204,9 @@ interface IERC4365Payable is IERC4365 { } ``` -The **Payable extension** is OPTIONAL for smart contracts implementing this ERC. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: +The **Payable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: -- Implementers SHOULD require recipients to provide funding equal to the token price. +- Implementers SHOULD require recipients to provide funding equal to the token price. ```solidity interface IERC4365Supply is IERC4365 { @@ -237,60 +237,60 @@ interface IERC4365Supply is IERC4365 { } ``` -## Rationale - +## Rationale + ### Overview The proposed interface and implementation draw heavy inspiration from ERC-1155 which paved the way for managing multiple token types in the same smart contract reducing gas costs. It draws from the lessons and prior discussions which emerged from the standard and therefore inherits from its design and structure. - + ERC-1155 presents multiple interesting features also applicable to redeemable tokens: -- Because one contract is able to hold multiple different token types, there is no need to deploy multiple contracts for each collection as with previous standards. This saves on deployment gas costs as well as reduces redundant bytecode on the Ethereum blockchain. -- ERC-1155 is fungibility-agnostic which means the same contract can manage both fungible and non-fungible token types. -- Batch operations are supported making it possible to mint or query the balance for multiple token ids within the same call. -- Eliminates the possibility to lock tokens in smart contracts due to the requirement for smart contracts to implement the `ERC1155TokenReceiver` interface. -- Smart contracts implementing the `ERC1155TokenReceiver` interface may reject an increase in balance. +- Because one contract is able to hold multiple different token types, there is no need to deploy multiple contracts for each collection as with previous standards. This saves on deployment gas costs as well as reduces redundant bytecode on the Ethereum blockchain. +- ERC-1155 is fungibility-agnostic which means the same contract can manage both fungible and non-fungible token types. +- Batch operations are supported making it possible to mint or query the balance for multiple token ids within the same call. +- Eliminates the possibility to lock tokens in smart contracts due to the requirement for smart contracts to implement the `ERC1155TokenReceiver` interface. +- Smart contracts implementing the `ERC1155TokenReceiver` interface may reject an increase in balance. -This standard does not assume who has the power to mint/burn tokens nor under what condition the actions can occur. However, it requires that the token holders have the ability to redeem their tokens. +This standard does not assume who has the power to mint/burn tokens nor under what condition the actions can occur. However, it requires that the token holders have the ability to redeem their tokens. ### Fungibility -This ERC, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. - +This ERC, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. + One way to achieve non-fungible tokens is to utilize split ID bits reserving the top 128 bits of the 256 bits `id` parameter to represent the base token ID while using the bottom 128 bits to represent the index of the non-fungible to make it unique. - -Alternatively, a more intuitive approach to represent non-fungible tokens is to allow a maximum value of 1 for each. This would reflect the real world, where unique items have a quantity of 1 and fungible items have a quantity greater than 1. + +Alternatively, a more intuitive approach to represent non-fungible tokens is to allow a maximum value of 1 for each. This would reflect the real world, where unique items have a quantity of 1 and fungible items have a quantity greater than 1. ### Batch Operations -ERC-1155, likewise this ERC, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. - -However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this ERC support bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. +ERC-1155, likewise this ERC, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. + +However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this ERC support bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. ### Transfer -This ERC does not enforce transferability between addresses except for minting and burning. However, it recognizes the possible need for it when for example implementing resell functionality and, therefore, does not prevent it. +This ERC does not enforce transferability between addresses except for minting and burning. However, it recognizes the possible need for it when for example implementing resell functionality and, therefore, does not prevent it. ### Redeem -The core addition to redeemable tokens is the possibility to redeem tokens in exchange for currency, access, etc. As tokens only can be redeemed by their holders a possible `redeemBatch` function has been excluded as it is not expected that a holder would want to redeem multiple token types simultaneously. +The core addition to redeemable tokens is the possibility to redeem tokens in exchange for currency, access, etc. As tokens only can be redeemed by their holders a possible `redeemBatch` function has been excluded as it is not expected that a holder would want to redeem multiple token types simultaneously. ### Safe Mint Only -This ERC takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. +This ERC takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. -## Backwards Compatibility +## Backwards Compatibility Because of the heavy inspiration from the ERC-1155 standard many concepts and methods remain identical, namely the concept of a batch, the `balanceOf` and `balanceOfBatch` functions, and to some extent the URI Storage and Supply extensions. -## Reference Implementation - +## Reference Implementation + - [Reference implementation](../assets/eip-4365/) -## Security Considerations +## Security Considerations Needs discussion. -## Copyright +## Copyright -Copyright and related rights waived via [CC0](../LICENSE.md). \ No newline at end of file +Copyright and related rights waived via [CC0](../LICENSE.md). diff --git a/assets/eip-4365/contracts/examples/Ticket.sol b/assets/eip-4365/contracts/examples/Ticket.sol index bc574d906eda5..8810648578c7f 100644 --- a/assets/eip-4365/contracts/examples/Ticket.sol +++ b/assets/eip-4365/contracts/examples/Ticket.sol @@ -54,4 +54,4 @@ contract Ticket is ERC4365, ERC4365Expirable { function _setExpiryDate(uint256 id, uint256 date) internal override onlyOwner { super._setExpiryDate(id, date); } -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol b/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol index bd21e9c3c0311..b7462aa38aeb0 100644 --- a/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol +++ b/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol @@ -409,4 +409,4 @@ contract ERC4365 is Context, ERC165, IERC4365 { } } } -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol b/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol index 5ecbb18a580c3..32a7ad31f13f6 100644 --- a/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol +++ b/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol @@ -92,4 +92,4 @@ interface IERC4365 is IERC165 { * cannot exceed `account` balance of token type `id`. */ function redeem (address account, uint256 id, uint256 amount, bytes memory data) external; -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol b/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol index 0ee3ebd32ab6e..e1e555bab7e86 100644 --- a/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol +++ b/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol @@ -46,5 +46,3 @@ interface IERC4365Receiver is IERC165 { bytes calldata data ) external returns (bytes4); } - - diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol index c5a42a3dcb80d..40b9887805780 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol @@ -70,4 +70,4 @@ abstract contract ERC4365Expirable is ERC4365 { _setExpiryDate(ids[i], dates[i]); } } -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol index c76c06b8cf51c..b9ba96d0cc952 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol @@ -52,4 +52,4 @@ abstract contract ERC4365Payable is ERC4365 { _setPrice(ids[i], amounts[i]); } } -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol index c6804032a6a0f..9c1a8d27ffc22 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol @@ -81,4 +81,4 @@ abstract contract ERC4365URIStorage is ERC165, IERC4365URIStorage, ERC4365 { function _isTokenURISet(uint256 id) private view returns (bool) { return bytes(_tokenURIs[id]).length > 0; } -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol index 0f034e0a6bc5e..2c32f6623478e 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol @@ -28,4 +28,4 @@ interface IERC4365Expirable is IERC4365 { * by comparing the expiry date with `block.timestamp`. */ function isExpired(uint256 id) external view returns (bool); -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol index ed223b0d9ae8f..174b509cbdbd3 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol @@ -21,4 +21,4 @@ interface IERC4365Payable is IERC4365 { * @dev Returns the price for the token type `id`. */ function price(uint256 id) external view returns (uint256); -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol index bdf1e80f2ba94..e2566877376e2 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol @@ -31,4 +31,4 @@ interface IERC4365Supply is IERC4365 { * @dev Indicates whether any token of token type `id` exists, or not. */ function exists(uint256 id) external view returns (bool); -} \ No newline at end of file +} diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol index 466292afaba46..fc83bf3acee1f 100644 --- a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol +++ b/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol @@ -17,4 +17,4 @@ interface IERC4365URIStorage is IERC4365 { * @dev Returns the Uniform Resource Identifier (URI) for `id` token. */ function tokenURI(uint256 id) external view returns (string memory); -} \ No newline at end of file +} From b376862ce85bf84dbc38673c18a52d63e13db6af Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Tue, 21 Mar 2023 15:02:39 +0100 Subject: [PATCH 05/20] Fix EIP errors --- EIPS/{eip-4365.md => to-be-assigned.md} | 0 assets/{eip-4365 => to-be-assigned}/.gitignore | 0 assets/{eip-4365 => to-be-assigned}/README.md | 0 assets/{eip-4365 => to-be-assigned}/contracts/.gitkeep | 0 assets/{eip-4365 => to-be-assigned}/contracts/Migrations.sol | 0 assets/{eip-4365 => to-be-assigned}/contracts/examples/Ticket.sol | 0 .../contracts/token/ERC4365/ERC4365.sol | 0 .../contracts/token/ERC4365/IERC4365.sol | 0 .../contracts/token/ERC4365/IERC4365Receiver.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Expirable.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Payable.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Supply.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365URIStorage.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Expirable.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Payable.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Supply.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365URIStorage.sol | 0 assets/{eip-4365 => to-be-assigned}/contracts/utils/Address.sol | 0 assets/{eip-4365 => to-be-assigned}/contracts/utils/Context.sol | 0 assets/{eip-4365 => to-be-assigned}/contracts/utils/Strings.sol | 0 .../contracts/utils/introspection/ERC165.sol | 0 .../contracts/utils/introspection/IERC165.sol | 0 assets/{eip-4365 => to-be-assigned}/contracts/utils/math/Math.sol | 0 assets/{eip-4365 => to-be-assigned}/migrations/.gitkeep | 0 .../migrations/1_initial_migration.js | 0 .../{eip-4365 => to-be-assigned}/migrations/2_deploy_contracts.js | 0 assets/{eip-4365 => to-be-assigned}/test/.gitkeep | 0 assets/{eip-4365 => to-be-assigned}/truffle-config.js | 0 28 files changed, 0 insertions(+), 0 deletions(-) rename EIPS/{eip-4365.md => to-be-assigned.md} (100%) rename assets/{eip-4365 => to-be-assigned}/.gitignore (100%) rename assets/{eip-4365 => to-be-assigned}/README.md (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/.gitkeep (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/Migrations.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/examples/Ticket.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/ERC4365.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/IERC4365.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/IERC4365Receiver.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/ERC4365Expirable.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/ERC4365Payable.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/ERC4365Supply.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/IERC4365Expirable.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/IERC4365Payable.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/IERC4365Supply.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/Address.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/Context.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/Strings.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/introspection/ERC165.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/introspection/IERC165.sol (100%) rename assets/{eip-4365 => to-be-assigned}/contracts/utils/math/Math.sol (100%) rename assets/{eip-4365 => to-be-assigned}/migrations/.gitkeep (100%) rename assets/{eip-4365 => to-be-assigned}/migrations/1_initial_migration.js (100%) rename assets/{eip-4365 => to-be-assigned}/migrations/2_deploy_contracts.js (100%) rename assets/{eip-4365 => to-be-assigned}/test/.gitkeep (100%) rename assets/{eip-4365 => to-be-assigned}/truffle-config.js (100%) diff --git a/EIPS/eip-4365.md b/EIPS/to-be-assigned.md similarity index 100% rename from EIPS/eip-4365.md rename to EIPS/to-be-assigned.md diff --git a/assets/eip-4365/.gitignore b/assets/to-be-assigned/.gitignore similarity index 100% rename from assets/eip-4365/.gitignore rename to assets/to-be-assigned/.gitignore diff --git a/assets/eip-4365/README.md b/assets/to-be-assigned/README.md similarity index 100% rename from assets/eip-4365/README.md rename to assets/to-be-assigned/README.md diff --git a/assets/eip-4365/contracts/.gitkeep b/assets/to-be-assigned/contracts/.gitkeep similarity index 100% rename from assets/eip-4365/contracts/.gitkeep rename to assets/to-be-assigned/contracts/.gitkeep diff --git a/assets/eip-4365/contracts/Migrations.sol b/assets/to-be-assigned/contracts/Migrations.sol similarity index 100% rename from assets/eip-4365/contracts/Migrations.sol rename to assets/to-be-assigned/contracts/Migrations.sol diff --git a/assets/eip-4365/contracts/examples/Ticket.sol b/assets/to-be-assigned/contracts/examples/Ticket.sol similarity index 100% rename from assets/eip-4365/contracts/examples/Ticket.sol rename to assets/to-be-assigned/contracts/examples/Ticket.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/ERC4365.sol b/assets/to-be-assigned/contracts/token/ERC4365/ERC4365.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/ERC4365.sol rename to assets/to-be-assigned/contracts/token/ERC4365/ERC4365.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365.sol b/assets/to-be-assigned/contracts/token/ERC4365/IERC4365.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/IERC4365.sol rename to assets/to-be-assigned/contracts/token/ERC4365/IERC4365.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol b/assets/to-be-assigned/contracts/token/ERC4365/IERC4365Receiver.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/IERC4365Receiver.sol rename to assets/to-be-assigned/contracts/token/ERC4365/IERC4365Receiver.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Expirable.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Expirable.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Expirable.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Payable.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Payable.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Payable.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Supply.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365Supply.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Supply.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Expirable.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Expirable.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Expirable.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Payable.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Payable.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Payable.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Supply.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365Supply.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Supply.sol diff --git a/assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol b/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol similarity index 100% rename from assets/eip-4365/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol rename to assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol diff --git a/assets/eip-4365/contracts/utils/Address.sol b/assets/to-be-assigned/contracts/utils/Address.sol similarity index 100% rename from assets/eip-4365/contracts/utils/Address.sol rename to assets/to-be-assigned/contracts/utils/Address.sol diff --git a/assets/eip-4365/contracts/utils/Context.sol b/assets/to-be-assigned/contracts/utils/Context.sol similarity index 100% rename from assets/eip-4365/contracts/utils/Context.sol rename to assets/to-be-assigned/contracts/utils/Context.sol diff --git a/assets/eip-4365/contracts/utils/Strings.sol b/assets/to-be-assigned/contracts/utils/Strings.sol similarity index 100% rename from assets/eip-4365/contracts/utils/Strings.sol rename to assets/to-be-assigned/contracts/utils/Strings.sol diff --git a/assets/eip-4365/contracts/utils/introspection/ERC165.sol b/assets/to-be-assigned/contracts/utils/introspection/ERC165.sol similarity index 100% rename from assets/eip-4365/contracts/utils/introspection/ERC165.sol rename to assets/to-be-assigned/contracts/utils/introspection/ERC165.sol diff --git a/assets/eip-4365/contracts/utils/introspection/IERC165.sol b/assets/to-be-assigned/contracts/utils/introspection/IERC165.sol similarity index 100% rename from assets/eip-4365/contracts/utils/introspection/IERC165.sol rename to assets/to-be-assigned/contracts/utils/introspection/IERC165.sol diff --git a/assets/eip-4365/contracts/utils/math/Math.sol b/assets/to-be-assigned/contracts/utils/math/Math.sol similarity index 100% rename from assets/eip-4365/contracts/utils/math/Math.sol rename to assets/to-be-assigned/contracts/utils/math/Math.sol diff --git a/assets/eip-4365/migrations/.gitkeep b/assets/to-be-assigned/migrations/.gitkeep similarity index 100% rename from assets/eip-4365/migrations/.gitkeep rename to assets/to-be-assigned/migrations/.gitkeep diff --git a/assets/eip-4365/migrations/1_initial_migration.js b/assets/to-be-assigned/migrations/1_initial_migration.js similarity index 100% rename from assets/eip-4365/migrations/1_initial_migration.js rename to assets/to-be-assigned/migrations/1_initial_migration.js diff --git a/assets/eip-4365/migrations/2_deploy_contracts.js b/assets/to-be-assigned/migrations/2_deploy_contracts.js similarity index 100% rename from assets/eip-4365/migrations/2_deploy_contracts.js rename to assets/to-be-assigned/migrations/2_deploy_contracts.js diff --git a/assets/eip-4365/test/.gitkeep b/assets/to-be-assigned/test/.gitkeep similarity index 100% rename from assets/eip-4365/test/.gitkeep rename to assets/to-be-assigned/test/.gitkeep diff --git a/assets/eip-4365/truffle-config.js b/assets/to-be-assigned/truffle-config.js similarity index 100% rename from assets/eip-4365/truffle-config.js rename to assets/to-be-assigned/truffle-config.js From 1321932625bd8ec5925110aba3fdeac66d375037 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Tue, 21 Mar 2023 15:13:54 +0100 Subject: [PATCH 06/20] Fix EIP errors --- EIPS/{to-be-assigned.md => eip-draft_title_abbrev.md.md} | 3 +-- assets/{to-be-assigned => eip-draft_title_abbrev}/.gitignore | 0 assets/{to-be-assigned => eip-draft_title_abbrev}/README.md | 0 .../contracts/.gitkeep | 0 .../contracts/Migrations.sol | 0 .../contracts/examples/Ticket.sol | 0 .../contracts/token/ERC4365/ERC4365.sol | 0 .../contracts/token/ERC4365/IERC4365.sol | 0 .../contracts/token/ERC4365/IERC4365Receiver.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Expirable.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Payable.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365Supply.sol | 0 .../contracts/token/ERC4365/extensions/ERC4365URIStorage.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Expirable.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Payable.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365Supply.sol | 0 .../contracts/token/ERC4365/extensions/IERC4365URIStorage.sol | 0 .../contracts/utils/Address.sol | 0 .../contracts/utils/Context.sol | 0 .../contracts/utils/Strings.sol | 0 .../contracts/utils/introspection/ERC165.sol | 0 .../contracts/utils/introspection/IERC165.sol | 0 .../contracts/utils/math/Math.sol | 0 .../migrations/.gitkeep | 0 .../migrations/1_initial_migration.js | 0 .../migrations/2_deploy_contracts.js | 0 .../{to-be-assigned => eip-draft_title_abbrev}/test/.gitkeep | 0 .../truffle-config.js | 0 28 files changed, 1 insertion(+), 2 deletions(-) rename EIPS/{to-be-assigned.md => eip-draft_title_abbrev.md.md} (98%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/.gitignore (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/README.md (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/.gitkeep (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/Migrations.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/examples/Ticket.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/ERC4365.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/IERC4365.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/IERC4365Receiver.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/ERC4365Expirable.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/ERC4365Payable.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/ERC4365Supply.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/IERC4365Expirable.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/IERC4365Payable.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/IERC4365Supply.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/Address.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/Context.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/Strings.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/introspection/ERC165.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/introspection/IERC165.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/contracts/utils/math/Math.sol (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/migrations/.gitkeep (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/migrations/1_initial_migration.js (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/migrations/2_deploy_contracts.js (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/test/.gitkeep (100%) rename assets/{to-be-assigned => eip-draft_title_abbrev}/truffle-config.js (100%) diff --git a/EIPS/to-be-assigned.md b/EIPS/eip-draft_title_abbrev.md.md similarity index 98% rename from EIPS/to-be-assigned.md rename to EIPS/eip-draft_title_abbrev.md.md index 28a8816d9e442..eab24abfd64b6 100644 --- a/EIPS/to-be-assigned.md +++ b/EIPS/eip-draft_title_abbrev.md.md @@ -1,5 +1,4 @@ --- -eip: title: Redeemable Tokens description: A proposition for redeemable tokens author: Lucaz Lindgren (@LucazFFz) @@ -32,7 +31,7 @@ Additionally, these tokens can be used to create, among others, vouchers, gift c The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -**Every smart contract implementing this ERC MUST implement the all of the functions in the `ERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** +**Every smart contract implementing this ERC MUST implement the all of the functions in the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity interface IERC4365 is IERC165 { diff --git a/assets/to-be-assigned/.gitignore b/assets/eip-draft_title_abbrev/.gitignore similarity index 100% rename from assets/to-be-assigned/.gitignore rename to assets/eip-draft_title_abbrev/.gitignore diff --git a/assets/to-be-assigned/README.md b/assets/eip-draft_title_abbrev/README.md similarity index 100% rename from assets/to-be-assigned/README.md rename to assets/eip-draft_title_abbrev/README.md diff --git a/assets/to-be-assigned/contracts/.gitkeep b/assets/eip-draft_title_abbrev/contracts/.gitkeep similarity index 100% rename from assets/to-be-assigned/contracts/.gitkeep rename to assets/eip-draft_title_abbrev/contracts/.gitkeep diff --git a/assets/to-be-assigned/contracts/Migrations.sol b/assets/eip-draft_title_abbrev/contracts/Migrations.sol similarity index 100% rename from assets/to-be-assigned/contracts/Migrations.sol rename to assets/eip-draft_title_abbrev/contracts/Migrations.sol diff --git a/assets/to-be-assigned/contracts/examples/Ticket.sol b/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol similarity index 100% rename from assets/to-be-assigned/contracts/examples/Ticket.sol rename to assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/ERC4365.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/ERC4365.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/ERC4365.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/ERC4365.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/IERC4365.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/IERC4365.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/IERC4365Receiver.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365Receiver.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/IERC4365Receiver.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365Receiver.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Expirable.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Expirable.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Expirable.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Expirable.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Payable.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Payable.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Payable.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Payable.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Supply.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Supply.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365Supply.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Supply.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Expirable.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Expirable.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Expirable.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Expirable.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Payable.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Payable.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Payable.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Payable.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Supply.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Supply.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365Supply.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Supply.sol diff --git a/assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol b/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol similarity index 100% rename from assets/to-be-assigned/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol rename to assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol diff --git a/assets/to-be-assigned/contracts/utils/Address.sol b/assets/eip-draft_title_abbrev/contracts/utils/Address.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/Address.sol rename to assets/eip-draft_title_abbrev/contracts/utils/Address.sol diff --git a/assets/to-be-assigned/contracts/utils/Context.sol b/assets/eip-draft_title_abbrev/contracts/utils/Context.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/Context.sol rename to assets/eip-draft_title_abbrev/contracts/utils/Context.sol diff --git a/assets/to-be-assigned/contracts/utils/Strings.sol b/assets/eip-draft_title_abbrev/contracts/utils/Strings.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/Strings.sol rename to assets/eip-draft_title_abbrev/contracts/utils/Strings.sol diff --git a/assets/to-be-assigned/contracts/utils/introspection/ERC165.sol b/assets/eip-draft_title_abbrev/contracts/utils/introspection/ERC165.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/introspection/ERC165.sol rename to assets/eip-draft_title_abbrev/contracts/utils/introspection/ERC165.sol diff --git a/assets/to-be-assigned/contracts/utils/introspection/IERC165.sol b/assets/eip-draft_title_abbrev/contracts/utils/introspection/IERC165.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/introspection/IERC165.sol rename to assets/eip-draft_title_abbrev/contracts/utils/introspection/IERC165.sol diff --git a/assets/to-be-assigned/contracts/utils/math/Math.sol b/assets/eip-draft_title_abbrev/contracts/utils/math/Math.sol similarity index 100% rename from assets/to-be-assigned/contracts/utils/math/Math.sol rename to assets/eip-draft_title_abbrev/contracts/utils/math/Math.sol diff --git a/assets/to-be-assigned/migrations/.gitkeep b/assets/eip-draft_title_abbrev/migrations/.gitkeep similarity index 100% rename from assets/to-be-assigned/migrations/.gitkeep rename to assets/eip-draft_title_abbrev/migrations/.gitkeep diff --git a/assets/to-be-assigned/migrations/1_initial_migration.js b/assets/eip-draft_title_abbrev/migrations/1_initial_migration.js similarity index 100% rename from assets/to-be-assigned/migrations/1_initial_migration.js rename to assets/eip-draft_title_abbrev/migrations/1_initial_migration.js diff --git a/assets/to-be-assigned/migrations/2_deploy_contracts.js b/assets/eip-draft_title_abbrev/migrations/2_deploy_contracts.js similarity index 100% rename from assets/to-be-assigned/migrations/2_deploy_contracts.js rename to assets/eip-draft_title_abbrev/migrations/2_deploy_contracts.js diff --git a/assets/to-be-assigned/test/.gitkeep b/assets/eip-draft_title_abbrev/test/.gitkeep similarity index 100% rename from assets/to-be-assigned/test/.gitkeep rename to assets/eip-draft_title_abbrev/test/.gitkeep diff --git a/assets/to-be-assigned/truffle-config.js b/assets/eip-draft_title_abbrev/truffle-config.js similarity index 100% rename from assets/to-be-assigned/truffle-config.js rename to assets/eip-draft_title_abbrev/truffle-config.js From 661fadbe9aa1242ba49afae97e95738b46374f8f Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Tue, 21 Mar 2023 15:20:01 +0100 Subject: [PATCH 07/20] Fix EIP errors --- .../{eip-draft_title_abbrev.md.md => eip-draft_title_abbrev.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename EIPS/{eip-draft_title_abbrev.md.md => eip-draft_title_abbrev.md} (97%) diff --git a/EIPS/eip-draft_title_abbrev.md.md b/EIPS/eip-draft_title_abbrev.md similarity index 97% rename from EIPS/eip-draft_title_abbrev.md.md rename to EIPS/eip-draft_title_abbrev.md index eab24abfd64b6..5681e14702eab 100644 --- a/EIPS/eip-draft_title_abbrev.md.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -12,7 +12,7 @@ requires: 165 ## Abstract -This ERC outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +[ERC-4365](./eip-draft_title_abbrev.md) outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. From a2b7ac343e02bec16f586bca02082781c4bd5d9c Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Tue, 21 Mar 2023 15:28:43 +0100 Subject: [PATCH 08/20] Fix reference implementation link --- EIPS/eip-draft_title_abbrev.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 5681e14702eab..331b122c25cf4 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -31,7 +31,7 @@ Additionally, these tokens can be used to create, among others, vouchers, gift c The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -**Every smart contract implementing this ERC MUST implement the all of the functions in the `IERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** +**Every smart contract implementing this ERC MUST implement the all of the functions in the `ERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity interface IERC4365 is IERC165 { @@ -284,7 +284,7 @@ Because of the heavy inspiration from the ERC-1155 standard many concepts and me ## Reference Implementation -- [Reference implementation](../assets/eip-4365/) +- [Reference implementation](../assets/eip-draft_title_abbrev/) ## Security Considerations From 3568e2a838b0ffbb982ebb644ae4d56d9e70cade Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Wed, 22 Mar 2023 17:26:41 +0100 Subject: [PATCH 09/20] Fix eip-draft_title_abbrev.md where the code for the supply and payable extensions are mixed up --- EIPS/eip-draft_title_abbrev.md | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 331b122c25cf4..7ac31b7babf11 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -184,29 +184,6 @@ The **Supply extension** is OPTIONAL for compliant smart contracts. This allows - Implementers SHOULD increment total supply upon minting and decrement upon burning. - Implementers are RECOMMENDED to override the `_beforeMint` hook to increment total supply upon minting and decrement upon burning. -```solidity -interface IERC4365Payable is IERC4365 { - /** - * @dev Sets the price `amount` for the token of token type `id`. - */ - function setPrice(uint256 id, uint256 amount) external; - - /** - * @dev [Batched] version of {setPrice}. - */ - function setBatchPrices(uint256[] memory ids, uint256[] memory amounts) external; - - /** - * @dev Returns the price for the token type `id`. - */ - function price(uint256 id) external view returns (uint256); -} -``` - -The **Payable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: - -- Implementers SHOULD require recipients to provide funding equal to the token price. - ```solidity interface IERC4365Supply is IERC4365 { /** @@ -236,6 +213,29 @@ interface IERC4365Supply is IERC4365 { } ``` +The **Payable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: + +- Implementers SHOULD require recipients to provide funding equal to the token price. + +```solidity +interface IERC4365Payable is IERC4365 { + /** + * @dev Sets the price `amount` for the token of token type `id`. + */ + function setPrice(uint256 id, uint256 amount) external; + + /** + * @dev [Batched] version of {setPrice}. + */ + function setBatchPrices(uint256[] memory ids, uint256[] memory amounts) external; + + /** + * @dev Returns the price for the token type `id`. + */ + function price(uint256 id) external view returns (uint256); +} +``` + ## Rationale ### Overview From 949213d4a65857050f87baf878f96651cd8f2670 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Thu, 23 Mar 2023 10:25:01 +0100 Subject: [PATCH 10/20] Apply suggestions from code review Co-authored-by: Gavin John --- EIPS/eip-draft_title_abbrev.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 7ac31b7babf11..84e55b12c6ad4 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -12,7 +12,7 @@ requires: 165 ## Abstract -[ERC-4365](./eip-draft_title_abbrev.md) outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +This EIP outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. @@ -31,10 +31,10 @@ Additionally, these tokens can be used to create, among others, vouchers, gift c The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -**Every smart contract implementing this ERC MUST implement the all of the functions in the `ERC4365` interface. Additionally, they MUST implement the ERC-165 `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** +**Every smart contract implementing this ERC MUST implement the all of the functions in the `IRedeemableToken` interface. Additionally, they MUST implement the [ERC-165](./eip-165.md) `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity -interface IERC4365 is IERC165 { +interface IRedeemableToken is IERC165 { /** * @dev Emitted when `amount` tokens of token type `id` are minted to `to` by `minter`. */ @@ -131,7 +131,7 @@ In addition, in order for a contract to be compliant with this ERC, it MUST abid - Implementers SHOULD allow token recipients to burn any token they receive. - Implementers MAY enable token issuers to burn the tokens they issued. -**Smart contracts MUST implement all of the functions in the `ERC4365Receiver` interface to accept tokens being minted to them.** +**Smart contracts MUST implement all of the functions in the `IRedeemableTokenReceiver` interface to accept tokens being minted to them.** The **URI Storage extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique URI for each token ID. From 13dd05b751d616ccd3a751007df40d77b49c19ac Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren Date: Thu, 23 Mar 2023 17:17:12 +0100 Subject: [PATCH 11/20] Change name from ERC4365 to RedeemableToken --- EIPS/eip-draft_title_abbrev.md | 20 +++---- .../contracts/examples/Ticket.sol | 8 +-- .../IRedeemableToken.sol} | 2 +- .../IRedeemableTokenReceiver.sol} | 20 +++---- .../RedeemableToken.sol} | 56 +++++++++---------- .../extensions/IRedeemableTokenExpirable.sol} | 6 +- .../extensions/IRedeemableTokenPayable.sol} | 6 +- .../extensions/IRedeemableTokenSupply.sol} | 6 +- .../IRedeemableTokenURIStorage.sol} | 6 +- .../extensions/RedeemableTokenExpirable.sol} | 16 +++--- .../extensions/RedeemableTokenPayable.sol} | 14 ++--- .../extensions/RedeemableTokenSupply.sol} | 26 ++++----- .../extensions/RedeemableTokenURIStorage.sol} | 14 ++--- 13 files changed, 100 insertions(+), 100 deletions(-) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/IERC4365.sol => RedeemableToken/IRedeemableToken.sol} (98%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/IERC4365Receiver.sol => RedeemableToken/IRedeemableTokenReceiver.sol} (63%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/ERC4365.sol => RedeemableToken/RedeemableToken.sol} (83%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/IERC4365Expirable.sol => RedeemableToken/extensions/IRedeemableTokenExpirable.sol} (83%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/IERC4365Payable.sol => RedeemableToken/extensions/IRedeemableTokenPayable.sol} (75%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/IERC4365Supply.sol => RedeemableToken/extensions/IRedeemableTokenSupply.sol} (83%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/IERC4365URIStorage.sol => RedeemableToken/extensions/IRedeemableTokenURIStorage.sol} (70%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/ERC4365Expirable.sol => RedeemableToken/extensions/RedeemableTokenExpirable.sol} (72%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/ERC4365Payable.sol => RedeemableToken/extensions/RedeemableTokenPayable.sol} (73%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/ERC4365Supply.sol => RedeemableToken/extensions/RedeemableTokenSupply.sol} (73%) rename assets/eip-draft_title_abbrev/contracts/token/{ERC4365/extensions/ERC4365URIStorage.sol => RedeemableToken/extensions/RedeemableTokenURIStorage.sol} (82%) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 84e55b12c6ad4..286592a48a3ee 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -12,7 +12,7 @@ requires: 165 ## Abstract -This EIP outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. +This ERC outlines a smart contract interface that can represent any number of fungible and non-fungible redeemable token types. The standard builds upon the [ERC-1155](./eip-1155.md) standard borrowing many of the ideas introduced by it including support for multiple tokens within the same contract and batch operations. Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. @@ -136,7 +136,7 @@ In addition, in order for a contract to be compliant with this ERC, it MUST abid The **URI Storage extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique URI for each token ID. ```solidity -interface IERC4365URIStorage is IERC4365 { +interface IRedeemableTokenURIStorage is IRedeemableToken { /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. */ @@ -149,12 +149,12 @@ interface IERC4365URIStorage is IERC4365 { } ``` -The **Expirable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `ERC4365Expirable` extension MUST abide by the following: +The **Expirable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique expiry date for each token ID. Smart contracts implementing the `RedeemableTokenExpirable` extension MUST abide by the following: - Implementers MUST NOT allow tokens to be minted or redeemed if expired. ```solidity -interface IERC4365Expirable is IERC4365 { +interface IRedeemableTokenExpirable is IRedeemableToken { /** * @dev Sets the expiry date for the token of token type `id`. */ @@ -178,14 +178,14 @@ interface IERC4365Expirable is IERC4365 { } ``` -The **Supply extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `ERC4365Supply` extension MUST abide by the following: +The **Supply extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique max supply for each token ID. Smart contracts implementing the `RedeemableTokenSupply` extension MUST abide by the following: - Implementers SHOULD NOT allow tokens to be minted if total supply exceeds max supply. - Implementers SHOULD increment total supply upon minting and decrement upon burning. - Implementers are RECOMMENDED to override the `_beforeMint` hook to increment total supply upon minting and decrement upon burning. ```solidity -interface IERC4365Supply is IERC4365 { +interface IRedeemableTokenSupply is IRedeemableToken { /** * @dev Sets the max supply for the token of token type `id`. */ @@ -213,12 +213,12 @@ interface IERC4365Supply is IERC4365 { } ``` -The **Payable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `ERC4365Payable` extension MUST abide by the following: +The **Payable extension** is OPTIONAL for compliant smart contracts. This allows contracts to associate a unique price for each token ID. Smart contracts implementing the `RedeemableTokenPayable` extension MUST abide by the following: - Implementers SHOULD require recipients to provide funding equal to the token price. ```solidity -interface IERC4365Payable is IERC4365 { +interface IRedeemableTokenPayable is IRedeemableToken { /** * @dev Sets the price `amount` for the token of token type `id`. */ @@ -264,7 +264,7 @@ Alternatively, a more intuitive approach to represent non-fungible tokens is to ERC-1155, likewise this ERC, conveniently supports batch operations, where a batch is represented by an array of token IDs and an amount for each token ID making it possible to for example mint multiple token IDs in one call. -However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this ERC support bundle operations. A bundle is simply a collection of batches where each batch have a seperate address. +However, a batch often time only concerns one address. While minting a batch of tokens to an address in one transaction is convenient, supporting the ability to mint to multiple addresses in one transaction is even more convenient. Therefore, this ERC supports bundle operations. A bundle is simply a collection of batches where each batch has a separate address. ### Transfer @@ -276,7 +276,7 @@ The core addition to redeemable tokens is the possibility to redeem tokens in ex ### Safe Mint Only -This ERC takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `ERC4365Mint` or `ERC4365MintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. +This ERC takes inspiration from the ERC-1155 standard and only supports safe-style transfers when minting tokens. This enables receiver contracts to depend on `RedeemableTokenMint` or `RedeemableTokenMintBatch` functions to be called at the end of minting. This allows receivers to reject an increase in balance. ## Backwards Compatibility diff --git a/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol b/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol index 8810648578c7f..ff43477393104 100644 --- a/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol +++ b/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol @@ -2,15 +2,15 @@ pragma solidity ^0.8.0; -import "../token/ERC4365/IERC4365.sol"; -import "../token/ERC4365/extensions/ERC4365Expirable.sol"; +import "../token/RedeemableToken/IRedeemableToken.sol"; +import "../token/RedeemableToken/extensions/RedeemableTokenExpirable.sol"; -contract Ticket is ERC4365, ERC4365Expirable { +contract Ticket is RedeemableToken, RedeemableTokenExpirable { using Address for address; address public owner; - constructor(address owner_, string memory baseURI_) ERC4365(baseURI_) { + constructor(address owner_, string memory baseURI_) RedeemableToken(baseURI_) { owner = owner_; } diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol similarity index 98% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol index 32a7ad31f13f6..f57ac2c4aa090 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol @@ -7,7 +7,7 @@ import "../../utils/introspection/IERC165.sol"; * @dev Interface proposal for Redeemable tokens. * Note: The ERC-165 identifier for this interface is 0x9d1da9d1. */ -interface IERC4365 is IERC165 { +interface IRedeemableToken is IERC165 { /** * @dev Emitted when `amount` tokens of token type `id` are minted to `to` by `minter`. */ diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365Receiver.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol similarity index 63% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365Receiver.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol index e1e555bab7e86..5b0c61a4e8cfb 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/IERC4365Receiver.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol @@ -5,22 +5,22 @@ pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** - * Interface for smart contracts wishing to receive ownership of ERC4365 tokens. + * Interface for smart contracts wishing to receive ownership of RedeemableToken tokens. */ -interface IERC4365Receiver is IERC165 { +interface IRedeemableTokenReceiver is IERC165 { /** - * @dev Handles the receipt of a single ERC4365 token type. + * @dev Handles the receipt of a single RedeemableToken token type. * * NOTE: To accept the transfer, this must return - * `bytes4(keccak256("onERC4365Mint(address,address,uint256,uint256,bytes)"))`. + * `bytes4(keccak256("onRedeemableTokenMint(address,address,uint256,uint256,bytes)"))`. * * @param minter The address which initiated minting (i.e. msg.sender). * @param id The ID of the token being transferred. * @param amount The amount of tokens being transferred. * @param data Additional data with no specified format. - * @return `bytes4(keccak256("onERC4365Mint(address,uint256,uint256,bytes)"))` if minting is allowed. + * @return `bytes4(keccak256("onRedeemableTokenMint(address,uint256,uint256,bytes)"))` if minting is allowed. */ - function onERC4365Mint( + function onRedeemableTokenMint( address minter, uint256 id, uint256 amount, @@ -28,18 +28,18 @@ interface IERC4365Receiver is IERC165 { ) external returns (bytes4); /** - * @dev Handles the receipt of multiple ERC4365 token types. + * @dev Handles the receipt of multiple RedeemableToken token types. * * NOTE: To accept the transfer(s), this must return - * `bytes4(keccak256("onERC4365BatchMint(address,address,uint256[],uint256[],bytes)"))`. + * `bytes4(keccak256("onRedeemableTokenBatchMint(address,address,uint256[],uint256[],bytes)"))`. * * @param minter The address which initiated minting (i.e. msg.sender). * @param ids An array containing ids of each token being transferred (order and length must match values array). * @param amounts An array containing amounts of each token being transferred (order and length must match ids array). * @param data Additional data with no specified format. - * @return `bytes4(keccak256("onERC4365BatchMint(address,uint256[],uint256[],bytes)"))` if minting is allowed. + * @return `bytes4(keccak256("onRedeemableTokenBatchMint(address,uint256[],uint256[],bytes)"))` if minting is allowed. */ - function onERC4365BatchMint( + function onRedeemableTokenBatchMint( address minter, uint256[] calldata ids, uint256[] calldata amounts, diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/ERC4365.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/RedeemableToken.sol similarity index 83% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/ERC4365.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/RedeemableToken.sol index b7462aa38aeb0..3bde93a333c30 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/ERC4365.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/RedeemableToken.sol @@ -4,14 +4,14 @@ pragma solidity ^0.8.0; import "../../utils/Address.sol"; import "../../utils/Context.sol"; -import "./IERC4365Receiver.sol"; +import "./IRedeemableTokenReceiver.sol"; import "../../utils/introspection/ERC165.sol"; -import "./IERC4365.sol"; +import "./IRedeemableToken.sol"; /** * @dev Implementation proposal for redeemable tokens (tickets). */ -contract ERC4365 is Context, ERC165, IERC4365 { +contract RedeemableToken is Context, ERC165, IRedeemableToken { using Address for address; // Mapping from token ID to account balances. id => (account => balance) @@ -32,7 +32,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { } /** - * @dev See {IERC4365-redeem}. + * @dev See {IRedeemableToken-redeem}. */ function redeem( address account, @@ -41,7 +41,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { bytes memory data ) external virtual { require(_balances[id][account] >= _redeemed[id][account] + amount, - "ERC4365: redeem amount exceeds balance"); + "RedeemableToken: redeem amount exceeds balance"); _beforeRedeem(account, id, amount, data); @@ -53,7 +53,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) { - return interfaceId == type(IERC4365).interfaceId || super.supportsInterface(interfaceId); + return interfaceId == type(IRedeemableToken).interfaceId || super.supportsInterface(interfaceId); } /** @@ -72,12 +72,12 @@ contract ERC4365 is Context, ERC165, IERC4365 { * @dev See {IERC-4365-balanceOf}. */ function balanceOf(address account, uint256 id) public view virtual returns (uint256) { - require(account != address(0), "ERC4365: address zero is not a valid owner"); + require(account != address(0), "RedeemableToken: address zero is not a valid owner"); return _balances[id][account]; } /** - * @dev See {IERC4365-balanceOfBatch}. + * @dev See {IRedeemableToken-balanceOfBatch}. */ function balanceOfBatch(address account, uint256[] memory ids) public @@ -96,7 +96,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { } /** - * @dev See {IERC4365-balanceOfBundle}. + * @dev See {IRedeemableToken-balanceOfBundle}. */ function balanceOfBundle(address[] memory accounts, uint256[][] memory ids) public @@ -115,15 +115,15 @@ contract ERC4365 is Context, ERC165, IERC4365 { } /** - * @dev See {IERC4365-balanceOfRedeemed}. + * @dev See {IRedeemableToken-balanceOfRedeemed}. */ function balanceOfRedeemed(address account, uint256 id) public view virtual returns (uint256) { - require(account != address(0), "ERC4365: address zero is not a valid owner"); + require(account != address(0), "RedeemableToken: address zero is not a valid owner"); return _redeemed[id][account]; } /** - * @dev See {IERC4365-balanceOfRedeemedBatch}. + * @dev See {IRedeemableToken-balanceOfRedeemedBatch}. */ function balanceOfRedeemedBatch(address account, uint256[] memory ids) public @@ -142,7 +142,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { } /** - * @dev See {IERC4365-balanceOfRedeemedBundle}. + * @dev See {IRedeemableToken-balanceOfRedeemedBundle}. */ function balanceOfRedeemedBundle(address[] memory accounts, uint256[][] memory ids) public @@ -189,7 +189,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { * * Requirements: * - `to` cannot be the zero address. - * - If `to` refers to a smart contract, it must implement [IERC4365REceiver-onERC4365Received] and + * - If `to` refers to a smart contract, it must implement [IRedeemableTokenREceiver-onRedeemableTokenReceived] and * return the acceptance magic value. */ function _mint( @@ -218,7 +218,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { * * Requirements: * - `ids` and `amounts` must have the same length. - * - If `to` refers to a smart contract, it must implement [IERC4365REceiver-onERC4365BatchReceived] and + * - If `to` refers to a smart contract, it must implement [IRedeemableTokenREceiver-onRedeemableTokenBatchReceived] and * return the acceptance magic value. */ function _mintBatch( @@ -275,14 +275,14 @@ contract ERC4365 is Context, ERC165, IERC4365 { uint256 id, uint256 amount ) internal virtual { - require(from != address(0), "ERC4365: burn from the zero address"); + require(from != address(0), "RedeemableToken: burn from the zero address"); address burner = _msgSender(); _beforeBurn(burner, from, id, amount); uint256 fromBalance = _balances[id][from]; - require(fromBalance >= amount, "ERC4365: burn amount exceeds balance"); + require(fromBalance >= amount, "RedeemableToken: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } @@ -303,8 +303,8 @@ contract ERC4365 is Context, ERC165, IERC4365 { uint256[] memory ids, uint256[] memory amounts ) internal virtual { - require(from != address(0), "ERC4365: burn from the zero address"); - require(ids.length == amounts.length, "ERC4365: ids and amounts length mismatch"); + require(from != address(0), "RedeemableToken: burn from the zero address"); + require(ids.length == amounts.length, "RedeemableToken: ids and amounts length mismatch"); address burner = _msgSender(); @@ -315,7 +315,7 @@ contract ERC4365 is Context, ERC165, IERC4365 { _beforeBurn(burner, from, ids[i], amounts[i]); uint256 fromBalance = _balances[id][from]; - require(fromBalance >= amount, "ERC4365: burn amount exceeds balance"); + require(fromBalance >= amount, "RedeemableToken: burn amount exceeds balance"); unchecked { _balances[id][from] = fromBalance - amount; } @@ -375,14 +375,14 @@ contract ERC4365 is Context, ERC165, IERC4365 { bytes memory data ) private { if (to.isContract()) { - try IERC4365Receiver(to).onERC4365Mint(minter, id, amount, data) returns (bytes4 response) { - if (response != IERC4365Receiver.onERC4365Mint.selector) { - revert("ERC4365: ERC4365Receiver rejected tokens"); + try IRedeemableTokenReceiver(to).onRedeemableTokenMint(minter, id, amount, data) returns (bytes4 response) { + if (response != IRedeemableTokenReceiver.onRedeemableTokenMint.selector) { + revert("RedeemableToken: RedeemableTokenReceiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { - revert("ERC4365: mint to non-ERC4365Receiver implementer"); + revert("RedeemableToken: mint to non-RedeemableTokenReceiver implementer"); } } } @@ -395,17 +395,17 @@ contract ERC4365 is Context, ERC165, IERC4365 { bytes memory data ) private { if (to.isContract()) { - try IERC4365Receiver(to).onERC4365BatchMint(minter, ids, amounts, data) returns ( + try IRedeemableTokenReceiver(to).onRedeemableTokenBatchMint(minter, ids, amounts, data) returns ( bytes4 response ) { - if (response != IERC4365Receiver.onERC4365BatchMint.selector) { + if (response != IRedeemableTokenReceiver.onRedeemableTokenBatchMint.selector) { - revert("ERC4365: ERC4365Receiver rejected tokens"); + revert("RedeemableToken: RedeemableTokenReceiver rejected tokens"); } } catch Error(string memory reason) { revert(reason); } catch { - revert("ERC4365: mint to non-ERC4365Receiver implementer"); + revert("RedeemableToken: mint to non-RedeemableTokenReceiver implementer"); } } } diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Expirable.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol similarity index 83% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Expirable.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol index 2c32f6623478e..6e6af8efe99a2 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Expirable.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../IERC4365.sol"; +import "../IRedeemableToken.sol"; /** - * @dev Proposal of an interface for ERC-4365 tokens with an expiry date. + * @dev Proposal of an interface for Redeemable Tokens with an expiry date. * NOTE: The dates are stored as unix timestamps in seconds. */ -interface IERC4365Expirable is IERC4365 { +interface IRedeemableTokenExpirable is IRedeemableToken { /** * @dev Sets the expiry date for the token of token type `id`. */ diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Payable.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol similarity index 75% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Payable.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol index 174b509cbdbd3..038ffdfabd968 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Payable.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../IERC4365.sol"; +import "../IRedeemableToken.sol"; /** - * @dev Proposal of an interface for ERC-4365 tokens with a price. + * @dev Proposal of an interface for Redeemable Tokens with a price. */ -interface IERC4365Payable is IERC4365 { +interface IRedeemableTokenPayable is IRedeemableToken { /** * @dev Sets the price `amount` for the token of token type `id`. */ diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Supply.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol similarity index 83% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Supply.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol index e2566877376e2..520901a4d5f6b 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365Supply.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../IERC4365.sol"; +import "../IRedeemableToken.sol"; /** - * @dev Proposal of an interface for ERC-4365 tokens with a max supply. + * @dev Proposal of an interface for Redeemable Tokens with a max supply. */ -interface IERC4365Supply is IERC4365 { +interface IRedeemableTokenSupply is IRedeemableToken { /** * @dev Sets the max supply for the token of token type `id`. */ diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol similarity index 70% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol index fc83bf3acee1f..4d6c9d8caf843 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/IERC4365URIStorage.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "../IERC4365.sol"; +import "../IRedeemableToken.sol"; import "../../../utils/introspection/IERC165.sol"; /** - * @dev Proposal of an interface for ERC-4365 token with storage based token URI management. + * @dev Proposal of an interface for Redeemable Tokens with storage based token URI management. */ -interface IERC4365URIStorage is IERC4365 { +interface IRedeemableTokenURIStorage is IRedeemableToken { /** * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI. */ diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Expirable.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol similarity index 72% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Expirable.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol index 40b9887805780..cb0aedc272c64 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Expirable.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol @@ -1,13 +1,13 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import "./IERC4365Expirable.sol"; -import "../ERC4365.sol"; +import "./IRedeemableTokenExpirable.sol"; +import "../RedeemableToken.sol"; /** * @dev See {IERC1238Expirable}. */ -abstract contract ERC4365Expirable is ERC4365 { +abstract contract RedeemableTokenExpirable is RedeemableToken { // Optional mapping for token expiry date. mapping(uint256 => uint256) private _expiryDate; @@ -31,7 +31,7 @@ abstract contract ERC4365Expirable is ERC4365 { function expiryDate(uint256 id) public view virtual returns (uint256) { uint256 date = _expiryDate[id]; - require(date != 0, "ERC4365Expirable: no expiry date set"); + require(date != 0, "RedeemableTokenExpirable: no expiry date set"); return date; } @@ -42,7 +42,7 @@ abstract contract ERC4365Expirable is ERC4365 { function isExpired(uint256 id) public view virtual returns (bool) { uint256 date = _expiryDate[id]; - require(date != 0, "ERC4365Expirable: no expiry date set"); + require(date != 0, "RedeemableTokenExpirable: no expiry date set"); return date < block.timestamp; } @@ -54,8 +54,8 @@ abstract contract ERC4365Expirable is ERC4365 { * - The new date must be after the current expiry date. */ function _setExpiryDate(uint256 id, uint256 date) internal virtual { - require(date > block.timestamp, "ERC4365Expirable: expiry date cannot be in the past"); - require(date > _expiryDate[id], "ERC4365Expirable: expiry date can only be extended"); + require(date > block.timestamp, "RedeemableTokenExpirable: expiry date cannot be in the past"); + require(date > _expiryDate[id], "RedeemableTokenExpirable: expiry date can only be extended"); _expiryDate[id] = date; } @@ -64,7 +64,7 @@ abstract contract ERC4365Expirable is ERC4365 { * @dev [Batched] version of {_setExpiryDate}. */ function _setBatchExpiryDates(uint256[] memory ids, uint256[] memory dates) internal { - require(ids.length == dates.length, "ERC4365Expirable: ids and token URIs length mismatch"); + require(ids.length == dates.length, "RedeemableTokenExpirable: ids and token URIs length mismatch"); for (uint256 i = 0; i < ids.length; i++) { _setExpiryDate(ids[i], dates[i]); diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Payable.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol similarity index 73% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Payable.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol index b9ba96d0cc952..a5ec9d60e7d38 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Payable.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.0; -import "./IERC4365Payable.sol"; -import "../ERC4365.sol"; +import "./IRedeemableTokenPayable.sol"; +import "../RedeemableToken.sol"; /** - * @dev See {IERC4365Payable}. + * @dev See {IRedeemableTokenPayable}. */ -abstract contract ERC4365Payable is ERC4365 { +abstract contract RedeemableTokenPayable is RedeemableToken { // Optional mapping for token price. mapping(uint256 => uint256) private _price; @@ -27,11 +27,11 @@ abstract contract ERC4365Payable is ERC4365 { } /** - * @dev See {IERC4365Payable-price}. + * @dev See {IRedeemableTokenPayable-price}. */ function price(uint256 id) public view virtual returns (uint256) { uint256 amount = _price[id]; - require(amount != 0, "ERC4365Pay: no price set"); + require(amount != 0, "RedeemableTokenPay: no price set"); return amount; } @@ -46,7 +46,7 @@ abstract contract ERC4365Payable is ERC4365 { * @dev [Batched] version of {_setPrice}. */ function _setBatchPrices(uint256[] memory ids, uint256[] memory amounts) internal { - require(ids.length == amounts.length, "ERC4365Supply: ids and amounts length mismatch"); + require(ids.length == amounts.length, "RedeemableTokenSupply: ids and amounts length mismatch"); for (uint256 i = 0; i < ids.length; i++) { _setPrice(ids[i], amounts[i]); diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Supply.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol similarity index 73% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Supply.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol index efda6c87dda8b..4a22703249d23 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365Supply.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol @@ -2,13 +2,13 @@ pragma solidity ^0.8.0; -import "./IERC4365Supply.sol"; -import "../ERC4365.sol"; +import "./IRedeemableTokenSupply.sol"; +import "../RedeemableToken.sol"; /** - * @dev See {IERC4365Supply}. + * @dev See {IRedeemableTokenSupply}. */ -abstract contract ERC4365Supply is ERC4365 { +abstract contract RedeemableTokenSupply is RedeemableToken { // Mapping from token ID to total supply. mapping(uint256 => uint256) private _totalSupply; @@ -30,26 +30,26 @@ abstract contract ERC4365Supply is ERC4365 { } /** - * @dev See {IERC4365Supply-totalSupply}. + * @dev See {IRedeemableTokenSupply-totalSupply}. */ function totalSupply(uint256 id) public view virtual returns (uint256) { return _totalSupply[id]; } /** - * @dev See {IERC4365Supply-maxSupply}. + * @dev See {IRedeemableTokenSupply-maxSupply}. */ function maxSupply(uint256 id) public view virtual returns (uint256) { uint256 max = _maxSupply[id]; - require(max != 0, "ERC4365Supply: no maxSupply set"); + require(max != 0, "RedeemableTokenSupply: no maxSupply set"); return max; } /** - * @dev See {IERC4365Supply-exists}. + * @dev See {IRedeemableTokenSupply-exists}. */ function exists(uint256 id) public view virtual returns (bool) { - return ERC4365Supply.totalSupply(id) > 0; + return RedeemableTokenSupply.totalSupply(id) > 0; } /** @@ -63,7 +63,7 @@ abstract contract ERC4365Supply is ERC4365 { * @dev [Batched] version of {setMaxSupply}. */ function _setBatchMaxSupplies(uint256[] memory ids, uint256[] memory amounts) internal { - require(ids.length == amounts.length, "ERC4365Supply: ids and amounts length mismatch"); + require(ids.length == amounts.length, "RedeemableTokenSupply: ids and amounts length mismatch"); for (uint256 i = 0; i < ids.length; i++) { _setMaxSupply(ids[i], amounts[i]); @@ -71,7 +71,7 @@ abstract contract ERC4365Supply is ERC4365 { } /** - * @dev See {ERC4365-_beforeMint}. + * @dev See {RedeemableToken-_beforeMint}. */ function _beforeMint( address minter, @@ -86,7 +86,7 @@ abstract contract ERC4365Supply is ERC4365 { } /** - * @dev See {ERC4365-_beforeBurn. + * @dev See {RedeemableToken-_beforeBurn. */ function _beforeBurn( address burner, @@ -96,7 +96,7 @@ abstract contract ERC4365Supply is ERC4365 { ) internal virtual override { super._beforeBurn(burner, from, id, amount); - require(_totalSupply[id] >= amount, "ERC4365: burn amount exceeds totalSupply"); + require(_totalSupply[id] >= amount, "RedeemableToken: burn amount exceeds totalSupply"); unchecked { _totalSupply[id] -= amount; } diff --git a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol similarity index 82% rename from assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol rename to assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol index 9c1a8d27ffc22..0b71c39d5e583 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/ERC4365/extensions/ERC4365URIStorage.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol @@ -2,14 +2,14 @@ pragma solidity ^0.8.0; -import "../ERC4365.sol"; +import "../RedeemableToken.sol"; import "../../../utils/introspection/ERC165.sol"; -import "./IERC4365URIStorage.sol"; +import "./IRedeemableTokenURIStorage.sol"; /** - * @dev See {IERC4365URIStorage}. + * @dev See {IRedeemableTokenURIStorage}. */ -abstract contract ERC4365URIStorage is ERC165, IERC4365URIStorage, ERC4365 { +abstract contract RedeemableTokenURIStorage is ERC165, IRedeemableTokenURIStorage, RedeemableToken { // Optional mapping for token URIs. mapping(uint256 => string) private _tokenURIs; @@ -17,14 +17,14 @@ abstract contract ERC4365URIStorage is ERC165, IERC4365URIStorage, ERC4365 { public view virtual - override(ERC4365, ERC165, IERC165) + override(RedeemableToken, ERC165, IERC165) returns (bool) { - return interfaceId == type(IERC4365URIStorage).interfaceId || super.supportsInterface(interfaceId); + return interfaceId == type(IRedeemableTokenURIStorage).interfaceId || super.supportsInterface(interfaceId); } /** - * @dev See {IERC4365URIStorage-tokenURI}. + * @dev See {IRedeemableTokenURIStorage-tokenURI}. */ function tokenURI(uint256 id) public view virtual override returns (string memory) { string memory _tokenURI = _tokenURIs[id]; From 47cd39af9eec4393c11edc6c9e37011394ff78e5 Mon Sep 17 00:00:00 2001 From: LucazFFz Date: Thu, 23 Mar 2023 18:17:59 +0100 Subject: [PATCH 12/20] Fix minor grammatical issues --- EIPS/eip-draft_title_abbrev.md | 2 +- .../contracts/token/RedeemableToken/IRedeemableToken.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 286592a48a3ee..68b7ed3f74238 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -31,7 +31,7 @@ Additionally, these tokens can be used to create, among others, vouchers, gift c The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. -**Every smart contract implementing this ERC MUST implement the all of the functions in the `IRedeemableToken` interface. Additionally, they MUST implement the [ERC-165](./eip-165.md) `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** +**Every smart contract implementing this ERC MUST implement all of the functions in the `IRedeemableToken` interface. Additionally, they MUST implement the [ERC-165](./eip-165.md) `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity interface IRedeemableToken is IERC165 { diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol index f57ac2c4aa090..0be4a2e5e4c13 100644 --- a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol +++ b/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol @@ -5,7 +5,7 @@ import "../../utils/introspection/IERC165.sol"; /** * @dev Interface proposal for Redeemable tokens. - * Note: The ERC-165 identifier for this interface is 0x9d1da9d1. + * Note: The ERC-165 identifier for this interface is 0x9d1da9d1. */ interface IRedeemableToken is IERC165 { /** From 34e555e1a8337564612ecac5362c375d81ad0a37 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Fri, 24 Mar 2023 17:14:06 +0100 Subject: [PATCH 13/20] Update EIPS/eip-draft_title_abbrev.md Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com> --- EIPS/eip-draft_title_abbrev.md | 1 + 1 file changed, 1 insertion(+) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-draft_title_abbrev.md index 68b7ed3f74238..b5c68511261b5 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-draft_title_abbrev.md @@ -1,4 +1,5 @@ --- +eip: 6732 title: Redeemable Tokens description: A proposition for redeemable tokens author: Lucaz Lindgren (@LucazFFz) From 4699fd28a9fe6edb1cde348777a0d4e926c31a15 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:00:41 +0200 Subject: [PATCH 14/20] Change to assigned eip number --- EIPS/{eip-draft_title_abbrev.md => eip-6732.md} | 2 +- assets/{eip-draft_title_abbrev => eip-6732}/.gitignore | 0 assets/{eip-draft_title_abbrev => eip-6732}/README.md | 0 assets/{eip-draft_title_abbrev => eip-6732}/contracts/.gitkeep | 0 .../contracts/Migrations.sol | 0 .../contracts/examples/Ticket.sol | 0 .../contracts/token/RedeemableToken/IRedeemableToken.sol | 0 .../token/RedeemableToken/IRedeemableTokenReceiver.sol | 0 .../contracts/token/RedeemableToken/RedeemableToken.sol | 0 .../RedeemableToken/extensions/IRedeemableTokenExpirable.sol | 0 .../RedeemableToken/extensions/IRedeemableTokenPayable.sol | 0 .../token/RedeemableToken/extensions/IRedeemableTokenSupply.sol | 0 .../RedeemableToken/extensions/IRedeemableTokenURIStorage.sol | 0 .../RedeemableToken/extensions/RedeemableTokenExpirable.sol | 0 .../token/RedeemableToken/extensions/RedeemableTokenPayable.sol | 0 .../token/RedeemableToken/extensions/RedeemableTokenSupply.sol | 0 .../RedeemableToken/extensions/RedeemableTokenURIStorage.sol | 0 .../contracts/utils/Address.sol | 0 .../contracts/utils/Context.sol | 0 .../contracts/utils/Strings.sol | 0 .../contracts/utils/introspection/ERC165.sol | 0 .../contracts/utils/introspection/IERC165.sol | 0 .../contracts/utils/math/Math.sol | 0 assets/{eip-draft_title_abbrev => eip-6732}/migrations/.gitkeep | 0 .../migrations/1_initial_migration.js | 0 .../migrations/2_deploy_contracts.js | 0 assets/{eip-draft_title_abbrev => eip-6732}/test/.gitkeep | 0 assets/{eip-draft_title_abbrev => eip-6732}/truffle-config.js | 0 28 files changed, 1 insertion(+), 1 deletion(-) rename EIPS/{eip-draft_title_abbrev.md => eip-6732.md} (99%) rename assets/{eip-draft_title_abbrev => eip-6732}/.gitignore (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/README.md (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/.gitkeep (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/Migrations.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/examples/Ticket.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/IRedeemableToken.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/RedeemableToken.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/Address.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/Context.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/Strings.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/introspection/ERC165.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/introspection/IERC165.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/contracts/utils/math/Math.sol (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/migrations/.gitkeep (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/migrations/1_initial_migration.js (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/migrations/2_deploy_contracts.js (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/test/.gitkeep (100%) rename assets/{eip-draft_title_abbrev => eip-6732}/truffle-config.js (100%) diff --git a/EIPS/eip-draft_title_abbrev.md b/EIPS/eip-6732.md similarity index 99% rename from EIPS/eip-draft_title_abbrev.md rename to EIPS/eip-6732.md index b5c68511261b5..2d4cdcc39a84e 100644 --- a/EIPS/eip-draft_title_abbrev.md +++ b/EIPS/eip-6732.md @@ -3,7 +3,7 @@ eip: 6732 title: Redeemable Tokens description: A proposition for redeemable tokens author: Lucaz Lindgren (@LucazFFz) -discussions-to: https://ethereum-magicians.org/t/eip-4365-redeemable-tokens/13441 +discussions-to: https://ethereum-magicians.org/t/eip-6732-redeemable-tokens/13441 status: Draft type: Standards Track category: ERC diff --git a/assets/eip-draft_title_abbrev/.gitignore b/assets/eip-6732/.gitignore similarity index 100% rename from assets/eip-draft_title_abbrev/.gitignore rename to assets/eip-6732/.gitignore diff --git a/assets/eip-draft_title_abbrev/README.md b/assets/eip-6732/README.md similarity index 100% rename from assets/eip-draft_title_abbrev/README.md rename to assets/eip-6732/README.md diff --git a/assets/eip-draft_title_abbrev/contracts/.gitkeep b/assets/eip-6732/contracts/.gitkeep similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/.gitkeep rename to assets/eip-6732/contracts/.gitkeep diff --git a/assets/eip-draft_title_abbrev/contracts/Migrations.sol b/assets/eip-6732/contracts/Migrations.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/Migrations.sol rename to assets/eip-6732/contracts/Migrations.sol diff --git a/assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol b/assets/eip-6732/contracts/examples/Ticket.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/examples/Ticket.sol rename to assets/eip-6732/contracts/examples/Ticket.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol b/assets/eip-6732/contracts/token/RedeemableToken/IRedeemableToken.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableToken.sol rename to assets/eip-6732/contracts/token/RedeemableToken/IRedeemableToken.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol b/assets/eip-6732/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol rename to assets/eip-6732/contracts/token/RedeemableToken/IRedeemableTokenReceiver.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/RedeemableToken.sol b/assets/eip-6732/contracts/token/RedeemableToken/RedeemableToken.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/RedeemableToken.sol rename to assets/eip-6732/contracts/token/RedeemableToken/RedeemableToken.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenExpirable.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenPayable.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenSupply.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/IRedeemableTokenURIStorage.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenExpirable.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenPayable.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenSupply.sol diff --git a/assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol b/assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol rename to assets/eip-6732/contracts/token/RedeemableToken/extensions/RedeemableTokenURIStorage.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/Address.sol b/assets/eip-6732/contracts/utils/Address.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/Address.sol rename to assets/eip-6732/contracts/utils/Address.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/Context.sol b/assets/eip-6732/contracts/utils/Context.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/Context.sol rename to assets/eip-6732/contracts/utils/Context.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/Strings.sol b/assets/eip-6732/contracts/utils/Strings.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/Strings.sol rename to assets/eip-6732/contracts/utils/Strings.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/introspection/ERC165.sol b/assets/eip-6732/contracts/utils/introspection/ERC165.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/introspection/ERC165.sol rename to assets/eip-6732/contracts/utils/introspection/ERC165.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/introspection/IERC165.sol b/assets/eip-6732/contracts/utils/introspection/IERC165.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/introspection/IERC165.sol rename to assets/eip-6732/contracts/utils/introspection/IERC165.sol diff --git a/assets/eip-draft_title_abbrev/contracts/utils/math/Math.sol b/assets/eip-6732/contracts/utils/math/Math.sol similarity index 100% rename from assets/eip-draft_title_abbrev/contracts/utils/math/Math.sol rename to assets/eip-6732/contracts/utils/math/Math.sol diff --git a/assets/eip-draft_title_abbrev/migrations/.gitkeep b/assets/eip-6732/migrations/.gitkeep similarity index 100% rename from assets/eip-draft_title_abbrev/migrations/.gitkeep rename to assets/eip-6732/migrations/.gitkeep diff --git a/assets/eip-draft_title_abbrev/migrations/1_initial_migration.js b/assets/eip-6732/migrations/1_initial_migration.js similarity index 100% rename from assets/eip-draft_title_abbrev/migrations/1_initial_migration.js rename to assets/eip-6732/migrations/1_initial_migration.js diff --git a/assets/eip-draft_title_abbrev/migrations/2_deploy_contracts.js b/assets/eip-6732/migrations/2_deploy_contracts.js similarity index 100% rename from assets/eip-draft_title_abbrev/migrations/2_deploy_contracts.js rename to assets/eip-6732/migrations/2_deploy_contracts.js diff --git a/assets/eip-draft_title_abbrev/test/.gitkeep b/assets/eip-6732/test/.gitkeep similarity index 100% rename from assets/eip-draft_title_abbrev/test/.gitkeep rename to assets/eip-6732/test/.gitkeep diff --git a/assets/eip-draft_title_abbrev/truffle-config.js b/assets/eip-6732/truffle-config.js similarity index 100% rename from assets/eip-draft_title_abbrev/truffle-config.js rename to assets/eip-6732/truffle-config.js From 54cd1ff36feebbef100224ab94a01f75f6fd44a1 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Tue, 28 Mar 2023 12:16:06 +0200 Subject: [PATCH 15/20] Update eip-6732.md --- EIPS/eip-6732.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index 2d4cdcc39a84e..9509993b6906b 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -285,7 +285,7 @@ Because of the heavy inspiration from the ERC-1155 standard many concepts and me ## Reference Implementation -- [Reference implementation](../assets/eip-draft_title_abbrev/) +- [Reference implementation](../assets/eip-6732/) ## Security Considerations From 68a8c0a43999253dd53f9c87eefb8bec0aabf5d8 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:58:05 +0200 Subject: [PATCH 16/20] Update EIPS/eip-6732.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-6732.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index 9509993b6906b..c722d88307298 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -1,7 +1,7 @@ --- eip: 6732 title: Redeemable Tokens -description: A proposition for redeemable tokens +description: An interface for tokens that can be exchanged for a reward or other action author: Lucaz Lindgren (@LucazFFz) discussions-to: https://ethereum-magicians.org/t/eip-6732-redeemable-tokens/13441 status: Draft From f2dda34e4ecfc362f8cb7477a39844b3ca5149e8 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:58:30 +0200 Subject: [PATCH 17/20] Update EIPS/eip-6732.md Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com> --- EIPS/eip-6732.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index c722d88307298..a5dd060f42f67 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -35,7 +35,7 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S **Every smart contract implementing this ERC MUST implement all of the functions in the `IRedeemableToken` interface. Additionally, they MUST implement the [ERC-165](./eip-165.md) `supportsInterface` function and MUST return the constant value `true` if the constant value `0x9d1da9d1` is passed through the `interfaceId` argument.** ```solidity -interface IRedeemableToken is IERC165 { +interface IRedeemableToken /* is IERC165 */ { /** * @dev Emitted when `amount` tokens of token type `id` are minted to `to` by `minter`. */ From 10017497e3b86e14be8c70706fc9b734d3da3666 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Thu, 20 Apr 2023 12:29:00 +0200 Subject: [PATCH 18/20] Update eip-6732.md --- EIPS/eip-6732.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index a5dd060f42f67..939d581eace91 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -17,6 +17,8 @@ This ERC outlines a smart contract interface that can represent any number of fu Contrary to the ERC-1155 standard, this ERC does not enforce transferability as it recognizes situations where implementers might not want to allow it. Additionally, it introduces several extensions used to expand the functionality like the **Expirable extension** which provides a simple way to add an expiry date to tokens. +Redeem in the context of this ERC represent the action of exchanging an item (like a coupon, ticket, or something similar) for money, an award, etc. + ## Motivation The core idea of this ERC is to standardize and simplify the development of redeemable tokens (tickets) on the Ethereum blockchain. The tokens can be redeemed in exchange for currency or access (the reward for redeeming is left to implementers). The tokens can be exchanged for real-world or digital rewards. From 1c2c7407ffabfaf275d518e7fbdd18b728dae086 Mon Sep 17 00:00:00 2001 From: Lucaz Lindgren <96021478+LucazFFz@users.noreply.github.com> Date: Thu, 20 Apr 2023 12:37:30 +0200 Subject: [PATCH 19/20] Update EIPS/eip-6732.md --- EIPS/eip-6732.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index 939d581eace91..fd081018d11b0 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -257,7 +257,7 @@ This standard does not assume who has the power to mint/burn tokens nor under wh ### Fungibility -This ERC, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable Tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. +This ERC, likewise ERC-1155, chooses to stay agnostic regarding the fungibility of redeemable tokens. It recognizes that it may be useful in some cases to have both fungible and non-fungible redeemable tokens managed in the same contract. One way to achieve non-fungible tokens is to utilize split ID bits reserving the top 128 bits of the 256 bits `id` parameter to represent the base token ID while using the bottom 128 bits to represent the index of the non-fungible to make it unique. From 580a4a7dae901e69122f6699f90e9d7f2f5f3378 Mon Sep 17 00:00:00 2001 From: Sam Wilson Date: Wed, 13 Sep 2023 17:46:48 -0400 Subject: [PATCH 20/20] 6732: Minor tweaks --- EIPS/eip-6732.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EIPS/eip-6732.md b/EIPS/eip-6732.md index fd081018d11b0..28a8b1c589007 100644 --- a/EIPS/eip-6732.md +++ b/EIPS/eip-6732.md @@ -287,11 +287,11 @@ Because of the heavy inspiration from the ERC-1155 standard many concepts and me ## Reference Implementation -- [Reference implementation](../assets/eip-6732/) +- [Reference implementation](../assets/eip-6732/README.md) ## Security Considerations -Needs discussion. + ## Copyright