Skip to content

Commit

Permalink
feat(state-fingerprint-computer-registry): move computer registry int…
Browse files Browse the repository at this point in the history
…o pwn config
  • Loading branch information
ashhanai committed Mar 26, 2024
1 parent aa27f9a commit a2b12dc
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 214 deletions.
48 changes: 46 additions & 2 deletions src/config/PWNConfig.sol
Original file line number Diff line number Diff line change
@@ -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";


Expand Down Expand Up @@ -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 *|
Expand All @@ -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 *|
Expand Down Expand Up @@ -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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 2 additions & 4 deletions src/loan/terms/simple/proposal/PWNSimpleLoanListProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions src/loan/terms/simple/proposal/PWNSimpleLoanProposal.sol
Original file line number Diff line number Diff line change
@@ -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";

/**
Expand All @@ -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.
Expand All @@ -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)"),
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 0 additions & 57 deletions src/state-fingerprint/StateFingerprintComputerRegistry.sol

This file was deleted.

121 changes: 118 additions & 3 deletions test/unit/PWNConfig.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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);
Expand All @@ -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)
);
}

}


Expand Down Expand Up @@ -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);
}

}
2 changes: 1 addition & 1 deletion test/unit/PWNSimpleLoanDutchAuctionProposal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
2 changes: 1 addition & 1 deletion test/unit/PWNSimpleLoanFungibleProposal.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
Loading

0 comments on commit a2b12dc

Please sign in to comment.