Skip to content

Commit

Permalink
Merge d3f7827 into 3c52209
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanmmurciaua authored Jul 23, 2022
2 parents 3c52209 + d3f7827 commit 9523834
Show file tree
Hide file tree
Showing 11 changed files with 1,352 additions and 0 deletions.
116 changes: 116 additions & 0 deletions EIPS/eip-5216.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
eip: 5216
title: EIP-1155 Approval By Amount Extension
description: Extension for EIP-1155 secure approvals
author: Iván Mañús Murcia, Juan Carlos Cantó Martinez (@EscuelaCrypto in Telegram)
discussions-to: https://ethereum-magicians.org/t/eip-erc1155-approval-by-amount/9898
status: Draft
type: Standards Track
category: ERC
created: 2022-07-11
requires: 20, 1155
---

## Abstract

This specification defines standard functions for approving amounts of an [ERC-1155](./eip-1155.md). An implementation allows approve by id, different amounts both batch and individual. The proposal depends on and extends the existing [ERC-1155](./eip-1155.md).

## Motivation

[ERC-1155](./eip-1155.md) has created a scenario where multiple token management and transactions occur on a daily basis. Although it can be used as [ERC-721](./eip-721.md), the most common way to use it is to create collections through its `ids` in order to have an indefinite `amount` of tokens of one type. These tokens have been implemented in a wide variety of projects, but the most important are marketplaces.
The nature of tokens is trading, transfer and use, so it is important that your peer-to-peer transactions are as secure as possible.

The way the [ERC-1155](./eip-1155.md) standard approves tokens is with the `setApprovalForAll(address operator, bool approved)` function, which approves ALL tokens of an `id`. However, this is a standard that combines ideas from the [ERC-20](./eip-20.md) and [ERC-721](./eip-721.md) standards, and it is important to create a trust mechanism, where an owner can allow a third party, such as a marketplace, to approve a limited number of tokens of an `id` and not all at once.

In turn, it is also necessary to subtract the amount of tokens approved once they have been successfully transferred to avoid the scenario that we have now, where ALL tokens of an `id` are approved without revoking that approval at any time. In our honest opinion, this is quite dangerous because if you don't revoke that approval with `setApprovalForAll(operatorAddress, false)`, you let that the operator do whateaver he wants whenever he wants with all your tokens.

By having a way to approve and revoke as the [ERC-20](./eip-20.md) standard works, i.e. by amounts we reduce that security problem:

- By `approve` function, we allow an operator to use an amount of tokens per id.
- Through the function `allowance` you can see the amount of tokens that an approved account has per id.

Both following the [ERC-20](./eip-20.md) standard name patterns.


## Specification

The keywords “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

Every contract compliant to the `ERC1155ApprovalByAmount` extension MUST implement the `IERC1155ApprovalByAmount` interface. The **approval by amount extension** is OPTIONAL for [ERC-1155](./eip-1155.md) contracts.

### Interface implementation

```solidity
/**
* @title ERC-1155 Approval By Amount Extension
* Note: the ERC-165 identifier for this interface is 0x1be07d74
*/
interface IERC1155ApprovalByAmount is IERC1155 {
/**
* @notice Emmited when `account` grants or revokes permission to `operator` to transfer their tokens, according to
* `id` and with an amount: `amount`.
*/
event ApprovalByAmount(address indexed account, address indexed operator, uint256 id, uint256 amount);
/**
* @notice Grants permision to `operator` to transfer the caller's tokens, according to `id`, and an amount: `amount`.
* Emits an {ApprovalByAmount} event.
*
* Requirements:
* - `operator` cannot be the caller.
*/
function approve(address operator, uint256 id, uint256 amount) external;
/**
* @notice Returns the amount allocated to `operator` approved to transfer ``account``'s tokens, according to `id`.
*/
function allowance(address account, address operator, uint256 id) external view returns (uint256);
}
```

The `_allowances` mapping MAY be implemented as `internal` or `private`.

The `approve(address operator, uint256 id, uint256 amount)` function MAY be implemented as `public` or `external` and it is RECOMMENDED implements `private` `_approve(address owner, address operator, uint256 id, uint256 amount)` function, which is responsible for performing the approval.

The `allowance(address account, address operator, uint256 id)` function MAY be implemented as `public` or `external` for visibility and MUST be implemented as `view`.

Every contract implementing the `ERC1155ApprovalByAmount` extension MUST implement `_checkApprovalForBatch(address from, address to, uint256[] memory ids, uint256[] memory amounts)` function in some way. This function is necessary to manage
batch transfers subtracting the amount of tokens transferred.

In same way, `safe(Batch)TrasferFrom` overrided function from `ERC1155` standard it is also important to change its implementation:

- In `safeTransferFrom` MUST be added to require an extra condition: `|| allowance(from, _msgSender(), id)`.
- In `safeTransferFrom` MUST be subtracted from `_allowances` mapping the transferred amount of tokens: `_allowances[from][_msgSender()][id] -= amount`.
- In `safeBatchTransferFrom` MUST be added to require an extra condition that checks if the `allowance` of all `ids` have the approved `amounts` (See `_checkApprovalForBatch` function reference implementation)

The `ApprovalByAmount` event MUST be emitted when a certain number of tokens are approved.

The `supportsInterface` method MUST return `true` when called with `0x1be07d74`.

## Rationale

The chosen name resonates with the purpose of its existence. Users can approve their tokens by id and amounts to `operators`.

The [ERC-20](./eip-20.md) standard name patterns, were used to simplify the understanding of how the interface works due to similarity with how [ERC-20](./eip-20.md) works with approvals.

## Backwards Compatibility

This standard is compatible with current [ERC-1155](./eip-1155.md) standards.

## Test Cases

Test cases are available in the reference implementation [here](../assets/eip-5216/test/erc1155approvalbyamount.js).

## Reference Implementation

The reference implementation can be found [here](../assets/eip-5216/contracts/ERC1155ApprovalByAmount.sol).

## Security Considerations

Implementors of the `ERC1155ApprovalByAmount` standard must consider thoroughly the amount of tokens they give permission to `operators`. They should also revoke the rest.

## Copyright

Copyright and related rights waived via [CC0](https://eips.ethereum.org/LICENSE).
11 changes: 11 additions & 0 deletions assets/eip-5216/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
node_modules

node_modules
.env
coverage
coverage.json
typechain

#Hardhat files
cache
artifacts
51 changes: 51 additions & 0 deletions assets/eip-5216/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<div align="center">

# ERC1155 Approval By Amount Extension

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

</div>

## Install

In order to install the required dependencies you need to execute:
```shell
npm install
```

## Compile

In order to compile the solidity contracts you need to execute:
```shell
npx hardhat compile
```

## Tests
In order to test the contracts you need to execute:

```shell
npx hardhat test
```

#### Results
Here are the results:
```
ERC1155ApprovalByAmount
approve
✔ Approve id 0 for U1 with an amount of 10 (141ms)
✔ Should revert when owner try to approve himself (134ms)
safeTransferFrom
✔ Should revert when caller isn't the from param (63ms)
✔ Should revert when id to transfer is not approved and caller != from (63ms)
✔ Transfer 10 1155-0 to U2 by owner (116ms)
✔ Transfer 10 1155-0 to U1 call by himself (136ms)
✔ Should revert when U1 try to transfer 1 1155-0 to himself with allowance actual in 0 (60ms)
safeBatchTransferFrom
✔ Approve id 1 for U1 with an amount of 10 (122ms)
✔ Should be reverted because Id 0 is not approved for U1 (70ms)
✔ Transfer 10 of 0 and 1 from owner to U2 (153ms)
✔ Approve for Id 0 and transfer 10 of 0 and 1 to U1 (239ms)
12 passing (5s)
```
Loading

0 comments on commit 9523834

Please sign in to comment.