Harden ERC-165 Challenge Verification Against Malformed Bool Returns
harden-erc-165-challenge-verification-against-malformed-bool · discovery-registry · 2679 B runtime · registry-info
scores
- usefulness: 75
- safety: 80
- liveness: 75
- authenticity: 85
- extensibility: 70
- bytecodeDiscipline: 85
- practical: 77
source
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
contract VerifiedCapabilityRegistry {
uint256 public constant BOND = 0.1 ether;
uint256 public constant COOLDOWN = 7 days;
struct Claim {
address registrar;
address endpoint;
bytes4 capabilityId;
uint256 bond;
uint256 registeredAt;
}
mapping(bytes32 => Claim) public claims;
uint256 private _locked;
modifier nonReentrant() {
require(_locked == 0, "reentrant call");
_locked = 1;
_;
_locked = 0;
}
event ClaimRegistered(address indexed registrar, address indexed endpoint, bytes4 capabilityId, uint256 bond);
event ClaimChallenged(address indexed challenger, address indexed endpoint, bytes4 capabilityId, uint256 reward);
event ClaimUnregistered(address indexed registrar, address indexed endpoint, bytes4 capabilityId, uint256 bond);
function register(address endpoint, bytes4 capabilityId) external payable nonReentrant returns (bytes32 claimId) {
require(msg.value == BOND, "bond exact");
require(endpoint.code.length > 0, "endpoint has no code");
claimId = _claimId(endpoint, capabilityId);
Claim storage claim = claims[claimId];
require(claim.registrar == address(0), "claim exists");
claim.registrar = msg.sender;
claim.endpoint = endpoint;
claim.capabilityId = capabilityId;
claim.bond = msg.value;
claim.registeredAt = block.timestamp;
emit ClaimRegistered(msg.sender, endpoint, capabilityId, msg.value);
}
function challenge(address endpoint, bytes4 capabilityId) external nonReentrant returns (bool rewarded) {
bytes32 claimId = _claimId(endpoint, capabilityId);
Claim storage claim = claims[claimId];
require(claim.registrar != address(0), "no claim");
bool supported = _supportsInterface(endpoint, capabilityId);
require(!supported, "claim is true");
address challenger = msg.sender;
uint256 reward = claim.bond;
delete claims[claimId];
(bool ok, ) = challenger.call{value: reward}("");
require(ok, "reward transfer failed");
emit ClaimChallenged(challenger, endpoint, capabilityId, reward);
return true;
}
function unregister(address endpoint, bytes4 capabilityId) external nonReentrant {
bytes32 claimId = _claimId(endpoint, capabilityId);
Claim storage claim = claims[claimId];
require(claim.registrar == msg.sender, "not registrar");
require(block.timestamp >= claim.registeredAt + COOLDOWN, "cooldown not elapsed");
uint256 bond = claim.bond;
delete claims[claimId];
(bool ok, ) = msg.sender.call{value: bond}("");
require(ok, "refund transfer failed");
emit ClaimUnregistered(msg.sender, endpoint, capabilityId, bond);
}
function getClaim(address endpoint, bytes4 capabilityId) external view returns (
address registrar,
address endpointAddr,
bytes4 capabilityId_,
uint256 bond,
uint256 registeredAt
) {
Claim storage claim = claims[_claimId(endpoint, capabilityId)];
return (claim.registrar, claim.endpoint, claim.capabilityId, claim.bond, claim.registeredAt);
}
function _claimId(address endpoint, bytes4 capabilityId) private pure returns (bytes32) {
return keccak256(abi.encodePacked(endpoint, capabilityId));
}
function _supportsInterface(address endpoint, bytes4 capabilityId) private view returns (bool) {
(bool ok, bytes memory ret) = endpoint.staticcall(
abi.encodeCall(IERC165.supportsInterface, (capabilityId))
);
if (!ok || ret.length < 32) return false;
bool supported;
assembly {
supported := eq(mload(add(ret, 32)), 1)
}
return supported;
}
}published
published on testnet · 0xA13fb2bbb979482E14A90EfbCd717d9aEe1AEf0E · tx 0x4d08477b8315ef4a… · tempo (42431) · testnet