From caf6cfdf3c0b62b931aa43155c1fcb8d63365ec4 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 12:38:54 -0300 Subject: [PATCH 01/24] ON-476: add revocable field --- contracts/ERC7432/ERC7432.sol | 110 +++++++++++++++++----- contracts/ERC7432/interfaces/IERC7432.sol | 11 ++- hardhat.config.ts | 2 +- 3 files changed, 96 insertions(+), 27 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index f929192..7ed38a6 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -5,26 +5,35 @@ pragma solidity 0.8.9; import { IERC7432 } from "./interfaces/IERC7432.sol"; contract ERC7432 is IERC7432 { - // grantor => grantee => tokenAddress => tokenId => role => struct(expirationDate, data) mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) public roleAssignments; - // grantor => tokenAddress => tokenId => role => grantee - mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees; + // grantor => tokenAddress => tokenId => role => grantees + mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) + public latestGrantees; // grantor => tokenAddress => tokenId => operator => isApproved - mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) public tokenIdApprovals; + mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) + public tokenIdApprovals; // grantor => operator => tokenAddress => isApproved - mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals; + mapping(address => mapping(address => mapping(address => bool))) + public tokenApprovals; modifier validExpirationDate(uint64 _expirationDate) { - require(_expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); + require( + _expirationDate > block.timestamp, + "ERC7432: expiration date must be in the future" + ); _; } - modifier onlyApproved(address _tokenAddress, uint256 _tokenId, address _grantor) { + modifier onlyApproved( + address _tokenAddress, + uint256 _tokenId, + address _grantor + ) { require( isRoleApprovedForAll(_tokenAddress, _grantor, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _grantor, msg.sender), @@ -39,9 +48,19 @@ contract ERC7432 is IERC7432 { uint256 _tokenId, address _grantee, uint64 _expirationDate, + bool _revocable, bytes calldata _data ) external { - _grantRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, _expirationDate, _data); + _grantRole( + _role, + _tokenAddress, + _tokenId, + msg.sender, + _grantee, + _expirationDate, + _revocable, + _data + ); } function grantRoleFrom( @@ -51,9 +70,19 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee, uint64 _expirationDate, + bool _revocable, bytes calldata _data ) external override onlyApproved(_tokenAddress, _tokenId, _grantor) { - _grantRole(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _data); + _grantRole( + _role, + _tokenAddress, + _tokenId, + _grantor, + _grantee, + _expirationDate, + _revocable, + _data + ); } function _grantRole( @@ -63,14 +92,30 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee, uint64 _expirationDate, + bool _revocable, bytes calldata _data ) internal validExpirationDate(_expirationDate) { - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _data); + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][ + _role + ] = RoleData(_expirationDate, _revocable, _data); latestGrantees[_grantor][_tokenAddress][_tokenId][_role] = _grantee; - emit RoleGranted( _role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _data); + emit RoleGranted( + _role, + _tokenAddress, + _tokenId, + _grantor, + _grantee, + _expirationDate, + _data + ); } - function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external { + function revokeRole( + bytes32 _role, + address _tokenAddress, + uint256 _tokenId, + address _grantee + ) external { _revokeRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee); } @@ -91,7 +136,14 @@ contract ERC7432 is IERC7432 { address _revoker, address _grantee ) internal { - delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role]; + require( + roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role] + .revocable || msg.sender == _grantee, + "ERC7432: role is not revocable" + ); + delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][ + _role + ]; delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role]; emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee); } @@ -103,7 +155,9 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; + return + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] + .expirationDate > block.timestamp; } function hasUniqueRole( @@ -113,7 +167,11 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > + return + latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == + _grantee && + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] + .expirationDate > block.timestamp; } @@ -124,22 +182,28 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bytes memory data_) { - RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role]; + RoleData memory _roleData = roleAssignments[_grantor][_grantee][ + _tokenAddress + ][_tokenId][_role]; return (_roleData.data); } - function roleExpirationDate( + function roleExpirationDate( bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantor, address _grantee - ) external view returns (uint64 expirationDate_){ - RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role]; + ) external view returns (uint64 expirationDate_) { + RoleData memory _roleData = roleAssignments[_grantor][_grantee][ + _tokenAddress + ][_tokenId][_role]; return (_roleData.expirationDate); } - function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + function supportsInterface( + bytes4 interfaceId + ) external view virtual override returns (bool) { return interfaceId == type(IERC7432).interfaceId; } @@ -158,8 +222,10 @@ contract ERC7432 is IERC7432 { address _operator, bool _approved ) external override { - tokenIdApprovals[msg.sender][_tokenAddress][_tokenId][_operator] = _approved; - emit RoleApproval( _tokenAddress, _tokenId, _operator, _approved); + tokenIdApprovals[msg.sender][_tokenAddress][_tokenId][ + _operator + ] = _approved; + emit RoleApproval(_tokenAddress, _tokenId, _operator, _approved); } function isRoleApprovedForAll( diff --git a/contracts/ERC7432/interfaces/IERC7432.sol b/contracts/ERC7432/interfaces/IERC7432.sol index 432a3fa..b3e1abf 100644 --- a/contracts/ERC7432/interfaces/IERC7432.sol +++ b/contracts/ERC7432/interfaces/IERC7432.sol @@ -2,8 +2,7 @@ pragma solidity 0.8.9; -import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; - +import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @title ERC-7432 Non-Fungible Token Roles /// @dev See https://eips.ethereum.org/EIPS/eip-7432 @@ -11,6 +10,7 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol interface IERC7432 is IERC165 { struct RoleData { uint64 expirationDate; + bool revocable; bytes data; } @@ -78,6 +78,7 @@ interface IERC7432 is IERC165 { /// @param _tokenId The token identifier. /// @param _grantee The user receiving the role. /// @param _expirationDate The expiration date of the role. + /// @param _revocable Whether the role is revocable or not. /// @param _data Any additional data about the role. function grantRole( bytes32 _role, @@ -85,6 +86,7 @@ interface IERC7432 is IERC165 { uint256 _tokenId, address _grantee, uint64 _expirationDate, + bool _revocable, bytes calldata _data ) external; @@ -107,6 +109,7 @@ interface IERC7432 is IERC165 { /// @param _grantor The user assigning the role. /// @param _grantee The user that receives the role. /// @param _expirationDate The expiration date of the role. + /// @param _revocable Whether the role is revocable or not. /// @param _data Any additional data about the role. function grantRoleFrom( bytes32 _role, @@ -115,6 +118,7 @@ interface IERC7432 is IERC165 { address _grantor, address _grantee, uint64 _expirationDate, + bool _revocable, bytes calldata _data ) external; @@ -233,5 +237,4 @@ interface IERC7432 is IERC165 { address _grantor, address _operator ) external view returns (bool); - -} \ No newline at end of file +} diff --git a/hardhat.config.ts b/hardhat.config.ts index af201de..cced2c7 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -17,4 +17,4 @@ module.exports = { overwrite: false, runOnCompile: true, }, -} \ No newline at end of file +} From 138221c6d9e993210df6c00ce25d93fbd16d8055 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:37:50 -0300 Subject: [PATCH 02/24] ON-476: Fix tests --- contracts/ERC7432/ERC7432.sol | 7 +--- contracts/ERC7432/interfaces/IERC7432.sol | 2 +- test/ERC7432.spec.ts | 47 ++++++++++++++++++++++- test/contants.ts | 2 +- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 7ed38a6..1e3d51c 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -136,11 +136,8 @@ contract ERC7432 is IERC7432 { address _revoker, address _grantee ) internal { - require( - roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role] - .revocable || msg.sender == _grantee, - "ERC7432: role is not revocable" - ); + bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; + require(_isRevocable || msg.sender == _grantee, "ERC7432: role is not revocable"); delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][ _role ]; diff --git a/contracts/ERC7432/interfaces/IERC7432.sol b/contracts/ERC7432/interfaces/IERC7432.sol index b3e1abf..3239b69 100644 --- a/contracts/ERC7432/interfaces/IERC7432.sol +++ b/contracts/ERC7432/interfaces/IERC7432.sol @@ -2,7 +2,7 @@ pragma solidity 0.8.9; -import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /// @title ERC-7432 Non-Fungible Token Roles /// @dev See https://eips.ethereum.org/EIPS/eip-7432 diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index dfa7bda..be009dc 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -8,7 +8,7 @@ import axios from 'axios' import { defaultAbiCoder, solidityKeccak256 } from 'ethers/lib/utils' import { NftMetadata, Role } from './types' -const { HashZero, AddressZero } = ethers.constants +const {HashZero, AddressZero} = ethers.constants const ONE_DAY = 60 * 60 * 24 describe('ERC7432', () => { @@ -106,6 +106,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, + true, data, ), ) @@ -124,6 +125,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDateInThePast, + true, HashZero, ), ).to.be.revertedWith('ERC7432: expiration date must be in the future') @@ -131,11 +133,36 @@ describe('ERC7432', () => { }) describe('Revoke role', async () => { + beforeEach(async () => { + await ERC7432.connect(grantor).grantRole( + PROPERTY_MANAGER, + AddressZero, + tokenId, + userOne.address, + expirationDate, + true, + data, + ) + }) it('should revoke role', async () => { await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address)) .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) }) + it('should NOT revoke role if role is not revocable', async () => { + await ERC7432.connect(grantor).grantRole( + PROPERTY_MANAGER, + AddressZero, + tokenId, + userOne.address, + expirationDate, + false, + data, + ) + await expect( + ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address), + ).to.be.revertedWith('ERC7432: role is not revocable') + }) }) describe('Has role', async () => { @@ -147,6 +174,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, + true, HashZero, ), ) @@ -160,6 +188,7 @@ describe('ERC7432', () => { tokenId, userTwo.address, expirationDate, + true, HashZero, ), ) @@ -234,6 +263,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, + true, customData, ), ) @@ -291,6 +321,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, + true, customData, ) @@ -337,6 +368,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, + true, HashZero, ), ) @@ -366,6 +398,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, + true, HashZero, ), ).to.be.revertedWith('ERC7432: sender must be approved') @@ -373,6 +406,18 @@ describe('ERC7432', () => { }) describe('Revoke role from', async () => { + beforeEach(async () => { + await ERC7432.connect(operator).grantRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + expirationDate, + true, + HashZero, + ) + }) it('should revoke role from', async () => { await expect( ERC7432.connect(operator).revokeRoleFrom( diff --git a/test/contants.ts b/test/contants.ts index 3caca4b..e9f3a94 100644 --- a/test/contants.ts +++ b/test/contants.ts @@ -1 +1 @@ -export const ERC7432InterfaceId = '0xd7e151ef' \ No newline at end of file +export const ERC7432InterfaceId = '0x25be10b2' \ No newline at end of file From ddce0644676af407a999002f8d14111a1a9e9cc1 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:46:21 -0300 Subject: [PATCH 03/24] ON-476: Add more tests --- contracts/ERC7432/ERC7432.sol | 9 +++++---- contracts/ERC7432/interfaces/IERC7432.sol | 2 +- test/ERC7432.spec.ts | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 1e3d51c..3a2cc73 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -116,7 +116,7 @@ contract ERC7432 is IERC7432 { uint256 _tokenId, address _grantee ) external { - _revokeRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee); + _revokeRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, msg.sender); } function revokeRoleFrom( @@ -126,7 +126,7 @@ contract ERC7432 is IERC7432 { address _revoker, address _grantee ) external override onlyApproved(_tokenAddress, _tokenId, _revoker) { - _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee); + _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee, _grantee); } function _revokeRole( @@ -134,10 +134,11 @@ contract ERC7432 is IERC7432 { address _tokenAddress, uint256 _tokenId, address _revoker, - address _grantee + address _grantee, + address _caller ) internal { bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; - require(_isRevocable || msg.sender == _grantee, "ERC7432: role is not revocable"); + require(_isRevocable || _caller == _grantee, "ERC7432: role is not revocable"); delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][ _role ]; diff --git a/contracts/ERC7432/interfaces/IERC7432.sol b/contracts/ERC7432/interfaces/IERC7432.sol index 3239b69..fa9fbba 100644 --- a/contracts/ERC7432/interfaces/IERC7432.sol +++ b/contracts/ERC7432/interfaces/IERC7432.sol @@ -6,7 +6,7 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol /// @title ERC-7432 Non-Fungible Token Roles /// @dev See https://eips.ethereum.org/EIPS/eip-7432 -/// Note: the ERC-165 identifier for this interface is 0xd7e151ef. +/// Note: the ERC-165 identifier for this interface is 0x25be10b2. interface IERC7432 is IERC165 { struct RoleData { uint64 expirationDate; diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index be009dc..b4fcc53 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -149,6 +149,25 @@ describe('ERC7432', () => { .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) }) + it("should revoke role if caller is the grantee", async () => { + await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address)) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + }) + it('should revoke role if role is not revocable, but grantor is also the grantee', async () => { + await ERC7432.connect(grantor).grantRole( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + expirationDate, + false, + data, + ) + await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address)) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address) + }) it('should NOT revoke role if role is not revocable', async () => { await ERC7432.connect(grantor).grantRole( PROPERTY_MANAGER, From 84a366796f0ccfe1615e11aa30a376dafc628d7b Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:51:43 -0300 Subject: [PATCH 04/24] ON-476: lint --- contracts/ERC7432/ERC7432.sol | 60 ++++++++--------------------------- 1 file changed, 14 insertions(+), 46 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 3a2cc73..040be9e 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -6,34 +6,24 @@ import { IERC7432 } from "./interfaces/IERC7432.sol"; contract ERC7432 is IERC7432 { // grantor => grantee => tokenAddress => tokenId => role => struct(expirationDate, data) - mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) - public roleAssignments; + mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) public roleAssignments; // grantor => tokenAddress => tokenId => role => grantees - mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) - public latestGrantees; + mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees; // grantor => tokenAddress => tokenId => operator => isApproved - mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) - public tokenIdApprovals; + mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) public tokenIdApprovals; // grantor => operator => tokenAddress => isApproved - mapping(address => mapping(address => mapping(address => bool))) - public tokenApprovals; + mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals; modifier validExpirationDate(uint64 _expirationDate) { require( - _expirationDate > block.timestamp, - "ERC7432: expiration date must be in the future" - ); + _expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); _; } - modifier onlyApproved( - address _tokenAddress, - uint256 _tokenId, - address _grantor - ) { + modifier onlyApproved(address _tokenAddress, uint256 _tokenId, address _grantor) { require( isRoleApprovedForAll(_tokenAddress, _grantor, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _grantor, msg.sender), @@ -95,9 +85,7 @@ contract ERC7432 is IERC7432 { bool _revocable, bytes calldata _data ) internal validExpirationDate(_expirationDate) { - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][ - _role - ] = RoleData(_expirationDate, _revocable, _data); + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _revocable, _data); latestGrantees[_grantor][_tokenAddress][_tokenId][_role] = _grantee; emit RoleGranted( _role, @@ -110,12 +98,7 @@ contract ERC7432 is IERC7432 { ); } - function revokeRole( - bytes32 _role, - address _tokenAddress, - uint256 _tokenId, - address _grantee - ) external { + function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external { _revokeRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, msg.sender); } @@ -153,9 +136,7 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] - .expirationDate > block.timestamp; + return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; } function hasUniqueRole( @@ -165,12 +146,7 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return - latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == - _grantee && - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] - .expirationDate > - block.timestamp; + return latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; } function roleData( @@ -180,9 +156,7 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bytes memory data_) { - RoleData memory _roleData = roleAssignments[_grantor][_grantee][ - _tokenAddress - ][_tokenId][_role]; + RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role]; return (_roleData.data); } @@ -193,15 +167,11 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (uint64 expirationDate_) { - RoleData memory _roleData = roleAssignments[_grantor][_grantee][ - _tokenAddress - ][_tokenId][_role]; + RoleData memory _roleData = roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role]; return (_roleData.expirationDate); } - function supportsInterface( - bytes4 interfaceId - ) external view virtual override returns (bool) { + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { return interfaceId == type(IERC7432).interfaceId; } @@ -220,9 +190,7 @@ contract ERC7432 is IERC7432 { address _operator, bool _approved ) external override { - tokenIdApprovals[msg.sender][_tokenAddress][_tokenId][ - _operator - ] = _approved; + tokenIdApprovals[msg.sender][_tokenAddress][_tokenId][_operator] = _approved; emit RoleApproval(_tokenAddress, _tokenId, _operator, _approved); } From 6f32a20f7761df5c497f45c19cb2fcf6eb6575d1 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:55:11 -0300 Subject: [PATCH 05/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 040be9e..30d089e 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -18,8 +18,7 @@ contract ERC7432 is IERC7432 { mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals; modifier validExpirationDate(uint64 _expirationDate) { - require( - _expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); + require(_expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); _; } @@ -41,16 +40,7 @@ contract ERC7432 is IERC7432 { bool _revocable, bytes calldata _data ) external { - _grantRole( - _role, - _tokenAddress, - _tokenId, - msg.sender, - _grantee, - _expirationDate, - _revocable, - _data - ); + _grantRole(_role, _tokenAddress, _tokenId, msg.sender, _grantee, _expirationDate, _revocable, _data); } function grantRoleFrom( @@ -87,15 +77,7 @@ contract ERC7432 is IERC7432 { ) internal validExpirationDate(_expirationDate) { roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _revocable, _data); latestGrantees[_grantor][_tokenAddress][_tokenId][_role] = _grantee; - emit RoleGranted( - _role, - _tokenAddress, - _tokenId, - _grantor, - _grantee, - _expirationDate, - _data - ); + emit RoleGranted(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _data); } function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external { @@ -122,9 +104,7 @@ contract ERC7432 is IERC7432 { ) internal { bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; require(_isRevocable || _caller == _grantee, "ERC7432: role is not revocable"); - delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][ - _role - ]; + delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role]; delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role]; emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee); } @@ -136,7 +116,8 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; + return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] + .expirationDate > block.timestamp; } function hasUniqueRole( From 196533b8ab9d5d4d5b26b485be0570e99e9267fa Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:56:16 -0300 Subject: [PATCH 06/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 30d089e..feac20a 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -6,16 +6,20 @@ import { IERC7432 } from "./interfaces/IERC7432.sol"; contract ERC7432 is IERC7432 { // grantor => grantee => tokenAddress => tokenId => role => struct(expirationDate, data) - mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) public roleAssignments; + mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) + public roleAssignments; // grantor => tokenAddress => tokenId => role => grantees - mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees; + mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) + public latestGrantees; // grantor => tokenAddress => tokenId => operator => isApproved - mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) public tokenIdApprovals; + mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) + public tokenIdApprovals; // grantor => operator => tokenAddress => isApproved - mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals; + mapping(address => mapping(address => mapping(address => bool))) + public tokenApprovals; modifier validExpirationDate(uint64 _expirationDate) { require(_expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); From 61666f106cb0b7bd757fe73aaabd4a0d927e55bf Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:56:46 -0300 Subject: [PATCH 07/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index feac20a..594b4f7 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -10,16 +10,13 @@ contract ERC7432 is IERC7432 { public roleAssignments; // grantor => tokenAddress => tokenId => role => grantees - mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) - public latestGrantees; + mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees; // grantor => tokenAddress => tokenId => operator => isApproved - mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) - public tokenIdApprovals; + mapping(address => mapping(address => mapping(uint256 => mapping(address => bool)))) public tokenIdApprovals; // grantor => operator => tokenAddress => isApproved - mapping(address => mapping(address => mapping(address => bool))) - public tokenApprovals; + mapping(address => mapping(address => mapping(address => bool))) public tokenApprovals; modifier validExpirationDate(uint64 _expirationDate) { require(_expirationDate > block.timestamp, "ERC7432: expiration date must be in the future"); From 032a094d4afbcdc9bcc8369356c433e1231c5340 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:57:30 -0300 Subject: [PATCH 08/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 594b4f7..20418dd 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -54,16 +54,7 @@ contract ERC7432 is IERC7432 { bool _revocable, bytes calldata _data ) external override onlyApproved(_tokenAddress, _tokenId, _grantor) { - _grantRole( - _role, - _tokenAddress, - _tokenId, - _grantor, - _grantee, - _expirationDate, - _revocable, - _data - ); + _grantRole(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _revocable, _data); } function _grantRole( From 2fae839e3c891e1af96c295da3ec90be0580f736 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:59:18 -0300 Subject: [PATCH 09/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 20418dd..4d59892 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -108,8 +108,9 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] - .expirationDate > block.timestamp; + return + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] + .expirationDate > block.timestamp; } function hasUniqueRole( @@ -119,7 +120,12 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; + return + latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == + _grantee && + roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] + .expirationDate > + block.timestamp; } function roleData( From 9e302418cac3359ed019e61dfbcbb40027f079e1 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 14:59:40 -0300 Subject: [PATCH 10/24] ON-476: prettier --- contracts/ERC7432/ERC7432.sol | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 4d59892..e57af4a 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -108,9 +108,8 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] - .expirationDate > block.timestamp; + return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId] + [_role].expirationDate > block.timestamp; } function hasUniqueRole( @@ -120,12 +119,7 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return - latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == - _grantee && - roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] - .expirationDate > - block.timestamp; + return latestGrantees[_grantor][_tokenAddress][_tokenId][_role] == _grantee && roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; } function roleData( From 9a564558292d6483b53b33ee26ba6fba2e3ac8f4 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 15:00:23 -0300 Subject: [PATCH 11/24] ON-476: one line config --- contracts/ERC7432/ERC7432.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index e57af4a..0c46730 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -108,8 +108,7 @@ contract ERC7432 is IERC7432 { address _grantor, address _grantee ) external view returns (bool) { - return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId] - [_role].expirationDate > block.timestamp; + return roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role].expirationDate > block.timestamp; } function hasUniqueRole( From c472d5c1c746fd126d439ef1422998ea36232c0d Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 16:04:14 -0300 Subject: [PATCH 12/24] ON-476: fix spaces --- test/ERC7432.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index b4fcc53..c78f254 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -8,7 +8,7 @@ import axios from 'axios' import { defaultAbiCoder, solidityKeccak256 } from 'ethers/lib/utils' import { NftMetadata, Role } from './types' -const {HashZero, AddressZero} = ethers.constants +const { HashZero, AddressZero } = ethers.constants const ONE_DAY = 60 * 60 * 24 describe('ERC7432', () => { From 38e2e8d7fb9ca9dded23c3d4dd35810e4813b756 Mon Sep 17 00:00:00 2001 From: Daniel Lima <38267570+karacurt@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:44:26 -0300 Subject: [PATCH 13/24] Update contracts/ERC7432/ERC7432.sol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernani São Thiago --- contracts/ERC7432/ERC7432.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 0c46730..026727c 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -9,7 +9,7 @@ contract ERC7432 is IERC7432 { mapping(address => mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => RoleData))))) public roleAssignments; - // grantor => tokenAddress => tokenId => role => grantees + // grantor => tokenAddress => tokenId => role => grantee mapping(address => mapping(address => mapping(uint256 => mapping(bytes32 => address)))) public latestGrantees; // grantor => tokenAddress => tokenId => operator => isApproved From e88dd6160019e6e08563aa475f81e11f7dbf1e1b Mon Sep 17 00:00:00 2001 From: Daniel Lima <38267570+karacurt@users.noreply.github.com> Date: Mon, 18 Sep 2023 16:44:38 -0300 Subject: [PATCH 14/24] Update contracts/ERC7432/ERC7432.sol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernani São Thiago --- contracts/ERC7432/ERC7432.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 026727c..431fd31 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -95,7 +95,7 @@ contract ERC7432 is IERC7432 { address _caller ) internal { bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; - require(_isRevocable || _caller == _grantee, "ERC7432: role is not revocable"); + require(_isRevocable || _caller == _grantee, "ERC7432: Account can't revoke this role"); delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role]; delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role]; emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee); From e26155b2d21bbd43da805b692faddb20bc09f0fb Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 16:56:12 -0300 Subject: [PATCH 15/24] ON-476: fix tests --- contracts/ERC7432/ERC7432.sol | 2 +- contracts/ERC7432/interfaces/IERC7432.sol | 2 ++ test/ERC7432.spec.ts | 31 +++++++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 431fd31..331851d 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -69,7 +69,7 @@ contract ERC7432 is IERC7432 { ) internal validExpirationDate(_expirationDate) { roleAssignments[_grantor][_grantee][_tokenAddress][_tokenId][_role] = RoleData(_expirationDate, _revocable, _data); latestGrantees[_grantor][_tokenAddress][_tokenId][_role] = _grantee; - emit RoleGranted(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _data); + emit RoleGranted(_role, _tokenAddress, _tokenId, _grantor, _grantee, _expirationDate, _revocable, _data); } function revokeRole(bytes32 _role, address _tokenAddress, uint256 _tokenId, address _grantee) external { diff --git a/contracts/ERC7432/interfaces/IERC7432.sol b/contracts/ERC7432/interfaces/IERC7432.sol index fa9fbba..c346dce 100644 --- a/contracts/ERC7432/interfaces/IERC7432.sol +++ b/contracts/ERC7432/interfaces/IERC7432.sol @@ -23,6 +23,7 @@ interface IERC7432 is IERC165 { /// @param _grantor The user assigning the role. /// @param _grantee The user receiving the role. /// @param _expirationDate The expiration date of the role. + /// @param _revocable Whether the role is revocable or not. /// @param _data Any additional data about the role. event RoleGranted( bytes32 indexed _role, @@ -31,6 +32,7 @@ interface IERC7432 is IERC165 { address _grantor, address _grantee, uint64 _expirationDate, + bool _revocable, bytes _data ); diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index c78f254..47b6cf1 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -26,6 +26,7 @@ describe('ERC7432', () => { const PROPERTY_TENANT = solidityKeccak256(['string'], ['PROPERTY_TENANT']) const tokenId = 1 + const revokable = true before(async function () { // prettier-ignore @@ -106,12 +107,12 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - true, + revokable, data, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, data) + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, revokable, data) }) it('should NOT grant role if expiration date is in the past', async () => { const blockNumber = await hre.ethers.provider.getBlockNumber() @@ -125,7 +126,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDateInThePast, - true, + revokable, HashZero, ), ).to.be.revertedWith('ERC7432: expiration date must be in the future') @@ -140,7 +141,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - true, + revokable, data, ) }) @@ -180,7 +181,7 @@ describe('ERC7432', () => { ) await expect( ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address), - ).to.be.revertedWith('ERC7432: role is not revocable') + ).to.be.revertedWith(`ERC7432: Account can't revoke this role`) }) }) @@ -193,12 +194,12 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - true, + revokable, HashZero, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, HashZero) + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, revokable, HashZero) await expect( ERC7432.connect(grantor).grantRole( @@ -207,12 +208,12 @@ describe('ERC7432', () => { tokenId, userTwo.address, expirationDate, - true, + revokable, HashZero, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userTwo.address, expirationDate, HashZero) + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userTwo.address, expirationDate, revokable, HashZero) }) describe('Unique Roles', async () => { @@ -282,7 +283,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - true, + revokable, customData, ), ) @@ -294,6 +295,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, + revokable, customData, ) @@ -340,7 +342,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - true, + revokable, customData, ) @@ -387,7 +389,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - true, + revokable, HashZero, ), ) @@ -399,6 +401,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, + revokable, HashZero, ) }) @@ -417,7 +420,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - true, + revokable, HashZero, ), ).to.be.revertedWith('ERC7432: sender must be approved') @@ -433,7 +436,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - true, + revokable, HashZero, ) }) From 9cc14bc8116f7c29f5f0b8f89de8d47a1addfe3d Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 17:07:58 -0300 Subject: [PATCH 16/24] ON-476: update revokeFrom to allow grantee approved operators --- contracts/ERC7432/ERC7432.sol | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 331851d..500e62f 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -82,8 +82,14 @@ contract ERC7432 is IERC7432 { uint256 _tokenId, address _revoker, address _grantee - ) external override onlyApproved(_tokenAddress, _tokenId, _revoker) { - _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee, _grantee); + ) external override { + bool _isRevokerApproved = isRoleApprovedForAll(_tokenAddress, _revoker, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _revoker, msg.sender); + bool _isGranteeApproved = isRoleApprovedForAll(_tokenAddress, _grantee, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _grantee, msg.sender); + require(_isRevokerApproved || _isGranteeApproved, "ERC7432: sender must be approved"); + + address _caller = _isGranteeApproved ? _grantee : _revoker; // In case of operator being approved for both grantee and revoker, the grantee will be the caller. + + _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee, _caller); } function _revokeRole( From 49bd7bd42779f6ca4615b9b3ee1c0c73c3ba7d29 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 18:27:06 -0300 Subject: [PATCH 17/24] ON-476: Add more tests --- test/ERC7432.spec.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index 47b6cf1..a191677 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -168,6 +168,7 @@ describe('ERC7432', () => { await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address)) .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address) + expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address)).to.be.equal(false) }) it('should NOT revoke role if role is not revocable', async () => { await ERC7432.connect(grantor).grantRole( @@ -469,6 +470,22 @@ describe('ERC7432', () => { ), ).to.be.revertedWith('ERC7432: sender must be approved') }) + it('should revoke role from if operator is approved by grantee', async () => { + await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) + expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address)).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address)).to.be.equal(false) + }) }) }) } From f5fd9ece88465a65c63672a852d2ac8649ccec7d Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Mon, 18 Sep 2023 18:29:14 -0300 Subject: [PATCH 18/24] ON-476: coverage 100% --- test/ERC7432.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index a191677..8db91d2 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -471,6 +471,7 @@ describe('ERC7432', () => { ).to.be.revertedWith('ERC7432: sender must be approved') }) it('should revoke role from if operator is approved by grantee', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, false) await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address)).to.be.equal(true) await expect( From 9ac8501b8c50b7a3a2f8cc3c5b3e44380c39e3fc Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 19 Sep 2023 10:16:30 -0300 Subject: [PATCH 19/24] ON-476: Add revocable and non-revocable tests --- test/ERC7432.spec.ts | 284 ++++++++++++++++++++++++++++++++----------- 1 file changed, 214 insertions(+), 70 deletions(-) diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index 8db91d2..4bbe66f 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -1,14 +1,14 @@ -import hre, { ethers } from 'hardhat' -import { Contract } from 'ethers' -import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' -import { expect } from 'chai' -import { ERC7432InterfaceId } from './contants' +import hre, {ethers} from 'hardhat' +import {Contract} from 'ethers' +import {SignerWithAddress} from '@nomiclabs/hardhat-ethers/signers' +import {expect} from 'chai' +import {ERC7432InterfaceId} from './contants' import nock from 'nock' import axios from 'axios' -import { defaultAbiCoder, solidityKeccak256 } from 'ethers/lib/utils' -import { NftMetadata, Role } from './types' +import {defaultAbiCoder, solidityKeccak256} from 'ethers/lib/utils' +import {NftMetadata, Role} from './types' -const { HashZero, AddressZero } = ethers.constants +const {HashZero, AddressZero} = ethers.constants const ONE_DAY = 60 * 60 * 24 describe('ERC7432', () => { @@ -26,7 +26,7 @@ describe('ERC7432', () => { const PROPERTY_TENANT = solidityKeccak256(['string'], ['PROPERTY_TENANT']) const tokenId = 1 - const revokable = true + const revocable = true before(async function () { // prettier-ignore @@ -107,12 +107,21 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - revokable, + revocable, data, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, revokable, data) + .withArgs( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + expirationDate, + revocable, + data, + ) }) it('should NOT grant role if expiration date is in the past', async () => { const blockNumber = await hre.ethers.provider.getBlockNumber() @@ -126,7 +135,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDateInThePast, - revokable, + revocable, HashZero, ), ).to.be.revertedWith('ERC7432: expiration date must be in the future') @@ -141,7 +150,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - revokable, + revocable, data, ) }) @@ -150,7 +159,7 @@ describe('ERC7432', () => { .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) }) - it("should revoke role if caller is the grantee", async () => { + it('should revoke role if caller is the grantee', async () => { await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address)) .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) @@ -168,7 +177,9 @@ describe('ERC7432', () => { await expect(ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address)) .to.emit(ERC7432, 'RoleRevoked') .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address) - expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address)).to.be.equal(false) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, grantor.address), + ).to.be.equal(false) }) it('should NOT revoke role if role is not revocable', async () => { await ERC7432.connect(grantor).grantRole( @@ -195,12 +206,21 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - revokable, + revocable, HashZero, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, expirationDate, revokable, HashZero) + .withArgs( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + expirationDate, + revocable, + HashZero, + ) await expect( ERC7432.connect(grantor).grantRole( @@ -209,12 +229,21 @@ describe('ERC7432', () => { tokenId, userTwo.address, expirationDate, - revokable, + revocable, HashZero, ), ) .to.emit(ERC7432, 'RoleGranted') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userTwo.address, expirationDate, revokable, HashZero) + .withArgs( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userTwo.address, + expirationDate, + revocable, + HashZero, + ) }) describe('Unique Roles', async () => { @@ -284,7 +313,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - revokable, + revocable, customData, ), ) @@ -296,7 +325,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - revokable, + revocable, customData, ) @@ -343,7 +372,7 @@ describe('ERC7432', () => { tokenId, userOne.address, expirationDate, - revokable, + revocable, customData, ) @@ -390,7 +419,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - revokable, + revocable, HashZero, ), ) @@ -402,7 +431,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - revokable, + revocable, HashZero, ) }) @@ -421,7 +450,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, expirationDate, - revokable, + revocable, HashZero, ), ).to.be.revertedWith('ERC7432: sender must be approved') @@ -429,63 +458,178 @@ describe('ERC7432', () => { }) describe('Revoke role from', async () => { - beforeEach(async () => { - await ERC7432.connect(operator).grantRoleFrom( - PROPERTY_MANAGER, - AddressZero, - tokenId, - grantor.address, - userOne.address, - expirationDate, - revokable, - HashZero, - ) - }) - it('should revoke role from', async () => { - await expect( - ERC7432.connect(operator).revokeRoleFrom( + describe('Revocable roles', async () => { + beforeEach(async () => { + await ERC7432.connect(operator).grantRoleFrom( PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, - ), - ) - .to.emit(ERC7432, 'RoleRevoked') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) - }) - it('should NOT revoke role from if operator is not approved', async () => { - if (approval === 'Approval for TokenId') { + expirationDate, + revocable, + HashZero, + ) + }) + it('should revoke role from', async () => { + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + }) + it('should NOT revoke role from if operator is not approved', async () => { + if (approval === 'Approval for TokenId') { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, false) + } else { + await ERC7432.connect(grantor).setRoleApprovalForAll(AddressZero, operator.address, false) + } + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ).to.be.revertedWith('ERC7432: sender must be approved') + }) + it('should revoke role from if operator is only approved by grantee', async () => { await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, false) - } else { - await ERC7432.connect(grantor).setRoleApprovalForAll(AddressZero, operator.address, false) - } - await expect( - ERC7432.connect(operator).revokeRoleFrom( - PROPERTY_MANAGER, - AddressZero, - tokenId, - grantor.address, - userOne.address, - ), - ).to.be.revertedWith('ERC7432: sender must be approved') + await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(false) + }) + it('should revoke role from if operator is approved by both grantor and grantee', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, true) + await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(false) + }) + it('should revoke role from if operator is only approved by grantor', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, true) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(false) + }) }) - it('should revoke role from if operator is approved by grantee', async () => { - await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, false) - await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) - expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address)).to.be.equal(true) - await expect( - ERC7432.connect(operator).revokeRoleFrom( + describe('Non-Revocable roles', async () => { + beforeEach(async () => { + await ERC7432.connect(operator).grantRoleFrom( PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address, - ), - ) - .to.emit(ERC7432, 'RoleRevoked') - .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) - expect(await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address)).to.be.equal(false) + expirationDate, + !revocable, + HashZero, + ) + }) + it('should revoke role from if operator is only approved by grantee', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, false) + await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(false) + }) + it('should revoke role from if operator is approved by both grantor and grantee', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, true) + await ERC7432.connect(userOne).approveRole(AddressZero, tokenId, operator.address, true) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ) + .to.emit(ERC7432, 'RoleRevoked') + .withArgs(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address) + expect( + await ERC7432.hasRole(PROPERTY_MANAGER, AddressZero, tokenId, grantor.address, userOne.address), + ).to.be.equal(false) + }) + it('should NOT revoke role from if operator is only approved by grantor', async () => { + await ERC7432.connect(grantor).approveRole(AddressZero, tokenId, operator.address, true) + await expect( + ERC7432.connect(operator).revokeRoleFrom( + PROPERTY_MANAGER, + AddressZero, + tokenId, + grantor.address, + userOne.address, + ), + ).to.be.revertedWith(`ERC7432: Account can't revoke this role`) + }) }) }) }) From 354d7ae79ac4127d7b9131e59a2e07d705fd616c Mon Sep 17 00:00:00 2001 From: Daniel Lima <38267570+karacurt@users.noreply.github.com> Date: Tue, 19 Sep 2023 10:39:33 -0300 Subject: [PATCH 20/24] Update contracts/ERC7432/ERC7432.sol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ernani São Thiago --- contracts/ERC7432/ERC7432.sol | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 500e62f..8f1383e 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -101,7 +101,8 @@ contract ERC7432 is IERC7432 { address _caller ) internal { bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; - require(_isRevocable || _caller == _grantee, "ERC7432: Account can't revoke this role"); + require(_isRevocable, "ERC7432: Role is not revocable"); + require(_caller == _grantee, "ERC7432: Caller is not allowed to revoke this role"); delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role]; delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role]; emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee); From 75e41b228a9441e829717071258bcf67a1034a14 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 19 Sep 2023 10:44:19 -0300 Subject: [PATCH 21/24] ON-476: fix require --- contracts/ERC7432/ERC7432.sol | 3 +- hardhat.config.ts | 8 ++ package-lock.json | 200 +++++++--------------------------- package.json | 1 + test/ERC7432.spec.ts | 4 +- 5 files changed, 49 insertions(+), 167 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 8f1383e..133178e 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -101,8 +101,7 @@ contract ERC7432 is IERC7432 { address _caller ) internal { bool _isRevocable = roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role].revocable; - require(_isRevocable, "ERC7432: Role is not revocable"); - require(_caller == _grantee, "ERC7432: Caller is not allowed to revoke this role"); + require(_isRevocable || _caller == _grantee, "ERC7432: Role is not revocable or caller is not the grantee"); delete roleAssignments[_revoker][_grantee][_tokenAddress][_tokenId][_role]; delete latestGrantees[_revoker][_tokenAddress][_tokenId][_role]; emit RoleRevoked(_role, _tokenAddress, _tokenId, _revoker, _grantee); diff --git a/hardhat.config.ts b/hardhat.config.ts index cced2c7..e98c49e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,6 +1,7 @@ import 'solidity-coverage' import 'hardhat-spdx-license-identifier' import '@nomicfoundation/hardhat-toolbox' +import 'hardhat-gas-reporter' module.exports = { solidity: { @@ -10,6 +11,13 @@ module.exports = { runs: 200, }, }, + gasReporter: { + enabled: true, + excludeContracts: ['contracts/test'], + gasPrice: 100, + token: 'MATIC', + currency: 'USD', + }, mocha: { timeout: 840000, }, diff --git a/package-lock.json b/package-lock.json index d343142..2079ca8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "chai": "^4.3.6", "ethers": "^5.7.1", "hardhat": "^2.11.2", + "hardhat-gas-reporter": "^1.0.9", "nock": "^13.3.2", "solidity-coverage": "^0.8.2", "ts-node": "^10.9.1", @@ -1506,7 +1507,6 @@ "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.5.tgz", "integrity": "sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==", "dev": true, - "peer": true, "dependencies": { "antlr4ts": "^0.5.0-alpha.4" } @@ -1633,7 +1633,6 @@ "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", "dev": true, - "peer": true, "dependencies": { "@types/node": "*" } @@ -1643,7 +1642,6 @@ "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", "dev": true, - "peer": true, "dependencies": { "@types/node": "*" } @@ -1698,8 +1696,7 @@ "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/@types/readable-stream": { "version": "2.3.15", @@ -1817,7 +1814,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1945,7 +1941,6 @@ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -1993,15 +1988,13 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, - "peer": true, "dependencies": { "safer-buffer": "~2.1.0" } @@ -2011,7 +2004,6 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, - "peer": true, "engines": { "node": ">=0.8" } @@ -2073,7 +2065,6 @@ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, - "peer": true, "engines": { "node": "*" } @@ -2082,8 +2073,7 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/axios": { "version": "1.4.0", @@ -2133,7 +2123,6 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, - "peer": true, "dependencies": { "tweetnacl": "^0.14.3" } @@ -2142,8 +2131,7 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/bech32": { "version": "1.1.4", @@ -2336,8 +2324,7 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/catering": { "version": "2.1.1", @@ -2408,7 +2395,6 @@ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", "dev": true, - "peer": true, "engines": { "node": "*" } @@ -2491,7 +2477,6 @@ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", "dev": true, - "peer": true, "dependencies": { "object-assign": "^4.1.0", "string-width": "^2.1.1" @@ -2552,7 +2537,6 @@ "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, - "peer": true, "engines": { "node": ">=0.1.90" } @@ -2640,7 +2624,6 @@ "engines": [ "node >= 0.8" ], - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -2653,7 +2636,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, - "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2668,15 +2650,13 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/concat-stream/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -2693,8 +2673,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/crc-32": { "version": "1.2.2", @@ -2743,7 +2722,6 @@ "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", "dev": true, - "peer": true, "engines": { "node": "*" } @@ -2753,7 +2731,6 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, - "peer": true, "dependencies": { "assert-plus": "^1.0.0" }, @@ -2905,7 +2882,6 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, - "peer": true, "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -3137,7 +3113,6 @@ "resolved": "https://registry.npmjs.org/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz", "integrity": "sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ==", "dev": true, - "peer": true, "dependencies": { "@ethersproject/abi": "^5.0.0-beta.146", "@solidity-parser/parser": "^0.14.0", @@ -3174,8 +3149,7 @@ "type": "individual", "url": "https://paulmillr.com/funding/" } - ], - "peer": true + ] }, "node_modules/eth-gas-reporter/node_modules/@scure/bip32": { "version": "1.1.5", @@ -3188,7 +3162,6 @@ "url": "https://paulmillr.com/funding/" } ], - "peer": true, "dependencies": { "@noble/hashes": "~1.2.0", "@noble/secp256k1": "~1.7.0", @@ -3206,7 +3179,6 @@ "url": "https://paulmillr.com/funding/" } ], - "peer": true, "dependencies": { "@noble/hashes": "~1.2.0", "@scure/base": "~1.1.0" @@ -3217,7 +3189,6 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3227,7 +3198,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3237,7 +3207,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -3246,15 +3215,13 @@ "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3264,7 +3231,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", "dev": true, - "peer": true, "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", @@ -3286,7 +3252,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, - "peer": true, "dependencies": { "string-width": "^3.1.0", "strip-ansi": "^5.2.0", @@ -3299,7 +3264,6 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dev": true, - "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -3309,7 +3273,6 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3319,7 +3282,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true, - "peer": true, "engines": { "node": ">=0.3.1" } @@ -3328,15 +3290,13 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "peer": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -3350,7 +3310,6 @@ "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", "dev": true, - "peer": true, "dependencies": { "@noble/hashes": "1.2.0", "@noble/secp256k1": "1.7.1", @@ -3363,7 +3322,6 @@ "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.49.tgz", "integrity": "sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg==", "dev": true, - "peer": true, "dependencies": { "aes-js": "3.0.0", "bn.js": "^4.11.9", @@ -3381,7 +3339,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, - "peer": true, "dependencies": { "locate-path": "^3.0.0" }, @@ -3394,7 +3351,6 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.1.tgz", "integrity": "sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA==", "dev": true, - "peer": true, "dependencies": { "is-buffer": "~2.0.3" }, @@ -3413,7 +3369,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -3423,7 +3378,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, - "peer": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3441,7 +3395,6 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", "dev": true, - "peer": true, "dependencies": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.0" @@ -3451,15 +3404,13 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz", "integrity": "sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3473,7 +3424,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, - "peer": true, "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -3487,7 +3437,6 @@ "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, - "peer": true, "dependencies": { "chalk": "^2.4.2" }, @@ -3500,7 +3449,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3513,7 +3461,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, - "peer": true, "dependencies": { "minimist": "^1.2.5" }, @@ -3526,7 +3473,6 @@ "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", "dev": true, - "peer": true, "dependencies": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", @@ -3569,15 +3515,13 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -3593,7 +3537,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, - "peer": true, "dependencies": { "p-limit": "^2.0.0" }, @@ -3606,7 +3549,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -3616,7 +3558,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", "dev": true, - "peer": true, "dependencies": { "picomatch": "^2.0.4" }, @@ -3628,22 +3569,19 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-2.0.4.tgz", "integrity": "sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/setimmediate": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.4.tgz", "integrity": "sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, - "peer": true, "dependencies": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -3658,7 +3596,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, - "peer": true, "dependencies": { "ansi-regex": "^4.1.0" }, @@ -3671,7 +3608,6 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -3681,7 +3617,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, - "peer": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -3694,15 +3629,13 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", "integrity": "sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg==", "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, - "peer": true, "dependencies": { "ansi-styles": "^3.2.0", "string-width": "^3.0.0", @@ -3716,15 +3649,13 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/eth-gas-reporter/node_modules/yargs": { "version": "13.3.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, - "peer": true, "dependencies": { "cliui": "^5.0.0", "find-up": "^3.0.0", @@ -3743,7 +3674,6 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, - "peer": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -3754,7 +3684,6 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, - "peer": true, "dependencies": { "flat": "^4.1.0", "lodash": "^4.17.15", @@ -3939,8 +3868,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/extsprintf": { "version": "1.3.0", @@ -3949,15 +3877,13 @@ "dev": true, "engines": [ "node >=0.6.0" - ], - "peer": true + ] }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "peer": true + "dev": true }, "node_modules/fast-glob": { "version": "3.3.1", @@ -3979,8 +3905,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -4072,7 +3997,6 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, - "peer": true, "engines": { "node": "*" } @@ -4113,8 +4037,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", @@ -4209,7 +4132,6 @@ "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", "integrity": "sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -4235,7 +4157,6 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, - "peer": true, "dependencies": { "assert-plus": "^1.0.0" } @@ -4404,7 +4325,6 @@ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -4415,7 +4335,6 @@ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "deprecated": "this library is no longer supported", "dev": true, - "peer": true, "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -4499,7 +4418,6 @@ "resolved": "https://registry.npmjs.org/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz", "integrity": "sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg==", "dev": true, - "peer": true, "dependencies": { "array-uniq": "1.0.3", "eth-gas-reporter": "^0.2.25", @@ -4701,7 +4619,6 @@ "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", "dev": true, - "peer": true, "dependencies": { "caseless": "^0.12.0", "concat-stream": "^1.6.2", @@ -4732,7 +4649,6 @@ "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", "dev": true, - "peer": true, "dependencies": { "@types/node": "^10.0.3" } @@ -4741,15 +4657,13 @@ "version": "10.17.60", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, - "peer": true, "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -5134,8 +5048,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/is-unicode-supported": { "version": "0.1.0", @@ -5164,8 +5077,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "peer": true + "dev": true }, "node_modules/isexe": { "version": "2.0.0", @@ -5177,8 +5089,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true, - "peer": true + "dev": true }, "node_modules/js-sdsl": { "version": "4.4.2", @@ -5209,22 +5120,19 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/json-stringify-safe": { "version": "5.0.1", @@ -5254,7 +5162,6 @@ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, - "peer": true, "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -5486,8 +5393,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==", - "dev": true, - "peer": true + "dev": true }, "node_modules/mcl-wasm": { "version": "0.7.9", @@ -5944,7 +5850,6 @@ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, - "peer": true, "engines": { "node": "*" } @@ -5954,7 +5859,6 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -6103,8 +6007,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", - "dev": true, - "peer": true + "dev": true }, "node_modules/path-exists": { "version": "3.0.0", @@ -6164,8 +6067,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true, - "peer": true + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", @@ -6215,15 +6117,13 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "peer": true + "dev": true }, "node_modules/promise": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", "dev": true, - "peer": true, "dependencies": { "asap": "~2.0.6" } @@ -6247,15 +6147,13 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true, - "peer": true + "dev": true }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -6265,7 +6163,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, - "peer": true, "engines": { "node": ">=0.6" } @@ -6390,7 +6287,6 @@ "resolved": "https://registry.npmjs.org/req-cwd/-/req-cwd-2.0.0.tgz", "integrity": "sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ==", "dev": true, - "peer": true, "dependencies": { "req-from": "^2.0.0" }, @@ -6403,7 +6299,6 @@ "resolved": "https://registry.npmjs.org/req-from/-/req-from-2.0.0.tgz", "integrity": "sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA==", "dev": true, - "peer": true, "dependencies": { "resolve-from": "^3.0.0" }, @@ -6417,7 +6312,6 @@ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, - "peer": true, "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -6449,7 +6343,6 @@ "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", "dev": true, - "peer": true, "dependencies": { "lodash": "^4.17.19" }, @@ -6466,7 +6359,6 @@ "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", "dev": true, - "peer": true, "dependencies": { "request-promise-core": "1.1.4", "stealthy-require": "^1.1.1", @@ -6484,7 +6376,6 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, - "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -6500,7 +6391,6 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, - "peer": true, "bin": { "uuid": "bin/uuid" } @@ -6543,7 +6433,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "dev": true, - "peer": true, "engines": { "node": ">=4" } @@ -6872,7 +6761,6 @@ "resolved": "https://registry.npmjs.org/sha1/-/sha1-1.1.1.tgz", "integrity": "sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA==", "dev": true, - "peer": true, "dependencies": { "charenc": ">= 0.0.1", "crypt": ">= 0.0.1" @@ -7605,7 +7493,6 @@ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, - "peer": true, "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -7630,8 +7517,7 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/stacktrace-parser": { "version": "0.1.10", @@ -7665,7 +7551,6 @@ "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g==", "dev": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -7821,7 +7706,6 @@ "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", "dev": true, - "peer": true, "dependencies": { "http-response-object": "^3.0.1", "sync-rpc": "^1.2.1", @@ -7836,7 +7720,6 @@ "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", "dev": true, - "peer": true, "dependencies": { "get-port": "^3.1.0" } @@ -7945,7 +7828,6 @@ "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", "dev": true, - "peer": true, "dependencies": { "@types/concat-stream": "^1.6.0", "@types/form-data": "0.0.33", @@ -7967,15 +7849,13 @@ "version": "8.10.66", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", - "dev": true, - "peer": true + "dev": true }, "node_modules/then-request/node_modules/form-data": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dev": true, - "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -8020,7 +7900,6 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, - "peer": true, "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -8190,7 +8069,6 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, - "peer": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -8365,8 +8243,7 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true, - "peer": true + "dev": true }, "node_modules/typescript": { "version": "4.9.5", @@ -8450,7 +8327,6 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "peer": true, "dependencies": { "punycode": "^2.1.0" } @@ -8488,7 +8364,6 @@ "engines": [ "node >=0.6.0" ], - "peer": true, "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -8727,7 +8602,6 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz", "integrity": "sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA==", "dev": true, - "peer": true, "engines": { "node": ">=0.4.0" } diff --git a/package.json b/package.json index d3a4a4f..92ce79b 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "chai": "^4.3.6", "ethers": "^5.7.1", "hardhat": "^2.11.2", + "hardhat-gas-reporter": "^1.0.9", "nock": "^13.3.2", "solidity-coverage": "^0.8.2", "ts-node": "^10.9.1", diff --git a/test/ERC7432.spec.ts b/test/ERC7432.spec.ts index 4bbe66f..36cfd7d 100644 --- a/test/ERC7432.spec.ts +++ b/test/ERC7432.spec.ts @@ -193,7 +193,7 @@ describe('ERC7432', () => { ) await expect( ERC7432.connect(grantor).revokeRole(PROPERTY_MANAGER, AddressZero, tokenId, userOne.address), - ).to.be.revertedWith(`ERC7432: Account can't revoke this role`) + ).to.be.revertedWith(`ERC7432: Role is not revocable or caller is not the grantee`) }) }) @@ -628,7 +628,7 @@ describe('ERC7432', () => { grantor.address, userOne.address, ), - ).to.be.revertedWith(`ERC7432: Account can't revoke this role`) + ).to.be.revertedWith(`ERC7432: Role is not revocable or caller is not the grantee`) }) }) }) From 9b5437cd58847d3e780ed7d93db41489a208a151 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 19 Sep 2023 10:56:10 -0300 Subject: [PATCH 22/24] ON-476: Adds approval internal function --- contracts/ERC7432/ERC7432.sol | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index 133178e..aac5dcd 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -25,8 +25,7 @@ contract ERC7432 is IERC7432 { modifier onlyApproved(address _tokenAddress, uint256 _tokenId, address _grantor) { require( - isRoleApprovedForAll(_tokenAddress, _grantor, msg.sender) || - getApprovedRole(_tokenAddress, _tokenId, _grantor, msg.sender), + _isRoleApproved(_tokenAddress, _tokenId, _grantor, msg.sender), "ERC7432: sender must be approved" ); _; @@ -83,8 +82,8 @@ contract ERC7432 is IERC7432 { address _revoker, address _grantee ) external override { - bool _isRevokerApproved = isRoleApprovedForAll(_tokenAddress, _revoker, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _revoker, msg.sender); - bool _isGranteeApproved = isRoleApprovedForAll(_tokenAddress, _grantee, msg.sender) || getApprovedRole(_tokenAddress, _tokenId, _grantee, msg.sender); + bool _isRevokerApproved = _isRoleApproved(_tokenAddress, _tokenId, _revoker, msg.sender); + bool _isGranteeApproved = _isRoleApproved(_tokenAddress, _tokenId, _grantee, msg.sender); require(_isRevokerApproved || _isGranteeApproved, "ERC7432: sender must be approved"); address _caller = _isGranteeApproved ? _grantee : _revoker; // In case of operator being approved for both grantee and revoker, the grantee will be the caller. @@ -188,4 +187,13 @@ contract ERC7432 is IERC7432 { ) public view override returns (bool) { return tokenIdApprovals[_grantor][_tokenAddress][_tokenId][_operator]; } + + function _isRoleApproved( + address _tokenAddress, + uint256 _tokenId, + address _grantor, + address _operator + ) internal view returns (bool) { + return isRoleApprovedForAll(_tokenAddress, _grantor, _operator) || getApprovedRole(_tokenAddress, _tokenId, _grantor, _operator); + } } From 3226af9931f703d16f667e3ef1d7ca604d809dc9 Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 19 Sep 2023 10:58:36 -0300 Subject: [PATCH 23/24] ON-476: exclude folders from gas report --- hardhat.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index e98c49e..f15096f 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -13,7 +13,7 @@ module.exports = { }, gasReporter: { enabled: true, - excludeContracts: ['contracts/test'], + excludeContracts: ['contracts/mocks'], gasPrice: 100, token: 'MATIC', currency: 'USD', From 4c0e1dae2de73a442e26acd300f0ddc3dc06cfef Mon Sep 17 00:00:00 2001 From: Daniel Lima Date: Tue, 19 Sep 2023 15:28:11 -0300 Subject: [PATCH 24/24] ON-476: PR fixes --- contracts/ERC7432/ERC7432.sol | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/contracts/ERC7432/ERC7432.sol b/contracts/ERC7432/ERC7432.sol index aac5dcd..f3b8ee1 100644 --- a/contracts/ERC7432/ERC7432.sol +++ b/contracts/ERC7432/ERC7432.sol @@ -23,9 +23,9 @@ contract ERC7432 is IERC7432 { _; } - modifier onlyApproved(address _tokenAddress, uint256 _tokenId, address _grantor) { + modifier onlyApproved(address _tokenAddress, uint256 _tokenId, address _account) { require( - _isRoleApproved(_tokenAddress, _tokenId, _grantor, msg.sender), + _isRoleApproved(_tokenAddress, _tokenId, _account, msg.sender), "ERC7432: sender must be approved" ); _; @@ -82,15 +82,20 @@ contract ERC7432 is IERC7432 { address _revoker, address _grantee ) external override { - bool _isRevokerApproved = _isRoleApproved(_tokenAddress, _tokenId, _revoker, msg.sender); - bool _isGranteeApproved = _isRoleApproved(_tokenAddress, _tokenId, _grantee, msg.sender); - require(_isRevokerApproved || _isGranteeApproved, "ERC7432: sender must be approved"); - - address _caller = _isGranteeApproved ? _grantee : _revoker; // In case of operator being approved for both grantee and revoker, the grantee will be the caller. - + address _caller = _getApprovedCaller(_tokenAddress, _tokenId, _revoker, _grantee); _revokeRole(_role, _tokenAddress, _tokenId, _revoker, _grantee, _caller); } + function _getApprovedCaller(address _tokenAddress, uint256 _tokenId, address _revoker, address _grantee) internal view returns (address) { + if(_isRoleApproved(_tokenAddress, _tokenId, _grantee, msg.sender)){ + return _grantee; + } else if(_isRoleApproved(_tokenAddress, _tokenId, _revoker, msg.sender)){ + return _revoker; + } else { + revert("ERC7432: sender must be approved"); + } + } + function _revokeRole( bytes32 _role, address _tokenAddress,