pragma solidity ^0.5.0;
/// @title Provides helper functions to determine the validity of passed signatures.
/// @author Noah Zinsmeister
/// @dev Supports both prefixed and un-prefixed signatures.
contract SignatureVerifier {
/// @notice Determines whether the passed signature of `messageHash` was made by the private key of `_address`.
/// @param _address The address that may or may not have signed the passed messageHash.
/// @param messageHash The messageHash that may or may not have been signed.
/// @param v The v component of the signature.
/// @param r The r component of the signature.
/// @param s The s component of the signature.
/// @return true if the signature can be verified, false otherwise.
function isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s) public pure returns (bool) {
return _isSigned(_address, messageHash, v, r, s) || _isSignedPrefixed(_address, messageHash, v, r, s);
}
/// @dev Checks unprefixed signatures.
function _isSigned(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
internal pure returns (bool)
{
return ecrecover(messageHash, v, r, s) == _address;
}
/// @dev Checks prefixed signatures.
function _isSignedPrefixed(address _address, bytes32 messageHash, uint8 v, bytes32 r, bytes32 s)
internal pure returns (bool)
{
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
return _isSigned(_address, keccak256(abi.encodePacked(prefix, messageHash)), v, r, s);
}
}
/// @title An implementation of the set data structure for addresses.
/// @author Noah Zinsmeister
/// @dev O(1) insertion, removal, contains, and length functions.
library AddressSet {
struct Set {
address[] members;
mapping(address => uint) memberIndices;
}
/// @dev Inserts an element into a set. If the element already exists in the set, the function is a no-op.
/// @param self The set to insert into.
/// @param other The element to insert.
function insert(Set storage self, address other) internal {
if (!contains(self, other)) {
self.memberIndices[other] = self.members.push(other);
}
}
/// @dev Removes an element from a set. If the element does not exist in the set, the function is a no-op.
/// @param self The set to remove from.
/// @param other The element to remove.
function remove(Set storage self, address other) internal {
if (contains(self, other)) {
// replace other with the last element
self.members[self.memberIndices[other] - 1] = self.members[length(self) - 1];
// reflect this change in the indices
self.memberIndices[self.members[self.memberIndices[other] - 1]] = self.memberIndices[other];
delete self.memberIndices[other];
// remove the last element
self.members.pop();
}
}
/// @dev Checks set membership.
/// @param self The set to check membership in.
/// @param other The element to check membership of.
/// @return true if the element is in the set, false otherwise.
function contains(Set storage self, address other) internal view returns (bool) {
return ( // solium-disable-line operator-whitespace
self.memberIndices[other] > 0 &&
self.members.length >= self.memberIndices[other] &&
self.members[self.memberIndices[other] - 1] == other
);
}
/// @dev Returns the number of elements in a set.
/// @param self The set to check the length of.
/// @return The number of elements in the set.
function length(Set storage self) internal view returns (uint) {
return self.members.length;
}
}
/// @title The ERC-1484 Identity Registry.
/// @author Noah Zinsmeister
/// @author Andy Chorlian
contract IdentityRegistry is SignatureVerifier {
using AddressSet for AddressSet.Set;
// Identity Data Structure and Parameters //////////////////////////////////////////////////////////////////////////
struct Identity {
address recoveryAddress;
AddressSet.Set associatedAddresses;
AddressSet.Set providers;
AddressSet.Set resolvers;
}
mapping (uint => Identity) private identityDirectory;
mapping (address => uint) private associatedAddressDirectory;
uint public nextEIN = 1;
uint public maxAssociatedAddresses = 50;
// Signature Timeout ///////////////////////////////////////////////////////////////////////////////////////////////
uint public signatureTimeout = 1 days;
/// @dev Enforces that the passed timestamp is within signatureTimeout seconds of now.
/// @param timestamp The timestamp to check the validity of.
modifier ensureSignatureTimeValid(uint timestamp) {
require(
// solium-disable-next-line security/no-block-members
block.timestamp >= timestamp && block.timestamp < timestamp + signatureTimeout, "Timestamp is not valid."
);
_;
}
// Recovery Address Change Logging /////////////////////////////////////////////////////////////////////////////////
struct RecoveryAddressChange {
uint timestamp;
address oldRecoveryAddress;
}
mapping (uint => RecoveryAddressChange) private recoveryAddressChangeLogs;
// Recovery Logging ////////////////////////////////////////////////////////////////////////////////////////////////
struct Recovery {
uint timestamp;
bytes32 hashedOldAssociatedAddresses;
}
mapping (uint => Recovery) private recoveryLogs;
// Recovery Timeout ////////////////////////////////////////////////////////////////////////////////////////////////
uint public recoveryTimeout = 2 weeks;
/// @dev Checks if the passed EIN has changed their recovery address within recoveryTimeout seconds of now.
function canChangeRecoveryAddress(uint ein) private view returns (bool) {
// solium-disable-next-line security/no-block-members
return block.timestamp > recoveryAddressChangeLogs[ein].timestamp + recoveryTimeout;
}
/// @dev Checks if the passed EIN has recovered within recoveryTimeout seconds of now.
function canRecover(uint ein) private view returns (bool) {
// solium-disable-next-line security/no-block-members
return block.timestamp > recoveryLogs[ein].timestamp + recoveryTimeout;
}
// Identity View Functions /////////////////////////////////////////////////////////////////////////////////////////
/// @notice Checks if the passed EIN exists.
/// @dev Does not throw.
/// @param ein The EIN to check the existence of.
/// @return true if the passed EIN exists, false otherwise.
function identityExists(uint ein) public view returns (bool) {
return ein < nextEIN && ein > 0;
}
/// @dev Ensures that the passed EIN exists.
/// @param ein The EIN to check the existence of.
modifier _identityExists(uint ein) {
require(identityExists(ein), "The identity does not exist.");
_;
}
/// @notice Checks if the passed address is associated with an Identity.
/// @dev Does not throw.
/// @param _address The address to check.
/// @return true if the passed address is associated with an Identity, false otherwise.
function hasIdentity(address _address) public view returns (bool) {
return identityExists(associatedAddressDirectory[_address]);
}
/// @dev Ensures that the passed address is or is not associated with an Identity.
/// @param _address The address to check.
/// @param check If true, ensures that the address has an Identity, if false, vice versa.
/// @return true if the associated status is equal to check, false otherwise.
modifier _hasIdentity(address _address, bool check) {
require(
hasIdentity(_address) == check,
check ?
"The passed address does not have an identity but should." :
"The passed address has an identity but should not."
);
_;
}
/// @notice Gets the EIN associated with the passed address.
/// @dev Throws if the address is not associated with an Identity.
/// @param _address The address to check.
/// @return The associated EIN.
function getEIN(address _address) public view _hasIdentity(_address, true) returns (uint ein) {
return associatedAddressDirectory[_address];
}
/// @notice Checks whether the passed EIN is associated with the passed address.
/// @dev Does not throw.
/// @param ein The EIN to check.
/// @param _address The address to check.
/// @return true if the passed address is associated with the passed EIN, false otherwise.
function isAssociatedAddressFor(uint ein, address _address) public view returns (bool) {
return identityDirectory[ein].associatedAddresses.contains(_address);
}
/// @notice Checks whether the passed provider is set for the passed EIN.
/// @dev Does not throw.
/// @param ein The EIN to check.
/// @param provider The provider to check.
/// @return true if the provider is set for the passed EIN, false otherwise.
function isProviderFor(uint ein, address provider) public view returns (bool) {
return identityDirectory[ein].providers.contains(provider);
}
/// @dev Ensures that the msg.sender is a provider for the passed EIN.
/// @param ein The EIN to check.
modifier _isProviderFor(uint ein) {
require(isProviderFor(ein, msg.sender), "The identity has not set the passed provider.");
_;
}
/// @notice Checks whether the passed resolver is set for the passed EIN.
/// @dev Does not throw.
/// @param ein The EIN to check.
/// @param resolver The resolver to check.
/// @return true if the resolver is set for the passed EIN, false otherwise.
function isResolverFor(uint ein, address resolver) public view returns (bool) {
return identityDirectory[ein].resolvers.contains(resolver);
}
/// @notice Gets all identity-related information for the passed EIN.
/// @dev Throws if the passed EIN does not exist.
/// @param ein The EIN to get information for.
/// @return All the information for the Identity denominated by the passed EIN.
function getIdentity(uint ein) public view _identityExists(ein)
returns (
address recoveryAddress,
address[] memory associatedAddresses, address[] memory providers, address[] memory resolvers
)
{
Identity storage _identity = identityDirectory[ein];
return (
_identity.recoveryAddress,
_identity.associatedAddresses.members,
_identity.providers.members,
_identity.resolvers.members
);
}
// Identity Management Functions ///////////////////////////////////////////////////////////////////////////////////
/// @notice Create an new Identity for the transaction sender.
/// @dev Sets the msg.sender as the only associatedAddress.
/// @param recoveryAddress A recovery address to set for the new Identity.
/// @param providers A list of providers to set for the new Identity.
/// @param resolvers A list of resolvers to set for the new Identity.
/// @return The EIN of the new Identity.
function createIdentity(address recoveryAddress, address[] memory providers, address[] memory resolvers)
public returns (uint ein)
{
return createIdentity(recoveryAddress, msg.sender, providers, resolvers, false);
}
/// @notice Allows creation of a new Identity for the passed associatedAddress.
/// @param recoveryAddress A recovery address to set for the new Identity.
/// @param associatedAddress An associated address to set for the new Identity (must have produced the signature).
/// @param providers A list of providers to set for the new Identity.
/// @param resolvers A list of resolvers to set for the new Identity.
/// @param v The v component of the signature.
/// @param r The r component of the signature.
/// @param s The s component of the signature.
/// @param timestamp The timestamp of the signature.
/// @return The EIN of the new Identity.
function createIdentityDelegated(
address recoveryAddress, address associatedAddress, address[] memory providers, address[] memory resolvers,
uint8 v, bytes32 r, bytes32 s, uint timestamp
)
public ensureSignatureTimeValid(timestamp) returns (uint ein)
{
require(
isSigned(
associatedAddress,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
"I authorize the creation of an Identity on my behalf.",
recoveryAddress, associatedAddress, providers, resolvers, timestamp
)
),
v, r, s
),
"Permission denied."
);
return createIdentity(recoveryAddress, associatedAddress, providers, resolvers, true);
}
/// @dev Common logic for all identity creation.
function createIdentity(
address recoveryAddress,
address associatedAddress, address[] memory providers, address[] memory resolvers, bool delegated
)
private _hasIdentity(associatedAddress, false) returns (uint)
{
uint ein = nextEIN++;
Identity storage _identity = identityDirectory[ein];
_identity.recoveryAddress = recoveryAddress;
addAssociatedAddress(ein, associatedAddress);
addProviders(ein, providers, delegated);
addResolvers(ein, resolvers, delegated);
emit IdentityCreated(msg.sender, ein, recoveryAddress, associatedAddress, providers, resolvers, delegated);
return ein;
}
/// @notice Allows an associated address to add another associated address to its Identity.
/// @param approvingAddress An associated address for an Identity.
/// @param addressToAdd A new address to set for the Identity of the sender.
/// @param v The v component of the signature.
/// @param r The r component of the signature.
/// @param s The s component of the signature.
/// @param timestamp The timestamp of the signature.
function addAssociatedAddress(
address approvingAddress, address addressToAdd, uint8 v, bytes32 r, bytes32 s, uint timestamp
)
public ensureSignatureTimeValid(timestamp)
{
bool fromApprovingAddress = msg.sender == approvingAddress;
require(
fromApprovingAddress || msg.sender == addressToAdd, "One or both of the passed addresses are malformed."
);
uint ein = getEIN(approvingAddress);
require(
isSigned(
fromApprovingAddress ? addressToAdd : approvingAddress,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
fromApprovingAddress ?
"I authorize being added to this Identity." :
"I authorize adding this address to my Identity.",
ein, addressToAdd, timestamp
)
),
v, r, s
),
"Permission denied."
);
addAssociatedAddress(ein, addressToAdd);
emit AssociatedAddressAdded(msg.sender, ein, approvingAddress, addressToAdd, false);
}
/// @notice Allows addition of an associated address to an Identity.
/// @dev The first signature must be that of the approvingAddress.
/// @param approvingAddress An associated address for an Identity.
/// @param addressToAdd A new address to set for the Identity of approvingAddress.
/// @param v The v component of the signatures.
/// @param r The r component of the signatures.
/// @param s The s component of the signatures.
/// @param timestamp The timestamp of the signatures.
function addAssociatedAddressDelegated(
address approvingAddress, address addressToAdd,
uint8[2] memory v, bytes32[2] memory r, bytes32[2] memory s, uint[2] memory timestamp
)
public ensureSignatureTimeValid(timestamp[0]) ensureSignatureTimeValid(timestamp[1])
{
uint ein = getEIN(approvingAddress);
require(
isSigned(
approvingAddress,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
"I authorize adding this address to my Identity.",
ein, addressToAdd, timestamp[0]
)
),
v[0], r[0], s[0]
),
"Permission denied from approving address."
);
require(
isSigned(
addressToAdd,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
"I authorize being added to this Identity.",
ein, addressToAdd, timestamp[1]
)
),
v[1], r[1], s[1]
),
"Permission denied from address to add."
);
addAssociatedAddress(ein, addressToAdd);
emit AssociatedAddressAdded(msg.sender, ein, approvingAddress, addressToAdd, true);
}
/// @dev Common logic for all address addition.
function addAssociatedAddress(uint ein, address addressToAdd) private _hasIdentity(addressToAdd, false) {
require(
identityDirectory[ein].associatedAddresses.length() < maxAssociatedAddresses, "Too many addresses."
);
identityDirectory[ein].associatedAddresses.insert(addressToAdd);
associatedAddressDirectory[addressToAdd] = ein;
}
/// @notice Allows an associated address to remove itself from its Identity.
function removeAssociatedAddress() public {
uint ein = getEIN(msg.sender);
removeAssociatedAddress(ein, msg.sender);
emit AssociatedAddressRemoved(msg.sender, ein, msg.sender, false);
}
/// @notice Allows removal of an associated address from an Identity.
/// @param addressToRemove An associated address to remove from its Identity.
/// @param v The v component of the signature.
/// @param r The r component of the signature.
/// @param s The s component of the signature.
/// @param timestamp The timestamp of the signature.
function removeAssociatedAddressDelegated(address addressToRemove, uint8 v, bytes32 r, bytes32 s, uint timestamp)
public ensureSignatureTimeValid(timestamp)
{
uint ein = getEIN(addressToRemove);
require(
isSigned(
addressToRemove,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
"I authorize removing this address from my Identity.",
ein, addressToRemove, timestamp
)
),
v, r, s
),
"Permission denied."
);
removeAssociatedAddress(ein, addressToRemove);
emit AssociatedAddressRemoved(msg.sender, ein, addressToRemove, true);
}
/// @dev Common logic for all address removal.
function removeAssociatedAddress(uint ein, address addressToRemove) private {
identityDirectory[ein].associatedAddresses.remove(addressToRemove);
delete associatedAddressDirectory[addressToRemove];
}
/// @notice Allows an associated address to add providers to its Identity.
/// @param providers A list of providers.
function addProviders(address[] memory providers) public {
addProviders(getEIN(msg.sender), providers, false);
}
/// @notice Allows providers to add providers to an Identity.
/// @param ein The EIN to add providers to.
/// @param providers A list of providers.
function addProvidersFor(uint ein, address[] memory providers) public _isProviderFor(ein) {
addProviders(ein, providers, true);
}
/// @dev Common logic for all provider adding.
function addProviders(uint ein, address[] memory providers, bool delegated) private {
Identity storage _identity = identityDirectory[ein];
for (uint i; i < providers.length; i++) {
_identity.providers.insert(providers[i]);
emit ProviderAdded(msg.sender, ein, providers[i], delegated);
}
}
/// @notice Allows an associated address to remove providers from its Identity.
/// @param providers A list of providers.
function removeProviders(address[] memory providers) public {
removeProviders(getEIN(msg.sender), providers, false);
}
/// @notice Allows providers to remove providers to an Identity.
/// @param ein The EIN to remove providers from.
/// @param providers A list of providers.
function removeProvidersFor(uint ein, address[] memory providers) public _isProviderFor(ein) {
removeProviders(ein, providers, true);
}
/// @dev Common logic for all provider removal.
function removeProviders(uint ein, address[] memory providers, bool delegated) private {
Identity storage _identity = identityDirectory[ein];
for (uint i; i < providers.length; i++) {
_identity.providers.remove(providers[i]);
emit ProviderRemoved(msg.sender, ein, providers[i], delegated);
}
}
/// @notice Allows an associated address to add resolvers to its Identity.
/// @param resolvers A list of resolvers.
function addResolvers(address[] memory resolvers) public {
addResolvers(getEIN(msg.sender), resolvers, false);
}
/// @notice Allows providers to add resolvers to an Identity.
/// @param ein The EIN to add resolvers to.
/// @param resolvers A list of resolvers.
function addResolversFor(uint ein, address[] memory resolvers) public _isProviderFor(ein) {
addResolvers(ein, resolvers, true);
}
/// @dev Common logic for all resolver adding.
function addResolvers(uint ein, address[] memory resolvers, bool delegated) private {
Identity storage _identity = identityDirectory[ein];
for (uint i; i < resolvers.length; i++) {
_identity.resolvers.insert(resolvers[i]);
emit ResolverAdded(msg.sender, ein, resolvers[i], delegated);
}
}
/// @notice Allows an associated address to remove resolvers from its Identity.
/// @param resolvers A list of resolvers.
function removeResolvers(address[] memory resolvers) public {
removeResolvers(getEIN(msg.sender), resolvers, true);
}
/// @notice Allows providers to remove resolvers from an Identity.
/// @param ein The EIN to remove resolvers from.
/// @param resolvers A list of resolvers.
function removeResolversFor(uint ein, address[] memory resolvers) public _isProviderFor(ein) {
removeResolvers(ein, resolvers, true);
}
/// @dev Common logic for all resolver removal.
function removeResolvers(uint ein, address[] memory resolvers, bool delegated) private {
Identity storage _identity = identityDirectory[ein];
for (uint i; i < resolvers.length; i++) {
_identity.resolvers.remove(resolvers[i]);
emit ResolverRemoved(msg.sender, ein, resolvers[i], delegated);
}
}
// Recovery Management Functions ///////////////////////////////////////////////////////////////////////////////////
/// @notice Allows an associated address to change the recovery address for its Identity.
/// @dev Recovery addresses can be changed at most once every recoveryTimeout seconds.
/// @param newRecoveryAddress A recovery address to set for the sender's EIN.
function triggerRecoveryAddressChange(address newRecoveryAddress) public {
triggerRecoveryAddressChange(getEIN(msg.sender), newRecoveryAddress, false);
}
/// @notice Allows providers to change the recovery address for an Identity.
/// @dev Recovery addresses can be changed at most once every recoveryTimeout seconds.
/// @param ein The EIN to set the recovery address of.
/// @param newRecoveryAddress A recovery address to set for the passed EIN.
function triggerRecoveryAddressChangeFor(uint ein, address newRecoveryAddress) public _isProviderFor(ein) {
triggerRecoveryAddressChange(ein, newRecoveryAddress, true);
}
/// @dev Common logic for all recovery address changes.
function triggerRecoveryAddressChange(uint ein, address newRecoveryAddress, bool delegated) private {
Identity storage _identity = identityDirectory[ein];
require(canChangeRecoveryAddress(ein), "Cannot trigger a change in recovery address yet.");
// solium-disable-next-line security/no-block-members
recoveryAddressChangeLogs[ein] = RecoveryAddressChange(block.timestamp, _identity.recoveryAddress);
emit RecoveryAddressChangeTriggered(msg.sender, ein, _identity.recoveryAddress, newRecoveryAddress, delegated);
_identity.recoveryAddress = newRecoveryAddress;
}
/// @notice Allows recovery addresses to trigger the recovery process for an Identity.
/// @dev msg.sender must be current recovery address, or the old one if it was changed recently.
/// @param ein The EIN to trigger recovery for.
/// @param newAssociatedAddress A recovery address to set for the passed EIN.
/// @param v The v component of the signature.
/// @param r The r component of the signature.
/// @param s The s component of the signature.
/// @param timestamp The timestamp of the signature.
function triggerRecovery(uint ein, address newAssociatedAddress, uint8 v, bytes32 r, bytes32 s, uint timestamp)
public _identityExists(ein) _hasIdentity(newAssociatedAddress, false) ensureSignatureTimeValid(timestamp)
{
require(canRecover(ein), "Cannot trigger recovery yet.");
Identity storage _identity = identityDirectory[ein];
// ensure the sender is the recovery address/old recovery address if there's been a recent change
if (canChangeRecoveryAddress(ein)) {
require(
msg.sender == _identity.recoveryAddress, "Only the current recovery address can trigger recovery."
);
} else {
require(
msg.sender == recoveryAddressChangeLogs[ein].oldRecoveryAddress,
"Only the recently removed recovery address can trigger recovery."
);
}
require(
isSigned(
newAssociatedAddress,
keccak256(
abi.encodePacked(
byte(0x19), byte(0), address(this),
"I authorize being added to this Identity via recovery.",
ein, newAssociatedAddress, timestamp
)
),
v, r, s
),
"Permission denied."
);
// log the old associated addresses to facilitate destruction if necessary
recoveryLogs[ein] = Recovery(
block.timestamp, // solium-disable-line security/no-block-members
keccak256(abi.encodePacked(_identity.associatedAddresses.members))
);
emit RecoveryTriggered(msg.sender, ein, _identity.associatedAddresses.members, newAssociatedAddress);
// remove identity data, and add the new address as the sole associated address
resetIdentityData(_identity, msg.sender, false);
addAssociatedAddress(ein, newAssociatedAddress);
}
/// @notice Allows associated addresses recently removed via recovery to permanently disable their old Identity.
/// @param ein The EIN to trigger destruction of.
/// @param firstChunk The array of addresses before the msg.sender in the pre-recovery associated addresses array.
/// @param lastChunk The array of addresses after the msg.sender in the pre-recovery associated addresses array.
/// @param resetResolvers true if the destroyer wants resolvers to be removed, false otherwise.
function triggerDestruction(uint ein, address[] memory firstChunk, address[] memory lastChunk, bool resetResolvers)
public _identityExists(ein)
{
require(!canRecover(ein), "Recovery has not recently been triggered.");
Identity storage _identity = identityDirectory[ein];
// ensure that the msg.sender was an old associated address for the referenced identity
address payable[1] memory middleChunk = [msg.sender];
require(
keccak256(
abi.encodePacked(firstChunk, middleChunk, lastChunk)
) == recoveryLogs[ein].hashedOldAssociatedAddresses,
"Cannot destroy an EIN from an address that was not recently removed from said EIN via recovery."
);
emit IdentityDestroyed(msg.sender, ein, _identity.recoveryAddress, resetResolvers);
resetIdentityData(_identity, address(0), resetResolvers);
}
/// @dev Common logic for clearing the data of an Identity.
function resetIdentityData(Identity storage identity, address newRecoveryAddress, bool resetResolvers) private {
for (uint i; i < identity.associatedAddresses.members.length; i++) {
delete associatedAddressDirectory[identity.associatedAddresses.members[i]];
}
delete identity.associatedAddresses;
delete identity.providers;
if (resetResolvers) delete identity.resolvers;
identity.recoveryAddress = newRecoveryAddress;
}
// Events //////////////////////////////////////////////////////////////////////////////////////////////////////////
event IdentityCreated(
address indexed initiator, uint indexed ein,
address recoveryAddress, address associatedAddress, address[] providers, address[] resolvers, bool delegated
);
event AssociatedAddressAdded(
address indexed initiator, uint indexed ein, address approvingAddress, address addedAddress, bool delegated
);
event AssociatedAddressRemoved(address indexed initiator, uint indexed ein, address removedAddress, bool delegated);
event ProviderAdded(address indexed initiator, uint indexed ein, address provider, bool delegated);
event ProviderRemoved(address indexed initiator, uint indexed ein, address provider, bool delegated);
event ResolverAdded(address indexed initiator, uint indexed ein, address resolvers, bool delegated);
event ResolverRemoved(address indexed initiator, uint indexed ein, address resolvers, bool delegated);
event RecoveryAddressChangeTriggered(
address indexed initiator, uint indexed ein,
address oldRecoveryAddress, address newRecoveryAddress, bool delegated
);
event RecoveryTriggered(
address indexed initiator, uint indexed ein, address[] oldAssociatedAddresses, address newAssociatedAddress
);
event IdentityDestroyed(address indexed initiator, uint indexed ein, address recoveryAddress, bool resolversReset);
}
{
"compilationTarget": {
"IdentityRegistry.sol": "IdentityRegistry"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"resolvers","type":"address[]"}],"name":"addResolversFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"getEIN","outputs":[{"name":"ein","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"providers","type":"address[]"}],"name":"removeProvidersFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"recoveryTimeout","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"recoveryAddress","type":"address"},{"name":"associatedAddress","type":"address"},{"name":"providers","type":"address[]"},{"name":"resolvers","type":"address[]"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"timestamp","type":"uint256"}],"name":"createIdentityDelegated","outputs":[{"name":"ein","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newRecoveryAddress","type":"address"}],"name":"triggerRecoveryAddressChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"providers","type":"address[]"}],"name":"removeProviders","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"hasIdentity","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"newRecoveryAddress","type":"address"}],"name":"triggerRecoveryAddressChangeFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"recoveryAddress","type":"address"},{"name":"providers","type":"address[]"},{"name":"resolvers","type":"address[]"}],"name":"createIdentity","outputs":[{"name":"ein","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"approvingAddress","type":"address"},{"name":"addressToAdd","type":"address"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"timestamp","type":"uint256"}],"name":"addAssociatedAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"removeAssociatedAddress","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"ein","type":"uint256"},{"name":"provider","type":"address"}],"name":"isProviderFor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"signatureTimeout","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"resolvers","type":"address[]"}],"name":"removeResolversFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"ein","type":"uint256"}],"name":"identityExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"providers","type":"address[]"}],"name":"addProviders","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"ein","type":"uint256"}],"name":"getIdentity","outputs":[{"name":"recoveryAddress","type":"address"},{"name":"associatedAddresses","type":"address[]"},{"name":"providers","type":"address[]"},{"name":"resolvers","type":"address[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"},{"name":"messageHash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"isSigned","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"newAssociatedAddress","type":"address"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"timestamp","type":"uint256"}],"name":"triggerRecovery","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"providers","type":"address[]"}],"name":"addProvidersFor","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"nextEIN","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"ein","type":"uint256"},{"name":"_address","type":"address"}],"name":"isAssociatedAddressFor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"approvingAddress","type":"address"},{"name":"addressToAdd","type":"address"},{"name":"v","type":"uint8[2]"},{"name":"r","type":"bytes32[2]"},{"name":"s","type":"bytes32[2]"},{"name":"timestamp","type":"uint256[2]"}],"name":"addAssociatedAddressDelegated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxAssociatedAddresses","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"resolvers","type":"address[]"}],"name":"removeResolvers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"ein","type":"uint256"},{"name":"resolver","type":"address"}],"name":"isResolverFor","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addressToRemove","type":"address"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"},{"name":"timestamp","type":"uint256"}],"name":"removeAssociatedAddressDelegated","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"resolvers","type":"address[]"}],"name":"addResolvers","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"ein","type":"uint256"},{"name":"firstChunk","type":"address[]"},{"name":"lastChunk","type":"address[]"},{"name":"resetResolvers","type":"bool"}],"name":"triggerDestruction","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"recoveryAddress","type":"address"},{"indexed":false,"name":"associatedAddress","type":"address"},{"indexed":false,"name":"providers","type":"address[]"},{"indexed":false,"name":"resolvers","type":"address[]"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"IdentityCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"approvingAddress","type":"address"},{"indexed":false,"name":"addedAddress","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"AssociatedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"removedAddress","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"AssociatedAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"provider","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"ProviderAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"provider","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"ProviderRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"resolvers","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"ResolverAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"resolvers","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"ResolverRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"oldRecoveryAddress","type":"address"},{"indexed":false,"name":"newRecoveryAddress","type":"address"},{"indexed":false,"name":"delegated","type":"bool"}],"name":"RecoveryAddressChangeTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"oldAssociatedAddresses","type":"address[]"},{"indexed":false,"name":"newAssociatedAddress","type":"address"}],"name":"RecoveryTriggered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"initiator","type":"address"},{"indexed":true,"name":"ein","type":"uint256"},{"indexed":false,"name":"recoveryAddress","type":"address"},{"indexed":false,"name":"resolversReset","type":"bool"}],"name":"IdentityDestroyed","type":"event"}]