// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.13; contract IDelegation { string public constant name = "ID management contract"; uint256 incDelegateId; struct Delegate { uint32 nonce; address delegateAddr; Role role; Permission permission; uint expiryBlock; } /** * @dev Enumerated Permissions * Roles have different permissions * APPEND ONLY */ enum Permission { NOz, ANNOUNCE, OWNERSHIP_TRANSFER, DELEGATE_ADD, DELEGATE_REMOVE } /** * @dev Enumerated Roles * Roles have different permissions * APPEND ONLY */ enum Role { NONE, OWNER, ANNOUNCER } /// @notice The EIP-712 typehash for the contract's domain bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)"); mapping (address => uint32) public nonces; mapping (address => mapping(uint => Delegate)) public delegates; //mapping (address => mapping(address => uint)) public delegator; event AddDelegate(address indexed delegate, Role role, Permission permission, expiryBlock); event RemoveDelegate(address indexed delegate); /** * @dev Add or change permissions for delegate */ function delegate(address newDelegate, Role role, Permission permission,uint expiryBlock) external { return _delegate(msg.sender, newDelegate, Role role, Permission permission, expiryBlock); } function _delegate(address delegator, address delegatee, Role role, Permission permission, uint expiryBlock) internal { delegates[delegator][incDelegateId].nonce = nonces[delegator]; delegates[delegator][incDelegateId].delegateAddr = delegatee; delegates[delegator][incDelegateId].role = role; delegates[delegator][incDelegateId].permission = permission; delegates[delegator][incDelegateId].expiryBlock = expiryBlock; incDelegateId++; event AddDelegate(address indexed delegatee, Role role, Permission permission, expiryBlock); } /** * @dev Add or change permissions for delegate by EIP-712 signature */ function delegateBySig( uint8 v, bytes32 r, bytes32 s, Delegate calldata change ) external { bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, change.delegateAddr, change.nonce, change.expiryBlock, change.role, change.permission)); bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), "delegateBySig: invalid signature"); require(nonce == nonces[signatory]++, "delegateBySig: invalid nonce"); require(block.number <= expiryBlock, "delegateBySig: signature expired"); return _delegate(signatory, change.delegateAddr, change.role, change.permission, change.expiryBlock); } // /** // * @dev Remove Delegate // */ // function delegateRemove(address address_) external { // return _delegateRemove(msg.sender, address_); // }; // function _delegateRemove(address delegator, address address_) internal { // event RemoveDelegate(address indexed address_); // }; // /** // * @dev Remove delegate by EIP-712 signature // */ // function delegateRemoveBySig( // uint delegateId, // uint8 v, // bytes32 r, // bytes32 s, // Delegate calldata change // ) external { // bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), getChainId(), address(this))); // bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, change.delegateAddr, change.nonce, change.expiryBlock, change.role, change.permission)); // bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash)); // address signatory = ecrecover(digest, v, r, s); // require(signatory != address(0), "delegateBySig: invalid signature"); // require(nonce == nonces[signatory]++, "delegateBySig: invalid nonce"); // require(block.number <= expiryBlock, "delegateBySig: signature expired"); // return _delegateRemove(signatory, delegatee, delegateId); // }; // /** // * @dev Checks to see if address_ is authorized with the given permission // */ // function isAuthorizedTo( // address address_, // Permission permission, // uint256 blockNumber // ) external view returns (bool) { // //return delegateAdd[address].permission == permission && delegateAdd[address].expiryBlock >= block.number; // } function getNonceForDelegate(address addr) external view returns (uint32) { return nonces[addr]; } function getChainId() internal view returns (uint) { uint256 chainId; assembly { chainId := chainid() } return chainId; } }
0.4.18