Skip to content
This repository has been archived by the owner on Apr 17, 2019. It is now read-only.

Commit

Permalink
Magic return
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaylina committed Feb 24, 2018
1 parent fa7777b commit 78eb6fa
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 30 deletions.
2 changes: 1 addition & 1 deletion contracts/ERC820Implementer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ contract ERC820Registry {
}

contract ERC820Implementer {
ERC820Registry erc820Registry = ERC820Registry(0x2634839Fb9cad4E0DD41482B72bc8cBc58a0D392);
ERC820Registry erc820Registry = ERC820Registry(0x991a1bcb077599290d7305493c9A630c20f8b798);

function setInterfaceImplementation(string ifaceLabel, address impl) internal {
bytes32 ifaceHash = keccak256(ifaceLabel);
Expand Down
6 changes: 4 additions & 2 deletions contracts/ERC820ImplementerInterface.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
pragma solidity ^0.4.18;

contract ERC820ImplementerInterface {

bytes32 constant ERC820_ACCEPT_MAGIC = keccak256("ERC820_ACCEPT_MAGIC");
/// @notice Contracts that implement an interferce in behalf of another contract must return true
/// @param addr Address that the contract woll implement the interface in behalf of
/// @param interfaceHash keccak256 of the name of the interface
/// @return true if the contract can implement the interface represented by
/// @return ERC820_ACCEPT_MAGIC if the contract can implement the interface represented by
/// `ìnterfaceHash` in behalf of `addr`
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bool);
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bytes32);
}
13 changes: 8 additions & 5 deletions contracts/ERC820Registry.sol
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
pragma solidity 0.4.20;

contract ERC820ImplementerInterface {
interface ERC820ImplementerInterface {
/// @notice Contracts that implement an interferce in behalf of another contract must return true
/// @param addr Address that the contract woll implement the interface in behalf of
/// @param interfaceHash keccak256 of the name of the interface
/// @return true if the contract can implement the interface represented by
/// @return ERC820_ACCEPT_MAGIC if the contract can implement the interface represented by
/// `ìnterfaceHash` in behalf of `addr`
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bool);
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bytes32);
}

contract ERC820Registry {
bytes4 constant InvalidID = 0xffffffff;
bytes4 constant ERC165ID = 0x01ffc9a7;
bytes32 constant ERC820_ACCEPT_MAGIC = keccak256("ERC820_ACCEPT_MAGIC");


mapping (address => mapping(bytes32 => address)) interfaces;
mapping (address => address) managers;
Expand Down Expand Up @@ -74,7 +76,8 @@ contract ERC820Registry {
function setInterfaceImplementer(address addr, bytes32 iHash, address implementer) public canManage(addr) {
require(!isERC165Interface(iHash));
if ((implementer != 0) && (implementer!=msg.sender)) {
require(ERC820ImplementerInterface(implementer).canImplementInterfaceForAddress(addr, iHash));
require(ERC820ImplementerInterface(implementer).canImplementInterfaceForAddress(addr, iHash)
== ERC820_ACCEPT_MAGIC);
}
interfaces[addr][iHash] = implementer;
InterfaceImplementerSet(addr, iHash, implementer);
Expand Down Expand Up @@ -133,7 +136,7 @@ contract ERC820Registry {
30000, // 30k gas
_contract, // To addr
x, // Inputs are stored at location x
0x20, // Inputs are 32 bytes long
0x08, // Inputs are 8 bytes long
x, // Store output over input (saves space)
0x20) // Outputs are 32 bytes long

Expand Down
9 changes: 6 additions & 3 deletions contracts/ExampleImplementer.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
pragma solidity ^0.4.18;

contract ExampleImplementer {
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bool) {
return true;
import "./ERC820ImplementerInterface.sol";


contract ExampleImplementer is ERC820ImplementerInterface {
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bytes32) {
return ERC820_ACCEPT_MAGIC;
}
}
2 changes: 1 addition & 1 deletion contracts/ExampleImplementer2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "./ERC820Implementer.sol";
contract ExampleImplementer2 is ERC820Implementer {

function ExampleImplementer2() public {
setInterfaceImplementation("IExampleImplementer2", this);
setInterfaceImplementation("ERC820ExampleImplementer2", this);
// delegateManagement(msg.sender);
}

Expand Down
102 changes: 87 additions & 15 deletions eip-820.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,36 @@ This standard also solves the problem of having different addresses for differen
### The smart contract

```
pragma solidity 0.4.19;
pragma solidity 0.4.20;
contract EIP820ImplementerInterface {
interface ERC820ImplementerInterface {
/// @notice Contracts that implement an interferce in behalf of another contract must return true
/// @param addr Address that the contract woll implement the interface in behalf of
/// @param interfaceHash keccak256 of the name of the interface
/// @return true if the contract can implement the interface represented by
/// @return ERC820_ACCEPT_MAGIC if the contract can implement the interface represented by
/// `ìnterfaceHash` in behalf of `addr`
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bool);
function canImplementInterfaceForAddress(address addr, bytes32 interfaceHash) view public returns(bytes32);
}
contract EIP820Registry {
contract ERC820Registry {
bytes4 constant InvalidID = 0xffffffff;
bytes4 constant ERC165ID = 0x01ffc9a7;
bytes32 constant ERC820_ACCEPT_MAGIC = keccak256("ERC820_ACCEPT_MAGIC");
mapping (address => mapping(bytes32 => address)) interfaces;
mapping (address => address) managers;
mapping (address => mapping(bytes4 => bool)) erc165Cache;
modifier canManage(address addr) {
require(getManager(addr) == msg.sender);
_;
}
event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);
event ManagerChanged(address indexed addr, address indexed newManager);
/// @notice Query the hash of an interface given a name
/// @param interfaceName Name of the interfce
function interfaceHash(string interfaceName) public pure returns(bytes32) {
Expand Down Expand Up @@ -89,10 +98,14 @@ contract EIP820Registry {
/// @notice Query if an address implements an interface and thru which contract
/// @param addr Address that is being queried for the implementation of an interface
/// @param iHash SHA3 of the name of the interface as a string
/// Example `web3.utils.sha3('Ierc777`')`
/// @return The address of the contract that implements a speficic interface
/// Example `web3.utils.sha3('ERC777Token`')`
/// @return The address of the contract that implements a specific interface
/// or 0x0 if `addr` does not implement this interface
function getInterfaceImplementer(address addr, bytes32 iHash) public constant returns (address) {
function getInterfaceImplementer(address addr, bytes32 iHash) constant public returns (address) {
if (isERC165Interface(iHash)) {
bytes4 i165Hash = bytes4(iHash);
return erc165InterfaceSupported(addr, i165Hash) ? addr : 0;
}
return interfaces[addr][iHash];
}
Expand All @@ -102,30 +115,89 @@ contract EIP820Registry {
/// @param iHash SHA3 of the name of the interface as a string
/// For example `web3.utils.sha3('Ierc777')` for the Ierc777
function setInterfaceImplementer(address addr, bytes32 iHash, address implementer) public canManage(addr) {
require(!isERC165Interface(iHash));
if ((implementer != 0) && (implementer!=msg.sender)) {
require(EIP820ImplementerInterface(implementer).canImplementInterfaceForAddress(addr, iHash));
require(ERC820ImplementerInterface(implementer).canImplementInterfaceForAddress(addr, iHash)
== ERC820_ACCEPT_MAGIC);
}
interfaces[addr][iHash] = implementer;
InterfaceImplementerSet(addr, iHash, implementer);
}
event InterfaceImplementerSet(address indexed addr, bytes32 indexed interfaceHash, address indexed implementer);
event ManagerChanged(address indexed addr, address indexed newManager);
}
/// ERC165 Specific
function isERC165Interface(bytes32 iHash) internal pure returns (bool) {
return iHash & 0x00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF == 0;
}
function erc165InterfaceSupported(address _contract, bytes4 _interfaceId) constant public returns (bool) {
if (!erc165Cache[_contract][_interfaceId]) {
erc165UpdateCache(_contract, _interfaceId);
}
return interfaces[_contract][_interfaceId] != 0;
}
function erc165UpdateCache(address _contract, bytes4 _interfaceId) public {
interfaces[_contract][_interfaceId] =
erc165InterfaceSupported_NoCache(_contract, _interfaceId) ? _contract : 0;
erc165Cache[_contract][_interfaceId] = true;
}
function erc165InterfaceSupported_NoCache(address _contract, bytes4 _interfaceId) public constant returns (bool) {
uint256 success;
uint256 result;
(success, result) = noThrowCall(_contract, ERC165ID);
if ((success==0)||(result==0)) {
return false;
}
(success, result) = noThrowCall(_contract, InvalidID);
if ((success==0)||(result!=0)) {
return false;
}
(success, result) = noThrowCall(_contract, _interfaceId);
if ((success==1)&&(result==1)) {
return true;
}
return false;
}
function noThrowCall(address _contract, bytes4 _interfaceId) constant internal returns (uint256 success, uint256 result) {
bytes4 erc165ID = ERC165ID;
assembly {
let x := mload(0x40) // Find empty storage location using "free memory pointer"
mstore(x, erc165ID) // Place signature at begining of empty storage
mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature
success := staticcall(
30000, // 30k gas
_contract, // To addr
x, // Inputs are stored at location x
0x08, // Inputs are 8 bytes long
x, // Store output over input (saves space)
0x20) // Outputs are 32 bytes long
result := mload(x) // Load the result
}
}
}
```

### Raw transaction for deploying the smart contract on any chain.
```
0xf9051b8085174876e800830c35008080b904c86060604052341561000f57600080fd5b6104aa8061001e6000396000f30060606040526004361061006c5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100715780633d5840631461009c5780635df8122f146100d757806365ba36c1146100fc578063aabbb8ca1461015f575b600080fd5b341561007c57600080fd5b61009a600160a060020a036004358116906024359060443516610181565b005b34156100a757600080fd5b6100bb600160a060020a03600435166102ec565b604051600160a060020a03909116815260200160405180910390f35b34156100e257600080fd5b61009a600160a060020a0360043581169060243516610338565b341561010757600080fd5b61014d60046024813581810190830135806020601f820181900481020160405190810160405281815292919060208401838380828437509496506103f395505050505050565b60405190815260200160405180910390f35b341561016a57600080fd5b6100bb600160a060020a0360043516602435610458565b8233600160a060020a0316610195826102ec565b600160a060020a0316146101a857600080fd5b600160a060020a038216158015906101d2575033600160a060020a031682600160a060020a031614155b156102735781600160a060020a031663f008325085856000604051602001526040517c010000000000000000000000000000000000000000000000000000000063ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b151561024d57600080fd5b6102c65a03f1151561025e57600080fd5b50505060405180519050151561027357600080fd5b600160a060020a0384811660008181526020818152604080832088845290915290819020805473ffffffffffffffffffffffffffffffffffffffff191693861693841790558591907f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db153905160405180910390a450505050565b600160a060020a038082166000908152600160205260408120549091161515610316575080610333565b50600160a060020a03808216600090815260016020526040902054165b919050565b8133600160a060020a031661034c826102ec565b600160a060020a03161461035f57600080fd5b82600160a060020a031682600160a060020a03161461037e5781610381565b60005b600160a060020a0384811660008181526001602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191694841694909417909355908416917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350905160405180910390a3505050565b6000816040518082805190602001908083835b602083106104255780518252601f199092019160209182019101610406565b6001836020036101000a038019825116818451161790925250505091909101925060409150505180910390209050919050565b600160a060020a03918216600090815260208181526040808320938352929052205416905600a165627a7a723058205b4403251cca7ea41667bb21ed92b7b6b52d87068e201fbe5456b663e1faf72900291ba079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798a00aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
0xf908778085174876e800830c35008080b908246060604052341561000f57600080fd5b6108068061001e6000396000f30060606040526004361061008d5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166329965a1d81146100925780633d584063146100bd578063571a1f66146100f85780635df8122f1461012457806365ba36c11461014957806390e47957146101ac578063aabbb8ca146101ec578063ddc23ddd1461020e575b600080fd5b341561009d57600080fd5b6100bb600160a060020a03600435811690602435906044351661023a565b005b34156100c857600080fd5b6100dc600160a060020a03600435166103ec565b604051600160a060020a03909116815260200160405180910390f35b341561010357600080fd5b6100bb600160a060020a0360043516600160e060020a031960243516610438565b341561012f57600080fd5b6100bb600160a060020a03600435811690602435166104c2565b341561015457600080fd5b61019a60046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061057d95505050505050565b60405190815260200160405180910390f35b34156101b757600080fd5b6101d8600160a060020a0360043516600160e060020a0319602435166105e2565b604051901515815260200160405180910390f35b34156101f757600080fd5b6100dc600160a060020a0360043516602435610658565b341561021957600080fd5b6101d8600160a060020a0360043516600160e060020a0319602435166106b7565b8233600160a060020a031661024e826103ec565b600160a060020a03161461026157600080fd5b61026a8361076e565b1561027457600080fd5b600160a060020a0382161580159061029e575033600160a060020a031682600160a060020a031614155b15610373576040517f4552433832305f4143434550545f4d41474943000000000000000000000000008152601301604051908190039020600160a060020a03831663f008325086866000604051602001526040517c010000000000000000000000000000000000000000000000000000000063ffffffff8516028152600160a060020a0390921660048301526024820152604401602060405180830381600087803b151561034b57600080fd5b6102c65a03f1151561035c57600080fd5b505050604051805191909114905061037357600080fd5b600160a060020a0384811660008181526020818152604080832088845290915290819020805473ffffffffffffffffffffffffffffffffffffffff191693861693841790558591907f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db153905160405180910390a450505050565b600160a060020a038082166000908152600160205260408120549091161515610416575080610433565b50600160a060020a03808216600090815260016020526040902054165b919050565b61044282826106b7565b61044d57600061044f565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b8133600160a060020a03166104d6826103ec565b600160a060020a0316146104e957600080fd5b82600160a060020a031682600160a060020a031614610508578161050b565b60005b600160a060020a0384811660008181526001602052604090819020805473ffffffffffffffffffffffffffffffffffffffff191694841694909417909355908416917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a4350905160405180910390a3505050565b6000816040518082805190602001908083835b602083106105af5780518252601f199092019160209182019101610590565b6001836020036101000a038019825116818451161790925250505091909101925060409150505180910390209050919050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff161515610623576106238383610438565b50600160a060020a03918216600090815260208181526040808320600160e060020a0319949094168352929052205416151590565b6000806106648361076e565b1561068957508161067584826105e2565b610680576000610682565b835b91506106b0565b600160a060020a038085166000908152602081815260408083208784529091529020541691505b5092915050565b600080806106e5857f01ffc9a700000000000000000000000000000000000000000000000000000000610790565b90925090508115806106f5575080155b156107035760009250610766565b61071585600160e060020a0319610790565b909250905081158061072657508015155b156107345760009250610766565b61073e8585610790565b90925090506001821480156107535750806001145b156107615760019250610766565b600092505b505092915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6000807f01ffc9a70000000000000000000000000000000000000000000000000000000060405181815284600482015260208160088389617530fa935080519250505092509290505600a165627a7a72305820b424185958879a1eef1cb7235bfd8ed607a7402b46853860e5343340925f028e00291ba079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798a00aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
```

You can see the string `a` at the end. This is the `s` of the signature, meaning that its a deterministic by hand forced signature.

### Special registry deployment account.

```
0x1e9f423db6b0c5e2b7caa49555962bd97e98a75f
0x91c2b265ece9442ed28e3c4283652b1894dcdabb
```

This account is generated by reverse engineering it from it's signature for the transaction, in this way no one knows the private key, but it is known that it's the valid signer of the deployment transaction.
Expand All @@ -137,7 +209,7 @@ The way to deploy this contract is by sending ETH to the registry deployment acc

### Deployed contract.
```
0x4b3b1c4850eeb21ee224f05a2c27f9f3cb620f6a
0x991a1bcb077599290d7305493c9a630c20f8b798
```

The contract will have this address for every chain it is deployed to.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eip820",
"version": "0.0.19",
"version": "0.0.20",
"description": "EIP 820 - Pseudo-introspaection using a registry contract",
"main": "index.js",
"files": [
Expand Down
4 changes: 2 additions & 2 deletions test/MainScenario.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ describe('ERC820 Test', () => {
}).timeout(20000);

it('should set an address', async () => {
interfaceHash = await erc820Registry.interfaceHash("IExampleInterface");
assert.equal(interfaceHash, web3.utils.sha3("IExampleInterface"));
interfaceHash = await erc820Registry.interfaceHash("ERC820ExampleImplementer2");
assert.equal(interfaceHash, web3.utils.sha3("ERC820ExampleImplementer2"));
await erc820Registry.setInterfaceImplementer(addr, interfaceHash, implementer.$address, {from: addr});
const rImplementer = await erc820Registry.getInterfaceImplementer(addr, interfaceHash);
assert.equal(rImplementer, implementer.$address);
Expand Down

0 comments on commit 78eb6fa

Please sign in to comment.