Skip to content

Commit

Permalink
Add claim issuer upgradeable
Browse files Browse the repository at this point in the history
  • Loading branch information
aliarbak committed Mar 27, 2024
1 parent a483cda commit c2ba91a
Show file tree
Hide file tree
Showing 8 changed files with 2,188 additions and 263 deletions.
89 changes: 89 additions & 0 deletions contracts/ClaimIssuerUpgradeable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "./interface/IClaimIssuer.sol";
import "./Identity.sol";

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";

contract ClaimIssuerUpgradeable is IClaimIssuer, Identity, UUPSUpgradeable {
mapping (bytes => bool) public revokedClaims;

// solhint-disable-next-line no-empty-blocks
constructor(address initialManagementKey, bool _isLibrary) Identity(initialManagementKey, _isLibrary) { }

/**
* @dev See {IClaimIssuer-revokeClaimBySignature}.
*/
function revokeClaimBySignature(bytes calldata signature) external override delegatedOnly onlyManager {
require(!revokedClaims[signature], "Conflict: Claim already revoked");

revokedClaims[signature] = true;

emit ClaimRevoked(signature);
}

/**
* @dev See {IClaimIssuer-revokeClaim}.
*/
function revokeClaim(bytes32 _claimId, address _identity) external override delegatedOnly onlyManager returns(bool) {
uint256 foundClaimTopic;
uint256 scheme;
address issuer;
bytes memory sig;
bytes memory data;

( foundClaimTopic, scheme, issuer, sig, data, ) = Identity(_identity).getClaim(_claimId);

require(!revokedClaims[sig], "Conflict: Claim already revoked");

revokedClaims[sig] = true;
emit ClaimRevoked(sig);
return true;
}

/**
* @dev See {IClaimIssuer-isClaimValid}.
*/
function isClaimValid(
IIdentity _identity,
uint256 claimTopic,
bytes memory sig,
bytes memory data)
public override(Identity, IClaimIssuer) view returns (bool claimValid)
{
bytes32 dataHash = keccak256(abi.encode(_identity, claimTopic, data));
// Use abi.encodePacked to concatenate the message prefix and the message to sign.
bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash));

// Recover address of data signer
address recovered = getRecoveredAddress(sig, prefixedHash);

// Take hash of recovered address
bytes32 hashedAddr = keccak256(abi.encode(recovered));

// Does the trusted identifier have they key which signed the user's claim?
// && (isClaimRevoked(_claimId) == false)
if (keyHasPurpose(hashedAddr, 3) && (isClaimRevoked(sig) == false)) {
return true;
}

return false;
}

/**
* @dev See {IClaimIssuer-isClaimRevoked}.
*/
function isClaimRevoked(bytes memory _sig) public override view returns (bool) {
if (revokedClaims[_sig]) {
return true;
}

return false;
}

// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address /*newImplementation*/) internal override virtual {
require(keyHasPurpose(keccak256(abi.encode(msg.sender)), 42), "Caller is not authorized to upgrade");
}
}
94 changes: 94 additions & 0 deletions contracts/_testContracts/TestUpgradedClaimIssuer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;

import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "../Identity.sol";
import "../interface/IClaimIssuer.sol";

contract TestUpgradedClaimIssuer is IClaimIssuer, Identity, UUPSUpgradeable {
mapping (bytes => bool) public revokedClaims;

uint256 public newField;

// solhint-disable-next-line no-empty-blocks
constructor(address initialManagementKey, bool _isLibrary) Identity(initialManagementKey, _isLibrary) { }

function setNewField(uint256 _newField) external onlyManager {
newField = _newField;
}

/**
* @dev See {IClaimIssuer-revokeClaimBySignature}.
*/
function revokeClaimBySignature(bytes calldata signature) external override delegatedOnly onlyManager {
require(!revokedClaims[signature], "Conflict: Claim already revoked");

revokedClaims[signature] = true;

emit ClaimRevoked(signature);
}

/**
* @dev See {IClaimIssuer-revokeClaim}.
*/
function revokeClaim(bytes32 _claimId, address _identity) external override delegatedOnly onlyManager returns(bool) {
uint256 foundClaimTopic;
uint256 scheme;
address issuer;
bytes memory sig;
bytes memory data;

( foundClaimTopic, scheme, issuer, sig, data, ) = Identity(_identity).getClaim(_claimId);

require(!revokedClaims[sig], "Conflict: Claim already revoked");

revokedClaims[sig] = true;
emit ClaimRevoked(sig);
return true;
}

/**
* @dev See {IClaimIssuer-isClaimValid}.
*/
function isClaimValid(
IIdentity _identity,
uint256 claimTopic,
bytes memory sig,
bytes memory data)
public override(Identity, IClaimIssuer) view returns (bool claimValid)
{
bytes32 dataHash = keccak256(abi.encode(_identity, claimTopic, data));
// Use abi.encodePacked to concatenate the message prefix and the message to sign.
bytes32 prefixedHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash));

// Recover address of data signer
address recovered = getRecoveredAddress(sig, prefixedHash);

// Take hash of recovered address
bytes32 hashedAddr = keccak256(abi.encode(recovered));

// Does the trusted identifier have they key which signed the user's claim?
// && (isClaimRevoked(_claimId) == false)
if (keyHasPurpose(hashedAddr, 3) && (isClaimRevoked(sig) == false)) {
return true;
}

return false;
}

/**
* @dev See {IClaimIssuer-isClaimRevoked}.
*/
function isClaimRevoked(bytes memory _sig) public override view returns (bool) {
if (revokedClaims[_sig]) {
return true;
}

return false;
}

// solhint-disable-next-line no-empty-blocks
function _authorizeUpgrade(address /*newImplementation*/) internal override virtual {
require(keyHasPurpose(keccak256(abi.encode(msg.sender)), 42), "Caller is not authorized to upgrade");
}
}
9 changes: 9 additions & 0 deletions contracts/proxy/ClaimIssuerProxy.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity 0.8.17;
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

contract ClaimIssuerProxy is ERC1967Proxy {
// solhint-disable-next-line no-empty-blocks
constructor(address implementation, bytes memory _data) ERC1967Proxy(implementation, _data) { }
}
2 changes: 1 addition & 1 deletion contracts/storage/Structs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ contract Structs {
* Specification: Keys are cryptographic public keys, or contract addresses associated with this identity.
* The structure should be as follows:
* key: A public key owned by this identity
* purposes: uint256[] Array of the key purposes, like 1 = MANAGEMENT, 2 = EXECUTION
* purposes: uint256[] Array of the key purposes, like 1 = MANAGEMENT, 2 = EXECUTION, 42 = UPGRADE
* keyType: The type of key used, which would be a uint256 for different key types. e.g. 1 = ECDSA, 2 = RSA, etc.
* key: bytes32 The public key. // Its the Keccak256 hash of the key
*/
Expand Down
1 change: 1 addition & 0 deletions hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import "@nomicfoundation/hardhat-toolbox";
import { HardhatUserConfig } from "hardhat/config";
import 'solidity-coverage';
import '@openzeppelin/hardhat-upgrades';
import "@nomiclabs/hardhat-solhint";

import "./tasks/add-claim.task";
Expand Down
Loading

0 comments on commit c2ba91a

Please sign in to comment.