diff --git a/.gitignore b/.gitignore index 4995de0..80cef0a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ gas-report.txt # IDE .idea .vscode +.claude +CLAUDE.md # Environment variables .env diff --git a/contracts/IdentityUtilities.sol b/contracts/IdentityUtilities.sol index 4766631..655c65c 100644 --- a/contracts/IdentityUtilities.sol +++ b/contracts/IdentityUtilities.sol @@ -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"; diff --git a/contracts/factory/ClaimIssuerFactory.sol b/contracts/factory/ClaimIssuerFactory.sol index 1e05bf8..cbc8048 100644 --- a/contracts/factory/ClaimIssuerFactory.sol +++ b/contracts/factory/ClaimIssuerFactory.sol @@ -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; } diff --git a/contracts/factory/IdFactory.sol b/contracts/factory/IdFactory.sol index bd03142..dd661b0 100644 --- a/contracts/factory/IdFactory.sol +++ b/contracts/factory/IdFactory.sol @@ -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"; @@ -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 @@ -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; } /** @@ -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); } } diff --git a/contracts/gateway/Gateway.sol b/contracts/gateway/Gateway.sol index 6d3b119..fe2825a 100644 --- a/contracts/gateway/Gateway.sol +++ b/contracts/gateway/Gateway.sol @@ -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()); diff --git a/contracts/interface/IClaimIssuer.sol b/contracts/interface/IClaimIssuer.sol index 703e279..dd7bbdd 100644 --- a/contracts/interface/IClaimIssuer.sol +++ b/contracts/interface/IClaimIssuer.sol @@ -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 { diff --git a/contracts/interface/IIdentity.sol b/contracts/interface/IIdentity.sol index 3ed6fa0..502deea 100644 --- a/contracts/interface/IIdentity.sol +++ b/contracts/interface/IIdentity.sol @@ -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 { diff --git a/contracts/interface/IIdentityUtilities.sol b/contracts/interface/IIdentityUtilities.sol index 4afeacd..82cff9b 100644 --- a/contracts/interface/IIdentityUtilities.sol +++ b/contracts/interface/IIdentityUtilities.sol @@ -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 diff --git a/contracts/proxy/ClaimIssuerProxy.sol b/contracts/proxy/ClaimIssuerProxy.sol index 55468c1..9baa9b7 100644 --- a/contracts/proxy/ClaimIssuerProxy.sol +++ b/contracts/proxy/ClaimIssuerProxy.sol @@ -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 diff --git a/contracts/proxy/ImplementationAuthority.sol b/contracts/proxy/ImplementationAuthority.sol index 782c8dd..b25dd34 100644 --- a/contracts/proxy/ImplementationAuthority.sol +++ b/contracts/proxy/ImplementationAuthority.sol @@ -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) { } } diff --git a/foundry.lock b/foundry.lock new file mode 100644 index 0000000..d0c0159 --- /dev/null +++ b/foundry.lock @@ -0,0 +1,8 @@ +{ + "lib/forge-std": { + "tag": { + "name": "v1.14.0", + "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" + } + } +} \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 9b51c60..20f397e 100644 --- a/foundry.toml +++ b/foundry.toml @@ -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" @@ -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}" @@ -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" diff --git a/package-lock.json b/package-lock.json index b2801c8..533940c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -290,9 +290,9 @@ } }, "node_modules/@commitlint/load/node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", "dependencies": { @@ -803,7 +803,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-4.0.0.tgz", "integrity": "sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ==", - "deprecated": "This package is no longer maintained. For the JavaScript API, please use @conventional-changelog/git-client instead.", "dev": true, "license": "MIT", "dependencies": { @@ -963,9 +962,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index b87dcba..83553b1 100644 --- a/package.json +++ b/package.json @@ -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] + } } } diff --git a/remappings.txt b/remappings.txt index c81387d..47dbdad 100644 --- a/remappings.txt +++ b/remappings.txt @@ -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/ diff --git a/soldeer.lock b/soldeer.lock index db0b719..f1170bd 100644 --- a/soldeer.lock +++ b/soldeer.lock @@ -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" diff --git a/test/Proxy.t.sol b/test/Proxy.t.sol index 9fd2948..4f16f6a 100644 --- a/test/Proxy.t.sol +++ b/test/Proxy.t.sol @@ -22,7 +22,7 @@ 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); @@ -30,7 +30,7 @@ contract ProxyTest is OnchainIDSetup { 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)); @@ -38,7 +38,7 @@ contract ProxyTest is OnchainIDSetup { 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 { @@ -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) @@ -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 diff --git a/test/factory/ClaimIssuerFactory.t.sol b/test/factory/ClaimIssuerFactory.t.sol index 3cd2fd9..d6645df 100644 --- a/test/factory/ClaimIssuerFactory.t.sol +++ b/test/factory/ClaimIssuerFactory.t.sol @@ -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(); } @@ -42,7 +42,6 @@ contract ClaimIssuerFactoryTest is Test { } function test_revertDeployOnBehalfZeroAddress() public { - vm.prank(deployer); vm.expectRevert(Errors.ZeroAddress.selector); factory.deployClaimIssuerOnBehalf(address(0)); } @@ -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); @@ -97,13 +91,11 @@ 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"); @@ -111,7 +103,6 @@ contract ClaimIssuerFactoryTest is Test { } function test_shouldUpdateImplementation() public { - vm.prank(deployer); factory.updateImplementation(alice); assertEq(factory.implementation(), alice); diff --git a/test/factory/IdFactory.t.sol b/test/factory/IdFactory.t.sol index 728892c..e3133ef 100644 --- a/test/factory/IdFactory.t.sol +++ b/test/factory/IdFactory.t.sol @@ -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 { @@ -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, diff --git a/test/factory/TokenOid.t.sol b/test/factory/TokenOid.t.sol index 32790da..ef2f236 100644 --- a/test/factory/TokenOid.t.sol +++ b/test/factory/TokenOid.t.sol @@ -1,10 +1,13 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.27; -import { IdentityHelper } from "../helpers/IdentityHelper.sol"; +import { CreateX } from "@createx/CreateX.sol"; +import { Test } from "@forge-std/Test.sol"; + import { IdFactory } from "contracts/factory/IdFactory.sol"; import { Errors } from "contracts/libraries/Errors.sol"; -import { Test } from "forge-std/Test.sol"; + +import { IdentityHelper } from "../helpers/IdentityHelper.sol"; contract TokenOidTest is Test { @@ -20,7 +23,7 @@ contract TokenOidTest is Test { bob = makeAddr("tokenOidBob"); vm.startPrank(deployer); - setup = IdentityHelper.deployFactory(deployer); + setup = IdentityHelper.deployFactory(deployer, address(new CreateX()), address(this)); vm.stopPrank(); } @@ -33,22 +36,18 @@ contract TokenOidTest is Test { } function test_addTokenFactory_revertZeroAddress() public { - vm.prank(deployer); vm.expectRevert(Errors.ZeroAddress.selector); setup.idFactory.addTokenFactory(address(0)); } function test_addTokenFactory_shouldAdd() public { - vm.prank(deployer); setup.idFactory.addTokenFactory(alice); assertTrue(setup.idFactory.isTokenFactory(alice)); } function test_addTokenFactory_revertAlreadyFactory() public { - vm.prank(deployer); setup.idFactory.addTokenFactory(alice); - vm.prank(deployer); vm.expectRevert(abi.encodeWithSelector(Errors.AlreadyAFactory.selector, alice)); setup.idFactory.addTokenFactory(alice); } @@ -62,22 +61,18 @@ contract TokenOidTest is Test { } function test_removeTokenFactory_revertZeroAddress() public { - vm.prank(deployer); vm.expectRevert(Errors.ZeroAddress.selector); setup.idFactory.removeTokenFactory(address(0)); } function test_removeTokenFactory_revertNotFactory() public { - vm.prank(deployer); vm.expectRevert(abi.encodeWithSelector(Errors.NotAFactory.selector, bob)); setup.idFactory.removeTokenFactory(bob); } function test_removeTokenFactory_shouldRemove() public { - vm.prank(deployer); setup.idFactory.addTokenFactory(alice); - vm.prank(deployer); setup.idFactory.removeTokenFactory(alice); assertFalse(setup.idFactory.isTokenFactory(alice)); } @@ -91,19 +86,16 @@ contract TokenOidTest is Test { } function test_createTokenIdentity_revertTokenZeroAddress() public { - vm.prank(deployer); vm.expectRevert(Errors.ZeroAddress.selector); setup.idFactory.createTokenIdentity(address(0), alice, "TST"); } function test_createTokenIdentity_revertOwnerZeroAddress() public { - vm.prank(deployer); vm.expectRevert(Errors.ZeroAddress.selector); setup.idFactory.createTokenIdentity(alice, address(0), "TST"); } function test_createTokenIdentity_revertEmptySalt() public { - vm.prank(deployer); vm.expectRevert(Errors.EmptyString.selector); setup.idFactory.createTokenIdentity(alice, alice, ""); } @@ -111,7 +103,6 @@ contract TokenOidTest is Test { /// @notice Token factory should be able to create token identity function test_createTokenIdentity_viaTokenFactory_shouldCreate() public { // Register alice as a token factory - vm.prank(deployer); setup.idFactory.addTokenFactory(alice); // alice (as token factory) creates a token identity @@ -127,7 +118,6 @@ contract TokenOidTest is Test { function test_createTokenIdentity_shouldCreateAndRevertDuplicate() public { assertFalse(setup.idFactory.isSaltTaken("Tokensalt1")); - vm.prank(deployer); setup.idFactory.createTokenIdentity(alice, bob, "salt1"); address tokenIdentityAddr = setup.idFactory.getIdentity(alice); @@ -137,12 +127,10 @@ contract TokenOidTest is Test { assertEq(setup.idFactory.getToken(tokenIdentityAddr), alice); // Same salt should revert - vm.prank(deployer); vm.expectRevert(abi.encodeWithSelector(Errors.SaltTaken.selector, "Tokensalt1")); setup.idFactory.createTokenIdentity(alice, alice, "salt1"); // Same token address should revert - vm.prank(deployer); vm.expectRevert(abi.encodeWithSelector(Errors.TokenAlreadyLinked.selector, alice)); setup.idFactory.createTokenIdentity(alice, alice, "salt2"); } diff --git a/test/gateway/Gateway.t.sol b/test/gateway/Gateway.t.sol index 8dd4003..112e990 100644 --- a/test/gateway/Gateway.t.sol +++ b/test/gateway/Gateway.t.sol @@ -1,15 +1,17 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.27; -import { ClaimSignerHelper } from "../helpers/ClaimSignerHelper.sol"; -import { IdentityHelper } from "../helpers/IdentityHelper.sol"; +import { CreateX } from "@createx/CreateX.sol"; +import { Test, Vm } from "@forge-std/Test.sol"; + import { Identity } from "contracts/Identity.sol"; import { IdFactory } from "contracts/factory/IdFactory.sol"; import { Gateway } from "contracts/gateway/Gateway.sol"; import { Errors } from "contracts/libraries/Errors.sol"; import { KeyPurposes } from "contracts/libraries/KeyPurposes.sol"; -import { Test } from "forge-std/Test.sol"; -import { Vm } from "forge-std/Vm.sol"; + +import { ClaimSignerHelper } from "../helpers/ClaimSignerHelper.sol"; +import { IdentityHelper } from "../helpers/IdentityHelper.sol"; contract GatewayTest is Test { @@ -33,7 +35,7 @@ contract GatewayTest is Test { vm.warp(365 days); vm.startPrank(deployer); - setup = IdentityHelper.deployFactory(deployer); + setup = IdentityHelper.deployFactory(deployer, address(new CreateX()), address(this)); vm.stopPrank(); } @@ -64,7 +66,7 @@ contract GatewayTest is Test { } function _deployGateway(address[] memory signers) internal returns (Gateway) { - return new Gateway(address(setup.idFactory), signers); + return new Gateway(address(setup.idFactory), signers, address(this)); } function _deployGatewayWithCarol() internal returns (Gateway) { @@ -78,13 +80,13 @@ contract GatewayTest is Test { function test_constructor_revertZeroFactory() public { address[] memory signers = new address[](0); vm.expectRevert(Errors.ZeroAddress.selector); - new Gateway(address(0), signers); + new Gateway(address(0), signers, address(this)); } function test_constructor_revertTooManySigners() public { address[] memory signers = new address[](11); vm.expectRevert(Errors.TooManySigners.selector); - new Gateway(address(setup.idFactory), signers); + new Gateway(address(setup.idFactory), signers, address(this)); } // ============ deployIdentityWithSalt ============ @@ -116,7 +118,6 @@ contract GatewayTest is Test { function test_deployIdentityWithSalt_shouldDeploy() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp + 365 days; @@ -130,7 +131,6 @@ contract GatewayTest is Test { function test_deployIdentityWithSalt_noExpiry() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); bytes memory sig = _signDeploy(carolPk, alice, "saltToUse", 0); @@ -142,7 +142,6 @@ contract GatewayTest is Test { function test_deployIdentityWithSalt_revertRevokedSignature() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp + 365 days; @@ -156,7 +155,6 @@ contract GatewayTest is Test { function test_deployIdentityWithSalt_revertExpiredSignature() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp - 2 days; @@ -190,7 +188,6 @@ contract GatewayTest is Test { function test_deployWithKeys_shouldDeploy() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp + 365 days; @@ -211,7 +208,6 @@ contract GatewayTest is Test { function test_deployWithKeys_noExpiry() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); bytes32[] memory keys = new bytes32[](1); @@ -228,7 +224,6 @@ contract GatewayTest is Test { function test_deployWithKeys_revertRevokedSignature() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp + 365 days; @@ -244,7 +239,6 @@ contract GatewayTest is Test { function test_deployWithKeys_revertExpiredSignature() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); uint256 expiry = block.timestamp - 2 days; @@ -260,7 +254,6 @@ contract GatewayTest is Test { function test_deployForWallet_revertZeroAddress() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.expectRevert(Errors.ZeroAddress.selector); @@ -269,7 +262,6 @@ contract GatewayTest is Test { function test_deployForWallet_anotherSender() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.prank(bob); @@ -282,7 +274,6 @@ contract GatewayTest is Test { function test_deployForWallet_shouldDeploy() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.prank(alice); @@ -294,7 +285,6 @@ contract GatewayTest is Test { function test_deployForWallet_revertAlreadyDeployed() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.prank(alice); @@ -309,7 +299,6 @@ contract GatewayTest is Test { function test_transferOwnership_shouldTransfer() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); gateway.transferFactoryOwnership(bob); @@ -318,7 +307,6 @@ contract GatewayTest is Test { function test_transferOwnership_revertNotOwner() public { Gateway gateway = _deployGatewayWithCarol(); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.prank(alice); @@ -456,7 +444,6 @@ contract GatewayTest is Test { address[] memory signers = new address[](1); signers[0] = alice; Gateway gateway = _deployGateway(signers); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.prank(alice); @@ -468,7 +455,6 @@ contract GatewayTest is Test { address[] memory signers = new address[](1); signers[0] = alice; Gateway gateway = _deployGateway(signers); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); vm.expectRevert(Errors.CallToFactoryFailed.selector); @@ -479,7 +465,6 @@ contract GatewayTest is Test { address[] memory signers = new address[](1); signers[0] = alice; Gateway gateway = _deployGateway(signers); - vm.prank(deployer); setup.idFactory.transferOwnership(address(gateway)); gateway.callFactory(abi.encodeCall(IdFactory.addTokenFactory, (bob))); diff --git a/test/helpers/IdentityHelper.sol b/test/helpers/IdentityHelper.sol index 15344f8..01ac39c 100644 --- a/test/helpers/IdentityHelper.sol +++ b/test/helpers/IdentityHelper.sol @@ -15,21 +15,18 @@ library IdentityHelper { IdFactory idFactory; } - /// @notice Deploys complete Identity Factory infrastructure - /// @param managementKey The initial management key address - /// @return setup Struct containing all deployed contracts - function deployFactory(address managementKey) internal returns (OnchainIDSetup memory setup) { + function deployFactory(address managementKey, address createx, address owner) + internal + returns (OnchainIDSetup memory setup) + { setup.identityImplementation = new Identity(managementKey, false); - setup.implementationAuthority = new ImplementationAuthority(address(setup.identityImplementation)); - setup.idFactory = new IdFactory(address(setup.implementationAuthority)); + setup.implementationAuthority = new ImplementationAuthority(address(setup.identityImplementation), owner); + setup.idFactory = new IdFactory(address(setup.implementationAuthority), createx, owner); } - /// @notice Deploys an Identity through the custom IdentityProxy pattern - /// @param initialManagementKey The management key for the identity - /// @return identity The Identity contract at the proxy address - function deployIdentityWithProxy(address initialManagementKey) internal returns (Identity) { + function deployIdentityWithProxy(address initialManagementKey, address owner) internal returns (Identity) { Identity impl = new Identity(initialManagementKey, false); - ImplementationAuthority ia = new ImplementationAuthority(address(impl)); + ImplementationAuthority ia = new ImplementationAuthority(address(impl), owner); IdentityProxy proxy = new IdentityProxy(address(ia), initialManagementKey); return Identity(address(proxy)); } diff --git a/test/helpers/OnchainIDSetup.sol b/test/helpers/OnchainIDSetup.sol index 5d582fe..c7e3159 100644 --- a/test/helpers/OnchainIDSetup.sol +++ b/test/helpers/OnchainIDSetup.sol @@ -1,23 +1,27 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.27; -import { Constants } from "../utils/Constants.sol"; -import { ClaimIssuerHelper } from "./ClaimIssuerHelper.sol"; -import { ClaimSignerHelper } from "./ClaimSignerHelper.sol"; -import { IdentityHelper } from "./IdentityHelper.sol"; +import { CreateX } from "@createx/CreateX.sol"; +import { Test } from "@forge-std/Test.sol"; + import { ClaimIssuer } from "contracts/ClaimIssuer.sol"; import { Identity } from "contracts/Identity.sol"; import { IdFactory } from "contracts/factory/IdFactory.sol"; import { KeyPurposes } from "contracts/libraries/KeyPurposes.sol"; import { KeyTypes } from "contracts/libraries/KeyTypes.sol"; import { ImplementationAuthority } from "contracts/proxy/ImplementationAuthority.sol"; -import { Test } from "forge-std/Test.sol"; + +import { Constants } from "../utils/Constants.sol"; +import { ClaimIssuerHelper } from "./ClaimIssuerHelper.sol"; +import { ClaimSignerHelper } from "./ClaimSignerHelper.sol"; +import { IdentityHelper } from "./IdentityHelper.sol"; /// @notice Base test contract providing full OnchainID infrastructure contract OnchainIDSetup is Test { // Infrastructure IdentityHelper.OnchainIDSetup public onchainidSetup; + CreateX public createx = new CreateX(); // Standard test addresses with private keys address public deployer; @@ -61,7 +65,7 @@ contract OnchainIDSetup is Test { // Deploy factory infrastructure (as deployer) vm.startPrank(deployer); - onchainidSetup = IdentityHelper.deployFactory(deployer); + onchainidSetup = IdentityHelper.deployFactory(deployer, address(createx), deployer); vm.stopPrank(); // Deploy ClaimIssuer with proxy diff --git a/test/identities/Executions.t.sol b/test/identities/Executions.t.sol index 2b244dd..6efb75d 100644 --- a/test/identities/Executions.t.sol +++ b/test/identities/Executions.t.sol @@ -6,7 +6,6 @@ import { OnchainIDSetup } from "../helpers/OnchainIDSetup.sol"; import { Identity } from "contracts/Identity.sol"; import { KeyManager } from "contracts/KeyManager.sol"; import { IERC734 } from "contracts/interface/IERC734.sol"; -import { IERC735 } from "contracts/interface/IERC735.sol"; import { Errors } from "contracts/libraries/Errors.sol"; import { KeyPurposes } from "contracts/libraries/KeyPurposes.sol"; import { KeyTypes } from "contracts/libraries/KeyTypes.sol"; diff --git a/test/identities/ProxyPattern.t.sol b/test/identities/ProxyPattern.t.sol index b9d3e27..648e6ab 100644 --- a/test/identities/ProxyPattern.t.sol +++ b/test/identities/ProxyPattern.t.sol @@ -20,7 +20,7 @@ contract ProxyPatternTest is Test { function test_deployIdentityThroughProxyAndWorkCorrectly() public { vm.prank(deployer); - Identity identityProxy = IdentityHelper.deployIdentityWithProxy(deployer); + Identity identityProxy = IdentityHelper.deployIdentityWithProxy(deployer, address(this)); assertEq(identityProxy.version(), "3.0.0"); diff --git a/test/identity-utilities/IdentityUtilities.t.sol b/test/identity-utilities/IdentityUtilities.t.sol index 0ea248f..abb1148 100644 --- a/test/identity-utilities/IdentityUtilities.t.sol +++ b/test/identity-utilities/IdentityUtilities.t.sol @@ -879,7 +879,7 @@ contract IdentityUtilitiesTest is Test { (address claimSigner,) = makeAddrAndKey("claimSigner"); ClaimIssuer ci = ClaimIssuerHelper.deployWithProxy(claimIssuerOwner); - Identity identity = IdentityHelper.deployIdentityWithProxy(identityOwner); + Identity identity = IdentityHelper.deployIdentityWithProxy(identityOwner, address(this)); // Add CLAIM_SIGNER key to claim issuer for the claimIssuerOwner vm.prank(claimIssuerOwner); @@ -942,7 +942,7 @@ contract IdentityUtilitiesTest is Test { _addDefaultTopic(3004, "Test Topic", _singleStringArray("name"), _singleStringArray("string")); // Deploy Identity - Identity identity = IdentityHelper.deployIdentityWithProxy(admin); + Identity identity = IdentityHelper.deployIdentityWithProxy(admin, address(this)); // Add CLAIM_SIGNER key for admin on the identity vm.prank(admin); @@ -971,7 +971,7 @@ contract IdentityUtilitiesTest is Test { function test_isClaimValid_zeroAddressIssuer() public { TestIdentityUtilities testUtil = new TestIdentityUtilities(); - Identity identity = IdentityHelper.deployIdentityWithProxy(admin); + Identity identity = IdentityHelper.deployIdentityWithProxy(admin, address(this)); bool result = testUtil.checkIsClaimValid(address(identity), 3007, address(0), hex"", hex""); assertFalse(result); @@ -979,7 +979,7 @@ contract IdentityUtilitiesTest is Test { function test_isClaimValid_invalidContractIssuer() public { TestIdentityUtilities testUtil = new TestIdentityUtilities(); - Identity identity = IdentityHelper.deployIdentityWithProxy(admin); + Identity identity = IdentityHelper.deployIdentityWithProxy(admin, address(this)); // Deploy a contract that does not implement isClaimValid (catches and returns false) TestContract invalidContract = new TestContract(); diff --git a/test/mocks/RevertingIdentity.sol b/test/mocks/RevertingIdentity.sol index efb12bf..ffc9fe2 100644 --- a/test/mocks/RevertingIdentity.sol +++ b/test/mocks/RevertingIdentity.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; +pragma solidity ^0.8.27; /// @notice Mock identity whose initialize always reverts, causing IdentityProxy CREATE2 to fail contract RevertingIdentity { diff --git a/test/mocks/Test.sol b/test/mocks/Test.sol index 4f0318f..5d29794 100644 --- a/test/mocks/Test.sol +++ b/test/mocks/Test.sol @@ -1,4 +1,4 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; +pragma solidity ^0.8.27; contract Test { } // solhint-disable-line diff --git a/test/mocks/TestIdentityUtilities.sol b/test/mocks/TestIdentityUtilities.sol index 65b53a4..1fe744a 100644 --- a/test/mocks/TestIdentityUtilities.sol +++ b/test/mocks/TestIdentityUtilities.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-3.0 -pragma solidity 0.8.27; +pragma solidity ^0.8.27; import { IdentityUtilities } from "contracts/IdentityUtilities.sol"; import { IIdentity } from "contracts/interface/IIdentity.sol";