diff --git a/src/config/PWNConfig.sol b/src/config/PWNConfig.sol index 025e3cd..1730b9f 100644 --- a/src/config/PWNConfig.sol +++ b/src/config/PWNConfig.sol @@ -1,9 +1,11 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.16; -import "openzeppelin-contracts/contracts/access/Ownable2Step.sol"; -import "openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; +import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol"; +import { Initializable } from "openzeppelin-contracts/contracts/proxy/utils/Initializable.sol"; +import { ERC165Checker } from "openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol"; +import { IERC5646 } from "@pwn/loan/token/IERC5646.sol"; import "@pwn/PWNErrors.sol"; @@ -40,6 +42,11 @@ contract PWNConfig is Ownable2Step, Initializable { */ mapping (address => string) private _loanMetadataUri; + /** + * @notice Mapping holding registered computer to an asset. + * @dev Only owner can update the mapping. + */ + mapping (address => address) private _computerRegistry; /*----------------------------------------------------------*| |* # EVENTS & ERRORS DEFINITIONS *| @@ -65,6 +72,10 @@ contract PWNConfig is Ownable2Step, Initializable { */ event DefaultLOANMetadataUriUpdated(string newUri); + /** + * @notice Error emitted when registering a computer which does not implement the IERC5646 interface. + */ + error InvalidComputerContract(); /*----------------------------------------------------------*| |* # CONSTRUCTOR *| @@ -167,4 +178,37 @@ contract PWNConfig is Ownable2Step, Initializable { uri = _loanMetadataUri[address(0)]; } + + /*----------------------------------------------------------*| + |* # STATE FINGERPRINT COMPUTER *| + |*----------------------------------------------------------*/ + + /** + * @notice Returns the ERC5646 computer for a given asset. + * @param asset The asset for which the computer is requested. + * @return The computer for the given asset. + */ + function getStateFingerprintComputer(address asset) external view returns (IERC5646) { + address computer = _computerRegistry[asset]; + if (computer == address(0)) + if (ERC165Checker.supportsInterface(asset, type(IERC5646).interfaceId)) + computer = asset; + + return IERC5646(computer); + } + + /** + * @notice Registers a state fingerprint computer for a given asset. + * @dev Only owner can register a computer. Computer can be set to address(0) to remove the computer. + * @param asset The asset for which the computer is registered. + * @param computer The computer to be registered. + */ + function registerStateFingerprintComputer(address asset, address computer) external onlyOwner { + if (computer != address(0)) + if (!ERC165Checker.supportsInterface(computer, type(IERC5646).interfaceId)) + revert InvalidComputerContract(); + + _computerRegistry[asset] = computer; + } + } diff --git a/src/loan/terms/simple/proposal/PWNSimpleLoanDutchAuctionProposal.sol b/src/loan/terms/simple/proposal/PWNSimpleLoanDutchAuctionProposal.sol index dcecda2..80b5e53 100644 --- a/src/loan/terms/simple/proposal/PWNSimpleLoanDutchAuctionProposal.sol +++ b/src/loan/terms/simple/proposal/PWNSimpleLoanDutchAuctionProposal.sol @@ -97,10 +97,8 @@ contract PWNSimpleLoanDutchAuctionProposal is PWNSimpleLoanProposal { constructor( address _hub, address _revokedNonce, - address _stateFingerprintComputerRegistry - ) PWNSimpleLoanProposal( - _hub, _revokedNonce, _stateFingerprintComputerRegistry, "PWNSimpleLoanDutchAuctionProposal", VERSION - ) {} + address _config + ) PWNSimpleLoanProposal(_hub, _revokedNonce, _config, "PWNSimpleLoanDutchAuctionProposal", VERSION) {} /** * @notice Get an proposal hash according to EIP-712 diff --git a/src/loan/terms/simple/proposal/PWNSimpleLoanFungibleProposal.sol b/src/loan/terms/simple/proposal/PWNSimpleLoanFungibleProposal.sol index a02ab90..58b11c0 100644 --- a/src/loan/terms/simple/proposal/PWNSimpleLoanFungibleProposal.sol +++ b/src/loan/terms/simple/proposal/PWNSimpleLoanFungibleProposal.sol @@ -96,10 +96,8 @@ contract PWNSimpleLoanFungibleProposal is PWNSimpleLoanProposal { constructor( address _hub, address _revokedNonce, - address _stateFingerprintComputerRegistry - ) PWNSimpleLoanProposal( - _hub, _revokedNonce, _stateFingerprintComputerRegistry, "PWNSimpleLoanFungibleProposal", VERSION - ) {} + address _config + ) PWNSimpleLoanProposal(_hub, _revokedNonce, _config, "PWNSimpleLoanFungibleProposal", VERSION) {} /** * @notice Get an proposal hash according to EIP-712 diff --git a/src/loan/terms/simple/proposal/PWNSimpleLoanListProposal.sol b/src/loan/terms/simple/proposal/PWNSimpleLoanListProposal.sol index 6c7db90..7703922 100644 --- a/src/loan/terms/simple/proposal/PWNSimpleLoanListProposal.sol +++ b/src/loan/terms/simple/proposal/PWNSimpleLoanListProposal.sol @@ -94,10 +94,8 @@ contract PWNSimpleLoanListProposal is PWNSimpleLoanProposal { constructor( address _hub, address _revokedNonce, - address _stateFingerprintComputerRegistry - ) PWNSimpleLoanProposal( - _hub, _revokedNonce, _stateFingerprintComputerRegistry, "PWNSimpleLoanListProposal", VERSION - ) {} + address _config + ) PWNSimpleLoanProposal(_hub, _revokedNonce, _config, "PWNSimpleLoanListProposal", VERSION) {} /** * @notice Get an proposal hash according to EIP-712 diff --git a/src/loan/terms/simple/proposal/PWNSimpleLoanProposal.sol b/src/loan/terms/simple/proposal/PWNSimpleLoanProposal.sol index f0a1f54..cbcefa9 100644 --- a/src/loan/terms/simple/proposal/PWNSimpleLoanProposal.sol +++ b/src/loan/terms/simple/proposal/PWNSimpleLoanProposal.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.16; +import { PWNConfig, IERC5646 } from "@pwn/config/PWNConfig.sol"; import { PWNHub } from "@pwn/hub/PWNHub.sol"; import { PWNHubTags } from "@pwn/hub/PWNHubTags.sol"; import { PWNSignatureChecker } from "@pwn/loan/lib/PWNSignatureChecker.sol"; import { Permit } from "@pwn/loan/vault/Permit.sol"; import { PWNRevokedNonce } from "@pwn/nonce/PWNRevokedNonce.sol"; -import { StateFingerprintComputerRegistry, IERC5646 } from "@pwn/state-fingerprint/StateFingerprintComputerRegistry.sol"; import "@pwn/PWNErrors.sol"; /** @@ -22,7 +22,7 @@ abstract contract PWNSimpleLoanProposal { PWNHub public immutable hub; PWNRevokedNonce public immutable revokedNonce; - StateFingerprintComputerRegistry public immutable stateFingerprintComputerRegistry; + PWNConfig public immutable config; /** * @dev Mapping of proposals made via on-chain transactions. @@ -40,13 +40,13 @@ abstract contract PWNSimpleLoanProposal { constructor( address _hub, address _revokedNonce, - address _stateFingerprintComputerRegistry, + address _config, string memory name, string memory version ) { hub = PWNHub(_hub); revokedNonce = PWNRevokedNonce(_revokedNonce); - stateFingerprintComputerRegistry = StateFingerprintComputerRegistry(_stateFingerprintComputerRegistry); + config = PWNConfig(_config); DOMAIN_SEPARATOR = keccak256(abi.encode( keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"), @@ -155,7 +155,7 @@ abstract contract PWNSimpleLoanProposal { * @param stateFingerprint Proposed state fingerprint. */ function _checkCollateralState(address addr, uint256 id, bytes32 stateFingerprint) internal view { - IERC5646 computer = stateFingerprintComputerRegistry.getStateFingerprintComputer(addr); + IERC5646 computer = config.getStateFingerprintComputer(addr); if (address(computer) == address(0)) { // Asset is not implementing ERC5646 and no computer is registered revert MissingStateFingerprintComputer(); diff --git a/src/loan/terms/simple/proposal/PWNSimpleLoanSimpleProposal.sol b/src/loan/terms/simple/proposal/PWNSimpleLoanSimpleProposal.sol index fe8c1e4..1415885 100644 --- a/src/loan/terms/simple/proposal/PWNSimpleLoanSimpleProposal.sol +++ b/src/loan/terms/simple/proposal/PWNSimpleLoanSimpleProposal.sol @@ -79,10 +79,8 @@ contract PWNSimpleLoanSimpleProposal is PWNSimpleLoanProposal { constructor( address _hub, address _revokedNonce, - address _stateFingerprintComputerRegistry - ) PWNSimpleLoanProposal( - _hub, _revokedNonce, _stateFingerprintComputerRegistry, "PWNSimpleLoanSimpleProposal", VERSION - ) {} + address _config + ) PWNSimpleLoanProposal(_hub, _revokedNonce, _config, "PWNSimpleLoanSimpleProposal", VERSION) {} /** * @notice Get an proposal hash according to EIP-712 diff --git a/src/state-fingerprint/StateFingerprintComputerRegistry.sol b/src/state-fingerprint/StateFingerprintComputerRegistry.sol deleted file mode 100644 index d037023..0000000 --- a/src/state-fingerprint/StateFingerprintComputerRegistry.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity 0.8.16; - -import { Ownable2Step } from "openzeppelin-contracts/contracts/access/Ownable2Step.sol"; -import { ERC165Checker } from "openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sol"; - -import { IERC5646 } from "@pwn/loan/token/IERC5646.sol"; - - -/** - * @title State Fingerprint Computer Registry - * @notice Registry for state fingerprint computers. - * @dev The computers are used to calculate the state fingerprint of an asset. - * It can be a dedicated contract or the asset itself if it implements the IERC5646 interface. - */ -contract StateFingerprintComputerRegistry is Ownable2Step { - - /** - * @notice Error emitted when registering a computer which does not implement the IERC5646 interface. - */ - error InvalidComputerContract(); - - /** - * @notice Mapping holding registered computer to an asset. - * @dev Only owner can update the mapping. - */ - mapping (address => address) private _computerRegistry; - - /** - * @notice Returns the ERC5646 computer for a given asset. - * @param asset The asset for which the computer is requested. - * @return The computer for the given asset. - */ - function getStateFingerprintComputer(address asset) external view returns (IERC5646) { - address computer = _computerRegistry[asset]; - if (computer == address(0)) - if (ERC165Checker.supportsInterface(asset, type(IERC5646).interfaceId)) - computer = asset; - - return IERC5646(computer); - } - - /** - * @notice Registers a state fingerprint computer for a given asset. - * @dev Only owner can register a computer. Computer can be set to address(0) to remove the computer. - * @param asset The asset for which the computer is registered. - * @param computer The computer to be registered. - */ - function registerStateFingerprintComputer(address asset, address computer) external onlyOwner { - if (computer != address(0)) - if (!ERC165Checker.supportsInterface(computer, type(IERC5646).interfaceId)) - revert InvalidComputerContract(); - - _computerRegistry[asset] = computer; - } - -} diff --git a/test/unit/PWNConfig.t.sol b/test/unit/PWNConfig.t.sol index 198bf1c..b935f28 100644 --- a/test/unit/PWNConfig.t.sol +++ b/test/unit/PWNConfig.t.sol @@ -3,7 +3,10 @@ pragma solidity 0.8.16; import "forge-std/Test.sol"; -import "@pwn/config/PWNConfig.sol"; +import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; + +import { PWNConfig, IERC5646 } from "@pwn/config/PWNConfig.sol"; +import "@pwn/PWNErrors.sol"; abstract contract PWNConfigTest is Test { @@ -14,10 +17,11 @@ abstract contract PWNConfigTest is Test { bytes32 internal constant FEE_SLOT = bytes32(uint256(1)); // `fee` property position bytes32 internal constant FEE_COLLECTOR_SLOT = bytes32(uint256(2)); // `feeCollector` property position bytes32 internal constant LOAN_METADATA_URI_SLOT = bytes32(uint256(3)); // `loanMetadataUri` mapping position + bytes32 internal constant REGISTRY_SLOT = bytes32(uint256(4)); // `_computerRegistry` mapping position PWNConfig config; - address owner = address(0x43); - address feeCollector = address(0xfeeC001ec704); + address owner = makeAddr("owner"); + address feeCollector = makeAddr("feeCollector"); event FeeUpdated(uint16 oldFee, uint16 newFee); event FeeCollectorUpdated(address oldFeeCollector, address newFeeCollector); @@ -34,6 +38,20 @@ abstract contract PWNConfigTest is Test { vm.store(address(config), FEE_COLLECTOR_SLOT, bytes32(uint256(uint160(feeCollector)))); } + function _mockERC5646Support(address asset, bool result) internal { + _mockERC165Call(asset, type(IERC165).interfaceId, true); + _mockERC165Call(asset, hex"ffffffff", false); + _mockERC165Call(asset, type(IERC5646).interfaceId, result); + } + + function _mockERC165Call(address asset, bytes4 interfaceId, bool result) internal { + vm.mockCall( + asset, + abi.encodeWithSignature("supportsInterface(bytes4)", interfaceId), + abi.encode(result) + ); + } + } @@ -341,3 +359,100 @@ contract PWNConfig_LoanMetadataUri_Test is PWNConfigTest { } } + + +/*----------------------------------------------------------*| +|* # GET STATE FINGERPRINT COMPUTER *| +|*----------------------------------------------------------*/ + +contract PWNConfig_GetStateFingerprintComputer_Test is PWNConfigTest { + + function setUp() override public { + super.setUp(); + + _initialize(); + } + + + function testFuzz_shouldReturnStoredComputer_whenIsRegistered(address asset, address computer) external { + bytes32 assetSlot = keccak256(abi.encode(asset, REGISTRY_SLOT)); + vm.store(address(config), assetSlot, bytes32(uint256(uint160(computer)))); + + assertEq(address(config.getStateFingerprintComputer(asset)), computer); + } + + function testFuzz_shouldReturnAsset_whenComputerIsNotRegistered_whenAssetImplementsERC5646(address asset) external { + assumeAddressIsNot(asset, AddressType.ForgeAddress, AddressType.Precompile); + + _mockERC5646Support(asset, true); + + assertEq(address(config.getStateFingerprintComputer(asset)), asset); + } + + function testFuzz_shouldReturnZeroAddress_whenComputerIsNotRegistered_whenAssetNotImplementsERC5646(address asset) external { + assertEq(address(config.getStateFingerprintComputer(asset)), address(0)); + } + +} + + +/*----------------------------------------------------------*| +|* # REGISTER STATE FINGERPRINT COMPUTER *| +|*----------------------------------------------------------*/ + +contract PWNConfig_RegisterStateFingerprintComputer_Test is PWNConfigTest { + + function setUp() override public { + super.setUp(); + + _initialize(); + } + + + function testFuzz_shouldFail_whenCallerIsNotOwner(address caller) external { + vm.assume(caller != owner); + + vm.expectRevert("Ownable: caller is not the owner"); + vm.prank(caller); + config.registerStateFingerprintComputer(address(0), address(0)); + } + + function testFuzz_shouldUnregisterComputer_whenComputerIsZeroAddress(address asset) external { + address computer = makeAddr("computer"); + bytes32 assetSlot = keccak256(abi.encode(asset, REGISTRY_SLOT)); + vm.store(address(config), assetSlot, bytes32(uint256(uint160(computer)))); + + vm.prank(owner); + config.registerStateFingerprintComputer(asset, address(0)); + + assertEq(address(config.getStateFingerprintComputer(asset)), address(0)); + } + + function testFuzz_shouldFail_whenComputerDoesNotImplementERC165(address asset, address computer) external { + assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); + + vm.expectRevert(abi.encodeWithSelector(PWNConfig.InvalidComputerContract.selector)); + vm.prank(owner); + config.registerStateFingerprintComputer(asset, computer); + } + + function testFuzz_shouldFail_whenComputerDoesNotImplementERC5646(address asset, address computer) external { + assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); + _mockERC5646Support(computer, false); + + vm.expectRevert(abi.encodeWithSelector(PWNConfig.InvalidComputerContract.selector)); + vm.prank(owner); + config.registerStateFingerprintComputer(asset, computer); + } + + function testFuzz_shouldRegisterComputer(address asset, address computer) external { + assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); + _mockERC5646Support(computer, true); + + vm.prank(owner); + config.registerStateFingerprintComputer(asset, computer); + + assertEq(address(config.getStateFingerprintComputer(asset)), computer); + } + +} diff --git a/test/unit/PWNSimpleLoanDutchAuctionProposal.t.sol b/test/unit/PWNSimpleLoanDutchAuctionProposal.t.sol index f95eddb..e744f35 100644 --- a/test/unit/PWNSimpleLoanDutchAuctionProposal.t.sol +++ b/test/unit/PWNSimpleLoanDutchAuctionProposal.t.sol @@ -32,7 +32,7 @@ abstract contract PWNSimpleLoanDutchAuctionProposalTest is PWNSimpleLoanProposal function setUp() virtual public override { super.setUp(); - proposalContract = new PWNSimpleLoanDutchAuctionProposal(hub, revokedNonce, stateFingerprintComputerRegistry); + proposalContract = new PWNSimpleLoanDutchAuctionProposal(hub, revokedNonce, config); proposalContractAddr = PWNSimpleLoanProposal(proposalContract); proposal = PWNSimpleLoanDutchAuctionProposal.Proposal({ diff --git a/test/unit/PWNSimpleLoanFungibleProposal.t.sol b/test/unit/PWNSimpleLoanFungibleProposal.t.sol index ed0dfd5..b8b011e 100644 --- a/test/unit/PWNSimpleLoanFungibleProposal.t.sol +++ b/test/unit/PWNSimpleLoanFungibleProposal.t.sol @@ -32,7 +32,7 @@ abstract contract PWNSimpleLoanFungibleProposalTest is PWNSimpleLoanProposalTest function setUp() virtual public override { super.setUp(); - proposalContract = new PWNSimpleLoanFungibleProposal(hub, revokedNonce, stateFingerprintComputerRegistry); + proposalContract = new PWNSimpleLoanFungibleProposal(hub, revokedNonce, config); proposalContractAddr = PWNSimpleLoanProposal(proposalContract); proposal = PWNSimpleLoanFungibleProposal.Proposal({ diff --git a/test/unit/PWNSimpleLoanListProposal.t.sol b/test/unit/PWNSimpleLoanListProposal.t.sol index 136a65e..c2f97ba 100644 --- a/test/unit/PWNSimpleLoanListProposal.t.sol +++ b/test/unit/PWNSimpleLoanListProposal.t.sol @@ -32,7 +32,7 @@ abstract contract PWNSimpleLoanListProposalTest is PWNSimpleLoanProposalTest { function setUp() virtual public override { super.setUp(); - proposalContract = new PWNSimpleLoanListProposal(hub, revokedNonce, stateFingerprintComputerRegistry); + proposalContract = new PWNSimpleLoanListProposal(hub, revokedNonce, config); proposalContractAddr = PWNSimpleLoanProposal(proposalContract); proposal = PWNSimpleLoanListProposal.Proposal({ diff --git a/test/unit/PWNSimpleLoanProposal.t.sol b/test/unit/PWNSimpleLoanProposal.t.sol index c3e3e5e..e229a31 100644 --- a/test/unit/PWNSimpleLoanProposal.t.sol +++ b/test/unit/PWNSimpleLoanProposal.t.sol @@ -20,7 +20,7 @@ abstract contract PWNSimpleLoanProposalTest is Test { address public hub = makeAddr("hub"); address public revokedNonce = makeAddr("revokedNonce"); - address public stateFingerprintComputerRegistry = makeAddr("stateFingerprintComputerRegistry"); + address public config = makeAddr("config"); address public stateFingerprintComputer = makeAddr("stateFingerprintComputer"); address public activeLoanContract = makeAddr("activeLoanContract"); address public token = makeAddr("token"); @@ -84,7 +84,7 @@ abstract contract PWNSimpleLoanProposalTest is Test { ); vm.mockCall( - stateFingerprintComputerRegistry, + config, abi.encodeWithSignature("getStateFingerprintComputer(address)"), abi.encode(stateFingerprintComputer) ); @@ -153,7 +153,7 @@ abstract contract PWNSimpleLoanProposal_AcceptProposal_Test is PWNSimpleLoanProp params.checkCollateralStateFingerprint = false; vm.expectCall({ - callee: stateFingerprintComputerRegistry, + callee: config, data: abi.encodeWithSignature("getStateFingerprintComputer(address)"), count: 0 }); @@ -163,7 +163,7 @@ abstract contract PWNSimpleLoanProposal_AcceptProposal_Test is PWNSimpleLoanProp function test_shouldFail_whenComputerRegistryReturnsZeroAddress_whenShouldCheckStateFingerprint() external { vm.mockCall( - stateFingerprintComputerRegistry, + config, abi.encodeWithSignature("getStateFingerprintComputer(address)", token), // test expects `token` being used as collateral asset abi.encode(address(0)) ); @@ -426,7 +426,7 @@ abstract contract PWNSimpleLoanProposal_AcceptRefinanceProposal_Test is PWNSimpl params.checkCollateralStateFingerprint = false; vm.expectCall({ - callee: stateFingerprintComputerRegistry, + callee: config, data: abi.encodeWithSignature("getStateFingerprintComputer(address)"), count: 0 }); @@ -436,7 +436,7 @@ abstract contract PWNSimpleLoanProposal_AcceptRefinanceProposal_Test is PWNSimpl function test_shouldFail_whenComputerRegistryReturnsZeroAddress_whenShouldCheckStateFingerprint() external { vm.mockCall( - stateFingerprintComputerRegistry, + config, abi.encodeWithSignature("getStateFingerprintComputer(address)", token), // test expects `token` being used as collateral asset abi.encode(address(0)) ); diff --git a/test/unit/PWNSimpleLoanSimpleProposal.t.sol b/test/unit/PWNSimpleLoanSimpleProposal.t.sol index 8eb8c79..c7e6e86 100644 --- a/test/unit/PWNSimpleLoanSimpleProposal.t.sol +++ b/test/unit/PWNSimpleLoanSimpleProposal.t.sol @@ -29,7 +29,7 @@ abstract contract PWNSimpleLoanSimpleProposalTest is PWNSimpleLoanProposalTest { function setUp() virtual public override { super.setUp(); - proposalContract = new PWNSimpleLoanSimpleProposal(hub, revokedNonce, stateFingerprintComputerRegistry); + proposalContract = new PWNSimpleLoanSimpleProposal(hub, revokedNonce, config); proposalContractAddr = PWNSimpleLoanProposal(proposalContract); proposal = PWNSimpleLoanSimpleProposal.Proposal({ diff --git a/test/unit/StateFingerprintComputerRegistry.t.sol b/test/unit/StateFingerprintComputerRegistry.t.sol deleted file mode 100644 index 0e5d6b2..0000000 --- a/test/unit/StateFingerprintComputerRegistry.t.sol +++ /dev/null @@ -1,121 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -pragma solidity 0.8.16; - -import "forge-std/Test.sol"; - -import { IERC165 } from "openzeppelin-contracts/contracts/utils/introspection/IERC165.sol"; - -import { StateFingerprintComputerRegistry, IERC5646 } from "@pwn/state-fingerprint/StateFingerprintComputerRegistry.sol"; - - -abstract contract StateFingerprintComputerRegistryTest is Test { - - bytes32 internal constant OWNER_SLOT = bytes32(uint256(0)); - bytes32 internal constant REGISTRY_SLOT = bytes32(uint256(2)); - - address owner = makeAddr("owner"); - StateFingerprintComputerRegistry registry; - - function setUp() external { - vm.prank(owner); - registry = new StateFingerprintComputerRegistry(); - } - - function _mockERC5646Support(address asset, bool result) internal { - _mockERC165Call(asset, type(IERC165).interfaceId, true); - _mockERC165Call(asset, hex"ffffffff", false); - _mockERC165Call(asset, type(IERC5646).interfaceId, result); - } - - function _mockERC165Call(address asset, bytes4 interfaceId, bool result) internal { - vm.mockCall( - asset, - abi.encodeWithSignature("supportsInterface(bytes4)", interfaceId), - abi.encode(result) - ); - } - -} - - -/*----------------------------------------------------------*| -|* # GET STATE FINGERPRINT COMPUTER *| -|*----------------------------------------------------------*/ - -contract StateFingerprintComputerRegistry_GetStateFingerprintComputer_Test is StateFingerprintComputerRegistryTest { - - function testFuzz_shouldReturnStoredComputer_whenIsRegistered(address asset, address computer) external { - bytes32 assetSlot = keccak256(abi.encode(asset, REGISTRY_SLOT)); - vm.store(address(registry), assetSlot, bytes32(uint256(uint160(computer)))); - - assertEq(address(registry.getStateFingerprintComputer(asset)), computer); - } - - function testFuzz_shouldReturnAsset_whenComputerIsNotRegistered_whenAssetImplementsERC5646(address asset) external { - assumeAddressIsNot(asset, AddressType.ForgeAddress, AddressType.Precompile); - - _mockERC5646Support(asset, true); - - assertEq(address(registry.getStateFingerprintComputer(asset)), asset); - } - - function testFuzz_shouldReturnZeroAddress_whenComputerIsNotRegistered_whenAssetNotImplementsERC5646(address asset) external { - assertEq(address(registry.getStateFingerprintComputer(asset)), address(0)); - } - -} - - -/*----------------------------------------------------------*| -|* # REGISTER STATE FINGERPRINT COMPUTER *| -|*----------------------------------------------------------*/ - -contract StateFingerprintComputerRegistry_RegisterStateFingerprintComputer_Test is StateFingerprintComputerRegistryTest { - - function testFuzz_shouldFail_whenCallerIsNotOwner(address caller) external { - vm.assume(caller != owner); - - vm.expectRevert("Ownable: caller is not the owner"); - vm.prank(caller); - registry.registerStateFingerprintComputer(address(0), address(0)); - } - - function testFuzz_shouldUnregisterComputer_whenComputerIsZeroAddress(address asset) external { - address computer = makeAddr("computer"); - bytes32 assetSlot = keccak256(abi.encode(asset, REGISTRY_SLOT)); - vm.store(address(registry), assetSlot, bytes32(uint256(uint160(computer)))); - - vm.prank(owner); - registry.registerStateFingerprintComputer(asset, address(0)); - - assertEq(address(registry.getStateFingerprintComputer(asset)), address(0)); - } - - function testFuzz_shouldFail_whenComputerDoesNotImplementERC165(address asset, address computer) external { - assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); - - vm.expectRevert(abi.encodeWithSelector(StateFingerprintComputerRegistry.InvalidComputerContract.selector)); - vm.prank(owner); - registry.registerStateFingerprintComputer(asset, computer); - } - - function testFuzz_shouldFail_whenComputerDoesNotImplementERC5646(address asset, address computer) external { - assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); - _mockERC5646Support(computer, false); - - vm.expectRevert(abi.encodeWithSelector(StateFingerprintComputerRegistry.InvalidComputerContract.selector)); - vm.prank(owner); - registry.registerStateFingerprintComputer(asset, computer); - } - - function testFuzz_shouldRegisterComputer(address asset, address computer) external { - assumeAddressIsNot(computer, AddressType.ForgeAddress, AddressType.Precompile, AddressType.ZeroAddress); - _mockERC5646Support(computer, true); - - vm.prank(owner); - registry.registerStateFingerprintComputer(asset, computer); - - assertEq(address(registry.getStateFingerprintComputer(asset)), computer); - } - -}