Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contracts/ClaimIssuer.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

import "./interface/IClaimIssuer.sol";
import "./Identity.sol";
Expand All @@ -24,7 +24,7 @@ contract ClaimIssuer is IClaimIssuer, Identity {
/**
* @dev See {IClaimIssuer-revokeClaim}.
*/
function revokeClaim(bytes32 _claimId, address _identity) external override delegatedOnly onlyManager returns(bool) {
function revokeClaim(bytes32 _claimId, address payable _identity) external override delegatedOnly onlyManager returns(bool) {
uint256 foundClaimTopic;
uint256 scheme;
address issuer;
Expand Down
211 changes: 178 additions & 33 deletions contracts/Identity.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

import "./interface/IIdentity.sol";
import "./interface/IClaimIssuer.sol";
Expand Down Expand Up @@ -56,6 +56,8 @@ contract Identity is Storage, IIdentity, Version {
}
}

receive() external payable {}

/**
* @notice When using this contract as an implementation for a proxy, call this initializer with a delegatecall.
*
Expand Down Expand Up @@ -92,10 +94,52 @@ contract Identity is Storage, IIdentity, Version {
emit ExecutionRequested(_executionId, _to, _value, _data);

if (keyHasPurpose(keccak256(abi.encode(msg.sender)), 1)) {
approve(_executionId, true);
_approveAndExecute(_executionId, true);
}
else if (_to != address(this) && keyHasPurpose(keccak256(abi.encode(msg.sender)), 2)){
approve(_executionId, true);
_approveAndExecute(_executionId, true);
}

return _executionId;
}

/**
* @dev See {IERC734-execute}.
* @notice Passes an execution instruction to the keymanager, using signatures instead of sender verification.
* If the sender is an ACTION key and the destination address is not the identity contract itself, then the
* execution is immediately approved and performed.
* If the destination address is the identity itself, then the execution would be performed immediately only if
* the sender is a MANAGEMENT key.
* Otherwise the execution request must be approved via the `approve` method.
* @param _keyType The type of key used for the signature, a uint256 for different key types. 1 = ECDSA, 2 = RSA, 3 = P256.
* @return executionId to use in the approve function, to approve or reject this execution.
*/
function executeSigned(address _to, uint256 _value, bytes memory _data, uint256 nonce, uint256 _keyType, uint8 v, bytes32 r, bytes32 s)
external
delegatedOnly
override
payable
returns (uint256 executionId) {
bytes32 executionSigner = _recoverSignerForExecution(_to, _value, _data, nonce, _keyType, v, r, s);

uint256 _executionId = _executionNonce;
_executions[_executionId].to = _to;
_executions[_executionId].value = _value;
_executions[_executionId].data = _data;
_executionNonce++;

emit ExecutionRequested(_executionId, _to, _value, _data);

if (keyHasPurpose(executionSigner, 1)) {
require(nonce == _operationNonce, "Invalid nonce");
_operationNonce++;

_approveAndExecute(_executionId, true);
} else if (_to != address(this) && keyHasPurpose(executionSigner, 2)){
require(nonce == _operationNonce, "Invalid nonce");
_operationNonce++;

_approveAndExecute(_executionId, true);
}

return _executionId;
Expand Down Expand Up @@ -233,39 +277,36 @@ contract Identity is Storage, IIdentity, Version {
require(keyHasPurpose(keccak256(abi.encode(msg.sender)), 2), "Sender does not have action key");
}

emit Approved(_id, _approve);

if (_approve == true) {
_executions[_id].approved = true;

// solhint-disable-next-line avoid-low-level-calls
(success,) = _executions[_id].to.call{value:(_executions[_id].value)}(_executions[_id].data);

if (success) {
_executions[_id].executed = true;
return _approveAndExecute(_id, _approve);
}

emit Executed(
_id,
_executions[_id].to,
_executions[_id].value,
_executions[_id].data
);
function approveSigned(uint256 _id, bool _approve, uint256 _keyType, uint8 v, bytes32 r, bytes32 s)
public
delegatedOnly
override
returns (bool success)
{
require(_id < _executionNonce, "Cannot approve a non-existing execution");
require(!_executions[_id].executed, "Request already executed");

return true;
} else {
emit ExecutionFailed(
_id,
_executions[_id].to,
_executions[_id].value,
_executions[_id].data
);
bytes32 executionSigner = _recoverSignerForPendingExecution(
_id,
_executions[_id].to,
_executions[_id].value,
_executions[_id].data,
_keyType,
v,
r,
s
);

return false;
}
if(_executions[_id].to == address(this)) {
require(keyHasPurpose(executionSigner, 1), "Sender does not have management key");
} else {
_executions[_id].approved = false;
require(keyHasPurpose(executionSigner, 2), "Sender does not have action key");
}
return false;

return _approveAndExecute(_id, _approve);
}

/**
Expand Down Expand Up @@ -354,7 +395,12 @@ contract Identity is Storage, IIdentity, Version {
returns (bytes32 claimRequestId)
{
if (_issuer != address(this)) {
require(IClaimIssuer(_issuer).isClaimValid(IIdentity(address(this)), _topic, _signature, _data), "invalid claim");
require(IClaimIssuer(_issuer).isClaimValid(
IIdentity(address(this)),
_topic,
_signature,
_data),
"invalid claim");
}

bytes32 claimId = keccak256(abi.encode(_issuer, _topic));
Expand Down Expand Up @@ -511,7 +557,9 @@ contract Identity is Storage, IIdentity, Version {
{
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));
bytes32 prefixedHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)
);

// Recover address of data signer
address recovered = getRecoveredAddress(sig, prefixedHash);
Expand Down Expand Up @@ -584,6 +632,103 @@ contract Identity is Storage, IIdentity, Version {
emit KeyAdded(_key, 1, 1);
}

function _approveAndExecute(uint256 _id, bool _approve) internal delegatedOnly returns (bool success) {
require(_id < _executionNonce, "Cannot approve a non-existing execution");
require(!_executions[_id].executed, "Request already executed");

emit Approved(_id, _approve);

if (_approve == true) {
_executions[_id].approved = true;

// solhint-disable-next-line avoid-low-level-calls
(success,) = _executions[_id].to.call{value:(_executions[_id].value)}(_executions[_id].data);

if (success) {
_executions[_id].executed = true;

emit Executed(
_id,
_executions[_id].to,
_executions[_id].value,
_executions[_id].data
);

return true;
} else {
emit ExecutionFailed(
_id,
_executions[_id].to,
_executions[_id].value,
_executions[_id].data
);

return false;
}
} else {
_executions[_id].approved = false;
}
return false;
}

function _recoverSignerForExecution(
address _to,
uint256 _value,
bytes memory _data,
uint256 _nonce,
uint256 _keyType,
uint8 v,
bytes32 r,
bytes32 s
) internal delegatedOnly view returns(bytes32 keyHash) {
if (_keyType == 1) {
bytes32 dataHash = keccak256(abi.encode(address(this), _to, _value, _data, _nonce));
bytes32 prefixedHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)
);
address recovered = ecrecover(prefixedHash, v, r, s);

return keccak256(abi.encode(recovered));
} else if (_keyType == 3) {
revert("Not implemented.");
} else {
revert("Invalid key type");
}
}

function _recoverSignerForPendingExecution(
uint256 _id,
address _to,
uint256 _value,
bytes memory _data,
uint256 _keyType,
uint8 v,
bytes32 r,
bytes32 s
) internal delegatedOnly view returns(bytes32 keyHash) {
if (_keyType == 1) {
bytes32 dataHash = keccak256(abi.encode(address(this), _id, _to, _value, _data));
bytes32 prefixedHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)
);
address recovered = ecrecover(prefixedHash, v, r, s);

return keccak256(abi.encode(recovered));
} else if (_keyType == 3) {
revert("Not implemented.");
} else {
revert("Invalid key type");
}
}

/**
* @notice Return the operation nonce (for signed operations).
* @return The next sequential nonce.
*/
function getNonce() public view virtual returns (uint256) {
return _operationNonce;
}

/**
* @notice Computes if the context in which the function is called is a constructor or not.
*
Expand Down
2 changes: 1 addition & 1 deletion contracts/Test.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

contract Test {} // solhint-disable-line
2 changes: 1 addition & 1 deletion contracts/_testContracts/VerifierUser.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* solhint-disable */

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

import "../verifiers/Verifier.sol";

Expand Down
4 changes: 2 additions & 2 deletions contracts/factory/IdFactory.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

import "../proxy/IdentityProxy.sol";
import "./IIdFactory.sol";
Expand Down Expand Up @@ -31,7 +31,7 @@ contract IdFactory is IIdFactory, Ownable {


// setting
constructor (address implementationAuthority) {
constructor (address implementationAuthority) Ownable(msg.sender) {
require(implementationAuthority != address(0), "invalid argument - zero address");
_implementationAuthority = implementationAuthority;
}
Expand Down
26 changes: 13 additions & 13 deletions contracts/gateway/Gateway.sol
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.17;
pragma solidity 0.8.27;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "../factory/IdFactory.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

using ECDSA for bytes32;
using MessageHashUtils for bytes32;

/// A required parameter was set to the Zero address.
error ZeroAddress();
Expand Down Expand Up @@ -42,7 +45,7 @@ contract Gateway is Ownable {
* @dev Constructor for the ONCHAINID Factory Gateway.
* @param idFactoryAddress the address of the factory to operate (the Gateway must be owner of the Factory).
*/
constructor(address idFactoryAddress, address[] memory signersToApprove) Ownable() {
constructor(address idFactoryAddress, address[] memory signersToApprove) Ownable(msg.sender) {
if (idFactoryAddress == address(0)) {
revert ZeroAddress();
}
Expand Down Expand Up @@ -117,17 +120,14 @@ contract Gateway is Ownable {
revert ExpiredSignature(signature);
}

address signer = ECDSA.recover(
keccak256(
abi.encode(
"Authorize ONCHAINID deployment",
identityOwner,
salt,
signatureExpiry
)
).toEthSignedMessageHash(),
signature
);
address signer = keccak256(
abi.encode(
"Authorize ONCHAINID deployment",
identityOwner,
salt,
signatureExpiry
)
).toEthSignedMessageHash().recover(signature);

if (!approvedSigners[signer]) {
revert UnapprovedSigner(signer);
Expand Down
2 changes: 1 addition & 1 deletion contracts/interface/IClaimIssuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ interface IClaimIssuer is IIdentity {
* @param _identity the address of the identity contract
* @return isRevoked true when the claim is revoked
*/
function revokeClaim(bytes32 _claimId, address _identity) external returns(bool);
function revokeClaim(bytes32 _claimId, address payable _identity) external returns(bool);

/**
* @dev Revoke a claim previously issued, the claim is no longer considered as valid after revocation.
Expand Down
Loading