Skip to content

Commit 4800bc3

Browse files
authored
Update ERC-7590: Handles erc20s with transfer fees.
Merged by EIP-Bot.
1 parent 27c7722 commit 4800bc3

File tree

2 files changed

+21
-2
lines changed

2 files changed

+21
-2
lines changed

ERCS/erc-7590.md

+4
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ Caution is advised when dealing with non-audited contracts.
179179

180180
Implementations MUST use the message sender as from parameter when they are transferring tokens into an NFT. Otherwise, since the current contract needs approval, it could potentially pull the external tokens into a different NFT.
181181

182+
When transferring [ERC-20](./eip-20.md) tokens in or out of an NFT, it could be the case that the amount transferred is not the same as the amount requested. This could happen if the [ERC-20](./eip-20.md) contract has a fee on transfer. This could cause a bug on your Token Holder contract if you do not manage it properly. There are 2 ways to do it, both of which are valid:
183+
1. Use the `IERC20` interface to check the balance of the contract before and after the transfer, and revert if the balance is not the expected one, hence not supporting tokens with fees on transfer.
184+
2. Use the `IERC20` interface to check the balance of the contract before and after the transfer, and use the difference to calculate the amount of tokens that were actually transferred.
185+
182186
To prevent a seller from front running the sale of an NFT holding [ERC-20](./eip-20.md) tokens to transfer out such tokens before a sale is executed, marketplaces MUST beware of the `erc20TransferOutNonce` and revert if it has changed since listed.
183187

184188
[ERC-20](./eip-20.md) tokens that are transferred directly to the NFT contract will be lost.

assets/erc-7590/contracts/AbstractERC7590.sol

+17-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
88
error InvalidValue();
99
error InvalidAddress();
1010
error InsufficientBalance();
11+
error InvalidAmountTransferred();
1112

1213
abstract contract AbstractERC7590 is IERC7590 {
1314
mapping(uint256 tokenId => mapping(address erc20Address => uint256 balance))
@@ -57,10 +58,17 @@ abstract contract AbstractERC7590 is IERC7590 {
5758
amount,
5859
data
5960
);
61+
IERC20 erc20 = IERC20(erc20Contract);
62+
uint256 initBalance = erc20.balanceOf(address(this));
6063
_balances[tokenId][erc20Contract] -= amount;
6164
_erc20TransferOutNonce[tokenId]++;
6265

63-
IERC20(erc20Contract).transfer(to, amount);
66+
erc20.transfer(to, amount);
67+
uint256 newBalance = erc20.balanceOf(address(this));
68+
// Here you can either use the difference as the amount, or revert if the difference is not equal to the amount and you don't want to support transfer fees
69+
if (newBalance + amount != initBalance) {
70+
revert InvalidAmountTransferred();
71+
}
6472

6573
emit TransferredERC20(erc20Contract, tokenId, to, amount);
6674
_afterTransferHeldERC20FromToken(
@@ -94,7 +102,14 @@ abstract contract AbstractERC7590 is IERC7590 {
94102
amount,
95103
data
96104
);
97-
IERC20(erc20Contract).transferFrom(msg.sender, address(this), amount);
105+
IERC20 erc20 = IERC20(erc20Contract);
106+
uint256 initBalance = erc20.balanceOf(address(this));
107+
erc20.transferFrom(msg.sender, address(this), amount);
108+
uint256 newBalance = erc20.balanceOf(address(this));
109+
// Here you can either use the difference as the amount, or revert if the difference is not equal to the amount and you don't want to support transfer fees
110+
if (initBalance + amount != newBalance) {
111+
revert InvalidAmountTransferred();
112+
}
98113
_balances[tokenId][erc20Contract] += amount;
99114

100115
emit ReceivedERC20(erc20Contract, tokenId, msg.sender, amount);

0 commit comments

Comments
 (0)