Update cache to use explicit return values of 32 byte length

This commit is contained in:
William Entriken 2018-02-16 06:51:50 -05:00 committed by GitHub
parent 50f59da47f
commit 529ce1b2ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 33 additions and 16 deletions

View File

@ -36,11 +36,11 @@ For this standard, an *interface* is a set of [function selectors as calculated
We define the interface identifier as the XOR of all function selectors in the interface. This code example shows how to calculate an interface identifier: We define the interface identifier as the XOR of all function selectors in the interface. This code example shows how to calculate an interface identifier:
```solidity ```solidity
pragma solidity ^0.4.19; pragma solidity ^0.4.20;
interface Solidity101 { interface Solidity101 {
function hello() public pure; function hello() external pure;
function world(int) public pure; function world(int) external pure;
} }
contract Selector { contract Selector {
@ -58,7 +58,7 @@ Note: interfaces do not permit optional functions, therefore, the interface iden
A contract that is compliant with ERC-165 shall implement the following interface (referred as `ERC165.sol`): A contract that is compliant with ERC-165 shall implement the following interface (referred as `ERC165.sol`):
```solidity ```solidity
pragma solidity ^0.4.19; pragma solidity ^0.4.20;
interface ERC165 { interface ERC165 {
/// @notice Query if a contract implements an interface /// @notice Query if a contract implements an interface
@ -113,7 +113,7 @@ Also [the ENS](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-137.md) alr
Following is a caching contract that detects which interfaces other contracts implement. From @fulldecent and @jbaylina. Following is a caching contract that detects which interfaces other contracts implement. From @fulldecent and @jbaylina.
```solidity ```solidity
pragma solidity ^0.4.19; pragma solidity ^0.4.20;
contract ERC165Cache { contract ERC165Cache {
bytes4 constant InvalidID = 0xffffffff; bytes4 constant InvalidID = 0xffffffff;
@ -139,25 +139,42 @@ contract ERC165Cache {
} }
function determineInterfaceImplementationStatus(address _contract, bytes4 _interfaceId) internal view returns (ImplStatus) { function determineInterfaceImplementationStatus(address _contract, bytes4 _interfaceId) internal view returns (ImplStatus) {
if (noThrowCall(_contract, InvalidID)) return ImplStatus.No; uint256 success;
if (!noThrowCall(_contract, ERC165ID)) return ImplStatus.No; uint256 result;
if (noThrowCall(_contract, _interfaceId)) return ImplStatus.Yes;
(success, result) = noThrowCall(_contract, ERC165ID);
if ((success==0)||(result==0)) {
return ImplStatus.No; return ImplStatus.No;
} }
function noThrowCall(address _contract, bytes4 _interfaceId) internal view returns (bool result) { (success, result) = noThrowCall(_contract, InvalidID);
if ((success==0)||(result!=0)) {
return ImplStatus.No;
}
(success, result) = noThrowCall(_contract, _interfaceId);
if ((success==1)&&(result==1)) {
return ImplStatus.Yes;
}
return ImplStatus.No;
}
function noThrowCall(address _contract, bytes4 _interfaceId) constant internal returns (uint256 success, uint256 result) {
bytes4 erc165ID = ERC165ID; bytes4 erc165ID = ERC165ID;
assembly { assembly {
let x := mload(0x40) // Find empty storage location using "free memory pointer" let x := mload(0x40) // Find empty storage location using "free memory pointer"
mstore(x, erc165ID) // Place signature at begining of empty storage mstore(x, erc165ID) // Place signature at begining of empty storage
mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature
staticcall(30000, // 30k gas
success := staticcall(
30000, // 5k gas
_contract, // To addr _contract, // To addr
x, // Inputs are stored at location x x, // Inputs are stored at location x
0x8, // Inputs are 8 byes long 0x8, // Inputs are 8 byes long
x, // Store output over input (saves space) x, // Store output over input (saves space)
0x20) // Outputs are 32 bytes long 0x20) // Outputs are 32 bytes long
pop // Discard call return value
result := mload(x) // Load the result result := mload(x) // Load the result
} }
} }