Skip to content

Commit

Permalink
fix: emit correct transfer and approval events (#194) (#215)
Browse files Browse the repository at this point in the history
Signed-off-by: Mariusz Jasuwienas <[email protected]>
  • Loading branch information
arianejasuwienas authored Jan 29, 2025
1 parent eed1e21 commit e4a7e92
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 40 deletions.
76 changes: 51 additions & 25 deletions README.md

Large diffs are not rendered by default.

15 changes: 7 additions & 8 deletions contracts/HtsSystemContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {SetTokenInfo} from "./SetTokenInfo.sol";

address constant HTS_ADDRESS = address(0x167);

contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
contract HtsSystemContract is IHederaTokenService {

/**
* The slot's value contains the next token ID to use when a token is being created.
Expand Down Expand Up @@ -574,7 +574,7 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
address to = address(bytes20(msg.data[72:92]));
uint256 amount = uint256(bytes32(msg.data[92:124]));
_approve(from, to, amount);
emit Approval(from, to, amount);
emit IERC20Events.Approval(from, to, amount);
return abi.encode(true);
}
if (selector == this.approveNFT.selector) {
Expand Down Expand Up @@ -670,7 +670,7 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
uint256 amount = uint256(bytes32(msg.data[60:92]));
address owner = msg.sender;
_approve(owner, spender, amount);
emit Approval(owner, spender, amount);
emit IERC20Events.Approval(owner, spender, amount);
return abi.encode(true);
}
return _redirectForHRC719(selector);
Expand Down Expand Up @@ -844,7 +844,7 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
require(from != address(0), "hts: invalid sender");
require(to != address(0), "hts: invalid receiver");
_update(from, to, amount);
emit Transfer(from, to, amount);
emit IERC20Events.Transfer(from, to, amount);
}

function _transferNFT(address sender, address from, address to, uint256 serialId) private {
Expand Down Expand Up @@ -872,7 +872,7 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {

// Set the new owner
assembly { sstore(slot, to) }
emit Transfer(from, to, serialId);
emit IERC721Events.Transfer(from, to, serialId);
}

function _update(address from, address to, uint256 amount) public {
Expand Down Expand Up @@ -917,8 +917,7 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
bytes32 slot = _getApprovedSlot(uint32(serialId));
address newApproved = isApproved ? spender : address(0);
assembly { sstore(slot, newApproved) }

emit Approval(owner, spender, serialId);
emit IERC721Events.Approval(owner, spender, serialId);
}

/**
Expand All @@ -939,6 +938,6 @@ contract HtsSystemContract is IHederaTokenService, IERC20Events, IERC721Events {
require(operator != address(0) && operator != sender, "setApprovalForAll: invalid operator");
bytes32 slot = _isApprovedForAllSlot(sender, operator);
assembly { sstore(slot, approved) }
emit ApprovalForAll(sender, operator, approved);
emit IERC721Events.ApprovalForAll(sender, operator, approved);
}
}
2 changes: 1 addition & 1 deletion contracts/IERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface IERC20 {

/**
* @dev Returns the value of tokens owned by `account`.
*/
*/
function balanceOf(address account) external view returns (uint256);

/**
Expand Down
27 changes: 27 additions & 0 deletions contracts/IERC721.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,34 @@
pragma solidity ^0.8.0;

/**
* These events should be emitted by `transfer|transferFrom`, `approve` and `setApprovalForAll` respectively.
*
* See https://ethereum.org/en/developers/docs/standards/tokens/erc-721/#events for more information.
*/
interface IERC721Events {
/**
* @dev Emitted when ownership of any NFT changes by any mechanism.
* This event emits when NFTs are created (`from` == 0) and destroyed (`to` == 0).
* Otherwise, it indicates that the token with ID {tokenId} was transferred from {from} to {to},
* where {from} represents the previous owner of the token, not the approved spender.
*
* Exception: during contract creation, any number of NFTs may be created and assigned without emitting Transfer.
*
* At the time of any transfer, the approved address for that NFT (if any) is reset to none.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

/**
* @dev Emitted when the approved address for an NFT is changed or reaffirmed from {from} to {to} address.
* The zero {to} address indicates there will be no approved address.
* Additionally the approved address for that NFT (if any) is reset to none.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

/**
* @dev Emitted when an operator {operator} is enabled or disabled {approved}
* for an owner {owner}. The operator {operator} can than manage all NFTs of the owner {owner}.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}

Expand Down Expand Up @@ -45,6 +70,8 @@ interface IERC721 {
*
* Requirements:
* - `serialId` must exist.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function ownerOf(uint256 serialId) external view returns (address);

Expand Down
3 changes: 1 addition & 2 deletions test/ERC721.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ pragma solidity ^0.8.0;
import {HtsSystemContract} from "../contracts/HtsSystemContract.sol";
import {Test, console} from "forge-std/Test.sol";
import {IERC721, IERC721Events} from "../contracts/IERC721.sol";
import {IERC20Events} from "../contracts/IERC20.sol";
import {TestSetup} from "./lib/TestSetup.sol";

contract ERC721TokenTest is Test, TestSetup, IERC721Events, IERC20Events {
contract ERC721TokenTest is Test, TestSetup, IERC721Events {

function setUp() external {
setUpMockStorageForNonFork();
Expand Down
8 changes: 4 additions & 4 deletions test/HTS.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ contract HTSTest is Test, TestSetup {
uint256 serialId = 1;
vm.startPrank(CFNFTFF_TREASURY);
vm.expectEmit(CFNFTFF);
emit IERC20Events.Transfer(CFNFTFF_TREASURY, to, serialId);
emit IERC721Events.Transfer(CFNFTFF_TREASURY, to, serialId);
IHederaTokenService(HTS_ADDRESS).transferNFT(CFNFTFF, CFNFTFF_TREASURY, to, int64(int256(serialId)));
vm.stopPrank();
assertEq(IERC721(CFNFTFF).ownerOf(serialId), to);
Expand All @@ -697,7 +697,7 @@ contract HTSTest is Test, TestSetup {
uint256 serialId = 1;
vm.startPrank(CFNFTFF_TREASURY);
vm.expectEmit(CFNFTFF);
emit IERC20Events.Transfer(CFNFTFF_TREASURY, to, serialId);
emit IERC721Events.Transfer(CFNFTFF_TREASURY, to, serialId);
IHederaTokenService(HTS_ADDRESS).transferFromNFT(CFNFTFF, CFNFTFF_TREASURY, to, serialId);
vm.stopPrank();
assertEq(IERC721(CFNFTFF).ownerOf(serialId), to);
Expand Down Expand Up @@ -770,7 +770,7 @@ contract HTSTest is Test, TestSetup {
to[0] = makeAddr("recipient");
vm.startPrank(CFNFTFF_TREASURY);
vm.expectEmit(CFNFTFF);
emit IERC20Events.Transfer(CFNFTFF_TREASURY, to[0], serialId[0]);
emit IERC721Events.Transfer(CFNFTFF_TREASURY, to[0], serialId[0]);
IHederaTokenService(HTS_ADDRESS).transferNFT(CFNFTFF, from[0], to[0], int64(int256(serialId[0])));
vm.stopPrank();
assertEq(IERC721(CFNFTFF).ownerOf(serialId[0]), to[0]);
Expand Down Expand Up @@ -811,7 +811,7 @@ contract HTSTest is Test, TestSetup {
assertNotEq(IERC721(token).getApproved(1), newSpender);
vm.prank(CFNFTFF_TREASURY);
vm.expectEmit(token);
emit IERC20Events.Approval(CFNFTFF_TREASURY, newSpender, 1);
emit IERC721Events.Approval(CFNFTFF_TREASURY, newSpender, 1);
int64 responseCodeApprove = IHederaTokenService(HTS_ADDRESS).approveNFT(token, newSpender, 1);
assertEq(responseCodeApprove, HederaResponseCodes.SUCCESS);
assertEq(IERC721(token).getApproved(1), newSpender);
Expand Down

0 comments on commit e4a7e92

Please sign in to comment.