Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ gas-report.txt
# IDE
.idea
.vscode
.claude
CLAUDE.md
Comment on lines +35 to +36
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to mention them? I'm using it too, but just a question if we can add them, same for different repos

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially there could be some sensitive data in these files, I don't want to check that at every commit so I prefer not to include them.


# Environment variables
.env
Expand Down
2 changes: 1 addition & 1 deletion contracts/IdentityUtilities.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.27;
pragma solidity ^0.8.27;

import { IClaimIssuer } from "./interface/IClaimIssuer.sol";
import { IIdentity } from "./interface/IIdentity.sol";
Expand Down
2 changes: 1 addition & 1 deletion contracts/factory/ClaimIssuerFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract ClaimIssuerFactory is Ownable {
/// @notice Event emitted when the implementation is updated
event ImplementationUpdated(address indexed oldImplementation, address indexed newImplementation);

constructor(address implementationAddress) Ownable(msg.sender) {
constructor(address implementationAddress, address owner) Ownable(owner) {
_implementation = implementationAddress;
}

Expand Down
29 changes: 9 additions & 20 deletions contracts/factory/IdFactory.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import { ICreateX } from "@createx/ICreateX.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";

import { IERC734 } from "../interface/IERC734.sol";
Expand All @@ -15,6 +16,8 @@ contract IdFactory is IIdFactory, Ownable {
// address of the _implementationAuthority contract making the link to the implementation contract
address public immutable implementationAuthority;

address public immutable deployer;

mapping(address => bool) private _tokenFactories;

// as it is not possible to deploy 2 times the same contract address, this mapping allows us to check which
Expand All @@ -34,9 +37,12 @@ contract IdFactory is IIdFactory, Ownable {
mapping(address => address) private _tokenAddress;

// setting
constructor(address implementationAuthorityAddress) Ownable(msg.sender) {
constructor(address implementationAuthorityAddress, address deployerAddress, address owner) Ownable(owner) {
require(implementationAuthorityAddress != address(0), Errors.ZeroAddress());
require(deployerAddress != address(0), Errors.ZeroAddress());

implementationAuthority = implementationAuthorityAddress;
deployer = deployerAddress;
}

/**
Expand Down Expand Up @@ -208,30 +214,13 @@ contract IdFactory is IIdFactory, Ownable {
return _tokenFactories[_factory];
}

// deploy function with create2 opcode call
// returns the address of the contract created
function _deploy(string memory salt, bytes memory bytecode) private returns (address) {
bytes32 saltBytes = bytes32(keccak256(abi.encodePacked(salt)));
address addr;
// solhint-disable-next-line no-inline-assembly
assembly {
let encoded_data := add(0x20, bytecode) // load initialization code.
let encoded_size := mload(bytecode) // load init code's length.
addr := create2(0, encoded_data, encoded_size, saltBytes)
if iszero(extcodesize(addr)) {
revert(0, 0)
}
}
emit Deployed(addr);
return addr;
}

// function used to deploy an identity using CREATE2
function _deployIdentity(string memory _salt, address _wallet) private returns (address) {
bytes memory _code = type(IdentityProxy).creationCode;
bytes memory _constructData = abi.encode(implementationAuthority, _wallet);
bytes memory bytecode = abi.encodePacked(_code, _constructData);
return _deploy(_salt, bytecode);

return ICreateX(deployer).deployCreate3(keccak256(abi.encodePacked(_salt)), bytecode);
}

}
2 changes: 1 addition & 1 deletion contracts/gateway/Gateway.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,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(msg.sender) {
constructor(address idFactoryAddress, address[] memory signersToApprove, address owner) Ownable(owner) {
require(idFactoryAddress != address(0), Errors.ZeroAddress());
require(signersToApprove.length <= 10, Errors.TooManySigners());

Expand Down
2 changes: 1 addition & 1 deletion contracts/interface/IClaimIssuer.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import "./IIdentity.sol";
import { IIdentity } from "./IIdentity.sol";

interface IClaimIssuer is IIdentity {

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

import "./IERC734.sol";
import "./IERC735.sol";
import { IERC734 } from "./IERC734.sol";
import { IERC735 } from "./IERC735.sol";

// solhint-disable-next-line no-empty-blocks
interface IIdentity is IERC734, IERC735 {
Expand Down
2 changes: 1 addition & 1 deletion contracts/interface/IIdentityUtilities.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.27;
pragma solidity ^0.8.27;

/// @title IIdentityUtilities
/// @notice Interface for a schema registry that maps topic IDs to structured metadata schemas
Expand Down
2 changes: 1 addition & 1 deletion contracts/proxy/ClaimIssuerProxy.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.27;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";

/**
* @title ClaimIssuerProxy
Expand Down
2 changes: 1 addition & 1 deletion contracts/proxy/ImplementationAuthority.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ import { UpgradeableBeacon } from "@openzeppelin/contracts/proxy/beacon/Upgradea

contract ImplementationAuthority is UpgradeableBeacon {

constructor(address implementation) UpgradeableBeacon(implementation, msg.sender) { }
constructor(address implementation, address owner) UpgradeableBeacon(implementation, owner) { }

}
8 changes: 8 additions & 0 deletions foundry.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"lib/forge-std": {
"tag": {
"name": "v1.14.0",
"rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6"
}
}
}
5 changes: 4 additions & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ test = "test"
script = "scripts"
libs = ["dependencies"]

solc_version = "0.8.27"
solc_version = "0.8.30"
optimizer = true
optimizer_runs = 200
evm_version = "shanghai"
Expand All @@ -18,6 +18,8 @@ bracket_spacing = true
[profile.default.lint]
lint_on_build = true

fs_permissions = [{ access = "read", path = "out" }]

[rpc_endpoints]
baseSepolia = "https://base-sepolia.g.alchemy.com/v2/${ALCHEMY_KEY}"
base = "https://base-mainnet.g.alchemy.com/v2/${ALCHEMY_KEY}"
Expand All @@ -29,4 +31,5 @@ remappings_regenerate = false
forge-std = { version = "v1.14.0", git = "https://github.com/foundry-rs/forge-std.git", tag = "v1.14.0" }
"@openzeppelin-contracts" = "5.2.0"
"@openzeppelin-contracts-upgradeable" = "4.9.6"
createx = { version = "main", git = "https://github.com/TokenySolutions/createx", branch = "main" }
solady = "0.1.15"
13 changes: 6 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@
"commitlint": {
"extends": [
"@ballcat/commitlint-config-gitmoji"
]
],
"parserPreset": {
"parserOpts": {
"headerPattern": "^(:\\w*:|(?:[\\u2700-\\u27BF]|[\\uD83C-\\uDBFF][\\uDC00-\\uDFFF]|[\\u2600-\\u26FF]|[\\u2700-\\u27BF]|[\\u00A9\\u00AE]|[\\u203C\\u2049]|[\\u2139]|[\\u2194-\\u21AA]|[\\u231A-\\u25FC]|[\\u25FB-\\u25FE]|[\\u2934-\\u2935]|[\\u2B05-\\u2B55]|[\\u3030\\u303D]|[\\u3297\\u3299]|\\uFE0F)+) (?:\\((.*)\\) )?(.*)$",
"headerCorrespondence": ["type", "scope", "subject"]
}
},
"rules": {
"type-enum": [0],
"type-case": [0]
}
}
}
1 change: 1 addition & 0 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@createx/=dependencies/createx-main/src/
@forge-std/=dependencies/forge-std-v1.14.0/src/
@openzeppelin/contracts-upgradeable/=dependencies/@openzeppelin-contracts-upgradeable-4.9.6/
@openzeppelin/contracts/=dependencies/@openzeppelin-contracts-5.2.0/
Expand Down
6 changes: 6 additions & 0 deletions soldeer.lock
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ url = "https://soldeer-revisions.s3.amazonaws.com/@openzeppelin-contracts-upgrad
checksum = "dddc8efa3da3dcd0dbda63efdc34d6006ece3ae5a8f46b0cf914870df45b9c71"
integrity = "e67f536c763f35149aac483acfa21637c6b6b6c3f8a71860f8e717cf110138cd"

[[dependencies]]
name = "createx"
version = "main"
git = "https://github.com/TokenySolutions/createx"
rev = "829450f70a9119413911877eae695bec95e49ba1"

[[dependencies]]
name = "forge-std"
version = "v1.14.0"
Expand Down
10 changes: 5 additions & 5 deletions test/Proxy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ contract ProxyTest is OnchainIDSetup {

function test_revertBecauseImplementationIsNotIdentity() public {
TestContract testContract = new TestContract();
ImplementationAuthority authority = new ImplementationAuthority(address(testContract));
ImplementationAuthority authority = new ImplementationAuthority(address(testContract), address(this));

vm.expectRevert(OZErrors.FailedCall.selector);
new IdentityProxy(address(authority), alice);
}

function test_revertBecauseInitialKeyIsZeroAddress() public {
Identity impl = new Identity(deployer, true);
ImplementationAuthority authority = new ImplementationAuthority(address(impl));
ImplementationAuthority authority = new ImplementationAuthority(address(impl), address(this));

vm.expectRevert(Errors.ZeroAddress.selector);
new IdentityProxy(address(authority), address(0));
}

function test_preventCreatingAuthorityWithZeroAddress() public {
vm.expectRevert(abi.encode(UpgradeableBeacon.BeaconInvalidImplementation.selector, address(0)));
new ImplementationAuthority(address(0));
new ImplementationAuthority(address(0), address(this));
}

function test_preventUpdatingToZeroAddress() public {
Expand All @@ -55,7 +55,7 @@ contract ProxyTest is OnchainIDSetup {

function test_implementationAuthority_shouldReturnCorrectAddress() public {
Identity impl = new Identity(deployer, false);
ImplementationAuthority authority = new ImplementationAuthority(address(impl));
ImplementationAuthority authority = new ImplementationAuthority(address(impl), address(this));
IdentityProxy proxy = new IdentityProxy(address(authority), deployer);

// ERC-1967 beacon slot: bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)
Expand All @@ -67,7 +67,7 @@ contract ProxyTest is OnchainIDSetup {
function test_updateImplementationAddress() public {
// Deploy identity with its own proxy and authority
Identity impl = new Identity(deployer, false);
ImplementationAuthority authority = new ImplementationAuthority(address(impl));
ImplementationAuthority authority = new ImplementationAuthority(address(impl), address(this));
new IdentityProxy(address(authority), deployer);

// Deploy new implementation
Expand Down
11 changes: 1 addition & 10 deletions test/factory/ClaimIssuerFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract ClaimIssuerFactoryTest is Test {

vm.startPrank(deployer);
claimIssuerImpl = new ClaimIssuer(deployer);
factory = new ClaimIssuerFactory(address(claimIssuerImpl));
factory = new ClaimIssuerFactory(address(claimIssuerImpl), address(this));
vm.stopPrank();
}

Expand All @@ -42,7 +42,6 @@ contract ClaimIssuerFactoryTest is Test {
}

function test_revertDeployOnBehalfZeroAddress() public {
vm.prank(deployer);
vm.expectRevert(Errors.ZeroAddress.selector);
factory.deployClaimIssuerOnBehalf(address(0));
}
Expand All @@ -54,29 +53,24 @@ contract ClaimIssuerFactoryTest is Test {
}

function test_revertBlacklistZeroAddress() public {
vm.prank(deployer);
vm.expectRevert(Errors.ZeroAddress.selector);
factory.blacklistAddress(address(0), true);
}

function test_shouldBlacklistAddress() public {
vm.prank(deployer);
factory.blacklistAddress(alice, true);

assertTrue(factory.isBlacklisted(alice));
}

function test_shouldUnblacklistAddress() public {
vm.startPrank(deployer);
factory.blacklistAddress(alice, true);
factory.blacklistAddress(alice, false);
vm.stopPrank();

assertFalse(factory.isBlacklisted(alice));
}

function test_revertDeployFromBlacklisted() public {
vm.prank(deployer);
factory.blacklistAddress(alice, true);

vm.prank(alice);
Expand All @@ -97,21 +91,18 @@ contract ClaimIssuerFactoryTest is Test {
}

function test_revertUpdateImplementationZeroAddress() public {
vm.prank(deployer);
vm.expectRevert(Errors.ZeroAddress.selector);
factory.updateImplementation(address(0));
}

function test_shouldDeployClaimIssuerOnBehalf() public {
vm.prank(deployer);
address deployed = factory.deployClaimIssuerOnBehalf(alice);

assertTrue(deployed != address(0), "Should deploy ClaimIssuer");
assertEq(factory.claimIssuer(alice), deployed, "Should map alice to deployed ClaimIssuer");
}

function test_shouldUpdateImplementation() public {
vm.prank(deployer);
factory.updateImplementation(alice);

assertEq(factory.implementation(), alice);
Expand Down
11 changes: 8 additions & 3 deletions test/factory/IdFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ contract IdFactoryTest is OnchainIDSetup {

function test_revertBecauseAuthorityIsZeroAddress() public {
vm.expectRevert(Errors.ZeroAddress.selector);
new IdFactory(address(0));
new IdFactory(address(0), address(createx), address(this));
}

function test_revertWhenDeployerIsZeroAddress() public {
vm.expectRevert(Errors.ZeroAddress.selector);
new IdFactory(address(0x1), address(0), address(this));
}

function test_revertBecauseSenderNotAllowedToCreateIdentities() public {
Expand Down Expand Up @@ -266,8 +271,8 @@ contract IdFactoryTest is OnchainIDSetup {
function test_createIdentity_revertWhenCreate2Fails() public {
// Deploy a factory with a reverting implementation
RevertingIdentity revertingImpl = new RevertingIdentity();
ImplementationAuthority badAuthority = new ImplementationAuthority(address(revertingImpl));
IdFactory badFactory = new IdFactory(address(badAuthority));
ImplementationAuthority badAuthority = new ImplementationAuthority(address(revertingImpl), address(this));
IdFactory badFactory = new IdFactory(address(badAuthority), address(createx), address(this));

// createIdentity will try CREATE2 with IdentityProxy whose constructor
// delegatecalls initialize() on RevertingIdentity, which reverts,
Expand Down
Loading
Loading